@@ -398,6 +398,29 @@ func TestReconciler_Reconcile(t *testing.T) {
398398 },
399399 expectedResult : common .ResultNormal ,
400400 },
401+ {
402+ name : "IPAddressType incompatible with Subnet" ,
403+ objects : []client.Object {& v1alpha1.SubnetIPReservation {
404+ ObjectMeta : metav1.ObjectMeta {Name : "ipr-1" , Namespace : "ns-1" },
405+ Spec : v1alpha1.SubnetIPReservationSpec {
406+ Subnet : "subnet-1" ,
407+ NumberOfIPs : 5 ,
408+ IPAddressType : v1alpha1 .IPAddressTypeIPv6 ,
409+ },
410+ }},
411+ preparedFunc : func (r * Reconciler ) * gomonkey.Patches {
412+ patches := gomonkey .ApplyPrivateMethod (reflect .TypeOf (r ), "validateSubnet" , func (_ * Reconciler , ctx context.Context , ns string , name string ) (* v1alpha1.Subnet , * errorWithRetry ) {
413+ return & v1alpha1.Subnet {
414+ Spec : v1alpha1.SubnetSpec {IPAddressType : v1alpha1 .IPAddressTypeIPv4 },
415+ }, nil
416+ })
417+ patches .ApplyMethod (reflect .TypeOf (r .IPReservationService .NSXClient ), "NSXCheckVersion" , func (_ * nsx.Client , feature int ) bool {
418+ return true
419+ })
420+ return patches
421+ },
422+ expectedResult : common .ResultNormal ,
423+ },
401424 }
402425 for _ , tc := range tests {
403426 r := createFakeReconciler (tc .objects ... )
@@ -508,6 +531,87 @@ func TestReconcile_validateSubnet(t *testing.T) {
508531 }
509532}
510533
534+ func TestValidateIPAddressTypeCompatibility (t * testing.T ) {
535+ tests := []struct {
536+ name string
537+ subnetType v1alpha1.IPAddressType
538+ reservationType v1alpha1.IPAddressType
539+ expectedErrSubstr string
540+ }{
541+ {
542+ name : "IPv4 subnet with IPv4 reservation" ,
543+ subnetType : v1alpha1 .IPAddressTypeIPv4 ,
544+ reservationType : v1alpha1 .IPAddressTypeIPv4 ,
545+ },
546+ {
547+ name : "IPv4 subnet with empty reservation defaults to IPv4" ,
548+ subnetType : v1alpha1 .IPAddressTypeIPv4 ,
549+ reservationType : "" ,
550+ },
551+ {
552+ name : "IPv4 subnet with IPv6 reservation - incompatible" ,
553+ subnetType : v1alpha1 .IPAddressTypeIPv4 ,
554+ reservationType : v1alpha1 .IPAddressTypeIPv6 ,
555+ expectedErrSubstr : "incompatible" ,
556+ },
557+ {
558+ name : "IPv4 subnet with dual-stack reservation - incompatible" ,
559+ subnetType : v1alpha1 .IPAddressTypeIPv4 ,
560+ reservationType : v1alpha1 .IPAddressTypeIPv4IPv6 ,
561+ expectedErrSubstr : "incompatible" ,
562+ },
563+ {
564+ name : "IPv6 subnet with IPv6 reservation" ,
565+ subnetType : v1alpha1 .IPAddressTypeIPv6 ,
566+ reservationType : v1alpha1 .IPAddressTypeIPv6 ,
567+ },
568+ {
569+ name : "IPv6 subnet with IPv4 reservation - incompatible" ,
570+ subnetType : v1alpha1 .IPAddressTypeIPv6 ,
571+ reservationType : v1alpha1 .IPAddressTypeIPv4 ,
572+ expectedErrSubstr : "incompatible" ,
573+ },
574+ {
575+ name : "Dual-stack subnet with IPv4 reservation" ,
576+ subnetType : v1alpha1 .IPAddressTypeIPv4IPv6 ,
577+ reservationType : v1alpha1 .IPAddressTypeIPv4 ,
578+ },
579+ {
580+ name : "Dual-stack subnet with IPv6 reservation" ,
581+ subnetType : v1alpha1 .IPAddressTypeIPv4IPv6 ,
582+ reservationType : v1alpha1 .IPAddressTypeIPv6 ,
583+ },
584+ {
585+ name : "Dual-stack subnet with dual-stack reservation" ,
586+ subnetType : v1alpha1 .IPAddressTypeIPv4IPv6 ,
587+ reservationType : v1alpha1 .IPAddressTypeIPv4IPv6 ,
588+ },
589+ {
590+ name : "Empty subnet type defaults to IPv4, IPv4 reservation" ,
591+ subnetType : "" ,
592+ reservationType : v1alpha1 .IPAddressTypeIPv4 ,
593+ },
594+ {
595+ name : "Empty subnet type defaults to IPv4, IPv6 reservation - incompatible" ,
596+ subnetType : "" ,
597+ reservationType : v1alpha1 .IPAddressTypeIPv6 ,
598+ expectedErrSubstr : "incompatible" ,
599+ },
600+ }
601+
602+ for _ , tc := range tests {
603+ t .Run (tc .name , func (t * testing.T ) {
604+ err := validateIPAddressTypeCompatibility (tc .subnetType , tc .reservationType )
605+ if tc .expectedErrSubstr != "" {
606+ assert .Error (t , err )
607+ assert .Contains (t , err .Error (), tc .expectedErrSubstr )
608+ } else {
609+ assert .NoError (t , err )
610+ }
611+ })
612+ }
613+ }
614+
511615func TestReconcile_CollectGarbage (t * testing.T ) {
512616 ipr1 := & v1alpha1.SubnetIPReservation {
513617 ObjectMeta : metav1.ObjectMeta {
0 commit comments