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