github.com/q45/go@v0.0.0-20151101211701-a4fb8c13db3f/src/net/dial_test.go (about) 1 // Copyright 2011 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package net 6 7 import ( 8 "io" 9 "net/internal/socktest" 10 "runtime" 11 "sync" 12 "testing" 13 "time" 14 ) 15 16 var prohibitionaryDialArgTests = []struct { 17 network string 18 address string 19 }{ 20 {"tcp6", "127.0.0.1"}, 21 {"tcp6", "::ffff:127.0.0.1"}, 22 } 23 24 func TestProhibitionaryDialArg(t *testing.T) { 25 switch runtime.GOOS { 26 case "plan9": 27 t.Skipf("not supported on %s", runtime.GOOS) 28 } 29 if testing.Short() || !*testExternal { 30 t.Skip("avoid external network") 31 } 32 if !supportsIPv4map { 33 t.Skip("mapping ipv4 address inside ipv6 address not supported") 34 } 35 36 ln, err := Listen("tcp", "[::]:0") 37 if err != nil { 38 t.Fatal(err) 39 } 40 defer ln.Close() 41 42 _, port, err := SplitHostPort(ln.Addr().String()) 43 if err != nil { 44 t.Fatal(err) 45 } 46 47 for i, tt := range prohibitionaryDialArgTests { 48 c, err := Dial(tt.network, JoinHostPort(tt.address, port)) 49 if err == nil { 50 c.Close() 51 t.Errorf("#%d: %v", i, err) 52 } 53 } 54 } 55 56 func TestSelfConnect(t *testing.T) { 57 if runtime.GOOS == "windows" { 58 // TODO(brainman): do not know why it hangs. 59 t.Skip("known-broken test on windows") 60 } 61 62 // Test that Dial does not honor self-connects. 63 // See the comment in DialTCP. 64 65 // Find a port that would be used as a local address. 66 l, err := Listen("tcp", "127.0.0.1:0") 67 if err != nil { 68 t.Fatal(err) 69 } 70 c, err := Dial("tcp", l.Addr().String()) 71 if err != nil { 72 t.Fatal(err) 73 } 74 addr := c.LocalAddr().String() 75 c.Close() 76 l.Close() 77 78 // Try to connect to that address repeatedly. 79 n := 100000 80 if testing.Short() { 81 n = 1000 82 } 83 switch runtime.GOOS { 84 case "darwin", "dragonfly", "freebsd", "netbsd", "openbsd", "plan9", "solaris", "windows": 85 // Non-Linux systems take a long time to figure 86 // out that there is nothing listening on localhost. 87 n = 100 88 } 89 for i := 0; i < n; i++ { 90 c, err := DialTimeout("tcp", addr, time.Millisecond) 91 if err == nil { 92 if c.LocalAddr().String() == addr { 93 t.Errorf("#%d: Dial %q self-connect", i, addr) 94 } else { 95 t.Logf("#%d: Dial %q succeeded - possibly racing with other listener", i, addr) 96 } 97 c.Close() 98 } 99 } 100 } 101 102 func TestDialTimeoutFDLeak(t *testing.T) { 103 switch runtime.GOOS { 104 case "plan9": 105 t.Skipf("%s does not have full support of socktest", runtime.GOOS) 106 } 107 108 const T = 100 * time.Millisecond 109 110 switch runtime.GOOS { 111 case "plan9", "windows": 112 origTestHookDialChannel := testHookDialChannel 113 testHookDialChannel = func() { time.Sleep(2 * T) } 114 defer func() { testHookDialChannel = origTestHookDialChannel }() 115 if runtime.GOOS == "plan9" { 116 break 117 } 118 fallthrough 119 default: 120 sw.Set(socktest.FilterConnect, func(so *socktest.Status) (socktest.AfterFilter, error) { 121 time.Sleep(2 * T) 122 return nil, errTimeout 123 }) 124 defer sw.Set(socktest.FilterConnect, nil) 125 } 126 127 // Avoid tracking open-close jitterbugs between netFD and 128 // socket that leads to confusion of information inside 129 // socktest.Switch. 130 // It may happen when the Dial call bumps against TCP 131 // simultaneous open. See selfConnect in tcpsock_posix.go. 132 defer func() { 133 sw.Set(socktest.FilterClose, nil) 134 forceCloseSockets() 135 }() 136 var mu sync.Mutex 137 var attempts int 138 sw.Set(socktest.FilterClose, func(so *socktest.Status) (socktest.AfterFilter, error) { 139 mu.Lock() 140 attempts++ 141 mu.Unlock() 142 return nil, errTimedout 143 }) 144 145 const N = 100 146 var wg sync.WaitGroup 147 wg.Add(N) 148 for i := 0; i < N; i++ { 149 go func() { 150 defer wg.Done() 151 // This dial never starts to send any SYN 152 // segment because of above socket filter and 153 // test hook. 154 c, err := DialTimeout("tcp", "127.0.0.1:0", T) 155 if err == nil { 156 t.Errorf("unexpectedly established: tcp:%s->%s", c.LocalAddr(), c.RemoteAddr()) 157 c.Close() 158 } 159 }() 160 } 161 wg.Wait() 162 if attempts < N { 163 t.Errorf("got %d; want >= %d", attempts, N) 164 } 165 } 166 167 func TestDialerDualStackFDLeak(t *testing.T) { 168 switch runtime.GOOS { 169 case "plan9": 170 t.Skipf("%s does not have full support of socktest", runtime.GOOS) 171 case "windows": 172 t.Skipf("not implemented a way to cancel dial racers in TCP SYN-SENT state on %s", runtime.GOOS) 173 } 174 if !supportsIPv4 || !supportsIPv6 { 175 t.Skip("both IPv4 and IPv6 are required") 176 } 177 178 origTestHookLookupIP := testHookLookupIP 179 defer func() { testHookLookupIP = origTestHookLookupIP }() 180 testHookLookupIP = lookupLocalhost 181 handler := func(dss *dualStackServer, ln Listener) { 182 for { 183 c, err := ln.Accept() 184 if err != nil { 185 return 186 } 187 c.Close() 188 } 189 } 190 dss, err := newDualStackServer([]streamListener{ 191 {network: "tcp4", address: "127.0.0.1"}, 192 {network: "tcp6", address: "::1"}, 193 }) 194 if err != nil { 195 t.Fatal(err) 196 } 197 defer dss.teardown() 198 if err := dss.buildup(handler); err != nil { 199 t.Fatal(err) 200 } 201 202 before := sw.Sockets() 203 const T = 100 * time.Millisecond 204 const N = 10 205 var wg sync.WaitGroup 206 wg.Add(N) 207 d := &Dialer{DualStack: true, Timeout: T} 208 for i := 0; i < N; i++ { 209 go func() { 210 defer wg.Done() 211 c, err := d.Dial("tcp", JoinHostPort("localhost", dss.port)) 212 if err != nil { 213 t.Error(err) 214 return 215 } 216 c.Close() 217 }() 218 } 219 wg.Wait() 220 time.Sleep(2 * T) // wait for the dial racers to stop 221 after := sw.Sockets() 222 if len(after) != len(before) { 223 t.Errorf("got %d; want %d", len(after), len(before)) 224 } 225 } 226 227 // Define a pair of blackholed (IPv4, IPv6) addresses, for which dialTCP is 228 // expected to hang until the timeout elapses. These addresses are reserved 229 // for benchmarking by RFC 6890. 230 const ( 231 slowDst4 = "192.18.0.254" 232 slowDst6 = "2001:2::254" 233 slowTimeout = 1 * time.Second 234 ) 235 236 // In some environments, the slow IPs may be explicitly unreachable, and fail 237 // more quickly than expected. This test hook prevents dialTCP from returning 238 // before the deadline. 239 func slowDialTCP(net string, laddr, raddr *TCPAddr, deadline time.Time) (*TCPConn, error) { 240 c, err := dialTCP(net, laddr, raddr, deadline) 241 if ParseIP(slowDst4).Equal(raddr.IP) || ParseIP(slowDst6).Equal(raddr.IP) { 242 time.Sleep(deadline.Sub(time.Now())) 243 } 244 return c, err 245 } 246 247 func dialClosedPort() (actual, expected time.Duration) { 248 // Estimate the expected time for this platform. 249 // On Windows, dialing a closed port takes roughly 1 second, 250 // but other platforms should be instantaneous. 251 if runtime.GOOS == "windows" { 252 expected = 1500 * time.Millisecond 253 } else { 254 expected = 95 * time.Millisecond 255 } 256 257 l, err := Listen("tcp", "127.0.0.1:0") 258 if err != nil { 259 return 999 * time.Hour, expected 260 } 261 addr := l.Addr().String() 262 l.Close() 263 // On OpenBSD, interference from TestSelfConnect is mysteriously 264 // causing the first attempt to hang for a few seconds, so we throw 265 // away the first result and keep the second. 266 for i := 1; ; i++ { 267 startTime := time.Now() 268 c, err := Dial("tcp", addr) 269 if err == nil { 270 c.Close() 271 } 272 elapsed := time.Now().Sub(startTime) 273 if i == 2 { 274 return elapsed, expected 275 } 276 } 277 } 278 279 func TestDialParallel(t *testing.T) { 280 if testing.Short() || !*testExternal { 281 t.Skip("avoid external network") 282 } 283 if !supportsIPv4 || !supportsIPv6 { 284 t.Skip("both IPv4 and IPv6 are required") 285 } 286 287 closedPortDelay, expectClosedPortDelay := dialClosedPort() 288 if closedPortDelay > expectClosedPortDelay { 289 t.Errorf("got %v; want <= %v", closedPortDelay, expectClosedPortDelay) 290 } 291 292 const instant time.Duration = 0 293 const fallbackDelay = 200 * time.Millisecond 294 295 // Some cases will run quickly when "connection refused" is fast, 296 // or trigger the fallbackDelay on Windows. This value holds the 297 // lesser of the two delays. 298 var closedPortOrFallbackDelay time.Duration 299 if closedPortDelay < fallbackDelay { 300 closedPortOrFallbackDelay = closedPortDelay 301 } else { 302 closedPortOrFallbackDelay = fallbackDelay 303 } 304 305 origTestHookDialTCP := testHookDialTCP 306 defer func() { testHookDialTCP = origTestHookDialTCP }() 307 testHookDialTCP = slowDialTCP 308 309 nCopies := func(s string, n int) []string { 310 out := make([]string, n) 311 for i := 0; i < n; i++ { 312 out[i] = s 313 } 314 return out 315 } 316 317 var testCases = []struct { 318 primaries []string 319 fallbacks []string 320 teardownNetwork string 321 expectOk bool 322 expectElapsed time.Duration 323 }{ 324 // These should just work on the first try. 325 {[]string{"127.0.0.1"}, []string{}, "", true, instant}, 326 {[]string{"::1"}, []string{}, "", true, instant}, 327 {[]string{"127.0.0.1", "::1"}, []string{slowDst6}, "tcp6", true, instant}, 328 {[]string{"::1", "127.0.0.1"}, []string{slowDst4}, "tcp4", true, instant}, 329 // Primary is slow; fallback should kick in. 330 {[]string{slowDst4}, []string{"::1"}, "", true, fallbackDelay}, 331 // Skip a "connection refused" in the primary thread. 332 {[]string{"127.0.0.1", "::1"}, []string{}, "tcp4", true, closedPortDelay}, 333 {[]string{"::1", "127.0.0.1"}, []string{}, "tcp6", true, closedPortDelay}, 334 // Skip a "connection refused" in the fallback thread. 335 {[]string{slowDst4, slowDst6}, []string{"::1", "127.0.0.1"}, "tcp6", true, fallbackDelay + closedPortDelay}, 336 // Primary refused, fallback without delay. 337 {[]string{"127.0.0.1"}, []string{"::1"}, "tcp4", true, closedPortOrFallbackDelay}, 338 {[]string{"::1"}, []string{"127.0.0.1"}, "tcp6", true, closedPortOrFallbackDelay}, 339 // Everything is refused. 340 {[]string{"127.0.0.1"}, []string{}, "tcp4", false, closedPortDelay}, 341 // Nothing to do; fail instantly. 342 {[]string{}, []string{}, "", false, instant}, 343 // Connecting to tons of addresses should not trip the deadline. 344 {nCopies("::1", 1000), []string{}, "", true, instant}, 345 } 346 347 handler := func(dss *dualStackServer, ln Listener) { 348 for { 349 c, err := ln.Accept() 350 if err != nil { 351 return 352 } 353 c.Close() 354 } 355 } 356 357 // Convert a list of IP strings into TCPAddrs. 358 makeAddrs := func(ips []string, port string) addrList { 359 var out addrList 360 for _, ip := range ips { 361 addr, err := ResolveTCPAddr("tcp", JoinHostPort(ip, port)) 362 if err != nil { 363 t.Fatal(err) 364 } 365 out = append(out, addr) 366 } 367 return out 368 } 369 370 for i, tt := range testCases { 371 dss, err := newDualStackServer([]streamListener{ 372 {network: "tcp4", address: "127.0.0.1"}, 373 {network: "tcp6", address: "::1"}, 374 }) 375 if err != nil { 376 t.Fatal(err) 377 } 378 defer dss.teardown() 379 if err := dss.buildup(handler); err != nil { 380 t.Fatal(err) 381 } 382 if tt.teardownNetwork != "" { 383 // Destroy one of the listening sockets, creating an unreachable port. 384 dss.teardownNetwork(tt.teardownNetwork) 385 } 386 387 primaries := makeAddrs(tt.primaries, dss.port) 388 fallbacks := makeAddrs(tt.fallbacks, dss.port) 389 d := Dialer{ 390 FallbackDelay: fallbackDelay, 391 Timeout: slowTimeout, 392 } 393 ctx := &dialContext{ 394 Dialer: d, 395 network: "tcp", 396 address: "?", 397 finalDeadline: d.deadline(time.Now()), 398 } 399 startTime := time.Now() 400 c, err := dialParallel(ctx, primaries, fallbacks) 401 elapsed := time.Now().Sub(startTime) 402 403 if c != nil { 404 c.Close() 405 } 406 407 if tt.expectOk && err != nil { 408 t.Errorf("#%d: got %v; want nil", i, err) 409 } else if !tt.expectOk && err == nil { 410 t.Errorf("#%d: got nil; want non-nil", i) 411 } 412 413 expectElapsedMin := tt.expectElapsed - 95*time.Millisecond 414 expectElapsedMax := tt.expectElapsed + 95*time.Millisecond 415 if !(elapsed >= expectElapsedMin) { 416 t.Errorf("#%d: got %v; want >= %v", i, elapsed, expectElapsedMin) 417 } else if !(elapsed <= expectElapsedMax) { 418 t.Errorf("#%d: got %v; want <= %v", i, elapsed, expectElapsedMax) 419 } 420 } 421 // Wait for any slowDst4/slowDst6 connections to timeout. 422 time.Sleep(slowTimeout * 3 / 2) 423 } 424 425 func lookupSlowFast(fn func(string) ([]IPAddr, error), host string) ([]IPAddr, error) { 426 switch host { 427 case "slow6loopback4": 428 // Returns a slow IPv6 address, and a local IPv4 address. 429 return []IPAddr{ 430 {IP: ParseIP(slowDst6)}, 431 {IP: ParseIP("127.0.0.1")}, 432 }, nil 433 default: 434 return fn(host) 435 } 436 } 437 438 func TestDialerFallbackDelay(t *testing.T) { 439 if testing.Short() || !*testExternal { 440 t.Skip("avoid external network") 441 } 442 if !supportsIPv4 || !supportsIPv6 { 443 t.Skip("both IPv4 and IPv6 are required") 444 } 445 446 origTestHookLookupIP := testHookLookupIP 447 defer func() { testHookLookupIP = origTestHookLookupIP }() 448 testHookLookupIP = lookupSlowFast 449 450 origTestHookDialTCP := testHookDialTCP 451 defer func() { testHookDialTCP = origTestHookDialTCP }() 452 testHookDialTCP = slowDialTCP 453 454 var testCases = []struct { 455 dualstack bool 456 delay time.Duration 457 expectElapsed time.Duration 458 }{ 459 // Use a very brief delay, which should fallback immediately. 460 {true, 1 * time.Nanosecond, 0}, 461 // Use a 200ms explicit timeout. 462 {true, 200 * time.Millisecond, 200 * time.Millisecond}, 463 // The default is 300ms. 464 {true, 0, 300 * time.Millisecond}, 465 // This case is last, in order to wait for hanging slowDst6 connections. 466 {false, 0, slowTimeout}, 467 } 468 469 handler := func(dss *dualStackServer, ln Listener) { 470 for { 471 c, err := ln.Accept() 472 if err != nil { 473 return 474 } 475 c.Close() 476 } 477 } 478 dss, err := newDualStackServer([]streamListener{ 479 {network: "tcp", address: "127.0.0.1"}, 480 }) 481 if err != nil { 482 t.Fatal(err) 483 } 484 defer dss.teardown() 485 if err := dss.buildup(handler); err != nil { 486 t.Fatal(err) 487 } 488 489 for i, tt := range testCases { 490 d := &Dialer{DualStack: tt.dualstack, FallbackDelay: tt.delay, Timeout: slowTimeout} 491 492 startTime := time.Now() 493 c, err := d.Dial("tcp", JoinHostPort("slow6loopback4", dss.port)) 494 elapsed := time.Now().Sub(startTime) 495 if err == nil { 496 c.Close() 497 } else if tt.dualstack { 498 t.Error(err) 499 } 500 expectMin := tt.expectElapsed - 1*time.Millisecond 501 expectMax := tt.expectElapsed + 95*time.Millisecond 502 if !(elapsed >= expectMin) { 503 t.Errorf("#%d: got %v; want >= %v", i, elapsed, expectMin) 504 } 505 if !(elapsed <= expectMax) { 506 t.Errorf("#%d: got %v; want <= %v", i, elapsed, expectMax) 507 } 508 } 509 } 510 511 func TestDialSerialAsyncSpuriousConnection(t *testing.T) { 512 if runtime.GOOS == "plan9" { 513 t.Skip("skipping on plan9; no deadline support, golang.org/issue/11932") 514 } 515 ln, err := newLocalListener("tcp") 516 if err != nil { 517 t.Fatal(err) 518 } 519 defer ln.Close() 520 521 d := Dialer{} 522 ctx := &dialContext{ 523 Dialer: d, 524 network: "tcp", 525 address: "?", 526 finalDeadline: d.deadline(time.Now()), 527 } 528 529 results := make(chan dialResult) 530 cancel := make(chan struct{}) 531 532 // Spawn a connection in the background. 533 go dialSerialAsync(ctx, addrList{ln.Addr()}, nil, cancel, results) 534 535 // Receive it at the server. 536 c, err := ln.Accept() 537 if err != nil { 538 t.Fatal(err) 539 } 540 defer c.Close() 541 542 // Tell dialSerialAsync that someone else won the race. 543 close(cancel) 544 545 // The connection should close itself, without sending data. 546 c.SetReadDeadline(time.Now().Add(1 * time.Second)) 547 var b [1]byte 548 if _, err := c.Read(b[:]); err != io.EOF { 549 t.Errorf("got %v; want %v", err, io.EOF) 550 } 551 } 552 553 func TestDialerPartialDeadline(t *testing.T) { 554 now := time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC) 555 var testCases = []struct { 556 now time.Time 557 deadline time.Time 558 addrs int 559 expectDeadline time.Time 560 expectErr error 561 }{ 562 // Regular division. 563 {now, now.Add(12 * time.Second), 1, now.Add(12 * time.Second), nil}, 564 {now, now.Add(12 * time.Second), 2, now.Add(6 * time.Second), nil}, 565 {now, now.Add(12 * time.Second), 3, now.Add(4 * time.Second), nil}, 566 // Bump against the 2-second sane minimum. 567 {now, now.Add(12 * time.Second), 999, now.Add(2 * time.Second), nil}, 568 // Total available is now below the sane minimum. 569 {now, now.Add(1900 * time.Millisecond), 999, now.Add(1900 * time.Millisecond), nil}, 570 // Null deadline. 571 {now, noDeadline, 1, noDeadline, nil}, 572 // Step the clock forward and cross the deadline. 573 {now.Add(-1 * time.Millisecond), now, 1, now, nil}, 574 {now.Add(0 * time.Millisecond), now, 1, noDeadline, errTimeout}, 575 {now.Add(1 * time.Millisecond), now, 1, noDeadline, errTimeout}, 576 } 577 for i, tt := range testCases { 578 deadline, err := partialDeadline(tt.now, tt.deadline, tt.addrs) 579 if err != tt.expectErr { 580 t.Errorf("#%d: got %v; want %v", i, err, tt.expectErr) 581 } 582 if deadline != tt.expectDeadline { 583 t.Errorf("#%d: got %v; want %v", i, deadline, tt.expectDeadline) 584 } 585 } 586 } 587 588 func TestDialerLocalAddr(t *testing.T) { 589 ch := make(chan error, 1) 590 handler := func(ls *localServer, ln Listener) { 591 c, err := ln.Accept() 592 if err != nil { 593 ch <- err 594 return 595 } 596 defer c.Close() 597 ch <- nil 598 } 599 ls, err := newLocalServer("tcp") 600 if err != nil { 601 t.Fatal(err) 602 } 603 defer ls.teardown() 604 if err := ls.buildup(handler); err != nil { 605 t.Fatal(err) 606 } 607 608 laddr, err := ResolveTCPAddr(ls.Listener.Addr().Network(), ls.Listener.Addr().String()) 609 if err != nil { 610 t.Fatal(err) 611 } 612 laddr.Port = 0 613 d := &Dialer{LocalAddr: laddr} 614 c, err := d.Dial(ls.Listener.Addr().Network(), ls.Addr().String()) 615 if err != nil { 616 t.Fatal(err) 617 } 618 defer c.Close() 619 c.Read(make([]byte, 1)) 620 err = <-ch 621 if err != nil { 622 t.Error(err) 623 } 624 } 625 626 func TestDialerDualStack(t *testing.T) { 627 if !supportsIPv4 || !supportsIPv6 { 628 t.Skip("both IPv4 and IPv6 are required") 629 } 630 631 closedPortDelay, expectClosedPortDelay := dialClosedPort() 632 if closedPortDelay > expectClosedPortDelay { 633 t.Errorf("got %v; want <= %v", closedPortDelay, expectClosedPortDelay) 634 } 635 636 origTestHookLookupIP := testHookLookupIP 637 defer func() { testHookLookupIP = origTestHookLookupIP }() 638 testHookLookupIP = lookupLocalhost 639 handler := func(dss *dualStackServer, ln Listener) { 640 for { 641 c, err := ln.Accept() 642 if err != nil { 643 return 644 } 645 c.Close() 646 } 647 } 648 649 var timeout = 150*time.Millisecond + closedPortDelay 650 for _, dualstack := range []bool{false, true} { 651 dss, err := newDualStackServer([]streamListener{ 652 {network: "tcp4", address: "127.0.0.1"}, 653 {network: "tcp6", address: "::1"}, 654 }) 655 if err != nil { 656 t.Fatal(err) 657 } 658 defer dss.teardown() 659 if err := dss.buildup(handler); err != nil { 660 t.Fatal(err) 661 } 662 663 d := &Dialer{DualStack: dualstack, Timeout: timeout} 664 for range dss.lns { 665 c, err := d.Dial("tcp", JoinHostPort("localhost", dss.port)) 666 if err != nil { 667 t.Error(err) 668 continue 669 } 670 switch addr := c.LocalAddr().(*TCPAddr); { 671 case addr.IP.To4() != nil: 672 dss.teardownNetwork("tcp4") 673 case addr.IP.To16() != nil && addr.IP.To4() == nil: 674 dss.teardownNetwork("tcp6") 675 } 676 c.Close() 677 } 678 } 679 time.Sleep(timeout * 3 / 2) // wait for the dial racers to stop 680 } 681 682 func TestDialerKeepAlive(t *testing.T) { 683 handler := func(ls *localServer, ln Listener) { 684 for { 685 c, err := ln.Accept() 686 if err != nil { 687 return 688 } 689 c.Close() 690 } 691 } 692 ls, err := newLocalServer("tcp") 693 if err != nil { 694 t.Fatal(err) 695 } 696 defer ls.teardown() 697 if err := ls.buildup(handler); err != nil { 698 t.Fatal(err) 699 } 700 defer func() { testHookSetKeepAlive = func() {} }() 701 702 for _, keepAlive := range []bool{false, true} { 703 got := false 704 testHookSetKeepAlive = func() { got = true } 705 var d Dialer 706 if keepAlive { 707 d.KeepAlive = 30 * time.Second 708 } 709 c, err := d.Dial("tcp", ls.Listener.Addr().String()) 710 if err != nil { 711 t.Fatal(err) 712 } 713 c.Close() 714 if got != keepAlive { 715 t.Errorf("Dialer.KeepAlive = %v: SetKeepAlive called = %v, want %v", d.KeepAlive, got, !got) 716 } 717 } 718 }