Skip to content

Commit 626f9af

Browse files
committed
test: create RetryMiddlewareTest
1 parent 3bed2b6 commit 626f9af

File tree

1 file changed

+117
-0
lines changed

1 file changed

+117
-0
lines changed
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* Copyright (c) 2024 Kai Sassnowski
7+
*
8+
* For the full copyright and license information, please view
9+
* the LICENSE file that was distributed with this source code.
10+
*
11+
* @see https://github.com/roach-php/roach
12+
*/
13+
14+
namespace RoachPHP\Tests\Downloader\Middleware;
15+
16+
use PHPUnit\Framework\TestCase;
17+
use RoachPHP\Downloader\Middleware\RetryMiddleware;
18+
use RoachPHP\Scheduling\ArrayRequestScheduler;
19+
use RoachPHP\Scheduling\Timing\ClockInterface;
20+
use RoachPHP\Scheduling\Timing\FakeClock;
21+
use RoachPHP\Testing\Concerns\InteractsWithRequestsAndResponses;
22+
use RoachPHP\Testing\FakeLogger;
23+
24+
final class RetryMiddlewareTest extends TestCase
25+
{
26+
use InteractsWithRequestsAndResponses;
27+
28+
private RetryMiddleware $middleware;
29+
30+
private ArrayRequestScheduler $scheduler;
31+
32+
private FakeLogger $logger;
33+
34+
protected function setUp(): void
35+
{
36+
$this->scheduler = new ArrayRequestScheduler($this->createMock(ClockInterface::class));
37+
$this->logger = new FakeLogger();
38+
$this->middleware = new RetryMiddleware($this->scheduler, $this->logger);
39+
}
40+
41+
public function testDoesNotRetrySuccessfulResponse(): void
42+
{
43+
$response = $this->makeResponse(status: 200);
44+
$this->middleware->configure([]);
45+
46+
$result = $this->middleware->handleResponse($response);
47+
48+
self::assertSame($response, $result);
49+
self::assertFalse($result->wasDropped());
50+
self::assertCount(0, $this->scheduler->forceNextRequests(10));
51+
}
52+
53+
public function testDoesNotRetryNonRetryableErrorResponse(): void
54+
{
55+
$response = $this->makeResponse(status: 404);
56+
$this->middleware->configure(['retryOnStatus' => [500]]);
57+
58+
$result = $this->middleware->handleResponse($response);
59+
60+
self::assertSame($response, $result);
61+
self::assertFalse($result->wasDropped());
62+
self::assertCount(0, $this->scheduler->forceNextRequests(10));
63+
}
64+
65+
public function testRetriesARetryableResponse(): void
66+
{
67+
$request = $this->makeRequest('https://example.com');
68+
$response = $this->makeResponse(request: $request, status: 503);
69+
$this->middleware->configure([
70+
'retryOnStatus' => [503],
71+
'maxRetries' => 2,
72+
'initialDelay' => 500,
73+
]);
74+
75+
$result = $this->middleware->handleResponse($response);
76+
77+
self::assertTrue($result->wasDropped());
78+
79+
$retriedRequests = $this->scheduler->forceNextRequests(10);
80+
self::assertCount(1, $retriedRequests);
81+
82+
$retriedRequest = $retriedRequests[0];
83+
self::assertSame(1, $retriedRequest->getMeta('retry_count'));
84+
self::assertSame('https://example.com', $retriedRequest->getUri());
85+
self::assertSame(500, $retriedRequest->getOptions()['delay']);
86+
}
87+
88+
public function testStopsRetryingAfterMaxRetries(): void
89+
{
90+
$request = $this->makeRequest()->withMeta('retry_count', 3);
91+
$response = $this->makeResponse(request: $request, status: 500);
92+
$this->middleware->configure(['maxRetries' => 3]);
93+
94+
$result = $this->middleware->handleResponse($response);
95+
96+
self::assertSame($response, $result);
97+
self::assertFalse($result->wasDropped());
98+
self::assertCount(0, $this->scheduler->forceNextRequests(10));
99+
}
100+
101+
public function testCalculatesExponentialBackoffCorrectly(): void
102+
{
103+
$request = $this->makeRequest()->withMeta('retry_count', 2);
104+
$response = $this->makeResponse(request: $request, status: 500);
105+
$this->middleware->configure([
106+
'initialDelay' => 1000, // 1s
107+
'delayMultiplier' => 2.0,
108+
]);
109+
110+
$this->middleware->handleResponse($response);
111+
112+
// initialDelay * (delayMultiplier ^ retry_count)
113+
// 1000 * (2.0 ^ 2) = 1000 * 4 = 4000ms
114+
$retriedRequest = $this->scheduler->forceNextRequests(10)[0];
115+
self::assertSame(4000, $retriedRequest->getOptions()['delay']);
116+
}
117+
}

0 commit comments

Comments
 (0)