@@ -257,6 +257,109 @@ final class RetryPolicyServiceTests: XCTestCase {
257257 let lastError = await errorContainer. getError ( )
258258 XCTAssertNotNil ( lastError)
259259 }
260+
261+ // MARK: Tests - Max Total Duration
262+
263+ func test_thatRetryThrowsTotalDurationExceededError_whenDeadlineIsExceeded( ) async throws {
264+ // given
265+ let slowService = RetryPolicyService (
266+ strategy: . constant( retry: 10 , duration: . milliseconds( 200 ) ) ,
267+ maxTotalDuration: . milliseconds( 300 )
268+ )
269+
270+ // when
271+ var receivedError : Error ?
272+ do {
273+ _ = try await slowService. retry {
274+ throw URLError ( . unknown)
275+ }
276+ } catch {
277+ receivedError = error
278+ }
279+
280+ // then
281+ XCTAssertEqual ( receivedError as? RetryPolicyError , . totalDurationExceeded)
282+ }
283+
284+ func test_thatRetrySucceeds_whenOperationCompletesBeforeDeadline( ) async throws {
285+ // given
286+ let expectedValue = 42
287+ let service = RetryPolicyService (
288+ strategy: . constant( retry: 5 , duration: . nanoseconds( 1 ) ) ,
289+ maxTotalDuration: . seconds( 5 )
290+ )
291+
292+ // when
293+ let result = try await service. retry {
294+ expectedValue
295+ }
296+
297+ // then
298+ XCTAssertEqual ( result, expectedValue)
299+ }
300+
301+ func test_thatRetrySucceedsAfterRetries_whenDeadlineIsNotExceeded( ) async throws {
302+ // given
303+ let counter = Counter ( )
304+ let expectedValue = 99
305+ let service = RetryPolicyService (
306+ strategy: . constant( retry: 5 , duration: . nanoseconds( 1 ) ) ,
307+ maxTotalDuration: . seconds( 5 )
308+ )
309+
310+ // when
311+ let result = try await service. retry {
312+ let count = await counter. increment ( )
313+ if count >= 3 { return expectedValue }
314+ throw URLError ( . unknown)
315+ }
316+
317+ // then
318+ XCTAssertEqual ( result, expectedValue)
319+ }
320+
321+ func test_thatRetryThrowsTotalDurationExceeded_notRetryLimitExceeded_whenDeadlineHitsFirst( ) async throws {
322+ // given
323+ let service = RetryPolicyService (
324+ strategy: . constant( retry: 100 , duration: . milliseconds( 100 ) ) ,
325+ maxTotalDuration: . milliseconds( 250 )
326+ )
327+
328+ // when
329+ var receivedError : Error ?
330+ do {
331+ _ = try await service. retry {
332+ throw URLError ( . unknown)
333+ }
334+ } catch {
335+ receivedError = error
336+ }
337+
338+ // then
339+ XCTAssertEqual ( receivedError as? RetryPolicyError , . totalDurationExceeded)
340+ XCTAssertNotEqual ( receivedError as? RetryPolicyError , . retryLimitExceeded)
341+ }
342+
343+ func test_thatRetryIgnoresDeadline_whenMaxTotalDurationIsNil( ) async throws {
344+ // given
345+ let counter = Counter ( )
346+ let service = RetryPolicyService (
347+ strategy: . constant( retry: . defaultRetryCount, duration: . nanoseconds( 1 ) ) ,
348+ maxTotalDuration: nil
349+ )
350+
351+ // when
352+ do {
353+ _ = try await service. retry {
354+ _ = await counter. increment ( )
355+ throw URLError ( . unknown)
356+ }
357+ } catch { }
358+
359+ // then
360+ let attempts = await counter. getValue ( )
361+ XCTAssertEqual ( attempts, . defaultRetryCount + 1 )
362+ }
260363}
261364
262365// MARK: - Counter
0 commit comments