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