github.com/weedge/lib@v0.0.0-20230424045628-a36dcc1d90e4/poller/netpoll/netpoll_unix_test.go (about) 1 // +build linux darwin dragonfly freebsd netbsd openbsd 2 3 package netpoll 4 5 import ( 6 "bytes" 7 "io" 8 "log" 9 "net" 10 "os" 11 "sync" 12 "sync/atomic" 13 "syscall" 14 "testing" 15 "time" 16 17 "golang.org/x/sys/unix" 18 ) 19 20 func TestPollerReadOnce(t *testing.T) { 21 poller, err := New(config(t)) 22 if err != nil { 23 t.Fatal(err) 24 } 25 26 r, w, err := socketPair() 27 if err != nil { 28 t.Fatal(err) 29 } 30 31 conn, err := net.FileConn(os.NewFile(uintptr(r), "|0")) 32 if err != nil { 33 t.Fatal(err) 34 } 35 36 var ( 37 data = []byte("hello") 38 done = make(chan struct{}) 39 received = make([]byte, 0, len(data)) 40 ) 41 42 var ( 43 mu sync.Mutex 44 events []Event 45 ) 46 desc := Must(HandleReadOnce(conn)) 47 err = poller.Start(desc, func(event Event) { 48 mu.Lock() 49 events = append(events, event) 50 mu.Unlock() 51 52 if event&EventRead == 0 { 53 return 54 } 55 56 bts := make([]byte, 128) 57 n, err := conn.Read(bts) 58 switch { 59 case err == io.EOF: 60 defer close(done) 61 if err = poller.Stop(desc); err != nil { 62 t.Fatalf("poller.Stop() error: %v", err) 63 } 64 65 case err != nil: 66 t.Fatal(err) 67 68 default: 69 received = append(received, bts[:n]...) 70 if err := poller.Resume(desc); err != nil { 71 t.Fatalf("poller.Resume() error: %v", err) 72 } 73 } 74 }) 75 if err != nil { 76 t.Fatal(err) 77 } 78 79 // Write data by a single byte. 80 for i := 0; i < len(data); i++ { 81 _, err = unix.Write(w, data[i:i+1]) 82 if err != nil { 83 t.Fatal(err) 84 } 85 time.Sleep(time.Millisecond) 86 } 87 88 if err = unix.Close(w); err != nil { 89 t.Fatalf("unix.Close() error: %v", err) 90 } 91 92 <-done 93 94 if count, exp := len(events), len(data)+1; count != exp { // expect +1 for EPOLLRDHUP or EPOLLHUP 95 t.Errorf("callback called %d times (%v); want %d", count, events, exp) 96 return 97 } 98 99 if last, want := events[len(events)-1], EventRead|EventHup|EventReadHup; last != want { 100 t.Errorf("last callback call was made with %s; want %s", last, want) 101 } 102 for i, m := range events[:len(events)-1] { 103 if m != EventRead { 104 t.Errorf("callback call #%d was made with %s; want %s", i, m, EventRead) 105 } 106 } 107 if !bytes.Equal(data, received) { 108 t.Errorf("bytes are not equal:\ngot: %v\nwant: %v\n", received, data) 109 } 110 } 111 112 func TestPollerWriteOnce(t *testing.T) { 113 poller, err := New(config(t)) 114 if err != nil { 115 t.Fatal(err) 116 } 117 118 r, w, err := socketPair() 119 if err != nil { 120 t.Fatal(err) 121 } 122 123 sendLoWat, err := unix.GetsockoptInt(w, unix.SOL_SOCKET, unix.SO_SNDLOWAT) 124 if err != nil { 125 t.Fatalf("get SO_SNDLOWAT error: %v", err) 126 } 127 sendBuf, err := unix.GetsockoptInt(w, unix.SOL_SOCKET, unix.SO_SNDBUF) 128 if err != nil { 129 t.Fatalf("get SO_SNDBUF error: %v", err) 130 } 131 132 log.Printf("send buf is %d", sendBuf) 133 log.Printf("send low watermark is %d", sendLoWat) 134 135 filled, err := fillSendBuffer(w) 136 if err != nil { 137 t.Fatalf("fill send buffer error: %v", err) 138 } 139 log.Printf("filled send buffer: %d", filled) 140 141 var ( 142 writeEvents = new(uint32) 143 writeHup = new(uint32) 144 ) 145 146 wc, err := net.FileConn(os.NewFile(uintptr(w), "w")) 147 if err != nil { 148 t.Fatal(err) 149 } 150 151 desc := Must(HandleWriteOnce(wc)) 152 err = poller.Start(desc, func(e Event) { 153 log.Printf("received event from poller: %s", e) 154 atomic.AddUint32(writeEvents, 1) 155 156 if e&EventHup != 0 { 157 atomic.AddUint32(writeHup, 1) 158 return 159 } 160 if e&EventErr != 0 { 161 return 162 } 163 164 filled, err := fillSendBuffer(w) 165 if err != nil { 166 t.Fatalf("fill send buffer error: %v", err) 167 } 168 log.Printf("filled send buffer: %d", filled) 169 170 if err := poller.Resume(desc); err != nil { 171 t.Fatalf("poller.Resume() error %v", err) 172 } 173 }) 174 if err != nil { 175 t.Fatalf("poller.Start(w) error: %v", err) 176 } 177 178 // Read sendLoWat-1 bytes such that next read will trigger write event. 179 if n, err := unix.Read(r, make([]byte, sendLoWat-1)); err != nil { 180 t.Fatalf("unix.Read() error: %v", err) 181 } else { 182 log.Printf("read %d (from %d: SNDLOWAT-1)", n, sendLoWat-1) 183 } 184 185 time.Sleep(time.Millisecond * 50) 186 if n := atomic.LoadUint32(writeEvents); n > 0 { 187 t.Fatalf("write events: %v; want 0", n) 188 } 189 190 if n, err := unix.Read(r, make([]byte, filled)); err != nil { 191 t.Fatalf("empty receive buffer error: %v", err) 192 } else { 193 log.Printf("emptied receive buffer: %d", n) 194 } 195 time.Sleep(time.Millisecond * 50) 196 if n := atomic.LoadUint32(writeEvents); n != 1 { 197 t.Errorf("write events: %v; want 1", n) 198 } 199 200 if err := unix.Close(r); err != nil { 201 t.Fatalf("unix.Close() error: %v", err) 202 } 203 log.Println("closed read-end of pair") 204 time.Sleep(time.Millisecond * 50) 205 if n := atomic.LoadUint32(writeHup); n != 1 { 206 t.Errorf("hup events: %v; want 1", n) 207 } 208 } 209 210 func emptyRecvBuffer(fd int, k int) (n int, err error) { 211 for eagain := 0; eagain < 10; { 212 var x int 213 p := make([]byte, k+1) 214 x, err = unix.Read(fd, p) 215 if err != nil { 216 if err == syscall.EAGAIN { 217 err = nil 218 eagain++ 219 continue 220 } 221 return 222 } 223 n += x 224 } 225 return 226 } 227 228 func fillSendBuffer(fd int) (n int, err error) { 229 p := bytes.Repeat([]byte{'x'}, 1) 230 for eagain := 0; eagain < 10; { 231 var x int 232 x, err = unix.Write(fd, p) 233 if err != nil { 234 if err == syscall.EAGAIN { 235 err = nil 236 eagain++ 237 continue 238 } 239 return 240 } 241 n += x 242 } 243 return 244 } 245 246 func socketPair() (r, w int, err error) { 247 fd, err := unix.Socketpair(unix.AF_UNIX, unix.SOCK_STREAM, 0) 248 if err != nil { 249 return 250 } 251 252 if err = unix.SetNonblock(fd[0], true); err != nil { 253 return 254 } 255 if err = unix.SetNonblock(fd[1], true); err != nil { 256 return 257 } 258 259 buf := 4096 260 if err = unix.SetsockoptInt(fd[0], unix.SOL_SOCKET, unix.SO_SNDBUF, buf); err != nil { 261 return 262 } 263 if err = unix.SetsockoptInt(fd[1], unix.SOL_SOCKET, unix.SO_SNDBUF, buf); err != nil { 264 return 265 } 266 if err = unix.SetsockoptInt(fd[0], unix.SOL_SOCKET, unix.SO_RCVBUF, buf); err != nil { 267 return 268 } 269 if err = unix.SetsockoptInt(fd[1], unix.SOL_SOCKET, unix.SO_RCVBUF, buf); err != nil { 270 return 271 } 272 return fd[0], fd[1], nil 273 } 274 275 func config(tb testing.TB) *Config { 276 return &Config{ 277 OnWaitError: func(err error) { 278 tb.Fatal(err) 279 }, 280 } 281 } 282 283 type stubConn struct{} 284 285 func (s stubConn) Read(b []byte) (n int, err error) { return 0, nil } 286 func (s stubConn) Write(b []byte) (n int, err error) { return 0, nil } 287 func (s stubConn) Close() error { return nil } 288 func (s stubConn) LocalAddr() (addr net.Addr) { return } 289 func (s stubConn) RemoteAddr() (addr net.Addr) { return } 290 func (s stubConn) SetDeadline(t time.Time) error { return nil } 291 func (s stubConn) SetReadDeadline(t time.Time) error { return nil } 292 func (s stubConn) SetWriteDeadline(t time.Time) error { return nil }