From 2484830743f900f0efd0e75a97728404f271c2f4 Mon Sep 17 00:00:00 2001 From: Rashmi Gottipati Date: Tue, 20 Apr 2021 05:35:17 -0400 Subject: [PATCH] WIP: unit tests Signed-off-by: Rashmi Gottipati --- pkg/finalizer/finalizer.go | 11 ++-- pkg/finalizer/finalizer_test.go | 92 +++++++++++++++++++++++++++++++++ pkg/finalizer/types.go | 13 +++-- 3 files changed, 107 insertions(+), 9 deletions(-) create mode 100644 pkg/finalizer/finalizer_test.go diff --git a/pkg/finalizer/finalizer.go b/pkg/finalizer/finalizer.go index 5d242e9faa..8d4d078ff3 100644 --- a/pkg/finalizer/finalizer.go +++ b/pkg/finalizer/finalizer.go @@ -21,8 +21,9 @@ import ( "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" ) -func NewFinalizers() (Finalizers, error) { - return finalizers(map[string]Finalizer{}), nil +// NewFinalizers returns the Finalizers interface +func NewFinalizers() Finalizers { + return finalizers(map[string]Finalizer{}) } func (f finalizers) Register(key string, finalizer Finalizer) error { @@ -36,13 +37,13 @@ func (f finalizers) Register(key string, finalizer Finalizer) error { func (f finalizers) Finalize(ctx context.Context, obj client.Object) (bool, error) { needsUpdate := false for key, finalizer := range f { - if obj.GetDeletionTimestamp() == nil && !controllerutil.ContainsFinalizer(obj, key) { + if obj.GetDeletionTimestamp().IsZero() && !controllerutil.ContainsFinalizer(obj, key) { controllerutil.AddFinalizer(obj, key) needsUpdate = true } else if obj.GetDeletionTimestamp() != nil && controllerutil.ContainsFinalizer(obj, key) { - _, err := finalizer.Finalize(ctx, obj) + needsUpdate, err := finalizer.Finalize(ctx, obj) if err != nil { - return true, fmt.Errorf("finalize failed for key %q: %v", key, err) + return needsUpdate, fmt.Errorf("finalize failed for key %q: %v", key, err) } controllerutil.RemoveFinalizer(obj, key) needsUpdate = true diff --git a/pkg/finalizer/finalizer_test.go b/pkg/finalizer/finalizer_test.go new file mode 100644 index 0000000000..ef338d47dc --- /dev/null +++ b/pkg/finalizer/finalizer_test.go @@ -0,0 +1,92 @@ +package finalizer + +import ( + "context" + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/envtest/printer" +) + +type mockFinalizer struct{} + +func (f mockFinalizer) Finalize(context.Context, client.Object) (needsUpdate bool, err error) { + return true, nil +} +func TestFinalizer(t *testing.T) { + RegisterFailHandler(Fail) + suiteName := "Finalizer Suite" + RunSpecsWithDefaultAndCustomReporters(t, suiteName, []Reporter{printer.NewlineReporter{}, printer.NewProwReporter(suiteName)}) +} + +var _ = Describe("TestFinalizer", func() { + var err error + var pod *corev1.Pod + var finalizers Finalizers + var f mockFinalizer + BeforeEach(func() { + pod = &corev1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Finalizers: []string{"finalizers.sigs.k8s.io/testfinalizer"}, + }, + } + Expect(pod).NotTo(BeNil()) + + finalizers = NewFinalizers() + Expect(finalizers).NotTo(BeNil()) + + f := mockFinalizer{} + Expect(f).NotTo(BeNil()) + + }) + Describe("Finalizer helper library", func() { + It("Register should successfully register a finalizer", func() { + err = finalizers.Register("finalizers.sigs.k8s.io/testfinalizer", f) + Expect(err).To(BeNil()) + }) + + It("Register should return an error when it is called twice with the same key", func() { + err = finalizers.Register("finalizers.sigs.k8s.io/testfinalizer", f) + Expect(err).To(BeNil()) + + // calling Register again with the same key should return an error + err = finalizers.Register("finalizers.sigs.k8s.io/testfinalizer", f) + Expect(err).NotTo(BeNil()) + Expect(err.Error()).To(ContainSubstring("already registered")) + + }) + + It("Finalize should return no error and indicate false for needsUpdate if a finalizer is not registered", func() { + ret, err := finalizers.Finalize(context.TODO(), pod) + Expect(err).To(BeNil()) + Expect(ret).To(BeFalse()) + }) + + It("Finalize should return no error when deletion timestamp is not nil and the finalizer exists", func() { + now := metav1.Now() + pod.DeletionTimestamp = &now + + err = finalizers.Register("finalizers.sigs.k8s.io/testfinalizer", f) + Expect(err).To(BeNil()) + + _, err := finalizers.Finalize(context.TODO(), pod) + Expect(err).To(BeNil()) + }) + + It("Finalize should return no error when deletion timestamp is nil and finalizer does not exist", func() { + err = finalizers.Register("finalizers.sigs.k8s.io/testfinalizer", f) + Expect(err).To(BeNil()) + + pod.DeletionTimestamp = nil + pod.Finalizers = []string{} + + ret, err := finalizers.Finalize(context.TODO(), pod) + Expect(err).To(BeNil()) + Expect(ret).To(BeTrue()) + }) + }) +}) diff --git a/pkg/finalizer/types.go b/pkg/finalizer/types.go index eac28d3708..edca7f9661 100644 --- a/pkg/finalizer/types.go +++ b/pkg/finalizer/types.go @@ -19,21 +19,26 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" ) +// Registerer holds Register that will check if a key is already registered +// and error out and it does; and if not registered, it will add the finalizer +// to the finalizers map as the value for the provided key type Registerer interface { Register(key string, f Finalizer) error } +// Finalizer holds Finalize that will add/remove a finalizer based on the +// deletion timestamp being set and return an indication of whether the +// obj needs an update or not type Finalizer interface { Finalize(context.Context, client.Object) (needsUpdate bool, err error) } type finalizers map[string]Finalizer +// Finalizers implements Registerer and Finalizer to finalize all registered +// finalizers if the provided object has a deletion timestamp or set all +// registered finalizers if it does not type Finalizers interface { - // implements Registerer and Finalizer to finalize - // all registered finalizers if the provided object - // has a deletion timestamp or set all registered - // finalizers if it doesn't Registerer Finalizer }