package helper import ( "testing" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" controllerruntime "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" "sigs.k8s.io/controller-runtime/pkg/event" clusterv1alpha1 "github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1" workv1alpha1 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha1" "github.com/karmada-io/karmada/pkg/util" "github.com/karmada-io/karmada/pkg/util/gclient" "github.com/karmada-io/karmada/pkg/util/names" ) func TestNewClusterPredicateOnAgent(t *testing.T) { type want struct { create, update, delete, generic bool } tests := []struct { name string obj client.Object want want }{ { name: "not matched", obj: &clusterv1alpha1.Cluster{ObjectMeta: metav1.ObjectMeta{Name: "unmatched"}}, want: want{ create: false, update: false, delete: false, generic: false, }, }, { name: "matched", obj: &clusterv1alpha1.Cluster{ObjectMeta: metav1.ObjectMeta{Name: "test"}}, want: want{ create: true, update: true, delete: true, generic: false, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { pred := NewClusterPredicateOnAgent("test") if got := pred.Create(event.CreateEvent{Object: tt.obj}); got != tt.want.create { t.Errorf("Create() got = %v, want %v", got, tt.want.create) return } if got := pred.Update(event.UpdateEvent{ObjectOld: tt.obj, ObjectNew: tt.obj}); got != tt.want.update { t.Errorf("Update() got = %v, want %v", got, tt.want.update) return } if got := pred.Delete(event.DeleteEvent{Object: tt.obj}); got != tt.want.delete { t.Errorf("Delete() got = %v, want %v", got, tt.want.delete) return } if got := pred.Generic(event.GenericEvent{Object: tt.obj}); got != tt.want.generic { t.Errorf("Generic() got = %v, want %v", got, tt.want.generic) return } }) } } func TestNewExecutionPredicate(t *testing.T) { type args struct { mgr controllerruntime.Manager obj client.Object } type want struct { create, update, delete, generic bool } tests := []struct { name string args args want want }{ { name: "object is suppressed", args: args{ mgr: &fakeManager{client: fake.NewClientBuilder().WithScheme(gclient.NewSchema()).WithObjects( &clusterv1alpha1.Cluster{ ObjectMeta: metav1.ObjectMeta{Name: "cluster"}, Spec: clusterv1alpha1.ClusterSpec{SyncMode: clusterv1alpha1.Push}, }, ).Build()}, obj: &workv1alpha1.Work{ ObjectMeta: metav1.ObjectMeta{ Name: "work", Namespace: names.ExecutionSpacePrefix + "cluster", Labels: map[string]string{util.PropagationInstruction: util.PropagationInstructionSuppressed}, }, }, }, want: want{ create: false, update: false, delete: false, generic: false, }, }, { name: "get cluster name error", args: args{ mgr: &fakeManager{client: fake.NewClientBuilder().WithScheme(gclient.NewSchema()).WithObjects( &clusterv1alpha1.Cluster{ ObjectMeta: metav1.ObjectMeta{Name: "cluster"}, Spec: clusterv1alpha1.ClusterSpec{SyncMode: clusterv1alpha1.Push}, }, ).Build()}, obj: &workv1alpha1.Work{ ObjectMeta: metav1.ObjectMeta{Name: "work", Namespace: "cluster"}, }, }, want: want{ create: false, update: false, delete: false, generic: false, }, }, { name: "cluster not found", args: args{ mgr: &fakeManager{client: fake.NewClientBuilder().WithScheme(gclient.NewSchema()).WithObjects().Build()}, obj: &workv1alpha1.Work{ ObjectMeta: metav1.ObjectMeta{Name: "work", Namespace: names.ExecutionSpacePrefix + "cluster"}, }, }, want: want{ create: false, update: false, delete: false, generic: false, }, }, { name: "cluster is pull mode", args: args{ mgr: &fakeManager{client: fake.NewClientBuilder().WithScheme(gclient.NewSchema()).WithObjects( &clusterv1alpha1.Cluster{ ObjectMeta: metav1.ObjectMeta{Name: "cluster"}, Spec: clusterv1alpha1.ClusterSpec{SyncMode: clusterv1alpha1.Pull}, }, ).Build()}, obj: &workv1alpha1.Work{ ObjectMeta: metav1.ObjectMeta{Name: "work", Namespace: names.ExecutionSpacePrefix + "cluster"}, }, }, want: want{ create: false, update: false, delete: false, generic: false, }, }, { name: "matched", args: args{ mgr: &fakeManager{client: fake.NewClientBuilder().WithScheme(gclient.NewSchema()).WithObjects( &clusterv1alpha1.Cluster{ ObjectMeta: metav1.ObjectMeta{Name: "cluster"}, Spec: clusterv1alpha1.ClusterSpec{SyncMode: clusterv1alpha1.Push}, }, ).Build()}, obj: &workv1alpha1.Work{ ObjectMeta: metav1.ObjectMeta{Name: "work", Namespace: names.ExecutionSpacePrefix + "cluster"}, }, }, want: want{ create: true, update: true, delete: true, generic: false, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { pred := NewExecutionPredicate(tt.args.mgr) if got := pred.Create(event.CreateEvent{Object: tt.args.obj}); got != tt.want.create { t.Errorf("Create() got = %v, want %v", got, tt.want.create) return } if got := pred.Update(event.UpdateEvent{ObjectOld: tt.args.obj, ObjectNew: tt.args.obj}); got != tt.want.update { t.Errorf("Update() got = %v, want %v", got, tt.want.update) return } if got := pred.Delete(event.DeleteEvent{Object: tt.args.obj}); got != tt.want.delete { t.Errorf("Delete() got = %v, want %v", got, tt.want.delete) return } if got := pred.Generic(event.GenericEvent{Object: tt.args.obj}); got != tt.want.generic { t.Errorf("Generic() got = %v, want %v", got, tt.want.generic) return } }) } } func TestNewExecutionPredicate_Update(t *testing.T) { mgr := &fakeManager{client: fake.NewClientBuilder().WithScheme(gclient.NewSchema()).WithObjects( &clusterv1alpha1.Cluster{ ObjectMeta: metav1.ObjectMeta{Name: "cluster"}, Spec: clusterv1alpha1.ClusterSpec{SyncMode: clusterv1alpha1.Push}, }, ).Build()} unmatched := &workv1alpha1.Work{ ObjectMeta: metav1.ObjectMeta{ Name: "work", Namespace: names.ExecutionSpacePrefix + "cluster", Labels: map[string]string{util.PropagationInstruction: util.PropagationInstructionSuppressed}, }, } matched := &workv1alpha1.Work{ ObjectMeta: metav1.ObjectMeta{ Name: "work", Namespace: names.ExecutionSpacePrefix + "cluster", }, } type args struct { event event.UpdateEvent } tests := []struct { name string args args want bool }{ { name: "both old and new are unmatched", args: args{ event: event.UpdateEvent{ObjectOld: unmatched, ObjectNew: unmatched}, }, want: false, }, { name: "old is unmatched, new is matched", args: args{ event: event.UpdateEvent{ObjectOld: unmatched, ObjectNew: matched}, }, want: true, }, { name: "old is matched, new is unmatched", args: args{ event: event.UpdateEvent{ObjectOld: matched, ObjectNew: unmatched}, }, want: true, }, { name: "both old and new are matched", args: args{ event: event.UpdateEvent{ObjectOld: matched, ObjectNew: matched}, }, want: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { pred := NewExecutionPredicate(mgr) if got := pred.Update(tt.args.event); got != tt.want { t.Errorf("Update() got = %v, want %v", got, tt.want) return } }) } } func TestNewExecutionPredicateOnAgent(t *testing.T) { type want struct { create, update, delete, generic bool } tests := []struct { name string obj client.Object want want }{ { name: "object is suppressed", obj: &workv1alpha1.Work{ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{ util.PropagationInstruction: util.PropagationInstructionSuppressed, }}}, want: want{ create: false, update: false, delete: false, generic: false, }, }, { name: "matched", obj: &workv1alpha1.Work{ObjectMeta: metav1.ObjectMeta{}}, want: want{ create: true, update: true, delete: true, generic: false, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { pred := NewExecutionPredicateOnAgent() if got := pred.Create(event.CreateEvent{Object: tt.obj}); got != tt.want.create { t.Errorf("Create() got = %v, want %v", got, tt.want.create) return } if got := pred.Update(event.UpdateEvent{ObjectNew: tt.obj, ObjectOld: tt.obj}); got != tt.want.update { t.Errorf("Update() got = %v, want %v", got, tt.want.update) return } if got := pred.Delete(event.DeleteEvent{Object: tt.obj}); got != tt.want.delete { t.Errorf("Delete() got = %v, want %v", got, tt.want.delete) return } if got := pred.Generic(event.GenericEvent{Object: tt.obj}); got != tt.want.generic { t.Errorf("Generic() got = %v, want %v", got, tt.want.generic) return } }) } } func TestNewExecutionPredicateOnAgent_Update(t *testing.T) { unmatched := &workv1alpha1.Work{ ObjectMeta: metav1.ObjectMeta{ Name: "work", Namespace: names.ExecutionSpacePrefix + "cluster", Labels: map[string]string{util.PropagationInstruction: util.PropagationInstructionSuppressed}, }, } matched := &workv1alpha1.Work{ ObjectMeta: metav1.ObjectMeta{ Name: "work", Namespace: names.ExecutionSpacePrefix + "cluster", }, } type args struct { event event.UpdateEvent } tests := []struct { name string args args want bool }{ { name: "both old and new are unmatched", args: args{ event: event.UpdateEvent{ObjectOld: unmatched, ObjectNew: unmatched}, }, want: false, }, { name: "old is unmatched, new is matched", args: args{ event: event.UpdateEvent{ObjectOld: unmatched, ObjectNew: matched}, }, want: true, }, { name: "old is matched, new is unmatched", args: args{ event: event.UpdateEvent{ObjectOld: matched, ObjectNew: unmatched}, }, want: true, }, { name: "both old and new are matched", args: args{ event: event.UpdateEvent{ObjectOld: matched, ObjectNew: matched}, }, want: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { pred := NewExecutionPredicateOnAgent() if got := pred.Update(tt.args.event); got != tt.want { t.Errorf("Update() got = %v, want %v", got, tt.want) return } }) } } func TestNewPredicateForServiceExportController(t *testing.T) { type args struct { mgr controllerruntime.Manager obj client.Object } type want struct { create, update, delete, generic bool } tests := []struct { name string args args want want }{ { name: "object is suppressed", args: args{ mgr: &fakeManager{client: fake.NewClientBuilder().WithScheme(gclient.NewSchema()).WithObjects( &clusterv1alpha1.Cluster{ ObjectMeta: metav1.ObjectMeta{Name: "cluster"}, Spec: clusterv1alpha1.ClusterSpec{SyncMode: clusterv1alpha1.Push}, }, ).Build()}, obj: &workv1alpha1.Work{ ObjectMeta: metav1.ObjectMeta{ Name: "work", Namespace: names.ExecutionSpacePrefix + "cluster", Labels: map[string]string{util.PropagationInstruction: util.PropagationInstructionSuppressed}, }, }, }, want: want{ create: false, update: false, delete: false, generic: false, }, }, { name: "get cluster name error", args: args{ mgr: &fakeManager{client: fake.NewClientBuilder().WithScheme(gclient.NewSchema()).WithObjects( &clusterv1alpha1.Cluster{ ObjectMeta: metav1.ObjectMeta{Name: "cluster"}, Spec: clusterv1alpha1.ClusterSpec{SyncMode: clusterv1alpha1.Push}, }, ).Build()}, obj: &workv1alpha1.Work{ ObjectMeta: metav1.ObjectMeta{Name: "work", Namespace: "cluster"}, }, }, want: want{ create: false, update: false, delete: false, generic: false, }, }, { name: "cluster not found", args: args{ mgr: &fakeManager{client: fake.NewClientBuilder().WithScheme(gclient.NewSchema()).WithObjects().Build()}, obj: &workv1alpha1.Work{ ObjectMeta: metav1.ObjectMeta{Name: "work", Namespace: names.ExecutionSpacePrefix + "cluster"}, }, }, want: want{ create: false, update: false, delete: false, generic: false, }, }, { name: "cluster is pull mode", args: args{ mgr: &fakeManager{client: fake.NewClientBuilder().WithScheme(gclient.NewSchema()).WithObjects( &clusterv1alpha1.Cluster{ ObjectMeta: metav1.ObjectMeta{Name: "cluster"}, Spec: clusterv1alpha1.ClusterSpec{SyncMode: clusterv1alpha1.Pull}, }, ).Build()}, obj: &workv1alpha1.Work{ ObjectMeta: metav1.ObjectMeta{Name: "work", Namespace: names.ExecutionSpacePrefix + "cluster"}, }, }, want: want{ create: false, update: false, delete: false, generic: false, }, }, { name: "matched", args: args{ mgr: &fakeManager{client: fake.NewClientBuilder().WithScheme(gclient.NewSchema()).WithObjects( &clusterv1alpha1.Cluster{ ObjectMeta: metav1.ObjectMeta{Name: "cluster"}, Spec: clusterv1alpha1.ClusterSpec{SyncMode: clusterv1alpha1.Push}, }, ).Build()}, obj: &workv1alpha1.Work{ ObjectMeta: metav1.ObjectMeta{Name: "work", Namespace: names.ExecutionSpacePrefix + "cluster"}, }, }, want: want{ create: false, update: true, delete: false, generic: false, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { pred := NewPredicateForServiceExportController(tt.args.mgr) if got := pred.Create(event.CreateEvent{Object: tt.args.obj}); got != tt.want.create { t.Errorf("Create() got = %v, F %v", got, tt.want.create) return } if got := pred.Update(event.UpdateEvent{ObjectOld: tt.args.obj, ObjectNew: tt.args.obj}); got != tt.want.update { t.Errorf("Update() got = %v, want %v", got, tt.want.update) return } if got := pred.Delete(event.DeleteEvent{Object: tt.args.obj}); got != tt.want.delete { t.Errorf("Delete() got = %v, want %v", got, tt.want.delete) return } if got := pred.Generic(event.GenericEvent{Object: tt.args.obj}); got != tt.want.generic { t.Errorf("Generic() got = %v, want %v", got, tt.want.generic) return } }) } } func TestNewPredicateForServiceExportController_Update(t *testing.T) { mgr := &fakeManager{client: fake.NewClientBuilder().WithScheme(gclient.NewSchema()).WithObjects( &clusterv1alpha1.Cluster{ ObjectMeta: metav1.ObjectMeta{Name: "cluster"}, Spec: clusterv1alpha1.ClusterSpec{SyncMode: clusterv1alpha1.Push}, }, ).Build()} unmatched := &workv1alpha1.Work{ ObjectMeta: metav1.ObjectMeta{ Name: "work", Namespace: names.ExecutionSpacePrefix + "cluster", Labels: map[string]string{util.PropagationInstruction: util.PropagationInstructionSuppressed}, }, } matched := &workv1alpha1.Work{ ObjectMeta: metav1.ObjectMeta{ Name: "work", Namespace: names.ExecutionSpacePrefix + "cluster", }, } type args struct { event event.UpdateEvent } tests := []struct { name string args args want bool }{ { name: "both old and new are unmatched", args: args{ event: event.UpdateEvent{ObjectOld: unmatched, ObjectNew: unmatched}, }, want: false, }, { name: "old is unmatched, new is matched", args: args{ event: event.UpdateEvent{ObjectOld: unmatched, ObjectNew: matched}, }, want: true, }, { name: "old is matched, new is unmatched", args: args{ event: event.UpdateEvent{ObjectOld: matched, ObjectNew: unmatched}, }, want: true, }, { name: "both old and new are matched", args: args{ event: event.UpdateEvent{ObjectOld: matched, ObjectNew: matched}, }, want: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { pred := NewPredicateForServiceExportController(mgr) if got := pred.Update(tt.args.event); got != tt.want { t.Errorf("Update() got = %v, want %v", got, tt.want) return } }) } } func TestNewPredicateForServiceExportControllerOnAgent(t *testing.T) { pred := NewPredicateForServiceExportControllerOnAgent("cluster") type want struct { create, update, delete, generic bool } tests := []struct { name string obj client.Object want want }{ { name: "object is suppressed", obj: &workv1alpha1.Work{ObjectMeta: metav1.ObjectMeta{ Name: "work", Namespace: names.ExecutionSpacePrefix + "cluster", Labels: map[string]string{util.PropagationInstruction: util.PropagationInstructionSuppressed}, }}, want: want{ create: false, update: false, delete: false, generic: false, }, }, { name: "get cluster name error", obj: &workv1alpha1.Work{ObjectMeta: metav1.ObjectMeta{ Name: "work", Namespace: "cluster", }}, want: want{ create: false, update: false, delete: false, generic: false, }, }, { name: "cluster name unmatched", obj: &workv1alpha1.Work{ObjectMeta: metav1.ObjectMeta{ Name: "work", Namespace: names.ExecutionSpacePrefix + "unmatched", }}, want: want{ create: false, update: false, delete: false, generic: false, }, }, { name: "matched", obj: &workv1alpha1.Work{ObjectMeta: metav1.ObjectMeta{ Name: "work", Namespace: names.ExecutionSpacePrefix + "cluster", }}, want: want{ create: false, update: true, delete: false, generic: false, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := pred.Create(event.CreateEvent{Object: tt.obj}); got != tt.want.create { t.Errorf("Create() got = %v, want %v", got, tt.want.create) return } if got := pred.Update(event.UpdateEvent{ObjectOld: tt.obj, ObjectNew: tt.obj}); got != tt.want.update { t.Errorf("Update() got = %v, want %v", got, tt.want.update) return } if got := pred.Delete(event.DeleteEvent{Object: tt.obj}); got != tt.want.delete { t.Errorf("Delete() got = %v, want %v", got, tt.want.delete) return } if got := pred.Generic(event.GenericEvent{Object: tt.obj}); got != tt.want.generic { t.Errorf("Generic() got = %v, want %v", got, tt.want.generic) return } }) } } func TestNewPredicateForServiceExportControllerOnAgent_Update(t *testing.T) { unmatched := &workv1alpha1.Work{ ObjectMeta: metav1.ObjectMeta{ Name: "work", Namespace: names.ExecutionSpacePrefix + "cluster", Labels: map[string]string{util.PropagationInstruction: util.PropagationInstructionSuppressed}, }, } matched := &workv1alpha1.Work{ ObjectMeta: metav1.ObjectMeta{ Name: "work", Namespace: names.ExecutionSpacePrefix + "cluster", }, } type args struct { event event.UpdateEvent } tests := []struct { name string args args want bool }{ { name: "both old and new are unmatched", args: args{ event: event.UpdateEvent{ObjectOld: unmatched, ObjectNew: unmatched}, }, want: false, }, { name: "old is unmatched, new is matched", args: args{ event: event.UpdateEvent{ObjectOld: unmatched, ObjectNew: matched}, }, want: true, }, { name: "old is matched, new is unmatched", args: args{ event: event.UpdateEvent{ObjectOld: matched, ObjectNew: unmatched}, }, want: true, }, { name: "both old and new are matched", args: args{ event: event.UpdateEvent{ObjectOld: matched, ObjectNew: matched}, }, want: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { pred := NewPredicateForServiceExportControllerOnAgent("cluster") if got := pred.Update(tt.args.event); got != tt.want { t.Errorf("Update() got = %v, want %v", got, tt.want) return } }) } } type fakeManager struct { controllerruntime.Manager client client.Client } func (f *fakeManager) GetClient() client.Client { return f.client }