diff options
| author | Murilo Ijanc <[email protected]> | 2026-07-26 14:58:55 -0300 |
|---|---|---|
| committer | Murilo Ijanc <[email protected]> | 2026-07-26 14:58:55 -0300 |
| commit | 64764fb9fac0227f8e0443e7c7519d73aec275b9 (patch) | |
| tree | cb4fc56eeb6ecce53854f9c530609cf01ab3349f /tests/TransportTest.php | |
| download | php-0.1.0.tar.gz | |
Initial importv0.1.0
Diffstat (limited to 'tests/TransportTest.php')
| -rw-r--r-- | tests/TransportTest.php | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/tests/TransportTest.php b/tests/TransportTest.php new file mode 100644 index 0000000..da467a1 --- /dev/null +++ b/tests/TransportTest.php @@ -0,0 +1,141 @@ +<?php + +declare(strict_types=1); + +namespace Cepis\Tests; + +use Cepis\CepNotFoundException; +use Cepis\Client; +use Cepis\CurlTransport; +use Cepis\NetworkException; +use Cepis\RateLimitedException; +use Cepis\Response; +use Cepis\ServerErrorException; + +/** + * The transport seam is the extension point a WordPress plugin uses to route + * requests through `wp_remote_get`, so it gets tested the same way the rest + * does: a real implementation against the real test server. + */ +final class TransportTest extends ServerTestCase +{ + public function testDefaultTransportIsCurl(): void + { + self::assertInstanceOf(CurlTransport::class, (new Client())->transport); + } + + public function testAnAlternativeTransportIsUsedEndToEnd(): void + { + $client = new Client(baseUrl: $this->server->url, transport: new StreamTransport()); + $this->server->respond('/01001000', [self::json(self::SE_ADDRESS)]); + + $address = $client->lookup('01001000'); + + self::assertSame('São Paulo', $address->localidade); + self::assertSame(1, $this->server->countCalls('/01001000')); + } + + public function testTheClientSendsItsIdentifyingHeaders(): void + { + $transport = new RecordingTransport([new Response(200, [], '{"cep":"01001000"}')]); + $client = new Client(baseUrl: 'https://example.invalid', timeout: 3.5, transport: $transport); + + $client->lookup('01001000'); + + self::assertSame('https://example.invalid/01001000', $transport->calls[0]['url']); + self::assertStringContainsString('cepis-php/', $transport->calls[0]['headers']['User-Agent']); + self::assertArrayHasKey('Accept', $transport->calls[0]['headers']); + self::assertSame(3.5, $transport->calls[0]['timeout']); + } + + public function testATransportThrowingNetworkExceptionIsRetried(): void + { + $transport = new RecordingTransport([]); + $client = new Client( + baseUrl: 'https://example.invalid', + maxAttempts: 3, + backoffBase: 0.001, + backoffMax: 0.01, + transport: $transport, + ); + + try { + $client->lookup('01001000'); + self::fail('expected NetworkException'); + } catch (NetworkException) { + self::assertCount(3, $transport->calls); + } + } + + public function testATransportReturningA503IsRetriedNotThrown(): void + { + $transport = new RecordingTransport([ + new Response(503, [], '{}'), + new Response(503, [], '{}'), + new Response(200, [], json_encode(self::SE_ADDRESS, JSON_THROW_ON_ERROR)), + ]); + $client = new Client( + baseUrl: 'https://example.invalid', + backoffBase: 0.001, + backoffMax: 0.01, + transport: $transport, + ); + + self::assertSame('São Paulo', $client->lookup('01001000')->localidade); + self::assertCount(3, $transport->calls); + } + + public function testA404FromATransportIsNotRetried(): void + { + $transport = new RecordingTransport([new Response(404, [], '{}')]); + $client = new Client(baseUrl: 'https://example.invalid', transport: $transport); + + try { + $client->lookup('99999999'); + self::fail('expected CepNotFoundException'); + } catch (CepNotFoundException) { + self::assertCount(1, $transport->calls); + } + } + + public function testRetryAfterIsReadFromATransportSuppliedHeader(): void + { + $transport = new RecordingTransport([new Response(429, ['retry-after' => ['5']], '{}')]); + $client = new Client( + baseUrl: 'https://example.invalid', + maxAttempts: 1, + transport: $transport, + ); + + try { + $client->lookup('01001000'); + self::fail('expected RateLimitedException'); + } catch (RateLimitedException $exception) { + self::assertEqualsWithDelta(5.0, $exception->retryAfter, 1e-9); + } + } + + public function testResponseHeaderLookupIsCaseInsensitiveAndTakesListValues(): void + { + $response = new Response(200, ['Retry-After' => '7', 'X-Multi' => ['a', 'b']], ''); + + self::assertSame('7', $response->header('retry-after')); + self::assertSame('7', $response->header('RETRY-AFTER')); + self::assertSame('a', $response->header('x-multi')); + self::assertNull($response->header('absent')); + } + + public function testServerErrorStillSurfacesThroughAnAlternativeTransport(): void + { + $client = new Client( + baseUrl: $this->server->url, + backoffBase: 0.001, + backoffMax: 0.01, + transport: new StreamTransport(), + ); + $this->server->respond('/01001000', [self::raw(500, '{}')]); + + $this->expectException(ServerErrorException::class); + $client->lookup('01001000'); + } +} |