github.com/miolini/go@v0.0.0-20160405192216-fca68c8cb408/src/net/error_test.go (about) 1 // Copyright 2015 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 "fmt" 9 "io" 10 "io/ioutil" 11 "net/internal/socktest" 12 "os" 13 "runtime" 14 "testing" 15 "time" 16 ) 17 18 func (e *OpError) isValid() error { 19 if e.Op == "" { 20 return fmt.Errorf("OpError.Op is empty: %v", e) 21 } 22 if e.Net == "" { 23 return fmt.Errorf("OpError.Net is empty: %v", e) 24 } 25 for _, addr := range []Addr{e.Source, e.Addr} { 26 switch addr := addr.(type) { 27 case nil: 28 case *TCPAddr: 29 if addr == nil { 30 return fmt.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr, e) 31 } 32 case *UDPAddr: 33 if addr == nil { 34 return fmt.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr, e) 35 } 36 case *IPAddr: 37 if addr == nil { 38 return fmt.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr, e) 39 } 40 case *IPNet: 41 if addr == nil { 42 return fmt.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr, e) 43 } 44 case *UnixAddr: 45 if addr == nil { 46 return fmt.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr, e) 47 } 48 case *pipeAddr: 49 if addr == nil { 50 return fmt.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr, e) 51 } 52 case fileAddr: 53 if addr == "" { 54 return fmt.Errorf("OpError.Source or Addr is empty: %#v, %v", addr, e) 55 } 56 default: 57 return fmt.Errorf("OpError.Source or Addr is unknown type: %T, %v", addr, e) 58 } 59 } 60 if e.Err == nil { 61 return fmt.Errorf("OpError.Err is empty: %v", e) 62 } 63 return nil 64 } 65 66 // parseDialError parses nestedErr and reports whether it is a valid 67 // error value from Dial, Listen functions. 68 // It returns nil when nestedErr is valid. 69 func parseDialError(nestedErr error) error { 70 if nestedErr == nil { 71 return nil 72 } 73 74 switch err := nestedErr.(type) { 75 case *OpError: 76 if err := err.isValid(); err != nil { 77 return err 78 } 79 nestedErr = err.Err 80 goto second 81 } 82 return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr) 83 84 second: 85 if isPlatformError(nestedErr) { 86 return nil 87 } 88 switch err := nestedErr.(type) { 89 case *AddrError, addrinfoErrno, *DNSError, InvalidAddrError, *ParseError, *timeoutError, UnknownNetworkError: 90 return nil 91 case *os.SyscallError: 92 nestedErr = err.Err 93 goto third 94 case *os.PathError: // for Plan 9 95 nestedErr = err.Err 96 goto third 97 } 98 switch nestedErr { 99 case errCanceled, errClosing, errMissingAddress, errNoSuitableAddress: 100 return nil 101 } 102 return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr) 103 104 third: 105 if isPlatformError(nestedErr) { 106 return nil 107 } 108 return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr) 109 } 110 111 var dialErrorTests = []struct { 112 network, address string 113 }{ 114 {"foo", ""}, 115 {"bar", "baz"}, 116 {"datakit", "mh/astro/r70"}, 117 {"tcp", ""}, 118 {"tcp", "127.0.0.1:☺"}, 119 {"tcp", "no-such-name:80"}, 120 {"tcp", "mh/astro/r70:http"}, 121 122 {"tcp", JoinHostPort("127.0.0.1", "-1")}, 123 {"tcp", JoinHostPort("127.0.0.1", "123456789")}, 124 {"udp", JoinHostPort("127.0.0.1", "-1")}, 125 {"udp", JoinHostPort("127.0.0.1", "123456789")}, 126 {"ip:icmp", "127.0.0.1"}, 127 128 {"unix", "/path/to/somewhere"}, 129 {"unixgram", "/path/to/somewhere"}, 130 {"unixpacket", "/path/to/somewhere"}, 131 } 132 133 func TestDialError(t *testing.T) { 134 switch runtime.GOOS { 135 case "plan9": 136 t.Skipf("%s does not have full support of socktest", runtime.GOOS) 137 } 138 139 origTestHookLookupIP := testHookLookupIP 140 defer func() { testHookLookupIP = origTestHookLookupIP }() 141 testHookLookupIP = func(fn func(string) ([]IPAddr, error), host string) ([]IPAddr, error) { 142 return nil, &DNSError{Err: "dial error test", Name: "name", Server: "server", IsTimeout: true} 143 } 144 sw.Set(socktest.FilterConnect, func(so *socktest.Status) (socktest.AfterFilter, error) { 145 return nil, errOpNotSupported 146 }) 147 defer sw.Set(socktest.FilterConnect, nil) 148 149 d := Dialer{Timeout: someTimeout} 150 for i, tt := range dialErrorTests { 151 c, err := d.Dial(tt.network, tt.address) 152 if err == nil { 153 t.Errorf("#%d: should fail; %s:%s->%s", i, c.LocalAddr().Network(), c.LocalAddr(), c.RemoteAddr()) 154 c.Close() 155 continue 156 } 157 if tt.network == "tcp" || tt.network == "udp" { 158 nerr := err 159 if op, ok := nerr.(*OpError); ok { 160 nerr = op.Err 161 } 162 if sys, ok := nerr.(*os.SyscallError); ok { 163 nerr = sys.Err 164 } 165 if nerr == errOpNotSupported { 166 t.Errorf("#%d: should fail without %v; %s:%s->", i, nerr, tt.network, tt.address) 167 continue 168 } 169 } 170 if c != nil { 171 t.Errorf("Dial returned non-nil interface %T(%v) with err != nil", c, c) 172 } 173 if err = parseDialError(err); err != nil { 174 t.Errorf("#%d: %v", i, err) 175 continue 176 } 177 } 178 } 179 180 func TestProtocolDialError(t *testing.T) { 181 switch runtime.GOOS { 182 case "nacl", "solaris": 183 t.Skipf("not supported on %s", runtime.GOOS) 184 } 185 186 for _, network := range []string{"tcp", "udp", "ip:4294967296", "unix", "unixpacket", "unixgram"} { 187 var err error 188 switch network { 189 case "tcp": 190 _, err = DialTCP(network, nil, &TCPAddr{Port: 1 << 16}) 191 case "udp": 192 _, err = DialUDP(network, nil, &UDPAddr{Port: 1 << 16}) 193 case "ip:4294967296": 194 _, err = DialIP(network, nil, nil) 195 case "unix", "unixpacket", "unixgram": 196 _, err = DialUnix(network, nil, &UnixAddr{Name: "//"}) 197 } 198 if err == nil { 199 t.Errorf("%s: should fail", network) 200 continue 201 } 202 if err = parseDialError(err); err != nil { 203 t.Errorf("%s: %v", network, err) 204 continue 205 } 206 } 207 } 208 209 var listenErrorTests = []struct { 210 network, address string 211 }{ 212 {"foo", ""}, 213 {"bar", "baz"}, 214 {"datakit", "mh/astro/r70"}, 215 {"tcp", "127.0.0.1:☺"}, 216 {"tcp", "no-such-name:80"}, 217 {"tcp", "mh/astro/r70:http"}, 218 219 {"tcp", JoinHostPort("127.0.0.1", "-1")}, 220 {"tcp", JoinHostPort("127.0.0.1", "123456789")}, 221 222 {"unix", "/path/to/somewhere"}, 223 {"unixpacket", "/path/to/somewhere"}, 224 } 225 226 func TestListenError(t *testing.T) { 227 switch runtime.GOOS { 228 case "plan9": 229 t.Skipf("%s does not have full support of socktest", runtime.GOOS) 230 } 231 232 origTestHookLookupIP := testHookLookupIP 233 defer func() { testHookLookupIP = origTestHookLookupIP }() 234 testHookLookupIP = func(fn func(string) ([]IPAddr, error), host string) ([]IPAddr, error) { 235 return nil, &DNSError{Err: "listen error test", Name: "name", Server: "server", IsTimeout: true} 236 } 237 sw.Set(socktest.FilterListen, func(so *socktest.Status) (socktest.AfterFilter, error) { 238 return nil, errOpNotSupported 239 }) 240 defer sw.Set(socktest.FilterListen, nil) 241 242 for i, tt := range listenErrorTests { 243 ln, err := Listen(tt.network, tt.address) 244 if err == nil { 245 t.Errorf("#%d: should fail; %s:%s->", i, ln.Addr().Network(), ln.Addr()) 246 ln.Close() 247 continue 248 } 249 if tt.network == "tcp" { 250 nerr := err 251 if op, ok := nerr.(*OpError); ok { 252 nerr = op.Err 253 } 254 if sys, ok := nerr.(*os.SyscallError); ok { 255 nerr = sys.Err 256 } 257 if nerr == errOpNotSupported { 258 t.Errorf("#%d: should fail without %v; %s:%s->", i, nerr, tt.network, tt.address) 259 continue 260 } 261 } 262 if ln != nil { 263 t.Errorf("Listen returned non-nil interface %T(%v) with err != nil", ln, ln) 264 } 265 if err = parseDialError(err); err != nil { 266 t.Errorf("#%d: %v", i, err) 267 continue 268 } 269 } 270 } 271 272 var listenPacketErrorTests = []struct { 273 network, address string 274 }{ 275 {"foo", ""}, 276 {"bar", "baz"}, 277 {"datakit", "mh/astro/r70"}, 278 {"udp", "127.0.0.1:☺"}, 279 {"udp", "no-such-name:80"}, 280 {"udp", "mh/astro/r70:http"}, 281 282 {"udp", JoinHostPort("127.0.0.1", "-1")}, 283 {"udp", JoinHostPort("127.0.0.1", "123456789")}, 284 } 285 286 func TestListenPacketError(t *testing.T) { 287 switch runtime.GOOS { 288 case "plan9": 289 t.Skipf("%s does not have full support of socktest", runtime.GOOS) 290 } 291 292 origTestHookLookupIP := testHookLookupIP 293 defer func() { testHookLookupIP = origTestHookLookupIP }() 294 testHookLookupIP = func(fn func(string) ([]IPAddr, error), host string) ([]IPAddr, error) { 295 return nil, &DNSError{Err: "listen error test", Name: "name", Server: "server", IsTimeout: true} 296 } 297 298 for i, tt := range listenPacketErrorTests { 299 c, err := ListenPacket(tt.network, tt.address) 300 if err == nil { 301 t.Errorf("#%d: should fail; %s:%s->", i, c.LocalAddr().Network(), c.LocalAddr()) 302 c.Close() 303 continue 304 } 305 if c != nil { 306 t.Errorf("ListenPacket returned non-nil interface %T(%v) with err != nil", c, c) 307 } 308 if err = parseDialError(err); err != nil { 309 t.Errorf("#%d: %v", i, err) 310 continue 311 } 312 } 313 } 314 315 func TestProtocolListenError(t *testing.T) { 316 switch runtime.GOOS { 317 case "nacl", "plan9": 318 t.Skipf("not supported on %s", runtime.GOOS) 319 } 320 321 for _, network := range []string{"tcp", "udp", "ip:4294967296", "unix", "unixpacket", "unixgram"} { 322 var err error 323 switch network { 324 case "tcp": 325 _, err = ListenTCP(network, &TCPAddr{Port: 1 << 16}) 326 case "udp": 327 _, err = ListenUDP(network, &UDPAddr{Port: 1 << 16}) 328 case "ip:4294967296": 329 _, err = ListenIP(network, nil) 330 case "unix", "unixpacket": 331 _, err = ListenUnix(network, &UnixAddr{Name: "//"}) 332 case "unixgram": 333 _, err = ListenUnixgram(network, &UnixAddr{Name: "//"}) 334 } 335 if err == nil { 336 t.Errorf("%s: should fail", network) 337 continue 338 } 339 if err = parseDialError(err); err != nil { 340 t.Errorf("%s: %v", network, err) 341 continue 342 } 343 } 344 } 345 346 // parseReadError parses nestedErr and reports whether it is a valid 347 // error value from Read functions. 348 // It returns nil when nestedErr is valid. 349 func parseReadError(nestedErr error) error { 350 if nestedErr == nil { 351 return nil 352 } 353 354 switch err := nestedErr.(type) { 355 case *OpError: 356 if err := err.isValid(); err != nil { 357 return err 358 } 359 nestedErr = err.Err 360 goto second 361 } 362 if nestedErr == io.EOF { 363 return nil 364 } 365 return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr) 366 367 second: 368 if isPlatformError(nestedErr) { 369 return nil 370 } 371 switch err := nestedErr.(type) { 372 case *os.SyscallError: 373 nestedErr = err.Err 374 goto third 375 } 376 switch nestedErr { 377 case errClosing, errTimeout: 378 return nil 379 } 380 return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr) 381 382 third: 383 if isPlatformError(nestedErr) { 384 return nil 385 } 386 return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr) 387 } 388 389 // parseWriteError parses nestedErr and reports whether it is a valid 390 // error value from Write functions. 391 // It returns nil when nestedErr is valid. 392 func parseWriteError(nestedErr error) error { 393 if nestedErr == nil { 394 return nil 395 } 396 397 switch err := nestedErr.(type) { 398 case *OpError: 399 if err := err.isValid(); err != nil { 400 return err 401 } 402 nestedErr = err.Err 403 goto second 404 } 405 return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr) 406 407 second: 408 if isPlatformError(nestedErr) { 409 return nil 410 } 411 switch err := nestedErr.(type) { 412 case *AddrError, addrinfoErrno, *DNSError, InvalidAddrError, *ParseError, *timeoutError, UnknownNetworkError: 413 return nil 414 case *os.SyscallError: 415 nestedErr = err.Err 416 goto third 417 } 418 switch nestedErr { 419 case errCanceled, errClosing, errMissingAddress, errTimeout, ErrWriteToConnected, io.ErrUnexpectedEOF: 420 return nil 421 } 422 return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr) 423 424 third: 425 if isPlatformError(nestedErr) { 426 return nil 427 } 428 return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr) 429 } 430 431 // parseCloseError parses nestedErr and reports whether it is a valid 432 // error value from Close functions. 433 // It returns nil when nestedErr is valid. 434 func parseCloseError(nestedErr error) error { 435 if nestedErr == nil { 436 return nil 437 } 438 439 switch err := nestedErr.(type) { 440 case *OpError: 441 if err := err.isValid(); err != nil { 442 return err 443 } 444 nestedErr = err.Err 445 goto second 446 } 447 return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr) 448 449 second: 450 if isPlatformError(nestedErr) { 451 return nil 452 } 453 switch err := nestedErr.(type) { 454 case *os.SyscallError: 455 nestedErr = err.Err 456 goto third 457 case *os.PathError: // for Plan 9 458 nestedErr = err.Err 459 goto third 460 } 461 switch nestedErr { 462 case errClosing: 463 return nil 464 } 465 return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr) 466 467 third: 468 if isPlatformError(nestedErr) { 469 return nil 470 } 471 return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr) 472 } 473 474 func TestCloseError(t *testing.T) { 475 ln, err := newLocalListener("tcp") 476 if err != nil { 477 t.Fatal(err) 478 } 479 defer ln.Close() 480 c, err := Dial(ln.Addr().Network(), ln.Addr().String()) 481 if err != nil { 482 t.Fatal(err) 483 } 484 defer c.Close() 485 486 for i := 0; i < 3; i++ { 487 err = c.(*TCPConn).CloseRead() 488 if perr := parseCloseError(err); perr != nil { 489 t.Errorf("#%d: %v", i, perr) 490 } 491 } 492 for i := 0; i < 3; i++ { 493 err = c.(*TCPConn).CloseWrite() 494 if perr := parseCloseError(err); perr != nil { 495 t.Errorf("#%d: %v", i, perr) 496 } 497 } 498 for i := 0; i < 3; i++ { 499 err = c.Close() 500 if perr := parseCloseError(err); perr != nil { 501 t.Errorf("#%d: %v", i, perr) 502 } 503 err = ln.Close() 504 if perr := parseCloseError(err); perr != nil { 505 t.Errorf("#%d: %v", i, perr) 506 } 507 } 508 509 pc, err := ListenPacket("udp", "127.0.0.1:0") 510 if err != nil { 511 t.Fatal(err) 512 } 513 defer pc.Close() 514 515 for i := 0; i < 3; i++ { 516 err = pc.Close() 517 if perr := parseCloseError(err); perr != nil { 518 t.Errorf("#%d: %v", i, perr) 519 } 520 } 521 } 522 523 // parseAcceptError parses nestedErr and reports whether it is a valid 524 // error value from Accept functions. 525 // It returns nil when nestedErr is valid. 526 func parseAcceptError(nestedErr error) error { 527 if nestedErr == nil { 528 return nil 529 } 530 531 switch err := nestedErr.(type) { 532 case *OpError: 533 if err := err.isValid(); err != nil { 534 return err 535 } 536 nestedErr = err.Err 537 goto second 538 } 539 return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr) 540 541 second: 542 if isPlatformError(nestedErr) { 543 return nil 544 } 545 switch err := nestedErr.(type) { 546 case *os.SyscallError: 547 nestedErr = err.Err 548 goto third 549 case *os.PathError: // for Plan 9 550 nestedErr = err.Err 551 goto third 552 } 553 switch nestedErr { 554 case errClosing, errTimeout: 555 return nil 556 } 557 return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr) 558 559 third: 560 if isPlatformError(nestedErr) { 561 return nil 562 } 563 return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr) 564 } 565 566 func TestAcceptError(t *testing.T) { 567 handler := func(ls *localServer, ln Listener) { 568 for { 569 ln.(*TCPListener).SetDeadline(time.Now().Add(5 * time.Millisecond)) 570 c, err := ln.Accept() 571 if perr := parseAcceptError(err); perr != nil { 572 t.Error(perr) 573 } 574 if err != nil { 575 if c != nil { 576 t.Errorf("Accept returned non-nil interface %T(%v) with err != nil", c, c) 577 } 578 if nerr, ok := err.(Error); !ok || (!nerr.Timeout() && !nerr.Temporary()) { 579 return 580 } 581 continue 582 } 583 c.Close() 584 } 585 } 586 ls, err := newLocalServer("tcp") 587 if err != nil { 588 t.Fatal(err) 589 } 590 if err := ls.buildup(handler); err != nil { 591 ls.teardown() 592 t.Fatal(err) 593 } 594 595 time.Sleep(100 * time.Millisecond) 596 ls.teardown() 597 } 598 599 // parseCommonError parses nestedErr and reports whether it is a valid 600 // error value from miscellaneous functions. 601 // It returns nil when nestedErr is valid. 602 func parseCommonError(nestedErr error) error { 603 if nestedErr == nil { 604 return nil 605 } 606 607 switch err := nestedErr.(type) { 608 case *OpError: 609 if err := err.isValid(); err != nil { 610 return err 611 } 612 nestedErr = err.Err 613 goto second 614 } 615 return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr) 616 617 second: 618 if isPlatformError(nestedErr) { 619 return nil 620 } 621 switch err := nestedErr.(type) { 622 case *os.SyscallError: 623 nestedErr = err.Err 624 goto third 625 case *os.LinkError: 626 nestedErr = err.Err 627 goto third 628 case *os.PathError: 629 nestedErr = err.Err 630 goto third 631 } 632 switch nestedErr { 633 case errClosing: 634 return nil 635 } 636 return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr) 637 638 third: 639 if isPlatformError(nestedErr) { 640 return nil 641 } 642 return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr) 643 } 644 645 func TestFileError(t *testing.T) { 646 switch runtime.GOOS { 647 case "windows": 648 t.Skipf("not supported on %s", runtime.GOOS) 649 } 650 651 f, err := ioutil.TempFile("", "go-nettest") 652 if err != nil { 653 t.Fatal(err) 654 } 655 defer os.Remove(f.Name()) 656 defer f.Close() 657 658 c, err := FileConn(f) 659 if err != nil { 660 if c != nil { 661 t.Errorf("FileConn returned non-nil interface %T(%v) with err != nil", c, c) 662 } 663 if perr := parseCommonError(err); perr != nil { 664 t.Error(perr) 665 } 666 } else { 667 c.Close() 668 t.Error("should fail") 669 } 670 ln, err := FileListener(f) 671 if err != nil { 672 if ln != nil { 673 t.Errorf("FileListener returned non-nil interface %T(%v) with err != nil", ln, ln) 674 } 675 if perr := parseCommonError(err); perr != nil { 676 t.Error(perr) 677 } 678 } else { 679 ln.Close() 680 t.Error("should fail") 681 } 682 pc, err := FilePacketConn(f) 683 if err != nil { 684 if pc != nil { 685 t.Errorf("FilePacketConn returned non-nil interface %T(%v) with err != nil", pc, pc) 686 } 687 if perr := parseCommonError(err); perr != nil { 688 t.Error(perr) 689 } 690 } else { 691 pc.Close() 692 t.Error("should fail") 693 } 694 695 ln, err = newLocalListener("tcp") 696 if err != nil { 697 t.Fatal(err) 698 } 699 700 for i := 0; i < 3; i++ { 701 f, err := ln.(*TCPListener).File() 702 if err != nil { 703 if perr := parseCommonError(err); perr != nil { 704 t.Error(perr) 705 } 706 } else { 707 f.Close() 708 } 709 ln.Close() 710 } 711 }