@@ -10,6 +10,8 @@ import (
10
10
"sync/atomic"
11
11
"testing"
12
12
"time"
13
+
14
+ "github.com/hashicorp/terraform-provider-aws/internal/backoff"
13
15
)
14
16
15
17
// fastFixedInterval returns a very small fixed interval to speed tests.
@@ -322,3 +324,103 @@ func TestWaitForStatus_UnexpectedStateErrorMessage(t *testing.T) {
322
324
t .Errorf ("error message should contain allowed state 'PENDING', got: %s" , errMsg )
323
325
}
324
326
}
327
+
328
+ func TestBackoffInterval (t * testing.T ) {
329
+ t .Parallel ()
330
+
331
+ tests := []struct {
332
+ name string
333
+ delay backoff.Delay
334
+ attempts []uint
335
+ expectedDurations []time.Duration
336
+ }{
337
+ {
338
+ name : "fixed delay" ,
339
+ delay : backoff .FixedDelay (100 * time .Millisecond ),
340
+ attempts : []uint {0 , 1 , 2 , 3 },
341
+ expectedDurations : []time.Duration {0 , 100 * time .Millisecond , 100 * time .Millisecond , 100 * time .Millisecond },
342
+ },
343
+ {
344
+ name : "zero delay" ,
345
+ delay : backoff .ZeroDelay ,
346
+ attempts : []uint {0 , 1 , 2 },
347
+ expectedDurations : []time.Duration {0 , 0 , 0 },
348
+ },
349
+ }
350
+
351
+ for _ , tt := range tests {
352
+ t .Run (tt .name , func (t * testing.T ) {
353
+ t .Parallel ()
354
+
355
+ interval := BackoffInterval {delay : tt .delay }
356
+
357
+ for i , attempt := range tt .attempts {
358
+ got := interval .NextPoll (attempt )
359
+ want := tt .expectedDurations [i ]
360
+ if got != want {
361
+ t .Errorf ("NextPoll(%d) = %v, want %v" , attempt , got , want )
362
+ }
363
+ }
364
+ })
365
+ }
366
+ }
367
+
368
+ func TestWithBackoffDelay (t * testing.T ) {
369
+ t .Parallel ()
370
+
371
+ delay := backoff .FixedDelay (50 * time .Millisecond )
372
+ interval := WithBackoffDelay (delay )
373
+
374
+ // Verify it implements IntervalStrategy
375
+ var _ IntervalStrategy = interval
376
+
377
+ // Test that it wraps the delay correctly
378
+ if got := interval .NextPoll (0 ); got != 0 {
379
+ t .Errorf ("NextPoll(0) = %v, want 0" , got )
380
+ }
381
+ if got := interval .NextPoll (1 ); got != 50 * time .Millisecond {
382
+ t .Errorf ("NextPoll(1) = %v, want 50ms" , got )
383
+ }
384
+ }
385
+
386
+ func TestBackoffIntegration (t * testing.T ) {
387
+ t .Parallel ()
388
+
389
+ ctx := makeCtx (t )
390
+
391
+ var callCount atomic.Int32
392
+ fetch := func (context.Context ) (FetchResult [string ], error ) {
393
+ count := callCount .Add (1 )
394
+ switch count {
395
+ case 1 :
396
+ return FetchResult [string ]{Status : "CREATING" , Value : "attempt1" }, nil
397
+ case 2 :
398
+ return FetchResult [string ]{Status : "AVAILABLE" , Value : "success" }, nil
399
+ default :
400
+ t .Errorf ("unexpected call count: %d" , count )
401
+ return FetchResult [string ]{}, errors .New ("too many calls" )
402
+ }
403
+ }
404
+
405
+ opts := Options [string ]{
406
+ Timeout : 2 * time .Second ,
407
+ Interval : WithBackoffDelay (backoff .FixedDelay (fastFixedInterval )),
408
+ SuccessStates : []Status {"AVAILABLE" },
409
+ TransitionalStates : []Status {"CREATING" },
410
+ }
411
+
412
+ result , err := WaitForStatus (ctx , fetch , opts )
413
+ if err != nil {
414
+ t .Fatalf ("WaitForStatus() error = %v" , err )
415
+ }
416
+
417
+ if result .Status != "AVAILABLE" {
418
+ t .Errorf ("result.Status = %q, want %q" , result .Status , "AVAILABLE" )
419
+ }
420
+ if result .Value != "success" {
421
+ t .Errorf ("result.Value = %q, want %q" , result .Value , "success" )
422
+ }
423
+ if callCount .Load () != 2 {
424
+ t .Errorf ("expected 2 fetch calls, got %d" , callCount .Load ())
425
+ }
426
+ }
0 commit comments