@@ -67,84 +67,6 @@ class RetrySpec extends BaseSpec {
6767 run(policy)(errorIO) must completeAs(expected)
6868 }
6969
70- " withErrorMatcher - retry only on matched errors" in ticked { implicit ticker =>
71- val maxRetries = 5
72- val delay = 1 .second
73-
74- val error = new Error1
75- val policy =
76- Retry .constantDelay[IO , Throwable ](delay).withMaxRetries(maxRetries).withErrorMatcher {
77- case _ : Error1 => IO .pure(true )
78- }
79-
80- val expected = List (
81- RetryAttempt (Status (0 , Duration .Zero ), Decision .retry(delay), error),
82- RetryAttempt (Status (1 , 1 .second), Decision .retry(delay), error),
83- RetryAttempt (Status (2 , 2 .seconds), Decision .retry(delay), error),
84- RetryAttempt (Status (3 , 3 .seconds), Decision .retry(delay), error),
85- RetryAttempt (Status (4 , 4 .seconds), Decision .retry(delay), error),
86- RetryAttempt (Status (5 , 5 .seconds), Decision .giveUp, error)
87- )
88-
89- run(policy)(IO .raiseError(error)) must completeAs(expected)
90- }
91-
92- " withErrorMatcher - give up on mismatched errors" in ticked { implicit ticker =>
93- val maxRetries = 5
94- val delay = 1 .second
95-
96- val policy =
97- Retry .constantDelay[IO , Throwable ](delay).withMaxRetries(maxRetries).withErrorMatcher {
98- case _ : Error1 => IO .pure(true )
99- }
100-
101- val expected = List (
102- RetryAttempt (Status (0 , Duration .Zero ), Decision .giveUp)
103- )
104-
105- run(policy)(errorIO) must completeAs(expected)
106- }
107-
108- " withErrorMatcher - keep the last matcher - give up on mismatched" in ticked { implicit t =>
109- val delay = 1 .second
110- val maxRetries = 1
111-
112- val policy =
113- Retry
114- .constantDelay[IO , Throwable ](delay)
115- .withMaxRetries(maxRetries)
116- .withErrorMatcher { case _ : Error1 => IO .pure(true ) }
117- .withErrorMatcher { case _ : Error2 => IO .pure(true ) }
118-
119- val error = new Error1
120- val expected = List (
121- RetryAttempt (Status (0 , Duration .Zero ), Decision .giveUp, error)
122- )
123-
124- run(policy)(IO .raiseError(error)) must completeAs(expected)
125- }
126-
127- " withErrorMatcher - keep the last matcher" in ticked { implicit ticker =>
128- val delay = 1 .second
129- val maxRetries = 2
130-
131- val policy =
132- Retry
133- .constantDelay[IO , Throwable ](delay)
134- .withMaxRetries(maxRetries)
135- .withErrorMatcher { case _ : Error1 => IO .pure(true ) }
136- .withErrorMatcher { case _ : Error2 => IO .pure(true ) }
137-
138- val error = new Error2
139- val expected = List (
140- RetryAttempt (Status (0 , Duration .Zero ), Decision .retry(delay), error),
141- RetryAttempt (Status (1 , 1 .second), Decision .retry(delay), error),
142- RetryAttempt (Status (2 , 2 .seconds), Decision .giveUp, error)
143- )
144-
145- run(policy)(IO .raiseError(error)) must completeAs(expected)
146- }
147-
14870 " withCappedDelay - cap the individual delay" in ticked { implicit ticker =>
14971 val maxRetries = 5
15072 val delay = 2 .second
@@ -270,6 +192,144 @@ class RetrySpec extends BaseSpec {
270192
271193 }
272194
195+ " Retry#withErrorMatcher" should {
196+
197+ " retry only on matched errors" in ticked { implicit ticker =>
198+ val maxRetries = 2
199+ val delay = 1 .second
200+
201+ val error = new Error1
202+ val policy =
203+ Retry
204+ .constantDelay[IO , Throwable ](delay)
205+ .withMaxRetries(maxRetries)
206+ .withErrorMatcher(Retry .ErrorMatcher [IO , Throwable ].only[Error1 ])
207+
208+ val expected = List (
209+ RetryAttempt (Status (0 , Duration .Zero ), Decision .retry(delay), error),
210+ RetryAttempt (Status (1 , 1 .second), Decision .retry(delay), error),
211+ RetryAttempt (Status (2 , 2 .seconds), Decision .giveUp, error)
212+ )
213+
214+ run(policy)(IO .raiseError(error)) must completeAs(expected)
215+ }
216+
217+ " give up on mismatched errors" in ticked { implicit ticker =>
218+ val maxRetries = 5
219+ val delay = 1 .second
220+
221+ val policy =
222+ Retry
223+ .constantDelay[IO , Throwable ](delay)
224+ .withMaxRetries(maxRetries)
225+ .withErrorMatcher(Retry .ErrorMatcher [IO , Throwable ].only[Error1 ])
226+
227+ val expected = List (
228+ RetryAttempt (Status (0 , Duration .Zero ), Decision .giveUp)
229+ )
230+
231+ run(policy)(errorIO) must completeAs(expected)
232+ }
233+
234+ " keep the last matcher - give up on mismatched" in ticked { implicit ticker =>
235+ val delay = 1 .second
236+ val maxRetries = 1
237+
238+ val policy =
239+ Retry
240+ .constantDelay[IO , Throwable ](delay)
241+ .withMaxRetries(maxRetries)
242+ .withErrorMatcher(Retry .ErrorMatcher [IO , Throwable ].only[Error1 ])
243+ .withErrorMatcher(Retry .ErrorMatcher [IO , Throwable ].only[Error2 ])
244+
245+ val error = new Error1
246+ val expected = List (
247+ RetryAttempt (Status (0 , Duration .Zero ), Decision .giveUp, error)
248+ )
249+
250+ run(policy)(IO .raiseError(error)) must completeAs(expected)
251+ }
252+
253+ " keep the last matcher - retry on matching errors" in ticked { implicit ticker =>
254+ val delay = 1 .second
255+ val maxRetries = 2
256+
257+ val policy =
258+ Retry
259+ .constantDelay[IO , Throwable ](delay)
260+ .withMaxRetries(maxRetries)
261+ .withErrorMatcher(Retry .ErrorMatcher [IO , Throwable ].only[Error1 ])
262+ .withErrorMatcher(Retry .ErrorMatcher [IO , Throwable ].only[Error2 ])
263+
264+ val error = new Error2
265+ val expected = List (
266+ RetryAttempt (Status (0 , Duration .Zero ), Decision .retry(delay), error),
267+ RetryAttempt (Status (1 , 1 .second), Decision .retry(delay), error),
268+ RetryAttempt (Status (2 , 2 .seconds), Decision .giveUp, error)
269+ )
270+
271+ run(policy)(IO .raiseError(error)) must completeAs(expected)
272+ }
273+
274+ " ErrorMatcher.except - give up on 'excepted' errors" in ticked { implicit ticker =>
275+ val maxRetries = 2
276+ val delay = 1 .second
277+
278+ val error = new Error1
279+ val policy =
280+ Retry
281+ .constantDelay[IO , Throwable ](delay)
282+ .withMaxRetries(maxRetries)
283+ .withErrorMatcher(Retry .ErrorMatcher [IO , Throwable ].except[Error1 ])
284+
285+ val expected = List (
286+ RetryAttempt (Status (0 , Duration .Zero ), Decision .giveUp, error)
287+ )
288+
289+ run(policy)(IO .raiseError(error)) must completeAs(expected)
290+ }
291+
292+ " ErrorMatcher.except - give up on subtypes" in ticked { implicit ticker =>
293+ val maxRetries = 2
294+ val delay = 1 .second
295+
296+ val error = new Error1
297+ val policy =
298+ Retry
299+ .constantDelay[IO , Throwable ](delay)
300+ .withMaxRetries(maxRetries)
301+ .withErrorMatcher(Retry .ErrorMatcher [IO , Throwable ].except[RuntimeException ])
302+
303+ val expected = List (
304+ RetryAttempt (Status (0 , Duration .Zero ), Decision .giveUp, error)
305+ )
306+
307+ run(policy)(IO .raiseError(error)) must completeAs(expected)
308+ }
309+
310+ " ErrorMatcher.except - recover on all errors but the 'excepted' one" in ticked {
311+ implicit ticker =>
312+ val maxRetries = 2
313+ val delay = 1 .second
314+
315+ val error = new Error2
316+ val policy =
317+ Retry
318+ .constantDelay[IO , Throwable ](delay)
319+ .withMaxRetries(maxRetries)
320+ .withErrorMatcher(Retry .ErrorMatcher [IO , Throwable ].except[Error1 ])
321+
322+ val expected = List (
323+ RetryAttempt (Status (0 , Duration .Zero ), Decision .retry(delay), error),
324+ RetryAttempt (Status (1 , 1 .second), Decision .retry(delay), error),
325+ RetryAttempt (Status (2 , 2 .seconds), Decision .giveUp, error)
326+ )
327+
328+ run(policy)(IO .raiseError(error)) must completeAs(expected)
329+ }
330+
331+ }
332+
273333 " Retry.exponentialBackoff" should {
274334 // it's not random :)
275335 val RandomNextDouble = 1.0
0 commit comments