@@ -742,6 +742,164 @@ func TestReconcileEndpointSlicesMetrics(t *testing.T) {
742
742
expectMetrics (t , expectedMetrics {desiredSlices : 1 , actualSlices : 1 , desiredEndpoints : 10 , addedPerSync : 20 , removedPerSync : 10 , numCreated : 1 , numUpdated : 1 , numDeleted : 0 })
743
743
}
744
744
745
+ // When a Service has a non-nil deletionTimestamp we want to avoid creating any
746
+ // new EndpointSlices but continue to allow updates and deletes through. This
747
+ // test uses 3 EndpointSlices, 1 "to-create", 1 "to-update", and 1 "to-delete".
748
+ // Each test case exercises different combinations of calls to finalize with
749
+ // those resources.
750
+ func TestReconcilerFinalizeSvcDeletionTimestamp (t * testing.T ) {
751
+ now := metav1 .Now ()
752
+
753
+ testCases := []struct {
754
+ name string
755
+ deletionTimestamp * metav1.Time
756
+ attemptCreate bool
757
+ attemptUpdate bool
758
+ attemptDelete bool
759
+ expectCreatedSlice bool
760
+ expectUpdatedSlice bool
761
+ expectDeletedSlice bool
762
+ }{{
763
+ name : "Attempt create and update, nil deletion timestamp" ,
764
+ deletionTimestamp : nil ,
765
+ attemptCreate : true ,
766
+ attemptUpdate : true ,
767
+ expectCreatedSlice : true ,
768
+ expectUpdatedSlice : true ,
769
+ expectDeletedSlice : true ,
770
+ }, {
771
+ name : "Attempt create and update, deletion timestamp set" ,
772
+ deletionTimestamp : & now ,
773
+ attemptCreate : true ,
774
+ attemptUpdate : true ,
775
+ expectCreatedSlice : false ,
776
+ expectUpdatedSlice : true ,
777
+ expectDeletedSlice : true ,
778
+ }, {
779
+ // Slice scheduled for creation is transitioned to update of Slice
780
+ // scheduled for deletion.
781
+ name : "Attempt create, update, and delete, nil deletion timestamp, recycling in action" ,
782
+ deletionTimestamp : nil ,
783
+ attemptCreate : true ,
784
+ attemptUpdate : true ,
785
+ attemptDelete : true ,
786
+ expectCreatedSlice : false ,
787
+ expectUpdatedSlice : true ,
788
+ expectDeletedSlice : true ,
789
+ }, {
790
+ // Slice scheduled for creation is transitioned to update of Slice
791
+ // scheduled for deletion.
792
+ name : "Attempt create, update, and delete, deletion timestamp set, recycling in action" ,
793
+ deletionTimestamp : & now ,
794
+ attemptCreate : true ,
795
+ attemptUpdate : true ,
796
+ attemptDelete : true ,
797
+ expectCreatedSlice : false ,
798
+ expectUpdatedSlice : true ,
799
+ expectDeletedSlice : true ,
800
+ }, {
801
+ // Update and delete continue to work when deletionTimestamp is set.
802
+ name : "Attempt update delete, deletion timestamp set" ,
803
+ deletionTimestamp : & now ,
804
+ attemptCreate : false ,
805
+ attemptUpdate : true ,
806
+ attemptDelete : true ,
807
+ expectCreatedSlice : false ,
808
+ expectUpdatedSlice : true ,
809
+ expectDeletedSlice : false ,
810
+ }}
811
+
812
+ for _ , tc := range testCases {
813
+ t .Run (tc .name , func (t * testing.T ) {
814
+ client := newClientset ()
815
+ setupMetrics ()
816
+ r := newReconciler (client , []* corev1.Node {{ObjectMeta : metav1.ObjectMeta {Name : "node-1" }}}, defaultMaxEndpointsPerSlice )
817
+
818
+ namespace := "test"
819
+ svc , endpointMeta := newServiceAndEndpointMeta ("foo" , namespace )
820
+ svc .DeletionTimestamp = tc .deletionTimestamp
821
+ esToCreate := & discovery.EndpointSlice {
822
+ ObjectMeta : metav1.ObjectMeta {Name : "to-create" },
823
+ AddressType : endpointMeta .AddressType ,
824
+ Ports : endpointMeta .Ports ,
825
+ }
826
+
827
+ // Add EndpointSlice that can be updated.
828
+ esToUpdate , err := client .DiscoveryV1beta1 ().EndpointSlices (namespace ).Create (context .TODO (), & discovery.EndpointSlice {
829
+ ObjectMeta : metav1.ObjectMeta {Name : "to-update" },
830
+ AddressType : endpointMeta .AddressType ,
831
+ Ports : endpointMeta .Ports ,
832
+ }, metav1.CreateOptions {})
833
+ if err != nil {
834
+ t .Fatalf ("Expected no error creating EndpointSlice during test setup, got %v" , err )
835
+ }
836
+ // Add an endpoint so we can see if this has actually been updated by
837
+ // finalize func.
838
+ esToUpdate .Endpoints = []discovery.Endpoint {{Addresses : []string {"10.2.3.4" }}}
839
+
840
+ // Add EndpointSlice that can be deleted.
841
+ esToDelete , err := client .DiscoveryV1beta1 ().EndpointSlices (namespace ).Create (context .TODO (), & discovery.EndpointSlice {
842
+ ObjectMeta : metav1.ObjectMeta {Name : "to-delete" },
843
+ AddressType : endpointMeta .AddressType ,
844
+ Ports : endpointMeta .Ports ,
845
+ }, metav1.CreateOptions {})
846
+ if err != nil {
847
+ t .Fatalf ("Expected no error creating EndpointSlice during test setup, got %v" , err )
848
+ }
849
+
850
+ slicesToCreate := []* discovery.EndpointSlice {}
851
+ if tc .attemptCreate {
852
+ slicesToCreate = append (slicesToCreate , esToCreate .DeepCopy ())
853
+ }
854
+ slicesToUpdate := []* discovery.EndpointSlice {}
855
+ if tc .attemptUpdate {
856
+ slicesToUpdate = append (slicesToUpdate , esToUpdate .DeepCopy ())
857
+ }
858
+ slicesToDelete := []* discovery.EndpointSlice {}
859
+ if tc .attemptDelete {
860
+ slicesToDelete = append (slicesToDelete , esToDelete .DeepCopy ())
861
+ }
862
+
863
+ err = r .finalize (& svc , slicesToCreate , slicesToUpdate , slicesToDelete , time .Now ())
864
+ if err != nil {
865
+ t .Errorf ("Error calling r.finalize(): %v" , err )
866
+ }
867
+
868
+ fetchedSlices := fetchEndpointSlices (t , client , namespace )
869
+
870
+ createdSliceFound := false
871
+ updatedSliceFound := false
872
+ deletedSliceFound := false
873
+ for _ , epSlice := range fetchedSlices {
874
+ if epSlice .Name == esToCreate .Name {
875
+ createdSliceFound = true
876
+ }
877
+ if epSlice .Name == esToUpdate .Name {
878
+ updatedSliceFound = true
879
+ if tc .attemptUpdate && len (epSlice .Endpoints ) != len (esToUpdate .Endpoints ) {
880
+ t .Errorf ("Expected EndpointSlice to be updated with %d endpoints, got %d endpoints" , len (esToUpdate .Endpoints ), len (epSlice .Endpoints ))
881
+ }
882
+ }
883
+ if epSlice .Name == esToDelete .Name {
884
+ deletedSliceFound = true
885
+ }
886
+ }
887
+
888
+ if createdSliceFound != tc .expectCreatedSlice {
889
+ t .Errorf ("Expected created EndpointSlice existence to be %t, got %t" , tc .expectCreatedSlice , createdSliceFound )
890
+ }
891
+
892
+ if updatedSliceFound != tc .expectUpdatedSlice {
893
+ t .Errorf ("Expected updated EndpointSlice existence to be %t, got %t" , tc .expectUpdatedSlice , updatedSliceFound )
894
+ }
895
+
896
+ if deletedSliceFound != tc .expectDeletedSlice {
897
+ t .Errorf ("Expected deleted EndpointSlice existence to be %t, got %t" , tc .expectDeletedSlice , deletedSliceFound )
898
+ }
899
+ })
900
+ }
901
+ }
902
+
745
903
// Test Helpers
746
904
747
905
func newReconciler (client * fake.Clientset , nodes []* corev1.Node , maxEndpointsPerSlice int32 ) * reconciler {
0 commit comments