Skip to content

Commit

Permalink
Merge pull request #1392 from loadimpact/varriableLoopingVUsStepping
Browse files Browse the repository at this point in the history
fixes #1296
  • Loading branch information
mstoykov authored Apr 28, 2020
2 parents 6e86861 + fb145c2 commit edb8239
Show file tree
Hide file tree
Showing 4 changed files with 1,113 additions and 219 deletions.
52 changes: 22 additions & 30 deletions lib/execution_segment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ func TestExecutionTupleScale(t *testing.T) {
require.Equal(t, int64(1), et.ScaleInt64(2))
require.Equal(t, int64(1), et.ScaleInt64(3))
}

func TestBigScale(t *testing.T) {
es := new(ExecutionSegment)
ess, err := NewExecutionSegmentSequenceFromString("0,7/20,7/10,1")
Expand Down Expand Up @@ -431,29 +432,24 @@ func TestExecutionSegmentStringSequences(t *testing.T) {

// Return a randomly distributed sequence of n amount of
// execution segments whose length totals 1.
func generateRandomSequence(n int64, r *rand.Rand) (ExecutionSegmentSequence, error) {
func generateRandomSequence(t testing.TB, n, m int64, r *rand.Rand) ExecutionSegmentSequence {
var err error
var ess = ExecutionSegmentSequence(make([]*ExecutionSegment, n))
var numerators = make([]int64, n)
ess := ExecutionSegmentSequence(make([]*ExecutionSegment, n))
numerators := make([]int64, n)
var denominator int64
for i := int64(0); i < n; i++ {
for numerators[i] == 0 {
numerators[i] = r.Int63n(n)
denominator += numerators[i]
}
numerators[i] = 1 + r.Int63n(m)
denominator += numerators[i]
}
ess[0], err = NewExecutionSegment(big.NewRat(0, 1), big.NewRat(numerators[0], denominator))
if err != nil {
return nil, err
}
for i := int64(1); i < n; i++ {
ess[i], err = NewExecutionSegment(ess[i-1].to, new(big.Rat).Add(big.NewRat(numerators[i], denominator), ess[i-1].to))
if err != nil {
return nil, err
}
from := big.NewRat(0, 1)
for i := int64(0); i < n; i++ {
to := new(big.Rat).Add(big.NewRat(numerators[i], denominator), from)
ess[i], err = NewExecutionSegment(from, to)
require.NoError(t, err)
from = to
}

return ess, nil
return ess
}

// Ensure that the sum of scaling all execution segments in
Expand All @@ -468,8 +464,7 @@ func TestExecutionSegmentScaleConsistency(t *testing.T) {
const numTests = 10
for i := 0; i < numTests; i++ {
scale := rand.Int31n(99) + 2
seq, err := generateRandomSequence(r.Int63n(9)+2, r)
require.NoError(t, err)
seq := generateRandomSequence(t, r.Int63n(9)+2, 100, r)

t.Run(fmt.Sprintf("%d_%s", scale, seq), func(t *testing.T) {
var total int64
Expand All @@ -493,8 +488,7 @@ func TestExecutionTupleScaleConsistency(t *testing.T) {
const numTests = 10
for i := 0; i < numTests; i++ {
scale := rand.Int31n(99) + 2
seq, err := generateRandomSequence(r.Int63n(9)+2, r)
require.NoError(t, err)
seq := generateRandomSequence(t, r.Int63n(9)+2, 200, r)

et, err := NewExecutionTuple(seq[0], &seq)
require.NoError(t, err)
Expand Down Expand Up @@ -534,8 +528,7 @@ func TestExecutionSegmentScaleNoWobble(t *testing.T) {
// Random segments
const numTests = 10
for i := 0; i < numTests; i++ {
seq, err := generateRandomSequence(r.Int63n(9)+2, r)
require.NoError(t, err)
seq := generateRandomSequence(t, r.Int63n(9)+2, 100, r)

es := seq[rand.Intn(len(seq))]

Expand Down Expand Up @@ -628,15 +621,14 @@ func TestSequenceLCD(t *testing.T) {
}

func BenchmarkGetStripedOffsets(b *testing.B) {
var lengths = [...]int64{10, 100}
lengths := [...]int64{10, 100}
const seed = 777
r := rand.New(rand.NewSource(seed))

for _, length := range lengths {
length := length
b.Run(fmt.Sprintf("length%d,seed%d", length, seed), func(b *testing.B) {
sequence, err := generateRandomSequence(length, r)
require.NoError(b, err)
sequence := generateRandomSequence(b, length, 100, r)
b.ResetTimer()
for i := 0; i < b.N; i++ {
segment := sequence[int(r.Int63())%len(sequence)]
Expand All @@ -649,11 +641,11 @@ func BenchmarkGetStripedOffsets(b *testing.B) {
}

func BenchmarkGetStripedOffsetsEven(b *testing.B) {
var lengths = [...]int64{10, 100, 1000}
lengths := [...]int64{10, 100, 1000}
generateSequence := func(n int64) ExecutionSegmentSequence {
var err error
var ess = ExecutionSegmentSequence(make([]*ExecutionSegment, n))
var numerators = make([]int64, n)
ess := ExecutionSegmentSequence(make([]*ExecutionSegment, n))
numerators := make([]int64, n)
var denominator int64
for i := int64(0); i < n; i++ {
numerators[i] = 1 // nice and simple :)
Expand Down Expand Up @@ -731,7 +723,7 @@ func mustNewExecutionSegmentSequence(str string) *ExecutionSegmentSequence {
}

func TestNewExecutionTuple(t *testing.T) {
var testCases = []struct {
testCases := []struct {
seg *ExecutionSegment
seq *ExecutionSegmentSequence
scaleTests map[int64]int64
Expand Down
100 changes: 0 additions & 100 deletions lib/executor/executors_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -388,103 +388,3 @@ func TestConfigMapParsingAndValidation(t *testing.T) {
})
}
}

func TestVariableLoopingVUsConfigExecutionPlanExample(t *testing.T) {
t.Parallel()
et, err := lib.NewExecutionTuple(nil, nil)
require.NoError(t, err)
conf := NewVariableLoopingVUsConfig("test")
conf.StartVUs = null.IntFrom(4)
conf.Stages = []Stage{
{Target: null.IntFrom(6), Duration: types.NullDurationFrom(2 * time.Second)},
{Target: null.IntFrom(1), Duration: types.NullDurationFrom(5 * time.Second)},
{Target: null.IntFrom(5), Duration: types.NullDurationFrom(4 * time.Second)},
{Target: null.IntFrom(1), Duration: types.NullDurationFrom(4 * time.Second)},
{Target: null.IntFrom(4), Duration: types.NullDurationFrom(3 * time.Second)},
{Target: null.IntFrom(4), Duration: types.NullDurationFrom(2 * time.Second)},
{Target: null.IntFrom(1), Duration: types.NullDurationFrom(0 * time.Second)},
{Target: null.IntFrom(1), Duration: types.NullDurationFrom(3 * time.Second)},
}

expRawStepsNoZeroEnd := []lib.ExecutionStep{
{TimeOffset: 0 * time.Second, PlannedVUs: 4},
{TimeOffset: 1 * time.Second, PlannedVUs: 5},
{TimeOffset: 2 * time.Second, PlannedVUs: 6},
{TimeOffset: 3 * time.Second, PlannedVUs: 5},
{TimeOffset: 4 * time.Second, PlannedVUs: 4},
{TimeOffset: 5 * time.Second, PlannedVUs: 3},
{TimeOffset: 6 * time.Second, PlannedVUs: 2},
{TimeOffset: 7 * time.Second, PlannedVUs: 1},
{TimeOffset: 8 * time.Second, PlannedVUs: 2},
{TimeOffset: 9 * time.Second, PlannedVUs: 3},
{TimeOffset: 10 * time.Second, PlannedVUs: 4},
{TimeOffset: 11 * time.Second, PlannedVUs: 5},
{TimeOffset: 12 * time.Second, PlannedVUs: 4},
{TimeOffset: 13 * time.Second, PlannedVUs: 3},
{TimeOffset: 14 * time.Second, PlannedVUs: 2},
{TimeOffset: 15 * time.Second, PlannedVUs: 1},
{TimeOffset: 16 * time.Second, PlannedVUs: 2},
{TimeOffset: 17 * time.Second, PlannedVUs: 3},
{TimeOffset: 18 * time.Second, PlannedVUs: 4},
{TimeOffset: 20 * time.Second, PlannedVUs: 1},
}
rawStepsNoZeroEnd := conf.getRawExecutionSteps(nil, false)
assert.Equal(t, expRawStepsNoZeroEnd, rawStepsNoZeroEnd)
endOffset, isFinal := lib.GetEndOffset(rawStepsNoZeroEnd)
assert.Equal(t, 20*time.Second, endOffset)
assert.Equal(t, false, isFinal)

rawStepsZeroEnd := conf.getRawExecutionSteps(nil, true)
assert.Equal(t,
append(expRawStepsNoZeroEnd, lib.ExecutionStep{TimeOffset: 23 * time.Second, PlannedVUs: 0}),
rawStepsZeroEnd,
)
endOffset, isFinal = lib.GetEndOffset(rawStepsZeroEnd)
assert.Equal(t, 23*time.Second, endOffset)
assert.Equal(t, true, isFinal)

// GracefulStop and GracefulRampDown equal to the default 30 sec
assert.Equal(t, []lib.ExecutionStep{
{TimeOffset: 0 * time.Second, PlannedVUs: 4},
{TimeOffset: 1 * time.Second, PlannedVUs: 5},
{TimeOffset: 2 * time.Second, PlannedVUs: 6},
{TimeOffset: 33 * time.Second, PlannedVUs: 5},
{TimeOffset: 42 * time.Second, PlannedVUs: 4},
{TimeOffset: 50 * time.Second, PlannedVUs: 1},
{TimeOffset: 53 * time.Second, PlannedVUs: 0},
}, conf.GetExecutionRequirements(et))

// Try a longer GracefulStop than the GracefulRampDown
conf.GracefulStop = types.NullDurationFrom(80 * time.Second)
assert.Equal(t, []lib.ExecutionStep{
{TimeOffset: 0 * time.Second, PlannedVUs: 4},
{TimeOffset: 1 * time.Second, PlannedVUs: 5},
{TimeOffset: 2 * time.Second, PlannedVUs: 6},
{TimeOffset: 33 * time.Second, PlannedVUs: 5},
{TimeOffset: 42 * time.Second, PlannedVUs: 4},
{TimeOffset: 50 * time.Second, PlannedVUs: 1},
{TimeOffset: 103 * time.Second, PlannedVUs: 0},
}, conf.GetExecutionRequirements(et))

// Try a much shorter GracefulStop than the GracefulRampDown
conf.GracefulStop = types.NullDurationFrom(3 * time.Second)
assert.Equal(t, []lib.ExecutionStep{
{TimeOffset: 0 * time.Second, PlannedVUs: 4},
{TimeOffset: 1 * time.Second, PlannedVUs: 5},
{TimeOffset: 2 * time.Second, PlannedVUs: 6},
{TimeOffset: 26 * time.Second, PlannedVUs: 0},
}, conf.GetExecutionRequirements(et))

// Try a zero GracefulStop
conf.GracefulStop = types.NullDurationFrom(0 * time.Second)
assert.Equal(t, []lib.ExecutionStep{
{TimeOffset: 0 * time.Second, PlannedVUs: 4},
{TimeOffset: 1 * time.Second, PlannedVUs: 5},
{TimeOffset: 2 * time.Second, PlannedVUs: 6},
{TimeOffset: 23 * time.Second, PlannedVUs: 0},
}, conf.GetExecutionRequirements(et))

// Try a zero GracefulStop and GracefulRampDown, i.e. raw steps with 0 end cap
conf.GracefulRampDown = types.NullDurationFrom(0 * time.Second)
assert.Equal(t, rawStepsZeroEnd, conf.GetExecutionRequirements(et))
}
Loading

0 comments on commit edb8239

Please sign in to comment.