@@ -22,15 +22,20 @@ import (
2222 "reflect"
2323 "testing"
2424
25+ "github.com/stretchr/testify/assert"
2526 appsv1 "k8s.io/api/apps/v1"
2627 corev1 "k8s.io/api/core/v1"
28+ apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
2729 "k8s.io/apimachinery/pkg/api/meta"
2830 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2931 "k8s.io/apimachinery/pkg/runtime"
32+ "k8s.io/apimachinery/pkg/runtime/schema"
3033 "k8s.io/apimachinery/pkg/types"
34+ "k8s.io/apimachinery/pkg/util/uuid"
3135 fakedynamic "k8s.io/client-go/dynamic/fake"
3236 "k8s.io/client-go/kubernetes/scheme"
3337 "k8s.io/client-go/tools/record"
38+ "k8s.io/utils/ptr"
3439 controllerruntime "sigs.k8s.io/controller-runtime"
3540 "sigs.k8s.io/controller-runtime/pkg/client"
3641 "sigs.k8s.io/controller-runtime/pkg/client/fake"
@@ -39,6 +44,7 @@ import (
3944 policyv1alpha1 "github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1"
4045 workv1alpha1 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha1"
4146 workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2"
47+ "github.com/karmada-io/karmada/pkg/events"
4248 testing2 "github.com/karmada-io/karmada/pkg/search/proxy/testing"
4349 "github.com/karmada-io/karmada/pkg/util"
4450 "github.com/karmada-io/karmada/pkg/util/fedinformer/genericmanager"
@@ -439,3 +445,108 @@ func TestClusterResourceBindingController_newOverridePolicyFunc(t *testing.T) {
439445 })
440446 }
441447}
448+
449+ func TestUpdateClusterBindingDispatchingConditionIfNeeded (t * testing.T ) {
450+ tests := []struct {
451+ name string
452+ binding * workv1alpha2.ClusterResourceBinding
453+ expectedCondition metav1.Condition
454+ expectedEventCount int
455+ expectEventMessage string
456+ }{
457+ {
458+ name : "Binding scheduling is suspended" ,
459+ binding : newCrb (true , metav1.Condition {}),
460+ expectedCondition : metav1.Condition {
461+ Type : workv1alpha2 .Suspended ,
462+ Status : metav1 .ConditionTrue ,
463+ },
464+ expectedEventCount : 1 ,
465+ expectEventMessage : fmt .Sprintf ("%s %s %s" , corev1 .EventTypeNormal , events .EventReasonBindingScheduling , SuspendedSchedulingConditionMessage ),
466+ },
467+ {
468+ name : "Binding scheduling is not suspended" ,
469+ binding : newCrb (false , metav1.Condition {
470+ Type : workv1alpha2 .Suspended ,
471+ Status : metav1 .ConditionTrue ,
472+ Reason : SuspendedSchedulingConditionReason ,
473+ Message : SuspendedSchedulingConditionMessage ,
474+ }),
475+ expectedCondition : metav1.Condition {
476+ Type : workv1alpha2 .Suspended ,
477+ Status : metav1 .ConditionFalse ,
478+ },
479+ expectedEventCount : 1 ,
480+ expectEventMessage : fmt .Sprintf ("%s %s %s" , corev1 .EventTypeNormal , events .EventReasonBindingScheduling , SchedulingConditionMessage ),
481+ },
482+ {
483+ name : "Condition already matches, no update needed" ,
484+ binding : newCrb (true , metav1.Condition {
485+ Type : workv1alpha2 .Suspended ,
486+ Status : metav1 .ConditionTrue ,
487+ Reason : SuspendedSchedulingConditionReason ,
488+ Message : SuspendedSchedulingConditionMessage ,
489+ }),
490+ expectedCondition : metav1.Condition {
491+ Type : workv1alpha2 .Suspended ,
492+ Status : metav1 .ConditionTrue ,
493+ },
494+ },
495+ }
496+
497+ for _ , tt := range tests {
498+ t .Run (tt .name , func (t * testing.T ) {
499+ eventRecorder := record .NewFakeRecorder (1 )
500+ c := newClusterResourceBindingController (tt .binding , eventRecorder )
501+
502+ updatedBinding := & workv1alpha2.ClusterResourceBinding {}
503+ assert .NoError (t , c .Get (context .Background (), types.NamespacedName {Name : tt .binding .Name , Namespace : tt .binding .Namespace }, updatedBinding ))
504+
505+ err := updateBindingDispatchingConditionIfNeeded (context .Background (), c .Client , c .EventRecorder , tt .binding , apiextensionsv1 .ClusterScoped )
506+ if err != nil {
507+ t .Errorf ("updateBindingDispatchingConditionIfNeeded() returned an error: %v" , err )
508+ }
509+
510+ assert .NoError (t , c .Get (context .Background (), types.NamespacedName {Name : tt .binding .Name , Namespace : tt .binding .Namespace }, updatedBinding ))
511+ assert .True (t , meta .IsStatusConditionPresentAndEqual (tt .binding .Status .Conditions , tt .expectedCondition .Type , tt .expectedCondition .Status ))
512+ assert .Equal (t , tt .expectedEventCount , len (eventRecorder .Events ))
513+ if tt .expectEventMessage != "" {
514+ e := <- eventRecorder .Events
515+ assert .Equal (t , tt .expectEventMessage , e )
516+ }
517+ })
518+ }
519+ }
520+
521+ func newClusterResourceBindingController (binding * workv1alpha2.ClusterResourceBinding , eventRecord record.EventRecorder ) ClusterResourceBindingController {
522+ restMapper := meta .NewDefaultRESTMapper ([]schema.GroupVersion {corev1 .SchemeGroupVersion })
523+ fakeClient := fake .NewClientBuilder ().WithScheme (gclient .NewSchema ()).WithObjects (binding ).WithStatusSubresource (binding ).WithRESTMapper (restMapper ).Build ()
524+ return ClusterResourceBindingController {
525+ Client : fakeClient ,
526+ EventRecorder : eventRecord ,
527+ }
528+ }
529+
530+ func newCrb (suspended bool , condition metav1.Condition ) * workv1alpha2.ClusterResourceBinding {
531+ return & workv1alpha2.ClusterResourceBinding {
532+ TypeMeta : metav1.TypeMeta {
533+ Kind : workv1alpha2 .ResourceKindResourceBinding ,
534+ APIVersion : workv1alpha2 .GroupVersion .Version ,
535+ },
536+ ObjectMeta : metav1.ObjectMeta {
537+ Name : "test-rb" ,
538+ Namespace : "default" ,
539+ UID : uuid .NewUUID (),
540+ },
541+ Spec : workv1alpha2.ResourceBindingSpec {
542+ Suspension : & policyv1alpha1.Suspension {
543+ Scheduling : ptr .To (suspended ),
544+ },
545+ },
546+ Status : workv1alpha2.ResourceBindingStatus {
547+ Conditions : []metav1.Condition {
548+ condition ,
549+ },
550+ },
551+ }
552+ }
0 commit comments