use super::fixtures::*;
use super::*;
#[tokio::test(flavor = "current_thread")]
async fn topology_refresh_counts_component_reports() {
let source = RecordingTopologySource::default();
let request = NnsTopologyRefreshRequest::new(topology_read_request_fixture());
let report = refresh_nns_topology_report_with_source(&request, &source)
.await
.expect("topology refresh");
assert_eq!(report.schema_version, 1);
assert_eq!(report.component_count, 5);
assert_eq!(report.wrote_cache_count, 5);
assert_eq!(report.replaced_existing_cache_count, 1);
assert_eq!(report.components[0].source, "subnet_catalog");
assert_eq!(report.components[0].item_count, 2);
assert_eq!(report.components[1].source, "nodes");
assert_eq!(report.components[1].item_count, 3);
assert_eq!(report.components[2].source, "node_providers");
assert_eq!(report.components[2].item_count, 1);
assert_eq!(report.components[3].source, "node_operators");
assert_eq!(report.components[3].item_count, 2);
assert_eq!(report.components[4].source, "data_centers");
assert_eq!(report.components[4].item_count, 1);
assert_eq!(
*source.calls.lock().unwrap(),
[
"subnet_catalog",
"nodes",
"node_providers",
"node_operators",
"data_centers"
]
);
}
#[tokio::test(flavor = "current_thread")]
async fn topology_refresh_stops_at_the_first_source_failure() {
let request = NnsTopologyRefreshRequest::new(topology_read_request_fixture());
let components = [
"subnet_catalog",
"nodes",
"node_providers",
"node_operators",
"data_centers",
];
for (index, component) in components.iter().enumerate() {
let source = RecordingTopologySource {
fail_at: Some(component),
..Default::default()
};
let error = refresh_nns_topology_report_with_source(&request, &source)
.await
.expect_err("source failure");
assert!(
matches!(error, NnsTopologyHostError::Inventory(crate::nns::NnsInventoryError::InvalidSourceData { reason, .. }) if reason == *component)
);
assert_eq!(*source.calls.lock().unwrap(), components[..=index]);
}
let mut request = request;
request.read.cache.network = "local".to_string();
let source = RecordingTopologySource::default();
assert!(
matches!(refresh_nns_topology_report_with_source(&request, &source).await,
Err(NnsTopologyHostError::UnsupportedNetwork { network }) if network == "local")
);
assert!(source.calls.lock().unwrap().is_empty());
}
#[tokio::test(flavor = "current_thread")]
async fn topology_refresh_rejects_mismatched_component_collections() {
let request = NnsTopologyRefreshRequest::new(topology_read_request_fixture());
let components = [
"subnet_catalog",
"nodes",
"node_providers",
"node_operators",
"data_centers",
];
for (index, component) in components.iter().enumerate().skip(1) {
let source = RecordingTopologySource {
wrong_refresh_collection_at: Some(component),
..Default::default()
};
let error = refresh_nns_topology_report_with_source(&request, &source)
.await
.expect_err("collection mismatch");
let rejected_collection = match error {
NnsTopologyHostError::Inventory(crate::nns::NnsInventoryError::InvalidSourceData {
collection,
..
}) => collection,
other => panic!("unexpected refresh failure: {other}"),
};
let expected = [
crate::nns::NnsInventoryCollection::Node,
crate::nns::NnsInventoryCollection::NodeProvider,
crate::nns::NnsInventoryCollection::NodeOperator,
crate::nns::NnsInventoryCollection::DataCenter,
][index - 1];
assert_eq!(rejected_collection, expected);
assert_eq!(*source.calls.lock().unwrap(), components[..=index]);
}
}