mithril_client/cardano_database_client/
fetch.rs1use std::sync::Arc;
2
3use mithril_common::entities::EpochSpecifier;
4
5use crate::{
6 CardanoDatabaseSnapshot, CardanoDatabaseSnapshotListItem, MithrilResult,
7 cardano_database_client::CardanoDatabaseAggregatorRequest, common::Epoch,
8};
9
10pub struct InternalArtifactRetriever {
11 pub(super) aggregator_requester: Arc<dyn CardanoDatabaseAggregatorRequest>,
12}
13
14impl InternalArtifactRetriever {
15 pub fn new(aggregator_requester: Arc<dyn CardanoDatabaseAggregatorRequest>) -> Self {
17 Self {
18 aggregator_requester,
19 }
20 }
21
22 pub async fn list(&self) -> MithrilResult<Vec<CardanoDatabaseSnapshotListItem>> {
24 self.aggregator_requester.list_latest().await
25 }
26
27 pub async fn list_by_epoch(
29 &self,
30 epoch: Epoch,
31 ) -> MithrilResult<Vec<CardanoDatabaseSnapshotListItem>> {
32 self.aggregator_requester
33 .list_by_epoch(EpochSpecifier::Number(epoch))
34 .await
35 }
36
37 pub async fn list_for_latest_epoch(
39 &self,
40 ) -> MithrilResult<Vec<CardanoDatabaseSnapshotListItem>> {
41 self.aggregator_requester.list_by_epoch(EpochSpecifier::Latest).await
42 }
43
44 pub async fn list_for_latest_epoch_with_offset(
46 &self,
47 offset: u64,
48 ) -> MithrilResult<Vec<CardanoDatabaseSnapshotListItem>> {
49 self.aggregator_requester
50 .list_by_epoch(EpochSpecifier::LatestMinusOffset(offset))
51 .await
52 }
53
54 pub async fn get(&self, hash: &str) -> MithrilResult<Option<CardanoDatabaseSnapshot>> {
56 self.aggregator_requester.get_by_hash(hash).await
57 }
58}
59
60#[cfg(test)]
61mod tests {
62
63 use anyhow::anyhow;
64 use chrono::{DateTime, Utc};
65 use mockall::predicate::eq;
66
67 use mithril_common::entities::{CardanoDbBeacon, Epoch};
68
69 use crate::cardano_database_client::CardanoDatabaseClientDependencyInjector;
70 use crate::common::test::Dummy;
71
72 use super::*;
73
74 fn fake_messages() -> Vec<CardanoDatabaseSnapshotListItem> {
75 vec![
76 CardanoDatabaseSnapshotListItem {
77 hash: "hash-123".to_string(),
78 merkle_root: "mkroot-123".to_string(),
79 beacon: CardanoDbBeacon {
80 epoch: Epoch(1),
81 immutable_file_number: 123,
82 },
83 certificate_hash: "cert-hash-123".to_string(),
84 total_db_size_uncompressed: 800796318,
85 created_at: DateTime::parse_from_rfc3339("2025-01-19T13:43:05.618857482Z")
86 .unwrap()
87 .with_timezone(&Utc),
88 cardano_node_version: "0.0.1".to_string(),
89 },
90 CardanoDatabaseSnapshotListItem {
91 hash: "hash-456".to_string(),
92 merkle_root: "mkroot-456".to_string(),
93 beacon: CardanoDbBeacon {
94 epoch: Epoch(2),
95 immutable_file_number: 456,
96 },
97 certificate_hash: "cert-hash-456".to_string(),
98 total_db_size_uncompressed: 2960713808,
99 created_at: DateTime::parse_from_rfc3339("2025-01-27T15:22:05.618857482Z")
100 .unwrap()
101 .with_timezone(&Utc),
102 cardano_node_version: "0.0.1".to_string(),
103 },
104 ]
105 }
106
107 mod list {
108
109 use super::*;
110
111 #[tokio::test]
112 async fn list_cardano_database_snapshots_returns_messages() {
113 let message = fake_messages();
114 let client = CardanoDatabaseClientDependencyInjector::new()
115 .with_aggregator_requester_mock_config(|requester| {
116 requester.expect_list_latest().return_once(move || Ok(message));
117 })
118 .build_cardano_database_client();
119
120 let messages = client.list().await.unwrap();
121
122 assert_eq!(2, messages.len());
123 assert_eq!("hash-123".to_string(), messages[0].hash);
124 assert_eq!("hash-456".to_string(), messages[1].hash);
125 }
126
127 #[tokio::test]
128 async fn list_cardano_database_snapshots_by_epoch_returns_messages() {
129 let message = fake_messages();
130 let client = CardanoDatabaseClientDependencyInjector::new()
131 .with_aggregator_requester_mock_config(|requester| {
132 requester
133 .expect_list_by_epoch()
134 .with(eq(EpochSpecifier::Number(Epoch(4))))
135 .return_once(move |_| Ok(message));
136 })
137 .build_cardano_database_client();
138
139 let messages = client.list_by_epoch(Epoch(4)).await.unwrap();
140
141 assert_eq!(2, messages.len());
142 assert_eq!("hash-123".to_string(), messages[0].hash);
143 assert_eq!("hash-456".to_string(), messages[1].hash);
144 }
145
146 #[tokio::test]
147 async fn list_cardano_database_snapshots_for_latest_epoch_returns_messages() {
148 let message = fake_messages();
149 let client = CardanoDatabaseClientDependencyInjector::new()
150 .with_aggregator_requester_mock_config(|requester| {
151 requester
152 .expect_list_by_epoch()
153 .with(eq(EpochSpecifier::Latest))
154 .return_once(move |_| Ok(message));
155 })
156 .build_cardano_database_client();
157
158 let messages = client.list_for_latest_epoch().await.unwrap();
159
160 assert_eq!(2, messages.len());
161 assert_eq!("hash-123".to_string(), messages[0].hash);
162 assert_eq!("hash-456".to_string(), messages[1].hash);
163 }
164
165 #[tokio::test]
166 async fn list_cardano_database_snapshots_for_latest_epoch_with_offset_returns_messages() {
167 let message = fake_messages();
168 let client = CardanoDatabaseClientDependencyInjector::new()
169 .with_aggregator_requester_mock_config(|requester| {
170 requester
171 .expect_list_by_epoch()
172 .with(eq(EpochSpecifier::LatestMinusOffset(42)))
173 .return_once(move |_| Ok(message));
174 })
175 .build_cardano_database_client();
176
177 let messages = client.list_for_latest_epoch_with_offset(42).await.unwrap();
178
179 assert_eq!(2, messages.len());
180 assert_eq!("hash-123".to_string(), messages[0].hash);
181 assert_eq!("hash-456".to_string(), messages[1].hash);
182 }
183 }
184
185 mod get {
186 use super::*;
187
188 #[tokio::test]
189 async fn get_cardano_database_snapshot_returns_message() {
190 let expected_cardano_database_snapshot = CardanoDatabaseSnapshot {
191 hash: "hash-123".to_string(),
192 ..CardanoDatabaseSnapshot::dummy()
193 };
194 let message = expected_cardano_database_snapshot.clone();
195 let client = CardanoDatabaseClientDependencyInjector::new()
196 .with_aggregator_requester_mock_config(|requester| {
197 requester
198 .expect_get_by_hash()
199 .with(eq("hash-123".to_string()))
200 .return_once(move |_| Ok(Some(message)));
201 })
202 .build_cardano_database_client();
203
204 let cardano_database = client
205 .get("hash-123")
206 .await
207 .unwrap()
208 .expect("should return a Cardano database");
209
210 assert_eq!(expected_cardano_database_snapshot, cardano_database);
211 }
212
213 #[tokio::test]
214 async fn get_cardano_database_snapshot_returns_error() {
215 let client = CardanoDatabaseClientDependencyInjector::new()
216 .with_aggregator_requester_mock_config(|requester| {
217 requester
218 .expect_get_by_hash()
219 .return_once(move |_| Err(anyhow!("error")));
220 })
221 .build_cardano_database_client();
222
223 client
224 .get("hash-123")
225 .await
226 .expect_err("Get Cardano database should return an error");
227 }
228 }
229}