-
Notifications
You must be signed in to change notification settings - Fork 11.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[9.x] Allow faking connection errors in HTTP client #44852
Conversation
I needed this just the other day! |
Haha. Best timing ever. I am actually in the same situation. But one question. For example:
|
@commentatorboy in what case would you need to throw a Http::fakeSequence()
->pushStatus(400) // this will throw a RequestException
->pushStatus(200) |
@sebdesign Thank you for writing. Aha I see. I thought that there were other types of exceptions related to Http. So yeah thank you for clearing that up. :) |
Feels like a lot of code got shifted around here to add this feature. Can you elaborate on some of those changes and why they were needed? |
@taylorotwell of course! Factory::error()First, the Http::fake([
'*' => fn ($request, $options) => Http::response(),
]);
Http::fake(fn ($request, $options) => Http::response()); These closures were evaluated in the Factory::stubUrl() method or in the Factory::fake() method, respectively. The problem in the In order to address this, the transfer stats need to be evaluated much later, after the stubs have been converted to responses. PendingRequest::makePromise()When sending async/concurrent requests, the promises must be fulfilled with the response, or rejected with the response of the PendingRequest::buildRecorderHandler()Previously, the recorder was only handling fulfilled promises, but not rejected ones. In order to record requests that throw PendingRequest::buildStubHandler()Instead of evaluating all the stub callbacks that match the request, and then filtering them to select the first one that is not Then we decide how to handle the result: if it's ResponseSequence::pushError()In order to push a The solution is to evaluate the closure inside the I hope my explanation is not very confusing, and I'd be happy to address anything you want. |
I dunno - there are just too many changes here on an already fragile component we have had problems with PRs breaking before. I would just suggest just putting some HTTP calls where you need this testability behind another class that you can inject and mock and then throw ConnectionExceptions that way to test your systems response to those types of exceptions. |
Or, if you can figure out a way to add this to Http::fake without so many changes feel free to PR that. |
Purpose
This PR brings the ability to fake connection/networking errors when HTTP requests are made.
Why this is useful
Until now, we could fake HTTP responses, both successful or failed (4xx/5xx). But there is no way to test how the HTTP client or our application behaves when there is a networking error, e.g. a host that could not be resolved, a connection timeout, an SSL error, etc.
In fact, there are currently no tests that assert the
ConnectionFailed
event is dispatched, or that theretry
method catches theConnectionException
.Example use-case
I have some jobs that make API calls to a server that might be down or timeouts. When that happens, I need to notify someone.
Of course, I could do that before, but there was no easy way to test that case.
Usage
The new
Http::error()
method accepts two optional parameters: an error message, and an array with the (cURL) handler context.This method works with all the common features of the HTTP client:
HTTP::pool()
RequestSending
andConnectionFailed
eventsHttp::sequence()
andHttp::fakeSequence()
assertSent()
,assertNotSent()
, etc.Http::recorded()
Simple requests
Inside your tests, making a request will still throw a
ConnectionException
, but it will not actually send the request.Concurrent requests
When using
Http::pool()
, the response instance will be aHttp\Client\ConnectionException
instead of aHttp\Client\Response
.Events
Faking response sequences
Inspecting requests
When asserting requests that throws connection errors, the
Http::assert*()
methods receive aHttp\Client\ConnectionException
instead of aHttp\Client\Response
.