github.com/wasilibs/wazerox@v0.0.0-20240124024944-4923be63ab5f/imports/wasi_snapshot_preview1/clock_test.go (about) 1 package wasi_snapshot_preview1_test 2 3 import ( 4 _ "embed" 5 "testing" 6 7 wazero "github.com/wasilibs/wazerox" 8 "github.com/wasilibs/wazerox/internal/testing/require" 9 "github.com/wasilibs/wazerox/internal/wasip1" 10 ) 11 12 func Test_clockResGet(t *testing.T) { 13 mod, r, log := requireProxyModule(t, wazero.NewModuleConfig()) 14 defer r.Close(testCtx) 15 16 expectedMemoryMicro := []byte{ 17 '?', // resultResolution is after this 18 0xe8, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // little endian-encoded resolution (fixed to 1000). 19 '?', // stopped after encoding 20 } 21 22 expectedMemoryNano := []byte{ 23 '?', // resultResolution is after this 24 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // little endian-encoded resolution (fixed to 1000). 25 '?', // stopped after encoding 26 } 27 28 tests := []struct { 29 name string 30 clockID uint32 31 expectedMemory []byte 32 expectedLog string 33 }{ 34 { 35 name: "Realtime", 36 clockID: wasip1.ClockIDRealtime, 37 expectedMemory: expectedMemoryMicro, 38 expectedLog: ` 39 ==> wasi_snapshot_preview1.clock_res_get(id=realtime) 40 <== (resolution=1000,errno=ESUCCESS) 41 `, 42 }, 43 { 44 name: "Monotonic", 45 clockID: wasip1.ClockIDMonotonic, 46 expectedMemory: expectedMemoryNano, 47 expectedLog: ` 48 ==> wasi_snapshot_preview1.clock_res_get(id=monotonic) 49 <== (resolution=1,errno=ESUCCESS) 50 `, 51 }, 52 } 53 54 for _, tt := range tests { 55 tc := tt 56 57 t.Run(tc.name, func(t *testing.T) { 58 defer log.Reset() 59 60 resultResolution := 16 // arbitrary offset 61 maskMemory(t, mod, resultResolution+len(tc.expectedMemory)) 62 63 requireErrnoResult(t, wasip1.ErrnoSuccess, mod, wasip1.ClockResGetName, uint64(tc.clockID), uint64(resultResolution)) 64 require.Equal(t, tc.expectedLog, "\n"+log.String()) 65 66 actual, ok := mod.Memory().Read(uint32(resultResolution-1), uint32(len(tc.expectedMemory))) 67 require.True(t, ok) 68 require.Equal(t, tc.expectedMemory, actual) 69 }) 70 } 71 } 72 73 func Test_clockResGet_Unsupported(t *testing.T) { 74 mod, r, log := requireProxyModule(t, wazero.NewModuleConfig()) 75 defer r.Close(testCtx) 76 77 tests := []struct { 78 name string 79 clockID uint32 80 expectedErrno wasip1.Errno 81 expectedLog string 82 }{ 83 { 84 name: "process cputime", 85 clockID: 2, 86 expectedErrno: wasip1.ErrnoInval, 87 expectedLog: ` 88 ==> wasi_snapshot_preview1.clock_res_get(id=2) 89 <== (resolution=,errno=EINVAL) 90 `, 91 }, 92 { 93 name: "thread cputime", 94 clockID: 3, 95 expectedErrno: wasip1.ErrnoInval, 96 expectedLog: ` 97 ==> wasi_snapshot_preview1.clock_res_get(id=3) 98 <== (resolution=,errno=EINVAL) 99 `, 100 }, 101 { 102 name: "undefined", 103 clockID: 100, 104 expectedErrno: wasip1.ErrnoInval, 105 expectedLog: ` 106 ==> wasi_snapshot_preview1.clock_res_get(id=100) 107 <== (resolution=,errno=EINVAL) 108 `, 109 }, 110 } 111 for _, tt := range tests { 112 tc := tt 113 114 t.Run(tc.name, func(t *testing.T) { 115 defer log.Reset() 116 117 resultResolution := 16 // arbitrary offset 118 requireErrnoResult(t, tc.expectedErrno, mod, wasip1.ClockResGetName, uint64(tc.clockID), uint64(resultResolution)) 119 require.Equal(t, tc.expectedLog, "\n"+log.String()) 120 }) 121 } 122 } 123 124 func Test_clockTimeGet(t *testing.T) { 125 mod, r, log := requireProxyModule(t, wazero.NewModuleConfig()) 126 defer r.Close(testCtx) 127 128 tests := []struct { 129 name string 130 clockID uint32 131 expectedMemory []byte 132 expectedLog string 133 }{ 134 { 135 name: "Realtime", 136 clockID: wasip1.ClockIDRealtime, 137 expectedMemory: []byte{ 138 '?', // resultTimestamp is after this 139 0x0, 0x0, 0x1f, 0xa6, 0x70, 0xfc, 0xc5, 0x16, // little endian-encoded epochNanos 140 '?', // stopped after encoding 141 }, 142 expectedLog: ` 143 ==> wasi_snapshot_preview1.clock_time_get(id=realtime,precision=0) 144 <== (timestamp=1640995200000000000,errno=ESUCCESS) 145 `, 146 }, 147 { 148 name: "Monotonic", 149 clockID: wasip1.ClockIDMonotonic, 150 expectedMemory: []byte{ 151 '?', // resultTimestamp is after this 152 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // fake nanotime starts at zero 153 '?', // stopped after encoding 154 }, 155 expectedLog: ` 156 ==> wasi_snapshot_preview1.clock_time_get(id=monotonic,precision=0) 157 <== (timestamp=0,errno=ESUCCESS) 158 `, 159 }, 160 } 161 162 for _, tt := range tests { 163 tc := tt 164 t.Run(tc.name, func(t *testing.T) { 165 defer log.Reset() 166 167 resultTimestamp := 16 // arbitrary offset 168 maskMemory(t, mod, resultTimestamp+len(tc.expectedMemory)) 169 170 requireErrnoResult(t, wasip1.ErrnoSuccess, mod, wasip1.ClockTimeGetName, uint64(tc.clockID), 0 /* TODO: precision */, uint64(resultTimestamp)) 171 require.Equal(t, tc.expectedLog, "\n"+log.String()) 172 173 actual, ok := mod.Memory().Read(uint32(resultTimestamp-1), uint32(len(tc.expectedMemory))) 174 require.True(t, ok) 175 require.Equal(t, tc.expectedMemory, actual) 176 }) 177 } 178 } 179 180 // Similar to https://github.com/WebAssembly/wasi-testsuite/blob/dc7f8d27be1030cd4788ebdf07d9b57e5d23441e/tests/c/testsuite/clock_gettime-monotonic.c 181 func Test_clockTimeGet_monotonic(t *testing.T) { 182 mod, r, _ := requireProxyModule(t, wazero.NewModuleConfig(). 183 // Important not to use fake time! 184 WithSysNanotime()) 185 defer r.Close(testCtx) 186 187 getMonotonicTime := func() uint64 { 188 const offset uint32 = 0 189 requireErrnoResult(t, wasip1.ErrnoSuccess, mod, wasip1.ClockTimeGetName, uint64(wasip1.ClockIDMonotonic), 190 0 /* TODO: precision */, uint64(offset)) 191 timestamp, ok := mod.Memory().ReadUint64Le(offset) 192 require.True(t, ok) 193 return timestamp 194 } 195 196 t1 := getMonotonicTime() 197 t2 := getMonotonicTime() 198 t3 := getMonotonicTime() 199 t4 := getMonotonicTime() 200 201 require.True(t, t1 < t2) 202 require.True(t, t2 < t3) 203 require.True(t, t3 < t4) 204 } 205 206 func Test_clockTimeGet_Unsupported(t *testing.T) { 207 mod, r, log := requireProxyModule(t, wazero.NewModuleConfig()) 208 defer r.Close(testCtx) 209 210 tests := []struct { 211 name string 212 clockID uint32 213 expectedErrno wasip1.Errno 214 expectedLog string 215 }{ 216 { 217 name: "process cputime", 218 clockID: 2, 219 expectedErrno: wasip1.ErrnoInval, 220 expectedLog: ` 221 ==> wasi_snapshot_preview1.clock_time_get(id=2,precision=0) 222 <== (timestamp=,errno=EINVAL) 223 `, 224 }, 225 { 226 name: "thread cputime", 227 clockID: 3, 228 expectedErrno: wasip1.ErrnoInval, 229 expectedLog: ` 230 ==> wasi_snapshot_preview1.clock_time_get(id=3,precision=0) 231 <== (timestamp=,errno=EINVAL) 232 `, 233 }, 234 { 235 name: "undefined", 236 clockID: 100, 237 expectedErrno: wasip1.ErrnoInval, 238 expectedLog: ` 239 ==> wasi_snapshot_preview1.clock_time_get(id=100,precision=0) 240 <== (timestamp=,errno=EINVAL) 241 `, 242 }, 243 } 244 245 for _, tt := range tests { 246 tc := tt 247 248 t.Run(tc.name, func(t *testing.T) { 249 defer log.Reset() 250 251 resultTimestamp := 16 // arbitrary offset 252 requireErrnoResult(t, tc.expectedErrno, mod, wasip1.ClockTimeGetName, uint64(tc.clockID), uint64(0) /* TODO: precision */, uint64(resultTimestamp)) 253 require.Equal(t, tc.expectedLog, "\n"+log.String()) 254 }) 255 } 256 } 257 258 func Test_clockTimeGet_Errors(t *testing.T) { 259 mod, r, log := requireProxyModule(t, wazero.NewModuleConfig()) 260 defer r.Close(testCtx) 261 262 memorySize := mod.Memory().Size() 263 264 tests := []struct { 265 name string 266 resultTimestamp, argvLen uint32 267 expectedLog string 268 }{ 269 { 270 name: "resultTimestamp OOM", 271 resultTimestamp: memorySize, 272 expectedLog: ` 273 ==> wasi_snapshot_preview1.clock_time_get(id=realtime,precision=0) 274 <== (timestamp=,errno=EFAULT) 275 `, 276 }, 277 { 278 name: "resultTimestamp exceeds the maximum valid address by 1", 279 resultTimestamp: memorySize - 4 + 1, // 4 is the size of uint32, the type of the count of args 280 expectedLog: ` 281 ==> wasi_snapshot_preview1.clock_time_get(id=realtime,precision=0) 282 <== (timestamp=,errno=EFAULT) 283 `, 284 }, 285 } 286 287 for _, tt := range tests { 288 tc := tt 289 290 t.Run(tc.name, func(t *testing.T) { 291 defer log.Reset() 292 293 requireErrnoResult(t, wasip1.ErrnoFault, mod, wasip1.ClockTimeGetName, uint64(0) /* TODO: id */, uint64(0) /* TODO: precision */, uint64(tc.resultTimestamp)) 294 require.Equal(t, tc.expectedLog, "\n"+log.String()) 295 }) 296 } 297 }