google.golang.org/grpc@v1.72.2/test/goaway_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 "fmt" 24 "io" 25 "net" 26 "strings" 27 "testing" 28 "time" 29 30 "golang.org/x/net/http2" 31 "google.golang.org/grpc" 32 "google.golang.org/grpc/codes" 33 "google.golang.org/grpc/connectivity" 34 "google.golang.org/grpc/credentials/insecure" 35 "google.golang.org/grpc/internal" 36 "google.golang.org/grpc/internal/grpcsync" 37 "google.golang.org/grpc/internal/grpctest" 38 "google.golang.org/grpc/internal/stubserver" 39 "google.golang.org/grpc/internal/testutils" 40 "google.golang.org/grpc/keepalive" 41 "google.golang.org/grpc/resolver" 42 "google.golang.org/grpc/resolver/manual" 43 "google.golang.org/grpc/status" 44 45 testgrpc "google.golang.org/grpc/interop/grpc_testing" 46 testpb "google.golang.org/grpc/interop/grpc_testing" 47 ) 48 49 // TestGracefulClientOnGoAway attempts to ensure that when the server sends a 50 // GOAWAY (in this test, by configuring max connection age on the server), a 51 // client will never see an error. This requires that the client is appraised 52 // of the GOAWAY and updates its state accordingly before the transport stops 53 // accepting new streams. If a subconn is chosen by a picker and receives the 54 // goaway before creating the stream, an error will occur, but upon transparent 55 // retry, the clientconn will ensure a ready subconn is chosen. 56 func (s) TestGracefulClientOnGoAway(t *testing.T) { 57 const maxConnAge = 100 * time.Millisecond 58 const testTime = maxConnAge * 10 59 lis, err := testutils.LocalTCPListener() 60 if err != nil { 61 t.Fatalf("Failed to create listener: %v", err) 62 } 63 ss := &stubserver.StubServer{ 64 Listener: lis, 65 EmptyCallF: func(context.Context, *testpb.Empty) (*testpb.Empty, error) { 66 return &testpb.Empty{}, nil 67 }, 68 S: grpc.NewServer(grpc.KeepaliveParams(keepalive.ServerParameters{MaxConnectionAge: maxConnAge})), 69 } 70 stubserver.StartTestService(t, ss) 71 defer ss.S.Stop() 72 73 cc, err := grpc.NewClient(lis.Addr().String(), grpc.WithTransportCredentials(insecure.NewCredentials())) 74 if err != nil { 75 t.Fatalf("Failed to dial server: %v", err) 76 } 77 defer cc.Close() 78 c := testgrpc.NewTestServiceClient(cc) 79 80 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 81 defer cancel() 82 endTime := time.Now().Add(testTime) 83 for time.Now().Before(endTime) { 84 if _, err := c.EmptyCall(ctx, &testpb.Empty{}); err != nil { 85 t.Fatalf("EmptyCall(_, _) = _, %v; want _, <nil>", err) 86 } 87 } 88 } 89 90 func (s) TestDetailedGoAwayErrorOnGracefulClosePropagatesToRPCError(t *testing.T) { 91 rpcDoneOnClient := make(chan struct{}) 92 ss := &stubserver.StubServer{ 93 FullDuplexCallF: func(testgrpc.TestService_FullDuplexCallServer) error { 94 <-rpcDoneOnClient 95 return status.Error(codes.Internal, "arbitrary status") 96 }, 97 } 98 sopts := []grpc.ServerOption{ 99 grpc.KeepaliveParams(keepalive.ServerParameters{ 100 MaxConnectionAge: time.Millisecond * 100, 101 MaxConnectionAgeGrace: time.Nanosecond, // ~instantaneously, but non-zero to avoid default 102 }), 103 } 104 if err := ss.Start(sopts); err != nil { 105 t.Fatalf("Error starting endpoint server: %v", err) 106 } 107 defer ss.Stop() 108 109 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 110 defer cancel() 111 stream, err := ss.Client.FullDuplexCall(ctx) 112 if err != nil { 113 t.Fatalf("%v.FullDuplexCall = _, %v, want _, <nil>", ss.Client, err) 114 } 115 const expectedErrorMessageSubstring = "received prior goaway: code: NO_ERROR" 116 _, err = stream.Recv() 117 close(rpcDoneOnClient) 118 if err == nil || !strings.Contains(err.Error(), expectedErrorMessageSubstring) { 119 t.Fatalf("%v.Recv() = _, %v, want _, rpc error containing substring: %q", stream, err, expectedErrorMessageSubstring) 120 } 121 } 122 123 func (s) TestDetailedGoAwayErrorOnAbruptClosePropagatesToRPCError(t *testing.T) { 124 grpctest.TLogger.ExpectError("Client received GoAway with error code ENHANCE_YOUR_CALM and debug data equal to ASCII \"too_many_pings\"") 125 // set the min keepalive time very low so that this test can take 126 // a reasonable amount of time 127 prev := internal.KeepaliveMinPingTime 128 internal.KeepaliveMinPingTime = time.Millisecond 129 defer func() { internal.KeepaliveMinPingTime = prev }() 130 131 rpcDoneOnClient := make(chan struct{}) 132 ss := &stubserver.StubServer{ 133 FullDuplexCallF: func(testgrpc.TestService_FullDuplexCallServer) error { 134 <-rpcDoneOnClient 135 return status.Error(codes.Internal, "arbitrary status") 136 }, 137 } 138 sopts := []grpc.ServerOption{ 139 grpc.KeepaliveEnforcementPolicy(keepalive.EnforcementPolicy{ 140 MinTime: time.Second * 1000, /* arbitrary, large value */ 141 }), 142 } 143 dopts := []grpc.DialOption{ 144 grpc.WithKeepaliveParams(keepalive.ClientParameters{ 145 Time: time.Millisecond, /* should trigger "too many pings" error quickly */ 146 Timeout: time.Second * 1000, /* arbitrary, large value */ 147 PermitWithoutStream: false, 148 }), 149 } 150 if err := ss.Start(sopts, dopts...); err != nil { 151 t.Fatalf("Error starting endpoint server: %v", err) 152 } 153 defer ss.Stop() 154 155 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 156 defer cancel() 157 stream, err := ss.Client.FullDuplexCall(ctx) 158 if err != nil { 159 t.Fatalf("%v.FullDuplexCall = _, %v, want _, <nil>", ss.Client, err) 160 } 161 const expectedErrorMessageSubstring = `received prior goaway: code: ENHANCE_YOUR_CALM, debug data: "too_many_pings"` 162 _, err = stream.Recv() 163 close(rpcDoneOnClient) 164 if err == nil || !strings.Contains(err.Error(), expectedErrorMessageSubstring) { 165 t.Fatalf("%v.Recv() = _, %v, want _, rpc error containing substring: |%v|", stream, err, expectedErrorMessageSubstring) 166 } 167 } 168 169 func (s) TestClientConnCloseAfterGoAwayWithActiveStream(t *testing.T) { 170 for _, e := range listTestEnv() { 171 if e.name == "handler-tls" { 172 continue 173 } 174 testClientConnCloseAfterGoAwayWithActiveStream(t, e) 175 } 176 } 177 178 func testClientConnCloseAfterGoAwayWithActiveStream(t *testing.T, e env) { 179 te := newTest(t, e) 180 te.startServer(&testServer{security: e.security}) 181 defer te.tearDown() 182 cc := te.clientConn() 183 tc := testgrpc.NewTestServiceClient(cc) 184 185 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 186 defer cancel() 187 if _, err := tc.FullDuplexCall(ctx); err != nil { 188 t.Fatalf("%v.FullDuplexCall(_) = _, %v, want _, <nil>", tc, err) 189 } 190 done := make(chan struct{}) 191 go func() { 192 te.srv.GracefulStop() 193 close(done) 194 }() 195 time.Sleep(50 * time.Millisecond) 196 cc.Close() 197 timeout := time.NewTimer(time.Second) 198 select { 199 case <-done: 200 case <-timeout.C: 201 t.Fatalf("Test timed-out.") 202 } 203 } 204 205 func (s) TestServerGoAway(t *testing.T) { 206 for _, e := range listTestEnv() { 207 if e.name == "handler-tls" { 208 continue 209 } 210 testServerGoAway(t, e) 211 } 212 } 213 214 func testServerGoAway(t *testing.T, e env) { 215 te := newTest(t, e) 216 te.userAgent = testAppUA 217 te.startServer(&testServer{security: e.security}) 218 defer te.tearDown() 219 220 cc := te.clientConn() 221 tc := testgrpc.NewTestServiceClient(cc) 222 // Finish an RPC to make sure the connection is good. 223 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 224 defer cancel() 225 if _, err := tc.EmptyCall(ctx, &testpb.Empty{}, grpc.WaitForReady(true)); err != nil { 226 t.Fatalf("TestService/EmptyCall(_, _) = _, %v, want _, <nil>", err) 227 } 228 ch := make(chan struct{}) 229 go func() { 230 te.srv.GracefulStop() 231 close(ch) 232 }() 233 // Loop until the server side GoAway signal is propagated to the client. 234 for { 235 ctx, cancel := context.WithTimeout(context.Background(), defaultTestShortTimeout) 236 if _, err := tc.EmptyCall(ctx, &testpb.Empty{}); err != nil && status.Code(err) != codes.DeadlineExceeded { 237 cancel() 238 break 239 } 240 cancel() 241 } 242 // A new RPC should fail. 243 ctx, cancel = context.WithTimeout(context.Background(), defaultTestTimeout) 244 defer cancel() 245 if _, err := tc.EmptyCall(ctx, &testpb.Empty{}); status.Code(err) != codes.Unavailable && status.Code(err) != codes.Internal { 246 t.Fatalf("TestService/EmptyCall(_, _) = _, %v, want _, %s or %s", err, codes.Unavailable, codes.Internal) 247 } 248 <-ch 249 awaitNewConnLogOutput() 250 } 251 252 func (s) TestServerGoAwayPendingRPC(t *testing.T) { 253 for _, e := range listTestEnv() { 254 if e.name == "handler-tls" { 255 continue 256 } 257 testServerGoAwayPendingRPC(t, e) 258 } 259 } 260 261 func testServerGoAwayPendingRPC(t *testing.T, e env) { 262 te := newTest(t, e) 263 te.userAgent = testAppUA 264 te.declareLogNoise( 265 "transport: http2Client.notifyError got notified that the client transport was broken EOF", 266 "grpc: addrConn.transportMonitor exits due to: grpc: the connection is closing", 267 "grpc: addrConn.resetTransport failed to create client transport: connection error", 268 ) 269 te.startServer(&testServer{security: e.security}) 270 defer te.tearDown() 271 272 cc := te.clientConn() 273 tc := testgrpc.NewTestServiceClient(cc) 274 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 275 stream, err := tc.FullDuplexCall(ctx, grpc.WaitForReady(true)) 276 if err != nil { 277 t.Fatalf("%v.FullDuplexCall(_) = _, %v, want <nil>", tc, err) 278 } 279 // Finish an RPC to make sure the connection is good. 280 if _, err := tc.EmptyCall(ctx, &testpb.Empty{}, grpc.WaitForReady(true)); err != nil { 281 t.Fatalf("%v.EmptyCall(_, _, _) = _, %v, want _, <nil>", tc, err) 282 } 283 ch := make(chan struct{}) 284 go func() { 285 te.srv.GracefulStop() 286 close(ch) 287 }() 288 // Loop until the server side GoAway signal is propagated to the client. 289 start := time.Now() 290 errored := false 291 for time.Since(start) < time.Second { 292 ctx, cancel := context.WithTimeout(context.Background(), defaultTestShortTimeout) 293 _, err := tc.EmptyCall(ctx, &testpb.Empty{}, grpc.WaitForReady(true)) 294 cancel() 295 if err != nil { 296 errored = true 297 break 298 } 299 } 300 if !errored { 301 t.Fatalf("GoAway never received by client") 302 } 303 respParam := []*testpb.ResponseParameters{{Size: 1}} 304 payload, err := newPayload(testpb.PayloadType_COMPRESSABLE, int32(100)) 305 if err != nil { 306 t.Fatal(err) 307 } 308 req := &testpb.StreamingOutputCallRequest{ 309 ResponseType: testpb.PayloadType_COMPRESSABLE, 310 ResponseParameters: respParam, 311 Payload: payload, 312 } 313 // The existing RPC should be still good to proceed. 314 if err := stream.Send(req); err != nil { 315 t.Fatalf("%v.Send(_) = %v, want <nil>", stream, err) 316 } 317 if _, err := stream.Recv(); err != nil { 318 t.Fatalf("%v.Recv() = _, %v, want _, <nil>", stream, err) 319 } 320 // The RPC will run until canceled. 321 cancel() 322 <-ch 323 awaitNewConnLogOutput() 324 } 325 326 func (s) TestServerMultipleGoAwayPendingRPC(t *testing.T) { 327 for _, e := range listTestEnv() { 328 if e.name == "handler-tls" { 329 continue 330 } 331 testServerMultipleGoAwayPendingRPC(t, e) 332 } 333 } 334 335 func testServerMultipleGoAwayPendingRPC(t *testing.T, e env) { 336 te := newTest(t, e) 337 te.userAgent = testAppUA 338 te.declareLogNoise( 339 "transport: http2Client.notifyError got notified that the client transport was broken EOF", 340 "grpc: addrConn.transportMonitor exits due to: grpc: the connection is closing", 341 "grpc: addrConn.resetTransport failed to create client transport: connection error", 342 ) 343 te.startServer(&testServer{security: e.security}) 344 defer te.tearDown() 345 346 cc := te.clientConn() 347 tc := testgrpc.NewTestServiceClient(cc) 348 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 349 stream, err := tc.FullDuplexCall(ctx, grpc.WaitForReady(true)) 350 if err != nil { 351 t.Fatalf("%v.FullDuplexCall(_) = _, %v, want <nil>", tc, err) 352 } 353 // Finish an RPC to make sure the connection is good. 354 if _, err := tc.EmptyCall(ctx, &testpb.Empty{}, grpc.WaitForReady(true)); err != nil { 355 t.Fatalf("%v.EmptyCall(_, _, _) = _, %v, want _, <nil>", tc, err) 356 } 357 ch1 := make(chan struct{}) 358 go func() { 359 te.srv.GracefulStop() 360 close(ch1) 361 }() 362 ch2 := make(chan struct{}) 363 go func() { 364 te.srv.GracefulStop() 365 close(ch2) 366 }() 367 // Loop until the server side GoAway signal is propagated to the client. 368 369 for { 370 ctx, cancel := context.WithTimeout(context.Background(), defaultTestShortTimeout) 371 if _, err := tc.EmptyCall(ctx, &testpb.Empty{}, grpc.WaitForReady(true)); err != nil { 372 cancel() 373 break 374 } 375 cancel() 376 } 377 select { 378 case <-ch1: 379 t.Fatal("GracefulStop() terminated early") 380 case <-ch2: 381 t.Fatal("GracefulStop() terminated early") 382 default: 383 } 384 respParam := []*testpb.ResponseParameters{ 385 { 386 Size: 1, 387 }, 388 } 389 payload, err := newPayload(testpb.PayloadType_COMPRESSABLE, int32(100)) 390 if err != nil { 391 t.Fatal(err) 392 } 393 req := &testpb.StreamingOutputCallRequest{ 394 ResponseType: testpb.PayloadType_COMPRESSABLE, 395 ResponseParameters: respParam, 396 Payload: payload, 397 } 398 // The existing RPC should be still good to proceed. 399 if err := stream.Send(req); err != nil { 400 t.Fatalf("%v.Send(%v) = %v, want <nil>", stream, req, err) 401 } 402 if _, err := stream.Recv(); err != nil { 403 t.Fatalf("%v.Recv() = _, %v, want _, <nil>", stream, err) 404 } 405 if err := stream.CloseSend(); err != nil { 406 t.Fatalf("%v.CloseSend() = %v, want <nil>", stream, err) 407 } 408 409 <-ch1 410 <-ch2 411 cancel() 412 awaitNewConnLogOutput() 413 } 414 415 func (s) TestConcurrentClientConnCloseAndServerGoAway(t *testing.T) { 416 for _, e := range listTestEnv() { 417 if e.name == "handler-tls" { 418 continue 419 } 420 testConcurrentClientConnCloseAndServerGoAway(t, e) 421 } 422 } 423 424 func testConcurrentClientConnCloseAndServerGoAway(t *testing.T, e env) { 425 te := newTest(t, e) 426 te.userAgent = testAppUA 427 te.declareLogNoise( 428 "transport: http2Client.notifyError got notified that the client transport was broken EOF", 429 "grpc: addrConn.transportMonitor exits due to: grpc: the connection is closing", 430 "grpc: addrConn.resetTransport failed to create client transport: connection error", 431 ) 432 te.startServer(&testServer{security: e.security}) 433 defer te.tearDown() 434 435 cc := te.clientConn() 436 tc := testgrpc.NewTestServiceClient(cc) 437 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 438 defer cancel() 439 if _, err := tc.EmptyCall(ctx, &testpb.Empty{}, grpc.WaitForReady(true)); err != nil { 440 t.Fatalf("%v.EmptyCall(_, _, _) = _, %v, want _, <nil>", tc, err) 441 } 442 ch := make(chan struct{}) 443 // Close ClientConn and Server concurrently. 444 go func() { 445 te.srv.GracefulStop() 446 close(ch) 447 }() 448 go func() { 449 cc.Close() 450 }() 451 <-ch 452 } 453 454 func (s) TestConcurrentServerStopAndGoAway(t *testing.T) { 455 for _, e := range listTestEnv() { 456 if e.name == "handler-tls" { 457 continue 458 } 459 testConcurrentServerStopAndGoAway(t, e) 460 } 461 } 462 463 func testConcurrentServerStopAndGoAway(t *testing.T, e env) { 464 te := newTest(t, e) 465 te.userAgent = testAppUA 466 te.declareLogNoise( 467 "transport: http2Client.notifyError got notified that the client transport was broken EOF", 468 "grpc: addrConn.transportMonitor exits due to: grpc: the connection is closing", 469 "grpc: addrConn.resetTransport failed to create client transport: connection error", 470 ) 471 te.startServer(&testServer{security: e.security}) 472 defer te.tearDown() 473 474 cc := te.clientConn() 475 tc := testgrpc.NewTestServiceClient(cc) 476 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 477 defer cancel() 478 stream, err := tc.FullDuplexCall(ctx, grpc.WaitForReady(true)) 479 if err != nil { 480 t.Fatalf("%v.FullDuplexCall(_) = _, %v, want <nil>", tc, err) 481 } 482 483 // Finish an RPC to make sure the connection is good. 484 if _, err := tc.EmptyCall(ctx, &testpb.Empty{}, grpc.WaitForReady(true)); err != nil { 485 t.Fatalf("%v.EmptyCall(_, _, _) = _, %v, want _, <nil>", tc, err) 486 } 487 488 ch := make(chan struct{}) 489 go func() { 490 te.srv.GracefulStop() 491 close(ch) 492 }() 493 // Loop until the server side GoAway signal is propagated to the client. 494 for { 495 ctx, cancel := context.WithTimeout(context.Background(), defaultTestShortTimeout) 496 if _, err := tc.EmptyCall(ctx, &testpb.Empty{}, grpc.WaitForReady(true)); err != nil { 497 cancel() 498 break 499 } 500 cancel() 501 } 502 // Stop the server and close all the connections. 503 te.srv.Stop() 504 respParam := []*testpb.ResponseParameters{ 505 { 506 Size: 1, 507 }, 508 } 509 payload, err := newPayload(testpb.PayloadType_COMPRESSABLE, int32(100)) 510 if err != nil { 511 t.Fatal(err) 512 } 513 req := &testpb.StreamingOutputCallRequest{ 514 ResponseType: testpb.PayloadType_COMPRESSABLE, 515 ResponseParameters: respParam, 516 Payload: payload, 517 } 518 sendStart := time.Now() 519 for { 520 if err := stream.Send(req); err == io.EOF { 521 // stream.Send should eventually send io.EOF 522 break 523 } else if err != nil { 524 // Send should never return a transport-level error. 525 t.Fatalf("stream.Send(%v) = %v; want <nil or io.EOF>", req, err) 526 } 527 if time.Since(sendStart) > 2*time.Second { 528 t.Fatalf("stream.Send(_) did not return io.EOF after 2s") 529 } 530 time.Sleep(time.Millisecond) 531 } 532 if _, err := stream.Recv(); err == nil || err == io.EOF { 533 t.Fatalf("%v.Recv() = _, %v, want _, <non-nil, non-EOF>", stream, err) 534 } 535 <-ch 536 awaitNewConnLogOutput() 537 } 538 539 // Proxies typically send GO_AWAY followed by connection closure a minute or so later. This 540 // test ensures that the connection is re-created after GO_AWAY and not affected by the 541 // subsequent (old) connection closure. 542 func (s) TestGoAwayThenClose(t *testing.T) { 543 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 544 defer cancel() 545 546 lis1, err := testutils.LocalTCPListener() 547 if err != nil { 548 t.Fatalf("Error while listening. Err: %v", err) 549 } 550 551 unaryCallF := func(context.Context, *testpb.SimpleRequest) (*testpb.SimpleResponse, error) { 552 return &testpb.SimpleResponse{}, nil 553 } 554 fullDuplexCallF := func(stream testgrpc.TestService_FullDuplexCallServer) error { 555 if err := stream.Send(&testpb.StreamingOutputCallResponse{}); err != nil { 556 t.Errorf("Unexpected error from send: %v", err) 557 return err 558 } 559 // Wait until a message is received from client 560 _, err := stream.Recv() 561 if err == nil { 562 t.Error("Expected to never receive any message") 563 } 564 return err 565 } 566 ss1 := &stubserver.StubServer{ 567 Listener: lis1, 568 UnaryCallF: unaryCallF, 569 FullDuplexCallF: fullDuplexCallF, 570 S: grpc.NewServer(), 571 } 572 stubserver.StartTestService(t, ss1) 573 defer ss1.S.Stop() 574 575 conn2Established := grpcsync.NewEvent() 576 lis2, err := listenWithNotifyingListener("tcp", "localhost:0", conn2Established) 577 if err != nil { 578 t.Fatalf("Error while listening. Err: %v", err) 579 } 580 ss2 := &stubserver.StubServer{ 581 Listener: lis2, 582 UnaryCallF: unaryCallF, 583 FullDuplexCallF: fullDuplexCallF, 584 S: grpc.NewServer(), 585 } 586 stubserver.StartTestService(t, ss2) 587 defer ss2.S.Stop() 588 589 r := manual.NewBuilderWithScheme("whatever") 590 r.InitialState(resolver.State{Addresses: []resolver.Address{ 591 {Addr: lis1.Addr().String()}, 592 {Addr: lis2.Addr().String()}, 593 }}) 594 cc, err := grpc.NewClient(r.Scheme()+":///", grpc.WithResolvers(r), grpc.WithTransportCredentials(insecure.NewCredentials())) 595 if err != nil { 596 t.Fatalf("Error creating client: %v", err) 597 } 598 defer cc.Close() 599 600 client := testgrpc.NewTestServiceClient(cc) 601 602 // We make a streaming RPC and do an one-message-round-trip to make sure 603 // it's created on connection 1. 604 // 605 // We use a long-lived RPC because it will cause GracefulStop to send 606 // GO_AWAY, but the connection won't get closed until the server stops and 607 // the client receives the error. 608 t.Log("Creating first streaming RPC to server 1.") 609 stream, err := client.FullDuplexCall(ctx) 610 if err != nil { 611 t.Fatalf("FullDuplexCall(_) = _, %v; want _, nil", err) 612 } 613 if _, err = stream.Recv(); err != nil { 614 t.Fatalf("unexpected error from first recv: %v", err) 615 } 616 617 t.Log("Gracefully stopping server 1.") 618 go ss1.S.GracefulStop() 619 620 t.Log("Waiting for the ClientConn to enter IDLE state.") 621 testutils.AwaitState(ctx, t, cc, connectivity.Idle) 622 623 t.Log("Performing another RPC to create a connection to server 2.") 624 if _, err := client.UnaryCall(ctx, &testpb.SimpleRequest{}); err != nil { 625 t.Fatalf("UnaryCall(_) = _, %v; want _, nil", err) 626 } 627 628 t.Log("Waiting for a connection to server 2.") 629 select { 630 case <-conn2Established.Done(): 631 case <-ctx.Done(): 632 t.Fatalf("timed out waiting for connection 2 to be established") 633 } 634 635 // Close the listener for server2 to prevent it from allowing new connections. 636 lis2.Close() 637 638 t.Log("Hard closing connection 1.") 639 ss1.S.Stop() 640 641 t.Log("Waiting for the first stream to error.") 642 if _, err = stream.Recv(); err == nil { 643 t.Fatal("expected the stream to die, but got a successful Recv") 644 } 645 646 t.Log("Ensuring connection 2 is stable.") 647 for i := 0; i < 10; i++ { 648 if _, err := client.UnaryCall(ctx, &testpb.SimpleRequest{}); err != nil { 649 t.Fatalf("UnaryCall(_) = _, %v; want _, nil", err) 650 } 651 } 652 } 653 654 // TestGoAwayStreamIDSmallerThanCreatedStreams tests the scenario where a server 655 // sends a goaway with a stream id that is smaller than some created streams on 656 // the client, while the client is simultaneously creating new streams. This 657 // should not induce a deadlock. 658 func (s) TestGoAwayStreamIDSmallerThanCreatedStreams(t *testing.T) { 659 lis, err := net.Listen("tcp", "localhost:0") 660 if err != nil { 661 t.Fatalf("error listening: %v", err) 662 } 663 664 ctCh := testutils.NewChannel() 665 go func() { 666 conn, err := lis.Accept() 667 if err != nil { 668 t.Errorf("error in lis.Accept(): %v", err) 669 } 670 ct := newClientTester(t, conn) 671 ctCh.Send(ct) 672 }() 673 674 cc, err := grpc.NewClient(lis.Addr().String(), grpc.WithTransportCredentials(insecure.NewCredentials())) 675 if err != nil { 676 t.Fatalf("grpc.NewClient(%q) = %v", lis.Addr().String(), err) 677 } 678 defer cc.Close() 679 cc.Connect() 680 681 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 682 defer cancel() 683 684 val, err := ctCh.Receive(ctx) 685 if err != nil { 686 t.Fatalf("timeout waiting for client transport (should be given after http2 creation)") 687 } 688 ct := val.(*clientTester) 689 690 tc := testgrpc.NewTestServiceClient(cc) 691 someStreamsCreated := grpcsync.NewEvent() 692 goAwayWritten := grpcsync.NewEvent() 693 go func() { 694 for i := 0; i < 20; i++ { 695 if i == 10 { 696 <-goAwayWritten.Done() 697 } 698 tc.FullDuplexCall(ctx) 699 if i == 4 { 700 someStreamsCreated.Fire() 701 } 702 } 703 }() 704 705 <-someStreamsCreated.Done() 706 ct.writeGoAway(1, http2.ErrCodeNo, []byte{}) 707 goAwayWritten.Fire() 708 } 709 710 // TestTwoGoAwayPingFrames tests the scenario where you get two go away ping 711 // frames from the client during graceful shutdown. This should not crash the 712 // server. 713 func (s) TestTwoGoAwayPingFrames(t *testing.T) { 714 lis, err := net.Listen("tcp", "localhost:0") 715 if err != nil { 716 t.Fatalf("Failed to listen: %v", err) 717 } 718 defer lis.Close() 719 s := grpc.NewServer() 720 defer s.Stop() 721 go s.Serve(lis) 722 723 conn, err := net.DialTimeout("tcp", lis.Addr().String(), defaultTestTimeout) 724 if err != nil { 725 t.Fatalf("Failed to dial: %v", err) 726 } 727 728 st := newServerTesterFromConn(t, conn) 729 st.greet() 730 pingReceivedClientSide := testutils.NewChannel() 731 go func() { 732 for { 733 f, err := st.readFrame() 734 if err != nil { 735 return 736 } 737 switch f.(type) { 738 case *http2.GoAwayFrame: 739 case *http2.PingFrame: 740 pingReceivedClientSide.Send(nil) 741 default: 742 t.Errorf("server tester received unexpected frame type %T", f) 743 } 744 } 745 }() 746 gsDone := testutils.NewChannel() 747 go func() { 748 s.GracefulStop() 749 gsDone.Send(nil) 750 }() 751 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 752 defer cancel() 753 if _, err := pingReceivedClientSide.Receive(ctx); err != nil { 754 t.Fatalf("Error waiting for ping frame client side from graceful shutdown: %v", err) 755 } 756 // Write two goaway pings here. 757 st.writePing(true, [8]byte{1, 6, 1, 8, 0, 3, 3, 9}) 758 st.writePing(true, [8]byte{1, 6, 1, 8, 0, 3, 3, 9}) 759 // Close the conn to finish up the Graceful Shutdown process. 760 conn.Close() 761 if _, err := gsDone.Receive(ctx); err != nil { 762 t.Fatalf("Error waiting for graceful shutdown of the server: %v", err) 763 } 764 } 765 766 // TestClientSendsAGoAway tests the scenario where you get a go away ping 767 // frames from the client during graceful shutdown. 768 func (s) TestClientSendsAGoAway(t *testing.T) { 769 lis, err := net.Listen("tcp", "localhost:0") 770 if err != nil { 771 t.Fatalf("error listening: %v", err) 772 } 773 defer lis.Close() 774 goAwayReceived := make(chan struct{}) 775 errCh := make(chan error) 776 go func() { 777 conn, err := lis.Accept() 778 if err != nil { 779 t.Errorf("error in lis.Accept(): %v", err) 780 } 781 ct := newClientTester(t, conn) 782 defer ct.conn.Close() 783 for { 784 f, err := ct.fr.ReadFrame() 785 if err != nil { 786 errCh <- fmt.Errorf("error reading frame: %v", err) 787 return 788 } 789 switch fr := f.(type) { 790 case *http2.GoAwayFrame: 791 fr = f.(*http2.GoAwayFrame) 792 if fr.ErrCode == http2.ErrCodeNo { 793 t.Logf("GoAway received from client") 794 close(goAwayReceived) 795 return 796 } 797 default: 798 t.Errorf("server tester received unexpected frame type %T", f) 799 errCh <- fmt.Errorf("server tester received unexpected frame type %T", f) 800 close(errCh) 801 } 802 } 803 }() 804 805 cc, err := grpc.NewClient(lis.Addr().String(), grpc.WithTransportCredentials(insecure.NewCredentials())) 806 if err != nil { 807 t.Fatalf("error dialing: %v", err) 808 } 809 cc.Connect() 810 811 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 812 defer cancel() 813 814 testutils.AwaitState(ctx, t, cc, connectivity.Ready) 815 cc.Close() 816 select { 817 case <-goAwayReceived: 818 case err := <-errCh: 819 t.Errorf("Error receiving the goAway: %v", err) 820 case <-ctx.Done(): 821 t.Errorf("Context timed out") 822 } 823 }