@@ -535,3 +535,72 @@ func (s) TestServer_MismatchedAddressListenerReceivedOnServer(t *testing.T) {
535535 defer cc .Close ()
536536 waitForSuccessfulRPC (ctx , t , cc )
537537}
538+
539+ // Tests the case where the server receives a listener resource with a wildcard
540+ // port. The server should match the listener address and transition to Serving
541+ // mode regardless of the port on which it is listening.
542+ func (s ) TestServer_ListenerMatchWithWildcardPort (t * testing.T ) {
543+ ctx , cancel := context .WithTimeout (context .Background (), defaultTestTimeout )
544+ defer cancel ()
545+ managementServer := e2e .StartManagementServer (t , e2e.ManagementServerOptions {AllowResourceSubset : true })
546+
547+ // Create bootstrap configuration pointing to the above management server.
548+ nodeID := uuid .New ().String ()
549+ bootstrapContents := e2e .DefaultBootstrapContents (t , nodeID , managementServer .Address )
550+
551+ // Create a listener on a local port to act as the xDS enabled gRPC server.
552+ lis , err := testutils .LocalTCPListener ()
553+ if err != nil {
554+ t .Fatalf ("testutils.LocalTCPListener() failed: %v" , err )
555+ }
556+ host , port , err := hostPortFromListener (lis )
557+ if err != nil {
558+ t .Fatalf ("Failed to retrieve host and port of server: %v" , err )
559+ }
560+
561+ // Configure a server-side listener with a wildcard port on the management
562+ // server. Construct the listener with the actual port first so its resource
563+ // name matches the server's default watch name, then replace only the port
564+ // value in the socket address with zero.
565+ listener := e2e .DefaultServerListener (host , port , e2e .SecurityLevelNone , "routeName" )
566+ listener .Address .GetSocketAddress ().PortSpecifier = & v3corepb.SocketAddress_PortValue {
567+ PortValue : 0 ,
568+ }
569+ resources := e2e.UpdateOptions {
570+ NodeID : nodeID ,
571+ Listeners : []* v3listenerpb.Listener {listener },
572+ SkipValidation : true ,
573+ }
574+ if err := managementServer .Update (ctx , resources ); err != nil {
575+ t .Fatal (err )
576+ }
577+
578+ // Start an xDS-enabled gRPC server with the above bootstrap configuration.
579+ config , err := bootstrap .NewConfigFromContents (bootstrapContents )
580+ if err != nil {
581+ t .Fatalf ("Failed to parse bootstrap contents: %s, %v" , string (bootstrapContents ), err )
582+ }
583+ pool := xdsclient .NewPool (config )
584+ modeChangeHandler := newServingModeChangeHandler (t )
585+ modeChangeOpt := xds .ServingModeCallback (modeChangeHandler .modeChangeCallback )
586+ createStubServer (t , lis , modeChangeOpt , xds .ClientPoolForTesting (pool ))
587+
588+ // Ensure the server transitions to SERVING mode despite the wildcard port.
589+ select {
590+ case <- ctx .Done ():
591+ t .Fatal ("Timeout waiting for the xDS-enabled gRPC server to go SERVING" )
592+ case gotMode := <- modeChangeHandler .modeCh :
593+ if gotMode != connectivity .ServingModeServing {
594+ t .Fatalf ("Mode changed to %v, want %v" , gotMode , connectivity .ServingModeServing )
595+ }
596+ }
597+
598+ // Create a gRPC client to the server and verify that we can make a
599+ // successful RPC.
600+ cc , err := grpc .NewClient (lis .Addr ().String (), grpc .WithTransportCredentials (insecure .NewCredentials ()))
601+ if err != nil {
602+ t .Fatalf ("Failed to dial local test server: %v" , err )
603+ }
604+ defer cc .Close ()
605+ waitForSuccessfulRPC (ctx , t , cc )
606+ }
0 commit comments