wiremock-rs icon indicating copy to clipboard operation
wiremock-rs copied to clipboard

async `respond_with` / `Respond`

Open johannescpk opened this issue 3 years ago • 7 comments

Thanks for wiremock! It seems that it's currently not possible to execute async code in the respond method or respond trait. It'd be useful to have it natively supported by wiremock.

Wasn't able to find a workaround, tried

.respond_with(move |req: &Request| {
        let handle = tokio::runtime::Handle::current();
	std::thread::spawn(move || {
		handle.block_on(async {
			// Some async call
		});
	})
	.join()
	.unwrap();

	ResponseTemplate::new(200)
})

but that's blocking the tokio runtime since the test runs as #[tokio::test].

johannescpk avatar Jan 07 '22 08:01 johannescpk

What kind of async tasks are you trying to perform in response_with?

LukeMathWalker avatar Jan 07 '22 12:01 LukeMathWalker

It's some business logic, in this case it's tower::util::Oneshot calls.

johannescpk avatar Jan 10 '22 13:01 johannescpk

I'll need an example a bit more concrete to understand if it makes sense to extend the library or not 😄

LukeMathWalker avatar Jan 10 '22 13:01 LukeMathWalker

Personally I'd say it'd make sense to have callbacks be async in general unless there's a good reason to not do it. Reason being that it's easy to have a sync wrapper in an async context but it's hard the other way around.

In this specific case I'm testing the correct setup of a FHIR Subscription. The HTTP request flow looks like this. The relevant part is 9. and 10. where a handshake takes place.

Basically:

Client --[ HTTP POST Create Subscription ]--> Server
Server --[ HTTP POST Handshake ] --> Client

The library exposing the functionality has an async method create_subscription which should only return once the subscription was created in full, with a successful handshake. To test this I have two MockServer instances, one being the client and one being the server. The test then calls create_subscription and only after the subscription mock finished (the server mock returning the ResponseTemplate) it should do a mocked handshake call to the client so create_subscription returns. The communication inside the client to signal that the handshake arrived is made with tokio::Notify. In the tests I'm now also using Notify as a workaround (requires me to juggle a tokio::join! later in the test), but I'd like to directly use https://github.com/tokio-rs/axum/blob/main/examples/testing/src/main.rs#L64-L67 which is async.

johannescpk avatar Jan 10 '22 16:01 johannescpk

Hey there, thanks for this great library! I recently ran into the same issue. Trying to call some async code from a custom responder. Basically, I am trying to create a mock to validate an HTTP payload and one of the libraries to parse multipart data is async. e.g.

struct CustomResponder;

impl wiremock::Respond for CustomResponder {
    fn respond(&self, req: &wiremock::Request) -> wiremock::ResponseTemplate {
        // ... some logic ...
        
        // This is an async function so can't be used here
        let multipart = multer::Multipart::with_reader(req.body.as_slice(), boundary);
        
        // ... validate multipart data ...
    }

A lot of http libraries have gone async so it would be useful to be able to use them

rminderhoud avatar Mar 16 '23 22:03 rminderhoud

Just another example in case it helps: In the response method, I have to call another service (another mock which implements json rpc), which is async.

moh-eulith avatar Aug 16 '23 21:08 moh-eulith