Skip to content

Commit

Permalink
Add test
Browse files Browse the repository at this point in the history
  • Loading branch information
smklein committed Jan 8, 2025
1 parent 6b6dd59 commit 96e8673
Showing 1 changed file with 119 additions and 0 deletions.
119 changes: 119 additions & 0 deletions nexus/db-queries/src/db/datastore/support_bundle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -939,6 +939,15 @@ mod test {
}
}

fn delete_dataset_for_bundle(bp: &mut Blueprint, bundle: &SupportBundle) {
for datasets in bp.blueprint_datasets.values_mut() {
let bundle_dataset_id: DatasetUuid = bundle.dataset_id.into();
if datasets.datasets.remove(&bundle_dataset_id).is_some() {
datasets.generation = datasets.generation.next();
}
}
}

fn expunge_nexus_for_bundle(bp: &mut Blueprint, bundle: &SupportBundle) {
for zones in bp.blueprint_zones.values_mut() {
for (_, zone) in &mut zones.zones {
Expand Down Expand Up @@ -1171,6 +1180,116 @@ mod test {
logctx.cleanup_successful();
}

// This test is identical to "test_bundle_failed_from_expunged_dataset", but
// it fully deletes the dataset rather than marking it expunged in the
// blueprint.
#[tokio::test]
async fn test_bundle_failed_from_pruned_dataset() {
static TEST_NAME: &str = "test_bundle_failed_from_pruned_dataset";
let logctx = dev::test_setup_log(TEST_NAME);
let db = TestDatabase::new_with_datastore(&logctx.log).await;
let (opctx, datastore) = (db.opctx(), db.datastore());

let mut rng = SimRngState::from_seed(TEST_NAME);
let (_example, mut bp1) = ExampleSystemBuilder::new_with_rng(
&logctx.log,
rng.next_system_rng(),
)
.build();

// Weirdly, the "ExampleSystemBuilder" blueprint has a parent blueprint,
// but which isn't exposed through the API. Since we're only able to see
// the blueprint it emits, that means we can't actually make it the
// target because "the parent blueprint is not the current target".
//
// Instead of dealing with that, we lie: claim this is the primordial
// blueprint, with no parent.
//
// Regardless, make this starter blueprint our target.
bp1.parent_blueprint_id = None;
bp_insert_and_make_target(&opctx, &datastore, &bp1).await;

// Manually perform the equivalent of blueprint execution to populate
// database records.
let sleds = TestSled::new_from_blueprint(&bp1);
for sled in &sleds {
sled.create_database_records(&datastore, &opctx).await;
}

// Extract Nexus and Dataset information from the generated blueprint.
let this_nexus_id = get_nexuses_from_blueprint(
&bp1,
BlueprintZoneFilter::ShouldBeRunning,
)
.get(0)
.map(|id| *id)
.expect("There should be a Nexus in the example blueprint");
let debug_datasets = get_debug_datasets_from_blueprint(
&bp1,
BlueprintDatasetFilter::InService,
);
assert!(!debug_datasets.is_empty());

// When we create a bundle, it should exist on a dataset provisioned by
// the blueprint.
let bundle = datastore
.support_bundle_create(&opctx, "for the test", this_nexus_id)
.await
.expect("Should be able to create bundle");
assert_eq!(bundle.assigned_nexus, Some(this_nexus_id.into()));
assert!(
debug_datasets.contains(&DatasetUuid::from(bundle.dataset_id)),
"Bundle should have been allocated from a blueprint dataset"
);

// If we try to "fail support bundles" from expunged datasets/nexuses,
// we should see a no-op. Nothing has been expunged yet!
let report =
datastore.support_bundle_fail_expunged(&opctx, &bp1).await.expect(
"Should have been able to perform no-op support bundle failure",
);
assert_eq!(SupportBundleExpungementReport::default(), report);

// Fully remove the bundle's dataset (manually)
let bp2 = {
let mut bp2 = bp1.clone();
bp2.id = Uuid::new_v4();
bp2.parent_blueprint_id = Some(bp1.id);
delete_dataset_for_bundle(&mut bp2, &bundle);
bp2
};
bp_insert_and_make_target(&opctx, &datastore, &bp2).await;

datastore
.support_bundle_fail_expunged(&opctx, &bp1)
.await
.expect_err("bp1 is no longer the target; this should fail");
let report = datastore
.support_bundle_fail_expunged(&opctx, &bp2)
.await
.expect("Should have been able to mark bundle state as failed");
assert_eq!(
SupportBundleExpungementReport {
bundles_failed_missing_datasets: 1,
..Default::default()
},
report
);

let observed_bundle = datastore
.support_bundle_get(&opctx, bundle.id.into())
.await
.expect("Should be able to get bundle we just failed");
assert_eq!(SupportBundleState::Failed, observed_bundle.state);
assert!(observed_bundle
.reason_for_failure
.unwrap()
.contains(FAILURE_REASON_NO_DATASET));

db.terminate().await;
logctx.cleanup_successful();
}

#[tokio::test]
async fn test_bundle_failed_from_expunged_nexus_no_reassign() {
static TEST_NAME: &str =
Expand Down

0 comments on commit 96e8673

Please sign in to comment.