google.golang.org/grpc@v1.62.1/test/healthcheck_test.go (about)

     1  /*
     2   *
     3   * Copyright 2018 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 test
    20  
    21  import (
    22  	"context"
    23  	"errors"
    24  	"fmt"
    25  	"net"
    26  	"sync"
    27  	"testing"
    28  	"time"
    29  
    30  	"google.golang.org/grpc"
    31  	"google.golang.org/grpc/codes"
    32  	"google.golang.org/grpc/connectivity"
    33  	"google.golang.org/grpc/credentials/insecure"
    34  	"google.golang.org/grpc/health"
    35  	"google.golang.org/grpc/internal"
    36  	"google.golang.org/grpc/internal/channelz"
    37  	"google.golang.org/grpc/internal/grpctest"
    38  	"google.golang.org/grpc/internal/testutils"
    39  	"google.golang.org/grpc/resolver"
    40  	"google.golang.org/grpc/resolver/manual"
    41  	"google.golang.org/grpc/status"
    42  
    43  	healthgrpc "google.golang.org/grpc/health/grpc_health_v1"
    44  	healthpb "google.golang.org/grpc/health/grpc_health_v1"
    45  	testgrpc "google.golang.org/grpc/interop/grpc_testing"
    46  	testpb "google.golang.org/grpc/interop/grpc_testing"
    47  )
    48  
    49  var testHealthCheckFunc = internal.HealthCheckFunc
    50  
    51  func newTestHealthServer() *testHealthServer {
    52  	return newTestHealthServerWithWatchFunc(defaultWatchFunc)
    53  }
    54  
    55  func newTestHealthServerWithWatchFunc(f healthWatchFunc) *testHealthServer {
    56  	return &testHealthServer{
    57  		watchFunc: f,
    58  		update:    make(chan struct{}, 1),
    59  		status:    make(map[string]healthpb.HealthCheckResponse_ServingStatus),
    60  	}
    61  }
    62  
    63  // defaultWatchFunc will send a HealthCheckResponse to the client whenever SetServingStatus is called.
    64  func defaultWatchFunc(s *testHealthServer, in *healthpb.HealthCheckRequest, stream healthgrpc.Health_WatchServer) error {
    65  	if in.Service != "foo" {
    66  		return status.Error(codes.FailedPrecondition,
    67  			"the defaultWatchFunc only handles request with service name to be \"foo\"")
    68  	}
    69  	var done bool
    70  	for {
    71  		select {
    72  		case <-stream.Context().Done():
    73  			done = true
    74  		case <-s.update:
    75  		}
    76  		if done {
    77  			break
    78  		}
    79  		s.mu.Lock()
    80  		resp := &healthpb.HealthCheckResponse{
    81  			Status: s.status[in.Service],
    82  		}
    83  		s.mu.Unlock()
    84  		stream.SendMsg(resp)
    85  	}
    86  	return nil
    87  }
    88  
    89  type healthWatchFunc func(s *testHealthServer, in *healthpb.HealthCheckRequest, stream healthgrpc.Health_WatchServer) error
    90  
    91  type testHealthServer struct {
    92  	healthgrpc.UnimplementedHealthServer
    93  	watchFunc healthWatchFunc
    94  	mu        sync.Mutex
    95  	status    map[string]healthpb.HealthCheckResponse_ServingStatus
    96  	update    chan struct{}
    97  }
    98  
    99  func (s *testHealthServer) Check(ctx context.Context, in *healthpb.HealthCheckRequest) (*healthpb.HealthCheckResponse, error) {
   100  	return &healthpb.HealthCheckResponse{
   101  		Status: healthpb.HealthCheckResponse_SERVING,
   102  	}, nil
   103  }
   104  
   105  func (s *testHealthServer) Watch(in *healthpb.HealthCheckRequest, stream healthgrpc.Health_WatchServer) error {
   106  	return s.watchFunc(s, in, stream)
   107  }
   108  
   109  // SetServingStatus is called when need to reset the serving status of a service
   110  // or insert a new service entry into the statusMap.
   111  func (s *testHealthServer) SetServingStatus(service string, status healthpb.HealthCheckResponse_ServingStatus) {
   112  	s.mu.Lock()
   113  	s.status[service] = status
   114  	select {
   115  	case <-s.update:
   116  	default:
   117  	}
   118  	s.update <- struct{}{}
   119  	s.mu.Unlock()
   120  }
   121  
   122  func setupHealthCheckWrapper() (hcEnterChan chan struct{}, hcExitChan chan struct{}, wrapper internal.HealthChecker) {
   123  	hcEnterChan = make(chan struct{})
   124  	hcExitChan = make(chan struct{})
   125  	wrapper = func(ctx context.Context, newStream func(string) (any, error), update func(connectivity.State, error), service string) error {
   126  		close(hcEnterChan)
   127  		defer close(hcExitChan)
   128  		return testHealthCheckFunc(ctx, newStream, update, service)
   129  	}
   130  	return
   131  }
   132  
   133  func setupServer(t *testing.T, watchFunc healthWatchFunc) (*grpc.Server, net.Listener, *testHealthServer) {
   134  	t.Helper()
   135  
   136  	lis, err := net.Listen("tcp", "localhost:0")
   137  	if err != nil {
   138  		t.Fatalf("net.Listen() failed: %v", err)
   139  	}
   140  
   141  	var ts *testHealthServer
   142  	if watchFunc != nil {
   143  		ts = newTestHealthServerWithWatchFunc(watchFunc)
   144  	} else {
   145  		ts = newTestHealthServer()
   146  	}
   147  	s := grpc.NewServer()
   148  	healthgrpc.RegisterHealthServer(s, ts)
   149  	testgrpc.RegisterTestServiceServer(s, &testServer{})
   150  	go s.Serve(lis)
   151  	t.Cleanup(func() { s.Stop() })
   152  	return s, lis, ts
   153  }
   154  
   155  type clientConfig struct {
   156  	balancerName               string
   157  	testHealthCheckFuncWrapper internal.HealthChecker
   158  	extraDialOption            []grpc.DialOption
   159  }
   160  
   161  func setupClient(t *testing.T, c *clientConfig) (*grpc.ClientConn, *manual.Resolver) {
   162  	t.Helper()
   163  
   164  	r := manual.NewBuilderWithScheme("whatever")
   165  	opts := []grpc.DialOption{
   166  		grpc.WithTransportCredentials(insecure.NewCredentials()),
   167  		grpc.WithResolvers(r),
   168  	}
   169  	if c != nil {
   170  		if c.balancerName != "" {
   171  			opts = append(opts, grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"loadBalancingConfig": [{"%s":{}}]}`, c.balancerName)))
   172  		}
   173  		if c.testHealthCheckFuncWrapper != nil {
   174  			opts = append(opts, internal.WithHealthCheckFunc.(func(internal.HealthChecker) grpc.DialOption)(c.testHealthCheckFuncWrapper))
   175  		}
   176  		opts = append(opts, c.extraDialOption...)
   177  	}
   178  
   179  	cc, err := grpc.Dial(r.Scheme()+":///test.server", opts...)
   180  	if err != nil {
   181  		t.Fatalf("grpc.Dial() failed: %v", err)
   182  	}
   183  	t.Cleanup(func() { cc.Close() })
   184  	return cc, r
   185  }
   186  
   187  func (s) TestHealthCheckWatchStateChange(t *testing.T) {
   188  	_, lis, ts := setupServer(t, nil)
   189  
   190  	// The table below shows the expected series of addrConn connectivity transitions when server
   191  	// updates its health status. As there's only one addrConn corresponds with the ClientConn in this
   192  	// test, we use ClientConn's connectivity state as the addrConn connectivity state.
   193  	//+------------------------------+-------------------------------------------+
   194  	//| Health Check Returned Status | Expected addrConn Connectivity Transition |
   195  	//+------------------------------+-------------------------------------------+
   196  	//| NOT_SERVING                  | ->TRANSIENT FAILURE                       |
   197  	//| SERVING                      | ->READY                                   |
   198  	//| SERVICE_UNKNOWN              | ->TRANSIENT FAILURE                       |
   199  	//| SERVING                      | ->READY                                   |
   200  	//| UNKNOWN                      | ->TRANSIENT FAILURE                       |
   201  	//+------------------------------+-------------------------------------------+
   202  	ts.SetServingStatus("foo", healthpb.HealthCheckResponse_NOT_SERVING)
   203  
   204  	cc, r := setupClient(t, nil)
   205  	r.UpdateState(resolver.State{
   206  		Addresses: []resolver.Address{{Addr: lis.Addr().String()}},
   207  		ServiceConfig: parseServiceConfig(t, r, `{
   208  	"healthCheckConfig": {
   209  		"serviceName": "foo"
   210  	},
   211  	"loadBalancingConfig": [{"round_robin":{}}]
   212  }`)})
   213  
   214  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   215  	defer cancel()
   216  	testutils.AwaitNotState(ctx, t, cc, connectivity.Idle)
   217  	testutils.AwaitNotState(ctx, t, cc, connectivity.Connecting)
   218  	testutils.AwaitState(ctx, t, cc, connectivity.TransientFailure)
   219  	if s := cc.GetState(); s != connectivity.TransientFailure {
   220  		t.Fatalf("ClientConn is in %v state, want TRANSIENT FAILURE", s)
   221  	}
   222  
   223  	ts.SetServingStatus("foo", healthpb.HealthCheckResponse_SERVING)
   224  	testutils.AwaitNotState(ctx, t, cc, connectivity.TransientFailure)
   225  	if s := cc.GetState(); s != connectivity.Ready {
   226  		t.Fatalf("ClientConn is in %v state, want READY", s)
   227  	}
   228  
   229  	ts.SetServingStatus("foo", healthpb.HealthCheckResponse_SERVICE_UNKNOWN)
   230  	testutils.AwaitNotState(ctx, t, cc, connectivity.Ready)
   231  	if s := cc.GetState(); s != connectivity.TransientFailure {
   232  		t.Fatalf("ClientConn is in %v state, want TRANSIENT FAILURE", s)
   233  	}
   234  
   235  	ts.SetServingStatus("foo", healthpb.HealthCheckResponse_SERVING)
   236  	testutils.AwaitNotState(ctx, t, cc, connectivity.TransientFailure)
   237  	if s := cc.GetState(); s != connectivity.Ready {
   238  		t.Fatalf("ClientConn is in %v state, want READY", s)
   239  	}
   240  
   241  	ts.SetServingStatus("foo", healthpb.HealthCheckResponse_UNKNOWN)
   242  	testutils.AwaitNotState(ctx, t, cc, connectivity.Ready)
   243  	if s := cc.GetState(); s != connectivity.TransientFailure {
   244  		t.Fatalf("ClientConn is in %v state, want TRANSIENT FAILURE", s)
   245  	}
   246  }
   247  
   248  // If Watch returns Unimplemented, then the ClientConn should go into READY state.
   249  func (s) TestHealthCheckHealthServerNotRegistered(t *testing.T) {
   250  	grpctest.TLogger.ExpectError("Subchannel health check is unimplemented at server side, thus health check is disabled")
   251  	s := grpc.NewServer()
   252  	lis, err := net.Listen("tcp", "localhost:0")
   253  	if err != nil {
   254  		t.Fatalf("failed to listen due to err: %v", err)
   255  	}
   256  	go s.Serve(lis)
   257  	defer s.Stop()
   258  
   259  	cc, r := setupClient(t, nil)
   260  	r.UpdateState(resolver.State{
   261  		Addresses: []resolver.Address{{Addr: lis.Addr().String()}},
   262  		ServiceConfig: parseServiceConfig(t, r, `{
   263  	"healthCheckConfig": {
   264  		"serviceName": "foo"
   265  	},
   266  	"loadBalancingConfig": [{"round_robin":{}}]
   267  }`)})
   268  
   269  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   270  	defer cancel()
   271  	testutils.AwaitNotState(ctx, t, cc, connectivity.Idle)
   272  	testutils.AwaitNotState(ctx, t, cc, connectivity.Connecting)
   273  	if s := cc.GetState(); s != connectivity.Ready {
   274  		t.Fatalf("ClientConn is in %v state, want READY", s)
   275  	}
   276  }
   277  
   278  // In the case of a goaway received, the health check stream should be terminated and health check
   279  // function should exit.
   280  func (s) TestHealthCheckWithGoAway(t *testing.T) {
   281  	s, lis, ts := setupServer(t, nil)
   282  	ts.SetServingStatus("foo", healthpb.HealthCheckResponse_SERVING)
   283  
   284  	hcEnterChan, hcExitChan, testHealthCheckFuncWrapper := setupHealthCheckWrapper()
   285  	cc, r := setupClient(t, &clientConfig{testHealthCheckFuncWrapper: testHealthCheckFuncWrapper})
   286  	tc := testgrpc.NewTestServiceClient(cc)
   287  	r.UpdateState(resolver.State{
   288  		Addresses: []resolver.Address{{Addr: lis.Addr().String()}},
   289  		ServiceConfig: parseServiceConfig(t, r, `{
   290  	"healthCheckConfig": {
   291  		"serviceName": "foo"
   292  	},
   293  	"loadBalancingConfig": [{"round_robin":{}}]
   294  }`)})
   295  
   296  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   297  	defer cancel()
   298  	// make some rpcs to make sure connection is working.
   299  	if err := verifyResultWithDelay(func() (bool, error) {
   300  		if _, err := tc.EmptyCall(ctx, &testpb.Empty{}); err != nil {
   301  			return false, fmt.Errorf("TestService/EmptyCall(_, _) = _, %v, want _, <nil>", err)
   302  		}
   303  		return true, nil
   304  	}); err != nil {
   305  		t.Fatal(err)
   306  	}
   307  
   308  	// the stream rpc will persist through goaway event.
   309  	stream, err := tc.FullDuplexCall(ctx, grpc.WaitForReady(true))
   310  	if err != nil {
   311  		t.Fatalf("%v.FullDuplexCall(_) = _, %v, want <nil>", tc, err)
   312  	}
   313  	respParam := []*testpb.ResponseParameters{{Size: 1}}
   314  	payload, err := newPayload(testpb.PayloadType_COMPRESSABLE, int32(1))
   315  	if err != nil {
   316  		t.Fatal(err)
   317  	}
   318  	req := &testpb.StreamingOutputCallRequest{
   319  		ResponseParameters: respParam,
   320  		Payload:            payload,
   321  	}
   322  	if err := stream.Send(req); err != nil {
   323  		t.Fatalf("%v.Send(_) = %v, want <nil>", stream, err)
   324  	}
   325  	if _, err := stream.Recv(); err != nil {
   326  		t.Fatalf("%v.Recv() = _, %v, want _, <nil>", stream, err)
   327  	}
   328  
   329  	select {
   330  	case <-hcExitChan:
   331  		t.Fatal("Health check function has exited, which is not expected.")
   332  	default:
   333  	}
   334  
   335  	// server sends GoAway
   336  	go s.GracefulStop()
   337  
   338  	select {
   339  	case <-hcExitChan:
   340  	case <-time.After(5 * time.Second):
   341  		select {
   342  		case <-hcEnterChan:
   343  		default:
   344  			t.Fatal("Health check function has not entered after 5s.")
   345  		}
   346  		t.Fatal("Health check function has not exited after 5s.")
   347  	}
   348  
   349  	// The existing RPC should be still good to proceed.
   350  	if err := stream.Send(req); err != nil {
   351  		t.Fatalf("%v.Send(_) = %v, want <nil>", stream, err)
   352  	}
   353  	if _, err := stream.Recv(); err != nil {
   354  		t.Fatalf("%v.Recv() = _, %v, want _, <nil>", stream, err)
   355  	}
   356  }
   357  
   358  func (s) TestHealthCheckWithConnClose(t *testing.T) {
   359  	s, lis, ts := setupServer(t, nil)
   360  	ts.SetServingStatus("foo", healthpb.HealthCheckResponse_SERVING)
   361  
   362  	hcEnterChan, hcExitChan, testHealthCheckFuncWrapper := setupHealthCheckWrapper()
   363  	cc, r := setupClient(t, &clientConfig{testHealthCheckFuncWrapper: testHealthCheckFuncWrapper})
   364  	tc := testgrpc.NewTestServiceClient(cc)
   365  	r.UpdateState(resolver.State{
   366  		Addresses: []resolver.Address{{Addr: lis.Addr().String()}},
   367  		ServiceConfig: parseServiceConfig(t, r, `{
   368  	"healthCheckConfig": {
   369  		"serviceName": "foo"
   370  	},
   371  	"loadBalancingConfig": [{"round_robin":{}}]
   372  }`)})
   373  
   374  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   375  	defer cancel()
   376  	// make some rpcs to make sure connection is working.
   377  	if err := verifyResultWithDelay(func() (bool, error) {
   378  		if _, err := tc.EmptyCall(ctx, &testpb.Empty{}); err != nil {
   379  			return false, fmt.Errorf("TestService/EmptyCall(_, _) = _, %v, want _, <nil>", err)
   380  		}
   381  		return true, nil
   382  	}); err != nil {
   383  		t.Fatal(err)
   384  	}
   385  
   386  	select {
   387  	case <-hcExitChan:
   388  		t.Fatal("Health check function has exited, which is not expected.")
   389  	default:
   390  	}
   391  	// server closes the connection
   392  	s.Stop()
   393  
   394  	select {
   395  	case <-hcExitChan:
   396  	case <-time.After(5 * time.Second):
   397  		select {
   398  		case <-hcEnterChan:
   399  		default:
   400  			t.Fatal("Health check function has not entered after 5s.")
   401  		}
   402  		t.Fatal("Health check function has not exited after 5s.")
   403  	}
   404  }
   405  
   406  // addrConn drain happens when addrConn gets torn down due to its address being no longer in the
   407  // address list returned by the resolver.
   408  func (s) TestHealthCheckWithAddrConnDrain(t *testing.T) {
   409  	_, lis, ts := setupServer(t, nil)
   410  	ts.SetServingStatus("foo", healthpb.HealthCheckResponse_SERVING)
   411  
   412  	hcEnterChan, hcExitChan, testHealthCheckFuncWrapper := setupHealthCheckWrapper()
   413  	cc, r := setupClient(t, &clientConfig{testHealthCheckFuncWrapper: testHealthCheckFuncWrapper})
   414  	tc := testgrpc.NewTestServiceClient(cc)
   415  	sc := parseServiceConfig(t, r, `{
   416  	"healthCheckConfig": {
   417  		"serviceName": "foo"
   418  	},
   419  	"loadBalancingConfig": [{"round_robin":{}}]
   420  }`)
   421  	r.UpdateState(resolver.State{
   422  		Addresses:     []resolver.Address{{Addr: lis.Addr().String()}},
   423  		ServiceConfig: sc,
   424  	})
   425  
   426  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   427  	defer cancel()
   428  	// make some rpcs to make sure connection is working.
   429  	if err := verifyResultWithDelay(func() (bool, error) {
   430  		if _, err := tc.EmptyCall(ctx, &testpb.Empty{}); err != nil {
   431  			return false, fmt.Errorf("TestService/EmptyCall(_, _) = _, %v, want _, <nil>", err)
   432  		}
   433  		return true, nil
   434  	}); err != nil {
   435  		t.Fatal(err)
   436  	}
   437  
   438  	// the stream rpc will persist through goaway event.
   439  	stream, err := tc.FullDuplexCall(ctx, grpc.WaitForReady(true))
   440  	if err != nil {
   441  		t.Fatalf("%v.FullDuplexCall(_) = _, %v, want <nil>", tc, err)
   442  	}
   443  	respParam := []*testpb.ResponseParameters{{Size: 1}}
   444  	payload, err := newPayload(testpb.PayloadType_COMPRESSABLE, int32(1))
   445  	if err != nil {
   446  		t.Fatal(err)
   447  	}
   448  	req := &testpb.StreamingOutputCallRequest{
   449  		ResponseParameters: respParam,
   450  		Payload:            payload,
   451  	}
   452  	if err := stream.Send(req); err != nil {
   453  		t.Fatalf("%v.Send(_) = %v, want <nil>", stream, err)
   454  	}
   455  	if _, err := stream.Recv(); err != nil {
   456  		t.Fatalf("%v.Recv() = _, %v, want _, <nil>", stream, err)
   457  	}
   458  
   459  	select {
   460  	case <-hcExitChan:
   461  		t.Fatal("Health check function has exited, which is not expected.")
   462  	default:
   463  	}
   464  	// trigger teardown of the ac
   465  	r.UpdateState(resolver.State{Addresses: []resolver.Address{{Addr: "fake address"}}, ServiceConfig: sc})
   466  
   467  	select {
   468  	case <-hcExitChan:
   469  	case <-time.After(5 * time.Second):
   470  		select {
   471  		case <-hcEnterChan:
   472  		default:
   473  			t.Fatal("Health check function has not entered after 5s.")
   474  		}
   475  		t.Fatal("Health check function has not exited after 5s.")
   476  	}
   477  
   478  	// The existing RPC should be still good to proceed.
   479  	if err := stream.Send(req); err != nil {
   480  		t.Fatalf("%v.Send(_) = %v, want <nil>", stream, err)
   481  	}
   482  	if _, err := stream.Recv(); err != nil {
   483  		t.Fatalf("%v.Recv() = _, %v, want _, <nil>", stream, err)
   484  	}
   485  }
   486  
   487  // ClientConn close will lead to its addrConns being torn down.
   488  func (s) TestHealthCheckWithClientConnClose(t *testing.T) {
   489  	_, lis, ts := setupServer(t, nil)
   490  	ts.SetServingStatus("foo", healthpb.HealthCheckResponse_SERVING)
   491  
   492  	hcEnterChan, hcExitChan, testHealthCheckFuncWrapper := setupHealthCheckWrapper()
   493  	cc, r := setupClient(t, &clientConfig{testHealthCheckFuncWrapper: testHealthCheckFuncWrapper})
   494  	tc := testgrpc.NewTestServiceClient(cc)
   495  	r.UpdateState(resolver.State{
   496  		Addresses: []resolver.Address{{Addr: lis.Addr().String()}},
   497  		ServiceConfig: parseServiceConfig(t, r, `{
   498  	"healthCheckConfig": {
   499  		"serviceName": "foo"
   500  	},
   501  	"loadBalancingConfig": [{"round_robin":{}}]
   502  }`)})
   503  
   504  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   505  	defer cancel()
   506  	// make some rpcs to make sure connection is working.
   507  	if err := verifyResultWithDelay(func() (bool, error) {
   508  		if _, err := tc.EmptyCall(ctx, &testpb.Empty{}); err != nil {
   509  			return false, fmt.Errorf("TestService/EmptyCall(_, _) = _, %v, want _, <nil>", err)
   510  		}
   511  		return true, nil
   512  	}); err != nil {
   513  		t.Fatal(err)
   514  	}
   515  
   516  	select {
   517  	case <-hcExitChan:
   518  		t.Fatal("Health check function has exited, which is not expected.")
   519  	default:
   520  	}
   521  
   522  	// trigger addrConn teardown
   523  	cc.Close()
   524  
   525  	select {
   526  	case <-hcExitChan:
   527  	case <-time.After(5 * time.Second):
   528  		select {
   529  		case <-hcEnterChan:
   530  		default:
   531  			t.Fatal("Health check function has not entered after 5s.")
   532  		}
   533  		t.Fatal("Health check function has not exited after 5s.")
   534  	}
   535  }
   536  
   537  // This test is to test the logic in the createTransport after the health check function returns which
   538  // closes the skipReset channel(since it has not been closed inside health check func) to unblock
   539  // onGoAway/onClose goroutine.
   540  func (s) TestHealthCheckWithoutSetConnectivityStateCalledAddrConnShutDown(t *testing.T) {
   541  	watchFunc := func(s *testHealthServer, in *healthpb.HealthCheckRequest, stream healthgrpc.Health_WatchServer) error {
   542  		if in.Service != "delay" {
   543  			return status.Error(codes.FailedPrecondition,
   544  				"this special Watch function only handles request with service name to be \"delay\"")
   545  		}
   546  		// Do nothing to mock a delay of health check response from server side.
   547  		// This case is to help with the test that covers the condition that setConnectivityState is not
   548  		// called inside HealthCheckFunc before the func returns.
   549  		select {
   550  		case <-stream.Context().Done():
   551  		case <-time.After(5 * time.Second):
   552  		}
   553  		return nil
   554  	}
   555  	_, lis, ts := setupServer(t, watchFunc)
   556  	ts.SetServingStatus("delay", healthpb.HealthCheckResponse_SERVING)
   557  
   558  	hcEnterChan, hcExitChan, testHealthCheckFuncWrapper := setupHealthCheckWrapper()
   559  	_, r := setupClient(t, &clientConfig{testHealthCheckFuncWrapper: testHealthCheckFuncWrapper})
   560  
   561  	// The serviceName "delay" is specially handled at server side, where response will not be sent
   562  	// back to client immediately upon receiving the request (client should receive no response until
   563  	// test ends).
   564  	sc := parseServiceConfig(t, r, `{
   565  	"healthCheckConfig": {
   566  		"serviceName": "delay"
   567  	},
   568  	"loadBalancingConfig": [{"round_robin":{}}]
   569  }`)
   570  	r.UpdateState(resolver.State{
   571  		Addresses:     []resolver.Address{{Addr: lis.Addr().String()}},
   572  		ServiceConfig: sc,
   573  	})
   574  
   575  	select {
   576  	case <-hcExitChan:
   577  		t.Fatal("Health check function has exited, which is not expected.")
   578  	default:
   579  	}
   580  
   581  	select {
   582  	case <-hcEnterChan:
   583  	case <-time.After(5 * time.Second):
   584  		t.Fatal("Health check function has not been invoked after 5s.")
   585  	}
   586  	// trigger teardown of the ac, ac in SHUTDOWN state
   587  	r.UpdateState(resolver.State{Addresses: []resolver.Address{{Addr: "fake address"}}, ServiceConfig: sc})
   588  
   589  	// The health check func should exit without calling the setConnectivityState func, as server hasn't sent
   590  	// any response.
   591  	select {
   592  	case <-hcExitChan:
   593  	case <-time.After(5 * time.Second):
   594  		t.Fatal("Health check function has not exited after 5s.")
   595  	}
   596  	// The deferred leakcheck will check whether there's leaked goroutine, which is an indication
   597  	// whether we closes the skipReset channel to unblock onGoAway/onClose goroutine.
   598  }
   599  
   600  // This test is to test the logic in the createTransport after the health check function returns which
   601  // closes the allowedToReset channel(since it has not been closed inside health check func) to unblock
   602  // onGoAway/onClose goroutine.
   603  func (s) TestHealthCheckWithoutSetConnectivityStateCalled(t *testing.T) {
   604  	watchFunc := func(s *testHealthServer, in *healthpb.HealthCheckRequest, stream healthgrpc.Health_WatchServer) error {
   605  		if in.Service != "delay" {
   606  			return status.Error(codes.FailedPrecondition,
   607  				"this special Watch function only handles request with service name to be \"delay\"")
   608  		}
   609  		// Do nothing to mock a delay of health check response from server side.
   610  		// This case is to help with the test that covers the condition that setConnectivityState is not
   611  		// called inside HealthCheckFunc before the func returns.
   612  		select {
   613  		case <-stream.Context().Done():
   614  		case <-time.After(5 * time.Second):
   615  		}
   616  		return nil
   617  	}
   618  	s, lis, ts := setupServer(t, watchFunc)
   619  	ts.SetServingStatus("delay", healthpb.HealthCheckResponse_SERVING)
   620  
   621  	hcEnterChan, hcExitChan, testHealthCheckFuncWrapper := setupHealthCheckWrapper()
   622  	_, r := setupClient(t, &clientConfig{testHealthCheckFuncWrapper: testHealthCheckFuncWrapper})
   623  
   624  	// The serviceName "delay" is specially handled at server side, where response will not be sent
   625  	// back to client immediately upon receiving the request (client should receive no response until
   626  	// test ends).
   627  	r.UpdateState(resolver.State{
   628  		Addresses: []resolver.Address{{Addr: lis.Addr().String()}},
   629  		ServiceConfig: parseServiceConfig(t, r, `{
   630  	"healthCheckConfig": {
   631  		"serviceName": "delay"
   632  	},
   633  	"loadBalancingConfig": [{"round_robin":{}}]
   634  }`)})
   635  
   636  	select {
   637  	case <-hcExitChan:
   638  		t.Fatal("Health check function has exited, which is not expected.")
   639  	default:
   640  	}
   641  
   642  	select {
   643  	case <-hcEnterChan:
   644  	case <-time.After(5 * time.Second):
   645  		t.Fatal("Health check function has not been invoked after 5s.")
   646  	}
   647  	// trigger transport being closed
   648  	s.Stop()
   649  
   650  	// The health check func should exit without calling the setConnectivityState func, as server hasn't sent
   651  	// any response.
   652  	select {
   653  	case <-hcExitChan:
   654  	case <-time.After(5 * time.Second):
   655  		t.Fatal("Health check function has not exited after 5s.")
   656  	}
   657  	// The deferred leakcheck will check whether there's leaked goroutine, which is an indication
   658  	// whether we closes the allowedToReset channel to unblock onGoAway/onClose goroutine.
   659  }
   660  
   661  func testHealthCheckDisableWithDialOption(t *testing.T, addr string) {
   662  	hcEnterChan, _, testHealthCheckFuncWrapper := setupHealthCheckWrapper()
   663  	cc, r := setupClient(t, &clientConfig{
   664  		testHealthCheckFuncWrapper: testHealthCheckFuncWrapper,
   665  		extraDialOption:            []grpc.DialOption{grpc.WithDisableHealthCheck()},
   666  	})
   667  	tc := testgrpc.NewTestServiceClient(cc)
   668  	r.UpdateState(resolver.State{
   669  		Addresses: []resolver.Address{{Addr: addr}},
   670  		ServiceConfig: parseServiceConfig(t, r, `{
   671  	"healthCheckConfig": {
   672  		"serviceName": "foo"
   673  	},
   674  	"loadBalancingConfig": [{"round_robin":{}}]
   675  }`)})
   676  
   677  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   678  	defer cancel()
   679  	// send some rpcs to make sure transport has been created and is ready for use.
   680  	if err := verifyResultWithDelay(func() (bool, error) {
   681  		if _, err := tc.EmptyCall(ctx, &testpb.Empty{}); err != nil {
   682  			return false, fmt.Errorf("TestService/EmptyCall(_, _) = _, %v, want _, <nil>", err)
   683  		}
   684  		return true, nil
   685  	}); err != nil {
   686  		t.Fatal(err)
   687  	}
   688  
   689  	select {
   690  	case <-hcEnterChan:
   691  		t.Fatal("Health check function has exited, which is not expected.")
   692  	default:
   693  	}
   694  }
   695  
   696  func testHealthCheckDisableWithBalancer(t *testing.T, addr string) {
   697  	hcEnterChan, _, testHealthCheckFuncWrapper := setupHealthCheckWrapper()
   698  	cc, r := setupClient(t, &clientConfig{
   699  		testHealthCheckFuncWrapper: testHealthCheckFuncWrapper,
   700  	})
   701  	tc := testgrpc.NewTestServiceClient(cc)
   702  	r.UpdateState(resolver.State{
   703  		Addresses: []resolver.Address{{Addr: addr}},
   704  		ServiceConfig: parseServiceConfig(t, r, `{
   705  	"healthCheckConfig": {
   706  		"serviceName": "foo"
   707  	},
   708  	"loadBalancingConfig": [{"pick_first":{}}]
   709  }`)})
   710  
   711  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   712  	defer cancel()
   713  	// send some rpcs to make sure transport has been created and is ready for use.
   714  	if err := verifyResultWithDelay(func() (bool, error) {
   715  		if _, err := tc.EmptyCall(ctx, &testpb.Empty{}); err != nil {
   716  			return false, fmt.Errorf("TestService/EmptyCall(_, _) = _, %v, want _, <nil>", err)
   717  		}
   718  		return true, nil
   719  	}); err != nil {
   720  		t.Fatal(err)
   721  	}
   722  
   723  	select {
   724  	case <-hcEnterChan:
   725  		t.Fatal("Health check function has started, which is not expected.")
   726  	default:
   727  	}
   728  }
   729  
   730  func testHealthCheckDisableWithServiceConfig(t *testing.T, addr string) {
   731  	hcEnterChan, _, testHealthCheckFuncWrapper := setupHealthCheckWrapper()
   732  	cc, r := setupClient(t, &clientConfig{testHealthCheckFuncWrapper: testHealthCheckFuncWrapper})
   733  	tc := testgrpc.NewTestServiceClient(cc)
   734  	r.UpdateState(resolver.State{Addresses: []resolver.Address{{Addr: addr}}})
   735  
   736  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   737  	defer cancel()
   738  	// send some rpcs to make sure transport has been created and is ready for use.
   739  	if err := verifyResultWithDelay(func() (bool, error) {
   740  		if _, err := tc.EmptyCall(ctx, &testpb.Empty{}); err != nil {
   741  			return false, fmt.Errorf("TestService/EmptyCall(_, _) = _, %v, want _, <nil>", err)
   742  		}
   743  		return true, nil
   744  	}); err != nil {
   745  		t.Fatal(err)
   746  	}
   747  
   748  	select {
   749  	case <-hcEnterChan:
   750  		t.Fatal("Health check function has started, which is not expected.")
   751  	default:
   752  	}
   753  }
   754  
   755  func (s) TestHealthCheckDisable(t *testing.T) {
   756  	_, lis, ts := setupServer(t, nil)
   757  	ts.SetServingStatus("foo", healthpb.HealthCheckResponse_SERVING)
   758  
   759  	// test client side disabling configuration.
   760  	testHealthCheckDisableWithDialOption(t, lis.Addr().String())
   761  	testHealthCheckDisableWithBalancer(t, lis.Addr().String())
   762  	testHealthCheckDisableWithServiceConfig(t, lis.Addr().String())
   763  }
   764  
   765  func (s) TestHealthCheckChannelzCountingCallSuccess(t *testing.T) {
   766  	watchFunc := func(s *testHealthServer, in *healthpb.HealthCheckRequest, stream healthgrpc.Health_WatchServer) error {
   767  		if in.Service != "channelzSuccess" {
   768  			return status.Error(codes.FailedPrecondition,
   769  				"this special Watch function only handles request with service name to be \"channelzSuccess\"")
   770  		}
   771  		return status.Error(codes.OK, "fake success")
   772  	}
   773  	_, lis, _ := setupServer(t, watchFunc)
   774  
   775  	_, r := setupClient(t, nil)
   776  	r.UpdateState(resolver.State{
   777  		Addresses: []resolver.Address{{Addr: lis.Addr().String()}},
   778  		ServiceConfig: parseServiceConfig(t, r, `{
   779  	"healthCheckConfig": {
   780  		"serviceName": "channelzSuccess"
   781  	},
   782  	"loadBalancingConfig": [{"round_robin":{}}]
   783  }`)})
   784  
   785  	if err := verifyResultWithDelay(func() (bool, error) {
   786  		cm, _ := channelz.GetTopChannels(0, 0)
   787  		if len(cm) == 0 {
   788  			return false, errors.New("channelz.GetTopChannels return 0 top channel")
   789  		}
   790  		if len(cm[0].SubChans) == 0 {
   791  			return false, errors.New("there is 0 subchannel")
   792  		}
   793  		var id int64
   794  		for k := range cm[0].SubChans {
   795  			id = k
   796  			break
   797  		}
   798  		scm := channelz.GetSubChannel(id)
   799  		if scm == nil || scm.ChannelData == nil {
   800  			return false, errors.New("nil subchannel metric or nil subchannel metric ChannelData returned")
   801  		}
   802  		// exponential backoff retry may result in more than one health check call.
   803  		if scm.ChannelData.CallsStarted > 0 && scm.ChannelData.CallsSucceeded > 0 && scm.ChannelData.CallsFailed == 0 {
   804  			return true, nil
   805  		}
   806  		return false, fmt.Errorf("got %d CallsStarted, %d CallsSucceeded, want >0 >0", scm.ChannelData.CallsStarted, scm.ChannelData.CallsSucceeded)
   807  	}); err != nil {
   808  		t.Fatal(err)
   809  	}
   810  }
   811  
   812  func (s) TestHealthCheckChannelzCountingCallFailure(t *testing.T) {
   813  	watchFunc := func(s *testHealthServer, in *healthpb.HealthCheckRequest, stream healthgrpc.Health_WatchServer) error {
   814  		if in.Service != "channelzFailure" {
   815  			return status.Error(codes.FailedPrecondition,
   816  				"this special Watch function only handles request with service name to be \"channelzFailure\"")
   817  		}
   818  		return status.Error(codes.Internal, "fake failure")
   819  	}
   820  	_, lis, _ := setupServer(t, watchFunc)
   821  
   822  	_, r := setupClient(t, nil)
   823  	r.UpdateState(resolver.State{
   824  		Addresses: []resolver.Address{{Addr: lis.Addr().String()}},
   825  		ServiceConfig: parseServiceConfig(t, r, `{
   826  	"healthCheckConfig": {
   827  		"serviceName": "channelzFailure"
   828  	},
   829  	"loadBalancingConfig": [{"round_robin":{}}]
   830  }`)})
   831  
   832  	if err := verifyResultWithDelay(func() (bool, error) {
   833  		cm, _ := channelz.GetTopChannels(0, 0)
   834  		if len(cm) == 0 {
   835  			return false, errors.New("channelz.GetTopChannels return 0 top channel")
   836  		}
   837  		if len(cm[0].SubChans) == 0 {
   838  			return false, errors.New("there is 0 subchannel")
   839  		}
   840  		var id int64
   841  		for k := range cm[0].SubChans {
   842  			id = k
   843  			break
   844  		}
   845  		scm := channelz.GetSubChannel(id)
   846  		if scm == nil || scm.ChannelData == nil {
   847  			return false, errors.New("nil subchannel metric or nil subchannel metric ChannelData returned")
   848  		}
   849  		// exponential backoff retry may result in more than one health check call.
   850  		if scm.ChannelData.CallsStarted > 0 && scm.ChannelData.CallsFailed > 0 && scm.ChannelData.CallsSucceeded == 0 {
   851  			return true, nil
   852  		}
   853  		return false, fmt.Errorf("got %d CallsStarted, %d CallsFailed, want >0, >0", scm.ChannelData.CallsStarted, scm.ChannelData.CallsFailed)
   854  	}); err != nil {
   855  		t.Fatal(err)
   856  	}
   857  }
   858  
   859  // healthCheck is a helper function to make a unary health check RPC and return
   860  // the response.
   861  func healthCheck(d time.Duration, cc *grpc.ClientConn, service string) (*healthpb.HealthCheckResponse, error) {
   862  	ctx, cancel := context.WithTimeout(context.Background(), d)
   863  	defer cancel()
   864  	hc := healthgrpc.NewHealthClient(cc)
   865  	return hc.Check(ctx, &healthpb.HealthCheckRequest{Service: service})
   866  }
   867  
   868  // verifyHealthCheckStatus is a helper function to verify that the current
   869  // health status of the service matches the one passed in 'wantStatus'.
   870  func verifyHealthCheckStatus(t *testing.T, d time.Duration, cc *grpc.ClientConn, service string, wantStatus healthpb.HealthCheckResponse_ServingStatus) {
   871  	t.Helper()
   872  	resp, err := healthCheck(d, cc, service)
   873  	if err != nil {
   874  		t.Fatalf("Health/Check(_, _) = _, %v, want _, <nil>", err)
   875  	}
   876  	if resp.Status != wantStatus {
   877  		t.Fatalf("Got the serving status %v, want %v", resp.Status, wantStatus)
   878  	}
   879  }
   880  
   881  // verifyHealthCheckErrCode is a helper function to verify that a unary health
   882  // check RPC returns an error with a code set to 'wantCode'.
   883  func verifyHealthCheckErrCode(t *testing.T, d time.Duration, cc *grpc.ClientConn, service string, wantCode codes.Code) {
   884  	t.Helper()
   885  	if _, err := healthCheck(d, cc, service); status.Code(err) != wantCode {
   886  		t.Fatalf("Health/Check() got errCode %v, want %v", status.Code(err), wantCode)
   887  	}
   888  }
   889  
   890  // newHealthCheckStream is a helper function to start a health check streaming
   891  // RPC, and returns the stream.
   892  func newHealthCheckStream(t *testing.T, cc *grpc.ClientConn, service string) (healthgrpc.Health_WatchClient, context.CancelFunc) {
   893  	t.Helper()
   894  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   895  	hc := healthgrpc.NewHealthClient(cc)
   896  	stream, err := hc.Watch(ctx, &healthpb.HealthCheckRequest{Service: service})
   897  	if err != nil {
   898  		t.Fatalf("hc.Watch(_, %v) failed: %v", service, err)
   899  	}
   900  	return stream, cancel
   901  }
   902  
   903  // healthWatchChecker is a helper function to verify that the next health
   904  // status returned on the given stream matches the one passed in 'wantStatus'.
   905  func healthWatchChecker(t *testing.T, stream healthgrpc.Health_WatchClient, wantStatus healthpb.HealthCheckResponse_ServingStatus) {
   906  	t.Helper()
   907  	response, err := stream.Recv()
   908  	if err != nil {
   909  		t.Fatalf("stream.Recv() failed: %v", err)
   910  	}
   911  	if response.Status != wantStatus {
   912  		t.Fatalf("got servingStatus %v, want %v", response.Status, wantStatus)
   913  	}
   914  }
   915  
   916  // TestHealthCheckSuccess invokes the unary Check() RPC on the health server in
   917  // a successful case.
   918  func (s) TestHealthCheckSuccess(t *testing.T) {
   919  	for _, e := range listTestEnv() {
   920  		testHealthCheckSuccess(t, e)
   921  	}
   922  }
   923  
   924  func testHealthCheckSuccess(t *testing.T, e env) {
   925  	te := newTest(t, e)
   926  	te.enableHealthServer = true
   927  	te.startServer(&testServer{security: e.security})
   928  	te.setHealthServingStatus(defaultHealthService, healthpb.HealthCheckResponse_SERVING)
   929  	defer te.tearDown()
   930  
   931  	verifyHealthCheckErrCode(t, 1*time.Second, te.clientConn(), defaultHealthService, codes.OK)
   932  }
   933  
   934  // TestHealthCheckFailure invokes the unary Check() RPC on the health server
   935  // with an expired context and expects the RPC to fail.
   936  func (s) TestHealthCheckFailure(t *testing.T) {
   937  	for _, e := range listTestEnv() {
   938  		testHealthCheckFailure(t, e)
   939  	}
   940  }
   941  
   942  func testHealthCheckFailure(t *testing.T, e env) {
   943  	te := newTest(t, e)
   944  	te.declareLogNoise(
   945  		"Failed to dial ",
   946  		"grpc: the client connection is closing; please retry",
   947  	)
   948  	te.enableHealthServer = true
   949  	te.startServer(&testServer{security: e.security})
   950  	te.setHealthServingStatus(defaultHealthService, healthpb.HealthCheckResponse_SERVING)
   951  	defer te.tearDown()
   952  
   953  	verifyHealthCheckErrCode(t, 0*time.Second, te.clientConn(), defaultHealthService, codes.DeadlineExceeded)
   954  	awaitNewConnLogOutput()
   955  }
   956  
   957  // TestHealthCheckOff makes a unary Check() RPC on the health server where the
   958  // health status of the defaultHealthService is not set, and therefore expects
   959  // an error code 'codes.NotFound'.
   960  func (s) TestHealthCheckOff(t *testing.T) {
   961  	for _, e := range listTestEnv() {
   962  		// TODO(bradfitz): Temporarily skip this env due to #619.
   963  		if e.name == "handler-tls" {
   964  			continue
   965  		}
   966  		testHealthCheckOff(t, e)
   967  	}
   968  }
   969  
   970  func testHealthCheckOff(t *testing.T, e env) {
   971  	te := newTest(t, e)
   972  	te.enableHealthServer = true
   973  	te.startServer(&testServer{security: e.security})
   974  	defer te.tearDown()
   975  
   976  	verifyHealthCheckErrCode(t, 1*time.Second, te.clientConn(), defaultHealthService, codes.NotFound)
   977  }
   978  
   979  // TestHealthWatchMultipleClients makes a streaming Watch() RPC on the health
   980  // server with multiple clients and expects the same status on both streams.
   981  func (s) TestHealthWatchMultipleClients(t *testing.T) {
   982  	for _, e := range listTestEnv() {
   983  		testHealthWatchMultipleClients(t, e)
   984  	}
   985  }
   986  
   987  func testHealthWatchMultipleClients(t *testing.T, e env) {
   988  	te := newTest(t, e)
   989  	te.enableHealthServer = true
   990  	te.startServer(&testServer{security: e.security})
   991  	defer te.tearDown()
   992  
   993  	cc := te.clientConn()
   994  	stream1, cf1 := newHealthCheckStream(t, cc, defaultHealthService)
   995  	defer cf1()
   996  	healthWatchChecker(t, stream1, healthpb.HealthCheckResponse_SERVICE_UNKNOWN)
   997  
   998  	stream2, cf2 := newHealthCheckStream(t, cc, defaultHealthService)
   999  	defer cf2()
  1000  	healthWatchChecker(t, stream2, healthpb.HealthCheckResponse_SERVICE_UNKNOWN)
  1001  
  1002  	te.setHealthServingStatus(defaultHealthService, healthpb.HealthCheckResponse_NOT_SERVING)
  1003  	healthWatchChecker(t, stream1, healthpb.HealthCheckResponse_NOT_SERVING)
  1004  	healthWatchChecker(t, stream2, healthpb.HealthCheckResponse_NOT_SERVING)
  1005  }
  1006  
  1007  // TestHealthWatchSameStatusmakes a streaming Watch() RPC on the health server
  1008  // and makes sure that the health status of the server is as expected after
  1009  // multiple calls to SetServingStatus with the same status.
  1010  func (s) TestHealthWatchSameStatus(t *testing.T) {
  1011  	for _, e := range listTestEnv() {
  1012  		testHealthWatchSameStatus(t, e)
  1013  	}
  1014  }
  1015  
  1016  func testHealthWatchSameStatus(t *testing.T, e env) {
  1017  	te := newTest(t, e)
  1018  	te.enableHealthServer = true
  1019  	te.startServer(&testServer{security: e.security})
  1020  	defer te.tearDown()
  1021  
  1022  	stream, cf := newHealthCheckStream(t, te.clientConn(), defaultHealthService)
  1023  	defer cf()
  1024  
  1025  	healthWatchChecker(t, stream, healthpb.HealthCheckResponse_SERVICE_UNKNOWN)
  1026  	te.setHealthServingStatus(defaultHealthService, healthpb.HealthCheckResponse_SERVING)
  1027  	healthWatchChecker(t, stream, healthpb.HealthCheckResponse_SERVING)
  1028  	te.setHealthServingStatus(defaultHealthService, healthpb.HealthCheckResponse_SERVING)
  1029  	te.setHealthServingStatus(defaultHealthService, healthpb.HealthCheckResponse_NOT_SERVING)
  1030  	healthWatchChecker(t, stream, healthpb.HealthCheckResponse_NOT_SERVING)
  1031  }
  1032  
  1033  // TestHealthWatchServiceStatusSetBeforeStartingServer starts a health server
  1034  // on which the health status for the defaultService is set before the gRPC
  1035  // server is started, and expects the correct health status to be returned.
  1036  func (s) TestHealthWatchServiceStatusSetBeforeStartingServer(t *testing.T) {
  1037  	for _, e := range listTestEnv() {
  1038  		testHealthWatchSetServiceStatusBeforeStartingServer(t, e)
  1039  	}
  1040  }
  1041  
  1042  func testHealthWatchSetServiceStatusBeforeStartingServer(t *testing.T, e env) {
  1043  	hs := health.NewServer()
  1044  	te := newTest(t, e)
  1045  	te.healthServer = hs
  1046  	hs.SetServingStatus(defaultHealthService, healthpb.HealthCheckResponse_SERVING)
  1047  	te.startServer(&testServer{security: e.security})
  1048  	defer te.tearDown()
  1049  
  1050  	stream, cf := newHealthCheckStream(t, te.clientConn(), defaultHealthService)
  1051  	defer cf()
  1052  	healthWatchChecker(t, stream, healthpb.HealthCheckResponse_SERVING)
  1053  }
  1054  
  1055  // TestHealthWatchDefaultStatusChange verifies the simple case where the
  1056  // service starts off with a SERVICE_UNKNOWN status (because SetServingStatus
  1057  // hasn't been called yet) and then moves to SERVING after SetServingStatus is
  1058  // called.
  1059  func (s) TestHealthWatchDefaultStatusChange(t *testing.T) {
  1060  	for _, e := range listTestEnv() {
  1061  		testHealthWatchDefaultStatusChange(t, e)
  1062  	}
  1063  }
  1064  
  1065  func testHealthWatchDefaultStatusChange(t *testing.T, e env) {
  1066  	te := newTest(t, e)
  1067  	te.enableHealthServer = true
  1068  	te.startServer(&testServer{security: e.security})
  1069  	defer te.tearDown()
  1070  
  1071  	stream, cf := newHealthCheckStream(t, te.clientConn(), defaultHealthService)
  1072  	defer cf()
  1073  	healthWatchChecker(t, stream, healthpb.HealthCheckResponse_SERVICE_UNKNOWN)
  1074  	te.setHealthServingStatus(defaultHealthService, healthpb.HealthCheckResponse_SERVING)
  1075  	healthWatchChecker(t, stream, healthpb.HealthCheckResponse_SERVING)
  1076  }
  1077  
  1078  // TestHealthWatchSetServiceStatusBeforeClientCallsWatch verifies the case
  1079  // where the health status is set to SERVING before the client calls Watch().
  1080  func (s) TestHealthWatchSetServiceStatusBeforeClientCallsWatch(t *testing.T) {
  1081  	for _, e := range listTestEnv() {
  1082  		testHealthWatchSetServiceStatusBeforeClientCallsWatch(t, e)
  1083  	}
  1084  }
  1085  
  1086  func testHealthWatchSetServiceStatusBeforeClientCallsWatch(t *testing.T, e env) {
  1087  	te := newTest(t, e)
  1088  	te.enableHealthServer = true
  1089  	te.startServer(&testServer{security: e.security})
  1090  	te.setHealthServingStatus(defaultHealthService, healthpb.HealthCheckResponse_SERVING)
  1091  	defer te.tearDown()
  1092  
  1093  	stream, cf := newHealthCheckStream(t, te.clientConn(), defaultHealthService)
  1094  	defer cf()
  1095  	healthWatchChecker(t, stream, healthpb.HealthCheckResponse_SERVING)
  1096  }
  1097  
  1098  // TestHealthWatchOverallServerHealthChange verifies setting the overall status
  1099  // of the server by using the empty service name.
  1100  func (s) TestHealthWatchOverallServerHealthChange(t *testing.T) {
  1101  	for _, e := range listTestEnv() {
  1102  		testHealthWatchOverallServerHealthChange(t, e)
  1103  	}
  1104  }
  1105  
  1106  func testHealthWatchOverallServerHealthChange(t *testing.T, e env) {
  1107  	te := newTest(t, e)
  1108  	te.enableHealthServer = true
  1109  	te.startServer(&testServer{security: e.security})
  1110  	defer te.tearDown()
  1111  
  1112  	stream, cf := newHealthCheckStream(t, te.clientConn(), "")
  1113  	defer cf()
  1114  	healthWatchChecker(t, stream, healthpb.HealthCheckResponse_SERVING)
  1115  	te.setHealthServingStatus("", healthpb.HealthCheckResponse_NOT_SERVING)
  1116  	healthWatchChecker(t, stream, healthpb.HealthCheckResponse_NOT_SERVING)
  1117  }
  1118  
  1119  // TestUnknownHandler verifies that an expected error is returned (by setting
  1120  // the unknownHandler on the server) for a service which is not exposed to the
  1121  // client.
  1122  func (s) TestUnknownHandler(t *testing.T) {
  1123  	// An example unknownHandler that returns a different code and a different
  1124  	// method, making sure that we do not expose what methods are implemented to
  1125  	// a client that is not authenticated.
  1126  	unknownHandler := func(srv any, stream grpc.ServerStream) error {
  1127  		return status.Error(codes.Unauthenticated, "user unauthenticated")
  1128  	}
  1129  	for _, e := range listTestEnv() {
  1130  		// TODO(bradfitz): Temporarily skip this env due to #619.
  1131  		if e.name == "handler-tls" {
  1132  			continue
  1133  		}
  1134  		testUnknownHandler(t, e, unknownHandler)
  1135  	}
  1136  }
  1137  
  1138  func testUnknownHandler(t *testing.T, e env, unknownHandler grpc.StreamHandler) {
  1139  	te := newTest(t, e)
  1140  	te.unknownHandler = unknownHandler
  1141  	te.startServer(&testServer{security: e.security})
  1142  	defer te.tearDown()
  1143  	verifyHealthCheckErrCode(t, 1*time.Second, te.clientConn(), "", codes.Unauthenticated)
  1144  }
  1145  
  1146  // TestHealthCheckServingStatus makes a streaming Watch() RPC on the health
  1147  // server and verifies a bunch of health status transitions.
  1148  func (s) TestHealthCheckServingStatus(t *testing.T) {
  1149  	for _, e := range listTestEnv() {
  1150  		testHealthCheckServingStatus(t, e)
  1151  	}
  1152  }
  1153  
  1154  func testHealthCheckServingStatus(t *testing.T, e env) {
  1155  	te := newTest(t, e)
  1156  	te.enableHealthServer = true
  1157  	te.startServer(&testServer{security: e.security})
  1158  	defer te.tearDown()
  1159  
  1160  	cc := te.clientConn()
  1161  	verifyHealthCheckStatus(t, 1*time.Second, cc, "", healthpb.HealthCheckResponse_SERVING)
  1162  	verifyHealthCheckErrCode(t, 1*time.Second, cc, defaultHealthService, codes.NotFound)
  1163  	te.setHealthServingStatus(defaultHealthService, healthpb.HealthCheckResponse_SERVING)
  1164  	verifyHealthCheckStatus(t, 1*time.Second, cc, defaultHealthService, healthpb.HealthCheckResponse_SERVING)
  1165  	te.setHealthServingStatus(defaultHealthService, healthpb.HealthCheckResponse_NOT_SERVING)
  1166  	verifyHealthCheckStatus(t, 1*time.Second, cc, defaultHealthService, healthpb.HealthCheckResponse_NOT_SERVING)
  1167  }