diff --git a/pkg/util/informermanager/federatedinformermanager_test.go b/pkg/util/informermanager/federatedinformermanager_test.go index d19b44c73..c0c6b0c68 100644 --- a/pkg/util/informermanager/federatedinformermanager_test.go +++ b/pkg/util/informermanager/federatedinformermanager_test.go @@ -23,6 +23,70 @@ import ( "github.com/onsi/gomega" ) +func TestFederatedInformerManager(t *testing.T) { + _ = gomega.NewWithT(t) + + t.Run("clients for existing clusters should be available eventually", func(t *testing.T) { + + }) + + t.Run("clients for new clusters should be available eventually", func(t *testing.T) { + + }) + + t.Run("listers for existing FTCs and clusters should be available eventually", func(t *testing.T) { + + }) + + t.Run("listers for new FTCs should be available eventually", func(t *testing.T) { + + }) + + t.Run("listers for new clusteres should be available eventually", func(t *testing.T) { + + }) + + t.Run("event handlers for existing FTCs should be registed eventually", func(t *testing.T) { + + }) + + t.Run("event handlers for new FTCs should be registered eventually", func(t *testing.T) { + + }) + + t.Run("event handlers for new clusters should be registered eventually", func(t *testing.T) { + + }) + + t.Run("event handler should receive correct lastApplied and latest FTCs", func(t *testing.T) { + + }) + + t.Run("event handler should be registered on FTC update", func(t *testing.T) { + + }) + + t.Run("event handler should be unregistered on FTC update", func(t *testing.T) { + + }) + + t.Run("event handler should be re-registered on FTC update", func(t *testing.T) { + + }) + + t.Run("event handler should remain unchanged on FTC update", func(t *testing.T) { + + }) + + t.Run("event handler should be unregistered on FTC deletion", func(t *testing.T) { + + }) + + t.Run("event handler should be unregistered on cluster deletion", func(t *testing.T) { + + }) +} + // Verifies that clients for existing clusters are eventually available after the FederatedInformerManager is started. func TestFederatedInformerManagerClientAvailableForExistingClusters(t *testing.T) { g := gomega.NewGomegaWithT(t) diff --git a/pkg/util/informermanager/informermanager_test.go b/pkg/util/informermanager/informermanager_test.go index 0082cbc0d..d26e73202 100644 --- a/pkg/util/informermanager/informermanager_test.go +++ b/pkg/util/informermanager/informermanager_test.go @@ -117,8 +117,8 @@ func TestInformerManager(t *testing.T) { cm1 := getTestConfigMap("cm-1", "default") sc1 := getTestSecret("sc-1", "default") - alwaysRegistered := &countingResourceEventHandler{} - neverRegistered := &countingResourceEventHandler{} + alwaysRegistered := newCountingResourceEventHandler() + neverRegistered := newCountingResourceEventHandler() defaultFTCs := []*fedcorev1a1.FederatedTypeConfig{deploymentFTC, configmapFTC, secretFTC} defaultObjs := []*unstructured.Unstructured{dp1, cm1, sc1} @@ -137,8 +137,12 @@ func TestInformerManager(t *testing.T) { // 2. Verify alwaysRegistered is eventually registered for all existing FTCs. - alwaysRegistered.ExpectGenerateEvents(3) - alwaysRegistered.ExpectAddEvents(3) + alwaysRegistered.ExpectGenerateEvents(deploymentFTC.Name, 1) + alwaysRegistered.ExpectGenerateEvents(configmapFTC.Name, 1) + alwaysRegistered.ExpectGenerateEvents(secretFTC.Name, 1) + alwaysRegistered.ExpectAddEvents(deploymentGVK, 1) + alwaysRegistered.ExpectAddEvents(configmapGVK, 1) + alwaysRegistered.ExpectAddEvents(secretGVK, 1) alwaysRegistered.AssertEventually(g, time.Second*2) // 3. Verify newly generated events are received by alwaysRegistered @@ -147,16 +151,16 @@ func TestInformerManager(t *testing.T) { Namespace("default"). Create(ctx, getTestSecret("sc-2", "default"), metav1.CreateOptions{}) g.Expect(err).ToNot(gomega.HaveOccurred()) - alwaysRegistered.ExpectAddEvents(1) + alwaysRegistered.ExpectAddEvents(secretGVK, 1) dp1.SetAnnotations(map[string]string{"test": "test"}) _, err = dynamicClient.Resource(common.DeploymentGVR).Namespace("default").Update(ctx, dp1, metav1.UpdateOptions{}) g.Expect(err).ToNot(gomega.HaveOccurred()) - alwaysRegistered.ExpectUpdateEvents(1) + alwaysRegistered.ExpectUpdateEvents(deploymentGVK, 1) err = dynamicClient.Resource(common.ConfigMapGVR).Namespace("default").Delete(ctx, cm1.GetName(), metav1.DeleteOptions{}) g.Expect(err).ToNot(gomega.HaveOccurred()) - alwaysRegistered.ExpectDeleteEvents(1) + alwaysRegistered.ExpectDeleteEvents(configmapGVK, 1) alwaysRegistered.AssertEventually(g, time.Second*2) @@ -185,8 +189,8 @@ func TestInformerManager(t *testing.T) { dm3 := getTestDaemonSet("dm-3", "default") dm4 := getTestDaemonSet("dm-4", "default") - alwaysRegistered := &countingResourceEventHandler{} - neverRegistered := &countingResourceEventHandler{} + alwaysRegistered := newCountingResourceEventHandler() + neverRegistered := newCountingResourceEventHandler() defaultFTCs := []*fedcorev1a1.FederatedTypeConfig{} defaultObjs := []*unstructured.Unstructured{dm1, dm2, dm3, dm4} @@ -210,8 +214,8 @@ func TestInformerManager(t *testing.T) { // 3. Verify that alwaysRegistered is eventually registered for the new Daemonset FTC - alwaysRegistered.ExpectGenerateEvents(1) - alwaysRegistered.ExpectAddEvents(4) + alwaysRegistered.ExpectGenerateEvents(daemonsetFTC.Name, 1) + alwaysRegistered.ExpectAddEvents(daemonsetGVK, 4) alwaysRegistered.AssertEventually(g, time.Second*2) // 4. Verify that newly generated events are also received by alwaysRegistered @@ -219,11 +223,11 @@ func TestInformerManager(t *testing.T) { dm1.SetAnnotations(map[string]string{"test": "test"}) _, err = dynamicClient.Resource(common.DaemonSetGVR).Namespace("default").Update(ctx, dm1, metav1.UpdateOptions{}) g.Expect(err).ToNot(gomega.HaveOccurred()) - alwaysRegistered.ExpectUpdateEvents(1) + alwaysRegistered.ExpectUpdateEvents(daemonsetGVK, 1) err = dynamicClient.Resource(common.DaemonSetGVR).Namespace("default").Delete(ctx, dm4.GetName(), metav1.DeleteOptions{}) g.Expect(err).ToNot(gomega.HaveOccurred()) - alwaysRegistered.ExpectDeleteEvents(1) + alwaysRegistered.ExpectDeleteEvents(daemonsetGVK, 1) alwaysRegistered.AssertEventually(g, time.Second*2) @@ -307,7 +311,7 @@ func TestInformerManager(t *testing.T) { ftc := deploymentFTC.DeepCopy() ftc.SetAnnotations(map[string]string{"predicate": "false", "generator": "true"}) - handler := &countingResourceEventHandler{} + handler := newCountingResourceEventHandler() generator := newAnnotationBasedGenerator(handler) defaultFTCs := []*fedcorev1a1.FederatedTypeConfig{ftc} @@ -328,8 +332,8 @@ func TestInformerManager(t *testing.T) { // 4. Verify that handler is registered and additional events are received - handler.ExpectGenerateEvents(1) - handler.ExpectAddEvents(1) + handler.ExpectGenerateEvents(ftc.Name, 1) + handler.ExpectAddEvents(deploymentGVK, 1) handler.AssertEventually(g, time.Second*2) @@ -337,16 +341,16 @@ func TestInformerManager(t *testing.T) { Namespace("default"). Create(ctx, getTestDeployment("dp-2", "default"), metav1.CreateOptions{}) g.Expect(err).ToNot(gomega.HaveOccurred()) - handler.ExpectAddEvents(1) + handler.ExpectAddEvents(deploymentGVK, 1) dp2.SetAnnotations(map[string]string{"test-annotation": "test-value"}) dp2, err = dynamicClient.Resource(common.DeploymentGVR).Namespace("default").Update(ctx, dp2, metav1.UpdateOptions{}) g.Expect(err).ToNot(gomega.HaveOccurred()) - handler.ExpectUpdateEvents(1) + handler.ExpectUpdateEvents(deploymentGVK, 1) err = dynamicClient.Resource(common.DeploymentGVR).Namespace("default").Delete(ctx, dp2.GetName(), metav1.DeleteOptions{}) g.Expect(err).ToNot(gomega.HaveOccurred()) - handler.ExpectDeleteEvents(1) + handler.ExpectDeleteEvents(deploymentGVK, 1) handler.AssertEventually(g, time.Second*2) }) @@ -362,7 +366,7 @@ func TestInformerManager(t *testing.T) { ftc := deploymentFTC.DeepCopy() ftc.SetAnnotations(map[string]string{"predicate": "true", "generator": "true"}) - handler := &countingResourceEventHandler{} + handler := newCountingResourceEventHandler() generator := newAnnotationBasedGenerator(handler) defaultFTCs := []*fedcorev1a1.FederatedTypeConfig{ftc} @@ -373,8 +377,8 @@ func TestInformerManager(t *testing.T) { // 2. Verify that handler is registered initially. - handler.ExpectGenerateEvents(1) - handler.ExpectAddEvents(1) + handler.ExpectGenerateEvents(ftc.Name, 1) + handler.ExpectAddEvents(deploymentGVK, 1) handler.AssertEventually(g, time.Second*2) // 3. Update FTC to trigger unregistration @@ -411,7 +415,7 @@ func TestInformerManager(t *testing.T) { dp1 := getTestDeployment("dp-1", "default") ftc := deploymentFTC.DeepCopy() - handler := &countingResourceEventHandler{} + handler := newCountingResourceEventHandler() generator := &EventHandlerGenerator{ Predicate: alwaysRegisterPredicate, Generator: handler.GenerateEventHandler, @@ -425,8 +429,8 @@ func TestInformerManager(t *testing.T) { // 2. Verify that handler is registered initially - handler.ExpectGenerateEvents(1) - handler.ExpectAddEvents(1) + handler.ExpectGenerateEvents(ftc.Name, 1) + handler.ExpectAddEvents(deploymentGVK, 1) handler.AssertEventually(g, time.Second*2) // 3. Trigger FTC updates and verify re-registration @@ -435,15 +439,15 @@ func TestInformerManager(t *testing.T) { _, err := fedClient.CoreV1alpha1().FederatedTypeConfigs().Update(ctx, ftc, metav1.UpdateOptions{}) g.Expect(err).ToNot(gomega.HaveOccurred()) - handler.ExpectGenerateEvents(1) - handler.ExpectAddEvents(1) + handler.ExpectGenerateEvents(ftc.Name, 1) + handler.ExpectAddEvents(deploymentGVK, 1) handler.AssertEventually(g, time.Second*2) dp1.SetAnnotations(map[string]string{"test": "test"}) _, err = dynamicClient.Resource(common.DeploymentGVR).Namespace("default").Update(ctx, dp1, metav1.UpdateOptions{}) g.Expect(err).ToNot(gomega.HaveOccurred()) - handler.ExpectUpdateEvents(1) + handler.ExpectUpdateEvents(deploymentGVK, 1) handler.AssertEventually(g, time.Second*2) }) @@ -456,7 +460,7 @@ func TestInformerManager(t *testing.T) { dp1 := getTestDeployment("dp-1", "default") ftc := deploymentFTC.DeepCopy() - handler := &countingResourceEventHandler{} + handler := newCountingResourceEventHandler() generator := &EventHandlerGenerator{ Predicate: registerOncePredicate, Generator: handler.GenerateEventHandler, @@ -470,8 +474,8 @@ func TestInformerManager(t *testing.T) { // 2. Verify that handler is registered initially - handler.ExpectGenerateEvents(1) - handler.ExpectAddEvents(1) + handler.ExpectGenerateEvents(ftc.Name, 1) + handler.ExpectAddEvents(deploymentGVK, 1) handler.AssertEventually(g, time.Second*2) // 3. Trigger FTC updates and verify no re-registration @@ -488,7 +492,7 @@ func TestInformerManager(t *testing.T) { _, err = dynamicClient.Resource(common.DeploymentGVR).Namespace("default").Update(ctx, dp1, metav1.UpdateOptions{}) g.Expect(err).ToNot(gomega.HaveOccurred()) - handler.ExpectUpdateEvents(1) + handler.ExpectUpdateEvents(deploymentGVK, 1) handler.AssertEventually(g, time.Second*2) }) @@ -502,8 +506,8 @@ func TestInformerManager(t *testing.T) { cm1 := getTestConfigMap("cm-1", "default") sc1 := getTestSecret("sc-1", "default") - handler1 := &countingResourceEventHandler{} - handler2 := &countingResourceEventHandler{} + handler1 := newCountingResourceEventHandler() + handler2 := newCountingResourceEventHandler() generator1 := &EventHandlerGenerator{ Predicate: registerOncePredicate, Generator: handler1.GenerateEventHandler, @@ -521,12 +525,20 @@ func TestInformerManager(t *testing.T) { // 2. Verify that handler1 and handler2 is registered initially for all FTCs - handler1.ExpectGenerateEvents(3) - handler1.ExpectAddEvents(3) + handler1.ExpectGenerateEvents(deploymentFTC.Name, 1) + handler1.ExpectGenerateEvents(configmapFTC.Name, 1) + handler1.ExpectGenerateEvents(secretFTC.Name, 1) + handler1.ExpectAddEvents(deploymentGVK, 1) + handler1.ExpectAddEvents(configmapGVK, 1) + handler1.ExpectAddEvents(secretGVK, 1) handler1.AssertEventually(g, time.Second*2) - handler2.ExpectGenerateEvents(3) - handler2.ExpectAddEvents(3) + handler2.ExpectGenerateEvents(deploymentFTC.Name, 1) + handler2.ExpectGenerateEvents(configmapFTC.Name, 1) + handler2.ExpectGenerateEvents(secretFTC.Name, 1) + handler2.ExpectAddEvents(deploymentGVK, 1) + handler2.ExpectAddEvents(configmapGVK, 1) + handler2.ExpectAddEvents(secretGVK, 1) handler2.AssertEventually(g, time.Second*2) // 3. Delete the deployment FTC @@ -559,14 +571,14 @@ func TestInformerManager(t *testing.T) { Namespace("default"). Create(ctx, getTestSecret("sc-2", "default"), metav1.CreateOptions{}) g.Expect(err).ToNot(gomega.HaveOccurred()) - handler1.ExpectAddEvents(1) - handler2.ExpectAddEvents(1) + handler1.ExpectAddEvents(secretGVK, 1) + handler2.ExpectAddEvents(secretGVK, 1) cm1.SetAnnotations(map[string]string{"test": "test"}) _, err = dynamicClient.Resource(common.ConfigMapGVR).Namespace("default").Update(ctx, cm1, metav1.UpdateOptions{}) g.Expect(err).ToNot(gomega.HaveOccurred()) - handler1.ExpectUpdateEvents(1) - handler2.ExpectUpdateEvents(1) + handler1.ExpectUpdateEvents(configmapGVK, 1) + handler2.ExpectUpdateEvents(configmapGVK, 1) handler1.AssertEventually(g, time.Second*2) handler2.AssertEventually(g, time.Second*2) @@ -582,8 +594,8 @@ func TestInformerManager(t *testing.T) { cm1 := getTestConfigMap("cm-1", "default") sc1 := getTestSecret("sc-1", "default") - handler1 := &countingResourceEventHandler{} - handler2 := &countingResourceEventHandler{} + handler1 := newCountingResourceEventHandler() + handler2 := newCountingResourceEventHandler() generator1 := &EventHandlerGenerator{ Predicate: registerOncePredicate, Generator: handler1.GenerateEventHandler, @@ -602,12 +614,20 @@ func TestInformerManager(t *testing.T) { // 2. Verify that handler1 and handler2 is registered initially for all FTCs - handler1.ExpectGenerateEvents(3) - handler1.ExpectAddEvents(3) + handler1.ExpectGenerateEvents(deploymentFTC.Name, 1) + handler1.ExpectGenerateEvents(configmapFTC.Name, 1) + handler1.ExpectGenerateEvents(secretFTC.Name, 1) + handler1.ExpectAddEvents(deploymentGVK, 1) + handler1.ExpectAddEvents(configmapGVK, 1) + handler1.ExpectAddEvents(secretGVK, 1) handler1.AssertEventually(g, time.Second*2) - handler2.ExpectGenerateEvents(3) - handler2.ExpectAddEvents(3) + handler2.ExpectGenerateEvents(deploymentFTC.Name, 1) + handler2.ExpectGenerateEvents(configmapFTC.Name, 1) + handler2.ExpectGenerateEvents(secretFTC.Name, 1) + handler2.ExpectAddEvents(deploymentGVK, 1) + handler2.ExpectAddEvents(configmapGVK, 1) + handler2.ExpectAddEvents(secretGVK, 1) handler2.AssertEventually(g, time.Second*2) // 3. Shutdown the manager diff --git a/pkg/util/informermanager/testutils_test.go b/pkg/util/informermanager/testutils_test.go index c71897ba8..d9099f4af 100644 --- a/pkg/util/informermanager/testutils_test.go +++ b/pkg/util/informermanager/testutils_test.go @@ -1,6 +1,9 @@ package informermanager import ( + "fmt" + "path" + goruntime "runtime" "sync" "time" @@ -10,6 +13,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/util/rand" "k8s.io/client-go/tools/cache" @@ -76,6 +80,13 @@ var ( } ) +var ( + deploymentGVK = appsv1.SchemeGroupVersion.WithKind("Deployment") + daemonsetGVK = appsv1.SchemeGroupVersion.WithKind("DaemonSet") + configmapGVK = corev1.SchemeGroupVersion.WithKind("ConfigMap") + secretGVK = corev1.SchemeGroupVersion.WithKind("Secret") +) + func getTestDeployment(name, namespace string) *unstructured.Unstructured { dp := &appsv1.Deployment{ TypeMeta: metav1.TypeMeta{ @@ -184,85 +195,144 @@ func getTestCluster(name string) *fedcorev1a1.FederatedCluster { } } +func newCountingResourceEventHandler() *countingResourceEventHandler { + return &countingResourceEventHandler{ + lock: sync.RWMutex{}, + generateCount: map[string]int{}, + addEventCount: map[schema.GroupVersionKind]int{}, + updateEventCount: map[schema.GroupVersionKind]int{}, + deleteEventCount: map[schema.GroupVersionKind]int{}, + expectedGenerateCount: map[string]int{}, + expectedAddEventCount: map[schema.GroupVersionKind]int{}, + expectedUpdateEventCount: map[schema.GroupVersionKind]int{}, + expectedDeleteEventCount: map[schema.GroupVersionKind]int{}, + } +} + type countingResourceEventHandler struct { lock sync.RWMutex - generateCount int - addEventCount int - updateEventCount int - deleteEventCount int + generateCount map[string]int + addEventCount map[schema.GroupVersionKind]int + updateEventCount map[schema.GroupVersionKind]int + deleteEventCount map[schema.GroupVersionKind]int - expectedGenerateCount int - expectedAddEventCount int - expectedUpdateEventCount int - expectedDeleteEventCount int + expectedGenerateCount map[string]int + expectedAddEventCount map[schema.GroupVersionKind]int + expectedUpdateEventCount map[schema.GroupVersionKind]int + expectedDeleteEventCount map[schema.GroupVersionKind]int } -func (h *countingResourceEventHandler) ExpectGenerateEvents(i int) { +func (h *countingResourceEventHandler) ExpectGenerateEvents(ftcName string, n int) { h.lock.Lock() defer h.lock.Unlock() - h.expectedGenerateCount += i + h.expectedGenerateCount[ftcName] = h.expectedGenerateCount[ftcName] + n } -func (h *countingResourceEventHandler) ExpectAddEvents(i int) { +func (h *countingResourceEventHandler) ExpectAddEvents(gvk schema.GroupVersionKind, n int) { h.lock.Lock() defer h.lock.Unlock() - h.expectedAddEventCount += i + h.expectedAddEventCount[gvk] = h.expectedAddEventCount[gvk] + n } -func (h *countingResourceEventHandler) ExpectUpdateEvents(i int) { +func (h *countingResourceEventHandler) ExpectUpdateEvents(gvk schema.GroupVersionKind, n int) { h.lock.Lock() defer h.lock.Unlock() - h.expectedUpdateEventCount += i + h.expectedUpdateEventCount[gvk] = h.expectedUpdateEventCount[gvk] + n } -func (h *countingResourceEventHandler) ExpectDeleteEvents(i int) { +func (h *countingResourceEventHandler) ExpectDeleteEvents(gvk schema.GroupVersionKind, n int) { h.lock.Lock() defer h.lock.Unlock() - h.expectedDeleteEventCount += i + h.expectedDeleteEventCount[gvk] = h.expectedDeleteEventCount[gvk] + n } func (h *countingResourceEventHandler) AssertEventually(g gomega.Gomega, timeout time.Duration) { + _, file, no, _ := goruntime.Caller(1) + callerInfo := fmt.Sprintf("%s:%d", path.Base(file), no) + g.Eventually(func(g gomega.Gomega) { - g.Expect(h.generateCount).To(gomega.BeNumerically("==", h.expectedGenerateCount)) - g.Expect(h.addEventCount).To(gomega.BeNumerically("==", h.expectedAddEventCount)) - g.Expect(h.updateEventCount).To(gomega.BeNumerically("==", h.expectedUpdateEventCount)) - g.Expect(h.deleteEventCount).To(gomega.BeNumerically("==", h.expectedDeleteEventCount)) + for ftc := range h.expectedGenerateCount { + g.Expect(h.generateCount[ftc]). + To(gomega.BeNumerically("==", h.expectedGenerateCount[ftc]), "%s: incorrect number of generate events for %s", callerInfo, ftc) + } + for gvk := range h.expectedAddEventCount { + g.Expect(h.addEventCount[gvk]). + To(gomega.BeNumerically("==", h.expectedAddEventCount[gvk]), "%s: incorrect number of add events for %s", callerInfo, gvk) + } + for gvk := range h.expectedUpdateEventCount { + g.Expect(h.updateEventCount[gvk]). + To(gomega.BeNumerically("==", h.expectedUpdateEventCount[gvk]), "%s: incorrect number of update events for %s", callerInfo, gvk) + } + for gvk := range h.expectedDeleteEventCount { + g.Expect(h.deleteEventCount[gvk]). + To(gomega.BeNumerically("==", h.expectedDeleteEventCount[gvk]), "%s: incorrect number of delete events for %s", callerInfo, gvk) + } }).WithTimeout(timeout).Should(gomega.Succeed()) } func (h *countingResourceEventHandler) AssertConsistently(g gomega.Gomega, timeout time.Duration) { + _, file, no, _ := goruntime.Caller(1) + callerInfo := fmt.Sprintf("%s:%d", file, no) + g.Consistently(func(g gomega.Gomega) { - g.Expect(h.generateCount).To(gomega.BeNumerically("==", h.expectedGenerateCount)) - g.Expect(h.addEventCount).To(gomega.BeNumerically("==", h.expectedAddEventCount)) - g.Expect(h.updateEventCount).To(gomega.BeNumerically("==", h.expectedUpdateEventCount)) - g.Expect(h.deleteEventCount).To(gomega.BeNumerically("==", h.expectedDeleteEventCount)) + for ftc := range h.expectedGenerateCount { + g.Expect(h.generateCount[ftc]). + To(gomega.BeNumerically("==", h.expectedGenerateCount[ftc]), "%s: incorrect number of generate events for %s", callerInfo, ftc) + } + for gvk := range h.expectedAddEventCount { + g.Expect(h.addEventCount[gvk]). + To(gomega.BeNumerically("==", h.expectedAddEventCount[gvk]), "%s: incorrect number of add events for %s", callerInfo, gvk) + } + for gvk := range h.expectedUpdateEventCount { + g.Expect(h.updateEventCount[gvk]). + To(gomega.BeNumerically("==", h.expectedUpdateEventCount[gvk]), "%s: incorrect number of update events for %s", callerInfo, gvk) + } + for gvk := range h.expectedDeleteEventCount { + g.Expect(h.deleteEventCount[gvk]). + To(gomega.BeNumerically("==", h.expectedDeleteEventCount[gvk]), "%s: incorrect number of delete events for %s", callerInfo, gvk) + } }).WithTimeout(timeout).Should(gomega.Succeed()) } -func (h *countingResourceEventHandler) GenerateEventHandler(_ *fedcorev1a1.FederatedTypeConfig) cache.ResourceEventHandler { +func (h *countingResourceEventHandler) GenerateEventHandler(ftc *fedcorev1a1.FederatedTypeConfig) cache.ResourceEventHandler { h.lock.Lock() defer h.lock.Unlock() - h.generateCount++ + h.generateCount[ftc.Name] = h.generateCount[ftc.Name] + 1 return h } -func (h *countingResourceEventHandler) OnAdd(_ interface{}) { +func (h *countingResourceEventHandler) OnAdd(obj interface{}) { h.lock.Lock() defer h.lock.Unlock() - h.addEventCount++ + + gvk := h.mustParseObject(obj) + h.addEventCount[gvk] = h.addEventCount[gvk] + 1 } -func (h *countingResourceEventHandler) OnDelete(_ interface{}) { +func (h *countingResourceEventHandler) OnDelete(obj interface{}) { h.lock.Lock() defer h.lock.Unlock() - h.deleteEventCount++ + + gvk := h.mustParseObject(obj) + h.deleteEventCount[gvk] = h.deleteEventCount[gvk] + 1 } -func (h *countingResourceEventHandler) OnUpdate(_ interface{}, _ interface{}) { +func (h *countingResourceEventHandler) OnUpdate(_ interface{}, obj interface{}) { h.lock.Lock() defer h.lock.Unlock() - h.updateEventCount++ + + gvk := h.mustParseObject(obj) + h.updateEventCount[gvk] = h.updateEventCount[gvk] + 1 +} + +func (h *countingResourceEventHandler) mustParseObject(obj interface{}) schema.GroupVersionKind { + uns := obj.(*unstructured.Unstructured) + gv, err := schema.ParseGroupVersion(uns.GetAPIVersion()) + if err != nil { + panic(fmt.Errorf("failed to parse GroupVersion from unstructured: %w", err)) + } + return gv.WithKind(uns.GetKind()) } var _ cache.ResourceEventHandler = &countingResourceEventHandler{}