@@ -10,6 +10,7 @@ import (
1010
1111	"github.com/agiledragon/gomonkey/v2" 
1212	"github.com/stretchr/testify/assert" 
13+ 	"github.com/stretchr/testify/require" 
1314	"github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" 
1415	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 
1516	"k8s.io/apimachinery/pkg/runtime" 
@@ -803,3 +804,193 @@ func TestStartSubnetController(t *testing.T) {
803804		})
804805	}
805806}
807+ 
808+ func  TestReconcileWithSubnetConnectionBindingMaps (t  * testing.T ) {
809+ 	subnetName  :=  "subnet1" 
810+ 	ns  :=  "ns1" 
811+ 	testSubnet1  :=  & v1alpha1.Subnet {
812+ 		ObjectMeta : metav1.ObjectMeta {Name : subnetName , Namespace : ns },
813+ 		Spec : v1alpha1.SubnetSpec {
814+ 			AccessMode :     v1alpha1 .AccessMode (v1alpha1 .AccessModePrivate ),
815+ 			IPv4SubnetSize : 16 ,
816+ 		},
817+ 	}
818+ 	testSubnet2  :=  & v1alpha1.Subnet {
819+ 		ObjectMeta : metav1.ObjectMeta {Name : subnetName , Namespace : ns , Finalizers : []string {common .SubnetFinalizerName }},
820+ 		Spec : v1alpha1.SubnetSpec {
821+ 			AccessMode :     v1alpha1 .AccessMode (v1alpha1 .AccessModePrivate ),
822+ 			IPv4SubnetSize : 16 ,
823+ 		},
824+ 	}
825+ 	deletionTime  :=  metav1 .Now ()
826+ 	testSubnet3  :=  & v1alpha1.Subnet {
827+ 		ObjectMeta : metav1.ObjectMeta {
828+ 			Name :              subnetName ,
829+ 			Namespace :         ns ,
830+ 			Finalizers :        []string {common .SubnetFinalizerName },
831+ 			DeletionTimestamp : & deletionTime ,
832+ 		},
833+ 		Spec : v1alpha1.SubnetSpec {
834+ 			AccessMode :     v1alpha1 .AccessMode (v1alpha1 .AccessModePrivate ),
835+ 			IPv4SubnetSize : 16 ,
836+ 		},
837+ 	}
838+ 	for  _ , tc  :=  range  []struct  {
839+ 		name            string 
840+ 		existingSubnet  * v1alpha1.Subnet 
841+ 		patches         func (t  * testing.T , r  * SubnetReconciler ) * gomonkey.Patches 
842+ 		expectErrStr    string 
843+ 		expectRes       ctrl.Result 
844+ 	}{
845+ 		{
846+ 			name :           "Successfully add finalizer after a Subnet is used by SubnetConnectionBindingMap" ,
847+ 			existingSubnet : testSubnet1 ,
848+ 			patches : func (t  * testing.T , r  * SubnetReconciler ) * gomonkey.Patches  {
849+ 				patches  :=  gomonkey .ApplyPrivateMethod (reflect .TypeOf (r ), "getSubnetBindingCRsBySubnet" , func (_  * SubnetReconciler , _  context.Context , _  * v1alpha1.Subnet ) []v1alpha1.SubnetConnectionBindingMap  {
850+ 					return  []v1alpha1.SubnetConnectionBindingMap {{ObjectMeta : metav1.ObjectMeta {Name : "binding1" , Namespace : ns }}}
851+ 				})
852+ 				patches .ApplyMethod (reflect .TypeOf (r .Client ), "Update" , func (_  client.Client , _  context.Context , obj  client.Object , opts  ... client.UpdateOption ) error  {
853+ 					return  nil 
854+ 				})
855+ 				return  patchSuccessfulReconcileSubnetWorkflow (r , patches )
856+ 			},
857+ 			expectRes : ctrl.Result {},
858+ 		}, {
859+ 			name :           "Failed to add finalizer after a Subnet is used by SubnetConnectionBindingMap" ,
860+ 			existingSubnet : testSubnet1 ,
861+ 			patches : func (t  * testing.T , r  * SubnetReconciler ) * gomonkey.Patches  {
862+ 				patches  :=  gomonkey .ApplyPrivateMethod (reflect .TypeOf (r ), "getSubnetBindingCRsBySubnet" , func (_  * SubnetReconciler , _  context.Context , _  * v1alpha1.Subnet ) []v1alpha1.SubnetConnectionBindingMap  {
863+ 					return  []v1alpha1.SubnetConnectionBindingMap {{ObjectMeta : metav1.ObjectMeta {Name : "binding1" , Namespace : ns }}}
864+ 				})
865+ 				patches .ApplyMethod (reflect .TypeOf (r .Client ), "Update" , func (_  client.Client , _  context.Context , obj  client.Object , opts  ... client.UpdateOption ) error  {
866+ 					return  fmt .Errorf ("failed to update CR" )
867+ 				})
868+ 				patches .ApplyFunc (updateSubnetStatusConditions , func (_  client.Client , _  context.Context , _  * v1alpha1.Subnet , newConditions  []v1alpha1.Condition ) {
869+ 					require .Equal (t , 1 , len (newConditions ))
870+ 					cond  :=  newConditions [0 ]
871+ 					assert .Equal (t , "Failed to add the finalizer on a Subnet for the reference by SubnetConnectionBindingMap binding1" , cond .Message )
872+ 				})
873+ 				return  patches 
874+ 			},
875+ 			expectErrStr : "failed to update CR" ,
876+ 			expectRes :    common2 .ResultRequeue ,
877+ 		}, {
878+ 			name :           "Not add duplicated finalizer after a Subnet is used by SubnetConnectionBindingMap" ,
879+ 			existingSubnet : testSubnet2 ,
880+ 			patches : func (t  * testing.T , r  * SubnetReconciler ) * gomonkey.Patches  {
881+ 				patches  :=  gomonkey .ApplyPrivateMethod (reflect .TypeOf (r ), "getSubnetBindingCRsBySubnet" , func (_  * SubnetReconciler , _  context.Context , _  * v1alpha1.Subnet ) []v1alpha1.SubnetConnectionBindingMap  {
882+ 					return  []v1alpha1.SubnetConnectionBindingMap {{ObjectMeta : metav1.ObjectMeta {Name : "binding1" , Namespace : ns }}}
883+ 				})
884+ 				patches .ApplyMethod (reflect .TypeOf (r .Client ), "Update" , func (_  client.Client , _  context.Context , obj  client.Object , opts  ... client.UpdateOption ) error  {
885+ 					assert .FailNow (t , "Should not update Subnet CR finalizer" )
886+ 					return  nil 
887+ 				})
888+ 				return  patchSuccessfulReconcileSubnetWorkflow (r , patches )
889+ 			},
890+ 			expectRes : ctrl.Result {},
891+ 		}, {
892+ 			name :           "Successfully remove finalizer after a Subnet is not used by any SubnetConnectionBindingMaps" ,
893+ 			existingSubnet : testSubnet2 ,
894+ 			patches : func (t  * testing.T , r  * SubnetReconciler ) * gomonkey.Patches  {
895+ 				patches  :=  gomonkey .ApplyPrivateMethod (reflect .TypeOf (r ), "getSubnetBindingCRsBySubnet" , func (_  * SubnetReconciler , _  context.Context , _  * v1alpha1.Subnet ) []v1alpha1.SubnetConnectionBindingMap  {
896+ 					return  []v1alpha1.SubnetConnectionBindingMap {}
897+ 				})
898+ 				patches .ApplyMethod (reflect .TypeOf (r .Client ), "Update" , func (_  client.Client , _  context.Context , obj  client.Object , opts  ... client.UpdateOption ) error  {
899+ 					return  nil 
900+ 				})
901+ 				return  patchSuccessfulReconcileSubnetWorkflow (r , patches )
902+ 			},
903+ 			expectRes : ctrl.Result {},
904+ 		}, {
905+ 			name :           "Failed to remove finalizer after a Subnet is not used by any SubnetConnectionBindingMaps" ,
906+ 			existingSubnet : testSubnet2 ,
907+ 			patches : func (t  * testing.T , r  * SubnetReconciler ) * gomonkey.Patches  {
908+ 				patches  :=  gomonkey .ApplyPrivateMethod (reflect .TypeOf (r ), "getSubnetBindingCRsBySubnet" , func (_  * SubnetReconciler , _  context.Context , _  * v1alpha1.Subnet ) []v1alpha1.SubnetConnectionBindingMap  {
909+ 					return  []v1alpha1.SubnetConnectionBindingMap {}
910+ 				})
911+ 				patches .ApplyMethod (reflect .TypeOf (r .Client ), "Update" , func (_  client.Client , _  context.Context , obj  client.Object , opts  ... client.UpdateOption ) error  {
912+ 					return  fmt .Errorf ("failed to update CR" )
913+ 				})
914+ 				patches .ApplyFunc (updateSubnetStatusConditions , func (_  client.Client , _  context.Context , _  * v1alpha1.Subnet , newConditions  []v1alpha1.Condition ) {
915+ 					require .Equal (t , 1 , len (newConditions ))
916+ 					cond  :=  newConditions [0 ]
917+ 					assert .Equal (t , "Failed to remove the finalizer on a Subnet when there is no reference by SubnetConnectionBindingMaps" , cond .Message )
918+ 				})
919+ 				return  patches 
920+ 			},
921+ 			expectErrStr : "failed to update CR" ,
922+ 			expectRes :    common2 .ResultRequeue ,
923+ 		}, {
924+ 			name :           "Not update finalizers if a Subnet is not used by any SubnetConnectionBindingMaps" ,
925+ 			existingSubnet : testSubnet1 ,
926+ 			patches : func (t  * testing.T , r  * SubnetReconciler ) * gomonkey.Patches  {
927+ 				patches  :=  gomonkey .ApplyPrivateMethod (reflect .TypeOf (r ), "getSubnetBindingCRsBySubnet" , func (_  * SubnetReconciler , _  context.Context , _  * v1alpha1.Subnet ) []v1alpha1.SubnetConnectionBindingMap  {
928+ 					return  []v1alpha1.SubnetConnectionBindingMap {}
929+ 				})
930+ 				patches .ApplyMethod (reflect .TypeOf (r .Client ), "Update" , func (_  client.Client , _  context.Context , obj  client.Object , opts  ... client.UpdateOption ) error  {
931+ 					assert .FailNow (t , "Should not update Subnet CR finalizer" )
932+ 					return  nil 
933+ 				})
934+ 				return  patchSuccessfulReconcileSubnetWorkflow (r , patches )
935+ 			},
936+ 			expectRes : ctrl.Result {},
937+ 		}, {
938+ 			name :           "Delete a Subnet is not allowed if it is used by SubnetConnectionBindingMap" ,
939+ 			existingSubnet : testSubnet3 ,
940+ 			patches : func (t  * testing.T , r  * SubnetReconciler ) * gomonkey.Patches  {
941+ 				patches  :=  gomonkey .ApplyPrivateMethod (reflect .TypeOf (r ), "getSubnetBindingCRsBySubnet" , func (_  * SubnetReconciler , _  context.Context , _  * v1alpha1.Subnet ) []v1alpha1.SubnetConnectionBindingMap  {
942+ 					return  []v1alpha1.SubnetConnectionBindingMap {}
943+ 				})
944+ 				patches .ApplyPrivateMethod (reflect .TypeOf (r ), "getNSXSubnetBindingsBySubnet" , func (_  * SubnetReconciler , _  string ) []* v1alpha1.SubnetConnectionBindingMap  {
945+ 					return  []* v1alpha1.SubnetConnectionBindingMap {{ObjectMeta : metav1.ObjectMeta {Name : "binding1" , Namespace : ns }}}
946+ 				})
947+ 				patches .ApplyPrivateMethod (reflect .TypeOf (r ), "setSubnetDeletionFailedStatus" , func (_  * SubnetReconciler , _  context.Context , _  * v1alpha1.Subnet , _  metav1.Time , msg  string , reason  string ) {
948+ 					assert .Equal (t , "Subnet is used by SubnetConnectionBindingMap binding1 and not able to delete" , msg )
949+ 					assert .Equal (t , "SubnetInUse" , reason )
950+ 				})
951+ 				return  patches 
952+ 			},
953+ 			expectErrStr : "failed to delete Subnet CR ns1/subnet1" ,
954+ 			expectRes :    ResultRequeue ,
955+ 		},
956+ 	} {
957+ 		t .Run (tc .name , func (t  * testing.T ) {
958+ 			ctx  :=  context .TODO ()
959+ 			req  :=  ctrl.Request {NamespacedName : types.NamespacedName {Name : subnetName , Namespace : ns }}
960+ 			r  :=  createFakeSubnetReconciler ([]client.Object {tc .existingSubnet })
961+ 			if  tc .patches  !=  nil  {
962+ 				patches  :=  tc .patches (t , r )
963+ 				defer  patches .Reset ()
964+ 			}
965+ 
966+ 			res , err  :=  r .Reconcile (ctx , req )
967+ 
968+ 			if  tc .expectErrStr  !=  ""  {
969+ 				assert .EqualError (t , err , tc .expectErrStr )
970+ 			} else  {
971+ 				assert .NoError (t , err )
972+ 			}
973+ 			assert .Equal (t , tc .expectRes , res )
974+ 		})
975+ 	}
976+ }
977+ 
978+ func  patchSuccessfulReconcileSubnetWorkflow (r  * SubnetReconciler , patches  * gomonkey.Patches ) * gomonkey.Patches  {
979+ 	patches .ApplyMethod (reflect .TypeOf (r .SubnetService ), "GenerateSubnetNSTags" , func (_  * subnet.SubnetService , _  client.Object ) []model.Tag  {
980+ 		return  []model.Tag {{Scope : common .String ("test" ), Tag : common .String ("subnet" )}}
981+ 	})
982+ 	patches .ApplyMethod (reflect .TypeOf (r .VPCService ), "ListVPCInfo" , func (_  * vpc.VPCService , _  string ) []common.VPCResourceInfo  {
983+ 		return  []common.VPCResourceInfo {{ID : "vpc1" }}
984+ 	})
985+ 	patches .ApplyMethod (reflect .TypeOf (r .SubnetService ), "CreateOrUpdateSubnet" , func (_  * subnet.SubnetService , _  client.Object , _  common.VPCResourceInfo , _  []model.Tag ) (subnet  * model.VpcSubnet , err  error ) {
986+ 		return  & model.VpcSubnet {
987+ 			Path : common .String ("subnet-path" ),
988+ 		}, nil 
989+ 	})
990+ 	patches .ApplyPrivateMethod (reflect .TypeOf (r ), "updateSubnetStatus" , func (_  * SubnetReconciler , _  * v1alpha1.Subnet ) error  {
991+ 		return  nil 
992+ 	})
993+ 	patches .ApplyFunc (setSubnetReadyStatusTrue , func (_  client.Client , _  context.Context , _  client.Object , _  metav1.Time , _  ... interface {}) {
994+ 	})
995+ 	return  patches 
996+ }
0 commit comments