backoffhandler_test.go 4.7 KB

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