...

Source file src/google.golang.org/grpc/test/clientconn_test.go

Documentation: google.golang.org/grpc/test

     1  /*
     2   *
     3   * Copyright 2022 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  	"fmt"
    24  	"strings"
    25  	"testing"
    26  	"time"
    27  
    28  	"google.golang.org/grpc"
    29  	"google.golang.org/grpc/codes"
    30  	"google.golang.org/grpc/credentials/insecure"
    31  	"google.golang.org/grpc/internal/channelz"
    32  	testgrpc "google.golang.org/grpc/interop/grpc_testing"
    33  	testpb "google.golang.org/grpc/interop/grpc_testing"
    34  	"google.golang.org/grpc/resolver/manual"
    35  	"google.golang.org/grpc/status"
    36  )
    37  
    38  // TestClientConnClose_WithPendingRPC tests the scenario where the channel has
    39  // not yet received any update from the name resolver and hence RPCs are
    40  // blocking. The test verifies that closing the ClientConn unblocks the RPC with
    41  // the expected error code.
    42  func (s) TestClientConnClose_WithPendingRPC(t *testing.T) {
    43  	r := manual.NewBuilderWithScheme("whatever")
    44  	cc, err := grpc.NewClient(r.Scheme()+":///test.server", grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithResolvers(r))
    45  	if err != nil {
    46  		t.Fatalf("grpc.NewClient() failed: %v", err)
    47  	}
    48  	client := testgrpc.NewTestServiceClient(cc)
    49  
    50  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
    51  	defer cancel()
    52  	doneErrCh := make(chan error, 1)
    53  	go func() {
    54  		// This RPC would block until the ClientConn is closed, because the
    55  		// resolver has not provided its first update yet.
    56  		_, err := client.EmptyCall(ctx, &testpb.Empty{})
    57  		if status.Code(err) != codes.Canceled || !strings.Contains(err.Error(), "client connection is closing") {
    58  			doneErrCh <- fmt.Errorf("EmptyCall() = %v, want %s", err, codes.Canceled)
    59  		}
    60  		doneErrCh <- nil
    61  	}()
    62  
    63  	// Make sure that there is one pending RPC on the ClientConn before attempting
    64  	// to close it. If we don't do this, cc.Close() can happen before the above
    65  	// goroutine gets to make the RPC.
    66  	for {
    67  		if err := ctx.Err(); err != nil {
    68  			t.Fatal(err)
    69  		}
    70  		tcs, _ := channelz.GetTopChannels(0, 0)
    71  		if len(tcs) != 1 {
    72  			t.Fatalf("there should only be one top channel, not %d", len(tcs))
    73  		}
    74  		started := tcs[0].ChannelMetrics.CallsStarted.Load()
    75  		completed := tcs[0].ChannelMetrics.CallsSucceeded.Load() + tcs[0].ChannelMetrics.CallsFailed.Load()
    76  		if (started - completed) == 1 {
    77  			break
    78  		}
    79  		time.Sleep(defaultTestShortTimeout)
    80  	}
    81  	cc.Close()
    82  	if err := <-doneErrCh; err != nil {
    83  		t.Fatal(err)
    84  	}
    85  }
    86  

View as plain text