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 }