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> {
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(MockError::ARetryableError))
74 });
75 client
76 .expect_request()
77 .times(1)
78 .returning(move |_, _, _| Ok(http::Response::new(bytes.clone().into())));
79 client
80 }
81
82 #[xmtp_common::test]
83 async fn ignores_payloads() {
84 let mut client = MockNetworkClient::new();
85 let bytes = vec![0, 1, 2];
86 client
87 .expect_request()
88 .times(1)
89 .returning(move |_, _, _| Ok(http::Response::new(bytes.clone().into())));
90 let result: Result<(), _> = TestEndpoint.ignore_response().query(&client).await;
91 assert!(result.is_ok(), "{}", result.unwrap_err().to_string());
92 }
93
94 #[rstest]
95 #[xmtp_common::test]
96 async fn ignore_is_retryable(client: MockNetworkClient) {
97 let result: Result<(), _> = api::ignore(api::retry(TestEndpoint)).query(&client).await;
98 assert!(result.is_ok(), "{}", result.unwrap_err().to_string());
99 }
100
101 #[rstest]
102 #[xmtp_common::test]
103 async fn ignore_is_orthogonal(client: MockNetworkClient) {
104 let result: Result<(), _> = api::retry(api::ignore(TestEndpoint)).query(&client).await;
105 assert!(result.is_ok(), "{}", result.unwrap_err().to_string());
106 }
107
108 #[rstest]
109 #[xmtp_common::test]
110 async fn endpoint_chains_work(client: MockNetworkClient) {
111 let result: Result<(), _> = TestEndpoint.ignore_response().retry().query(&client).await;
112 assert!(result.is_ok(), "{}", result.unwrap_err().to_string());
113 }
114
115 #[rstest]
116 #[xmtp_common::test]
117 async fn endpoint_chains_orthogonal(client: MockNetworkClient) {
118 let result: Result<(), _> = TestEndpoint.retry().ignore_response().query(&client).await;
119 assert!(result.is_ok(), "{}", result.unwrap_err().to_string());
120 }
121
122 #[xmtp_common::test]
123 fn test_body_delegates_to_wrapped_endpoint() {
124 let ignore_endpoint = ignore(TestEndpoint);
125 let result = ignore_endpoint.body();
126 assert!(result.is_ok());
127 assert_eq!(result.unwrap(), bytes::Bytes::from(vec![]));
128 }
129
130 #[xmtp_common::test]
131 fn test_grpc_endpoint_delegates_to_wrapped_endpoint() {
132 let ignore_endpoint = ignore(TestEndpoint);
133 assert_eq!(ignore_endpoint.grpc_endpoint(), "");
134 }
135}