wa-lang.org/wazero@v1.0.2/imports/wasi_snapshot_preview1/poll_test.go (about)

     1  package wasi_snapshot_preview1
     2  
     3  import (
     4  	"testing"
     5  
     6  	"wa-lang.org/wazero"
     7  	internalsys "wa-lang.org/wazero/internal/sys"
     8  	"wa-lang.org/wazero/internal/testing/require"
     9  	"wa-lang.org/wazero/internal/wasm"
    10  )
    11  
    12  func Test_pollOneoff(t *testing.T) {
    13  	mod, r, log := requireProxyModule(t, wazero.NewModuleConfig())
    14  	defer r.Close(testCtx)
    15  
    16  	mem := []byte{
    17  		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // userdata
    18  		eventTypeClock, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // event type and padding
    19  		clockIDMonotonic, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // clockID
    20  		0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // timeout (ns)
    21  		0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // precision (ns)
    22  		0x00, 0x00, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // flags (relative)
    23  		'?', // stopped after encoding
    24  	}
    25  
    26  	expectedMem := []byte{
    27  		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // userdata
    28  		byte(ErrnoSuccess), 0x0, // errno is 16 bit
    29  		eventTypeClock, 0x0, 0x0, 0x0, // 4 bytes for type enum
    30  		'?', // stopped after encoding
    31  	}
    32  
    33  	in := uint32(0)    // past in
    34  	out := uint32(128) // past in
    35  	nsubscriptions := uint32(1)
    36  	resultNevents := uint32(512) // past out
    37  
    38  	maskMemory(t, testCtx, mod, 1024)
    39  	mod.Memory().Write(testCtx, in, mem)
    40  
    41  	requireErrno(t, ErrnoSuccess, mod, functionPollOneoff, uint64(in), uint64(out), uint64(nsubscriptions),
    42  		uint64(resultNevents))
    43  	require.Equal(t, `
    44  --> proxy.poll_oneoff(in=0,out=128,nsubscriptions=1,result.nevents=512)
    45  	==> wasi_snapshot_preview1.poll_oneoff(in=0,out=128,nsubscriptions=1,result.nevents=512)
    46  	<== ESUCCESS
    47  <-- (0)
    48  `, "\n"+log.String())
    49  
    50  	outMem, ok := mod.Memory().Read(testCtx, out, uint32(len(expectedMem)))
    51  	require.True(t, ok)
    52  	require.Equal(t, expectedMem, outMem)
    53  
    54  	nevents, ok := mod.Memory().ReadUint32Le(testCtx, resultNevents)
    55  	require.True(t, ok)
    56  	require.Equal(t, nsubscriptions, nevents)
    57  }
    58  
    59  func Test_pollOneoff_Errors(t *testing.T) {
    60  	mod, r, log := requireProxyModule(t, wazero.NewModuleConfig())
    61  	defer r.Close(testCtx)
    62  
    63  	tests := []struct {
    64  		name                                   string
    65  		in, out, nsubscriptions, resultNevents uint32
    66  		mem                                    []byte // at offset in
    67  		expectedErrno                          Errno
    68  		expectedMem                            []byte // at offset out
    69  		expectedLog                            string
    70  	}{
    71  		{
    72  			name:           "in out of range",
    73  			in:             wasm.MemoryPageSize,
    74  			nsubscriptions: 1,
    75  			out:            128, // past in
    76  			resultNevents:  512, // past out
    77  			expectedErrno:  ErrnoFault,
    78  			expectedLog: `
    79  --> proxy.poll_oneoff(in=65536,out=128,nsubscriptions=1,result.nevents=512)
    80  	==> wasi_snapshot_preview1.poll_oneoff(in=65536,out=128,nsubscriptions=1,result.nevents=512)
    81  	<== EFAULT
    82  <-- (21)
    83  `,
    84  		},
    85  		{
    86  			name:           "out out of range",
    87  			out:            wasm.MemoryPageSize,
    88  			resultNevents:  512, // past out
    89  			nsubscriptions: 1,
    90  			expectedErrno:  ErrnoFault,
    91  			expectedLog: `
    92  --> proxy.poll_oneoff(in=0,out=65536,nsubscriptions=1,result.nevents=512)
    93  	==> wasi_snapshot_preview1.poll_oneoff(in=0,out=65536,nsubscriptions=1,result.nevents=512)
    94  	<== EFAULT
    95  <-- (21)
    96  `,
    97  		},
    98  		{
    99  			name:           "resultNevents out of range",
   100  			resultNevents:  wasm.MemoryPageSize,
   101  			nsubscriptions: 1,
   102  			expectedErrno:  ErrnoFault,
   103  			expectedLog: `
   104  --> proxy.poll_oneoff(in=0,out=0,nsubscriptions=1,result.nevents=65536)
   105  	==> wasi_snapshot_preview1.poll_oneoff(in=0,out=0,nsubscriptions=1,result.nevents=65536)
   106  	<== EFAULT
   107  <-- (21)
   108  `,
   109  		},
   110  		{
   111  			name:          "nsubscriptions zero",
   112  			out:           128, // past in
   113  			resultNevents: 512, // past out
   114  			expectedErrno: ErrnoInval,
   115  			expectedLog: `
   116  --> proxy.poll_oneoff(in=0,out=128,nsubscriptions=0,result.nevents=512)
   117  	==> wasi_snapshot_preview1.poll_oneoff(in=0,out=128,nsubscriptions=0,result.nevents=512)
   118  	<== EINVAL
   119  <-- (28)
   120  `,
   121  		},
   122  		{
   123  			name:           "unsupported eventTypeFdRead",
   124  			nsubscriptions: 1,
   125  			mem: []byte{
   126  				0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // userdata
   127  				eventTypeFdRead, 0x0, 0x0, 0x0,
   128  				internalsys.FdStdin, 0x0, 0x0, 0x0, // valid readable FD
   129  				'?', // stopped after encoding
   130  			},
   131  			expectedErrno: ErrnoSuccess,
   132  			out:           128, // past in
   133  			resultNevents: 512, // past out
   134  			expectedMem: []byte{
   135  				0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // userdata
   136  				byte(ErrnoNotsup), 0x0, // errno is 16 bit
   137  				eventTypeFdRead, 0x0, 0x0, 0x0, // 4 bytes for type enum
   138  				'?', // stopped after encoding
   139  			},
   140  			expectedLog: `
   141  --> proxy.poll_oneoff(in=0,out=128,nsubscriptions=1,result.nevents=512)
   142  	==> wasi_snapshot_preview1.poll_oneoff(in=0,out=128,nsubscriptions=1,result.nevents=512)
   143  	<== ESUCCESS
   144  <-- (0)
   145  `,
   146  		},
   147  	}
   148  
   149  	for _, tt := range tests {
   150  		tc := tt
   151  		t.Run(tc.name, func(t *testing.T) {
   152  			defer log.Reset()
   153  
   154  			maskMemory(t, testCtx, mod, 1024)
   155  
   156  			if tc.mem != nil {
   157  				mod.Memory().Write(testCtx, tc.in, tc.mem)
   158  			}
   159  
   160  			requireErrno(t, tc.expectedErrno, mod, functionPollOneoff, uint64(tc.in), uint64(tc.out),
   161  				uint64(tc.nsubscriptions), uint64(tc.resultNevents))
   162  			require.Equal(t, tc.expectedLog, "\n"+log.String())
   163  
   164  			out, ok := mod.Memory().Read(testCtx, tc.out, uint32(len(tc.expectedMem)))
   165  			require.True(t, ok)
   166  			require.Equal(t, tc.expectedMem, out)
   167  
   168  			// Events should be written on success regardless of nested failure.
   169  			if tc.expectedErrno == ErrnoSuccess {
   170  				nevents, ok := mod.Memory().ReadUint32Le(testCtx, tc.resultNevents)
   171  				require.True(t, ok)
   172  				require.Equal(t, uint32(1), nevents)
   173  			}
   174  		})
   175  	}
   176  }