google.golang.org/grpc@v1.74.2/test/xds/xds_server_integration_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_test
    20  
    21  import (
    22  	"context"
    23  	"fmt"
    24  	"io"
    25  	"net"
    26  	"strconv"
    27  	"testing"
    28  	"time"
    29  
    30  	"github.com/google/uuid"
    31  	"google.golang.org/grpc"
    32  	"google.golang.org/grpc/codes"
    33  	"google.golang.org/grpc/credentials"
    34  	"google.golang.org/grpc/credentials/insecure"
    35  	xdscreds "google.golang.org/grpc/credentials/xds"
    36  	"google.golang.org/grpc/internal"
    37  	"google.golang.org/grpc/internal/grpcsync"
    38  	"google.golang.org/grpc/internal/stubserver"
    39  	"google.golang.org/grpc/internal/testutils"
    40  	"google.golang.org/grpc/internal/testutils/xds/e2e"
    41  	"google.golang.org/grpc/internal/testutils/xds/e2e/setup"
    42  	"google.golang.org/grpc/peer"
    43  	"google.golang.org/grpc/resolver"
    44  	"google.golang.org/grpc/status"
    45  	"google.golang.org/grpc/xds"
    46  
    47  	testgrpc "google.golang.org/grpc/interop/grpc_testing"
    48  	testpb "google.golang.org/grpc/interop/grpc_testing"
    49  )
    50  
    51  func testModeChangeServerOption(t *testing.T) grpc.ServerOption {
    52  	// Create a server option to get notified about serving mode changes. We don't
    53  	// do anything other than throwing a log entry here. But this is required,
    54  	// since the server code emits a log entry at the default level (which is
    55  	// ERROR) if no callback is registered for serving mode changes. Our
    56  	// testLogger fails the test if there is any log entry at ERROR level. It does
    57  	// provide an ExpectError()  method, but that takes a string and it would be
    58  	// painful to construct the exact error message expected here. Instead this
    59  	// works just fine.
    60  	return xds.ServingModeCallback(func(addr net.Addr, args xds.ServingModeChangeArgs) {
    61  		t.Logf("Serving mode for listener %q changed to %q, err: %v", addr.String(), args.Mode, args.Err)
    62  	})
    63  }
    64  
    65  // acceptNotifyingListener wraps a listener and notifies users when a server
    66  // calls the Listener.Accept() method. This can be used to ensure that the
    67  // server is ready before requests are sent to it.
    68  type acceptNotifyingListener struct {
    69  	net.Listener
    70  	serverReady grpcsync.Event
    71  }
    72  
    73  func (l *acceptNotifyingListener) Accept() (net.Conn, error) {
    74  	l.serverReady.Fire()
    75  	return l.Listener.Accept()
    76  }
    77  
    78  // setupGRPCServer performs the following:
    79  //   - spin up an xDS-enabled gRPC server, configure it with xdsCredentials and
    80  //     register the test service on it
    81  //   - create a local TCP listener and start serving on it
    82  //
    83  // Returns the following:
    84  // - local listener on which the xDS-enabled gRPC server is serving on
    85  // - cleanup function to be invoked by the tests when done
    86  func setupGRPCServer(t *testing.T, bootstrapContents []byte, opts ...grpc.ServerOption) (net.Listener, func()) {
    87  	t.Helper()
    88  
    89  	// Configure xDS credentials to be used on the server-side.
    90  	creds, err := xdscreds.NewServerCredentials(xdscreds.ServerOptions{
    91  		FallbackCreds: insecure.NewCredentials(),
    92  	})
    93  	if err != nil {
    94  		t.Fatal(err)
    95  	}
    96  
    97  	// Initialize a test gRPC server, assign it to the stub server, and start
    98  	// the test service.
    99  	stub := &stubserver.StubServer{
   100  		EmptyCallF: func(context.Context, *testpb.Empty) (*testpb.Empty, error) {
   101  			return &testpb.Empty{}, nil
   102  		},
   103  		UnaryCallF: func(context.Context, *testpb.SimpleRequest) (*testpb.SimpleResponse, error) {
   104  			return &testpb.SimpleResponse{}, nil
   105  		},
   106  		FullDuplexCallF: func(stream testgrpc.TestService_FullDuplexCallServer) error {
   107  			for {
   108  				_, err := stream.Recv() // hangs here forever if stream doesn't shut down...doesn't receive EOF without any errors
   109  				if err == io.EOF {
   110  					return nil
   111  				}
   112  			}
   113  		},
   114  	}
   115  
   116  	opts = append([]grpc.ServerOption{
   117  		grpc.Creds(creds),
   118  		testModeChangeServerOption(t),
   119  		xds.BootstrapContentsForTesting(bootstrapContents),
   120  	}, opts...)
   121  	if stub.S, err = xds.NewGRPCServer(opts...); err != nil {
   122  		t.Fatalf("Failed to create an xDS enabled gRPC server: %v", err)
   123  	}
   124  
   125  	// Create a local listener and pass it to Serve().
   126  	lis, err := testutils.LocalTCPListener()
   127  	if err != nil {
   128  		t.Fatalf("testutils.LocalTCPListener() failed: %v", err)
   129  	}
   130  
   131  	readyLis := &acceptNotifyingListener{
   132  		Listener:    lis,
   133  		serverReady: *grpcsync.NewEvent(),
   134  	}
   135  
   136  	stub.Listener = readyLis
   137  	stubserver.StartTestService(t, stub)
   138  
   139  	// Wait for the server to start running.
   140  	select {
   141  	case <-readyLis.serverReady.Done():
   142  	case <-time.After(defaultTestTimeout):
   143  		t.Fatalf("Timed out while waiting for the backend server to start serving")
   144  	}
   145  
   146  	return lis, func() {
   147  		stub.S.Stop()
   148  	}
   149  }
   150  
   151  func hostPortFromListener(lis net.Listener) (string, uint32, error) {
   152  	host, p, err := net.SplitHostPort(lis.Addr().String())
   153  	if err != nil {
   154  		return "", 0, fmt.Errorf("net.SplitHostPort(%s) failed: %v", lis.Addr().String(), err)
   155  	}
   156  	port, err := strconv.ParseInt(p, 10, 32)
   157  	if err != nil {
   158  		return "", 0, fmt.Errorf("strconv.ParseInt(%s, 10, 32) failed: %v", p, err)
   159  	}
   160  	return host, uint32(port), nil
   161  }
   162  
   163  // TestServerSideXDS_Fallback is an e2e test which verifies xDS credentials
   164  // fallback functionality.
   165  //
   166  // The following sequence of events happen as part of this test:
   167  //   - An xDS-enabled gRPC server is created and xDS credentials are configured.
   168  //   - xDS is enabled on the client by the use of the xds:/// scheme, and xDS
   169  //     credentials are configured.
   170  //   - Control plane is configured to not send any security configuration to both
   171  //     the client and the server. This results in both of them using the
   172  //     configured fallback credentials (which is insecure creds in this case).
   173  func (s) TestServerSideXDS_Fallback(t *testing.T) {
   174  	managementServer, nodeID, bootstrapContents, xdsResolver := setup.ManagementServerAndResolver(t)
   175  
   176  	lis, cleanup2 := setupGRPCServer(t, bootstrapContents)
   177  	defer cleanup2()
   178  
   179  	// Grab the host and port of the server and create client side xDS resources
   180  	// corresponding to it. This contains default resources with no security
   181  	// configuration in the Cluster resources.
   182  	host, port, err := hostPortFromListener(lis)
   183  	if err != nil {
   184  		t.Fatalf("failed to retrieve host and port of server: %v", err)
   185  	}
   186  	const serviceName = "my-service-fallback"
   187  	resources := e2e.DefaultClientResources(e2e.ResourceParams{
   188  		DialTarget: serviceName,
   189  		NodeID:     nodeID,
   190  		Host:       host,
   191  		Port:       port,
   192  		SecLevel:   e2e.SecurityLevelNone,
   193  	})
   194  
   195  	// Create an inbound xDS listener resource for the server side that does not
   196  	// contain any security configuration. This should force the server-side
   197  	// xdsCredentials to use fallback.
   198  	inboundLis := e2e.DefaultServerListener(host, port, e2e.SecurityLevelNone, "routeName")
   199  	resources.Listeners = append(resources.Listeners, inboundLis)
   200  
   201  	// Setup the management server with client and server-side resources.
   202  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   203  	defer cancel()
   204  	if err := managementServer.Update(ctx, resources); err != nil {
   205  		t.Fatal(err)
   206  	}
   207  
   208  	// Create client-side xDS credentials with an insecure fallback.
   209  	creds, err := xdscreds.NewClientCredentials(xdscreds.ClientOptions{
   210  		FallbackCreds: insecure.NewCredentials(),
   211  	})
   212  	if err != nil {
   213  		t.Fatal(err)
   214  	}
   215  
   216  	// Create a ClientConn with the xds scheme and make a successful RPC.
   217  	cc, err := grpc.NewClient(fmt.Sprintf("xds:///%s", serviceName), grpc.WithTransportCredentials(creds), grpc.WithResolvers(xdsResolver))
   218  	if err != nil {
   219  		t.Fatalf("failed to create a client for server: %v", err)
   220  	}
   221  	defer cc.Close()
   222  
   223  	client := testgrpc.NewTestServiceClient(cc)
   224  	if _, err := client.EmptyCall(ctx, &testpb.Empty{}, grpc.WaitForReady(true)); err != nil {
   225  		t.Errorf("rpc EmptyCall() failed: %v", err)
   226  	}
   227  }
   228  
   229  // TestServerSideXDS_FileWatcherCerts is an e2e test which verifies xDS
   230  // credentials with file watcher certificate provider.
   231  //
   232  // The following sequence of events happen as part of this test:
   233  //   - An xDS-enabled gRPC server is created and xDS credentials are configured.
   234  //   - xDS is enabled on the client by the use of the xds:/// scheme, and xDS
   235  //     credentials are configured.
   236  //   - Control plane is configured to send security configuration to both the
   237  //     client and the server, pointing to the file watcher certificate provider.
   238  //     We verify both TLS and mTLS scenarios.
   239  func (s) TestServerSideXDS_FileWatcherCerts(t *testing.T) {
   240  	tests := []struct {
   241  		name     string
   242  		secLevel e2e.SecurityLevel
   243  	}{
   244  		{
   245  			name:     "tls",
   246  			secLevel: e2e.SecurityLevelTLS,
   247  		},
   248  		{
   249  			name:     "mtls",
   250  			secLevel: e2e.SecurityLevelMTLS,
   251  		},
   252  	}
   253  	for _, test := range tests {
   254  		t.Run(test.name, func(t *testing.T) {
   255  			managementServer, nodeID, bootstrapContents, xdsResolver := setup.ManagementServerAndResolver(t)
   256  			lis, cleanup2 := setupGRPCServer(t, bootstrapContents)
   257  			defer cleanup2()
   258  
   259  			// Grab the host and port of the server and create client side xDS
   260  			// resources corresponding to it.
   261  			host, port, err := hostPortFromListener(lis)
   262  			if err != nil {
   263  				t.Fatalf("failed to retrieve host and port of server: %v", err)
   264  			}
   265  
   266  			// Create xDS resources to be consumed on the client side. This
   267  			// includes the listener, route configuration, cluster (with
   268  			// security configuration) and endpoint resources.
   269  			serviceName := "my-service-file-watcher-certs-" + test.name
   270  			resources := e2e.DefaultClientResources(e2e.ResourceParams{
   271  				DialTarget: serviceName,
   272  				NodeID:     nodeID,
   273  				Host:       host,
   274  				Port:       port,
   275  				SecLevel:   test.secLevel,
   276  			})
   277  
   278  			// Create an inbound xDS listener resource for the server side that
   279  			// contains security configuration pointing to the file watcher
   280  			// plugin.
   281  			inboundLis := e2e.DefaultServerListener(host, port, test.secLevel, "routeName")
   282  			resources.Listeners = append(resources.Listeners, inboundLis)
   283  
   284  			// Setup the management server with client and server resources.
   285  			ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   286  			defer cancel()
   287  			if err := managementServer.Update(ctx, resources); err != nil {
   288  				t.Fatal(err)
   289  			}
   290  
   291  			// Create client-side xDS credentials with an insecure fallback.
   292  			creds, err := xdscreds.NewClientCredentials(xdscreds.ClientOptions{
   293  				FallbackCreds: insecure.NewCredentials(),
   294  			})
   295  			if err != nil {
   296  				t.Fatal(err)
   297  			}
   298  
   299  			// Create a ClientConn with the xds scheme and make an RPC.
   300  			cc, err := grpc.NewClient(fmt.Sprintf("xds:///%s", serviceName), grpc.WithTransportCredentials(creds), grpc.WithResolvers(xdsResolver))
   301  			if err != nil {
   302  				t.Fatalf("failed to create a client for server: %v", err)
   303  			}
   304  			defer cc.Close()
   305  
   306  			client := testgrpc.NewTestServiceClient(cc)
   307  			if _, err := client.EmptyCall(ctx, &testpb.Empty{}, grpc.WaitForReady(true)); err != nil {
   308  				t.Fatalf("rpc EmptyCall() failed: %v", err)
   309  			}
   310  		})
   311  	}
   312  }
   313  
   314  // TestServerSideXDS_SecurityConfigChange is an e2e test where xDS is enabled on
   315  // the server-side and xdsCredentials are configured for security. The control
   316  // plane initially does not any security configuration. This forces the
   317  // xdsCredentials to use fallback creds, which is this case is insecure creds.
   318  // We verify that a client connecting with TLS creds is not able to successfully
   319  // make an RPC. The control plane then sends a listener resource with security
   320  // configuration pointing to the use of the file_watcher plugin and we verify
   321  // that the same client is now able to successfully make an RPC.
   322  func (s) TestServerSideXDS_SecurityConfigChange(t *testing.T) {
   323  	managementServer := e2e.StartManagementServer(t, e2e.ManagementServerOptions{AllowResourceSubset: true})
   324  
   325  	// Create bootstrap configuration pointing to the above management server.
   326  	nodeID := uuid.New().String()
   327  	bootstrapContents := e2e.DefaultBootstrapContents(t, nodeID, managementServer.Address)
   328  
   329  	// Create an xDS resolver with the above bootstrap configuration.
   330  	if internal.NewXDSResolverWithConfigForTesting == nil {
   331  		t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil")
   332  	}
   333  	xdsResolver, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(bootstrapContents)
   334  	if err != nil {
   335  		t.Fatalf("Failed to create xDS resolver for testing: %v", err)
   336  	}
   337  
   338  	lis, cleanup2 := setupGRPCServer(t, bootstrapContents)
   339  	defer cleanup2()
   340  
   341  	// Grab the host and port of the server and create client side xDS resources
   342  	// corresponding to it. This contains default resources with no security
   343  	// configuration in the Cluster resource. This should force the xDS
   344  	// credentials on the client to use its fallback.
   345  	host, port, err := hostPortFromListener(lis)
   346  	if err != nil {
   347  		t.Fatalf("failed to retrieve host and port of server: %v", err)
   348  	}
   349  	const serviceName = "my-service-security-config-change"
   350  	resources := e2e.DefaultClientResources(e2e.ResourceParams{
   351  		DialTarget: serviceName,
   352  		NodeID:     nodeID,
   353  		Host:       host,
   354  		Port:       port,
   355  		SecLevel:   e2e.SecurityLevelNone,
   356  	})
   357  
   358  	// Create an inbound xDS listener resource for the server side that does not
   359  	// contain any security configuration. This should force the xDS credentials
   360  	// on server to use its fallback.
   361  	inboundLis := e2e.DefaultServerListener(host, port, e2e.SecurityLevelNone, "routeName")
   362  	resources.Listeners = append(resources.Listeners, inboundLis)
   363  
   364  	// Setup the management server with client and server-side resources.
   365  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   366  	defer cancel()
   367  	if err := managementServer.Update(ctx, resources); err != nil {
   368  		t.Fatal(err)
   369  	}
   370  
   371  	// Create client-side xDS credentials with an insecure fallback.
   372  	xdsCreds, err := xdscreds.NewClientCredentials(xdscreds.ClientOptions{
   373  		FallbackCreds: insecure.NewCredentials(),
   374  	})
   375  	if err != nil {
   376  		t.Fatal(err)
   377  	}
   378  
   379  	// Create a ClientConn with the xds scheme and make a successful RPC.
   380  	xdsCC, err := grpc.NewClient(fmt.Sprintf("xds:///%s", serviceName), grpc.WithTransportCredentials(xdsCreds), grpc.WithResolvers(xdsResolver))
   381  	if err != nil {
   382  		t.Fatalf("failed to create a client for server: %v", err)
   383  	}
   384  	defer xdsCC.Close()
   385  
   386  	client := testgrpc.NewTestServiceClient(xdsCC)
   387  	if _, err := client.EmptyCall(ctx, &testpb.Empty{}, grpc.WaitForReady(true)); err != nil {
   388  		t.Fatalf("rpc EmptyCall() failed: %v", err)
   389  	}
   390  
   391  	// Create a ClientConn with TLS creds. This should fail since the server is
   392  	// using fallback credentials which in this case in insecure creds.
   393  	tlsCreds := testutils.CreateClientTLSCredentials(t)
   394  	tlsCC, err := grpc.NewClient(lis.Addr().String(), grpc.WithTransportCredentials(tlsCreds))
   395  	if err != nil {
   396  		t.Fatalf("failed to create a client for server: %v", err)
   397  	}
   398  	defer tlsCC.Close()
   399  
   400  	// We don't set 'waitForReady` here since we want this call to failfast.
   401  	client = testgrpc.NewTestServiceClient(tlsCC)
   402  	if _, err := client.EmptyCall(ctx, &testpb.Empty{}); status.Code(err) != codes.Unavailable {
   403  		t.Fatal("rpc EmptyCall() succeeded when expected to fail")
   404  	}
   405  
   406  	// Switch server and client side resources with ones that contain required
   407  	// security configuration for mTLS with a file watcher certificate provider.
   408  	resources = e2e.DefaultClientResources(e2e.ResourceParams{
   409  		DialTarget: serviceName,
   410  		NodeID:     nodeID,
   411  		Host:       host,
   412  		Port:       port,
   413  		SecLevel:   e2e.SecurityLevelMTLS,
   414  	})
   415  	inboundLis = e2e.DefaultServerListener(host, port, e2e.SecurityLevelMTLS, "routeName")
   416  	resources.Listeners = append(resources.Listeners, inboundLis)
   417  	if err := managementServer.Update(ctx, resources); err != nil {
   418  		t.Fatal(err)
   419  	}
   420  
   421  	// Make another RPC with `waitForReady` set and expect this to succeed.
   422  	if _, err := client.EmptyCall(ctx, &testpb.Empty{}, grpc.WaitForReady(true)); err != nil {
   423  		t.Fatalf("rpc EmptyCall() failed: %v", err)
   424  	}
   425  }
   426  
   427  // TestServerSideXDS_FileWatcherCertsSPIFFE is an e2e test which verifies xDS
   428  // credentials with file watcher certificate provider that is configured with a
   429  // SPIFFE Bundle Map for it's roots.
   430  //
   431  // The following sequence of events happen as part of this test:
   432  //   - An xDS-enabled gRPC server is created and xDS credentials are configured.
   433  //   - xDS is enabled on the client by the use of the xds:/// scheme, and xDS
   434  //     credentials are configured.
   435  //   - Control plane is configured to send security configuration to both the
   436  //     client and the server, pointing to the file watcher certificate provider.
   437  //     We verify both TLS and mTLS scenarios.
   438  func (s) TestServerSideXDS_FileWatcherCertsSPIFFE(t *testing.T) {
   439  	tests := []struct {
   440  		name     string
   441  		secLevel e2e.SecurityLevel
   442  	}{
   443  		{
   444  			name:     "tls",
   445  			secLevel: e2e.SecurityLevelTLS,
   446  		},
   447  		{
   448  			name:     "mtls",
   449  			secLevel: e2e.SecurityLevelMTLS,
   450  		},
   451  	}
   452  	for _, test := range tests {
   453  		t.Run(test.name, func(t *testing.T) {
   454  			managementServer, nodeID, bootstrapContents, xdsResolver := setup.ManagementServerAndResolverWithSPIFFE(t)
   455  			lis, cleanup2 := setupGRPCServer(t, bootstrapContents)
   456  			defer cleanup2()
   457  
   458  			// Grab the host and port of the server and create client side xDS
   459  			// resources corresponding to it.
   460  			host, port, err := hostPortFromListener(lis)
   461  			if err != nil {
   462  				t.Fatalf("failed to retrieve host and port of server: %v", err)
   463  			}
   464  
   465  			// Create xDS resources to be consumed on the client side. This
   466  			// includes the listener, route configuration, cluster (with
   467  			// security configuration) and endpoint resources.
   468  			serviceName := "my-service-file-watcher-certs-" + test.name
   469  			resources := e2e.DefaultClientResources(e2e.ResourceParams{
   470  				DialTarget: serviceName,
   471  				NodeID:     nodeID,
   472  				Host:       host,
   473  				Port:       port,
   474  				SecLevel:   test.secLevel,
   475  			})
   476  
   477  			// Create an inbound xDS listener resource for the server side that
   478  			// contains security configuration pointing to the file watcher
   479  			// plugin.
   480  			inboundLis := e2e.DefaultServerListener(host, port, test.secLevel, "routeName")
   481  			resources.Listeners = append(resources.Listeners, inboundLis)
   482  
   483  			// Setup the management server with client and server resources.
   484  			ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   485  			defer cancel()
   486  			if err := managementServer.Update(ctx, resources); err != nil {
   487  				t.Fatal(err)
   488  			}
   489  
   490  			// Create client-side xDS credentials with an insecure fallback.
   491  			creds, err := xdscreds.NewClientCredentials(xdscreds.ClientOptions{
   492  				FallbackCreds: insecure.NewCredentials(),
   493  			})
   494  			if err != nil {
   495  				t.Fatal(err)
   496  			}
   497  
   498  			// Create a ClientConn with the xds scheme and make an RPC.
   499  			cc, err := grpc.NewClient(fmt.Sprintf("xds:///%s", serviceName), grpc.WithTransportCredentials(creds), grpc.WithResolvers(xdsResolver))
   500  			if err != nil {
   501  				t.Fatalf("failed to create a client for server: %v", err)
   502  			}
   503  			defer cc.Close()
   504  
   505  			peer := &peer.Peer{}
   506  			client := testgrpc.NewTestServiceClient(cc)
   507  			if _, err := client.EmptyCall(ctx, &testpb.Empty{}, grpc.WaitForReady(true), grpc.Peer(peer)); err != nil {
   508  				t.Fatalf("rpc EmptyCall() failed: %v", err)
   509  			}
   510  			verifySecurityInformationFromPeerSPIFFE(t, peer, test.secLevel, 1)
   511  		})
   512  	}
   513  }
   514  
   515  // Checks the AuthInfo available in the peer if it matches the expected security
   516  // level of the connection.
   517  func verifySecurityInformationFromPeerSPIFFE(t *testing.T, pr *peer.Peer, wantSecLevel e2e.SecurityLevel, wantPeerChainLen int) {
   518  	// This is not a true helper in the Go sense, because it does not perform
   519  	// setup or cleanup tasks. Marking it a helper is to ensure that when the
   520  	// test fails, the line information of the caller is outputted instead of
   521  	// from here.
   522  	//
   523  	// And this function directly calls t.Fatalf() instead of returning an error
   524  	// and letting the caller decide what to do with it. This is also OK since
   525  	// all callers will simply end up calling t.Fatalf() with the returned
   526  	// error, and can't add any contextual information of value to the error
   527  	// message.
   528  	t.Helper()
   529  
   530  	authType := pr.AuthInfo.AuthType()
   531  	switch wantSecLevel {
   532  	case e2e.SecurityLevelNone:
   533  		if authType != "insecure" {
   534  			t.Fatalf("AuthType() is %s, want insecure", authType)
   535  		}
   536  	case e2e.SecurityLevelMTLS:
   537  		if authType != "tls" {
   538  			t.Fatalf("AuthType() is %s, want tls", authType)
   539  		}
   540  		ai, ok := pr.AuthInfo.(credentials.TLSInfo)
   541  		if !ok {
   542  			t.Fatalf("AuthInfo type is %T, want %T", pr.AuthInfo, credentials.TLSInfo{})
   543  		}
   544  		if len(ai.State.PeerCertificates) != wantPeerChainLen {
   545  			t.Fatalf("Number of peer certificates is %d, want %d", len(ai.State.PeerCertificates), wantPeerChainLen)
   546  		}
   547  	}
   548  }