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  }