Improve `MockService` ergonomics for sending error responses (#2810)

* Remove `std::error::Error` constraint

The generic `Error` type parameter doesn't have to implement the
standard `Error` trait, so having that constraint only unnecessarily
limits the types that can be used as an error for the service.

* Implement automatic conversion into `Error` type

Make the usage a little more ergonomic by not having to write manual
error type conversions.

* Add a documentation test for an error response

Show an example that responds to a call to the service with an error.

Co-authored-by: teor <teor@riseup.net>
This commit is contained in:
Janito Vaqueiro Ferreira Filho 2021-09-29 23:48:26 -03:00 committed by GitHub
parent 18acec6849
commit 175ac99a42
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 41 additions and 4 deletions

View File

@ -694,6 +694,42 @@ impl<Request, Response, Error> ResponseSender<Request, Response, Error> {
/// sent.
///
/// If this method is not called, the caller will panic.
///
/// # Example
///
/// ```
/// # use zebra_test::mock_service::MockService;
/// # use tower::{Service, ServiceExt};
/// #
/// # let reactor = tokio::runtime::Builder::new_current_thread()
/// # .enable_all()
/// # .build()
/// # .expect("Failed to build Tokio runtime");
/// #
/// # reactor.block_on(async {
/// // Mock a service with a `String` as the service `Error` type.
/// let mut mock_service: MockService<_, _, _, String> =
/// MockService::build().for_unit_tests();
///
/// # let mut service = mock_service.clone();
/// # let task = tokio::spawn(async move {
/// # let first_call_result = (&mut service).oneshot(1).await;
/// # let second_call_result = service.oneshot(1).await;
/// #
/// # (first_call_result, second_call_result)
/// # });
/// #
/// mock_service
/// .expect_request(1)
/// .await
/// .respond("Received one".to_owned());
///
/// mock_service
/// .expect_request(1)
/// .await
/// .respond(Err("Duplicate request"));
/// # });
/// ```
pub fn respond(self, response: impl ResponseResult<Response, Error>) {
let _ = self.response_sender.send(response.into_result());
}
@ -733,11 +769,12 @@ impl<Response, Error> ResponseResult<Response, Error> for Response {
}
}
impl<Response, Error> ResponseResult<Response, Error> for Result<Response, Error>
impl<Response, SourceError, TargetError> ResponseResult<Response, TargetError>
for Result<Response, SourceError>
where
Error: std::error::Error + Send + Sync + 'static,
SourceError: Into<TargetError>,
{
fn into_result(self) -> Result<Response, Error> {
self
fn into_result(self) -> Result<Response, TargetError> {
self.map_err(|source_error| source_error.into())
}
}