@@ -243,8 +243,6 @@ impl DataStore {
243243
244244 // If this affinity group is a member in other anti-affinity
245245 // groups, remove those memberships
246- //
247- // TODO: This needs testing
248246 {
249247 use db:: schema:: anti_affinity_group_affinity_membership:: dsl as member_dsl;
250248 diesel:: delete ( member_dsl:: anti_affinity_group_affinity_membership)
@@ -2459,6 +2457,101 @@ mod tests {
24592457 logctx. cleanup_successful ( ) ;
24602458 }
24612459
2460+ // Since this name is gnarly, just to be clear:
2461+ // - Affinity groups can be "members" within anti-affinity groups
2462+ // - If one of these memberships is alive when the affinity group is
2463+ // deleted, that membership should be automatically removed
2464+ //
2465+ // Basically, do not keep around a reference to a dead affinity group.
2466+ #[ tokio:: test]
2467+ async fn affinity_group_delete_group_deletes_membership_in_anti_affinity_groups (
2468+ ) {
2469+ // Setup
2470+ let logctx =
2471+ dev:: test_setup_log ( "affinity_group_delete_group_deletes_membership_in_anti_affinity_groups" ) ;
2472+ let db = TestDatabase :: new_with_datastore ( & logctx. log ) . await ;
2473+ let ( opctx, datastore) = ( db. opctx ( ) , db. datastore ( ) ) ;
2474+
2475+ // Create a project and the groups
2476+ let ( authz_project, ..) =
2477+ create_project ( & opctx, & datastore, "my-project" ) . await ;
2478+ let affinity_group = create_affinity_group (
2479+ & opctx,
2480+ & datastore,
2481+ & authz_project,
2482+ "affinity" ,
2483+ )
2484+ . await
2485+ . unwrap ( ) ;
2486+ let anti_affinity_group = create_anti_affinity_group (
2487+ & opctx,
2488+ & datastore,
2489+ & authz_project,
2490+ "anti-affinity" ,
2491+ )
2492+ . await
2493+ . unwrap ( ) ;
2494+
2495+ let ( .., authz_a_group) = LookupPath :: new ( opctx, datastore)
2496+ . affinity_group_id ( affinity_group. id ( ) )
2497+ . lookup_for ( authz:: Action :: Modify )
2498+ . await
2499+ . unwrap ( ) ;
2500+ let ( .., authz_aa_group) = LookupPath :: new ( opctx, datastore)
2501+ . anti_affinity_group_id ( anti_affinity_group. id ( ) )
2502+ . lookup_for ( authz:: Action :: Modify )
2503+ . await
2504+ . unwrap ( ) ;
2505+
2506+ // Add the affinity group to the anti-affinity group.
2507+ let member = external:: AntiAffinityGroupMember :: AffinityGroup (
2508+ AffinityGroupUuid :: from_untyped_uuid ( affinity_group. id ( ) ) ,
2509+ ) ;
2510+ datastore
2511+ . anti_affinity_group_member_add (
2512+ & opctx,
2513+ & authz_aa_group,
2514+ member. clone ( ) ,
2515+ )
2516+ . await
2517+ . unwrap ( ) ;
2518+
2519+ // Right now, the affinity group is observable
2520+ datastore
2521+ . anti_affinity_group_member_view (
2522+ & opctx,
2523+ & authz_aa_group,
2524+ member. clone ( ) ,
2525+ )
2526+ . await
2527+ . expect ( "Group member should be visible - we just added it" ) ;
2528+
2529+ // Delete the affinity group (the member)
2530+ datastore. affinity_group_delete ( & opctx, & authz_a_group) . await . unwrap ( ) ;
2531+
2532+ // The affinity group membership should have been revoked
2533+ let err = datastore
2534+ . anti_affinity_group_member_view (
2535+ & opctx,
2536+ & authz_aa_group,
2537+ member. clone ( ) ,
2538+ )
2539+ . await
2540+ . expect_err ( "Group member should no longer exist" ) ;
2541+ assert ! (
2542+ matches!(
2543+ err,
2544+ Error :: ObjectNotFound { type_name, .. }
2545+ if type_name == ResourceType :: AntiAffinityGroupMember
2546+ ) ,
2547+ "Unexpected error: {err:?}"
2548+ ) ;
2549+
2550+ // Clean up.
2551+ db. terminate ( ) . await ;
2552+ logctx. cleanup_successful ( ) ;
2553+ }
2554+
24622555 #[ tokio:: test]
24632556 async fn affinity_group_delete_instance_deletes_membership ( ) {
24642557 // Setup
0 commit comments