mithril_aggregator_client/query/get/
get_certificate.rs

1use async_trait::async_trait;
2use reqwest::StatusCode;
3
4use mithril_common::messages::CertificateMessage;
5
6use crate::AggregatorHttpClientResult;
7use crate::query::{AggregatorQuery, QueryContext, QueryMethod, ResponseExt};
8
9/// Query to get the details of a certificate
10pub struct GetCertificateQuery {
11    hash: String,
12}
13
14impl GetCertificateQuery {
15    /// Instantiate a query to get a certificate by hash
16    pub fn by_hash<H: Into<String>>(hash: H) -> Self {
17        Self { hash: hash.into() }
18    }
19
20    /// Instantiate a query to get the latest genesis certificate
21    pub fn latest_genesis() -> Self {
22        Self {
23            hash: "genesis".to_string(),
24        }
25    }
26}
27
28#[cfg_attr(target_family = "wasm", async_trait(?Send))]
29#[cfg_attr(not(target_family = "wasm"), async_trait)]
30impl AggregatorQuery for GetCertificateQuery {
31    type Response = Option<CertificateMessage>;
32    type Body = ();
33
34    fn method() -> QueryMethod {
35        QueryMethod::Get
36    }
37
38    fn route(&self) -> String {
39        format!("certificate/{}", self.hash)
40    }
41
42    async fn handle_response(
43        &self,
44        context: QueryContext,
45    ) -> AggregatorHttpClientResult<Self::Response> {
46        match context.response.status() {
47            StatusCode::OK => context.response.parse_json_option().await,
48            StatusCode::NOT_FOUND => Ok(None),
49            _ => Err(context.unhandled_status_code().await),
50        }
51    }
52}
53
54#[cfg(test)]
55mod tests {
56    use serde_json::json;
57
58    use mithril_common::test::double::Dummy;
59
60    use crate::AggregatorHttpClientError;
61    use crate::test::{assert_error_matches, setup_server_and_client};
62
63    use super::*;
64
65    #[tokio::test]
66    async fn test_certificates_details_ok_200() {
67        let (server, client) = setup_server_and_client();
68        let expected_message = CertificateMessage::dummy();
69        let _server_mock = server.mock(|when, then| {
70            when.path(format!("/certificate/{}", expected_message.hash));
71            then.status(200).body(json!(expected_message).to_string());
72        });
73
74        let fetched_message = client
75            .send(GetCertificateQuery::by_hash(&expected_message.hash))
76            .await
77            .unwrap();
78
79        assert_eq!(Some(expected_message), fetched_message);
80    }
81
82    #[tokio::test]
83    async fn test_certificates_details_ok_404() {
84        let (server, client) = setup_server_and_client();
85        let _server_mock = server.mock(|when, then| {
86            when.any_request();
87            then.status(404);
88        });
89
90        let fetched_message = client.send(GetCertificateQuery::by_hash("whatever")).await.unwrap();
91
92        assert_eq!(None, fetched_message);
93    }
94
95    #[tokio::test]
96    async fn test_certificates_details_ko_500() {
97        let (server, client) = setup_server_and_client();
98        let _server_mock = server.mock(|when, then| {
99            when.any_request();
100            then.status(500).body("an error occurred");
101        });
102
103        let error = client
104            .send(GetCertificateQuery::by_hash("whatever"))
105            .await
106            .unwrap_err();
107
108        assert_error_matches!(error, AggregatorHttpClientError::RemoteServerTechnical(_));
109    }
110
111    #[tokio::test]
112    async fn test_latest_genesis_ok_200() {
113        let (server, client) = setup_server_and_client();
114        let genesis_message = CertificateMessage::dummy();
115        let _server_mock = server.mock(|when, then| {
116            when.path("/certificate/genesis");
117            then.status(200).body(json!(genesis_message).to_string());
118        });
119
120        let fetched = client.send(GetCertificateQuery::latest_genesis()).await.unwrap();
121
122        assert_eq!(Some(genesis_message), fetched);
123    }
124
125    #[tokio::test]
126    async fn test_latest_genesis_ok_404() {
127        let (server, client) = setup_server_and_client();
128        let _server_mock = server.mock(|when, then| {
129            when.any_request();
130            then.status(404);
131        });
132
133        let fetched = client.send(GetCertificateQuery::latest_genesis()).await.unwrap();
134
135        assert_eq!(None, fetched);
136    }
137
138    #[tokio::test]
139    async fn test_latest_genesis_ko_500() {
140        let (server, client) = setup_server_and_client();
141        let _server_mock = server.mock(|when, then| {
142            when.any_request();
143            then.status(500).body("an error occurred");
144        });
145
146        let error = client.send(GetCertificateQuery::latest_genesis()).await.unwrap_err();
147
148        assert_error_matches!(error, AggregatorHttpClientError::RemoteServerTechnical(_));
149    }
150}