github.com/metacubex/tfo-go@v0.0.0-20240228025757-be1269474a66/tfo_test.go (about) 1 package tfo 2 3 import ( 4 "bytes" 5 "context" 6 "errors" 7 "io" 8 "net" 9 "os" 10 "sync" 11 "syscall" 12 "testing" 13 "time" 14 ) 15 16 type mptcpStatus uint8 17 18 const ( 19 mptcpUseDefault mptcpStatus = iota 20 mptcpEnabled 21 mptcpDisabled 22 ) 23 24 var listenConfigCases = []struct { 25 name string 26 listenConfig ListenConfig 27 mptcp mptcpStatus 28 }{ 29 {"TFO", ListenConfig{}, mptcpUseDefault}, 30 {"TFO+MPTCPEnabled", ListenConfig{}, mptcpEnabled}, 31 {"TFO+MPTCPDisabled", ListenConfig{}, mptcpDisabled}, 32 {"TFO+Backlog1024", ListenConfig{Backlog: 1024}, mptcpUseDefault}, 33 {"TFO+Backlog1024+MPTCPEnabled", ListenConfig{Backlog: 1024}, mptcpEnabled}, 34 {"TFO+Backlog1024+MPTCPDisabled", ListenConfig{Backlog: 1024}, mptcpDisabled}, 35 {"TFO+Backlog-1", ListenConfig{Backlog: -1}, mptcpUseDefault}, 36 {"TFO+Backlog-1+MPTCPEnabled", ListenConfig{Backlog: -1}, mptcpEnabled}, 37 {"TFO+Backlog-1+MPTCPDisabled", ListenConfig{Backlog: -1}, mptcpDisabled}, 38 {"TFO+Fallback", ListenConfig{Fallback: true}, mptcpUseDefault}, 39 {"TFO+Fallback+MPTCPEnabled", ListenConfig{Fallback: true}, mptcpEnabled}, 40 {"TFO+Fallback+MPTCPDisabled", ListenConfig{Fallback: true}, mptcpDisabled}, 41 {"NoTFO", ListenConfig{DisableTFO: true}, mptcpUseDefault}, 42 {"NoTFO+MPTCPEnabled", ListenConfig{DisableTFO: true}, mptcpEnabled}, 43 {"NoTFO+MPTCPDisabled", ListenConfig{DisableTFO: true}, mptcpDisabled}, 44 {"NoTFO+Backlog1024", ListenConfig{DisableTFO: true, Backlog: 1024}, mptcpUseDefault}, 45 {"NoTFO+Backlog1024+MPTCPEnabled", ListenConfig{DisableTFO: true, Backlog: 1024}, mptcpEnabled}, 46 {"NoTFO+Backlog1024+MPTCPDisabled", ListenConfig{DisableTFO: true, Backlog: 1024}, mptcpDisabled}, 47 {"NoTFO+Backlog-1", ListenConfig{DisableTFO: true, Backlog: -1}, mptcpUseDefault}, 48 {"NoTFO+Backlog-1+MPTCPEnabled", ListenConfig{DisableTFO: true, Backlog: -1}, mptcpEnabled}, 49 {"NoTFO+Backlog-1+MPTCPDisabled", ListenConfig{DisableTFO: true, Backlog: -1}, mptcpDisabled}, 50 {"NoTFO+Fallback", ListenConfig{DisableTFO: true, Fallback: true}, mptcpUseDefault}, 51 {"NoTFO+Fallback+MPTCPEnabled", ListenConfig{DisableTFO: true, Fallback: true}, mptcpEnabled}, 52 {"NoTFO+Fallback+MPTCPDisabled", ListenConfig{DisableTFO: true, Fallback: true}, mptcpDisabled}, 53 } 54 55 var dialerCases = []struct { 56 name string 57 dialer Dialer 58 mptcp mptcpStatus 59 }{ 60 {"TFO", Dialer{}, mptcpUseDefault}, 61 {"TFO+MPTCPEnabled", Dialer{}, mptcpEnabled}, 62 {"TFO+MPTCPDisabled", Dialer{}, mptcpDisabled}, 63 {"TFO+Fallback", Dialer{Fallback: true}, mptcpUseDefault}, 64 {"TFO+Fallback+MPTCPEnabled", Dialer{Fallback: true}, mptcpEnabled}, 65 {"TFO+Fallback+MPTCPDisabled", Dialer{Fallback: true}, mptcpDisabled}, 66 {"NoTFO", Dialer{DisableTFO: true}, mptcpUseDefault}, 67 {"NoTFO+MPTCPEnabled", Dialer{DisableTFO: true}, mptcpEnabled}, 68 {"NoTFO+MPTCPDisabled", Dialer{DisableTFO: true}, mptcpDisabled}, 69 {"NoTFO+Fallback", Dialer{DisableTFO: true, Fallback: true}, mptcpUseDefault}, 70 {"NoTFO+Fallback+MPTCPEnabled", Dialer{DisableTFO: true, Fallback: true}, mptcpEnabled}, 71 {"NoTFO+Fallback+MPTCPDisabled", Dialer{DisableTFO: true, Fallback: true}, mptcpDisabled}, 72 } 73 74 type testCase struct { 75 name string 76 listenConfig ListenConfig 77 dialer Dialer 78 } 79 80 // cases is a list of [ListenConfig] and [Dialer] combinations to test. 81 var cases []testCase 82 83 func init() { 84 // Initialize [listenConfigCases]. 85 for i := range listenConfigCases { 86 c := &listenConfigCases[i] 87 switch c.mptcp { 88 case mptcpUseDefault: 89 case mptcpEnabled: 90 c.listenConfig.SetMultipathTCP(true) 91 case mptcpDisabled: 92 c.listenConfig.SetMultipathTCP(false) 93 default: 94 panic("unreachable") 95 } 96 } 97 98 // Initialize [dialerCases]. 99 for i := range dialerCases { 100 c := &dialerCases[i] 101 switch c.mptcp { 102 case mptcpUseDefault: 103 case mptcpEnabled: 104 c.dialer.SetMultipathTCP(true) 105 case mptcpDisabled: 106 c.dialer.SetMultipathTCP(false) 107 default: 108 panic("unreachable") 109 } 110 } 111 112 // Generate [cases]. 113 cases = make([]testCase, 0, len(listenConfigCases)*len(dialerCases)) 114 for _, lc := range listenConfigCases { 115 if comptimeNoTFO && !lc.listenConfig.tfoDisabled() { 116 continue 117 } 118 for _, d := range dialerCases { 119 if comptimeNoTFO && !d.dialer.DisableTFO { 120 continue 121 } 122 cases = append(cases, testCase{ 123 name: lc.name + "/" + d.name, 124 listenConfig: lc.listenConfig, 125 dialer: d.dialer, 126 }) 127 } 128 } 129 } 130 131 // discardTCPServer is a TCP server that accepts and drains incoming connections. 132 type discardTCPServer struct { 133 ln *net.TCPListener 134 wg sync.WaitGroup 135 } 136 137 // newDiscardTCPServer creates a new [discardTCPServer] that listens on a random port. 138 func newDiscardTCPServer(ctx context.Context) (*discardTCPServer, error) { 139 lc := ListenConfig{DisableTFO: comptimeNoTFO} 140 ln, err := lc.Listen(ctx, "tcp", "[::1]:") 141 if err != nil { 142 return nil, err 143 } 144 return &discardTCPServer{ln: ln.(*net.TCPListener)}, nil 145 } 146 147 // Addr returns the server's address. 148 func (s *discardTCPServer) Addr() *net.TCPAddr { 149 return s.ln.Addr().(*net.TCPAddr) 150 } 151 152 // Start spins up a new goroutine that accepts and drains incoming connections 153 // until [discardTCPServer.Close] is called. 154 func (s *discardTCPServer) Start(t *testing.T) { 155 s.wg.Add(1) 156 157 go func() { 158 defer s.wg.Done() 159 160 for { 161 c, err := s.ln.AcceptTCP() 162 if err != nil { 163 if errors.Is(err, os.ErrDeadlineExceeded) { 164 return 165 } 166 t.Error("AcceptTCP:", err) 167 return 168 } 169 170 go func() { 171 defer c.Close() 172 173 n, err := io.Copy(io.Discard, c) 174 if err != nil { 175 t.Error("Copy:", err) 176 } 177 t.Logf("Discarded %d bytes from %s", n, c.RemoteAddr()) 178 }() 179 } 180 }() 181 } 182 183 // Close interrupts all running accept goroutines, waits for them to finish, 184 // and closes the listener. 185 func (s *discardTCPServer) Close() { 186 s.ln.SetDeadline(aLongTimeAgo) 187 s.wg.Wait() 188 s.ln.Close() 189 } 190 191 var ( 192 hello = []byte{'h', 'e', 'l', 'l', 'o'} 193 world = []byte{'w', 'o', 'r', 'l', 'd'} 194 helloworld = []byte{'h', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd'} 195 worldhello = []byte{'w', 'o', 'r', 'l', 'd', 'h', 'e', 'l', 'l', 'o'} 196 helloWorldSentence = []byte{'h', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!', '\n'} 197 ) 198 199 func testListenDialUDP(t *testing.T, lc ListenConfig, d Dialer) { 200 pc, err := lc.ListenPacket(context.Background(), "udp", "[::1]:") 201 if err != nil { 202 t.Fatal(err) 203 } 204 uc := pc.(*net.UDPConn) 205 defer uc.Close() 206 207 c, err := d.Dial("udp", uc.LocalAddr().String(), hello) 208 if err != nil { 209 t.Fatal(err) 210 } 211 defer c.Close() 212 213 b := make([]byte, 5) 214 n, _, err := uc.ReadFromUDPAddrPort(b) 215 if err != nil { 216 t.Fatal(err) 217 } 218 if n != 5 { 219 t.Fatalf("Expected 5 bytes, got %d", n) 220 } 221 if !bytes.Equal(b, hello) { 222 t.Fatalf("Expected %v, got %v", hello, b) 223 } 224 } 225 226 // TestListenDialUDP ensures that the UDP capabilities of [ListenConfig] and 227 // [Dialer] are not affected by this package. 228 func TestListenDialUDP(t *testing.T) { 229 for _, c := range cases { 230 t.Run(c.name, func(t *testing.T) { 231 testListenDialUDP(t, c.listenConfig, c.dialer) 232 }) 233 } 234 } 235 236 // TestListenCtrlFn ensures that the user-provided [ListenConfig.Control] function 237 // is called when [ListenConfig.Listen] is called. 238 func TestListenCtrlFn(t *testing.T) { 239 for _, c := range listenConfigCases { 240 t.Run(c.name, func(t *testing.T) { 241 testListenCtrlFn(t, c.listenConfig) 242 }) 243 } 244 } 245 246 // TestDialCtrlFn ensures that [Dialer]'s user-provided control functions 247 // are used in the same way as [net.Dialer]. 248 func TestDialCtrlFn(t *testing.T) { 249 s, err := newDiscardTCPServer(context.Background()) 250 if err != nil { 251 t.Fatal(err) 252 } 253 defer s.Close() 254 255 address := s.Addr().String() 256 257 for _, c := range dialerCases { 258 t.Run(c.name, func(t *testing.T) { 259 testDialCtrlFn(t, c.dialer, address) 260 testDialCtrlCtxFn(t, c.dialer, address) 261 testDialCtrlCtxFnSupersedesCtrlFn(t, c.dialer, address) 262 }) 263 } 264 } 265 266 // TestAddrFunctions ensures that the address methods on [*net.TCPListener] and 267 // [*net.TCPConn] return the correct values. 268 func TestAddrFunctions(t *testing.T) { 269 for _, c := range cases { 270 t.Run(c.name, func(t *testing.T) { 271 testAddrFunctions(t, c.listenConfig, c.dialer) 272 }) 273 } 274 } 275 276 // TestClientWriteReadServerReadWrite ensures that a client can write to a server, 277 // the server can read from the client, and the server can write to the client. 278 func TestClientWriteReadServerReadWrite(t *testing.T) { 279 for _, c := range cases { 280 t.Run(c.name, func(t *testing.T) { 281 testClientWriteReadServerReadWrite(t, c.listenConfig, c.dialer) 282 }) 283 } 284 } 285 286 // TestServerWriteReadClientReadWrite ensures that a server can write to a client, 287 // the client can read from the server, and the client can write to the server. 288 func TestServerWriteReadClientReadWrite(t *testing.T) { 289 for _, c := range cases { 290 t.Run(c.name, func(t *testing.T) { 291 testServerWriteReadClientReadWrite(t, c.listenConfig, c.dialer) 292 }) 293 } 294 } 295 296 // TestClientServerReadFrom ensures that the ReadFrom method 297 // on accepted and dialed connections works as expected. 298 func TestClientServerReadFrom(t *testing.T) { 299 for _, c := range cases { 300 t.Run(c.name, func(t *testing.T) { 301 testClientServerReadFrom(t, c.listenConfig, c.dialer) 302 }) 303 } 304 } 305 306 // TestSetDeadline ensures that the SetDeadline, SetReadDeadline, and 307 // SetWriteDeadline methods on accepted and dialed connections work as expected. 308 func TestSetDeadline(t *testing.T) { 309 for _, c := range cases { 310 t.Run(c.name, func(t *testing.T) { 311 testSetDeadline(t, c.listenConfig, c.dialer) 312 }) 313 } 314 } 315 316 func testRawConnControl(t *testing.T, sc syscall.Conn) { 317 rawConn, err := sc.SyscallConn() 318 if err != nil { 319 t.Fatal(err) 320 } 321 322 var success bool 323 324 if err = rawConn.Control(func(fd uintptr) { 325 success = fd != 0 326 }); err != nil { 327 t.Fatal(err) 328 } 329 330 if !success { 331 t.Error("RawConn Control failed") 332 } 333 } 334 335 func testListenCtrlFn(t *testing.T, lc ListenConfig) { 336 var success bool 337 338 lc.Control = func(network, address string, c syscall.RawConn) error { 339 return c.Control(func(fd uintptr) { 340 success = fd != 0 341 }) 342 } 343 344 ln, err := lc.Listen(context.Background(), "tcp", "") 345 if err != nil { 346 t.Fatal(err) 347 } 348 defer ln.Close() 349 350 if !success { 351 t.Error("ListenConfig ctrlFn failed") 352 } 353 354 testRawConnControl(t, ln.(syscall.Conn)) 355 } 356 357 func testDialCtrlFn(t *testing.T, d Dialer, address string) { 358 var success bool 359 360 d.Control = func(network, address string, c syscall.RawConn) error { 361 return c.Control(func(fd uintptr) { 362 success = fd != 0 363 }) 364 } 365 366 c, err := d.Dial("tcp", address, hello) 367 if err != nil { 368 t.Fatal(err) 369 } 370 defer c.Close() 371 372 if !success { 373 t.Error("Dialer ctrlFn failed") 374 } 375 376 testRawConnControl(t, c.(syscall.Conn)) 377 } 378 379 const ( 380 ctxKey = 64 381 ctxVal = 128 382 ) 383 384 func testDialCtrlCtxFn(t *testing.T, d Dialer, address string) { 385 var success bool 386 387 d.ControlContext = func(ctx context.Context, network, address string, c syscall.RawConn) error { 388 return c.Control(func(fd uintptr) { 389 success = fd != 0 && ctx.Value(ctxKey) == ctxVal 390 }) 391 } 392 393 ctx := context.WithValue(context.Background(), ctxKey, ctxVal) 394 c, err := d.DialContext(ctx, "tcp", address, hello) 395 if err != nil { 396 t.Fatal(err) 397 } 398 defer c.Close() 399 400 if !success { 401 t.Error("Dialer ctrlCtxFn failed") 402 } 403 404 testRawConnControl(t, c.(syscall.Conn)) 405 } 406 407 func testDialCtrlCtxFnSupersedesCtrlFn(t *testing.T, d Dialer, address string) { 408 var ctrlCtxFnCalled bool 409 410 d.Control = func(network, address string, c syscall.RawConn) error { 411 t.Error("Dialer.Control called") 412 return nil 413 } 414 415 d.ControlContext = func(ctx context.Context, network, address string, c syscall.RawConn) error { 416 ctrlCtxFnCalled = true 417 return nil 418 } 419 420 c, err := d.Dial("tcp", address, hello) 421 if err != nil { 422 t.Fatal(err) 423 } 424 defer c.Close() 425 426 if !ctrlCtxFnCalled { 427 t.Error("Dialer.ControlContext not called") 428 } 429 } 430 431 func testAddrFunctions(t *testing.T, lc ListenConfig, d Dialer) { 432 ln, err := lc.Listen(context.Background(), "tcp", "[::1]:") 433 if err != nil { 434 t.Fatal(err) 435 } 436 lntcp := ln.(*net.TCPListener) 437 defer lntcp.Close() 438 439 addr := lntcp.Addr().(*net.TCPAddr) 440 if !addr.IP.Equal(net.IPv6loopback) { 441 t.Fatalf("expected unspecified IP, got %v", addr.IP) 442 } 443 if addr.Port == 0 { 444 t.Fatalf("expected non-zero port, got %d", addr.Port) 445 } 446 447 c, err := d.Dial("tcp", addr.String(), hello) 448 if err != nil { 449 t.Fatal(err) 450 } 451 defer c.Close() 452 453 if laddr := c.LocalAddr().(*net.TCPAddr); !laddr.IP.Equal(net.IPv6loopback) || laddr.Port == 0 { 454 t.Errorf("Bad local addr: %v", laddr) 455 } 456 if raddr := c.RemoteAddr().(*net.TCPAddr); !raddr.IP.Equal(net.IPv6loopback) || raddr.Port != addr.Port { 457 t.Errorf("Bad remote addr: %v", raddr) 458 } 459 } 460 461 func write(w io.Writer, data []byte, t *testing.T) { 462 dataLen := len(data) 463 n, err := w.Write(data) 464 if err != nil { 465 t.Error(err) 466 return 467 } 468 if n != dataLen { 469 t.Errorf("Wrote %d bytes, should have written %d bytes", n, dataLen) 470 } 471 } 472 473 func writeWithReadFrom(w io.ReaderFrom, data []byte, t *testing.T) { 474 r := bytes.NewReader(data) 475 n, err := w.ReadFrom(r) 476 if err != nil { 477 t.Error(err) 478 } 479 bytesWritten := int(n) 480 dataLen := len(data) 481 if bytesWritten != dataLen { 482 t.Errorf("Wrote %d bytes, should have written %d bytes", bytesWritten, dataLen) 483 } 484 } 485 486 func readExactlyOneByte(r io.Reader, expectedByte byte, t *testing.T) { 487 b := make([]byte, 1) 488 n, err := r.Read(b) 489 if err != nil { 490 t.Fatal(err) 491 } 492 if n != 1 { 493 t.Fatalf("Read %d bytes, expected 1 byte", n) 494 } 495 if b[0] != expectedByte { 496 t.Fatalf("Read unexpected byte: '%c', expected '%c'", b[0], expectedByte) 497 } 498 } 499 500 func readUntilEOF(r io.Reader, expectedData []byte, t *testing.T) { 501 b, err := io.ReadAll(r) 502 if err != nil { 503 t.Error(err) 504 return 505 } 506 if !bytes.Equal(b, expectedData) { 507 t.Errorf("Read data %v is different from original data %v", b, expectedData) 508 } 509 } 510 511 func testClientWriteReadServerReadWrite(t *testing.T, lc ListenConfig, d Dialer) { 512 t.Logf("c->s payload: %v", helloworld) 513 t.Logf("s->c payload: %v", worldhello) 514 515 ln, err := lc.Listen(context.Background(), "tcp", "[::1]:") 516 if err != nil { 517 t.Fatal(err) 518 } 519 lntcp := ln.(*net.TCPListener) 520 defer lntcp.Close() 521 t.Log("Started listener on", lntcp.Addr()) 522 523 ctrlCh := make(chan struct{}) 524 go func() { 525 conn, err := lntcp.AcceptTCP() 526 if err != nil { 527 t.Error(err) 528 return 529 } 530 defer conn.Close() 531 t.Log("Accepted", conn.RemoteAddr()) 532 533 readUntilEOF(conn, helloworld, t) 534 write(conn, world, t) 535 write(conn, hello, t) 536 conn.CloseWrite() 537 close(ctrlCh) 538 }() 539 540 c, err := d.Dial("tcp", ln.Addr().String(), hello) 541 if err != nil { 542 t.Fatal(err) 543 } 544 tc := c.(*net.TCPConn) 545 defer tc.Close() 546 547 write(tc, world, t) 548 tc.CloseWrite() 549 readUntilEOF(tc, worldhello, t) 550 <-ctrlCh 551 } 552 553 func testServerWriteReadClientReadWrite(t *testing.T, lc ListenConfig, d Dialer) { 554 t.Logf("c->s payload: %v", helloworld) 555 t.Logf("s->c payload: %v", worldhello) 556 557 ln, err := lc.Listen(context.Background(), "tcp", "[::1]:") 558 if err != nil { 559 t.Fatal(err) 560 } 561 lntcp := ln.(*net.TCPListener) 562 defer lntcp.Close() 563 t.Log("Started listener on", lntcp.Addr()) 564 565 ctrlCh := make(chan struct{}) 566 go func() { 567 conn, err := lntcp.AcceptTCP() 568 if err != nil { 569 t.Error(err) 570 return 571 } 572 t.Log("Accepted", conn.RemoteAddr()) 573 defer conn.Close() 574 575 write(conn, world, t) 576 write(conn, hello, t) 577 conn.CloseWrite() 578 readUntilEOF(conn, helloworld, t) 579 close(ctrlCh) 580 }() 581 582 c, err := d.Dial("tcp", ln.Addr().String(), nil) 583 if err != nil { 584 t.Fatal(err) 585 } 586 tc := c.(*net.TCPConn) 587 defer tc.Close() 588 589 readUntilEOF(tc, worldhello, t) 590 write(tc, hello, t) 591 write(tc, world, t) 592 tc.CloseWrite() 593 <-ctrlCh 594 } 595 596 func testClientServerReadFrom(t *testing.T, lc ListenConfig, d Dialer) { 597 t.Logf("c->s payload: %v", helloworld) 598 t.Logf("s->c payload: %v", worldhello) 599 600 ln, err := lc.Listen(context.Background(), "tcp", "[::1]:") 601 if err != nil { 602 t.Fatal(err) 603 } 604 lntcp := ln.(*net.TCPListener) 605 defer lntcp.Close() 606 t.Log("Started listener on", lntcp.Addr()) 607 608 ctrlCh := make(chan struct{}) 609 go func() { 610 conn, err := lntcp.AcceptTCP() 611 if err != nil { 612 t.Error(err) 613 return 614 } 615 defer conn.Close() 616 t.Log("Accepted", conn.RemoteAddr()) 617 618 readUntilEOF(conn, helloworld, t) 619 writeWithReadFrom(conn, world, t) 620 writeWithReadFrom(conn, hello, t) 621 conn.CloseWrite() 622 close(ctrlCh) 623 }() 624 625 c, err := d.Dial("tcp", ln.Addr().String(), hello) 626 if err != nil { 627 t.Fatal(err) 628 } 629 tc := c.(*net.TCPConn) 630 defer tc.Close() 631 632 writeWithReadFrom(tc, world, t) 633 tc.CloseWrite() 634 readUntilEOF(tc, worldhello, t) 635 <-ctrlCh 636 } 637 638 func testSetDeadline(t *testing.T, lc ListenConfig, d Dialer) { 639 t.Logf("payload: %v", helloWorldSentence) 640 641 ln, err := lc.Listen(context.Background(), "tcp", "[::1]:") 642 if err != nil { 643 t.Fatal(err) 644 } 645 lntcp := ln.(*net.TCPListener) 646 defer lntcp.Close() 647 t.Log("Started listener on", lntcp.Addr()) 648 649 ctrlCh := make(chan struct{}) 650 go func() { 651 conn, err := lntcp.AcceptTCP() 652 if err != nil { 653 t.Error(err) 654 return 655 } 656 t.Log("Accepted", conn.RemoteAddr()) 657 defer conn.Close() 658 659 write(conn, helloWorldSentence, t) 660 readUntilEOF(conn, []byte{'h', 'l', 'l', ','}, t) 661 close(ctrlCh) 662 }() 663 664 c, err := d.Dial("tcp", ln.Addr().String(), helloWorldSentence[:1]) 665 if err != nil { 666 t.Fatal(err) 667 } 668 tc := c.(*net.TCPConn) 669 defer tc.Close() 670 671 b := make([]byte, 1) 672 673 // SetReadDeadline 674 readExactlyOneByte(tc, 'h', t) 675 if err := tc.SetReadDeadline(time.Now().Add(-time.Second)); err != nil { 676 t.Fatal(err) 677 } 678 if n, err := tc.Read(b); n != 0 || !errors.Is(err, os.ErrDeadlineExceeded) { 679 t.Fatal(n, err) 680 } 681 if err := tc.SetReadDeadline(time.Time{}); err != nil { 682 t.Fatal(err) 683 } 684 readExactlyOneByte(tc, 'e', t) 685 686 // SetWriteDeadline 687 if err := tc.SetWriteDeadline(time.Now().Add(-time.Second)); err != nil { 688 t.Fatal(err) 689 } 690 if n, err := tc.Write(helloWorldSentence[1:2]); n != 0 || !errors.Is(err, os.ErrDeadlineExceeded) { 691 t.Fatal(n, err) 692 } 693 if err := tc.SetWriteDeadline(time.Time{}); err != nil { 694 t.Fatal(err) 695 } 696 write(tc, helloWorldSentence[2:3], t) 697 698 // SetDeadline 699 readExactlyOneByte(tc, 'l', t) 700 write(tc, helloWorldSentence[3:4], t) 701 if err := tc.SetDeadline(time.Now().Add(-time.Second)); err != nil { 702 t.Fatal(err) 703 } 704 if _, err := tc.Read(b); !errors.Is(err, os.ErrDeadlineExceeded) { 705 t.Fatal(err) 706 } 707 if n, err := tc.Write(helloWorldSentence[4:5]); n != 0 || !errors.Is(err, os.ErrDeadlineExceeded) { 708 t.Fatal(n, err) 709 } 710 if err := tc.SetDeadline(time.Time{}); err != nil { 711 t.Fatal(err) 712 } 713 readExactlyOneByte(tc, 'l', t) 714 write(tc, helloWorldSentence[5:6], t) 715 716 tc.CloseWrite() 717 <-ctrlCh 718 }