mithril_aggregator_client/query/post/
post_register_signature.rs

1use async_trait::async_trait;
2use reqwest::StatusCode;
3use slog::debug;
4
5use mithril_common::messages::RegisterSignatureMessageHttp;
6
7use crate::query::{AggregatorQuery, QueryContext, QueryLogFields, QueryMethod};
8use crate::{AggregatorHttpClientError, AggregatorHttpClientResult};
9
10/// Query to register a signature to a Mithril Aggregator.
11pub struct PostRegisterSignatureQuery {
12    message: RegisterSignatureMessageHttp,
13}
14
15impl PostRegisterSignatureQuery {
16    /// Instantiate a new query to register a signature
17    pub fn new(message: RegisterSignatureMessageHttp) -> Self {
18        Self { message }
19    }
20}
21
22#[cfg_attr(target_family = "wasm", async_trait(?Send))]
23#[cfg_attr(not(target_family = "wasm"), async_trait)]
24impl AggregatorQuery for PostRegisterSignatureQuery {
25    type Response = ();
26    type Body = RegisterSignatureMessageHttp;
27
28    fn method() -> QueryMethod {
29        QueryMethod::Post
30    }
31
32    fn route(&self) -> String {
33        "register-signatures".to_string()
34    }
35
36    fn body(&self) -> Option<Self::Body> {
37        Some(self.message.clone())
38    }
39
40    fn entry_log_additional_fields(&self) -> QueryLogFields {
41        QueryLogFields::from([
42            ("party_id", self.message.party_id.clone()),
43            (
44                "signed_entity",
45                format!("{:?}", self.message.signed_entity_type),
46            ),
47        ])
48    }
49
50    async fn handle_response(
51        &self,
52        context: QueryContext,
53    ) -> AggregatorHttpClientResult<Self::Response> {
54        match context.response.status() {
55            StatusCode::CREATED | StatusCode::ACCEPTED => Ok(()),
56            StatusCode::GONE => {
57                let root_cause = AggregatorHttpClientError::get_root_cause(context.response).await;
58                debug!(context.logger, "Message already certified or expired"; "details" => &root_cause);
59
60                Ok(())
61            }
62            _ => Err(context.unhandled_status_code().await),
63        }
64    }
65}
66
67#[cfg(test)]
68mod tests {
69    use httpmock::Method::POST;
70
71    use mithril_common::entities::ClientError;
72    use mithril_common::test::double::Dummy;
73
74    use crate::test::{TestLogger, assert_error_matches, setup_server_and_client};
75
76    use super::*;
77
78    #[tokio::test]
79    async fn test_register_signature_ok_201() {
80        let expected_message = RegisterSignatureMessageHttp::dummy();
81        let (server, client) = setup_server_and_client();
82        let _server_mock = server.mock(|when, then| {
83            when.method(POST)
84                .path("/register-signatures")
85                .body(serde_json::to_string(&expected_message).unwrap());
86            then.status(201);
87        });
88
89        let register_signature =
90            client.send(PostRegisterSignatureQuery::new(expected_message)).await;
91        register_signature.expect("unexpected error");
92    }
93
94    #[tokio::test]
95    async fn test_register_signature_ok_202() {
96        let (server, client) = setup_server_and_client();
97        let _server_mock = server.mock(|when, then| {
98            when.method(POST).path("/register-signatures");
99            then.status(202);
100        });
101
102        let register_signature = client
103            .send(PostRegisterSignatureQuery::new(
104                RegisterSignatureMessageHttp::dummy(),
105            ))
106            .await;
107        register_signature.expect("unexpected error");
108    }
109
110    #[tokio::test]
111    async fn test_register_signature_ko_400() {
112        let (server, client) = setup_server_and_client();
113        let _server_mock = server.mock(|when, then| {
114            when.any_request();
115            then.status(400)
116                .body(serde_json::to_vec(&ClientError::dummy()).unwrap());
117        });
118
119        let error = client
120            .send(PostRegisterSignatureQuery::new(
121                RegisterSignatureMessageHttp::dummy(),
122            ))
123            .await
124            .unwrap_err();
125
126        assert_error_matches!(error, AggregatorHttpClientError::RemoteServerLogical(_));
127    }
128
129    #[tokio::test]
130    async fn test_register_signature_ok_410_log_response_body() {
131        let (logger, log_inspector) = TestLogger::memory();
132
133        let (server, mut client) = setup_server_and_client();
134        client.logger = logger;
135        let _server_mock = server.mock(|when, then| {
136            when.any_request();
137            then.status(410).body(
138                serde_json::to_vec(&ClientError::new(
139                    "already_aggregated".to_string(),
140                    "too late".to_string(),
141                ))
142                .unwrap(),
143            );
144        });
145
146        client
147            .send(PostRegisterSignatureQuery::new(
148                RegisterSignatureMessageHttp::dummy(),
149            ))
150            .await
151            .expect("Should not fail when status is 410 (GONE)");
152
153        assert!(log_inspector.contains_log("already_aggregated"));
154        assert!(log_inspector.contains_log("too late"));
155    }
156
157    #[tokio::test]
158    async fn test_register_signature_ko_409() {
159        let (server, client) = setup_server_and_client();
160        let _server_mock = server.mock(|when, then| {
161            when.any_request();
162            then.status(409);
163        });
164
165        let error = client
166            .send(PostRegisterSignatureQuery::new(
167                RegisterSignatureMessageHttp::dummy(),
168            ))
169            .await
170            .unwrap_err();
171
172        assert_error_matches!(error, AggregatorHttpClientError::RemoteServerLogical(_));
173    }
174
175    #[tokio::test]
176    async fn test_register_signature_ko_500() {
177        let (server, client) = setup_server_and_client();
178        let _server_mock = server.mock(|when, then| {
179            when.any_request();
180            then.status(500).body("an error occurred");
181        });
182
183        let error = client
184            .send(PostRegisterSignatureQuery::new(
185                RegisterSignatureMessageHttp::dummy(),
186            ))
187            .await
188            .unwrap_err();
189
190        assert_error_matches!(error, AggregatorHttpClientError::RemoteServerTechnical(_));
191    }
192}