diff --git a/internal/mithril-build-script/src/fake_aggregator.rs b/internal/mithril-build-script/src/fake_aggregator.rs index 44bf1cba079..61f3428fda2 100644 --- a/internal/mithril-build-script/src/fake_aggregator.rs +++ b/internal/mithril-build-script/src/fake_aggregator.rs @@ -106,6 +106,10 @@ impl FakeAggregatorData { "csd_hashes", BTreeSet::from_iter(self.individual_csds.keys().cloned()), ), + generate_ids_array( + "csd_epochs", + BTreeSet::from_iter(extract_csd_epochs(&self.individual_csds)), + ), generate_ids_array( "certificate_hashes", BTreeSet::from_iter(self.individual_certificates.keys().cloned()), @@ -143,6 +147,10 @@ impl FakeAggregatorData { "csd_hashes", BTreeSet::from_iter(self.individual_csds.keys().cloned()), ), + generate_ids_array( + "csd_epochs", + BTreeSet::from_iter(extract_csd_epochs(&self.individual_csds)), + ), generate_artifact_getter("csds", self.individual_csds), generate_list_getter("csd_list", self.csds_list), generate_ids_array( @@ -200,6 +208,28 @@ impl FakeAggregatorData { } } +pub fn extract_csd_epochs(individual_csds: &BTreeMap) -> Vec { + individual_csds + .values() + .map(|content| { + let json_value: serde_json::Value = + serde_json::from_str(content).unwrap_or_else(|err| { + panic!( + "Failed to parse JSON in csd content: {}\nError: {}", + content, err + ); + }); + + json_value + .get("epoch") + .and_then(|epoch| epoch.as_str().map(|s| s.to_owned())) + .unwrap_or_else(|| { + panic!("Epoch not found or invalid in csd content: {}", content); + }) + }) + .collect() +} + fn extract_artifact_id_and_content( key: &String, value: &serde_json::Value, @@ -377,4 +407,51 @@ fn b() {} ]); assert_eq!(expected, id_per_json); } + + #[test] + fn extract_csd_epochs_with_valid_data() { + let mut csds = BTreeMap::new(); + csds.insert( + "csd-123".to_string(), + r#"{"hash": "csd-123", "epoch": "123"}"#.to_string(), + ); + csds.insert( + "csd-456".to_string(), + r#"{"hash": "csd-456", "epoch": "456"}"#.to_string(), + ); + + let epochs = extract_csd_epochs(&csds); + + assert_eq!(epochs, vec!["123".to_string(), "456".to_string()]); + } + + #[test] + #[should_panic(expected = "Failed to parse JSON in csd content")] + fn extract_csd_epochs_with_invalid_json() { + let mut csds = BTreeMap::new(); + csds.insert( + "csd-123".to_string(), + r#""hash": "csd-123", "epoch": "123""#.to_string(), + ); + + extract_csd_epochs(&csds); + } + + #[test] + #[should_panic(expected = "Epoch not found or invalid in csd content")] + fn test_extract_csd_epochs_with_missing_epoch() { + let mut csds = BTreeMap::new(); + csds.insert("csd-123".to_string(), r#"{"hash": "csd-123"}"#.to_string()); + + extract_csd_epochs(&csds); + } + + #[test] + fn test_extract_csd_epochs_with_empty_map() { + let csds = BTreeMap::new(); + + let epochs = extract_csd_epochs(&csds); + + assert!(epochs.is_empty()); + } } diff --git a/mithril-test-lab/mithril-aggregator-fake/src/application.rs b/mithril-test-lab/mithril-aggregator-fake/src/application.rs index 16c40eda101..4ed0ba6e703 100644 --- a/mithril-test-lab/mithril-aggregator-fake/src/application.rs +++ b/mithril-test-lab/mithril-aggregator-fake/src/application.rs @@ -576,4 +576,56 @@ mod tests { test(task, PORT).await; } + + #[tokio::test] + async fn get_cardano_stake_distribution_by_epoch() { + const PORT: u16 = 3018; + let task = tokio::spawn(async move { + // Yield back to Tokio's scheduler to ensure the web server is ready before going on. + yield_now().await; + + let path = "/artifact/cardano-stake-distribution/epoch/{epoch}"; + let epoch = default_values::csd_epochs()[0]; + let response = http_request(PORT, &path.replace("{epoch}", epoch)).await; + + APISpec::verify_conformity( + get_spec_files(), + "GET", + path, + "application/json", + &Null, + &response, + &StatusCode::OK, + ) + .map_err(|e| anyhow!(e)) + }); + + test(task, PORT).await; + } + + #[tokio::test] + async fn get_no_cardano_stake_distribution_by_epoch() { + const PORT: u16 = 3019; + let task = tokio::spawn(async move { + // Yield back to Tokio's scheduler to ensure the web server is ready before going on. + yield_now().await; + + let path = "/artifact/cardano-stake-distribution/epoch/{epoch}"; + let epoch = &u64::MAX.to_string(); + let response = http_request(PORT, &path.replace("{epoch}", epoch)).await; + + APISpec::verify_conformity( + get_spec_files(), + "GET", + path, + "application/json", + &Null, + &response, + &StatusCode::NOT_FOUND, + ) + .map_err(|e| anyhow!(e)) + }); + + test(task, PORT).await; + } } diff --git a/mithril-test-lab/mithril-aggregator-fake/src/handlers.rs b/mithril-test-lab/mithril-aggregator-fake/src/handlers.rs index 46067d60a32..9dfbaa8e9a8 100644 --- a/mithril-test-lab/mithril-aggregator-fake/src/handlers.rs +++ b/mithril-test-lab/mithril-aggregator-fake/src/handlers.rs @@ -452,17 +452,8 @@ mod tests { #[tokio::test] async fn existing_csd_epoch() { - #[derive(Debug, serde::Deserialize)] - struct TmpCardanoStakeDistributionData { - epoch: u64, - } - let state: State = State(AppState::default().into()); - let hash = default_values::csd_hashes()[0].to_string(); - let csds = default_values::csds(); - let tmp_csd_data: TmpCardanoStakeDistributionData = - serde_json::from_str(csds.get(&hash).unwrap()).unwrap(); - let epoch = Path(tmp_csd_data.epoch.to_string()); + let epoch = Path(default_values::csd_epochs()[0].to_string()); let response = csd_by_epoch(epoch, state) .await