...

Source file src/sigs.k8s.io/controller-runtime/pkg/finalizer/finalizer_test.go

Documentation: sigs.k8s.io/controller-runtime/pkg/finalizer

     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  })
   216  

View as plain text