1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
|
package waiter
import (
mathrand "math/rand"
"strings"
"testing"
"time"
"github.com/aws/smithy-go/rand"
)
func TestComputeDelay(t *testing.T) {
cases := map[string]struct {
totalAttempts int64
minDelay time.Duration
maxDelay time.Duration
maxWaitTime time.Duration
expectedMaxDelays []time.Duration
expectedError string
expectedMinAttempts int
}{
"standard": {
totalAttempts: 8,
minDelay: 2 * time.Second,
maxDelay: 120 * time.Second,
maxWaitTime: 300 * time.Second,
expectedMaxDelays: []time.Duration{2, 4, 8, 16, 32, 64, 120, 120},
expectedMinAttempts: 8,
},
"zero minDelay": {
totalAttempts: 3,
minDelay: 0,
maxDelay: 120 * time.Second,
maxWaitTime: 300 * time.Second,
expectedError: "minDelay must be greater than zero",
},
"zero maxDelay": {
totalAttempts: 3,
minDelay: 10 * time.Second,
maxDelay: 0,
maxWaitTime: 300 * time.Second,
expectedError: "maxDelay must be greater than zero",
},
"zero remaining time": {
totalAttempts: 3,
minDelay: 10 * time.Second,
maxDelay: 20 * time.Second,
maxWaitTime: 0,
expectedMaxDelays: []time.Duration{0},
expectedMinAttempts: 1,
},
"max wait time is less than min delay": {
totalAttempts: 3,
minDelay: 10 * time.Second,
maxDelay: 20 * time.Second,
maxWaitTime: 5 * time.Second,
expectedMaxDelays: []time.Duration{0},
expectedMinAttempts: 1,
},
"large minDelay": {
totalAttempts: 80,
minDelay: 150 * time.Minute,
maxDelay: 200 * time.Minute,
maxWaitTime: 250 * time.Minute,
expectedMinAttempts: 1,
},
"large maxDelay": {
totalAttempts: 80,
minDelay: 15 * time.Minute,
maxDelay: 2000 * time.Minute,
maxWaitTime: 250 * time.Minute,
expectedMinAttempts: 5,
},
}
for name, c := range cases {
t.Run(name, func(t *testing.T) {
// mock smithy-go rand/#Reader
r := rand.Reader
defer func() {
rand.Reader = r
}()
rand.Reader = mathrand.New(mathrand.NewSource(1))
// mock waiter call
delays, err := mockwait(c.totalAttempts, c.minDelay, c.maxDelay, c.maxWaitTime)
if len(c.expectedError) != 0 {
if err == nil {
t.Fatalf("expected error, got none")
}
if e, a := c.expectedError, err.Error(); !strings.Contains(a, e) {
t.Fatalf("expected error %v, got %v instead", e, a)
}
} else if err != nil {
t.Fatalf("expected no error, got %v", err)
}
if e, a := c.expectedMinAttempts, len(delays); e > a {
t.Logf("%v", delays)
t.Fatalf("expected minimum attempts to be %v, got %v", e, a)
}
for i, expectedDelay := range c.expectedMaxDelays {
if e, a := expectedDelay*time.Second, delays[i]; e < a {
t.Fatalf("attempt %d : expected delay to be less than %v, got %v", i+1, e, a)
}
if e, a := c.minDelay, delays[i]; e > a && c.maxWaitTime > c.minDelay {
t.Fatalf("attempt %d : expected delay to be more than %v, got %v", i+1, e, a)
}
}
t.Logf("delays : %v", delays)
})
}
}
func mockwait(maxAttempts int64, minDelay, maxDelay, maxWaitTime time.Duration) ([]time.Duration, error) {
delays := make([]time.Duration, 0)
remainingTime := maxWaitTime
var attempt int64
for {
attempt++
if maxAttempts < attempt {
break
}
delay, err := ComputeDelay(attempt, minDelay, maxDelay, remainingTime)
if err != nil {
return delays, err
}
delays = append(delays, delay)
remainingTime -= delay
if remainingTime < minDelay {
break
}
}
return delays, nil
}
|