github.com/ydb-platform/ydb-go-sdk/v3@v3.57.0/internal/backoff/backoff_test.go (about) 1 package backoff 2 3 import ( 4 "fmt" 5 "strconv" 6 "testing" 7 "time" 8 9 "github.com/stretchr/testify/require" 10 ) 11 12 func TestDelays(t *testing.T) { 13 duration := func(s string) (d time.Duration) { 14 d, err := time.ParseDuration(s) 15 if err != nil { 16 panic(err) 17 } 18 19 return d 20 } 21 b := New( 22 WithSlotDuration(duration("500ms")), 23 WithCeiling(6), 24 WithJitterLimit(1), 25 WithSeed(0), 26 ) 27 for i, d := range map[int]time.Duration{ 28 0: duration("500ms"), 29 1: duration("1s"), 30 2: duration("2s"), 31 3: duration("4s"), 32 4: duration("8s"), 33 5: duration("16s"), 34 6: duration("32s"), 35 7: duration("32s"), 36 8: duration("32s"), 37 } { 38 t.Run(fmt.Sprintf("%v -> %v", i, d), func(t *testing.T) { 39 require.Equal(t, d, b.Delay(i)) 40 }) 41 } 42 } 43 44 func TestLogBackoff(t *testing.T) { 45 type exp struct { 46 eq time.Duration 47 gte time.Duration 48 lte time.Duration 49 } 50 for _, tt := range []struct { 51 backoff Backoff 52 exp []exp 53 seeds int64 54 }{ 55 { 56 backoff: New( 57 WithSlotDuration(time.Second), 58 WithCeiling(3), 59 WithJitterLimit(0), 60 WithSeed(0), 61 ), 62 exp: []exp{ 63 {gte: 0, lte: time.Second}, 64 {gte: 0, lte: 2 * time.Second}, 65 {gte: 0, lte: 4 * time.Second}, 66 {gte: 0, lte: 8 * time.Second}, 67 {gte: 0, lte: 8 * time.Second}, 68 {gte: 0, lte: 8 * time.Second}, 69 {gte: 0, lte: 8 * time.Second}, 70 }, 71 seeds: 1000, 72 }, 73 { 74 backoff: New( 75 WithSlotDuration(time.Second), 76 WithCeiling(3), 77 WithJitterLimit(0.5), 78 WithSeed(0), 79 ), 80 exp: []exp{ 81 {gte: 500 * time.Millisecond, lte: time.Second}, 82 {gte: 1 * time.Second, lte: 2 * time.Second}, 83 {gte: 2 * time.Second, lte: 4 * time.Second}, 84 {gte: 4 * time.Second, lte: 8 * time.Second}, 85 {gte: 4 * time.Second, lte: 8 * time.Second}, 86 {gte: 4 * time.Second, lte: 8 * time.Second}, 87 {gte: 4 * time.Second, lte: 8 * time.Second}, 88 }, 89 seeds: 1000, 90 }, 91 { 92 backoff: New( 93 WithSlotDuration(time.Second), 94 WithCeiling(3), 95 WithJitterLimit(1), 96 WithSeed(0), 97 ), 98 exp: []exp{ 99 {eq: time.Second}, 100 {eq: 2 * time.Second}, 101 {eq: 4 * time.Second}, 102 {eq: 8 * time.Second}, 103 {eq: 8 * time.Second}, 104 {eq: 8 * time.Second}, 105 {eq: 8 * time.Second}, 106 }, 107 }, 108 { 109 backoff: New( 110 WithSlotDuration(time.Second), 111 WithCeiling(6), 112 WithJitterLimit(1), 113 WithSeed(0), 114 ), 115 exp: []exp{ 116 {eq: time.Second}, 117 {eq: 2 * time.Second}, 118 {eq: 4 * time.Second}, 119 {eq: 8 * time.Second}, 120 {eq: 16 * time.Second}, 121 {eq: 32 * time.Second}, 122 {eq: 64 * time.Second}, 123 {eq: 64 * time.Second}, 124 {eq: 64 * time.Second}, 125 {eq: 64 * time.Second}, 126 {eq: 64 * time.Second}, 127 {eq: 64 * time.Second}, 128 }, 129 }, 130 } { 131 t.Run("", func(t *testing.T) { 132 if tt.seeds == 0 { 133 tt.seeds = 1 134 } 135 for seed := int64(0); seed < tt.seeds; seed++ { 136 for n, exp := range tt.exp { 137 act := tt.backoff.Delay(n) 138 if eq := exp.eq; eq != 0 { 139 if eq != act { 140 t.Fatalf( 141 "unexpected Backoff delay: %s; want %s", 142 act, eq, 143 ) 144 } 145 146 continue 147 } 148 if gte := exp.gte; act <= gte { 149 t.Errorf( 150 "unexpected Backoff delay: %s; want >= %s", 151 act, gte, 152 ) 153 } 154 if lte := exp.lte; act >= lte { 155 t.Errorf( 156 "unexpected Backoff delay: %s; want <= %s", 157 act, lte, 158 ) 159 } 160 } 161 } 162 }) 163 } 164 } 165 166 func TestFastSlowDelaysWithoutJitter(t *testing.T) { 167 for _, tt := range []struct { 168 name string 169 backoff Backoff 170 exp []time.Duration 171 }{ 172 { 173 name: "FastBackoff", 174 backoff: func() (backoff logBackoff) { 175 backoff = Fast 176 backoff.jitterLimit = 1 177 178 return backoff 179 }(), 180 exp: []time.Duration{ 181 5 * time.Millisecond, 182 10 * time.Millisecond, 183 20 * time.Millisecond, 184 40 * time.Millisecond, 185 80 * time.Millisecond, 186 160 * time.Millisecond, 187 320 * time.Millisecond, 188 320 * time.Millisecond, 189 320 * time.Millisecond, 190 320 * time.Millisecond, 191 320 * time.Millisecond, 192 }, 193 }, 194 { 195 name: "SlowBackoff", 196 backoff: func() (backoff logBackoff) { 197 backoff = Slow 198 backoff.jitterLimit = 1 199 200 return backoff 201 }(), 202 exp: []time.Duration{ 203 time.Second, 204 2 * time.Second, 205 4 * time.Second, 206 8 * time.Second, 207 16 * time.Second, 208 32 * time.Second, 209 64 * time.Second, 210 64 * time.Second, 211 64 * time.Second, 212 64 * time.Second, 213 64 * time.Second, 214 }, 215 }, 216 } { 217 t.Run(tt.name, func(t *testing.T) { 218 for n, exp := range tt.exp { 219 t.Run("delay#"+strconv.Itoa(n), func(t *testing.T) { 220 act := tt.backoff.Delay(n) 221 require.Equal(t, exp, act) 222 }) 223 } 224 }) 225 } 226 }