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