github.com/peggyl/go@v0.0.0-20151008231540-ae315999c2d5/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 ln, err := newLocalListener("tcp") 513 if err != nil { 514 t.Fatal(err) 515 } 516 defer ln.Close() 517 518 d := Dialer{} 519 ctx := &dialContext{ 520 Dialer: d, 521 network: "tcp", 522 address: "?", 523 finalDeadline: d.deadline(time.Now()), 524 } 525 526 results := make(chan dialResult) 527 cancel := make(chan struct{}) 528 529 // Spawn a connection in the background. 530 go dialSerialAsync(ctx, addrList{ln.Addr()}, nil, cancel, results) 531 532 // Receive it at the server. 533 c, err := ln.Accept() 534 if err != nil { 535 t.Fatal(err) 536 } 537 defer c.Close() 538 539 // Tell dialSerialAsync that someone else won the race. 540 close(cancel) 541 542 // The connection should close itself, without sending data. 543 c.SetReadDeadline(time.Now().Add(1 * time.Second)) 544 var b [1]byte 545 if _, err := c.Read(b[:]); err != io.EOF { 546 t.Errorf("got %v; want %v", err, io.EOF) 547 } 548 } 549 550 func TestDialerPartialDeadline(t *testing.T) { 551 now := time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC) 552 var testCases = []struct { 553 now time.Time 554 deadline time.Time 555 addrs int 556 expectDeadline time.Time 557 expectErr error 558 }{ 559 // Regular division. 560 {now, now.Add(12 * time.Second), 1, now.Add(12 * time.Second), nil}, 561 {now, now.Add(12 * time.Second), 2, now.Add(6 * time.Second), nil}, 562 {now, now.Add(12 * time.Second), 3, now.Add(4 * time.Second), nil}, 563 // Bump against the 2-second sane minimum. 564 {now, now.Add(12 * time.Second), 999, now.Add(2 * time.Second), nil}, 565 // Total available is now below the sane minimum. 566 {now, now.Add(1900 * time.Millisecond), 999, now.Add(1900 * time.Millisecond), nil}, 567 // Null deadline. 568 {now, noDeadline, 1, noDeadline, nil}, 569 // Step the clock forward and cross the deadline. 570 {now.Add(-1 * time.Millisecond), now, 1, now, nil}, 571 {now.Add(0 * time.Millisecond), now, 1, noDeadline, errTimeout}, 572 {now.Add(1 * time.Millisecond), now, 1, noDeadline, errTimeout}, 573 } 574 for i, tt := range testCases { 575 deadline, err := partialDeadline(tt.now, tt.deadline, tt.addrs) 576 if err != tt.expectErr { 577 t.Errorf("#%d: got %v; want %v", i, err, tt.expectErr) 578 } 579 if deadline != tt.expectDeadline { 580 t.Errorf("#%d: got %v; want %v", i, deadline, tt.expectDeadline) 581 } 582 } 583 } 584 585 func TestDialerLocalAddr(t *testing.T) { 586 ch := make(chan error, 1) 587 handler := func(ls *localServer, ln Listener) { 588 c, err := ln.Accept() 589 if err != nil { 590 ch <- err 591 return 592 } 593 defer c.Close() 594 ch <- nil 595 } 596 ls, err := newLocalServer("tcp") 597 if err != nil { 598 t.Fatal(err) 599 } 600 defer ls.teardown() 601 if err := ls.buildup(handler); err != nil { 602 t.Fatal(err) 603 } 604 605 laddr, err := ResolveTCPAddr(ls.Listener.Addr().Network(), ls.Listener.Addr().String()) 606 if err != nil { 607 t.Fatal(err) 608 } 609 laddr.Port = 0 610 d := &Dialer{LocalAddr: laddr} 611 c, err := d.Dial(ls.Listener.Addr().Network(), ls.Addr().String()) 612 if err != nil { 613 t.Fatal(err) 614 } 615 defer c.Close() 616 c.Read(make([]byte, 1)) 617 err = <-ch 618 if err != nil { 619 t.Error(err) 620 } 621 } 622 623 func TestDialerDualStack(t *testing.T) { 624 if !supportsIPv4 || !supportsIPv6 { 625 t.Skip("both IPv4 and IPv6 are required") 626 } 627 628 closedPortDelay, expectClosedPortDelay := dialClosedPort() 629 if closedPortDelay > expectClosedPortDelay { 630 t.Errorf("got %v; want <= %v", closedPortDelay, expectClosedPortDelay) 631 } 632 633 origTestHookLookupIP := testHookLookupIP 634 defer func() { testHookLookupIP = origTestHookLookupIP }() 635 testHookLookupIP = lookupLocalhost 636 handler := func(dss *dualStackServer, ln Listener) { 637 for { 638 c, err := ln.Accept() 639 if err != nil { 640 return 641 } 642 c.Close() 643 } 644 } 645 646 var timeout = 150*time.Millisecond + closedPortDelay 647 for _, dualstack := range []bool{false, true} { 648 dss, err := newDualStackServer([]streamListener{ 649 {network: "tcp4", address: "127.0.0.1"}, 650 {network: "tcp6", address: "::1"}, 651 }) 652 if err != nil { 653 t.Fatal(err) 654 } 655 defer dss.teardown() 656 if err := dss.buildup(handler); err != nil { 657 t.Fatal(err) 658 } 659 660 d := &Dialer{DualStack: dualstack, Timeout: timeout} 661 for range dss.lns { 662 c, err := d.Dial("tcp", JoinHostPort("localhost", dss.port)) 663 if err != nil { 664 t.Error(err) 665 continue 666 } 667 switch addr := c.LocalAddr().(*TCPAddr); { 668 case addr.IP.To4() != nil: 669 dss.teardownNetwork("tcp4") 670 case addr.IP.To16() != nil && addr.IP.To4() == nil: 671 dss.teardownNetwork("tcp6") 672 } 673 c.Close() 674 } 675 } 676 time.Sleep(timeout * 3 / 2) // wait for the dial racers to stop 677 } 678 679 func TestDialerKeepAlive(t *testing.T) { 680 handler := func(ls *localServer, ln Listener) { 681 for { 682 c, err := ln.Accept() 683 if err != nil { 684 return 685 } 686 c.Close() 687 } 688 } 689 ls, err := newLocalServer("tcp") 690 if err != nil { 691 t.Fatal(err) 692 } 693 defer ls.teardown() 694 if err := ls.buildup(handler); err != nil { 695 t.Fatal(err) 696 } 697 defer func() { testHookSetKeepAlive = func() {} }() 698 699 for _, keepAlive := range []bool{false, true} { 700 got := false 701 testHookSetKeepAlive = func() { got = true } 702 var d Dialer 703 if keepAlive { 704 d.KeepAlive = 30 * time.Second 705 } 706 c, err := d.Dial("tcp", ls.Listener.Addr().String()) 707 if err != nil { 708 t.Fatal(err) 709 } 710 c.Close() 711 if got != keepAlive { 712 t.Errorf("Dialer.KeepAlive = %v: SetKeepAlive called = %v, want %v", d.KeepAlive, got, !got) 713 } 714 } 715 }