Skip to content

Commit

Permalink
add more tests
Browse files Browse the repository at this point in the history
  • Loading branch information
bojand committed Oct 24, 2020
1 parent 946c6d7 commit bd4670e
Show file tree
Hide file tree
Showing 5 changed files with 230 additions and 27 deletions.
8 changes: 4 additions & 4 deletions load/pacer.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ type ConstantPacer struct {
}

// String returns a pretty-printed description of the ConstantPacer's behaviour:
// ConstantPacer{Freq: 1} => Constant{1 hits/1s}
// ConstantPacer{Freq: 1} => Constant{1 hits / 1s}
func (cp *ConstantPacer) String() string {
return fmt.Sprintf("Constant{%d hits/1s}", cp.Freq)
return fmt.Sprintf("Constant{%d hits / 1s}", cp.Freq)
}

// Pace determines the length of time to sleep until the next hit is sent.
Expand Down Expand Up @@ -258,9 +258,9 @@ func (p *StepPacer) hits(t time.Duration) float64 {
}

// String returns a pretty-printed description of the StepPacer's behaviour:
// StepPacer{Step: 1, StepDuration: 5s} => Step{1 hits/5s}
// StepPacer{Step: 1, StepDuration: 5s} => Step{Step:1 hits/5s}
func (p *StepPacer) String() string {
return fmt.Sprintf("Step{%d hits/%s}", p.Step, p.StepDuration.String())
return fmt.Sprintf("Step{Step: %d hits / %s}", p.Step, p.StepDuration.String())
}

