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
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
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
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
165
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
177
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
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
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 })
216
View as plain text