diff --git a/zebra-test/src/mock_service.rs b/zebra-test/src/mock_service.rs index 21debf97c13..92160a39f42 100644 --- a/zebra-test/src/mock_service.rs +++ b/zebra-test/src/mock_service.rs @@ -740,7 +740,9 @@ impl ResponseSender { /// This method takes ownership of the [`ResponseSender`] so that only one response can be /// sent. /// - /// If `respond` or `respond_with` are not called, the caller will panic. + /// # Panics + /// + /// If one of the `respond*` methods isn't called, the caller will panic. /// /// # Example /// @@ -789,7 +791,9 @@ impl ResponseSender { /// This method takes ownership of the [`ResponseSender`] so that only one response can be /// sent. /// - /// If `respond` or `respond_with` are not called, the caller will panic. + /// # Panics + /// + /// If one of the `respond*` methods isn't called, the caller will panic. /// /// # Example /// @@ -834,6 +838,106 @@ impl ResponseSender { let response_result = response_fn(self.request()).into_result(); let _ = self.response_sender.send(response_result); } + + /// Respond to the request using a fixed error value. + /// + /// The `error` must be the `Error` type. This helps avoid type resolution issues in the + /// compiler. + /// + /// This method takes ownership of the [`ResponseSender`] so that only one response can be + /// sent. + /// + /// # Panics + /// + /// If one of the `respond*` methods isn't 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_error("Duplicate request"); + /// # }); + /// ``` + pub fn respond_error(self, error: Error) { + // TODO: impl ResponseResult for BoxError/Error trait when overlapping impls are + // better supported by the compiler + let _ = self.response_sender.send(Err(error)); + } + + /// Respond to the request by calculating an error from the request. + /// + /// The `error` must be the `Error` type. This helps avoid type resolution issues in the + /// compiler. + /// + /// This method takes ownership of the [`ResponseSender`] so that only one response can be + /// sent. + /// + /// # Panics + /// + /// If one of the `respond*` methods isn't 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_with_error(|req| format!("Duplicate request: {}", req)); + /// # }); + /// ``` + pub fn respond_with_error(self, response_fn: F) + where + F: FnOnce(&Request) -> Error, + { + // TODO: impl ResponseResult for BoxError/Error trait when overlapping impls are + // better supported by the compiler + let response_result = Err(response_fn(self.request())); + let _ = self.response_sender.send(response_result); + } } /// A representation of an assertion type.