@@ -6,6 +6,7 @@ package e2e
66import (
77 "context"
88 "fmt"
9+ "math/rand/v2"
910 "strings"
1011 "testing"
1112 "time"
@@ -16,6 +17,9 @@ import (
1617 operatorclient "github.com/openshift/cluster-ingress-operator/pkg/operator/client"
1718 operatorcontroller "github.com/openshift/cluster-ingress-operator/pkg/operator/controller"
1819 util "github.com/openshift/cluster-ingress-operator/pkg/util"
20+ "github.com/stretchr/testify/assert"
21+ "github.com/stretchr/testify/require"
22+ condutils "k8s.io/apimachinery/pkg/api/meta"
1923
2024 corev1 "k8s.io/api/core/v1"
2125 apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
@@ -101,6 +105,7 @@ func TestGatewayAPI(t *testing.T) {
101105 t .Run ("testGatewayAPIDNS" , testGatewayAPIDNS )
102106 t .Run ("testGatewayAPIDNSListenerUpdate" , testGatewayAPIDNSListenerUpdate )
103107 t .Run ("testGatewayAPIDNSListenerWithNoHostname" , testGatewayAPIDNSListenerWithNoHostname )
108+ t .Run ("testGatewayOpenshiftConditions" , testGatewayOpenshiftConditions )
104109
105110 } else {
106111 t .Log ("Gateway API Controller not enabled, skipping controller tests" )
@@ -587,6 +592,179 @@ func testGatewayAPIDNS(t *testing.T) {
587592 }
588593 })
589594 }
595+ }
596+
597+ // This e2e test will verify the following scenarios:
598+ // 1 - Creating a gateway with the right base domain but outside of `openshift-ingress`
599+ // namespace will not generate a DNSRecord nor add conditions to the gateway
600+ // 2 - Creating a Gateway on `openshift-ingress` namespace using the wrong base
601+ // domain should add DNS conditions that there are no managed zones for this case
602+ // 3 - Creating a Gateway with the right base domain on `openshift-ingress` will
603+ // add the conditions on the gateway reflecting the right status of LoadBalancer and DNSRecord
604+ // 4 - Bumping some label on the Gateway should trigger a reconciliation that will
605+ // bump the generation of conditions
606+ // 5 - Adding a label on DNSRecord and/or Service will trigger a reconciliation
607+ // that should be verified by a newly recorded event
608+ func testGatewayOpenshiftConditions (t * testing.T ) {
609+ domain := "gwcondtest." + dnsConfig .Spec .BaseDomain
610+
611+ gatewayClass , err := createGatewayClass (t , operatorcontroller .OpenShiftDefaultGatewayClassName , operatorcontroller .OpenShiftGatewayClassControllerName )
612+ require .NoError (t , err , "failed to create gatewayclass" )
613+
614+ t .Run ("creating a new gateway outside of 'openshift-ingress' namespace should not get openshift conditions" , func (t * testing.T ) {
615+ rnd := rand .IntN (1000 )
616+ name := fmt .Sprintf ("gw-test-%d" , rnd )
617+ testDomain := fmt .Sprintf ("some-%d.%s" , rnd , domain )
618+ gateway , err := createGateway (gatewayClass , name , "default" , testDomain )
619+ require .NoError (t , err , "failed to create gateway" , "name" , name )
620+ t .Cleanup (func () {
621+ require .NoError (t , client .IgnoreNotFound (kclient .Delete (context .TODO (), gateway )), "failed to clean test gateway" , "name" , name )
622+ })
623+
624+ gateway , err = assertGatewaySuccessful (t , "default" , name )
625+ require .NoError (t , err , "failed waiting gateway to be ready" )
626+ // Give some time to guarantee our controller will watch the change but ignore it
627+ time .Sleep (time .Second )
628+
629+ // Get gateway a 2nd time ti check the conditions
630+ gateway , err = assertGatewaySuccessful (t , "default" , name )
631+ require .NoError (t , err , "failed waiting gateway to have conditions" )
632+ require .Nil (t , condutils .FindStatusCondition (gateway .Status .Conditions , "DNSManaged" ), "condition should not be present" )
633+ require .Nil (t , condutils .FindStatusCondition (gateway .Status .Conditions , "DNSReady" ), "condition should not be present" )
634+ require .Nil (t , condutils .FindStatusCondition (gateway .Status .Conditions , "LoadBalancerManaged" ), "condition should not be present" )
635+ require .Nil (t , condutils .FindStatusCondition (gateway .Status .Conditions , "LoadBalancerReady" ), "condition should not be present" )
636+ })
637+
638+ t .Run ("creating a new gateway with the wrong base domain should add openshift conditions reflecting the failure" , func (t * testing.T ) {
639+ rnd := rand .IntN (1000 )
640+ name := fmt .Sprintf ("gw-test-%d" , rnd )
641+ testDomain := fmt .Sprintf ("some-%d.not.something.managed.tld" , rnd )
642+ gateway , err := createGateway (gatewayClass , name , operatorcontroller .DefaultOperandNamespace , testDomain )
643+ require .NoError (t , err , "failed to create gateway" , "name" , name )
644+ t .Cleanup (func () {
645+ require .NoError (t , client .IgnoreNotFound (kclient .Delete (context .TODO (), gateway )), "failed to clean test gateway" , "name" , name )
646+ })
647+
648+ gateway , err = assertGatewaySuccessful (t , operatorcontroller .DefaultOperandNamespace , name )
649+ require .NoError (t , err , "failed waiting gateway to be ready" )
650+
651+ assert .Eventuallyf (t , func () bool {
652+ gw := & gatewayapiv1.Gateway {}
653+ nsName := types.NamespacedName {Namespace : operatorcontroller .DefaultOperandNamespace , Name : name }
654+ if err := kclient .Get (context .Background (), nsName , gw ); err != nil {
655+ t .Logf ("Failed to get gateway %v: %v; retrying..." , nsName , err )
656+ return false
657+ }
658+
659+ if condutils .IsStatusConditionTrue (gw .Status .Conditions , "DNSManaged" ) &&
660+ condutils .IsStatusConditionPresentAndEqual (gw .Status .Conditions , "DNSReady" , metav1 .ConditionUnknown ) &&
661+ condutils .IsStatusConditionTrue (gw .Status .Conditions , "LoadBalancerManaged" ) &&
662+ condutils .IsStatusConditionTrue (gw .Status .Conditions , "LoadBalancerReady" ) {
663+
664+ return true
665+ }
666+ t .Logf ("conditions are not yet the expected: %v, retrying..." , gw .Status .Conditions )
667+ return false
668+ }, 30 * time .Second , 2 * time .Second , "error waiting for openshift conditions to be present on Gateway" )
669+ })
670+
671+ t .Run ("creating a new gateway with the right base domain" , func (t * testing.T ) {
672+ rnd := rand .IntN (1000 )
673+ name := fmt .Sprintf ("gw-test-%d" , rnd )
674+ testDomain := fmt .Sprintf ("some-%d.%s" , rnd , domain )
675+ gateway , err := createGateway (gatewayClass , name , operatorcontroller .DefaultOperandNamespace , testDomain )
676+ require .NoError (t , err , "failed to create gateway" , "name" , name )
677+ t .Cleanup (func () {
678+ require .NoError (t , client .IgnoreNotFound (kclient .Delete (context .TODO (), gateway )), "failed to clean test gateway" , "name" , name )
679+ })
680+
681+ gateway , err = assertGatewaySuccessful (t , operatorcontroller .DefaultOperandNamespace , name )
682+ require .NoError (t , err , "failed waiting gateway to be ready" )
683+
684+ err = assertExpectedDNSRecords (t , map [expectedDnsRecord ]bool {
685+ {dnsName : "*." + testDomain + "." , gatewayName : name }: true })
686+
687+ assert .NoError (t , err , "dnsrecord never got ready" )
688+
689+ t .Run ("should add openshift conditions" , func (t * testing.T ) {
690+ assert .Eventuallyf (t , func () bool {
691+ gw := & gatewayapiv1.Gateway {}
692+ nsName := types.NamespacedName {Namespace : operatorcontroller .DefaultOperandNamespace , Name : name }
693+ if err := kclient .Get (context .Background (), nsName , gw ); err != nil {
694+ t .Logf ("Failed to get gateway %v: %v; retrying..." , nsName , err )
695+ return false
696+ }
697+
698+ if condutils .IsStatusConditionTrue (gw .Status .Conditions , "DNSManaged" ) &&
699+ condutils .IsStatusConditionTrue (gw .Status .Conditions , "DNSReady" ) &&
700+ condutils .IsStatusConditionTrue (gw .Status .Conditions , "LoadBalancerManaged" ) &&
701+ condutils .IsStatusConditionTrue (gw .Status .Conditions , "LoadBalancerReady" ) {
702+
703+ return true
704+ }
705+ t .Logf ("conditions are not yet the expected: %v, retrying..." , gw .Status .Conditions )
706+ return false
707+ }, 30 * time .Second , 2 * time .Second , "error waiting for openshift conditions to be present on Gateway" )
708+ })
709+
710+ t .Run ("should bump openshift conditions when the gateway is changed" , func (t * testing.T ) {
711+ // Try to add a new infrastructure label, forcing the generation to bump
712+ originalGateway := & gatewayapiv1.Gateway {}
713+ assert .Eventually (t , func () bool {
714+ gw := & gatewayapiv1.Gateway {}
715+ nsName := types.NamespacedName {Namespace : operatorcontroller .DefaultOperandNamespace , Name : name }
716+ if err := kclient .Get (context .Background (), nsName , gw ); err != nil {
717+ t .Logf ("Failed to get gateway %v: %v; retrying..." , nsName , err )
718+ return false
719+ }
720+ originalGateway = gw .DeepCopy ()
721+ if gw .Spec .Infrastructure == nil {
722+ gw .Spec .Infrastructure = & gatewayapiv1.GatewayInfrastructure {}
723+ }
724+ if gw .Spec .Infrastructure .Labels == nil {
725+ gw .Spec .Infrastructure .Labels = make (map [gatewayapiv1.LabelKey ]gatewayapiv1.LabelValue )
726+ }
727+
728+ gw .Spec .Infrastructure .Labels ["something" ] = "somelabel"
729+
730+ if err := kclient .Patch (context .Background (), gw , client .MergeFrom (originalGateway )); err != nil {
731+ t .Logf ("failed to patch gateway %v: %v; retrying..." , nsName , err )
732+ return false
733+ }
734+ return true
735+ }, 30 * time .Second , 2 * time .Second , "timeout waiting to patch the gateway" )
736+
737+ gw := & gatewayapiv1.Gateway {}
738+ // Get the Gateway and check if conditions are there, and if their generation are different from the originalGateway value
739+ assert .Eventually (t , func () bool {
740+ nsName := types.NamespacedName {Namespace : operatorcontroller .DefaultOperandNamespace , Name : name }
741+ if err := kclient .Get (context .Background (), nsName , gw ); err != nil {
742+ t .Logf ("Failed to get gateway %v: %v; retrying..." , nsName , err )
743+ return false
744+ }
745+
746+ dnsManaged := condutils .FindStatusCondition (gw .Status .Conditions , "DNSManaged" )
747+ dnsReady := condutils .FindStatusCondition (gw .Status .Conditions , "DNSReady" )
748+ loadBalancerManaged := condutils .FindStatusCondition (gw .Status .Conditions , "LoadBalancerManaged" )
749+ loadBalancerReady := condutils .FindStatusCondition (gw .Status .Conditions , "LoadBalancerReady" )
750+
751+ // Check if all conditions are not null and have a different generation from the original one
752+ // before adding the label
753+ if (dnsManaged != nil && dnsManaged .ObservedGeneration != originalGateway .Generation ) &&
754+ (dnsReady != nil && dnsReady .ObservedGeneration != originalGateway .Generation ) &&
755+ (loadBalancerManaged != nil && loadBalancerManaged .ObservedGeneration != originalGateway .Generation ) &&
756+ (loadBalancerReady != nil && loadBalancerReady .ObservedGeneration != originalGateway .Generation ) {
757+ return true
758+ }
759+
760+ t .Logf ("conditions are not yet the expected: %v, retrying..." , gw .Status .Conditions )
761+ return false
762+ }, 30 * time .Second , 2 * time .Second , "error waiting for openshift conditions to be present on Gateway" )
763+ // We expect exactly 6 conditions. If we get more than it, Istio is adding
764+ // more conditions and we need to be aware that Gateway API status.conditons has a maxItems of 8
765+ assert .Len (t , gw .Status .Conditions , 6 )
766+ })
767+ })
590768
591769}
592770
0 commit comments