@@ -3436,16 +3436,26 @@ func Test_deleteBindingFromSnapshot(t *testing.T) {
34363436 }
34373437}
34383438
3439- func TestCreateOrUpdateAttachedBinding_EmitsDependencyEvents (t * testing.T ) {
3440- testScheme := runtime .NewScheme ()
3441- utilruntime .Must (workv1alpha2 .AddToScheme (testScheme ))
3439+ type dependencyPolicyTestEnv struct {
3440+ distributor * DependenciesDistributor
3441+ client client.Client
3442+ recorder * record.FakeRecorder
3443+ existing * workv1alpha2.ResourceBinding
3444+ dependent * unstructured.Unstructured
3445+ }
3446+
3447+ func newDependencyPolicyTestEnv (t * testing.T ) * dependencyPolicyTestEnv {
3448+ t .Helper ()
3449+
3450+ scheme := runtime .NewScheme ()
3451+ utilruntime .Must (workv1alpha2 .Install (scheme ))
34423452
3443- dependentObj := & unstructured.Unstructured {}
3444- dependentObj .SetAPIVersion ("v1" )
3445- dependentObj .SetKind ("ConfigMap" )
3446- dependentObj .SetNamespace ("default" )
3447- dependentObj .SetName ("app-config" )
3448- dependentObj .SetUID (types .UID ("cm-uid" ))
3453+ dependent := & unstructured.Unstructured {}
3454+ dependent .SetAPIVersion ("v1" )
3455+ dependent .SetKind ("ConfigMap" )
3456+ dependent .SetNamespace ("default" )
3457+ dependent .SetName ("app-config" )
3458+ dependent .SetUID (types .UID ("cm-uid" ))
34493459
34503460 parentOne := & workv1alpha2.ResourceBinding {
34513461 ObjectMeta : metav1.ObjectMeta {
@@ -3461,17 +3471,68 @@ func TestCreateOrUpdateAttachedBinding_EmitsDependencyEvents(t *testing.T) {
34613471 PreserveResourcesOnDeletion : ptr .To (true ),
34623472 },
34633473 }
3464- attachedFromParentOne := buildAttachedBinding ( parentOne , dependentObj )
3465- // Simulate existing dependency binding already persisted in the cluster.
3474+
3475+ attachedFromParentOne := buildAttachedBinding ( parentOne , dependent )
34663476 existing := attachedFromParentOne .DeepCopy ()
34673477
3468- fakeClient := fake .NewClientBuilder ().WithScheme (testScheme ).WithObjects (existing ).Build ()
3478+ fakeClient := fake .NewClientBuilder ().WithScheme (scheme ).WithObjects (existing ).Build ()
34693479 recorder := record .NewFakeRecorder (10 )
3470- d := & DependenciesDistributor {
3480+
3481+ distributor := & DependenciesDistributor {
34713482 Client : fakeClient ,
34723483 EventRecorder : recorder ,
34733484 }
34743485
3486+ return & dependencyPolicyTestEnv {
3487+ distributor : distributor ,
3488+ client : fakeClient ,
3489+ recorder : recorder ,
3490+ existing : existing ,
3491+ dependent : dependent ,
3492+ }
3493+ }
3494+
3495+ func waitForEvents (t * testing.T , recorder * record.FakeRecorder , want int , timeout time.Duration ) []string {
3496+ t .Helper ()
3497+
3498+ eventList := make ([]string , 0 , want )
3499+ timeoutCh := time .After (timeout )
3500+ for len (eventList ) < want {
3501+ select {
3502+ case evt := <- recorder .Events :
3503+ eventList = append (eventList , evt )
3504+ case <- timeoutCh :
3505+ t .Fatalf ("timed out waiting for %d events, got %v" , want , eventList )
3506+ }
3507+ }
3508+ return eventList
3509+ }
3510+
3511+ func findEventByReason (t * testing.T , eventList []string , reason string ) string {
3512+ t .Helper ()
3513+
3514+ for _ , evt := range eventList {
3515+ if strings .Contains (evt , reason ) {
3516+ return evt
3517+ }
3518+ }
3519+ t .Fatalf ("expected event reason %s in %v" , reason , eventList )
3520+ return ""
3521+ }
3522+
3523+ func assertEventMessageContains (t * testing.T , event string , substrings ... string ) {
3524+ t .Helper ()
3525+
3526+ for _ , substring := range substrings {
3527+ if ! strings .Contains (event , substring ) {
3528+ t .Errorf ("event %q missing substring %q" , event , substring )
3529+ }
3530+ }
3531+ }
3532+
3533+ func TestCreateOrUpdateAttachedBinding_RecordsConflictEvent (t * testing.T ) {
3534+ env := newDependencyPolicyTestEnv (t )
3535+
34753536 parentTwo := & workv1alpha2.ResourceBinding {
34763537 ObjectMeta : metav1.ObjectMeta {
34773538 Name : "workload-b" ,
@@ -3486,66 +3547,84 @@ func TestCreateOrUpdateAttachedBinding_EmitsDependencyEvents(t *testing.T) {
34863547 PreserveResourcesOnDeletion : ptr .To (false ),
34873548 },
34883549 }
3489- attachedFromParentTwo := buildAttachedBinding (parentTwo , dependentObj )
3550+ attachedFromParentTwo := buildAttachedBinding (parentTwo , env . dependent )
34903551
3491- if err := d .createOrUpdateAttachedBinding (attachedFromParentTwo ); err != nil {
3552+ if err := env . distributor .createOrUpdateAttachedBinding (attachedFromParentTwo ); err != nil {
34923553 t .Fatalf ("createOrUpdateAttachedBinding() error = %v" , err )
34933554 }
34943555
34953556 updated := & workv1alpha2.ResourceBinding {}
3496- if err := fakeClient . Get (context .TODO (), client .ObjectKeyFromObject (existing ), updated ); err != nil {
3557+ if err := env . client . Get (context .TODO (), client .ObjectKeyFromObject (env . existing ), updated ); err != nil {
34973558 t .Fatalf ("failed to fetch updated binding: %v" , err )
34983559 }
34993560 if len (updated .Spec .RequiredBy ) != 2 {
35003561 t .Fatalf ("expected 2 parents after aggregation, got %d" , len (updated .Spec .RequiredBy ))
35013562 }
35023563
3503- eventsReceived := make ([]string , 0 , 2 )
3504- for len (eventsReceived ) < 2 {
3505- select {
3506- case evt := <- recorder .Events :
3507- eventsReceived = append (eventsReceived , evt )
3508- case <- time .After (time .Second ):
3509- t .Fatalf ("timed out waiting for dependency aggregation events, got %v" , eventsReceived )
3510- }
3511- }
3564+ eventList := waitForEvents (t , env .recorder , 2 , time .Second )
35123565
3513- var conflictEvent , aggregatedEvent string
3514- for _ , evt := range eventsReceived {
3515- if strings .Contains (evt , events .EventReasonDependencyPolicyConflict ) {
3516- conflictEvent = evt
3517- }
3518- if strings .Contains (evt , events .EventReasonDependencyPolicyAggregated ) {
3519- aggregatedEvent = evt
3520- }
3521- }
3566+ conflictEvent := findEventByReason (t , eventList , events .EventReasonDependencyPolicyConflict )
3567+ assertEventMessageContains (t , conflictEvent ,
3568+ "[dep-agg] conflict" ,
3569+ "conflictResolution existing=Overwrite incoming=Abort" ,
3570+ "preserveResourcesOnDeletion existing=true incoming=false" ,
3571+ )
35223572
3523- if conflictEvent == "" {
3524- t .Fatalf ("expected conflict event in %v" , eventsReceived )
3525- }
3526- if ! strings .Contains (conflictEvent , "[dep-agg] conflict" ) {
3527- t .Errorf ("unexpected conflict event message: %s" , conflictEvent )
3528- }
3529- if ! strings .Contains (conflictEvent , "conflictResolution existing=Overwrite incoming=Abort" ) {
3530- t .Errorf ("conflict event missing conflictResolution details: %s" , conflictEvent )
3531- }
3532- if ! strings .Contains (conflictEvent , "preserveResourcesOnDeletion existing=true incoming=false" ) {
3533- t .Errorf ("conflict event missing preserveResourcesOnDeletion details: %s" , conflictEvent )
3534- }
3573+ aggregatedEvent := findEventByReason (t , eventList , events .EventReasonDependencyPolicyAggregated )
3574+ assertEventMessageContains (t , aggregatedEvent ,
3575+ "[dep-agg] aggregated policy" ,
3576+ "conflictResolution=Abort" ,
3577+ "preserveResourcesOnDeletion=false" ,
3578+ "default/workload-a" ,
3579+ "default/workload-b" ,
3580+ )
3581+ }
35353582
3536- if aggregatedEvent == "" {
3537- t .Fatalf ("expected aggregation event in %v" , eventsReceived )
3583+ func TestCreateOrUpdateAttachedBinding_RecordsAggregationEvent (t * testing.T ) {
3584+ env := newDependencyPolicyTestEnv (t )
3585+
3586+ parentTwo := & workv1alpha2.ResourceBinding {
3587+ ObjectMeta : metav1.ObjectMeta {
3588+ Name : "workload-b" ,
3589+ Namespace : "default" ,
3590+ Labels : map [string ]string {
3591+ workv1alpha2 .ResourceBindingPermanentIDLabel : "rb-uid-b" ,
3592+ },
3593+ },
3594+ Spec : workv1alpha2.ResourceBindingSpec {
3595+ Clusters : []workv1alpha2.TargetCluster {{Name : "member2" }},
3596+ ConflictResolution : policyv1alpha1 .ConflictOverwrite ,
3597+ PreserveResourcesOnDeletion : ptr .To (true ),
3598+ },
35383599 }
3539- if ! strings .Contains (aggregatedEvent , "[dep-agg] aggregated policy" ) {
3540- t .Errorf ("unexpected aggregation event message: %s" , aggregatedEvent )
3600+ attachedFromParentTwo := buildAttachedBinding (parentTwo , env .dependent )
3601+
3602+ if err := env .distributor .createOrUpdateAttachedBinding (attachedFromParentTwo ); err != nil {
3603+ t .Fatalf ("createOrUpdateAttachedBinding() error = %v" , err )
35413604 }
3542- if ! strings .Contains (aggregatedEvent , "conflictResolution=Abort" ) {
3543- t .Errorf ("aggregation event missing conflictResolution result: %s" , aggregatedEvent )
3605+
3606+ updated := & workv1alpha2.ResourceBinding {}
3607+ if err := env .client .Get (context .TODO (), client .ObjectKeyFromObject (env .existing ), updated ); err != nil {
3608+ t .Fatalf ("failed to fetch updated binding: %v" , err )
35443609 }
3545- if ! strings . Contains ( aggregatedEvent , "preserveResourcesOnDeletion=false" ) {
3546- t .Errorf ( "aggregation event missing preserveResourcesOnDeletion result: %s " , aggregatedEvent )
3610+ if len ( updated . Spec . RequiredBy ) != 2 {
3611+ t .Fatalf ( "expected 2 parents after aggregation, got %d " , len ( updated . Spec . RequiredBy ) )
35473612 }
3548- if ! strings .Contains (aggregatedEvent , "default/workload-a" ) || ! strings .Contains (aggregatedEvent , "default/workload-b" ) {
3549- t .Errorf ("aggregation event missing parent list: %s" , aggregatedEvent )
3613+
3614+ eventList := waitForEvents (t , env .recorder , 1 , time .Second )
3615+
3616+ aggregatedEvent := findEventByReason (t , eventList , events .EventReasonDependencyPolicyAggregated )
3617+ assertEventMessageContains (t , aggregatedEvent ,
3618+ "[dep-agg] aggregated policy" ,
3619+ "conflictResolution=Overwrite" ,
3620+ "preserveResourcesOnDeletion=true" ,
3621+ "default/workload-a" ,
3622+ "default/workload-b" ,
3623+ )
3624+
3625+ for _ , evt := range eventList {
3626+ if strings .Contains (evt , events .EventReasonDependencyPolicyConflict ) {
3627+ t .Fatalf ("unexpected conflict event: %s" , evt )
3628+ }
35503629 }
35513630}
0 commit comments