xmtp_proto/traits/combinators/
ignore.rs1use std::marker::PhantomData;
2
3use crate::api::{ApiClientError, Client, Endpoint, Query, QueryRaw};
4
5pub struct Ignore<E> {
7 endpoint: E,
8}
9
10#[xmtp_common::async_trait]
11impl<E, C> Query<C> for Ignore<E>
12where
13 E: QueryRaw<C>,
14 C: Client,
15{
16 type Output = ();
17 async fn query(&mut self, client: &C) -> Result<(), ApiClientError<C::Error>> {
18 let _ = QueryRaw::<C>::query_raw(&mut self.endpoint, client).await?;
19 Ok(())
21 }
22}
23
24pub struct IgnoreSpecialized<S> {
25 _marker: PhantomData<S>,
26}
27
28impl<S, E: Endpoint<S>> Endpoint<IgnoreSpecialized<S>> for Ignore<E> {
29 type Output = <E as Endpoint<S>>::Output;
30
31 fn grpc_endpoint(&self) -> std::borrow::Cow<'static, str> {
32 self.endpoint.grpc_endpoint()
33 }
34
35 fn body(&self) -> Result<bytes::Bytes, crate::api::BodyError> {
36 self.endpoint.body()
37 }
38}
39
40pub fn ignore<E>(endpoint: E) -> Ignore<E> {
47 Ignore { endpoint }
48}
49
50#[cfg(test)]
51mod tests {
52 use prost::Message;
53
54 use super::*;
55 use crate::api::{
56 self, EndpointExt,
57 mock::{MockError, MockNetworkClient, TestEndpoint},
58 };
59 use rstest::*;
60
61 #[derive(prost::Message)]
62 struct TestProto {
63 #[prost(int64, tag = "1")]
64 inner: i64,
65 }
66
67 #[fixture]
68 fn client() -> MockNetworkClient {
69 let mut client = MockNetworkClient::new();
70 let bytes = TestProto { inner: 900 }.encode_to_vec();
71 client.expect_request().times(3).returning(|_, _, _| {
72 tracing::info!("error");
73 Err(ApiClientError::Client {
74 source: MockError::ARetryableError,
75 })
76 });
77 client
78 .expect_request()
79 .times(1)
80 .returning(move |_, _, _| Ok(http::Response::new(bytes.clone().into())));
81 client
82 }
83
84 #[xmtp_common::test]
85 async fn ignores_payloads() {
86 let mut client = MockNetworkClient::new();
87 let bytes = vec![0, 1, 2];
88 client
89 .expect_request()
90 .times(1)
91 .returning(move |_, _, _| Ok(http::Response::new(bytes.clone().into())));
92 let result: Result<(), _> = TestEndpoint.ignore_response().query(&client).await;
93 assert!(result.is_ok(), "{}", result.unwrap_err().to_string());
94 }
95
96 #[rstest]
97 #[xmtp_common::test]
98 async fn ignore_is_retryable(client: MockNetworkClient) {
99 let result: Result<(), _> = api::ignore(api::retry(TestEndpoint)).query(&client).await;
100 assert!(result.is_ok(), "{}", result.unwrap_err().to_string());
101 }
102
103 #[rstest]
104 #[xmtp_common::test]
105 async fn ignore_is_orthogonal(client: MockNetworkClient) {
106 let result: Result<(), _> = api::retry(api::ignore(TestEndpoint)).query(&client).await;
107 assert!(result.is_ok(), "{}", result.unwrap_err().to_string());
108 }
109
110 #[rstest]
111 #[xmtp_common::test]
112 async fn endpoint_chains_work(client: MockNetworkClient) {
113 let result: Result<(), _> = TestEndpoint.ignore_response().retry().query(&client).await;
114 assert!(result.is_ok(), "{}", result.unwrap_err().to_string());
115 }
116
117 #[rstest]
118 #[xmtp_common::test]
119 async fn endpoint_chains_orthogonal(client: MockNetworkClient) {
120 let result: Result<(), _> = TestEndpoint.retry().ignore_response().query(&client).await;
121 assert!(result.is_ok(), "{}", result.unwrap_err().to_string());
122 }
123
124 #[xmtp_common::test]
125 fn test_body_delegates_to_wrapped_endpoint() {
126 let ignore_endpoint = ignore(TestEndpoint);
127 let result = ignore_endpoint.body();
128 assert!(result.is_ok());
129 assert_eq!(result.unwrap(), bytes::Bytes::from(vec![]));
130 }
131
132 #[xmtp_common::test]
133 fn test_grpc_endpoint_delegates_to_wrapped_endpoint() {
134 let ignore_endpoint = ignore(TestEndpoint);
135 assert_eq!(ignore_endpoint.grpc_endpoint(), "");
136 }
137}