diff --git a/pkg/reconciler/internal/hook/hook_test.go b/pkg/reconciler/internal/hook/hook_test.go index c349e7cd..35f6f34c 100644 --- a/pkg/reconciler/internal/hook/hook_test.go +++ b/pkg/reconciler/internal/hook/hook_test.go @@ -18,6 +18,8 @@ package hook_test import ( "context" + "fmt" + "reflect" "strings" "github.com/go-logr/logr" @@ -30,10 +32,13 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "sigs.k8s.io/controller-runtime/pkg/cache" "sigs.k8s.io/controller-runtime/pkg/cache/informertest" + "sigs.k8s.io/controller-runtime/pkg/handler" + "sigs.k8s.io/controller-runtime/pkg/source" "github.com/operator-framework/helm-operator-plugins/pkg/hook" "github.com/operator-framework/helm-operator-plugins/pkg/internal/fake" internalhook "github.com/operator-framework/helm-operator-plugins/pkg/reconciler/internal/hook" + sdkhandler "github.com/operator-framework/operator-lib/handler" ) var _ = Describe("Hook", func() { @@ -124,6 +129,8 @@ var _ = Describe("Hook", func() { drw = internalhook.NewDependentResourceWatcher(c, rm, cache, sch) Expect(drw.Exec(owner, *rel, log)).To(Succeed()) Expect(c.WatchCalls).To(HaveLen(2)) + Expect(validateSourceHandlerType(c.WatchCalls[0].Source, handler.TypedEnqueueRequestForOwner[*unstructured.Unstructured](sch, rm, owner, handler.OnlyControllerOwner()))).To(BeTrue()) + Expect(validateSourceHandlerType(c.WatchCalls[1].Source, handler.TypedEnqueueRequestForOwner[*unstructured.Unstructured](sch, rm, owner, handler.OnlyControllerOwner()))).To(BeTrue()) }) Context("when the owner is cluster-scoped", func() { @@ -145,6 +152,8 @@ var _ = Describe("Hook", func() { drw = internalhook.NewDependentResourceWatcher(c, rm, cache, sch) Expect(drw.Exec(owner, *rel, log)).To(Succeed()) Expect(c.WatchCalls).To(HaveLen(2)) + Expect(validateSourceHandlerType(c.WatchCalls[0].Source, handler.TypedEnqueueRequestForOwner[*unstructured.Unstructured](sch, rm, owner, handler.OnlyControllerOwner()))).To(BeTrue()) + Expect(validateSourceHandlerType(c.WatchCalls[1].Source, handler.TypedEnqueueRequestForOwner[*unstructured.Unstructured](sch, rm, owner, handler.OnlyControllerOwner()))).To(BeTrue()) }) It("should watch cluster-scoped resources with ownerRef handler", func() { rel = &release.Release{ @@ -153,6 +162,8 @@ var _ = Describe("Hook", func() { drw = internalhook.NewDependentResourceWatcher(c, rm, cache, sch) Expect(drw.Exec(owner, *rel, log)).To(Succeed()) Expect(c.WatchCalls).To(HaveLen(2)) + Expect(validateSourceHandlerType(c.WatchCalls[0].Source, handler.TypedEnqueueRequestForOwner[*unstructured.Unstructured](sch, rm, owner, handler.OnlyControllerOwner()))).To(BeTrue()) + Expect(validateSourceHandlerType(c.WatchCalls[1].Source, handler.TypedEnqueueRequestForOwner[*unstructured.Unstructured](sch, rm, owner, handler.OnlyControllerOwner()))).To(BeTrue()) }) It("should watch resource policy keep resources with annotation handler", func() { rel = &release.Release{ @@ -161,6 +172,10 @@ var _ = Describe("Hook", func() { drw = internalhook.NewDependentResourceWatcher(c, rm, cache, sch) Expect(drw.Exec(owner, *rel, log)).To(Succeed()) Expect(c.WatchCalls).To(HaveLen(4)) + Expect(validateSourceHandlerType(c.WatchCalls[0].Source, &sdkhandler.EnqueueRequestForAnnotation[*unstructured.Unstructured]{})).To(BeTrue()) + Expect(validateSourceHandlerType(c.WatchCalls[1].Source, &sdkhandler.EnqueueRequestForAnnotation[*unstructured.Unstructured]{})).To(BeTrue()) + Expect(validateSourceHandlerType(c.WatchCalls[2].Source, &sdkhandler.EnqueueRequestForAnnotation[*unstructured.Unstructured]{})).To(BeTrue()) + Expect(validateSourceHandlerType(c.WatchCalls[3].Source, &sdkhandler.EnqueueRequestForAnnotation[*unstructured.Unstructured]{})).To(BeTrue()) }) }) @@ -184,6 +199,7 @@ var _ = Describe("Hook", func() { drw = internalhook.NewDependentResourceWatcher(c, rm, cache, sch) Expect(drw.Exec(owner, *rel, log)).To(Succeed()) Expect(c.WatchCalls).To(HaveLen(1)) + Expect(validateSourceHandlerType(c.WatchCalls[0].Source, handler.TypedEnqueueRequestForOwner[*unstructured.Unstructured](sch, rm, owner, handler.OnlyControllerOwner()))).To(BeTrue()) }) It("should watch cluster-scoped resources with annotation handler", func() { rel = &release.Release{ @@ -200,6 +216,7 @@ var _ = Describe("Hook", func() { drw = internalhook.NewDependentResourceWatcher(c, rm, cache, sch) Expect(drw.Exec(owner, *rel, log)).To(Succeed()) Expect(c.WatchCalls).To(HaveLen(1)) + Expect(validateSourceHandlerType(c.WatchCalls[0].Source, &sdkhandler.EnqueueRequestForAnnotation[*unstructured.Unstructured]{})).To(BeTrue()) }) It("should watch resource policy keep resources with annotation handler", func() { rel = &release.Release{ @@ -208,6 +225,9 @@ var _ = Describe("Hook", func() { drw = internalhook.NewDependentResourceWatcher(c, rm, cache, sch) Expect(drw.Exec(owner, *rel, log)).To(Succeed()) Expect(c.WatchCalls).To(HaveLen(3)) + Expect(validateSourceHandlerType(c.WatchCalls[0].Source, &sdkhandler.EnqueueRequestForAnnotation[*unstructured.Unstructured]{})).To(BeTrue()) + Expect(validateSourceHandlerType(c.WatchCalls[1].Source, &sdkhandler.EnqueueRequestForAnnotation[*unstructured.Unstructured]{})).To(BeTrue()) + Expect(validateSourceHandlerType(c.WatchCalls[2].Source, &sdkhandler.EnqueueRequestForAnnotation[*unstructured.Unstructured]{})).To(BeTrue()) }) It("should iterate the kind list and be able to set watches on each item", func() { rel = &release.Release{ @@ -216,6 +236,8 @@ var _ = Describe("Hook", func() { drw = internalhook.NewDependentResourceWatcher(c, rm, cache, sch) Expect(drw.Exec(owner, *rel, log)).To(Succeed()) Expect(c.WatchCalls).To(HaveLen(2)) + Expect(validateSourceHandlerType(c.WatchCalls[0].Source, handler.TypedEnqueueRequestForOwner[*unstructured.Unstructured](sch, rm, owner, handler.OnlyControllerOwner()))).To(BeTrue()) + Expect(validateSourceHandlerType(c.WatchCalls[1].Source, handler.TypedEnqueueRequestForOwner[*unstructured.Unstructured](sch, rm, owner, handler.OnlyControllerOwner()))).To(BeTrue()) }) It("should error when unable to list objects", func() { rel = &release.Release{ @@ -230,6 +252,23 @@ var _ = Describe("Hook", func() { }) }) +// validateSourceHandlerType takes in a source.Source and uses reflection to determine +// if the handler used by the source matches the expected type. +// It is assumed that the source.Source was created via the source.Kind() function. +func validateSourceHandlerType(s source.Source, expected interface{}) bool { + sourceVal := reflect.Indirect(reflect.ValueOf(s)) + handlerFieldVal := sourceVal.FieldByName("Handler") + + handlerField := reflect.Indirect(handlerFieldVal.Elem()) + handlerType := handlerField.Type() + + expectedValue := reflect.Indirect(reflect.ValueOf(expected)) + + expectedType := expectedValue.Type() + fmt.Println("XXX DEBUG", handlerType, expectedType, handlerType == expectedType) + return handlerType == expectedType +} + var ( rsOwnerNamespace = ` apiVersion: apps/v1