diff --git a/src/Downloader/Downloader.php b/src/Downloader/Downloader.php index 940d7ed..05e9bf3 100644 --- a/src/Downloader/Downloader.php +++ b/src/Downloader/Downloader.php @@ -13,6 +13,9 @@ namespace RoachPHP\Downloader; +use Exception; +use RoachPHP\Events\ExceptionReceived; +use RoachPHP\Events\ExceptionReceiving; use RoachPHP\Events\RequestDropped; use RoachPHP\Events\RequestSending; use RoachPHP\Events\ResponseDropped; @@ -20,6 +23,7 @@ use RoachPHP\Events\ResponseReceiving; use RoachPHP\Http\ClientInterface; use RoachPHP\Http\Request; +use RoachPHP\Http\RequestException; use RoachPHP\Http\Response; use Symfony\Component\EventDispatcher\EventDispatcherInterface; @@ -53,44 +57,48 @@ public function scheduledRequests(): int return \count($this->requests); } - public function prepare(Request $request): void + public function prepare(Request $request, ?callable $onRejected = null): void { - foreach ($this->middleware as $middleware) { - $request = $middleware->handleRequest($request); + try { + foreach ($this->middleware as $middleware) { + $request = $middleware->handleRequest($request); + + if ($request->wasDropped()) { + $this->eventDispatcher->dispatch( + new RequestDropped($request), + RequestDropped::NAME, + ); + + return; + } + } + + /** + * @psalm-suppress UnnecessaryVarAnnotation + * + * @var RequestSending $event + */ + $event = $this->eventDispatcher->dispatch( + new RequestSending($request), + RequestSending::NAME, + ); - if ($request->wasDropped()) { + if ($event->request->wasDropped()) { $this->eventDispatcher->dispatch( - new RequestDropped($request), + new RequestDropped($event->request), RequestDropped::NAME, ); return; } - } - - /** - * @psalm-suppress UnnecessaryVarAnnotation - * - * @var RequestSending $event - */ - $event = $this->eventDispatcher->dispatch( - new RequestSending($request), - RequestSending::NAME, - ); - if ($event->request->wasDropped()) { - $this->eventDispatcher->dispatch( - new RequestDropped($event->request), - RequestDropped::NAME, - ); - - return; + $this->requests[] = $event->request; + } catch (Exception $exception) { + $this->onExceptionReceived(new RequestException($request, $exception), $onRejected); } - - $this->requests[] = $event->request; } - public function flush(?callable $callback = null): void + public function flush(?callable $onFullFilled = null, ?callable $onRejected = null): void { $requests = $this->requests; @@ -98,7 +106,7 @@ public function flush(?callable $callback = null): void foreach ($requests as $key => $request) { if ($request->getResponse() !== null) { - $this->onResponseReceived($request->getResponse(), $callback); + $this->onResponseReceived($request->getResponse(), $onFullFilled); unset($requests[$key]); } @@ -108,9 +116,15 @@ public function flush(?callable $callback = null): void return; } - $this->client->pool(\array_values($requests), function (Response $response) use ($callback): void { - $this->onResponseReceived($response, $callback); - }); + $this->client->pool( + \array_values($requests), + function (Response $response) use ($onFullFilled): void { + $this->onResponseReceived($response, $onFullFilled); + }, + function (RequestException $requestException) use ($onRejected): void { + $this->onExceptionReceived($requestException, $onRejected); + } + ); } private function onResponseReceived(Response $response, ?callable $callback): void @@ -158,4 +172,28 @@ private function onResponseReceived(Response $response, ?callable $callback): vo $callback($response); } } + + private function onExceptionReceived(RequestException $requestException, ?callable $callback): void + { + $this->eventDispatcher->dispatch( + new ExceptionReceiving($requestException), + ExceptionReceiving::NAME, + ); + + foreach ($this->middleware as $middleware) { + $requestException = $middleware->handleException($requestException); + } + + $this->eventDispatcher->dispatch( + new ExceptionReceived($requestException), + ExceptionReceived::NAME, + ); + + if (null !== $callback) { + $callback($requestException); + + } else if (!$requestException->isHandled()) { + throw $requestException; + } + } } diff --git a/src/Downloader/DownloaderMiddlewareInterface.php b/src/Downloader/DownloaderMiddlewareInterface.php index 834359a..3e520fa 100644 --- a/src/Downloader/DownloaderMiddlewareInterface.php +++ b/src/Downloader/DownloaderMiddlewareInterface.php @@ -13,9 +13,10 @@ namespace RoachPHP\Downloader; +use RoachPHP\Downloader\Middleware\ExceptionMiddlewareInterface; use RoachPHP\Downloader\Middleware\RequestMiddlewareInterface; use RoachPHP\Downloader\Middleware\ResponseMiddlewareInterface; -interface DownloaderMiddlewareInterface extends RequestMiddlewareInterface, ResponseMiddlewareInterface +interface DownloaderMiddlewareInterface extends RequestMiddlewareInterface, ResponseMiddlewareInterface, ExceptionMiddlewareInterface { } diff --git a/src/Downloader/Middleware/DownloaderMiddlewareAdapter.php b/src/Downloader/Middleware/DownloaderMiddlewareAdapter.php index cb7219a..b270e25 100644 --- a/src/Downloader/Middleware/DownloaderMiddlewareAdapter.php +++ b/src/Downloader/Middleware/DownloaderMiddlewareAdapter.php @@ -13,8 +13,10 @@ namespace RoachPHP\Downloader\Middleware; +use Exception; use RoachPHP\Downloader\DownloaderMiddlewareInterface; use RoachPHP\Http\Request; +use RoachPHP\Http\RequestException; use RoachPHP\Http\Response; /** @@ -23,12 +25,12 @@ final class DownloaderMiddlewareAdapter implements DownloaderMiddlewareInterface { private function __construct( - private RequestMiddlewareInterface|ResponseMiddlewareInterface $middleware, + private RequestMiddlewareInterface|ResponseMiddlewareInterface|ExceptionMiddlewareInterface $middleware, ) { } public static function fromMiddleware( - RequestMiddlewareInterface|ResponseMiddlewareInterface $middleware, + RequestMiddlewareInterface|ResponseMiddlewareInterface|ExceptionMiddlewareInterface $middleware, ): DownloaderMiddlewareInterface { if ($middleware instanceof DownloaderMiddlewareInterface) { return $middleware; @@ -55,12 +57,21 @@ public function handleResponse(Response $response): Response return $response; } + public function handleException(RequestException $requestException): RequestException + { + if ($this->middleware instanceof ExceptionMiddlewareInterface) { + return $this->middleware->handleException($requestException); + } + + return $requestException; + } + public function configure(array $options): void { $this->middleware->configure($options); } - public function getMiddleware(): RequestMiddlewareInterface|ResponseMiddlewareInterface + public function getMiddleware(): RequestMiddlewareInterface|ResponseMiddlewareInterface|ExceptionMiddlewareInterface { return $this->middleware; } diff --git a/src/Downloader/Middleware/ExceptionMiddlewareInterface.php b/src/Downloader/Middleware/ExceptionMiddlewareInterface.php new file mode 100644 index 0000000..a36561b --- /dev/null +++ b/src/Downloader/Middleware/ExceptionMiddlewareInterface.php @@ -0,0 +1,13 @@ +exceptionsHandled[] = $requestException->getReason(); + + if (null !== $this->exceptionHandler) { + return ($this->exceptionHandler)($requestException); + } + + return $requestException; + } + public function assertRequestHandled(Request $request): void { Assert::assertContains($request, $this->requestsHandled); @@ -97,4 +118,19 @@ public function assertNoResponseHandled(): void { Assert::assertEmpty($this->responsesHandled); } + + public function assertExceptionHandled(Exception $exception): void + { + Assert::assertContains($exception, $this->exceptionsHandled); + } + + public function assertExceptionNotHandled(Exception $exception): void + { + Assert::assertNotContains($exception, $this->exceptionsHandled); + } + + public function assertNoExceptionHandled(): void + { + Assert::assertEmpty($this->exceptionsHandled); + } } diff --git a/src/Events/ExceptionReceived.php b/src/Events/ExceptionReceived.php new file mode 100644 index 0000000..8226ffc --- /dev/null +++ b/src/Events/ExceptionReceived.php @@ -0,0 +1,17 @@ + ['onRequestDropped', 100], ItemScraped::NAME => ['onItemScraped', 100], ItemDropped::NAME => ['onItemDropped', 100], + ExceptionReceived::NAME => ['onExceptionReceived', 100], ]; } @@ -81,4 +83,11 @@ public function onItemDropped(ItemDropped $event): void 'reason' => $event->item->getDropReason(), ]); } + + public function onExceptionReceived(ExceptionReceived $event): void + { + $this->logger->warning('Exception received', [ + 'exception' => $event->exception, + ]); + } } diff --git a/src/Http/FakeClient.php b/src/Http/FakeClient.php index cccd65a..0c99145 100644 --- a/src/Http/FakeClient.php +++ b/src/Http/FakeClient.php @@ -13,6 +13,8 @@ namespace RoachPHP\Http; +use GuzzleHttp\Exception\BadResponseException; +use GuzzleHttp\Exception\GuzzleException; use GuzzleHttp\Psr7\Response as GuzzleResponse; use PHPUnit\Framework\Assert; @@ -26,11 +28,22 @@ final class FakeClient implements ClientInterface */ private array $sentRequestUrls = []; + /** + * @var array + */ + private array $failingRequests = []; + public function pool(array $requests, ?callable $onFulfilled = null, ?callable $onRejected = null): void { foreach ($requests as $request) { $this->sentRequestUrls[] = $request->getUri(); + if (null !== $onRejected && in_array($request, $this->failingRequests)) { + $exception = new RequestException($request, new FakeGuzzleException()); + + $onRejected($exception); + } + if (null !== $onFulfilled) { $response = new Response(new GuzzleResponse(), $request); @@ -39,6 +52,13 @@ public function pool(array $requests, ?callable $onFulfilled = null, ?callable $ } } + public function makeRequestsFail(Request ...$request): static + { + $this->failingRequests = $request; + + return $this; + } + public function assertRequestWasSent(Request $request): void { $uri = $request->getUri(); diff --git a/src/Http/FakeGuzzleException.php b/src/Http/FakeGuzzleException.php new file mode 100644 index 0000000..85e50aa --- /dev/null +++ b/src/Http/FakeGuzzleException.php @@ -0,0 +1,12 @@ +request; } - public function getReason(): GuzzleException + public function getReason(): GuzzleException|\Exception { return $this->reason; } + + public function isHandled(): bool + { + return $this->handled; + } + + public function setHandled(): self + { + $this->handled = true; + + return $this; + } } diff --git a/tests/Downloader/DownloaderMiddlewareAdapterTest.php b/tests/Downloader/DownloaderMiddlewareAdapterTest.php index a2886e5..ed70e8d 100644 --- a/tests/Downloader/DownloaderMiddlewareAdapterTest.php +++ b/tests/Downloader/DownloaderMiddlewareAdapterTest.php @@ -13,12 +13,14 @@ namespace RoachPHP\Tests\Downloader; +use Exception; use PHPUnit\Framework\TestCase; use RoachPHP\Downloader\DownloaderMiddlewareInterface; use RoachPHP\Downloader\Middleware\DownloaderMiddlewareAdapter; use RoachPHP\Downloader\Middleware\RequestMiddlewareInterface; use RoachPHP\Downloader\Middleware\ResponseMiddlewareInterface; use RoachPHP\Http\Request; +use RoachPHP\Http\RequestException; use RoachPHP\Http\Response; use RoachPHP\Support\Configurable; use RoachPHP\Testing\Concerns\InteractsWithRequestsAndResponses; @@ -44,6 +46,11 @@ public function handleResponse(Response $response): Response { return $response; } + + public function handleException(RequestException $requestException): RequestException + { + return $requestException; + } }; $class = DownloaderMiddlewareAdapter::fromMiddleware($middleware); diff --git a/tests/Downloader/DownloaderTest.php b/tests/Downloader/DownloaderTest.php index f36dfa0..47b0b69 100644 --- a/tests/Downloader/DownloaderTest.php +++ b/tests/Downloader/DownloaderTest.php @@ -13,9 +13,12 @@ namespace RoachPHP\Tests\Downloader; +use Exception; use PHPUnit\Framework\TestCase; use RoachPHP\Downloader\Downloader; use RoachPHP\Downloader\Middleware\FakeMiddleware; +use RoachPHP\Events\ExceptionReceived; +use RoachPHP\Events\ExceptionReceiving; use RoachPHP\Events\FakeDispatcher; use RoachPHP\Events\RequestDropped; use RoachPHP\Events\RequestSending; @@ -24,6 +27,7 @@ use RoachPHP\Events\ResponseReceiving; use RoachPHP\Http\FakeClient; use RoachPHP\Http\Request; +use RoachPHP\Http\RequestException; use RoachPHP\Http\Response; use RoachPHP\Testing\Concerns\InteractsWithRequestsAndResponses; @@ -52,8 +56,8 @@ public function testSendRequests(): void $requestA = $this->makeRequest('::url-a::'); $requestB = $this->makeRequest('::url-a::'); - $this->downloader->prepare($requestA); - $this->downloader->prepare($requestB); + $this->downloader->prepare($requestA, null); + $this->downloader->prepare($requestB, null); $this->downloader->flush(); $this->client->assertRequestWasSent($requestA); @@ -69,7 +73,7 @@ public function testPassRequestsThroughRequestHandlersInOrder(): void $this->downloader ->withMiddleware($middlewareA, $middlewareB) - ->prepare($initialRequest); + ->prepare($initialRequest, null); $middlewareA->assertRequestHandled($initialRequest); $middlewareB->assertRequestHandled($middlewareARequest); @@ -83,7 +87,7 @@ public function testDoesNotPassOnRequestIfDroppedByMiddleware(): void $this->downloader ->withMiddleware($dropMiddleware, $middleware) - ->prepare($initialRequest); + ->prepare($initialRequest, null); $dropMiddleware->assertRequestHandled($initialRequest); $middleware->assertNoRequestsHandled(); @@ -96,7 +100,7 @@ public function testDoesNotSendRequestIfDroppedByMiddleware(): void $this->downloader ->withMiddleware($dropMiddleware) - ->prepare($request); + ->prepare($request, null); $this->downloader->flush(); $this->client->assertRequestWasNotSent($request); @@ -111,7 +115,7 @@ public function testSendResponsesThroughMiddlewareInOrder(): void $middlewareC = new FakeMiddleware(); $this->downloader->withMiddleware($middlewareA, $middlewareB, $middlewareC); - $this->downloader->prepare($this->makeRequest()); + $this->downloader->prepare($this->makeRequest(), null); $this->downloader->flush(); $middlewareB->assertResponseHandled($middlewareAResponse); @@ -124,7 +128,7 @@ public function testDontPassOnResponseIfDroppedByMiddleware(): void $middleware = new FakeMiddleware(); $this->downloader->withMiddleware($dropMiddleware, $middleware); - $this->downloader->prepare($this->makeRequest()); + $this->downloader->prepare($this->makeRequest(), null); $this->downloader->flush(); $middleware->assertNoResponseHandled(); @@ -136,8 +140,8 @@ public function testCallResponseCallbackForEachResponse(): void $this->makeRequest('::url-a::')->withMeta('index', 0), $this->makeRequest('::url-b::')->withMeta('index', 1), ]; - $this->downloader->prepare($requests[0]); - $this->downloader->prepare($requests[1]); + $this->downloader->prepare($requests[0], null); + $this->downloader->prepare($requests[1], null); $this->downloader->flush(static function (Response $response) use (&$requests): void { self::assertContains($response->getRequest(), $requests); @@ -152,7 +156,7 @@ public function testDontCallResponseCallbackIfResponseWasDropped(): void $dropMiddleware = new FakeMiddleware(null, static fn (Response $response) => $response->drop('::reason::')); $this->downloader->withMiddleware($dropMiddleware); - $this->downloader->prepare($this->makeRequest()); + $this->downloader->prepare($this->makeRequest(), null); $this->downloader->flush(static function () use (&$called): void { $called = true; }); @@ -166,7 +170,7 @@ public function testDispatchesAnEventIfRequestWasDropped(): void $dropMiddleware = new FakeMiddleware(static fn (Request $request) => $request->drop('::reason::')); $this->downloader->withMiddleware($dropMiddleware); - $this->downloader->prepare($request); + $this->downloader->prepare($request, null); $this->dispatcher->assertDispatched( RequestDropped::NAME, @@ -176,7 +180,7 @@ public function testDispatchesAnEventIfRequestWasDropped(): void public function testDoesNotDispatchEventIfRequestWasNotDropped(): void { - $this->downloader->prepare($this->makeRequest()); + $this->downloader->prepare($this->makeRequest(), null); $this->dispatcher->assertNotDispatched(RequestDropped::NAME); } @@ -184,7 +188,7 @@ public function testDoesNotDispatchEventIfRequestWasNotDropped(): void public function testDispatchesAnEventBeforeRequestIsScheduled(): void { $request = $this->makeRequest(); - $this->downloader->prepare($request); + $this->downloader->prepare($request, null); $this->dispatcher->assertDispatched( RequestSending::NAME, @@ -199,7 +203,7 @@ public function testDoesNotScheduleEventIfDroppedByEventListener(): void }); $request = $this->makeRequest(); - $this->downloader->prepare($request); + $this->downloader->prepare($request, null); $this->downloader->flush(); $this->client->assertRequestWasNotSent($request); @@ -212,7 +216,7 @@ public function testDispatchesAnEventIfRequestWasDroppedByListener(): void }); $request = $this->makeRequest(); - $this->downloader->prepare($request); + $this->downloader->prepare($request, null); $this->dispatcher->assertDispatched( RequestDropped::NAME, @@ -224,7 +228,7 @@ public function testDispatchEventWhenResponseWasReceived(): void { $request = $this->makeRequest(); - $this->downloader->prepare($request); + $this->downloader->prepare($request, null); $this->dispatcher->assertNotDispatched(ResponseReceiving::NAME); $this->downloader->flush(); @@ -266,7 +270,7 @@ public function testDontPassResponseToMiddlewareIfDroppedByExtension(): void $middleware = new FakeMiddleware(); $this->downloader->withMiddleware($middleware); - $this->downloader->prepare($request); + $this->downloader->prepare($request, null); $this->downloader->flush(); $middleware->assertNoResponseHandled(); @@ -279,7 +283,7 @@ public function testFireEventIfReceivedResponseWasDroppedByExtension(): void $event->response = $event->response->drop('::reason::'); }); - $this->downloader->prepare($request); + $this->downloader->prepare($request, null); $this->downloader->flush(); $this->dispatcher->assertDispatched( @@ -296,7 +300,7 @@ public function testDontCallParseCallbackIfRequestWasDroppedByExtension(): void $event->response = $event->response->drop('::reason::'); }); - $this->downloader->prepare($request); + $this->downloader->prepare($request, null); $this->downloader->flush(static function () use (&$called): void { $called = true; }); @@ -316,7 +320,7 @@ public function testDispatchEventWhenResponseWasProcessedByMiddleware(): void ); $this->downloader->withMiddleware($middleware); - $this->downloader->prepare($request); + $this->downloader->prepare($request, null); $this->downloader->flush(); $this->dispatcher->assertDispatched( @@ -332,7 +336,7 @@ public function testFireEventIfProcessedResponseWasDroppedByExtension(): void $event->response = $event->response->drop('::reason::'); }); - $this->downloader->prepare($request); + $this->downloader->prepare($request, null); $this->downloader->flush(); $this->dispatcher->assertDispatched( @@ -349,7 +353,7 @@ public function testDontCallParseCallbackIfProcessedResponseWasDroppedByExtensio $event->response = $event->response->drop('::reason::'); }); - $this->downloader->prepare($request); + $this->downloader->prepare($request, null); $this->downloader->flush(static function () use (&$called): void { $called = true; }); @@ -362,7 +366,7 @@ public function testDontSendRequestIfHasResponse(): void $request = $this->makeRequest(); $request = $request->withResponse($this->makeResponse($request)); - $this->downloader->prepare($request); + $this->downloader->prepare($request, null); $this->downloader->flush(); $this->client->assertRequestWasNotSent($request); @@ -373,7 +377,7 @@ public function testResponseDispatchedWhenNotSent(): void $request = $this->makeRequest(); $request = $request->withResponse($this->makeResponse($request)); - $this->downloader->prepare($request); + $this->downloader->prepare($request, null); $this->dispatcher->assertNotDispatched(ResponseReceiving::NAME); $this->downloader->flush(); @@ -394,8 +398,123 @@ public function testPassRequestsThroughRequestHandlersWhenHasResponse(): void $this->downloader ->withMiddleware($middleware) - ->prepare($request); + ->prepare($request, null); $middleware->assertRequestHandled($request); } + + public function testCallsOnRejectedCallbackWhenExceptionOccursDuringRequestHandling(): void + { + $called = false; + $request = $this->makeRequest(); + $exceptionMiddleware = new FakeMiddleware( + requestHandler: static fn () => throw new \Exception('Oh no!'), + // Handle request exception to not let the exception be thrown + exceptionHandler: static fn (RequestException $requestException) => $requestException->setHandled() + ); + + $this->downloader + ->withMiddleware($exceptionMiddleware) + ->prepare($request, function () use (&$called) { + $called = true; + }); + $this->downloader->flush(); + + $this->client->assertRequestWasNotSent($request); + self::assertTrue($called); + } + + public function testCallsOnRejectedCallbackWhenExceptionOccursDuringFlushing(): void + { + $called = false; + $request = $this->makeRequest(); + $this->client->makeRequestsFail($request); + + $this->downloader->prepare($request, null); + $this->downloader->flush(onRejected: function () use (&$called) { + $called = true; + }); + + self::assertTrue($called); + } + + public function testPassExceptionsThroughExceptionHandlers(): void + { + $request = $this->makeRequest(); + $exception = new Exception('Oh no!'); + $exceptionMiddleware = new FakeMiddleware( + requestHandler: static fn () => throw $exception, + // Handle request exception to not let the exception be thrown + exceptionHandler: static fn (RequestException $requestException) => $requestException->setHandled() + ); + + $this->downloader + ->withMiddleware($exceptionMiddleware) + ->prepare($request, null); + + $exceptionMiddleware->assertExceptionHandled($exception); + } + + public function testDispatchEventIfExceptionIsBeingReceived(): void + { + $request = $this->makeRequest(); + $successfulMiddleware = new FakeMiddleware(); + $exception = new Exception('On no!'); + $failingMiddleware = new FakeMiddleware( + requestHandler: static fn () => throw $exception, + // Handle request exception to not let the exception be thrown + exceptionHandler: static fn (RequestException $requestException) => $requestException->setHandled() + ); + + $this->downloader + ->withMiddleware($successfulMiddleware) + ->prepare($request, null); + $this->dispatcher->assertNotDispatched(ExceptionReceiving::class); + + $this->downloader + ->withMiddleware($failingMiddleware) + ->prepare($request, null); + + $this->dispatcher->assertDispatched( + ExceptionReceiving::NAME, + static fn (ExceptionReceiving $event) => $event->exception->getPrevious() == $exception, + ); + } + + public function testDispatchEventWhenExceptionWasProcessedByMiddleware(): void + { + $request = $this->makeRequest(); + $exception = new Exception('On no!'); + $middleware = new FakeMiddleware( + requestHandler: static fn () => throw $exception, + exceptionHandler: function (RequestException $requestException) { + $this->dispatcher->assertNotDispatched(ExceptionReceived::NAME); + + // Handle request exception to not let the exception be thrown + return $requestException->setHandled(); + }, + ); + $this->downloader->withMiddleware($middleware); + + $this->downloader->prepare($request, null); + + $this->dispatcher->assertDispatched( + ExceptionReceived::NAME, + static fn (ExceptionReceived $event) => $event->exception->getPrevious() === $exception, + ); + } + + public function testThrowsExceptionWhenNoMiddlewareSpecified(): void + { + $request = $this->makeRequest(); + $exception = new Exception('On no!'); + $middleware = new FakeMiddleware(requestHandler: static fn () => throw $exception); + $this->downloader->withMiddleware($middleware); + + try { + $this->downloader->prepare($request, null); + } catch (RequestException $requestException) { + $this->assertEquals($exception, $requestException->getPrevious()); + } + } } diff --git a/tests/Extensions/LoggerExtensionTest.php b/tests/Extensions/LoggerExtensionTest.php index 99de5a9..30290de 100644 --- a/tests/Extensions/LoggerExtensionTest.php +++ b/tests/Extensions/LoggerExtensionTest.php @@ -13,7 +13,9 @@ namespace RoachPHP\Tests\Extensions; +use Exception; use RoachPHP\Core\Run; +use RoachPHP\Events\ExceptionReceived; use RoachPHP\Events\ItemDropped; use RoachPHP\Events\ItemScraped; use RoachPHP\Events\RequestDropped; @@ -128,6 +130,20 @@ public function testLogWhenItemWasScraped(): void ); } + public function testLogWhenExceptionWasReceived(): void + { + self::assertFalse( + $this->logger->messageWasLogged('warning', 'Exception received'), + ); + + $exception = new Exception(); + $this->dispatch(new ExceptionReceived($exception), ExceptionReceived::NAME); + + self::assertTrue( + $this->logger->messageWasLogged('warning', 'Exception received', ['exception' => $exception]), + ); + } + protected function createExtension(): ExtensionInterface { $this->logger = new FakeLogger(); diff --git a/tests/Http/RequestExceptionTest.php b/tests/Http/RequestExceptionTest.php new file mode 100644 index 0000000..6ff24c3 --- /dev/null +++ b/tests/Http/RequestExceptionTest.php @@ -0,0 +1,30 @@ +makeRequest(), new \Exception()); + + $this->assertFalse($exception->isHandled()); + + $exception = $exception->setHandled(); + $this->assertTrue($exception->isHandled()); + } +}