github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/grpc/internal/transport/keepalive_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 // This file contains tests related to the following proposals: 20 // https://github.com/grpc/proposal/blob/master/A8-client-side-keepalive.md 21 // https://github.com/grpc/proposal/blob/master/A9-server-side-conn-mgt.md 22 // https://github.com/grpc/proposal/blob/master/A18-tcp-user-timeout.md 23 package transport 24 25 import ( 26 "context" 27 "fmt" 28 "io" 29 "net" 30 "testing" 31 "time" 32 33 "github.com/hxx258456/ccgo/grpc/internal/syscall" 34 "github.com/hxx258456/ccgo/grpc/keepalive" 35 "github.com/hxx258456/ccgo/net/http2" 36 ) 37 38 const defaultTestTimeout = 10 * time.Second 39 40 // TestMaxConnectionIdle tests that a server will send GoAway to an idle 41 // client. An idle client is one who doesn't make any RPC calls for a duration 42 // of MaxConnectionIdle time. 43 func (s) TestMaxConnectionIdle(t *testing.T) { 44 serverConfig := &ServerConfig{ 45 KeepaliveParams: keepalive.ServerParameters{ 46 MaxConnectionIdle: 2 * time.Second, 47 }, 48 } 49 server, client, cancel := setUpWithOptions(t, 0, serverConfig, suspended, ConnectOptions{}) 50 defer func() { 51 client.Close(fmt.Errorf("closed manually by test")) 52 server.stop() 53 cancel() 54 }() 55 56 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 57 defer cancel() 58 stream, err := client.NewStream(ctx, &CallHdr{}) 59 if err != nil { 60 t.Fatalf("client.NewStream() failed: %v", err) 61 } 62 client.CloseStream(stream, io.EOF) 63 64 // Wait for the server's MaxConnectionIdle timeout to kick in, and for it 65 // to send a GoAway. 66 timeout := time.NewTimer(time.Second * 4) 67 select { 68 case <-client.Error(): 69 if !timeout.Stop() { 70 <-timeout.C 71 } 72 if reason, _ := client.GetGoAwayReason(); reason != GoAwayNoReason { 73 t.Fatalf("GoAwayReason is %v, want %v", reason, GoAwayNoReason) 74 } 75 case <-timeout.C: 76 t.Fatalf("MaxConnectionIdle timeout expired, expected a GoAway from the server.") 77 } 78 } 79 80 // TestMaxConenctionIdleBusyClient tests that a server will not send GoAway to 81 // a busy client. 82 func (s) TestMaxConnectionIdleBusyClient(t *testing.T) { 83 serverConfig := &ServerConfig{ 84 KeepaliveParams: keepalive.ServerParameters{ 85 MaxConnectionIdle: 2 * time.Second, 86 }, 87 } 88 server, client, cancel := setUpWithOptions(t, 0, serverConfig, suspended, ConnectOptions{}) 89 defer func() { 90 client.Close(fmt.Errorf("closed manually by test")) 91 server.stop() 92 cancel() 93 }() 94 95 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 96 defer cancel() 97 _, err := client.NewStream(ctx, &CallHdr{}) 98 if err != nil { 99 t.Fatalf("client.NewStream() failed: %v", err) 100 } 101 102 // Wait for double the MaxConnectionIdle time to make sure the server does 103 // not send a GoAway, as the client has an open stream. 104 timeout := time.NewTimer(time.Second * 4) 105 select { 106 case <-client.GoAway(): 107 if !timeout.Stop() { 108 <-timeout.C 109 } 110 t.Fatalf("A non-idle client received a GoAway.") 111 case <-timeout.C: 112 } 113 } 114 115 // TestMaxConnectionAge tests that a server will send GoAway after a duration 116 // of MaxConnectionAge. 117 func (s) TestMaxConnectionAge(t *testing.T) { 118 serverConfig := &ServerConfig{ 119 KeepaliveParams: keepalive.ServerParameters{ 120 MaxConnectionAge: 1 * time.Second, 121 MaxConnectionAgeGrace: 1 * time.Second, 122 }, 123 } 124 server, client, cancel := setUpWithOptions(t, 0, serverConfig, suspended, ConnectOptions{}) 125 defer func() { 126 client.Close(fmt.Errorf("closed manually by test")) 127 server.stop() 128 cancel() 129 }() 130 131 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 132 defer cancel() 133 _, err := client.NewStream(ctx, &CallHdr{}) 134 if err != nil { 135 t.Fatalf("client.NewStream() failed: %v", err) 136 } 137 138 // Wait for the server's MaxConnectionAge timeout to kick in, and for it 139 // to send a GoAway. 140 timeout := time.NewTimer(4 * time.Second) 141 select { 142 case <-client.Error(): 143 if !timeout.Stop() { 144 <-timeout.C 145 } 146 if reason, _ := client.GetGoAwayReason(); reason != GoAwayNoReason { 147 t.Fatalf("GoAwayReason is %v, want %v", reason, GoAwayNoReason) 148 } 149 case <-timeout.C: 150 t.Fatalf("MaxConnectionAge timeout expired, expected a GoAway from the server.") 151 } 152 } 153 154 const ( 155 defaultWriteBufSize = 32 * 1024 156 defaultReadBufSize = 32 * 1024 157 ) 158 159 // TestKeepaliveServerClosesUnresponsiveClient tests that a server closes 160 // the connection with a client that doesn't respond to keepalive pings. 161 // 162 // This test creates a regular net.Conn connection to the server and sends the 163 // clientPreface and the initial Settings frame, and then remains unresponsive. 164 func (s) TestKeepaliveServerClosesUnresponsiveClient(t *testing.T) { 165 serverConfig := &ServerConfig{ 166 KeepaliveParams: keepalive.ServerParameters{ 167 Time: 1 * time.Second, 168 Timeout: 1 * time.Second, 169 }, 170 } 171 server, client, cancel := setUpWithOptions(t, 0, serverConfig, suspended, ConnectOptions{}) 172 defer func() { 173 client.Close(fmt.Errorf("closed manually by test")) 174 server.stop() 175 cancel() 176 }() 177 178 addr := server.addr() 179 conn, err := net.Dial("tcp", addr) 180 if err != nil { 181 t.Fatalf("net.Dial(tcp, %v) failed: %v", addr, err) 182 } 183 defer conn.Close() 184 185 if n, err := conn.Write(clientPreface); err != nil || n != len(clientPreface) { 186 t.Fatalf("conn.Write(clientPreface) failed: n=%v, err=%v", n, err) 187 } 188 framer := newFramer(conn, defaultWriteBufSize, defaultReadBufSize, 0) 189 if err := framer.fr.WriteSettings(http2.Setting{}); err != nil { 190 t.Fatal("framer.WriteSettings(http2.Setting{}) failed:", err) 191 } 192 framer.writer.Flush() 193 194 // We read from the net.Conn till we get an error, which is expected when 195 // the server closes the connection as part of the keepalive logic. 196 errCh := make(chan error, 1) 197 go func() { 198 b := make([]byte, 24) 199 for { 200 if _, err = conn.Read(b); err != nil { 201 errCh <- err 202 return 203 } 204 } 205 }() 206 207 // Server waits for KeepaliveParams.Time seconds before sending out a ping, 208 // and then waits for KeepaliveParams.Timeout for a ping ack. 209 timeout := time.NewTimer(4 * time.Second) 210 select { 211 case err := <-errCh: 212 if err != io.EOF { 213 t.Fatalf("client.Read(_) = _,%v, want io.EOF", err) 214 215 } 216 case <-timeout.C: 217 t.Fatalf("keepalive timeout expired, server should have closed the connection.") 218 } 219 } 220 221 // TestKeepaliveServerWithResponsiveClient tests that a server doesn't close 222 // the connection with a client that responds to keepalive pings. 223 func (s) TestKeepaliveServerWithResponsiveClient(t *testing.T) { 224 serverConfig := &ServerConfig{ 225 KeepaliveParams: keepalive.ServerParameters{ 226 Time: 1 * time.Second, 227 Timeout: 1 * time.Second, 228 }, 229 } 230 server, client, cancel := setUpWithOptions(t, 0, serverConfig, suspended, ConnectOptions{}) 231 defer func() { 232 client.Close(fmt.Errorf("closed manually by test")) 233 server.stop() 234 cancel() 235 }() 236 237 // Give keepalive logic some time by sleeping. 238 time.Sleep(4 * time.Second) 239 240 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 241 defer cancel() 242 // Make sure the client transport is healthy. 243 if _, err := client.NewStream(ctx, &CallHdr{}); err != nil { 244 t.Fatalf("client.NewStream() failed: %v", err) 245 } 246 } 247 248 // TestKeepaliveClientClosesUnresponsiveServer creates a server which does not 249 // respond to keepalive pings, and makes sure that the client closes the 250 // transport once the keepalive logic kicks in. Here, we set the 251 // `PermitWithoutStream` parameter to true which ensures that the keepalive 252 // logic is running even without any active streams. 253 func (s) TestKeepaliveClientClosesUnresponsiveServer(t *testing.T) { 254 connCh := make(chan net.Conn, 1) 255 client, cancel := setUpWithNoPingServer(t, ConnectOptions{KeepaliveParams: keepalive.ClientParameters{ 256 Time: 1 * time.Second, 257 Timeout: 1 * time.Second, 258 PermitWithoutStream: true, 259 }}, connCh) 260 defer cancel() 261 defer client.Close(fmt.Errorf("closed manually by test")) 262 263 conn, ok := <-connCh 264 if !ok { 265 t.Fatalf("Server didn't return connection object") 266 } 267 defer conn.Close() 268 269 // Sleep for keepalive to close the connection. 270 time.Sleep(4 * time.Second) 271 272 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 273 defer cancel() 274 // Make sure the client transport is not healthy. 275 if _, err := client.NewStream(ctx, &CallHdr{}); err == nil { 276 t.Fatal("client.NewStream() should have failed, but succeeded") 277 } 278 } 279 280 // TestKeepaliveClientOpenWithUnresponsiveServer creates a server which does 281 // not respond to keepalive pings, and makes sure that the client does not 282 // close the transport. Here, we do not set the `PermitWithoutStream` parameter 283 // to true which ensures that the keepalive logic is turned off without any 284 // active streams, and therefore the transport stays open. 285 func (s) TestKeepaliveClientOpenWithUnresponsiveServer(t *testing.T) { 286 connCh := make(chan net.Conn, 1) 287 client, cancel := setUpWithNoPingServer(t, ConnectOptions{KeepaliveParams: keepalive.ClientParameters{ 288 Time: 1 * time.Second, 289 Timeout: 1 * time.Second, 290 }}, connCh) 291 defer cancel() 292 defer client.Close(fmt.Errorf("closed manually by test")) 293 294 conn, ok := <-connCh 295 if !ok { 296 t.Fatalf("Server didn't return connection object") 297 } 298 defer conn.Close() 299 300 // Give keepalive some time. 301 time.Sleep(4 * time.Second) 302 303 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 304 defer cancel() 305 // Make sure the client transport is healthy. 306 if _, err := client.NewStream(ctx, &CallHdr{}); err != nil { 307 t.Fatalf("client.NewStream() failed: %v", err) 308 } 309 } 310 311 // TestKeepaliveClientClosesWithActiveStreams creates a server which does not 312 // respond to keepalive pings, and makes sure that the client closes the 313 // transport even when there is an active stream. 314 func (s) TestKeepaliveClientClosesWithActiveStreams(t *testing.T) { 315 connCh := make(chan net.Conn, 1) 316 client, cancel := setUpWithNoPingServer(t, ConnectOptions{KeepaliveParams: keepalive.ClientParameters{ 317 Time: 1 * time.Second, 318 Timeout: 1 * time.Second, 319 }}, connCh) 320 defer cancel() 321 defer client.Close(fmt.Errorf("closed manually by test")) 322 323 conn, ok := <-connCh 324 if !ok { 325 t.Fatalf("Server didn't return connection object") 326 } 327 defer conn.Close() 328 329 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 330 defer cancel() 331 // Create a stream, but send no data on it. 332 if _, err := client.NewStream(ctx, &CallHdr{}); err != nil { 333 t.Fatalf("client.NewStream() failed: %v", err) 334 } 335 336 // Give keepalive some time. 337 time.Sleep(4 * time.Second) 338 339 // Make sure the client transport is not healthy. 340 if _, err := client.NewStream(ctx, &CallHdr{}); err == nil { 341 t.Fatal("client.NewStream() should have failed, but succeeded") 342 } 343 } 344 345 // TestKeepaliveClientStaysHealthyWithResponsiveServer creates a server which 346 // responds to keepalive pings, and makes sure than a client transport stays 347 // healthy without any active streams. 348 func (s) TestKeepaliveClientStaysHealthyWithResponsiveServer(t *testing.T) { 349 server, client, cancel := setUpWithOptions(t, 0, 350 &ServerConfig{ 351 KeepalivePolicy: keepalive.EnforcementPolicy{ 352 PermitWithoutStream: true, 353 }, 354 }, 355 normal, 356 ConnectOptions{ 357 KeepaliveParams: keepalive.ClientParameters{ 358 Time: 1 * time.Second, 359 Timeout: 1 * time.Second, 360 PermitWithoutStream: true, 361 }}) 362 defer func() { 363 client.Close(fmt.Errorf("closed manually by test")) 364 server.stop() 365 cancel() 366 }() 367 368 // Give keepalive some time. 369 time.Sleep(4 * time.Second) 370 371 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 372 defer cancel() 373 // Make sure the client transport is healthy. 374 if _, err := client.NewStream(ctx, &CallHdr{}); err != nil { 375 t.Fatalf("client.NewStream() failed: %v", err) 376 } 377 } 378 379 // TestKeepaliveClientFrequency creates a server which expects at most 1 client 380 // ping for every 1.2 seconds, while the client is configured to send a ping 381 // every 1 second. So, this configuration should end up with the client 382 // transport being closed. But we had a bug wherein the client was sending one 383 // ping every [Time+Timeout] instead of every [Time] period, and this test 384 // explicitly makes sure the fix works and the client sends a ping every [Time] 385 // period. 386 func (s) TestKeepaliveClientFrequency(t *testing.T) { 387 serverConfig := &ServerConfig{ 388 KeepalivePolicy: keepalive.EnforcementPolicy{ 389 MinTime: 1200 * time.Millisecond, // 1.2 seconds 390 PermitWithoutStream: true, 391 }, 392 } 393 clientOptions := ConnectOptions{ 394 KeepaliveParams: keepalive.ClientParameters{ 395 Time: 1 * time.Second, 396 Timeout: 2 * time.Second, 397 PermitWithoutStream: true, 398 }, 399 } 400 server, client, cancel := setUpWithOptions(t, 0, serverConfig, normal, clientOptions) 401 defer func() { 402 client.Close(fmt.Errorf("closed manually by test")) 403 server.stop() 404 cancel() 405 }() 406 407 timeout := time.NewTimer(6 * time.Second) 408 select { 409 case <-client.Error(): 410 if !timeout.Stop() { 411 <-timeout.C 412 } 413 if reason, _ := client.GetGoAwayReason(); reason != GoAwayTooManyPings { 414 t.Fatalf("GoAwayReason is %v, want %v", reason, GoAwayTooManyPings) 415 } 416 case <-timeout.C: 417 t.Fatalf("client transport still healthy; expected GoAway from the server.") 418 } 419 420 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 421 defer cancel() 422 // Make sure the client transport is not healthy. 423 if _, err := client.NewStream(ctx, &CallHdr{}); err == nil { 424 t.Fatal("client.NewStream() should have failed, but succeeded") 425 } 426 } 427 428 // TestKeepaliveServerEnforcementWithAbusiveClientNoRPC verifies that the 429 // server closes a client transport when it sends too many keepalive pings 430 // (when there are no active streams), based on the configured 431 // EnforcementPolicy. 432 func (s) TestKeepaliveServerEnforcementWithAbusiveClientNoRPC(t *testing.T) { 433 serverConfig := &ServerConfig{ 434 KeepalivePolicy: keepalive.EnforcementPolicy{ 435 MinTime: 2 * time.Second, 436 }, 437 } 438 clientOptions := ConnectOptions{ 439 KeepaliveParams: keepalive.ClientParameters{ 440 Time: 50 * time.Millisecond, 441 Timeout: 1 * time.Second, 442 PermitWithoutStream: true, 443 }, 444 } 445 server, client, cancel := setUpWithOptions(t, 0, serverConfig, normal, clientOptions) 446 defer func() { 447 client.Close(fmt.Errorf("closed manually by test")) 448 server.stop() 449 cancel() 450 }() 451 452 timeout := time.NewTimer(4 * time.Second) 453 select { 454 case <-client.Error(): 455 if !timeout.Stop() { 456 <-timeout.C 457 } 458 if reason, _ := client.GetGoAwayReason(); reason != GoAwayTooManyPings { 459 t.Fatalf("GoAwayReason is %v, want %v", reason, GoAwayTooManyPings) 460 } 461 case <-timeout.C: 462 t.Fatalf("client transport still healthy; expected GoAway from the server.") 463 } 464 465 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 466 defer cancel() 467 // Make sure the client transport is not healthy. 468 if _, err := client.NewStream(ctx, &CallHdr{}); err == nil { 469 t.Fatal("client.NewStream() should have failed, but succeeded") 470 } 471 } 472 473 // TestKeepaliveServerEnforcementWithAbusiveClientWithRPC verifies that the 474 // server closes a client transport when it sends too many keepalive pings 475 // (even when there is an active stream), based on the configured 476 // EnforcementPolicy. 477 func (s) TestKeepaliveServerEnforcementWithAbusiveClientWithRPC(t *testing.T) { 478 serverConfig := &ServerConfig{ 479 KeepalivePolicy: keepalive.EnforcementPolicy{ 480 MinTime: 2 * time.Second, 481 }, 482 } 483 clientOptions := ConnectOptions{ 484 KeepaliveParams: keepalive.ClientParameters{ 485 Time: 50 * time.Millisecond, 486 Timeout: 1 * time.Second, 487 }, 488 } 489 server, client, cancel := setUpWithOptions(t, 0, serverConfig, suspended, clientOptions) 490 defer func() { 491 client.Close(fmt.Errorf("closed manually by test")) 492 server.stop() 493 cancel() 494 }() 495 496 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 497 defer cancel() 498 if _, err := client.NewStream(ctx, &CallHdr{}); err != nil { 499 t.Fatalf("client.NewStream() failed: %v", err) 500 } 501 502 timeout := time.NewTimer(4 * time.Second) 503 select { 504 case <-client.Error(): 505 if !timeout.Stop() { 506 <-timeout.C 507 } 508 if reason, _ := client.GetGoAwayReason(); reason != GoAwayTooManyPings { 509 t.Fatalf("GoAwayReason is %v, want %v", reason, GoAwayTooManyPings) 510 } 511 case <-timeout.C: 512 t.Fatalf("client transport still healthy; expected GoAway from the server.") 513 } 514 515 // Make sure the client transport is not healthy. 516 if _, err := client.NewStream(ctx, &CallHdr{}); err == nil { 517 t.Fatal("client.NewStream() should have failed, but succeeded") 518 } 519 } 520 521 // TestKeepaliveServerEnforcementWithObeyingClientNoRPC verifies that the 522 // server does not close a client transport (with no active streams) which 523 // sends keepalive pings in accordance to the configured keepalive 524 // EnforcementPolicy. 525 func (s) TestKeepaliveServerEnforcementWithObeyingClientNoRPC(t *testing.T) { 526 serverConfig := &ServerConfig{ 527 KeepalivePolicy: keepalive.EnforcementPolicy{ 528 MinTime: 100 * time.Millisecond, 529 PermitWithoutStream: true, 530 }, 531 } 532 clientOptions := ConnectOptions{ 533 KeepaliveParams: keepalive.ClientParameters{ 534 Time: 101 * time.Millisecond, 535 Timeout: 1 * time.Second, 536 PermitWithoutStream: true, 537 }, 538 } 539 server, client, cancel := setUpWithOptions(t, 0, serverConfig, normal, clientOptions) 540 defer func() { 541 client.Close(fmt.Errorf("closed manually by test")) 542 server.stop() 543 cancel() 544 }() 545 546 // Give keepalive enough time. 547 time.Sleep(3 * time.Second) 548 549 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 550 defer cancel() 551 // Make sure the client transport is healthy. 552 if _, err := client.NewStream(ctx, &CallHdr{}); err != nil { 553 t.Fatalf("client.NewStream() failed: %v", err) 554 } 555 } 556 557 // TestKeepaliveServerEnforcementWithObeyingClientWithRPC verifies that the 558 // server does not close a client transport (with active streams) which 559 // sends keepalive pings in accordance to the configured keepalive 560 // EnforcementPolicy. 561 func (s) TestKeepaliveServerEnforcementWithObeyingClientWithRPC(t *testing.T) { 562 serverConfig := &ServerConfig{ 563 KeepalivePolicy: keepalive.EnforcementPolicy{ 564 MinTime: 100 * time.Millisecond, 565 }, 566 } 567 clientOptions := ConnectOptions{ 568 KeepaliveParams: keepalive.ClientParameters{ 569 Time: 101 * time.Millisecond, 570 Timeout: 1 * time.Second, 571 }, 572 } 573 server, client, cancel := setUpWithOptions(t, 0, serverConfig, suspended, clientOptions) 574 defer func() { 575 client.Close(fmt.Errorf("closed manually by test")) 576 server.stop() 577 cancel() 578 }() 579 580 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 581 defer cancel() 582 if _, err := client.NewStream(ctx, &CallHdr{}); err != nil { 583 t.Fatalf("client.NewStream() failed: %v", err) 584 } 585 586 // Give keepalive enough time. 587 time.Sleep(3 * time.Second) 588 589 // Make sure the client transport is healthy. 590 if _, err := client.NewStream(ctx, &CallHdr{}); err != nil { 591 t.Fatalf("client.NewStream() failed: %v", err) 592 } 593 } 594 595 // TestKeepaliveServerEnforcementWithDormantKeepaliveOnClient verifies that the 596 // server does not closes a client transport, which has been configured to send 597 // more pings than allowed by the server's EnforcementPolicy. This client 598 // transport does not have any active streams and `PermitWithoutStream` is set 599 // to false. This should ensure that the keepalive functionality on the client 600 // side enters a dormant state. 601 func (s) TestKeepaliveServerEnforcementWithDormantKeepaliveOnClient(t *testing.T) { 602 serverConfig := &ServerConfig{ 603 KeepalivePolicy: keepalive.EnforcementPolicy{ 604 MinTime: 2 * time.Second, 605 }, 606 } 607 clientOptions := ConnectOptions{ 608 KeepaliveParams: keepalive.ClientParameters{ 609 Time: 50 * time.Millisecond, 610 Timeout: 1 * time.Second, 611 }, 612 } 613 server, client, cancel := setUpWithOptions(t, 0, serverConfig, normal, clientOptions) 614 defer func() { 615 client.Close(fmt.Errorf("closed manually by test")) 616 server.stop() 617 cancel() 618 }() 619 620 // No active streams on the client. Give keepalive enough time. 621 time.Sleep(5 * time.Second) 622 623 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 624 defer cancel() 625 // Make sure the client transport is healthy. 626 if _, err := client.NewStream(ctx, &CallHdr{}); err != nil { 627 t.Fatalf("client.NewStream() failed: %v", err) 628 } 629 } 630 631 // TestTCPUserTimeout tests that the TCP_USER_TIMEOUT socket option is set to 632 // the keepalive timeout, as detailed in proposal A18. 633 func (s) TestTCPUserTimeout(t *testing.T) { 634 tests := []struct { 635 time time.Duration 636 timeout time.Duration 637 wantTimeout time.Duration 638 }{ 639 { 640 10 * time.Second, 641 10 * time.Second, 642 10 * 1000 * time.Millisecond, 643 }, 644 { 645 0, 646 0, 647 0, 648 }, 649 } 650 for _, tt := range tests { 651 server, client, cancel := setUpWithOptions( 652 t, 653 0, 654 &ServerConfig{ 655 KeepaliveParams: keepalive.ServerParameters{ 656 Time: tt.timeout, 657 Timeout: tt.timeout, 658 }, 659 }, 660 normal, 661 ConnectOptions{ 662 KeepaliveParams: keepalive.ClientParameters{ 663 Time: tt.time, 664 Timeout: tt.timeout, 665 }, 666 }, 667 ) 668 defer func() { 669 client.Close(fmt.Errorf("closed manually by test")) 670 server.stop() 671 cancel() 672 }() 673 674 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 675 defer cancel() 676 stream, err := client.NewStream(ctx, &CallHdr{}) 677 if err != nil { 678 t.Fatalf("client.NewStream() failed: %v", err) 679 } 680 client.CloseStream(stream, io.EOF) 681 682 opt, err := syscall.GetTCPUserTimeout(client.conn) 683 if err != nil { 684 t.Fatalf("syscall.GetTCPUserTimeout() failed: %v", err) 685 } 686 if opt < 0 { 687 t.Skipf("skipping test on unsupported environment") 688 } 689 if gotTimeout := time.Duration(opt) * time.Millisecond; gotTimeout != tt.wantTimeout { 690 t.Fatalf("syscall.GetTCPUserTimeout() = %d, want %d", gotTimeout, tt.wantTimeout) 691 } 692 } 693 }