backoffhandler_test.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. package retry
  2. import (
  3. "context"
  4. "testing"
  5. "time"
  6. )
  7. func immediateTimeAfter(time.Duration) <-chan time.Time {
  8. c := make(chan time.Time, 1)
  9. c <- time.Now()
  10. return c
  11. }
  12. func TestBackoffRetries(t *testing.T) {
  13. ctx := context.Background()
  14. // make backoff return immediately
  15. backoff := BackoffHandler{maxRetries: 3, Clock: Clock{time.Now, immediateTimeAfter}}
  16. if !backoff.Backoff(ctx) {
  17. t.Fatalf("backoff failed immediately")
  18. }
  19. if !backoff.Backoff(ctx) {
  20. t.Fatalf("backoff failed after 1 retry")
  21. }
  22. if !backoff.Backoff(ctx) {
  23. t.Fatalf("backoff failed after 2 retry")
  24. }
  25. if backoff.Backoff(ctx) {
  26. t.Fatalf("backoff allowed after 3 (max) retries")
  27. }
  28. }
  29. func TestBackoffCancel(t *testing.T) {
  30. ctx, cancelFunc := context.WithCancel(context.Background())
  31. // prevent backoff from returning normally
  32. after := func(time.Duration) <-chan time.Time { return make(chan time.Time) }
  33. backoff := BackoffHandler{maxRetries: 3, Clock: Clock{time.Now, after}}
  34. cancelFunc()
  35. if backoff.Backoff(ctx) {
  36. t.Fatalf("backoff allowed after cancel")
  37. }
  38. if _, ok := backoff.GetMaxBackoffDuration(ctx); ok {
  39. t.Fatalf("backoff allowed after cancel")
  40. }
  41. }
  42. func TestBackoffGracePeriod(t *testing.T) {
  43. ctx := context.Background()
  44. currentTime := time.Now()
  45. // make Clock.Now return whatever we like
  46. now := func() time.Time { return currentTime }
  47. // make backoff return immediately
  48. backoff := BackoffHandler{maxRetries: 1, Clock: Clock{now, immediateTimeAfter}}
  49. if !backoff.Backoff(ctx) {
  50. t.Fatalf("backoff failed immediately")
  51. }
  52. // the next call to Backoff would fail unless it's after the grace period
  53. gracePeriod := backoff.SetGracePeriod()
  54. // advance time to after the grace period, which at most will be 8 seconds, but we will advance +1 second.
  55. currentTime = currentTime.Add(gracePeriod + time.Second)
  56. if !backoff.Backoff(ctx) {
  57. t.Fatalf("backoff failed after the grace period expired")
  58. }
  59. // confirm we ignore grace period after backoff
  60. if backoff.Backoff(ctx) {
  61. t.Fatalf("backoff allowed after 1 (max) retry")
  62. }
  63. }
  64. func TestGetMaxBackoffDurationRetries(t *testing.T) {
  65. ctx := context.Background()
  66. // make backoff return immediately
  67. backoff := BackoffHandler{maxRetries: 3, Clock: Clock{time.Now, immediateTimeAfter}}
  68. if _, ok := backoff.GetMaxBackoffDuration(ctx); !ok {
  69. t.Fatalf("backoff failed immediately")
  70. }
  71. backoff.Backoff(ctx) // noop
  72. if _, ok := backoff.GetMaxBackoffDuration(ctx); !ok {
  73. t.Fatalf("backoff failed after 1 retry")
  74. }
  75. backoff.Backoff(ctx) // noop
  76. if _, ok := backoff.GetMaxBackoffDuration(ctx); !ok {
  77. t.Fatalf("backoff failed after 2 retry")
  78. }
  79. backoff.Backoff(ctx) // noop
  80. if _, ok := backoff.GetMaxBackoffDuration(ctx); ok {
  81. t.Fatalf("backoff allowed after 3 (max) retries")
  82. }
  83. if backoff.Backoff(ctx) {
  84. t.Fatalf("backoff allowed after 3 (max) retries")
  85. }
  86. }
  87. func TestGetMaxBackoffDuration(t *testing.T) {
  88. ctx := context.Background()
  89. // make backoff return immediately
  90. backoff := BackoffHandler{maxRetries: 3, Clock: Clock{time.Now, immediateTimeAfter}}
  91. if duration, ok := backoff.GetMaxBackoffDuration(ctx); !ok || duration > time.Second*2 {
  92. t.Fatalf("backoff (%s) didn't return < 2 seconds on first retry", duration)
  93. }
  94. backoff.Backoff(ctx) // noop
  95. if duration, ok := backoff.GetMaxBackoffDuration(ctx); !ok || duration > time.Second*4 {
  96. t.Fatalf("backoff (%s) didn't return < 4 seconds on second retry", duration)
  97. }
  98. backoff.Backoff(ctx) // noop
  99. if duration, ok := backoff.GetMaxBackoffDuration(ctx); !ok || duration > time.Second*8 {
  100. t.Fatalf("backoff (%s) didn't return < 8 seconds on third retry", duration)
  101. }
  102. backoff.Backoff(ctx) // noop
  103. if duration, ok := backoff.GetMaxBackoffDuration(ctx); ok || duration != 0 {
  104. t.Fatalf("backoff (%s) didn't return 0 seconds on fourth retry (exceeding limit)", duration)
  105. }
  106. }
  107. func TestBackoffRetryForever(t *testing.T) {
  108. ctx := context.Background()
  109. // make backoff return immediately
  110. backoff := BackoffHandler{maxRetries: 3, retryForever: true, Clock: Clock{time.Now, immediateTimeAfter}}
  111. if duration, ok := backoff.GetMaxBackoffDuration(ctx); !ok || duration > time.Second*2 {
  112. t.Fatalf("backoff (%s) didn't return < 2 seconds on first retry", duration)
  113. }
  114. backoff.Backoff(ctx) // noop
  115. if duration, ok := backoff.GetMaxBackoffDuration(ctx); !ok || duration > time.Second*4 {
  116. t.Fatalf("backoff (%s) didn't return < 4 seconds on second retry", duration)
  117. }
  118. backoff.Backoff(ctx) // noop
  119. if duration, ok := backoff.GetMaxBackoffDuration(ctx); !ok || duration > time.Second*8 {
  120. t.Fatalf("backoff (%s) didn't return < 8 seconds on third retry", duration)
  121. }
  122. if !backoff.Backoff(ctx) {
  123. t.Fatalf("backoff refused on fourth retry despire RetryForever")
  124. }
  125. if duration, ok := backoff.GetMaxBackoffDuration(ctx); !ok || duration > time.Second*16 {
  126. t.Fatalf("backoff returned %v instead of 8 seconds on fourth retry", duration)
  127. }
  128. if !backoff.Backoff(ctx) {
  129. t.Fatalf("backoff refused on fifth retry despire RetryForever")
  130. }
  131. if duration, ok := backoff.GetMaxBackoffDuration(ctx); !ok || duration > time.Second*16 {
  132. t.Fatalf("backoff returned %v instead of 8 seconds on fifth retry", duration)
  133. }
  134. }