@@ -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