github.com/tetratelabs/wazero@v1.2.1/internal/sysfs/select_windows_test.go (about) 1 package sysfs 2 3 import ( 4 "context" 5 "os" 6 "syscall" 7 "testing" 8 "time" 9 10 "github.com/tetratelabs/wazero/internal/testing/require" 11 ) 12 13 func TestSelect_Windows(t *testing.T) { 14 type result struct { 15 hasData bool 16 err error 17 } 18 19 testCtx, cancel := context.WithCancel(context.Background()) 20 defer cancel() 21 22 pollToChannel := func(readHandle syscall.Handle, duration *time.Duration, ch chan result) { 23 r := result{} 24 r.hasData, r.err = pollNamedPipe(testCtx, readHandle, duration) 25 ch <- r 26 close(ch) 27 } 28 29 t.Run("peekNamedPipe should report the correct state of incoming data in the pipe", func(t *testing.T) { 30 r, w, err := os.Pipe() 31 require.NoError(t, err) 32 rh := syscall.Handle(r.Fd()) 33 wh := syscall.Handle(w.Fd()) 34 35 // Ensure the pipe has data. 36 hasData, err := peekNamedPipe(rh) 37 require.NoError(t, err) 38 require.False(t, hasData) 39 40 // Write to the channel. 41 msg, err := syscall.ByteSliceFromString("test\n") 42 require.NoError(t, err) 43 _, err = syscall.Write(wh, msg) 44 require.NoError(t, err) 45 46 // Ensure the pipe has data. 47 hasData, err = peekNamedPipe(rh) 48 require.NoError(t, err) 49 require.True(t, hasData) 50 }) 51 52 t.Run("pollNamedPipe should return immediately when duration is nil (no data)", func(t *testing.T) { 53 r, _, err := os.Pipe() 54 require.NoError(t, err) 55 rh := syscall.Handle(r.Fd()) 56 d := time.Duration(0) 57 hasData, err := pollNamedPipe(testCtx, rh, &d) 58 require.NoError(t, err) 59 require.False(t, hasData) 60 }) 61 62 t.Run("pollNamedPipe should return immediately when duration is nil (data)", func(t *testing.T) { 63 r, w, err := os.Pipe() 64 require.NoError(t, err) 65 rh := syscall.Handle(r.Fd()) 66 wh := syscall.Handle(w.Fd()) 67 68 // Write to the channel immediately. 69 msg, err := syscall.ByteSliceFromString("test\n") 70 require.NoError(t, err) 71 _, err = syscall.Write(wh, msg) 72 require.NoError(t, err) 73 74 // Verify that the write is reported. 75 d := time.Duration(0) 76 hasData, err := pollNamedPipe(testCtx, rh, &d) 77 require.NoError(t, err) 78 require.True(t, hasData) 79 }) 80 81 t.Run("pollNamedPipe should wait forever when duration is nil", func(t *testing.T) { 82 r, _, err := os.Pipe() 83 require.NoError(t, err) 84 rh := syscall.Handle(r.Fd()) 85 86 ch := make(chan result, 1) 87 go pollToChannel(rh, nil, ch) 88 89 // Wait a little, then ensure no writes occurred. 90 <-time.After(500 * time.Millisecond) 91 require.Equal(t, 0, len(ch)) 92 }) 93 94 t.Run("pollNamedPipe should wait forever when duration is nil", func(t *testing.T) { 95 r, w, err := os.Pipe() 96 require.NoError(t, err) 97 rh := syscall.Handle(r.Fd()) 98 wh := syscall.Handle(w.Fd()) 99 100 ch := make(chan result, 1) 101 go pollToChannel(rh, nil, ch) 102 103 // Wait a little, then ensure no writes occurred. 104 <-time.After(100 * time.Millisecond) 105 require.Equal(t, 0, len(ch)) 106 107 // Write a message to the pipe. 108 msg, err := syscall.ByteSliceFromString("test\n") 109 require.NoError(t, err) 110 _, err = syscall.Write(wh, msg) 111 require.NoError(t, err) 112 113 // Ensure that the write occurs (panic after an arbitrary timeout). 114 select { 115 case <-time.After(500 * time.Millisecond): 116 panic("unreachable!") 117 case r := <-ch: 118 require.NoError(t, r.err) 119 require.True(t, r.hasData) 120 } 121 }) 122 123 t.Run("pollNamedPipe should wait for the given duration", func(t *testing.T) { 124 r, w, err := os.Pipe() 125 require.NoError(t, err) 126 rh := syscall.Handle(r.Fd()) 127 wh := syscall.Handle(w.Fd()) 128 129 d := 500 * time.Millisecond 130 ch := make(chan result, 1) 131 go pollToChannel(rh, &d, ch) 132 133 // Wait a little, then ensure no writes occurred. 134 <-time.After(100 * time.Millisecond) 135 require.Equal(t, 0, len(ch)) 136 137 // Write a message to the pipe. 138 msg, err := syscall.ByteSliceFromString("test\n") 139 require.NoError(t, err) 140 _, err = syscall.Write(wh, msg) 141 require.NoError(t, err) 142 143 // Ensure that the write occurs before the timer expires. 144 select { 145 case <-time.After(500 * time.Millisecond): 146 panic("no data!") 147 case r := <-ch: 148 require.NoError(t, r.err) 149 require.True(t, r.hasData) 150 } 151 }) 152 153 t.Run("pollNamedPipe should timeout after the given duration", func(t *testing.T) { 154 r, _, err := os.Pipe() 155 require.NoError(t, err) 156 rh := syscall.Handle(r.Fd()) 157 158 d := 200 * time.Millisecond 159 ch := make(chan result, 1) 160 go pollToChannel(rh, &d, ch) 161 162 // Wait a little, then ensure a message has been written to the channel. 163 <-time.After(300 * time.Millisecond) 164 require.Equal(t, 1, len(ch)) 165 166 // Ensure that the timer has expired. 167 res := <-ch 168 require.NoError(t, res.err) 169 require.False(t, res.hasData) 170 }) 171 172 t.Run("pollNamedPipe should return when a write occurs before the given duration", func(t *testing.T) { 173 r, w, err := os.Pipe() 174 require.NoError(t, err) 175 rh := syscall.Handle(r.Fd()) 176 wh := syscall.Handle(w.Fd()) 177 178 d := 600 * time.Millisecond 179 ch := make(chan result, 1) 180 go pollToChannel(rh, &d, ch) 181 182 <-time.After(300 * time.Millisecond) 183 require.Equal(t, 0, len(ch)) 184 185 msg, err := syscall.ByteSliceFromString("test\n") 186 require.NoError(t, err) 187 _, err = syscall.Write(wh, msg) 188 require.NoError(t, err) 189 190 res := <-ch 191 require.NoError(t, res.err) 192 require.True(t, res.hasData) 193 }) 194 }