github.com/bananabytelabs/wazero@v0.0.0-20240105073314-54b22a776da8/internal/sys/sys_test.go (about) 1 package sys 2 3 import ( 4 "bytes" 5 "testing" 6 "time" 7 8 experimentalsys "github.com/bananabytelabs/wazero/experimental/sys" 9 "github.com/bananabytelabs/wazero/internal/fstest" 10 "github.com/bananabytelabs/wazero/internal/platform" 11 "github.com/bananabytelabs/wazero/internal/sysfs" 12 "github.com/bananabytelabs/wazero/internal/testing/require" 13 "github.com/bananabytelabs/wazero/sys" 14 ) 15 16 func TestContext_WalltimeNanos(t *testing.T) { 17 sysCtx := DefaultContext(nil) 18 19 require.Equal(t, int64(1640995200000000000), sysCtx.WalltimeNanos()) 20 } 21 22 func TestDefaultSysContext(t *testing.T) { 23 testFS := &sysfs.AdaptFS{FS: fstest.FS} 24 25 sysCtx, err := NewContext(0, nil, nil, nil, nil, nil, nil, nil, 0, nil, 0, nil, nil, []experimentalsys.FS{testFS}, []string{"/"}, nil) 26 require.NoError(t, err) 27 28 require.Nil(t, sysCtx.Args()) 29 require.Zero(t, sysCtx.ArgsSize()) 30 require.Nil(t, sysCtx.Environ()) 31 require.Zero(t, sysCtx.EnvironSize()) 32 // To compare functions, we can only compare pointers, but the pointer will 33 // change. Hence, we have to compare the results instead. 34 sec, _ := sysCtx.Walltime() 35 require.Equal(t, platform.FakeEpochNanos/time.Second.Nanoseconds(), sec) 36 require.Equal(t, sys.ClockResolution(1_000), sysCtx.WalltimeResolution()) 37 require.Zero(t, sysCtx.Nanotime()) // See above on functions. 38 require.Equal(t, sys.ClockResolution(1), sysCtx.NanotimeResolution()) 39 require.Equal(t, platform.FakeNanosleep, sysCtx.nanosleep) 40 require.Equal(t, platform.NewFakeRandSource(), sysCtx.RandSource()) 41 42 expected := FileTable{} 43 noopStdin, _ := stdinFileEntry(nil) 44 expected.Insert(noopStdin) 45 noopStdout, _ := stdioWriterFileEntry("stdout", nil) 46 expected.Insert(noopStdout) 47 noopStderr, _ := stdioWriterFileEntry("stderr", nil) 48 expected.Insert(noopStderr) 49 expected.Insert(&FileEntry{ 50 IsPreopen: true, 51 Name: "/", 52 FS: testFS, 53 File: &lazyDir{fs: testFS}, 54 }) 55 require.Equal(t, expected, sysCtx.FS().openedFiles) 56 } 57 58 func TestNewContext_Args(t *testing.T) { 59 tests := []struct { 60 name string 61 args [][]byte 62 maxSize uint32 63 expectedSize uint32 64 expectedErr string 65 }{ 66 { 67 name: "ok", 68 maxSize: 10, 69 args: [][]byte{[]byte("a"), []byte("bc")}, 70 expectedSize: 5, 71 }, 72 { 73 name: "exceeds max count", 74 maxSize: 1, 75 args: [][]byte{[]byte("a"), []byte("bc")}, 76 expectedErr: "args invalid: exceeds maximum count", 77 }, 78 { 79 name: "exceeds max size", 80 maxSize: 4, 81 args: [][]byte{[]byte("a"), []byte("bc")}, 82 expectedErr: "args invalid: exceeds maximum size", 83 }, 84 { 85 name: "null character", 86 maxSize: 10, 87 args: [][]byte{[]byte("a"), {'b', 0}}, 88 expectedErr: "args invalid: contains NUL character", 89 }, 90 } 91 92 for _, tt := range tests { 93 tc := tt 94 95 t.Run(tc.name, func(t *testing.T) { 96 sysCtx, err := NewContext(tc.maxSize, tc.args, nil, bytes.NewReader(make([]byte, 0)), nil, nil, nil, nil, 0, nil, 0, nil, nil, nil, nil, nil) 97 if tc.expectedErr == "" { 98 require.Nil(t, err) 99 require.Equal(t, tc.args, sysCtx.Args()) 100 require.Equal(t, tc.expectedSize, sysCtx.ArgsSize()) 101 } else { 102 require.EqualError(t, err, tc.expectedErr) 103 } 104 }) 105 } 106 } 107 108 func TestNewContext_Environ(t *testing.T) { 109 tests := []struct { 110 name string 111 environ [][]byte 112 maxSize uint32 113 expectedSize uint32 114 expectedErr string 115 }{ 116 { 117 name: "ok", 118 maxSize: 10, 119 environ: [][]byte{[]byte("a=b"), []byte("c=de")}, 120 expectedSize: 9, 121 }, 122 { 123 name: "exceeds max count", 124 maxSize: 1, 125 environ: [][]byte{[]byte("a=b"), []byte("c=de")}, 126 expectedErr: "environ invalid: exceeds maximum count", 127 }, 128 { 129 name: "exceeds max size", 130 maxSize: 4, 131 environ: [][]byte{[]byte("a=b"), []byte("c=de")}, 132 expectedErr: "environ invalid: exceeds maximum size", 133 }, 134 { 135 name: "null character", 136 maxSize: 10, 137 environ: [][]byte{[]byte("a=b"), append([]byte("c=d"), 0)}, 138 expectedErr: "environ invalid: contains NUL character", 139 }, 140 } 141 142 for _, tt := range tests { 143 tc := tt 144 145 t.Run(tc.name, func(t *testing.T) { 146 sysCtx, err := NewContext(tc.maxSize, nil, tc.environ, bytes.NewReader(make([]byte, 0)), nil, nil, nil, nil, 0, nil, 0, nil, nil, nil, nil, nil) 147 if tc.expectedErr == "" { 148 require.Nil(t, err) 149 require.Equal(t, tc.environ, sysCtx.Environ()) 150 require.Equal(t, tc.expectedSize, sysCtx.EnvironSize()) 151 } else { 152 require.EqualError(t, err, tc.expectedErr) 153 } 154 }) 155 } 156 } 157 158 func TestNewContext_Walltime(t *testing.T) { 159 tests := []struct { 160 name string 161 time sys.Walltime 162 resolution sys.ClockResolution 163 expectedErr string 164 }{ 165 { 166 name: "ok", 167 time: platform.NewFakeWalltime(), 168 resolution: 3, 169 }, 170 { 171 name: "invalid resolution", 172 time: platform.NewFakeWalltime(), 173 resolution: 0, 174 expectedErr: "invalid Walltime resolution: 0", 175 }, 176 } 177 178 for _, tt := range tests { 179 tc := tt 180 181 t.Run(tc.name, func(t *testing.T) { 182 sysCtx, err := NewContext(0, nil, nil, nil, nil, nil, nil, tc.time, tc.resolution, nil, 0, nil, nil, nil, nil, nil) 183 if tc.expectedErr == "" { 184 require.Nil(t, err) 185 require.Equal(t, tc.time, sysCtx.walltime) 186 require.Equal(t, tc.resolution, sysCtx.WalltimeResolution()) 187 } else { 188 require.EqualError(t, err, tc.expectedErr) 189 } 190 }) 191 } 192 } 193 194 func TestNewContext_Nanotime(t *testing.T) { 195 tests := []struct { 196 name string 197 time sys.Nanotime 198 resolution sys.ClockResolution 199 expectedErr string 200 }{ 201 { 202 name: "ok", 203 time: platform.NewFakeNanotime(), 204 resolution: 3, 205 }, 206 { 207 name: "invalid resolution", 208 time: platform.NewFakeNanotime(), 209 resolution: 0, 210 expectedErr: "invalid Nanotime resolution: 0", 211 }, 212 } 213 214 for _, tt := range tests { 215 tc := tt 216 217 t.Run(tc.name, func(t *testing.T) { 218 sysCtx, err := NewContext(0, nil, nil, nil, nil, nil, nil, nil, 0, tc.time, tc.resolution, nil, nil, nil, nil, nil) 219 if tc.expectedErr == "" { 220 require.Nil(t, err) 221 require.Equal(t, tc.time, sysCtx.nanotime) 222 require.Equal(t, tc.resolution, sysCtx.NanotimeResolution()) 223 } else { 224 require.EqualError(t, err, tc.expectedErr) 225 } 226 }) 227 } 228 } 229 230 func Test_clockResolutionInvalid(t *testing.T) { 231 tests := []struct { 232 name string 233 resolution sys.ClockResolution 234 expected bool 235 }{ 236 { 237 name: "ok", 238 resolution: 1, 239 }, 240 { 241 name: "zero", 242 resolution: 0, 243 expected: true, 244 }, 245 { 246 name: "too big", 247 resolution: sys.ClockResolution(time.Hour.Nanoseconds() * 2), 248 expected: true, 249 }, 250 } 251 252 for _, tt := range tests { 253 tc := tt 254 255 t.Run(tc.name, func(t *testing.T) { 256 require.Equal(t, tc.expected, clockResolutionInvalid(tc.resolution)) 257 }) 258 } 259 } 260 261 func TestNewContext_Nanosleep(t *testing.T) { 262 var aNs sys.Nanosleep = func(int64) {} 263 sysCtx, err := NewContext(0, nil, nil, nil, nil, nil, nil, nil, 0, nil, 0, aNs, nil, nil, nil, nil) 264 require.Nil(t, err) 265 require.Equal(t, aNs, sysCtx.nanosleep) 266 } 267 268 func TestNewContext_Osyield(t *testing.T) { 269 var oy sys.Osyield = func() {} 270 sysCtx, err := NewContext(0, nil, nil, nil, nil, nil, nil, nil, 0, nil, 0, nil, oy, nil, nil, nil) 271 require.Nil(t, err) 272 require.Equal(t, oy, sysCtx.osyield) 273 }