github.com/ianic/xnet/aio@v0.0.0-20230924160527-cee7f41ab201/loop_test.go (about) 1 package aio 2 3 import ( 4 "fmt" 5 "io" 6 "net" 7 "os" 8 "runtime" 9 "syscall" 10 "testing" 11 "time" 12 13 "github.com/stretchr/testify/require" 14 ) 15 16 func TestNetworkConnectWriteStdLib(t *testing.T) { 17 listen, err := net.Listen("tcp", "127.0.0.1:0") 18 require.NoError(t, err) 19 _, portStr, err := net.SplitHostPort(listen.Addr().String()) 20 require.NoError(t, err) 21 // t.Logf("running test server at port %s", portStr) 22 23 data := testRandomBuf(t, 1024) 24 go func() { 25 testSender(t, fmt.Sprintf("127.0.0.1:%s", portStr), data) 26 }() 27 28 var readBuffer []byte 29 conn, err := listen.Accept() 30 require.NoError(t, err) 31 chunk := make([]byte, 8) 32 for { 33 n, err := conn.Read(chunk) 34 if n == 0 { 35 break 36 } 37 require.NoError(t, err) 38 require.True(t, n >= 0) 39 readBuffer = append(readBuffer, chunk[:n]...) 40 } 41 conn.Close() 42 listen.Close() 43 44 require.Equal(t, data, readBuffer) 45 } 46 47 func TestTCPListener(t *testing.T) { 48 loop, err := New(Options{ 49 RingEntries: 16, 50 RecvBuffersCount: 8, 51 RecvBufferLen: 1024, 52 }) 53 require.NoError(t, err) 54 defer loop.Close() 55 56 conn := testConn{} 57 // called when tcp listener accepts tcp connection 58 tcpAccepted := func(fd int, tc *TCPConn) { 59 // t.Logf("accepted fd %d\n", fd) 60 tc.Bind(&conn) 61 } 62 // start listener 63 lsn, err := loop.Listen("[::1]:0", tcpAccepted) 64 require.NoError(t, err) 65 // t.Logf("tcp listener started at port %d", lsn.Port()) 66 67 data := testRandomBuf(t, 1024*4) 68 go func() { 69 testSender(t, fmt.Sprintf("[::1]:%d", lsn.port), data) 70 }() 71 72 // accept connection 73 loop.runOnce() 74 lsn.close(false) 75 // run until connection is closed 76 loop.runUntilDone() 77 78 require.True(t, len(conn.received) >= 4) 79 testRequireEqualBuffers(t, data, conn.received) 80 81 require.True(t, conn.closed, "conn.Closed should be called") 82 } 83 84 func TestTCPConnectSend(t *testing.T) { 85 listen, err := net.Listen("tcp", "[::1]:0") 86 require.NoError(t, err) 87 _, portStr, err := net.SplitHostPort(listen.Addr().String()) 88 addr := fmt.Sprintf("[::1]:%s", portStr) 89 require.NoError(t, err) 90 91 data := testRandomBuf(t, 4096) 92 closer := &testCloserConn{} 93 loopDone := make(chan struct{}) 94 go func() { 95 loop, err := New(DefaultOptions) 96 require.NoError(t, err) 97 defer loop.Close() 98 99 loop.Dial(addr, func(fd int, tc *TCPConn, err error) { 100 require.NoError(t, err) 101 closer.tc = tc 102 tc.Bind(closer) 103 tc.Send(data) 104 }) 105 loop.runUntilDone() 106 runtime.GC() // checks that pinned pointers are unpinned 107 close(loopDone) 108 }() 109 110 var readBuffer []byte 111 conn, err := listen.Accept() 112 require.NoError(t, err) 113 chunk := make([]byte, 1024) 114 for { 115 n, err := conn.Read(chunk) 116 if n == 0 { 117 break 118 } 119 //t.Logf("received chunk %d", n) 120 require.NoError(t, err) 121 require.True(t, n >= 0) 122 readBuffer = append(readBuffer, chunk[:n]...) 123 } 124 conn.Close() 125 listen.Close() 126 127 require.Equal(t, data, readBuffer) 128 <-loopDone 129 130 require.True(t, closer.closed) 131 } 132 133 func testSender(t *testing.T, addr string, data []byte) { 134 conn, err := net.DialTimeout("tcp", addr, time.Second) 135 require.Nil(t, err) 136 require.NotNil(t, conn) 137 n, err := conn.Write(data) 138 require.NoError(t, err) 139 require.Equal(t, len(data), n) 140 conn.Close() 141 } 142 143 type testConn struct { 144 received [][]byte 145 closed bool 146 } 147 148 func (c *testConn) Received(buf []byte) { 149 c.received = append(c.received, toOwn(buf)) 150 } 151 func (c *testConn) Sent() {} 152 func (c *testConn) Closed(error) { 153 c.closed = true 154 } 155 156 type testCloserConn struct { 157 tc *TCPConn 158 closed bool 159 } 160 161 func (c *testCloserConn) Received(buf []byte) {} 162 func (c *testCloserConn) Sent() { 163 c.tc.Close() 164 } 165 func (c *testCloserConn) Closed(error) { 166 c.closed = true 167 } 168 169 func toOwn(buf []byte) []byte { 170 own := make([]byte, len(buf)) 171 copy(own, buf) 172 return own 173 } 174 175 func testRequireEqualBuffers(t *testing.T, expected []byte, actual [][]byte) { 176 nn := 0 177 for _, buf := range actual { 178 require.True(t, len(expected) >= nn+len(buf)) 179 require.Equal(t, expected[nn:nn+len(buf)], buf) 180 nn += len(buf) 181 } 182 require.Equal(t, len(expected), nn) 183 } 184 185 func testRandomBuf(t *testing.T, size int) []byte { 186 f, err := os.Open("/dev/random") 187 require.NoError(t, err) 188 buf := make([]byte, size) 189 _, err = io.ReadFull(f, buf) 190 require.NoError(t, err) 191 return buf 192 } 193 194 func TestErrnoTemporary(t *testing.T) { 195 require.True(t, (&ErrErrno{Errno: syscall.EINTR}).Temporary()) 196 require.True(t, TemporaryError(syscall.EINTR)) 197 require.True(t, TemporaryError(syscall.ETIME)) 198 require.True(t, TemporaryError(syscall.ENOBUFS)) 199 }