github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/grpc/test/context_canceled_test.go (about)

     1  /*
     2   *
     3   * Copyright 2019 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  	"testing"
    24  	"time"
    25  
    26  	grpc "github.com/hxx258456/ccgo/grpc"
    27  	"github.com/hxx258456/ccgo/grpc/codes"
    28  	"github.com/hxx258456/ccgo/grpc/encoding/gzip"
    29  	"github.com/hxx258456/ccgo/grpc/internal/stubserver"
    30  	"github.com/hxx258456/ccgo/grpc/metadata"
    31  	"github.com/hxx258456/ccgo/grpc/status"
    32  	testpb "github.com/hxx258456/ccgo/grpc/test/grpc_testing"
    33  )
    34  
    35  func (s) TestContextCanceled(t *testing.T) {
    36  	ss := &stubserver.StubServer{
    37  		FullDuplexCallF: func(stream testpb.TestService_FullDuplexCallServer) error {
    38  			stream.SetTrailer(metadata.New(map[string]string{"a": "b"}))
    39  			return status.Error(codes.PermissionDenied, "perm denied")
    40  		},
    41  	}
    42  	if err := ss.Start(nil); err != nil {
    43  		t.Fatalf("Error starting endpoint server: %v", err)
    44  	}
    45  	defer ss.Stop()
    46  
    47  	// Runs 10 rounds of tests with the given delay and returns counts of status codes.
    48  	// Fails in case of trailer/status code inconsistency.
    49  	const cntRetry uint = 10
    50  	runTest := func(delay time.Duration) (cntCanceled, cntPermDenied uint) {
    51  		for i := uint(0); i < cntRetry; i++ {
    52  			ctx, cancel := context.WithTimeout(context.Background(), delay)
    53  			defer cancel()
    54  
    55  			str, err := ss.Client.FullDuplexCall(ctx)
    56  			if err != nil {
    57  				continue
    58  			}
    59  
    60  			_, err = str.Recv()
    61  			if err == nil {
    62  				t.Fatalf("non-nil error expected from Recv()")
    63  			}
    64  
    65  			_, trlOk := str.Trailer()["a"]
    66  			switch status.Code(err) {
    67  			case codes.PermissionDenied:
    68  				if !trlOk {
    69  					t.Fatalf(`status err: %v; wanted key "a" in trailer but didn't get it`, err)
    70  				}
    71  				cntPermDenied++
    72  			case codes.DeadlineExceeded:
    73  				if trlOk {
    74  					t.Fatalf(`status err: %v; didn't want key "a" in trailer but got it`, err)
    75  				}
    76  				cntCanceled++
    77  			default:
    78  				t.Fatalf(`unexpected status err: %v`, err)
    79  			}
    80  		}
    81  		return cntCanceled, cntPermDenied
    82  	}
    83  
    84  	// Tries to find the delay that causes canceled/perm denied race.
    85  	canceledOk, permDeniedOk := false, false
    86  	for lower, upper := time.Duration(0), 2*time.Millisecond; lower <= upper; {
    87  		delay := lower + (upper-lower)/2
    88  		cntCanceled, cntPermDenied := runTest(delay)
    89  		if cntPermDenied > 0 && cntCanceled > 0 {
    90  			// Delay that causes the race is found.
    91  			return
    92  		}
    93  
    94  		// Set OK flags.
    95  		if cntCanceled > 0 {
    96  			canceledOk = true
    97  		}
    98  		if cntPermDenied > 0 {
    99  			permDeniedOk = true
   100  		}
   101  
   102  		if cntPermDenied == 0 {
   103  			// No perm denied, increase the delay.
   104  			lower += (upper-lower)/10 + 1
   105  		} else {
   106  			// All perm denied, decrease the delay.
   107  			upper -= (upper-lower)/10 + 1
   108  		}
   109  	}
   110  
   111  	if !canceledOk || !permDeniedOk {
   112  		t.Fatalf(`couldn't find the delay that causes canceled/perm denied race.`)
   113  	}
   114  }
   115  
   116  // To make sure that canceling a stream with compression enabled won't result in
   117  // internal error, compressed flag set with identity or empty encoding.
   118  //
   119  // The root cause is a select race on stream headerChan and ctx. Stream gets
   120  // whether compression is enabled and the compression type from two separate
   121  // functions, both include select with context. If the `case non-ctx:` wins the
   122  // first one, but `case ctx.Done()` wins the second one, the compression info
   123  // will be inconsistent, and it causes internal error.
   124  func (s) TestCancelWhileRecvingWithCompression(t *testing.T) {
   125  	ss := &stubserver.StubServer{
   126  		FullDuplexCallF: func(stream testpb.TestService_FullDuplexCallServer) error {
   127  			for {
   128  				if err := stream.Send(&testpb.StreamingOutputCallResponse{
   129  					Payload: nil,
   130  				}); err != nil {
   131  					return err
   132  				}
   133  			}
   134  		},
   135  	}
   136  	if err := ss.Start(nil); err != nil {
   137  		t.Fatalf("Error starting endpoint server: %v", err)
   138  	}
   139  	defer ss.Stop()
   140  
   141  	for i := 0; i < 10; i++ {
   142  		ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
   143  		s, err := ss.Client.FullDuplexCall(ctx, grpc.UseCompressor(gzip.Name))
   144  		if err != nil {
   145  			t.Fatalf("failed to start bidi streaming RPC: %v", err)
   146  		}
   147  		// Cancel the stream while receiving to trigger the internal error.
   148  		time.AfterFunc(time.Millisecond, cancel)
   149  		for {
   150  			_, err := s.Recv()
   151  			if err != nil {
   152  				if status.Code(err) != codes.Canceled {
   153  					t.Fatalf("recv failed with %v, want Canceled", err)
   154  				}
   155  				break
   156  			}
   157  		}
   158  	}
   159  }