ic-query 0.89.0

Internet Computer query library for CloudEngine, NNS, SNS, ICRC, system canisters, and public network metadata
Documentation
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]);
    }
}