@@ -633,6 +633,52 @@ func BenchmarkDoWithDataNoErrors(b *testing.B) {
633633 }
634634}
635635
636+ type attemptsForErrorTestError struct {}
637+
638+ func (attemptsForErrorTestError ) Error () string { return "test error" }
639+
640+ func TestAttemptsForErrorNoDelayAfterFinalAttempt (t * testing.T ) {
641+ var count uint64
642+ var timestamps []time.Time
643+
644+ startTime := time .Now ()
645+
646+ err := Do (
647+ func () error {
648+ count ++
649+ timestamps = append (timestamps , time .Now ())
650+ return attemptsForErrorTestError {}
651+ },
652+ Attempts (3 ),
653+ Delay (200 * time .Millisecond ),
654+ DelayType (FixedDelay ),
655+ AttemptsForError (2 , attemptsForErrorTestError {}),
656+ LastErrorOnly (true ),
657+ Context (context .Background ()),
658+ )
659+
660+ endTime := time .Now ()
661+
662+ assert .Error (t , err )
663+ assert .Equal (t , uint64 (2 ), count , "should attempt exactly 2 times" )
664+ assert .Len (t , timestamps , 2 , "should have 2 timestamps" )
665+
666+ // Verify timing: first attempt at ~0ms, second at ~200ms, end immediately after second attempt
667+ firstAttemptTime := timestamps [0 ].Sub (startTime )
668+ secondAttemptTime := timestamps [1 ].Sub (startTime )
669+ totalTime := endTime .Sub (startTime )
670+
671+ // First attempt should be immediate
672+ assert .Less (t , firstAttemptTime , 50 * time .Millisecond , "first attempt should be immediate" )
673+
674+ // Second attempt should be after delay
675+ assert .Greater (t , secondAttemptTime , 150 * time .Millisecond , "second attempt should be after delay" )
676+ assert .Less (t , secondAttemptTime , 250 * time .Millisecond , "second attempt should not be too delayed" )
677+
678+ // Total time should not include delay after final attempt
679+ assert .Less (t , totalTime , 300 * time .Millisecond , "should not delay after final attempt" )
680+ }
681+
636682func TestOnRetryNotCalledOnLastAttempt (t * testing.T ) {
637683 callCount := 0
638684 onRetryCalls := make ([]uint , 0 )
0 commit comments