Repository: grpc/grpc-go
File: internal/xds/balancer/clusterimpl/tests/balancer_test.go (Go)

Code before:
	const userAuthorityOverride = "user-override.com"
	if _, err := client.EmptyCall(ctx, &testpb.Empty{}, grpc.CallAuthority(userAuthorityOverride)); err != nil {
		t.Fatalf("client.EmptyCall() failed: %v", err)
	}

	select {
	case got := <-authorityCh:
		if got != userAuthorityOverride {
			t.Errorf("Server received authority %q, want %q (user override)", got, userAuthorityOverride)
		}
	case <-ctx.Done():
		t.Fatalf("Timeout waiting for successful RPC.")
	}
}

// TestAuthorityOverridingWithTLS verifies the interaction between xDS Authority
// Rewriting and TLS Secure Naming. It ensures that when the :authority header
// is rewritten by the clusterimpl picker, the new authority is correctly
// validated against the server's TLS certificate before the RPC proceeds.
// Also check that RPC fails when the rewritten authority does not match the
// server's certificate due to secure naming validation.
func (s) TestAuthorityOverridingWithTLS(t *testing.T) {
	tests := []struct {
		name                 string
		xdsAuthorityOverride string
		expectSuccess        bool
	}{
		{
			name:                 "Valid_Authority_Rewrite",
			xdsAuthorityOverride: "x.test.example.com",
			expectSuccess:        true,
		},
		{
			name:                 "Authority_Rewrite_Mismatch",
			xdsAuthorityOverride: "xyz.exmaple.com",
			expectSuccess:        false,
		},
	}
	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			testutils.SetEnvConfig(t, &envconfig.XDSAuthorityRewrite, true)
			mgmtServer, resolverBuilder, nodeID := setupManagementServerAndResolver(t)

			serverCreds := testutils.CreateServerTLSCredentials(t, tls.RequireAndVerifyClientCert)

			// Start a server backend exposing the test service.
			authorityCh := make(chan string, 1)
			f := &stubserver.StubServer{
				EmptyCallF: func(ctx context.Context, _ *testpb.Empty) (*testpb.Empty, error) {
					if md, ok := metadata.FromIncomingContext(ctx); ok {
						if authVals := md.Get(":authority"); len(authVals) > 0 {

Review comment (refactor):
Prefer using the word "want" instead of "expect". We typically use the name `wantErr` in such cases, see https://google.github.io/styleguide/go/decisions#got-before-want.

In this case, we can change this field to a status code to simplify assertions in the test.

Code after:

			// Start a server backend exposing the test service.
			var gotAuthority string
			f := &stubserver.StubServer{
				EmptyCallF: func(ctx context.Context, _ *testpb.Empty) (*testpb.Empty, error) {
					if md, ok := metadata.FromIncomingContext(ctx); ok {
						if authVals := md.Get(":authority"); len(authVals) > 0 {
							gotAuthority = authVals[0]
						}
					}
					return &testpb.Empty{}, nil
				},
			}
			f.StartServer(grpc.Creds(serverCreds))
			defer f.Stop()

			clientCreds, err := xdscreds.NewClientCredentials(xdscreds.ClientOptions{FallbackCreds: insecure.NewCredentials()})
			if err != nil {
				t.Fatalf("Failed to create client credentials: %v", err)
			}

			ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
			defer cancel()
			configureXDSResources(ctx, t, mgmtServer, nodeID, f.Address, test.xdsAuthorityOverride, e2e.SecurityLevelMTLS)

			// Create ClientConn with TLS
			cc, err := grpc.NewClient("xds:///my-test-xds-service", grpc.WithTransportCredentials(clientCreds), grpc.WithResolvers(resolverBuilder))
			if err != nil {
				t.Fatalf("Failed to create client: %v", err)
			}
			defer cc.Close()

			client := testgrpc.NewTestServiceClient(cc)
			peer := &peer.Peer{}
			_, err = client.EmptyCall(ctx, &testpb.Empty{}, grpc.WaitForReady(true), grpc.Peer(peer))

			if test.wantSuccess {
				if err != nil {
					t.Fatalf("RPC failed unexpectedly: %v", err)
				}
				if gotAuthority != test.xdsAuthorityOverride {
					t.Errorf("invalid authority got: %q, want: %q", gotAuthority, test.xdsAuthorityOverride)
				}
			} else {
				if status.Code(err) != codes.Unavailable {
					t.Fatalf("Expected TLS failure due to authority mismatch, got: %q want: %q", codes.Unavailable, status.Code(err))
				}
			}
		})
	}
}