| // Copyright 2011 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| //go:build !js | |
| // +build !js | |
| package net | |
| import ( | |
| "os" | |
| "reflect" | |
| "runtime" | |
| "sync" | |
| "testing" | |
| ) | |
| // The full stack test cases for IPConn have been moved to the | |
| // following: | |
| // golang.org/x/net/ipv4 | |
| // golang.org/x/net/ipv6 | |
| // golang.org/x/net/icmp | |
| var fileConnTests = []struct { | |
| network string | |
| }{ | |
| {"tcp"}, | |
| {"udp"}, | |
| {"unix"}, | |
| {"unixpacket"}, | |
| } | |
| func TestFileConn(t *testing.T) { | |
| switch runtime.GOOS { | |
| case "plan9", "windows": | |
| t.Skipf("not supported on %s", runtime.GOOS) | |
| } | |
| for _, tt := range fileConnTests { | |
| if !testableNetwork(tt.network) { | |
| t.Logf("skipping %s test", tt.network) | |
| continue | |
| } | |
| var network, address string | |
| switch tt.network { | |
| case "udp": | |
| c, err := newLocalPacketListener(tt.network) | |
| if err != nil { | |
| t.Fatal(err) | |
| } | |
| defer c.Close() | |
| network = c.LocalAddr().Network() | |
| address = c.LocalAddr().String() | |
| default: | |
| handler := func(ls *localServer, ln Listener) { | |
| c, err := ln.Accept() | |
| if err != nil { | |
| return | |
| } | |
| defer c.Close() | |
| var b [1]byte | |
| c.Read(b[:]) | |
| } | |
| ls, err := newLocalServer(tt.network) | |
| if err != nil { | |
| t.Fatal(err) | |
| } | |
| defer ls.teardown() | |
| if err := ls.buildup(handler); err != nil { | |
| t.Fatal(err) | |
| } | |
| network = ls.Listener.Addr().Network() | |
| address = ls.Listener.Addr().String() | |
| } | |
| c1, err := Dial(network, address) | |
| if err != nil { | |
| if perr := parseDialError(err); perr != nil { | |
| t.Error(perr) | |
| } | |
| t.Fatal(err) | |
| } | |
| addr := c1.LocalAddr() | |
| var f *os.File | |
| switch c1 := c1.(type) { | |
| case *TCPConn: | |
| f, err = c1.File() | |
| case *UDPConn: | |
| f, err = c1.File() | |
| case *UnixConn: | |
| f, err = c1.File() | |
| } | |
| if err := c1.Close(); err != nil { | |
| if perr := parseCloseError(err, false); perr != nil { | |
| t.Error(perr) | |
| } | |
| t.Error(err) | |
| } | |
| if err != nil { | |
| if perr := parseCommonError(err); perr != nil { | |
| t.Error(perr) | |
| } | |
| t.Fatal(err) | |
| } | |
| c2, err := FileConn(f) | |
| if err := f.Close(); err != nil { | |
| t.Error(err) | |
| } | |
| if err != nil { | |
| if perr := parseCommonError(err); perr != nil { | |
| t.Error(perr) | |
| } | |
| t.Fatal(err) | |
| } | |
| defer c2.Close() | |
| if _, err := c2.Write([]byte("FILECONN TEST")); err != nil { | |
| if perr := parseWriteError(err); perr != nil { | |
| t.Error(perr) | |
| } | |
| t.Fatal(err) | |
| } | |
| if !reflect.DeepEqual(c2.LocalAddr(), addr) { | |
| t.Fatalf("got %#v; want %#v", c2.LocalAddr(), addr) | |
| } | |
| } | |
| } | |
| var fileListenerTests = []struct { | |
| network string | |
| }{ | |
| {"tcp"}, | |
| {"unix"}, | |
| {"unixpacket"}, | |
| } | |
| func TestFileListener(t *testing.T) { | |
| switch runtime.GOOS { | |
| case "plan9", "windows": | |
| t.Skipf("not supported on %s", runtime.GOOS) | |
| } | |
| for _, tt := range fileListenerTests { | |
| if !testableNetwork(tt.network) { | |
| t.Logf("skipping %s test", tt.network) | |
| continue | |
| } | |
| ln1, err := newLocalListener(tt.network) | |
| if err != nil { | |
| t.Fatal(err) | |
| } | |
| switch tt.network { | |
| case "unix", "unixpacket": | |
| defer os.Remove(ln1.Addr().String()) | |
| } | |
| addr := ln1.Addr() | |
| var f *os.File | |
| switch ln1 := ln1.(type) { | |
| case *TCPListener: | |
| f, err = ln1.File() | |
| case *UnixListener: | |
| f, err = ln1.File() | |
| } | |
| switch tt.network { | |
| case "unix", "unixpacket": | |
| defer ln1.Close() // UnixListener.Close calls syscall.Unlink internally | |
| default: | |
| if err := ln1.Close(); err != nil { | |
| t.Error(err) | |
| } | |
| } | |
| if err != nil { | |
| if perr := parseCommonError(err); perr != nil { | |
| t.Error(perr) | |
| } | |
| t.Fatal(err) | |
| } | |
| ln2, err := FileListener(f) | |
| if err := f.Close(); err != nil { | |
| t.Error(err) | |
| } | |
| if err != nil { | |
| if perr := parseCommonError(err); perr != nil { | |
| t.Error(perr) | |
| } | |
| t.Fatal(err) | |
| } | |
| defer ln2.Close() | |
| var wg sync.WaitGroup | |
| wg.Add(1) | |
| go func() { | |
| defer wg.Done() | |
| c, err := Dial(ln2.Addr().Network(), ln2.Addr().String()) | |
| if err != nil { | |
| if perr := parseDialError(err); perr != nil { | |
| t.Error(perr) | |
| } | |
| t.Error(err) | |
| return | |
| } | |
| c.Close() | |
| }() | |
| c, err := ln2.Accept() | |
| if err != nil { | |
| if perr := parseAcceptError(err); perr != nil { | |
| t.Error(perr) | |
| } | |
| t.Fatal(err) | |
| } | |
| c.Close() | |
| wg.Wait() | |
| if !reflect.DeepEqual(ln2.Addr(), addr) { | |
| t.Fatalf("got %#v; want %#v", ln2.Addr(), addr) | |
| } | |
| } | |
| } | |
| var filePacketConnTests = []struct { | |
| network string | |
| }{ | |
| {"udp"}, | |
| {"unixgram"}, | |
| } | |
| func TestFilePacketConn(t *testing.T) { | |
| switch runtime.GOOS { | |
| case "plan9", "windows": | |
| t.Skipf("not supported on %s", runtime.GOOS) | |
| } | |
| for _, tt := range filePacketConnTests { | |
| if !testableNetwork(tt.network) { | |
| t.Logf("skipping %s test", tt.network) | |
| continue | |
| } | |
| c1, err := newLocalPacketListener(tt.network) | |
| if err != nil { | |
| t.Fatal(err) | |
| } | |
| switch tt.network { | |
| case "unixgram": | |
| defer os.Remove(c1.LocalAddr().String()) | |
| } | |
| addr := c1.LocalAddr() | |
| var f *os.File | |
| switch c1 := c1.(type) { | |
| case *UDPConn: | |
| f, err = c1.File() | |
| case *UnixConn: | |
| f, err = c1.File() | |
| } | |
| if err := c1.Close(); err != nil { | |
| if perr := parseCloseError(err, false); perr != nil { | |
| t.Error(perr) | |
| } | |
| t.Error(err) | |
| } | |
| if err != nil { | |
| if perr := parseCommonError(err); perr != nil { | |
| t.Error(perr) | |
| } | |
| t.Fatal(err) | |
| } | |
| c2, err := FilePacketConn(f) | |
| if err := f.Close(); err != nil { | |
| t.Error(err) | |
| } | |
| if err != nil { | |
| if perr := parseCommonError(err); perr != nil { | |
| t.Error(perr) | |
| } | |
| t.Fatal(err) | |
| } | |
| defer c2.Close() | |
| if _, err := c2.WriteTo([]byte("FILEPACKETCONN TEST"), addr); err != nil { | |
| if perr := parseWriteError(err); perr != nil { | |
| t.Error(perr) | |
| } | |
| t.Fatal(err) | |
| } | |
| if !reflect.DeepEqual(c2.LocalAddr(), addr) { | |
| t.Fatalf("got %#v; want %#v", c2.LocalAddr(), addr) | |
| } | |
| } | |
| } | |
| // Issue 24483. | |
| func TestFileCloseRace(t *testing.T) { | |
| switch runtime.GOOS { | |
| case "plan9", "windows": | |
| t.Skipf("not supported on %s", runtime.GOOS) | |
| } | |
| if !testableNetwork("tcp") { | |
| t.Skip("tcp not supported") | |
| } | |
| handler := func(ls *localServer, ln Listener) { | |
| c, err := ln.Accept() | |
| if err != nil { | |
| return | |
| } | |
| defer c.Close() | |
| var b [1]byte | |
| c.Read(b[:]) | |
| } | |
| ls, err := newLocalServer("tcp") | |
| if err != nil { | |
| t.Fatal(err) | |
| } | |
| defer ls.teardown() | |
| if err := ls.buildup(handler); err != nil { | |
| t.Fatal(err) | |
| } | |
| const tries = 100 | |
| for i := 0; i < tries; i++ { | |
| c1, err := Dial(ls.Listener.Addr().Network(), ls.Listener.Addr().String()) | |
| if err != nil { | |
| t.Fatal(err) | |
| } | |
| tc := c1.(*TCPConn) | |
| var wg sync.WaitGroup | |
| wg.Add(2) | |
| go func() { | |
| defer wg.Done() | |
| f, err := tc.File() | |
| if err == nil { | |
| f.Close() | |
| } | |
| }() | |
| go func() { | |
| defer wg.Done() | |
| c1.Close() | |
| }() | |
| wg.Wait() | |
| } | |
| } |