...
Run Format

Source file src/net/error_test.go

Documentation: net

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

View as plain text