mithril_client/certificate_client/
fetch.rs1use anyhow::Context;
2use async_trait::async_trait;
3use std::sync::Arc;
4
5use mithril_common::certificate_chain::{CertificateRetriever, CertificateRetrieverError};
6use mithril_common::entities::Certificate;
7
8use crate::certificate_client::{CertificateAggregatorRequest, CertificateClient};
9use crate::{MithrilCertificate, MithrilCertificateListItem, MithrilResult};
10
11#[inline]
12pub(super) async fn list(
13 client: &CertificateClient,
14) -> MithrilResult<Vec<MithrilCertificateListItem>> {
15 client.aggregator_requester.list_latest().await
16}
17
18#[inline]
19pub(super) async fn get(
20 client: &CertificateClient,
21 certificate_hash: &str,
22) -> MithrilResult<Option<MithrilCertificate>> {
23 client.retriever.get(certificate_hash).await
24}
25
26pub(super) struct InternalCertificateRetriever {
30 aggregator_requester: Arc<dyn CertificateAggregatorRequest>,
31}
32
33impl InternalCertificateRetriever {
34 pub(super) fn new(
35 aggregator_requester: Arc<dyn CertificateAggregatorRequest>,
36 ) -> InternalCertificateRetriever {
37 InternalCertificateRetriever {
38 aggregator_requester,
39 }
40 }
41
42 pub(super) async fn get(
43 &self,
44 certificate_hash: &str,
45 ) -> MithrilResult<Option<MithrilCertificate>> {
46 self.aggregator_requester.get_by_hash(certificate_hash).await
47 }
48}
49
50#[cfg_attr(target_family = "wasm", async_trait(?Send))]
51#[cfg_attr(not(target_family = "wasm"), async_trait)]
52impl CertificateRetriever for InternalCertificateRetriever {
53 async fn get_certificate_details(
54 &self,
55 certificate_hash: &str,
56 ) -> Result<Certificate, CertificateRetrieverError> {
57 self.get(certificate_hash)
58 .await
59 .map_err(CertificateRetrieverError)?
60 .map(|message| message.try_into())
61 .transpose()
62 .map_err(CertificateRetrieverError)?
63 .with_context(|| format!("Certificate does not exist: '{certificate_hash}'"))
64 .map_err(CertificateRetrieverError)
65 }
66}
67
68#[cfg(test)]
69mod tests {
70 use anyhow::anyhow;
71
72 use mithril_common::test::double::{Dummy, fake_data};
73
74 use crate::certificate_client::tests_utils::CertificateClientTestBuilder;
75
76 use super::*;
77
78 #[tokio::test]
79 async fn get_certificate_list() {
80 let expected = vec![
81 MithrilCertificateListItem {
82 hash: "cert-hash-123".to_string(),
83 ..MithrilCertificateListItem::dummy()
84 },
85 MithrilCertificateListItem {
86 hash: "cert-hash-456".to_string(),
87 ..MithrilCertificateListItem::dummy()
88 },
89 ];
90 let message = expected.clone();
91 let certificate_client = CertificateClientTestBuilder::default()
92 .config_aggregator_requester_mock(|mock| {
93 mock.expect_list_latest().return_once(move || Ok(message));
94 })
95 .build();
96 let items = certificate_client.list().await.unwrap();
97
98 assert_eq!(expected, items);
99 }
100
101 #[tokio::test]
102 async fn get_certificate_empty_list() {
103 let certificate_client = CertificateClientTestBuilder::default()
104 .config_aggregator_requester_mock(|mock| {
105 mock.expect_list_latest().return_once(move || Ok(Vec::new()));
106 })
107 .build();
108 let items = certificate_client.list().await.unwrap();
109
110 assert!(items.is_empty());
111 }
112
113 #[tokio::test]
114 async fn test_show_ok_some() {
115 let certificate_hash = "cert-hash-123".to_string();
116 let certificate = fake_data::certificate(certificate_hash.clone());
117 let expected_certificate = certificate.clone();
118
119 let certificate_client = CertificateClientTestBuilder::default()
120 .config_aggregator_requester_mock(|mock| {
121 mock.expect_get_by_hash()
122 .return_once(move |_| {
123 let message: MithrilCertificate = certificate.try_into().unwrap();
124 Ok(Some(message))
125 })
126 .times(1);
127 })
128 .build();
129
130 let cert = certificate_client
131 .get("cert-hash-123")
132 .await
133 .unwrap()
134 .expect("The certificate should be found")
135 .try_into()
136 .unwrap();
137
138 assert_eq!(expected_certificate, cert);
139 }
140
141 #[tokio::test]
142 async fn test_show_ok_none() {
143 let certificate_client = CertificateClientTestBuilder::default()
144 .config_aggregator_requester_mock(|mock| {
145 mock.expect_get_by_hash().return_once(move |_| Ok(None)).times(1);
146 })
147 .build();
148
149 assert!(certificate_client.get("cert-hash-123").await.unwrap().is_none());
150 }
151
152 #[tokio::test]
153 async fn test_show_ko() {
154 let certificate_client = CertificateClientTestBuilder::default()
155 .config_aggregator_requester_mock(|mock| {
156 mock.expect_get_by_hash()
157 .return_once(move |_| Err(anyhow!("an error")))
158 .times(1);
159 })
160 .build();
161
162 certificate_client
163 .get("cert-hash-123")
164 .await
165 .expect_err("The certificate client should fail here.");
166 }
167}