// LinearPacer paces an attack by starting at a given request rate
Expand Down
98 changes: 80 additions & 18 deletions load/pacer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ func TestConstantPacer(t *testing.T) {

for _, tc := range []struct {
freq uint64
max uint64
elapsed time.Duration
hits uint64
wait time.Duration
Expand Down Expand Up @@ -108,8 +109,25 @@ func TestConstantPacer(t *testing.T) {
wait: 0,
stop: false,
},
// Max
{
freq: 1,
elapsed: 1 * time.Second,
hits: 10,
wait: 10 * time.Second,
stop: false,
max: 0,
},
{
freq: 1,
elapsed: 1 * time.Second,
hits: 10,
wait: 0,
stop: true,
max: 7,
},
} {
cp := ConstantPacer{Freq: tc.freq}
cp := ConstantPacer{Freq: tc.freq, Max: tc.max}
wait, stop := cp.Pace(tc.elapsed, tc.hits)
assert.Equal(t, tc.wait, wait)
assert.Equal(t, tc.stop, stop)
Expand Down Expand Up @@ -141,22 +159,10 @@ func TestConstantPacer_Rate(t *testing.T) {
}
}

// Stolen from https://github.com/google/go-cmp/cmp/cmpopts/equate.go
// to avoid an unwieldy dependency. Both fraction and margin set at 1e-6.
func floatEqual(x, y float64) bool {
relMarg := 1e-6 * math.Min(math.Abs(x), math.Abs(y))
return math.Abs(x-y) <= math.Max(1e-6, relMarg)
}

// A similar function to the above because SinePacer.Pace has discrete
// inputs and outputs but uses floats internally, and sometimes the
// floating point imprecision leaks out :-(
func durationEqual(x, y time.Duration) bool {
diff := x - y
if diff < 0 {
diff = -diff
}
return diff <= time.Microsecond
func TestConstantPacer_String(t *testing.T) {
cp := ConstantPacer{Freq: 5}
actual := cp.String()
assert.Equal(t, "Constant{5 hits / 1s}", actual)
}

func TestLinearPacer(t *testing.T) {
Expand Down Expand Up @@ -772,6 +778,7 @@ func TestStepPacer(t *testing.T) {
stepDuration time.Duration
stop uint64
stopDuration time.Duration
max uint64
// params
elapsed time.Duration
hits uint64
Expand Down Expand Up @@ -1003,10 +1010,36 @@ func TestStepPacer(t *testing.T) {
wait: 100 * time.Millisecond,
stopResult: false,
},
// Max
{
start: 5,
step: 5,
stepDuration: 5 * time.Second,
stop: 25,
stopDuration: 0 * time.Second,
max: 100,
elapsed: 5000 * time.Millisecond,
hits: 25,
wait: 100 * time.Millisecond,
stopResult: false,
},
{
start: 5,
step: 5,
stepDuration: 5 * time.Second,
stop: 25,
max: 10,
stopDuration: 0 * time.Second,
elapsed: 5000 * time.Millisecond,
hits: 25,
wait: 0,
stopResult: true,
},
} {
t.Run(strconv.Itoa(ti), func(t *testing.T) {
p := StepPacer{
Start: ConstantPacer{Freq: tc.start},
Start: ConstantPacer{Freq: tc.start, Max: tc.max},
Max: tc.max,
Step: tc.step, StepDuration: tc.stepDuration,
LoadDuration: tc.stopDuration, Stop: ConstantPacer{Freq: tc.stop}}

Expand All @@ -1017,3 +1050,32 @@ func TestStepPacer(t *testing.T) {
})
}
}

func TestStepPacer_String(t *testing.T) {
p := StepPacer{
Start: ConstantPacer{Freq: 5, Max: 100},
Max: 100,
Step: 2, StepDuration: 5 * time.Second,
LoadDuration: 25 * time.Second, Stop: ConstantPacer{Freq: 25}}

actual := p.String()
assert.Equal(t, "Step{Step: 2 hits / 5s}", actual)
}

// Stolen from https://github.com/google/go-cmp/cmp/cmpopts/equate.go
// to avoid an unwieldy dependency. Both fraction and margin set at 1e-6.
func floatEqual(x, y float64) bool {
relMarg := 1e-6 * math.Min(math.Abs(x), math.Abs(y))
return math.Abs(x-y) <= math.Max(1e-6, relMarg)
}

// A similar function to the above because SinePacer.Pace has discrete
// inputs and outputs but uses floats internally, and sometimes the
// floating point imprecision leaks out :-(
func durationEqual(x, y time.Duration) bool {
diff := x - y
if diff < 0 {
diff = -diff
}
return diff <= time.Microsecond
}
25 changes: 21 additions & 4 deletions load/worker_ticker.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ type WorkerTicker interface {
// TickValue is the delta value
type TickValue struct {
Delta int
Done bool
}

// ConstWorkerTicker is the const worker
Expand Down Expand Up @@ -69,15 +70,31 @@ func (c *StepWorkerTicker) Run() {

go func() {
for range ticker.C {
// we have load duration and we eclipsed it
if c.LoadDuration > 0 && time.Since(begin) > c.LoadDuration {
if c.Stop > 0 {
c.C <- TickValue{Delta: int(c.Stop - uint(wc))}
if stepUp && c.Stop > 0 && c.Stop > uint(wc) {
// if we have step up and stop value is > current count
// send the final diff
c.C <- TickValue{Delta: int(c.Stop - uint(wc)), Done: true}
} else if !stepUp && c.Stop > 0 && c.Stop < uint(wc) {
// if we have step down and stop value is < current count
// send the final diff
c.C <- TickValue{Delta: int(c.Stop - uint(wc)), Done: true}
} else {
// send done signal
c.C <- TickValue{Delta: 0, Done: true}
}

done <- true
return
} else if (c.Stop > 0 && stepUp && wc >= int(c.Stop)) ||
(!stepUp && wc <= int(c.Stop)) || wc <= 0 {
} else if (c.LoadDuration == 0) && ((c.Stop > 0 && stepUp && wc >= int(c.Stop)) ||
(!stepUp && wc <= int(c.Stop))) {
// we do not have load duration
// if we have stop and are step up and current count >= stop
// or if we have stop and are step down and current count <= stop
// send done signal

c.C <- TickValue{Delta: 0, Done: true}
done <- true
return
} else {
Expand Down
124 changes: 124 additions & 0 deletions load/worker_ticker_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package load

import (
"testing"
"time"

"github.com/stretchr/testify/assert"
)

func TestConstWorkerTicker(t *testing.T) {
wt := ConstWorkerTicker{N: 5, C: make(chan TickValue)}
defer wt.Finish()

wct := wt.Ticker()

assert.NotNil(t, wct)

go func() {
wt.Run()
}()

tv := <-wct

assert.NotEmpty(t, tv)
assert.Equal(t, 5, tv.Delta)
}

func TestStepWorkerTicker(t *testing.T) {
t.Parallel()

t.Run("step increase load duration", func(t *testing.T) {
wt := StepWorkerTicker{
C: make(chan TickValue),
Start: 5,
Step: 2,
Stop: 0,
StepDuration: 2 * time.Second,
LoadDuration: 5 * time.Second,
}

defer wt.Finish()

wct := wt.Ticker()

assert.NotNil(t, wct)

go func() {
wt.Run()
}()

tv := <-wct
assert.NotEmpty(t, tv)
assert.Equal(t, 5, tv.Delta)
assert.False(t, tv.Done)

start := time.Now()
tv = <-wct
end := time.Since(start)
assert.NotEmpty(t, tv)
assert.Equal(t, 2, tv.Delta)
assert.False(t, tv.Done)
expected := 2 * time.Second
assert.True(t, durationEqual(expected, end.Round(time.Second)), "expected %s to equal %s", expected, end)

tv = <-wct
end = time.Since(start)
assert.NotEmpty(t, tv)
assert.Equal(t, 2, tv.Delta)
assert.False(t, tv.Done)
assert.True(t, durationEqual(2*expected, end.Round(time.Second)), "expected %s to equal %s", expected, end)

tv = <-wct
assert.Equal(t, 0, tv.Delta)
assert.True(t, tv.Done)
})

t.Run("step increase load duration with stop", func(t *testing.T) {
wt := StepWorkerTicker{
C: make(chan TickValue),
Start: 5,
Step: 2,
Stop: 15,
StepDuration: 2 * time.Second,
LoadDuration: 5 * time.Second,
}

defer wt.Finish()

wct := wt.Ticker()

assert.NotNil(t, wct)

go func() {
wt.Run()
}()

tv := <-wct
assert.NotEmpty(t, tv)
assert.Equal(t, 5, tv.Delta)
assert.False(t, tv.Done)

start := time.Now()
tv = <-wct
end := time.Since(start)
assert.NotEmpty(t, tv)
assert.Equal(t, 2, tv.Delta)
assert.False(t, tv.Done)
expected := 2 * time.Second
assert.True(t, durationEqual(expected, end.Round(time.Second)), "expected %s to equal %s", expected, end)

tv = <-wct
end = time.Since(start)
assert.NotEmpty(t, tv)
assert.Equal(t, 2, tv.Delta)
assert.False(t, tv.Done)
assert.True(t, durationEqual(2*expected, end.Round(time.Second)), "expected %s to equal %s", expected, end)

tv = <-wct
end = time.Since(start)
assert.Equal(t, 6, tv.Delta)
assert.True(t, tv.Done)
assert.True(t, durationEqual(3*expected, end.Round(time.Second)), "expected %s to equal %s", expected, end)
})
}
2 changes: 1 addition & 1 deletion runner/requester.go
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ func (b *Requester) runWorkers(wt load.WorkerTicker, p load.Pacer) error {
errC <- w.runWorker()
}()
}
} else {
} else if tv.Delta < 0 {
nd := -1 * tv.Delta
wm.Lock()
wdc := 0
Expand Down

0 comments on commit bd4670e

Please sign in to comment.