github.com/d4l3k/go@v0.0.0-20151015000803-65fc379daeda/src/net/error_test.go (about)

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