backoff_test.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. package core
  2. import (
  3. "fmt"
  4. "math"
  5. "testing"
  6. "time"
  7. )
  8. // If given New with 0's and no jitter, ensure that certain invariants are met:
  9. //
  10. // - the default max duration and interval should be used
  11. // - noJitter should be true
  12. // - the RNG should not be initialised
  13. // - the first duration should be equal to the default interval
  14. func TestDefaults(t *testing.T) {
  15. b := NewWithoutJitter(0, 0)
  16. if b.maxDuration != DefaultMaxDuration {
  17. t.Fatalf("expected new backoff to use the default max duration (%s), but have %s", DefaultMaxDuration, b.maxDuration)
  18. }
  19. if b.interval != DefaultInterval {
  20. t.Fatalf("exepcted new backoff to use the default interval (%s), but have %s", DefaultInterval, b.interval)
  21. }
  22. if b.noJitter != true {
  23. t.Fatal("backoff should have been initialised without jitter")
  24. }
  25. dur := b.Duration()
  26. if dur != DefaultInterval {
  27. t.Fatalf("expected first duration to be %s, have %s", DefaultInterval, dur)
  28. }
  29. }
  30. // Given a zero-value initialised Backoff, it should be transparently
  31. // setup.
  32. func TestSetup(t *testing.T) {
  33. b := new(Backoff)
  34. dur := b.Duration()
  35. if dur < 0 || dur > (5*time.Minute) {
  36. t.Fatalf("want duration between 0 and 5 minutes, have %s", dur)
  37. }
  38. }
  39. // Ensure that tries incremenets as expected.
  40. func TestTries(t *testing.T) {
  41. b := NewWithoutJitter(5, 1)
  42. for i := uint64(0); i < 3; i++ {
  43. if b.n != i {
  44. t.Fatalf("want tries=%d, have tries=%d", i, b.n)
  45. }
  46. pow := 1 << i
  47. expected := time.Duration(pow)
  48. dur := b.Duration()
  49. if dur != expected {
  50. t.Fatalf("want duration=%d, have duration=%d at i=%d", expected, dur, i)
  51. }
  52. }
  53. for i := uint(3); i < 5; i++ {
  54. dur := b.Duration()
  55. if dur != 5 {
  56. t.Fatalf("want duration=5, have %d at i=%d", dur, i)
  57. }
  58. }
  59. }
  60. // Ensure that a call to Reset will actually reset the Backoff.
  61. func TestReset(t *testing.T) {
  62. const iter = 10
  63. b := New(1000, 1)
  64. for i := 0; i < iter; i++ {
  65. _ = b.Duration()
  66. }
  67. if b.n != iter {
  68. t.Fatalf("expected tries=%d, have tries=%d", iter, b.n)
  69. }
  70. b.Reset()
  71. if b.n != 0 {
  72. t.Fatalf("expected tries=0 after reset, have tries=%d", b.n)
  73. }
  74. }
  75. const decay = 5 * time.Millisecond
  76. const max = 10 * time.Millisecond
  77. const interval = time.Millisecond
  78. func TestDecay(t *testing.T) {
  79. const iter = 10
  80. b := NewWithoutJitter(max, 1)
  81. b.SetDecay(decay)
  82. var backoff time.Duration
  83. for i := 0; i < iter; i++ {
  84. backoff = b.Duration()
  85. }
  86. if b.n != iter {
  87. t.Fatalf("expected tries=%d, have tries=%d", iter, b.n)
  88. }
  89. // Don't decay below backoff
  90. b.lastTry = time.Now().Add(-backoff + 1)
  91. backoff = b.Duration()
  92. if b.n != iter+1 {
  93. t.Fatalf("expected tries=%d, have tries=%d", iter+1, b.n)
  94. }
  95. // Reset after backoff + decay
  96. b.lastTry = time.Now().Add(-backoff - decay)
  97. b.Duration()
  98. if b.n != 1 {
  99. t.Fatalf("expected tries=%d, have tries=%d", 1, b.n)
  100. }
  101. }
  102. // Ensure that decay works even if the retry counter is saturated.
  103. func TestDecaySaturation(t *testing.T) {
  104. b := NewWithoutJitter(1<<2, 1)
  105. b.SetDecay(decay)
  106. var duration time.Duration
  107. for i := 0; i <= 2; i++ {
  108. duration = b.Duration()
  109. }
  110. if duration != 1<<2 {
  111. t.Fatalf("expected duration=%v, have duration=%v", 1<<2, duration)
  112. }
  113. b.lastTry = time.Now().Add(-duration - decay)
  114. b.n = math.MaxUint64
  115. duration = b.Duration()
  116. if duration != 1 {
  117. t.Errorf("expected duration=%v, have duration=%v", 1, duration)
  118. }
  119. }
  120. func ExampleBackoff_SetDecay() {
  121. b := NewWithoutJitter(max, interval)
  122. b.SetDecay(decay)
  123. // try 0
  124. fmt.Println(b.Duration())
  125. // try 1
  126. fmt.Println(b.Duration())
  127. // try 2
  128. duration := b.Duration()
  129. fmt.Println(duration)
  130. // try 3, below decay
  131. time.Sleep(duration)
  132. duration = b.Duration()
  133. fmt.Println(duration)
  134. // try 4, resets
  135. time.Sleep(duration + decay)
  136. fmt.Println(b.Duration())
  137. // Output: 1ms
  138. // 2ms
  139. // 4ms
  140. // 8ms
  141. // 1ms
  142. }