socketry / async-http

MIT License
298 stars 45 forks source link

Support for mocked client requests. #41

Closed ioquatix closed 1 week ago

ioquatix commented 4 years ago

This provides some basic building blocks for mocking up Async::HTTP::Client in the same process.

https://github.com/socketry/async-http/issues/35

ioquatix commented 4 years ago

@ayanko @bblimke here is a rough POC showing how to use an endpoint and an internal HTTP connection/server (using HTTP2 by default) to easily intercept requests. It's inspired by @ayanko's webmock implementation, but I wanted to try and standardise some of it.

The next step is to try and figure out what Async::HTTP::Mock::Client should look like. Either, 1/ something which lets you stub in client side request/response with delegation to the server connection if required, or 2/ just doing everything on the server, proxying requests as needed.

Personally, while 2/ is simpler, the chance of it breaking things is higher, because we'd need to correctly proxy WebSockets, HTTPS, etc, it's basically a man in the middle. But because of that, it's a centralised place for the logic to go.

It's all in the same process. @ayanko see #35 for more discussion if you are interested.

ioquatix commented 4 years ago

The other part of this, is the ability to replace Async::HTTP::Client, which I'm happy to leave in WebMock since it's kind of a hack and maybe shouldn't be officially sanctioned (but unofficially allowed as per normal Ruby behaviour).

It would be nice if it was possible to only make these changes when working within the spec, but this would require injecting Async::HTTP::Client everywhere which is probably impossible in general. The only way I could see that working is some kind of feature within Ruby like refinements, which basically lets you override globals/constants on a per-block basis.

That being said, it would be nice if we split the WebMock support for Async into two parts - those that are fairly pure and require injection, and those which just do the constant replacement. That way, engineer's writing tests can decide for themselves what approach works best for them, and the former approach, I'd be happy to completely support within Async::HTTP::Mock.

coveralls commented 4 years ago

Coverage Status

Coverage increased (+0.2%) to 91.217% when pulling 92be93d3192e043e3a9fd97fde78109308055e52 on mock into 118f0ea2698b6656896d3b27e7997e22d46bc13a on master.

ioquatix commented 4 years ago

I realised a slightly better implementation might be:

endpoint = Async::HTTP::Endpoint.parse("http://localhost", Async::IO::Endpoint.unix("server.ipc"))

Using a unix pipe avoids all the in-process queues and behaves more like a standard I/O.