google.golang.org/grpc@v1.72.2/xds/server_test.go (about) 1 /* 2 * 3 * Copyright 2020 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19 package xds 20 21 import ( 22 "context" 23 "encoding/json" 24 "errors" 25 "fmt" 26 "net" 27 "reflect" 28 "strconv" 29 "strings" 30 "sync" 31 "testing" 32 "time" 33 34 "github.com/google/go-cmp/cmp" 35 "github.com/google/uuid" 36 "google.golang.org/grpc" 37 "google.golang.org/grpc/connectivity" 38 "google.golang.org/grpc/credentials/insecure" 39 "google.golang.org/grpc/credentials/tls/certprovider" 40 "google.golang.org/grpc/credentials/xds" 41 "google.golang.org/grpc/internal/grpctest" 42 "google.golang.org/grpc/internal/testutils" 43 "google.golang.org/grpc/internal/testutils/xds/e2e" 44 "google.golang.org/grpc/internal/xds/bootstrap" 45 "google.golang.org/grpc/xds/internal/xdsclient" 46 "google.golang.org/grpc/xds/internal/xdsclient/xdsresource/version" 47 48 v3listenerpb "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3" 49 v3discoverypb "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3" 50 51 _ "google.golang.org/grpc/xds/internal/httpfilter/router" // Register the router filter 52 ) 53 54 const ( 55 defaultTestTimeout = 5 * time.Second 56 defaultTestShortTimeout = 10 * time.Millisecond 57 nonExistentManagementServer = "non-existent-management-server" 58 ) 59 60 type s struct { 61 grpctest.Tester 62 } 63 64 func Test(t *testing.T) { 65 grpctest.RunSubTests(t, s{}) 66 } 67 68 type fakeGRPCServer struct { 69 done chan struct{} 70 registerServiceCh *testutils.Channel 71 serveCh *testutils.Channel 72 } 73 74 func (f *fakeGRPCServer) RegisterService(*grpc.ServiceDesc, any) { 75 f.registerServiceCh.Send(nil) 76 } 77 78 func (f *fakeGRPCServer) Serve(lis net.Listener) error { 79 f.serveCh.Send(nil) 80 <-f.done 81 lis.Close() 82 return nil 83 } 84 85 func (f *fakeGRPCServer) Stop() { 86 close(f.done) 87 } 88 func (f *fakeGRPCServer) GracefulStop() { 89 close(f.done) 90 } 91 92 func (f *fakeGRPCServer) GetServiceInfo() map[string]grpc.ServiceInfo { 93 panic("implement me") 94 } 95 96 func newFakeGRPCServer() *fakeGRPCServer { 97 return &fakeGRPCServer{ 98 done: make(chan struct{}), 99 registerServiceCh: testutils.NewChannel(), 100 serveCh: testutils.NewChannel(), 101 } 102 } 103 104 func generateBootstrapContents(t *testing.T, nodeID, serverURI string) []byte { 105 bs := e2e.DefaultBootstrapContents(t, nodeID, serverURI) 106 return bs 107 } 108 109 func (s) TestNewServer_Success(t *testing.T) { 110 xdsCreds, err := xds.NewServerCredentials(xds.ServerOptions{FallbackCreds: insecure.NewCredentials()}) 111 if err != nil { 112 t.Fatalf("failed to create xds server credentials: %v", err) 113 } 114 115 tests := []struct { 116 desc string 117 serverOpts []grpc.ServerOption 118 wantXDSCredsInUse bool 119 }{ 120 { 121 desc: "without_xds_creds", 122 serverOpts: []grpc.ServerOption{ 123 grpc.Creds(insecure.NewCredentials()), 124 BootstrapContentsForTesting(generateBootstrapContents(t, uuid.NewString(), nonExistentManagementServer)), 125 }, 126 }, 127 { 128 desc: "with_xds_creds", 129 serverOpts: []grpc.ServerOption{ 130 grpc.Creds(xdsCreds), 131 BootstrapContentsForTesting(generateBootstrapContents(t, uuid.NewString(), nonExistentManagementServer)), 132 }, 133 wantXDSCredsInUse: true, 134 }, 135 } 136 137 for _, test := range tests { 138 t.Run(test.desc, func(t *testing.T) { 139 // The xds package adds a couple of server options (unary and stream 140 // interceptors) to the server options passed in by the user. 141 wantServerOpts := len(test.serverOpts) + 2 142 143 origNewGRPCServer := newGRPCServer 144 newGRPCServer = func(opts ...grpc.ServerOption) grpcServer { 145 if got := len(opts); got != wantServerOpts { 146 t.Fatalf("%d ServerOptions passed to grpc.Server, want %d", got, wantServerOpts) 147 } 148 // Verify that the user passed ServerOptions are forwarded as is. 149 if !reflect.DeepEqual(opts[2:], test.serverOpts) { 150 t.Fatalf("got ServerOptions %v, want %v", opts[2:], test.serverOpts) 151 } 152 return grpc.NewServer(opts...) 153 } 154 defer func() { 155 newGRPCServer = origNewGRPCServer 156 }() 157 158 s, err := NewGRPCServer(test.serverOpts...) 159 if err != nil { 160 t.Fatalf("Failed to create an xDS enabled gRPC server: %v", err) 161 } 162 defer s.Stop() 163 }) 164 } 165 } 166 167 func (s) TestNewServer_Failure(t *testing.T) { 168 xdsCreds, err := xds.NewServerCredentials(xds.ServerOptions{FallbackCreds: insecure.NewCredentials()}) 169 if err != nil { 170 t.Fatalf("failed to create xds server credentials: %v", err) 171 } 172 173 tests := []struct { 174 desc string 175 serverOpts []grpc.ServerOption 176 wantErr string 177 }{ 178 { 179 desc: "bootstrap env var not set", 180 serverOpts: []grpc.ServerOption{grpc.Creds(xdsCreds), BootstrapContentsForTesting(nil)}, 181 wantErr: "failed to read xDS bootstrap config from env vars", 182 }, 183 { 184 desc: "empty bootstrap config", 185 serverOpts: []grpc.ServerOption{ 186 grpc.Creds(xdsCreds), 187 BootstrapContentsForTesting(nil), 188 }, 189 wantErr: "xDS client creation failed", 190 }, 191 { 192 desc: "server_listener_resource_name_template is missing", 193 serverOpts: []grpc.ServerOption{ 194 grpc.Creds(xdsCreds), 195 func() grpc.ServerOption { 196 bs, err := bootstrap.NewContentsForTesting(bootstrap.ConfigOptionsForTesting{ 197 Servers: []byte(fmt.Sprintf(`[{ 198 "server_uri": %q, 199 "channel_creds": [{"type": "insecure"}] 200 }]`, nonExistentManagementServer)), 201 Node: []byte(fmt.Sprintf(`{"id": "%s"}`, uuid.New().String())), 202 CertificateProviders: map[string]json.RawMessage{ 203 "cert-provider-instance": json.RawMessage("{}"), 204 }, 205 }) 206 if err != nil { 207 t.Fatalf("Failed to create bootstrap configuration: %v", err) 208 } 209 return BootstrapContentsForTesting(bs) 210 }(), 211 }, 212 wantErr: "missing server_listener_resource_name_template in the bootstrap configuration", 213 }, 214 } 215 216 for _, test := range tests { 217 t.Run(test.desc, func(t *testing.T) { 218 s, err := NewGRPCServer(test.serverOpts...) 219 if err == nil { 220 s.Stop() 221 t.Fatal("NewGRPCServer() succeeded when expected to fail") 222 } 223 if !strings.Contains(err.Error(), test.wantErr) { 224 t.Fatalf("NewGRPCServer() failed with error: %v, want: %s", err, test.wantErr) 225 } 226 }) 227 } 228 } 229 230 func (s) TestRegisterService(t *testing.T) { 231 fs := newFakeGRPCServer() 232 233 origNewGRPCServer := newGRPCServer 234 newGRPCServer = func(...grpc.ServerOption) grpcServer { return fs } 235 defer func() { newGRPCServer = origNewGRPCServer }() 236 237 s, err := NewGRPCServer(BootstrapContentsForTesting(generateBootstrapContents(t, uuid.NewString(), "non-existent-management-server"))) 238 if err != nil { 239 t.Fatalf("Failed to create an xDS enabled gRPC server: %v", err) 240 } 241 defer s.Stop() 242 243 s.RegisterService(&grpc.ServiceDesc{}, nil) 244 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 245 defer cancel() 246 if _, err := fs.registerServiceCh.Receive(ctx); err != nil { 247 t.Fatalf("Timeout when expecting RegisterService() to called on grpc.Server: %v", err) 248 } 249 } 250 251 const ( 252 fakeProvider1Name = "fake-certificate-provider-1" 253 fakeProvider2Name = "fake-certificate-provider-2" 254 ) 255 256 var ( 257 fpb1, fpb2 *fakeProviderBuilder 258 fakeProvider1Config json.RawMessage 259 fakeProvider2Config json.RawMessage 260 ) 261 262 func init() { 263 fpb1 = &fakeProviderBuilder{ 264 name: fakeProvider1Name, 265 buildCh: testutils.NewChannel(), 266 } 267 fpb2 = &fakeProviderBuilder{ 268 name: fakeProvider2Name, 269 buildCh: testutils.NewChannel(), 270 } 271 certprovider.Register(fpb1) 272 certprovider.Register(fpb2) 273 274 fakeProvider1Config = json.RawMessage(fmt.Sprintf(`{ 275 "plugin_name": "%s", 276 "config": "my fake config 1" 277 }`, fakeProvider1Name)) 278 fakeProvider2Config = json.RawMessage(fmt.Sprintf(`{ 279 "plugin_name": "%s", 280 "config": "my fake config 2" 281 }`, fakeProvider2Name)) 282 } 283 284 // fakeProviderBuilder builds new instances of fakeProvider and interprets the 285 // config provided to it as a string. 286 type fakeProviderBuilder struct { 287 name string 288 buildCh *testutils.Channel 289 } 290 291 func (b *fakeProviderBuilder) ParseConfig(cfg any) (*certprovider.BuildableConfig, error) { 292 var config string 293 if err := json.Unmarshal(cfg.(json.RawMessage), &config); err != nil { 294 return nil, fmt.Errorf("providerBuilder %s failed to unmarshal config: %v", b.name, cfg) 295 } 296 return certprovider.NewBuildableConfig(b.name, []byte(config), func(certprovider.BuildOptions) certprovider.Provider { 297 b.buildCh.Send(nil) 298 return &fakeProvider{ 299 Distributor: certprovider.NewDistributor(), 300 config: config, 301 } 302 }), nil 303 } 304 305 func (b *fakeProviderBuilder) Name() string { 306 return b.name 307 } 308 309 // fakeProvider is an implementation of the Provider interface which provides a 310 // method for tests to invoke to push new key materials. 311 type fakeProvider struct { 312 *certprovider.Distributor 313 config string 314 } 315 316 // Close helps implement the Provider interface. 317 func (p *fakeProvider) Close() { 318 p.Distributor.Stop() 319 } 320 321 func verifyCertProviderNotCreated() error { 322 sCtx, sCancel := context.WithTimeout(context.Background(), defaultTestShortTimeout) 323 defer sCancel() 324 if _, err := fpb1.buildCh.Receive(sCtx); err != context.DeadlineExceeded { 325 return errors.New("certificate provider created when no xDS creds were specified") 326 } 327 sCtx, sCancel = context.WithTimeout(context.Background(), defaultTestShortTimeout) 328 defer sCancel() 329 if _, err := fpb2.buildCh.Receive(sCtx); err != context.DeadlineExceeded { 330 return errors.New("certificate provider created when no xDS creds were specified") 331 } 332 return nil 333 } 334 335 func hostPortFromListener(t *testing.T, lis net.Listener) (string, uint32) { 336 t.Helper() 337 338 host, p, err := net.SplitHostPort(lis.Addr().String()) 339 if err != nil { 340 t.Fatalf("net.SplitHostPort(%s) failed: %v", lis.Addr().String(), err) 341 } 342 port, err := strconv.ParseInt(p, 10, 32) 343 if err != nil { 344 t.Fatalf("strconv.ParseInt(%s, 10, 32) failed: %v", p, err) 345 } 346 return host, uint32(port) 347 } 348 349 // TestServeSuccess tests the successful case of creating an xDS enabled gRPC 350 // server and calling Serve() on it. The test verifies that an LDS request is 351 // sent out for the expected name, and also verifies that the serving mode 352 // changes appropriately. 353 func (s) TestServeSuccess(t *testing.T) { 354 // Setup an xDS management server that pushes on a channel when an LDS 355 // request is received by it. 356 ldsRequestCh := make(chan []string, 1) 357 mgmtServer := e2e.StartManagementServer(t, e2e.ManagementServerOptions{ 358 OnStreamRequest: func(_ int64, req *v3discoverypb.DiscoveryRequest) error { 359 if req.GetTypeUrl() == version.V3ListenerURL { 360 select { 361 case ldsRequestCh <- req.GetResourceNames(): 362 default: 363 } 364 } 365 return nil 366 }, 367 }) 368 369 // Create bootstrap configuration pointing to the above management server. 370 nodeID := uuid.New().String() 371 bootstrapContents := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address) 372 373 // Override the function to create the underlying grpc.Server to allow the 374 // test to verify that Serve() is called on the underlying server. 375 fs := newFakeGRPCServer() 376 origNewGRPCServer := newGRPCServer 377 newGRPCServer = func(...grpc.ServerOption) grpcServer { return fs } 378 defer func() { newGRPCServer = origNewGRPCServer }() 379 380 // Create a new xDS enabled gRPC server and pass it a server option to get 381 // notified about serving mode changes. 382 modeChangeCh := testutils.NewChannel() 383 modeChangeOption := ServingModeCallback(func(addr net.Addr, args ServingModeChangeArgs) { 384 t.Logf("Server mode change callback invoked for listener %q with mode %q and error %v", addr.String(), args.Mode, args.Err) 385 modeChangeCh.Send(args.Mode) 386 }) 387 server, err := NewGRPCServer(modeChangeOption, BootstrapContentsForTesting(bootstrapContents)) 388 if err != nil { 389 t.Fatalf("Failed to create an xDS enabled gRPC server: %v", err) 390 } 391 defer server.Stop() 392 393 // Call Serve() in a goroutine. 394 lis, err := testutils.LocalTCPListener() 395 if err != nil { 396 t.Fatalf("testutils.LocalTCPListener() failed: %v", err) 397 } 398 go func() { 399 if err := server.Serve(lis); err != nil { 400 t.Error(err) 401 } 402 }() 403 404 // Ensure that the LDS request is sent out for the expected name. 405 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 406 defer cancel() 407 var gotNames []string 408 select { 409 case gotNames = <-ldsRequestCh: 410 case <-ctx.Done(): 411 t.Fatalf("Timeout when waiting for an LDS request to be sent out") 412 } 413 wantNames := []string{strings.ReplaceAll(e2e.ServerListenerResourceNameTemplate, "%s", lis.Addr().String())} 414 if !cmp.Equal(gotNames, wantNames) { 415 t.Fatalf("LDS watch registered for names %v, want %v", gotNames, wantNames) 416 } 417 418 // Update the management server with a good listener resource. 419 host, port := hostPortFromListener(t, lis) 420 resources := e2e.UpdateOptions{ 421 NodeID: nodeID, 422 Listeners: []*v3listenerpb.Listener{e2e.DefaultServerListener(host, port, e2e.SecurityLevelNone, "routeName")}, 423 } 424 if err := mgmtServer.Update(ctx, resources); err != nil { 425 t.Fatal(err) 426 } 427 428 // Verify the serving mode reports SERVING. 429 v, err := modeChangeCh.Receive(ctx) 430 if err != nil { 431 t.Fatalf("Timeout when waiting for serving mode to change: %v", err) 432 } 433 if mode := v.(connectivity.ServingMode); mode != connectivity.ServingModeServing { 434 t.Fatalf("Serving mode is %q, want %q", mode, connectivity.ServingModeServing) 435 } 436 437 // Verify that Serve() is called on the underlying gRPC server. 438 if _, err := fs.serveCh.Receive(ctx); err != nil { 439 t.Fatalf("Timeout when waiting for Serve() to be invoked on the grpc.Server") 440 } 441 442 // Update the listener resource on the management server in such a way that 443 // it will be NACKed by our xDS client. The listener_filters field is 444 // unsupported and will be NACKed. 445 resources.Listeners[0].ListenerFilters = []*v3listenerpb.ListenerFilter{{Name: "foo"}} 446 if err := mgmtServer.Update(ctx, resources); err != nil { 447 t.Fatal(err) 448 } 449 450 // Verify that there is no change in the serving mode. The server should 451 // continue using the previously received good configuration. 452 sCtx, sCancel := context.WithTimeout(context.Background(), defaultTestShortTimeout) 453 defer sCancel() 454 if v, err := modeChangeCh.Receive(sCtx); err != context.DeadlineExceeded { 455 t.Fatalf("Unexpected change in serving mode. New mode is %v", v.(connectivity.ServingMode)) 456 } 457 458 // Remove the listener resource from the management server. This should 459 // result in a resource-not-found error from the xDS client and should 460 // result in the server moving to NOT_SERVING mode. 461 resources.Listeners = nil 462 if err := mgmtServer.Update(ctx, resources); err != nil { 463 t.Fatal(err) 464 } 465 v, err = modeChangeCh.Receive(ctx) 466 if err != nil { 467 t.Fatalf("Timeout when waiting for serving mode to change: %v", err) 468 } 469 if mode := v.(connectivity.ServingMode); mode != connectivity.ServingModeNotServing { 470 t.Fatalf("Serving mode is %q, want %q", mode, connectivity.ServingModeNotServing) 471 } 472 } 473 474 // TestNewServer_ClientCreationFailure tests the case where the xDS client 475 // creation fails and verifies that the call to NewGRPCServer() fails. 476 func (s) TestNewServer_ClientCreationFailure(t *testing.T) { 477 origXDSClientPool := xdsClientPool 478 xdsClientPool = xdsclient.NewPool(nil) 479 defer func() { xdsClientPool = origXDSClientPool }() 480 481 if _, err := NewGRPCServer(); err == nil { 482 t.Fatal("NewGRPCServer() succeeded when expected to fail") 483 } 484 } 485 486 // TestHandleListenerUpdate_NoXDSCreds tests the case where an xds-enabled gRPC 487 // server is not configured with xDS credentials. Verifies that the security 488 // config received as part of a Listener update is not acted upon. 489 func (s) TestHandleListenerUpdate_NoXDSCreds(t *testing.T) { 490 mgmtServer := e2e.StartManagementServer(t, e2e.ManagementServerOptions{}) 491 492 // Generate bootstrap configuration pointing to the above management server 493 // with certificate provider configuration pointing to fake certificate 494 // providers. 495 nodeID := uuid.NewString() 496 bootstrapContents, err := bootstrap.NewContentsForTesting(bootstrap.ConfigOptionsForTesting{ 497 Servers: []byte(fmt.Sprintf(`[{ 498 "server_uri": %q, 499 "channel_creds": [{"type": "insecure"}] 500 }]`, mgmtServer.Address)), 501 Node: []byte(fmt.Sprintf(`{"id": "%s"}`, nodeID)), 502 CertificateProviders: map[string]json.RawMessage{ 503 e2e.ServerSideCertProviderInstance: fakeProvider1Config, 504 e2e.ClientSideCertProviderInstance: fakeProvider2Config, 505 }, 506 ServerListenerResourceNameTemplate: e2e.ServerListenerResourceNameTemplate, 507 }) 508 if err != nil { 509 t.Fatalf("Failed to create bootstrap configuration: %v", err) 510 } 511 512 // Create a new xDS enabled gRPC server and pass it a server option to get 513 // notified about serving mode changes. Also pass the above bootstrap 514 // configuration to be used during xDS client creation. 515 modeChangeCh := testutils.NewChannel() 516 modeChangeOption := ServingModeCallback(func(addr net.Addr, args ServingModeChangeArgs) { 517 t.Logf("Server mode change callback invoked for listener %q with mode %q and error %v", addr.String(), args.Mode, args.Err) 518 modeChangeCh.Send(args.Mode) 519 }) 520 server, err := NewGRPCServer(modeChangeOption, BootstrapContentsForTesting(bootstrapContents)) 521 if err != nil { 522 t.Fatalf("Failed to create an xDS enabled gRPC server: %v", err) 523 } 524 defer server.Stop() 525 526 // Call Serve() in a goroutine. 527 lis, err := testutils.LocalTCPListener() 528 if err != nil { 529 t.Fatalf("testutils.LocalTCPListener() failed: %v", err) 530 } 531 go func() { 532 if err := server.Serve(lis); err != nil { 533 t.Error(err) 534 } 535 }() 536 537 // Update the management server with a good listener resource that contains 538 // security configuration. 539 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 540 defer cancel() 541 host, port := hostPortFromListener(t, lis) 542 resources := e2e.UpdateOptions{ 543 NodeID: nodeID, 544 Listeners: []*v3listenerpb.Listener{e2e.DefaultServerListener(host, port, e2e.SecurityLevelMTLS, "routeName")}, 545 } 546 if err := mgmtServer.Update(ctx, resources); err != nil { 547 t.Fatal(err) 548 } 549 550 // Verify the serving mode reports SERVING. 551 v, err := modeChangeCh.Receive(ctx) 552 if err != nil { 553 t.Fatalf("Timeout when waiting for serving mode to change: %v", err) 554 } 555 if mode := v.(connectivity.ServingMode); mode != connectivity.ServingModeServing { 556 t.Fatalf("Serving mode is %q, want %q", mode, connectivity.ServingModeServing) 557 } 558 559 // Make sure the security configuration is not acted upon. 560 if err := verifyCertProviderNotCreated(); err != nil { 561 t.Fatal(err) 562 } 563 } 564 565 // TestHandleListenerUpdate_ErrorUpdate tests the case where an xds-enabled gRPC 566 // server is configured with xDS credentials, but receives a Listener update 567 // with an error. Verifies that no certificate providers are created. 568 func (s) TestHandleListenerUpdate_ErrorUpdate(t *testing.T) { 569 // Setup an xDS management server that pushes on a channel when an LDS 570 // request is received by it. 571 ldsRequestCh := make(chan []string, 1) 572 mgmtServer := e2e.StartManagementServer(t, e2e.ManagementServerOptions{ 573 OnStreamRequest: func(_ int64, req *v3discoverypb.DiscoveryRequest) error { 574 if req.GetTypeUrl() == version.V3ListenerURL { 575 select { 576 case ldsRequestCh <- req.GetResourceNames(): 577 default: 578 } 579 } 580 return nil 581 }, 582 }) 583 584 // Generate bootstrap configuration pointing to the above management server 585 // with certificate provider configuration pointing to fake certificate 586 // providers. 587 nodeID := uuid.New().String() 588 bootstrapContents, err := bootstrap.NewContentsForTesting(bootstrap.ConfigOptionsForTesting{ 589 Servers: []byte(fmt.Sprintf(`[{ 590 "server_uri": %q, 591 "channel_creds": [{"type": "insecure"}] 592 }]`, mgmtServer.Address)), 593 Node: []byte(fmt.Sprintf(`{"id": "%s"}`, nodeID)), 594 CertificateProviders: map[string]json.RawMessage{ 595 e2e.ServerSideCertProviderInstance: fakeProvider1Config, 596 e2e.ClientSideCertProviderInstance: fakeProvider2Config, 597 }, 598 ServerListenerResourceNameTemplate: e2e.ServerListenerResourceNameTemplate, 599 }) 600 if err != nil { 601 t.Fatalf("Failed to create bootstrap configuration: %v", err) 602 } 603 604 // Create a new xDS enabled gRPC server and pass it a server option to get 605 // notified about serving mode changes. Also pass the above bootstrap 606 // configuration to be used during xDS client creation. 607 modeChangeCh := testutils.NewChannel() 608 modeChangeOption := ServingModeCallback(func(addr net.Addr, args ServingModeChangeArgs) { 609 t.Logf("Server mode change callback invoked for listener %q with mode %q and error %v", addr.String(), args.Mode, args.Err) 610 modeChangeCh.Send(args.Mode) 611 }) 612 server, err := NewGRPCServer(modeChangeOption, BootstrapContentsForTesting(bootstrapContents)) 613 if err != nil { 614 t.Fatalf("Failed to create an xDS enabled gRPC server: %v", err) 615 } 616 defer server.Stop() 617 618 // Call Serve() in a goroutine. 619 lis, err := testutils.LocalTCPListener() 620 if err != nil { 621 t.Fatalf("testutils.LocalTCPListener() failed: %v", err) 622 } 623 go server.Serve(lis) 624 625 // Update the listener resource on the management server in such a way that 626 // it will be NACKed by our xDS client. The listener_filters field is 627 // unsupported and will be NACKed. 628 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 629 defer cancel() 630 host, port := hostPortFromListener(t, lis) 631 listener := e2e.DefaultServerListener(host, port, e2e.SecurityLevelMTLS, "routeName") 632 listener.ListenerFilters = []*v3listenerpb.ListenerFilter{{Name: "foo"}} 633 resources := e2e.UpdateOptions{ 634 NodeID: nodeID, 635 Listeners: []*v3listenerpb.Listener{listener}, 636 } 637 if err := mgmtServer.Update(ctx, resources); err != nil { 638 t.Fatal(err) 639 } 640 641 // Ensure that the LDS request is sent out for the expected name. 642 var gotNames []string 643 select { 644 case gotNames = <-ldsRequestCh: 645 case <-ctx.Done(): 646 t.Fatalf("Timeout when waiting for an LDS request to be sent out") 647 } 648 wantNames := []string{strings.ReplaceAll(e2e.ServerListenerResourceNameTemplate, "%s", lis.Addr().String())} 649 if !cmp.Equal(gotNames, wantNames) { 650 t.Fatalf("LDS watch registered for names %v, want %v", gotNames, wantNames) 651 } 652 653 // Make sure that no certificate providers are created. 654 if err := verifyCertProviderNotCreated(); err != nil { 655 t.Fatal(err) 656 } 657 658 // Also make sure that no serving mode updates are received. The serving 659 // mode does not change until the server comes to the conclusion that the 660 // requested resource is not present in the management server. This happens 661 // when the watch timer expires or when the resource is explicitly deleted 662 // by the management server. 663 sCtx, sCancel := context.WithTimeout(context.Background(), defaultTestShortTimeout) 664 defer sCancel() 665 if _, err := modeChangeCh.Receive(sCtx); err != context.DeadlineExceeded { 666 t.Fatal("Serving mode changed received when none expected") 667 } 668 } 669 670 // TestServeReturnsErrorAfterClose tests that the xds Server returns 671 // grpc.ErrServerStopped if Serve is called after Close on the server. 672 func (s) TestServeReturnsErrorAfterClose(t *testing.T) { 673 server, err := NewGRPCServer(BootstrapContentsForTesting(generateBootstrapContents(t, uuid.NewString(), nonExistentManagementServer))) 674 if err != nil { 675 t.Fatalf("Failed to create an xDS enabled gRPC server: %v", err) 676 } 677 678 lis, err := testutils.LocalTCPListener() 679 if err != nil { 680 t.Fatalf("testutils.LocalTCPListener() failed: %v", err) 681 } 682 server.Stop() 683 err = server.Serve(lis) 684 if err == nil || !strings.Contains(err.Error(), grpc.ErrServerStopped.Error()) { 685 t.Fatalf("server erorred with wrong error, want: %v, got :%v", grpc.ErrServerStopped, err) 686 } 687 } 688 689 // TestServeAndCloseDoNotRace tests that Serve and Close on the xDS Server do 690 // not race and leak the xDS Client. A leak would be found by the leak checker. 691 func (s) TestServeAndCloseDoNotRace(t *testing.T) { 692 lis, err := testutils.LocalTCPListener() 693 if err != nil { 694 t.Fatalf("testutils.LocalTCPListener() failed: %v", err) 695 } 696 697 // Generate bootstrap contents up front for all servers. 698 bootstrapContents := generateBootstrapContents(t, uuid.NewString(), nonExistentManagementServer) 699 700 wg := sync.WaitGroup{} 701 wg.Add(200) 702 for i := 0; i < 100; i++ { 703 server, err := NewGRPCServer(BootstrapContentsForTesting(bootstrapContents)) 704 if err != nil { 705 t.Fatalf("Failed to create an xDS enabled gRPC server: %v", err) 706 } 707 go func() { 708 server.Serve(lis) 709 wg.Done() 710 }() 711 go func() { 712 server.Stop() 713 wg.Done() 714 }() 715 } 716 wg.Wait() 717 }