@@ -138,6 +138,104 @@ void testFixedDelayStrategy() {
138138 assertFalse (decision3 .shouldRetry ());
139139 }
140140
141+ @ Test
142+ void linearBackoff_withCustomDelays_shouldIncreaseByIncrement () {
143+ var strategy = RetryStrategies .linearBackoff (5 , Duration .ofSeconds (2 ), Duration .ofSeconds (3 ));
144+
145+ var decision1 = strategy .makeRetryDecision (new RuntimeException ("test" ), 1 );
146+ var decision2 = strategy .makeRetryDecision (new RuntimeException ("test" ), 2 );
147+ var decision3 = strategy .makeRetryDecision (new RuntimeException ("test" ), 3 );
148+ var decision4 = strategy .makeRetryDecision (new RuntimeException ("test" ), 4 );
149+
150+ assertTrue (decision1 .shouldRetry ());
151+ assertEquals (Duration .ofSeconds (2 ), decision1 .delay ());
152+
153+ assertTrue (decision2 .shouldRetry ());
154+ assertEquals (Duration .ofSeconds (5 ), decision2 .delay ());
155+
156+ assertTrue (decision3 .shouldRetry ());
157+ assertEquals (Duration .ofSeconds (8 ), decision3 .delay ());
158+
159+ assertTrue (decision4 .shouldRetry ());
160+ assertEquals (Duration .ofSeconds (11 ), decision4 .delay ());
161+ }
162+
163+ @ Test
164+ void linearPreset_shouldUseOneThroughFiveSecondDelays () {
165+ var strategy = RetryStrategies .Presets .LINEAR ;
166+
167+ for (int attempt = 1 ; attempt <= 5 ; attempt ++) {
168+ var decision = strategy .makeRetryDecision (new RuntimeException ("test" ), attempt );
169+
170+ assertTrue (decision .shouldRetry (), "Should retry on attempt " + attempt );
171+ assertEquals (Duration .ofSeconds (attempt ), decision .delay ());
172+ }
173+
174+ var finalDecision = strategy .makeRetryDecision (new RuntimeException ("test" ), 6 );
175+ assertFalse (finalDecision .shouldRetry ());
176+ }
177+
178+ @ Test
179+ void linearBackoff_shouldStopAtMaxAttempts () {
180+ var strategy = RetryStrategies .linearBackoff (3 , Duration .ofSeconds (1 ), Duration .ofSeconds (1 ));
181+
182+ var decision1 = strategy .makeRetryDecision (new RuntimeException ("test" ), 1 );
183+ var decision2 = strategy .makeRetryDecision (new RuntimeException ("test" ), 2 );
184+ var decision3 = strategy .makeRetryDecision (new RuntimeException ("test" ), 3 );
185+
186+ assertTrue (decision1 .shouldRetry ());
187+ assertTrue (decision2 .shouldRetry ());
188+ assertFalse (decision3 .shouldRetry ());
189+ }
190+
191+ @ Test
192+ void linearBackoff_withInvalidMaxAttempts_shouldThrow () {
193+ var exception = assertThrows (
194+ IllegalArgumentException .class ,
195+ () -> RetryStrategies .linearBackoff (0 , Duration .ofSeconds (1 ), Duration .ofSeconds (1 )));
196+
197+ assertTrue (exception .getMessage ().contains ("maxAttempts" ));
198+ assertTrue (exception .getMessage ().contains ("positive" ));
199+ }
200+
201+ @ Test
202+ void linearBackoff_withSubSecondInitialDelay_shouldThrow () {
203+ var exception = assertThrows (
204+ IllegalArgumentException .class ,
205+ () -> RetryStrategies .linearBackoff (3 , Duration .ofMillis (500 ), Duration .ofSeconds (1 )));
206+
207+ assertTrue (exception .getMessage ().contains ("initialDelay" ));
208+ assertTrue (exception .getMessage ().contains ("at least 1 second" ));
209+ }
210+
211+ @ Test
212+ void linearBackoff_withNullInitialDelay_shouldThrow () {
213+ var exception = assertThrows (
214+ IllegalArgumentException .class , () -> RetryStrategies .linearBackoff (3 , null , Duration .ofSeconds (1 )));
215+
216+ assertTrue (exception .getMessage ().contains ("initialDelay" ));
217+ assertTrue (exception .getMessage ().contains ("cannot be null" ));
218+ }
219+
220+ @ Test
221+ void linearBackoff_withSubSecondIncrement_shouldThrow () {
222+ var exception = assertThrows (
223+ IllegalArgumentException .class ,
224+ () -> RetryStrategies .linearBackoff (3 , Duration .ofSeconds (1 ), Duration .ofMillis (500 )));
225+
226+ assertTrue (exception .getMessage ().contains ("increment" ));
227+ assertTrue (exception .getMessage ().contains ("at least 1 second" ));
228+ }
229+
230+ @ Test
231+ void linearBackoff_withNullIncrement_shouldThrow () {
232+ var exception = assertThrows (
233+ IllegalArgumentException .class , () -> RetryStrategies .linearBackoff (3 , Duration .ofSeconds (1 ), null ));
234+
235+ assertTrue (exception .getMessage ().contains ("increment" ));
236+ assertTrue (exception .getMessage ().contains ("cannot be null" ));
237+ }
238+
141239 @ Test
142240 void testInvalidParameters () {
143241 assertThrows (
0 commit comments