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