sigs.k8s.io/controller-runtime@v0.18.2/pkg/finalizer/finalizer_test.go (about) 1 package finalizer 2 3 import ( 4 "context" 5 "fmt" 6 "testing" 7 8 . "github.com/onsi/ginkgo/v2" 9 . "github.com/onsi/gomega" 10 corev1 "k8s.io/api/core/v1" 11 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 12 "sigs.k8s.io/controller-runtime/pkg/client" 13 ) 14 15 type mockFinalizer struct { 16 result Result 17 err error 18 } 19 20 func (f mockFinalizer) Finalize(context.Context, client.Object) (Result, error) { 21 return f.result, f.err 22 } 23 24 func TestFinalizer(t *testing.T) { 25 RegisterFailHandler(Fail) 26 RunSpecs(t, "Finalizer Suite") 27 } 28 29 var _ = Describe("TestFinalizer", func() { 30 var err error 31 var pod *corev1.Pod 32 var finalizers Finalizers 33 var f mockFinalizer 34 BeforeEach(func() { 35 pod = &corev1.Pod{ 36 ObjectMeta: metav1.ObjectMeta{}, 37 } 38 finalizers = NewFinalizers() 39 f = mockFinalizer{} 40 }) 41 Describe("Register", func() { 42 It("successfully registers a finalizer", func() { 43 err = finalizers.Register("finalizers.sigs.k8s.io/testfinalizer", f) 44 Expect(err).ToNot(HaveOccurred()) 45 }) 46 47 It("should fail when trying to register a finalizer that was already registered", func() { 48 err = finalizers.Register("finalizers.sigs.k8s.io/testfinalizer", f) 49 Expect(err).ToNot(HaveOccurred()) 50 51 // calling Register again with the same key should return an error 52 err = finalizers.Register("finalizers.sigs.k8s.io/testfinalizer", f) 53 Expect(err).To(HaveOccurred()) 54 Expect(err.Error()).To(ContainSubstring("already registered")) 55 56 }) 57 }) 58 59 Describe("Finalize", func() { 60 It("successfully finalizes and returns true for Updated when deletion timestamp is nil and finalizer does not exist", func() { 61 err = finalizers.Register("finalizers.sigs.k8s.io/testfinalizer", f) 62 Expect(err).ToNot(HaveOccurred()) 63 64 pod.DeletionTimestamp = nil 65 pod.Finalizers = []string{} 66 67 result, err := finalizers.Finalize(context.TODO(), pod) 68 Expect(err).ToNot(HaveOccurred()) 69 Expect(result.Updated).To(BeTrue()) 70 // when deletion timestamp is nil and finalizer is not present, the registered finalizer would be added to the obj 71 Expect(pod.Finalizers).To(HaveLen(1)) 72 Expect(pod.Finalizers[0]).To(Equal("finalizers.sigs.k8s.io/testfinalizer")) 73 74 }) 75 76 It("successfully finalizes and returns true for Updated when deletion timestamp is not nil and the finalizer exists", func() { 77 now := metav1.Now() 78 pod.DeletionTimestamp = &now 79 80 err = finalizers.Register("finalizers.sigs.k8s.io/testfinalizer", f) 81 Expect(err).ToNot(HaveOccurred()) 82 83 pod.Finalizers = []string{"finalizers.sigs.k8s.io/testfinalizer"} 84 85 result, err := finalizers.Finalize(context.TODO(), pod) 86 Expect(err).ToNot(HaveOccurred()) 87 Expect(result.Updated).To(BeTrue()) 88 // finalizer will be removed from the obj upon successful finalization 89 Expect(pod.Finalizers).To(BeEmpty()) 90 }) 91 92 It("should return no error and return false for Updated when deletion timestamp is nil and finalizer doesn't exist", func() { 93 pod.DeletionTimestamp = nil 94 pod.Finalizers = []string{} 95 96 result, err := finalizers.Finalize(context.TODO(), pod) 97 Expect(err).ToNot(HaveOccurred()) 98 Expect(result.Updated).To(BeFalse()) 99 Expect(pod.Finalizers).To(BeEmpty()) 100 101 }) 102 103 It("should return no error and return false for Updated when deletion timestamp is not nil and the finalizer doesn't exist", func() { 104 now := metav1.Now() 105 pod.DeletionTimestamp = &now 106 pod.Finalizers = []string{} 107 108 result, err := finalizers.Finalize(context.TODO(), pod) 109 Expect(err).ToNot(HaveOccurred()) 110 Expect(result.Updated).To(BeFalse()) 111 Expect(pod.Finalizers).To(BeEmpty()) 112 113 }) 114 115 It("successfully finalizes multiple finalizers and returns true for Updated when deletion timestamp is not nil and the finalizer exists", func() { 116 now := metav1.Now() 117 pod.DeletionTimestamp = &now 118 119 err = finalizers.Register("finalizers.sigs.k8s.io/testfinalizer", f) 120 Expect(err).ToNot(HaveOccurred()) 121 122 err = finalizers.Register("finalizers.sigs.k8s.io/newtestfinalizer", f) 123 Expect(err).ToNot(HaveOccurred()) 124 125 pod.Finalizers = []string{"finalizers.sigs.k8s.io/testfinalizer", "finalizers.sigs.k8s.io/newtestfinalizer"} 126 127 result, err := finalizers.Finalize(context.TODO(), pod) 128 Expect(err).ToNot(HaveOccurred()) 129 Expect(result.Updated).To(BeTrue()) 130 Expect(result.StatusUpdated).To(BeFalse()) 131 Expect(pod.Finalizers).To(BeEmpty()) 132 }) 133 134 It("should return result as false and a non-nil error", func() { 135 now := metav1.Now() 136 pod.DeletionTimestamp = &now 137 pod.Finalizers = []string{"finalizers.sigs.k8s.io/testfinalizer"} 138 139 f.result.Updated = false 140 f.result.StatusUpdated = false 141 f.err = fmt.Errorf("finalizer failed for %q", pod.Finalizers[0]) 142 143 err = finalizers.Register("finalizers.sigs.k8s.io/testfinalizer", f) 144 Expect(err).ToNot(HaveOccurred()) 145 146 result, err := finalizers.Finalize(context.TODO(), pod) 147 Expect(err).To(HaveOccurred()) 148 Expect(err.Error()).To(ContainSubstring("finalizer failed")) 149 Expect(result.Updated).To(BeFalse()) 150 Expect(result.StatusUpdated).To(BeFalse()) 151 Expect(pod.Finalizers).To(HaveLen(1)) 152 Expect(pod.Finalizers[0]).To(Equal("finalizers.sigs.k8s.io/testfinalizer")) 153 }) 154 155 It("should return expected result values and error values when registering multiple finalizers", func() { 156 now := metav1.Now() 157 pod.DeletionTimestamp = &now 158 pod.Finalizers = []string{ 159 "finalizers.sigs.k8s.io/testfinalizer1", 160 "finalizers.sigs.k8s.io/testfinalizer2", 161 "finalizers.sigs.k8s.io/testfinalizer3", 162 } 163 164 // registering multiple finalizers with different return values 165 // test for Updated as true, and nil error 166 f.result.Updated = true 167 f.result.StatusUpdated = false 168 f.err = nil 169 err = finalizers.Register("finalizers.sigs.k8s.io/testfinalizer1", f) 170 Expect(err).ToNot(HaveOccurred()) 171 172 result, err := finalizers.Finalize(context.TODO(), pod) 173 Expect(err).ToNot(HaveOccurred()) 174 Expect(result.Updated).To(BeTrue()) 175 Expect(result.StatusUpdated).To(BeFalse()) 176 // `finalizers.sigs.k8s.io/testfinalizer1` will be removed from the list 177 // of finalizers, so length will be 2. 178 Expect(pod.Finalizers).To(HaveLen(2)) 179 Expect(pod.Finalizers[0]).To(Equal("finalizers.sigs.k8s.io/testfinalizer2")) 180 Expect(pod.Finalizers[1]).To(Equal("finalizers.sigs.k8s.io/testfinalizer3")) 181 182 // test for Updated and StatusUpdated as false, and non-nil error 183 f.result.Updated = false 184 f.result.StatusUpdated = false 185 f.err = fmt.Errorf("finalizer failed") 186 err = finalizers.Register("finalizers.sigs.k8s.io/testfinalizer2", f) 187 Expect(err).ToNot(HaveOccurred()) 188 189 result, err = finalizers.Finalize(context.TODO(), pod) 190 Expect(err).To(HaveOccurred()) 191 Expect(err.Error()).To(ContainSubstring("finalizer failed")) 192 Expect(result.Updated).To(BeFalse()) 193 Expect(result.StatusUpdated).To(BeFalse()) 194 Expect(pod.Finalizers).To(HaveLen(2)) 195 Expect(pod.Finalizers[0]).To(Equal("finalizers.sigs.k8s.io/testfinalizer2")) 196 Expect(pod.Finalizers[1]).To(Equal("finalizers.sigs.k8s.io/testfinalizer3")) 197 198 // test for result as true, and non-nil error 199 f.result.Updated = true 200 f.result.StatusUpdated = true 201 f.err = fmt.Errorf("finalizer failed") 202 err = finalizers.Register("finalizers.sigs.k8s.io/testfinalizer3", f) 203 Expect(err).ToNot(HaveOccurred()) 204 205 result, err = finalizers.Finalize(context.TODO(), pod) 206 Expect(err).To(HaveOccurred()) 207 Expect(err.Error()).To(ContainSubstring("finalizer failed")) 208 Expect(result.Updated).To(BeTrue()) 209 Expect(result.StatusUpdated).To(BeTrue()) 210 Expect(pod.Finalizers).To(HaveLen(2)) 211 Expect(pod.Finalizers[0]).To(Equal("finalizers.sigs.k8s.io/testfinalizer2")) 212 Expect(pod.Finalizers[1]).To(Equal("finalizers.sigs.k8s.io/testfinalizer3")) 213 }) 214 }) 215 })