Skip to content

Commit 3984006

Browse files
authored
test(mqttea,dpf): fold per-case error and node-label tests into tables (#2708)
1 parent 8d7939d commit 3984006

4 files changed

Lines changed: 404 additions & 611 deletions

File tree

crates/dpf/src/sdk.rs

Lines changed: 137 additions & 198 deletions
Original file line numberDiff line numberDiff line change
@@ -2668,30 +2668,6 @@ mod tests {
26682668
assert_eq!(result, "old-password");
26692669
}
26702670

2671-
#[tokio::test]
2672-
async fn test_init_config_defaults() {
2673-
let config = InitDpfResourcesConfig::default();
2674-
assert!(config.bfb_url.is_empty());
2675-
assert_eq!(config.deployment_name, "dpu-deployment");
2676-
assert_eq!(config.flavor_name, crate::flavor::DEFAULT_FLAVOR_NAME);
2677-
assert!(config.services.is_empty());
2678-
}
2679-
2680-
#[tokio::test]
2681-
async fn test_init_config_custom() {
2682-
let config = InitDpfResourcesConfig {
2683-
bfb_url: "http://example.com/test.bfb".to_string(),
2684-
deployment_name: "my-deployment".to_string(),
2685-
flavor_name: "my-flavor".to_string(),
2686-
services: vec![],
2687-
proxy: None,
2688-
};
2689-
2690-
assert_eq!(config.bfb_url, "http://example.com/test.bfb");
2691-
assert_eq!(config.deployment_name, "my-deployment");
2692-
assert_eq!(config.flavor_name, "my-flavor");
2693-
}
2694-
26952671
fn terminating_timestamp() -> k8s_openapi::apimachinery::pkg::apis::meta::v1::Time {
26962672
k8s_openapi::apimachinery::pkg::apis::meta::v1::Time(
26972673
k8s_openapi::jiff::Timestamp::UNIX_EPOCH,
@@ -3128,186 +3104,149 @@ mod tests {
31283104
);
31293105
}
31303106

3107+
/// `verify_node_labels` against a `TestLabeler` (which requires the single
3108+
/// label `test/node=true`): a node carries the current labels only when its
3109+
/// `metadata.labels` is a superset of the labeler's `node_labels()`. A
3110+
/// missing node verifies as `true` because it will be (re)created with the
3111+
/// current labels. Each row seeds one node state and asserts the verdict.
3112+
///
3113+
/// Folds the six former `test_verify_node_labels_*` cases.
31313114
#[tokio::test]
3132-
async fn test_verify_node_labels_current_labels_returns_true() {
3133-
let mock = SdkMock::new();
3134-
let sdk = DpfSdkBuilder::new(mock.clone(), TEST_NAMESPACE, String::new())
3135-
.with_labeler(TestLabeler)
3136-
.build_without_resources()
3137-
.await
3138-
.unwrap();
3139-
3140-
let info = DpuNodeInfo {
3141-
node_id: "host-001".to_string(),
3142-
host_bmc_ip: "10.0.0.1".parse().unwrap(),
3143-
device_ids: vec!["dpu-001".to_string()],
3144-
};
3145-
sdk.register_dpu_node(info).await.unwrap();
3146-
3147-
assert!(sdk.verify_node_labels("node-host-001").await.unwrap());
3148-
}
3149-
3150-
#[tokio::test]
3151-
async fn test_verify_node_labels_missing_node_returns_true() {
3152-
let mock = SdkMock::new();
3153-
let sdk = DpfSdkBuilder::new(mock, TEST_NAMESPACE, String::new())
3154-
.with_labeler(TestLabeler)
3155-
.build_without_resources()
3156-
.await
3157-
.unwrap();
3158-
3159-
assert!(
3160-
sdk.verify_node_labels("node-does-not-exist").await.unwrap(),
3161-
"non-existent node should return true (will be created with current labels)"
3162-
);
3163-
}
3164-
3165-
#[tokio::test]
3166-
async fn test_verify_node_labels_stale_labels_returns_false() {
3167-
let mock = SdkMock::new();
3168-
3169-
let stale_node = DPUNode {
3170-
metadata: ObjectMeta {
3171-
name: Some("node-host-001".to_string()),
3172-
namespace: Some(TEST_NAMESPACE.to_string()),
3173-
labels: Some(BTreeMap::from([(
3174-
"old/stale-label".to_string(),
3175-
"true".to_string(),
3176-
)])),
3177-
..Default::default()
3178-
},
3179-
spec: DpuNodeSpec {
3180-
dpus: Some(vec![]),
3181-
node_dms_address: None,
3182-
node_reboot_method: None,
3183-
},
3184-
status: None,
3185-
};
3186-
mock.nodes
3187-
.write()
3188-
.unwrap()
3189-
.insert(SdkMock::key(&stale_node), stale_node);
3190-
3191-
let sdk = DpfSdkBuilder::new(mock, TEST_NAMESPACE, String::new())
3192-
.with_labeler(TestLabeler)
3193-
.build_without_resources()
3194-
.await
3195-
.unwrap();
3196-
3197-
assert!(
3198-
!sdk.verify_node_labels("node-host-001").await.unwrap(),
3199-
"node with stale labels should return false"
3200-
);
3201-
}
3202-
3203-
#[tokio::test]
3204-
async fn test_verify_node_labels_no_labels_returns_false() {
3205-
let mock = SdkMock::new();
3206-
3207-
let bare_node = DPUNode {
3208-
metadata: ObjectMeta {
3209-
name: Some("node-host-001".to_string()),
3210-
namespace: Some(TEST_NAMESPACE.to_string()),
3211-
labels: None,
3212-
..Default::default()
3213-
},
3214-
spec: DpuNodeSpec {
3215-
dpus: Some(vec![]),
3216-
node_dms_address: None,
3217-
node_reboot_method: None,
3218-
},
3219-
status: None,
3220-
};
3221-
mock.nodes
3222-
.write()
3223-
.unwrap()
3224-
.insert(SdkMock::key(&bare_node), bare_node);
3225-
3226-
let sdk = DpfSdkBuilder::new(mock, TEST_NAMESPACE, String::new())
3227-
.with_labeler(TestLabeler)
3228-
.build_without_resources()
3229-
.await
3230-
.unwrap();
3231-
3232-
assert!(
3233-
!sdk.verify_node_labels("node-host-001").await.unwrap(),
3234-
"node with no labels should return false when labeler expects labels"
3235-
);
3236-
}
3237-
3238-
#[tokio::test]
3239-
async fn test_verify_node_labels_superset_returns_true() {
3240-
let mock = SdkMock::new();
3241-
3242-
let superset_node = DPUNode {
3243-
metadata: ObjectMeta {
3244-
name: Some("node-host-001".to_string()),
3245-
namespace: Some(TEST_NAMESPACE.to_string()),
3246-
labels: Some(BTreeMap::from([
3247-
("test/node".to_string(), "true".to_string()),
3248-
("extra/label".to_string(), "extra-value".to_string()),
3249-
])),
3250-
..Default::default()
3251-
},
3252-
spec: DpuNodeSpec {
3253-
dpus: Some(vec![]),
3254-
node_dms_address: None,
3255-
node_reboot_method: None,
3256-
},
3257-
status: None,
3258-
};
3259-
mock.nodes
3260-
.write()
3261-
.unwrap()
3262-
.insert(SdkMock::key(&superset_node), superset_node);
3115+
async fn verify_node_labels_against_seeded_node() {
3116+
use carbide_test_support::Outcome::Yields;
3117+
use carbide_test_support::{Case, check_cases_async};
3118+
3119+
/// What the mock's node store holds before the check runs.
3120+
enum Seeded {
3121+
/// No node at all under the queried name.
3122+
Absent,
3123+
/// A node created through `register_dpu_node`, so it carries
3124+
/// whatever labels the labeler currently produces.
3125+
RegisteredByLabeler,
3126+
/// A node inserted directly with these `metadata.labels`
3127+
/// (`None` means the labels field is absent entirely).
3128+
WithLabels(Option<BTreeMap<String, String>>),
3129+
}
32633130

3264-
let sdk = DpfSdkBuilder::new(mock, TEST_NAMESPACE, String::new())
3265-
.with_labeler(TestLabeler)
3266-
.build_without_resources()
3267-
.await
3268-
.unwrap();
3131+
struct Row {
3132+
/// Pre-existing node state in the mock.
3133+
seeded: Seeded,
3134+
/// Node name passed to `verify_node_labels`.
3135+
query: &'static str,
3136+
}
32693137

3270-
assert!(
3271-
sdk.verify_node_labels("node-host-001").await.unwrap(),
3272-
"node with a superset of expected labels should return true"
3273-
);
3274-
}
3138+
// Build the per-row mock + SDK, seed the node, run the check.
3139+
let run = |row: Row| async move {
3140+
let mock = SdkMock::new();
3141+
// A node seeded with explicit labels is inserted before the SDK is
3142+
// built; `RegisteredByLabeler` is handled after the build (it needs
3143+
// the SDK to apply the labeler); `Absent` seeds nothing.
3144+
if let Seeded::WithLabels(labels) = &row.seeded {
3145+
let node = DPUNode {
3146+
metadata: ObjectMeta {
3147+
name: Some("node-host-001".to_string()),
3148+
namespace: Some(TEST_NAMESPACE.to_string()),
3149+
labels: labels.clone(),
3150+
..Default::default()
3151+
},
3152+
spec: DpuNodeSpec {
3153+
dpus: Some(vec![]),
3154+
node_dms_address: None,
3155+
node_reboot_method: None,
3156+
},
3157+
status: None,
3158+
};
3159+
mock.nodes
3160+
.write()
3161+
.unwrap()
3162+
.insert(SdkMock::key(&node), node);
3163+
}
32753164

3276-
#[tokio::test]
3277-
async fn test_verify_node_labels_wrong_value_returns_false() {
3278-
let mock = SdkMock::new();
3165+
let sdk = DpfSdkBuilder::new(mock, TEST_NAMESPACE, String::new())
3166+
.with_labeler(TestLabeler)
3167+
.build_without_resources()
3168+
.await
3169+
.unwrap();
3170+
3171+
if matches!(row.seeded, Seeded::RegisteredByLabeler) {
3172+
sdk.register_dpu_node(DpuNodeInfo {
3173+
node_id: "host-001".to_string(),
3174+
host_bmc_ip: "10.0.0.1".parse().unwrap(),
3175+
device_ids: vec!["dpu-001".to_string()],
3176+
})
3177+
.await
3178+
.unwrap();
3179+
}
32793180

3280-
let wrong_value_node = DPUNode {
3281-
metadata: ObjectMeta {
3282-
name: Some("node-host-001".to_string()),
3283-
namespace: Some(TEST_NAMESPACE.to_string()),
3284-
labels: Some(BTreeMap::from([(
3285-
"test/node".to_string(),
3286-
"false".to_string(),
3287-
)])),
3288-
..Default::default()
3289-
},
3290-
spec: DpuNodeSpec {
3291-
dpus: Some(vec![]),
3292-
node_dms_address: None,
3293-
node_reboot_method: None,
3294-
},
3295-
status: None,
3181+
// DpfError isn't PartialEq, so render it to a String for the
3182+
// table's Outcome comparison; these rows all expect success anyway.
3183+
sdk.verify_node_labels(row.query)
3184+
.await
3185+
.map_err(|e| e.to_string())
32963186
};
3297-
mock.nodes
3298-
.write()
3299-
.unwrap()
3300-
.insert(SdkMock::key(&wrong_value_node), wrong_value_node);
3301-
3302-
let sdk = DpfSdkBuilder::new(mock, TEST_NAMESPACE, String::new())
3303-
.with_labeler(TestLabeler)
3304-
.build_without_resources()
3305-
.await
3306-
.unwrap();
33073187

3308-
assert!(
3309-
!sdk.verify_node_labels("node-host-001").await.unwrap(),
3310-
"node with correct key but wrong value should return false"
3311-
);
3188+
check_cases_async(
3189+
[
3190+
Case {
3191+
scenario: "node registered by labeler has current labels",
3192+
input: Row {
3193+
seeded: Seeded::RegisteredByLabeler,
3194+
query: "node-host-001",
3195+
},
3196+
expect: Yields(true),
3197+
},
3198+
Case {
3199+
scenario: "missing node verifies true (created with current labels)",
3200+
input: Row {
3201+
seeded: Seeded::Absent,
3202+
query: "node-does-not-exist",
3203+
},
3204+
expect: Yields(true),
3205+
},
3206+
Case {
3207+
scenario: "stale labels (none of the required keys) -> false",
3208+
input: Row {
3209+
seeded: Seeded::WithLabels(Some(BTreeMap::from([(
3210+
"old/stale-label".to_string(),
3211+
"true".to_string(),
3212+
)]))),
3213+
query: "node-host-001",
3214+
},
3215+
expect: Yields(false),
3216+
},
3217+
Case {
3218+
scenario: "no labels field at all -> false",
3219+
input: Row {
3220+
seeded: Seeded::WithLabels(None),
3221+
query: "node-host-001",
3222+
},
3223+
expect: Yields(false),
3224+
},
3225+
Case {
3226+
scenario: "superset of required labels -> true",
3227+
input: Row {
3228+
seeded: Seeded::WithLabels(Some(BTreeMap::from([
3229+
("test/node".to_string(), "true".to_string()),
3230+
("extra/label".to_string(), "extra-value".to_string()),
3231+
]))),
3232+
query: "node-host-001",
3233+
},
3234+
expect: Yields(true),
3235+
},
3236+
Case {
3237+
scenario: "required key present but wrong value -> false",
3238+
input: Row {
3239+
seeded: Seeded::WithLabels(Some(BTreeMap::from([(
3240+
"test/node".to_string(),
3241+
"false".to_string(),
3242+
)]))),
3243+
query: "node-host-001",
3244+
},
3245+
expect: Yields(false),
3246+
},
3247+
],
3248+
run,
3249+
)
3250+
.await;
33123251
}
33133252
}

0 commit comments

Comments
 (0)