github.com/tetratelabs/wazero@v1.7.3-0.20240513003603-48f702e154b5/internal/sysfs/sock_test.go (about) 1 package sysfs 2 3 import ( 4 "net" 5 "testing" 6 "time" 7 8 "github.com/tetratelabs/wazero/experimental/sys" 9 "github.com/tetratelabs/wazero/internal/fsapi" 10 "github.com/tetratelabs/wazero/internal/testing/require" 11 ) 12 13 func TestTcpConnFile_Write(t *testing.T) { 14 listen, err := net.Listen("tcp", "127.0.0.1:0") 15 require.NoError(t, err) 16 defer listen.Close() 17 18 tcpAddr, err := net.ResolveTCPAddr("tcp", listen.Addr().String()) 19 require.NoError(t, err) 20 tcp, err := net.DialTCP("tcp", nil, tcpAddr) 21 require.NoError(t, err) 22 defer tcp.Close() //nolint 23 24 file := newTcpConn(tcp) 25 errno := sys.Errno(0) 26 // Ensure we don't interrupt until we get a non-zero errno, 27 // and we retry on EAGAIN (i.e. when nonblocking is true). 28 for { 29 _, errno = file.Write([]byte("wazero")) 30 if errno != sys.EAGAIN { 31 break 32 } 33 time.Sleep(100 * time.Millisecond) 34 } 35 require.Zero(t, errno) 36 37 conn, err := listen.Accept() 38 require.NoError(t, err) 39 defer conn.Close() 40 41 bytes := make([]byte, 4) 42 43 n, err := conn.Read(bytes) 44 require.NoError(t, err) 45 require.NotEqual(t, 0, n) 46 47 require.Equal(t, "waze", string(bytes)) 48 } 49 50 func TestTcpConnFile_Read(t *testing.T) { 51 // Test #1: Read from a TCP connection with default synchrony 52 // (i.e., without explicitly setting the non-blocking flag). 53 listen, err := net.Listen("tcp", "127.0.0.1:0") 54 require.NoError(t, err) 55 defer listen.Close() 56 57 tcpAddr, err := net.ResolveTCPAddr("tcp", listen.Addr().String()) 58 require.NoError(t, err) 59 tcp, err := net.DialTCP("tcp", nil, tcpAddr) 60 require.NoError(t, err) 61 defer tcp.Close() //nolint 62 63 n, err := tcp.Write([]byte("wazero")) 64 require.NoError(t, err) 65 require.NotEqual(t, 0, n) 66 67 conn, err := listen.Accept() 68 require.NoError(t, err) 69 defer conn.Close() 70 71 bytes := make([]byte, 4) 72 73 require.NoError(t, err) 74 errno := sys.Errno(0) 75 file := newTcpConn(conn.(*net.TCPConn)) 76 // Ensure we don't interrupt until we get a non-zero errno, 77 // and we retry on EAGAIN (i.e. when nonblocking is true). 78 for { 79 _, errno = file.Read(bytes) 80 if errno != sys.EAGAIN { 81 break 82 } 83 time.Sleep(100 * time.Millisecond) 84 } 85 require.Zero(t, errno) 86 require.NoError(t, err) 87 require.Equal(t, "waze", string(bytes)) 88 89 // Test #2: Read from a TCP connection asynchronously (i.e., with 90 // the non-blocking flag set explicitly). 91 tcpAddr2, err := net.ResolveTCPAddr("tcp", listen.Addr().String()) 92 require.NoError(t, err) 93 tcp2, err := net.DialTCP("tcp", nil, tcpAddr2) 94 require.NoError(t, err) 95 defer tcp.Close() //nolint 96 97 // Use a goroutine to asynchronously write to the TCP connection 98 // with a delay that is visible to the test. 99 go func() { 100 time.Sleep(200 * time.Millisecond) 101 n2, err := tcp2.Write([]byte("wazero")) 102 require.NoError(t, err) 103 require.NotEqual(t, 0, n2) 104 }() 105 106 conn2, err := listen.Accept() 107 require.NoError(t, err) 108 defer conn.Close() 109 110 bytes2 := make([]byte, 4) 111 112 require.NoError(t, err) 113 errno2 := sys.Errno(0) 114 file2 := newTcpConn(conn2.(*net.TCPConn)) 115 errno2 = file2.(*tcpConnFile).SetNonblock(true) 116 require.Zero(t, errno2) 117 118 // Ensure we start by getting EAGAIN. 119 _, errno2 = file2.Read(bytes2) 120 require.Equal(t, sys.EAGAIN, errno2) 121 122 // Ensure we don't interrupt until we get a non-zero errno, 123 // and we retry on EAGAIN (i.e. when nonblocking is true). 124 for { 125 _, errno2 = file2.Read(bytes2) 126 if errno2 != sys.EAGAIN { 127 break 128 } 129 } 130 require.Zero(t, errno2) 131 require.NoError(t, err) 132 require.Equal(t, "waze", string(bytes2)) 133 } 134 135 func TestTcpConnFile_Stat(t *testing.T) { 136 listen, err := net.Listen("tcp", "127.0.0.1:0") 137 require.NoError(t, err) 138 defer listen.Close() 139 140 tcpAddr, err := net.ResolveTCPAddr("tcp", listen.Addr().String()) 141 require.NoError(t, err) 142 tcp, err := net.DialTCP("tcp", nil, tcpAddr) 143 require.NoError(t, err) 144 defer tcp.Close() //nolint 145 146 conn, err := listen.Accept() 147 require.NoError(t, err) 148 defer conn.Close() 149 150 file := newTcpConn(tcp) 151 _, errno := file.Stat() 152 require.Zero(t, errno, "Stat should not fail") 153 } 154 155 func TestTcpConnFile_SetNonblock(t *testing.T) { 156 listen, err := net.Listen("tcp", "127.0.0.1:0") 157 require.NoError(t, err) 158 defer listen.Close() 159 160 lf := newTCPListenerFile(listen.(*net.TCPListener)) 161 162 tcpAddr, err := net.ResolveTCPAddr("tcp", listen.Addr().String()) 163 require.NoError(t, err) 164 tcp, err := net.DialTCP("tcp", nil, tcpAddr) 165 require.NoError(t, err) 166 defer tcp.Close() //nolint 167 168 nblf := fsapi.Adapt(lf) 169 errno := nblf.SetNonblock(true) 170 require.EqualErrno(t, 0, errno) 171 require.True(t, nblf.IsNonblock()) 172 173 conn, errno := lf.Accept() 174 require.EqualErrno(t, 0, errno) 175 defer conn.Close() 176 177 file := fsapi.Adapt(newTcpConn(tcp)) 178 errno = file.SetNonblock(true) 179 require.EqualErrno(t, 0, errno) 180 require.True(t, file.IsNonblock()) 181 }