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