package backoff import ( "math" "testing" "time" ) func TestBackOff(t *testing.T) { var ( testInitialInterval = 500 * time.Millisecond testRandomizationFactor = 0.1 testMultiplier = 2.0 testMaxInterval = 5 * time.Second ) exp := NewExponential() exp.InitialInterval = testInitialInterval exp.RandomizationFactor = testRandomizationFactor exp.Multiplier = testMultiplier exp.MaxInterval = testMaxInterval exp.Reset() var expectedResults = []time.Duration{500, 1000, 2000, 4000, 5000, 5000, 5000, 5000, 5000, 5000} for i, d := range expectedResults { expectedResults[i] = d * time.Millisecond } for _, expected := range expectedResults { assertEquals(t, expected, exp.currentInterval) // Assert that the next back off falls in the expected range. var minInterval = expected - time.Duration(testRandomizationFactor*float64(expected)) var maxInterval = expected + time.Duration(testRandomizationFactor*float64(expected)) var actualInterval = exp.GetSleepTime() if !(minInterval <= actualInterval && actualInterval <= maxInterval) { t.Error("error") } exp.IncrementCurrentInterval() } } func TestGetRandomizedInterval(t *testing.T) { // 33% chance of being 1. assertEquals(t, 1, getRandomValueFromInterval(0.5, 0, 2)) assertEquals(t, 1, getRandomValueFromInterval(0.5, 0.33, 2)) // 33% chance of being 2. assertEquals(t, 2, getRandomValueFromInterval(0.5, 0.34, 2)) assertEquals(t, 2, getRandomValueFromInterval(0.5, 0.66, 2)) // 33% chance of being 3. assertEquals(t, 3, getRandomValueFromInterval(0.5, 0.67, 2)) assertEquals(t, 3, getRandomValueFromInterval(0.5, 0.99, 2)) } type TestClock struct { i time.Duration start time.Time } func (c *TestClock) Now() time.Time { t := c.start.Add(c.i) c.i += time.Second return t } func TestBackOffOverflow(t *testing.T) { var ( testInitialInterval time.Duration = math.MaxInt64 / 2 testMaxInterval time.Duration = math.MaxInt64 testMultiplier float64 = 2.1 ) exp := NewExponential() exp.InitialInterval = testInitialInterval exp.Multiplier = testMultiplier exp.MaxInterval = testMaxInterval exp.Reset() exp.IncrementCurrentInterval() // Assert that when an overflow is possible the current varerval time.Duration is set to the max varerval time.Duration . assertEquals(t, testMaxInterval, exp.currentInterval) } func assertEquals(t *testing.T, expected, value time.Duration) { if expected != value { t.Errorf("got: %d, expected: %d", value, expected) } }