wa-lang.org/wazero@v1.0.2/imports/wasi_snapshot_preview1/wasi_test.go (about) 1 package wasi_snapshot_preview1 2 3 import ( 4 "bytes" 5 "context" 6 _ "embed" 7 "testing" 8 9 "wa-lang.org/wazero" 10 "wa-lang.org/wazero/api" 11 . "wa-lang.org/wazero/experimental" 12 "wa-lang.org/wazero/experimental/logging" 13 "wa-lang.org/wazero/internal/testing/proxy" 14 "wa-lang.org/wazero/internal/testing/require" 15 "wa-lang.org/wazero/sys" 16 ) 17 18 // testCtx is an arbitrary, non-default context. Non-nil also prevents linter errors. 19 var testCtx = context.WithValue(context.Background(), struct{}{}, "arbitrary") 20 21 const testMemoryPageSize = 1 22 23 // exitOnStartUnstableWasm was generated by the following: 24 // 25 // cd testdata; wat2wasm --debug-names exit_on_start_unstable.wat 26 // 27 //go:embed testdata/exit_on_start_unstable.wasm 28 var exitOnStartUnstableWasm []byte 29 30 func TestNewFunctionExporter(t *testing.T) { 31 t.Run("export as wasi_unstable", func(t *testing.T) { 32 r := wazero.NewRuntime(testCtx) 33 defer r.Close(testCtx) 34 35 // Instantiate the current WASI functions under the wasi_unstable 36 // instead of wasi_snapshot_preview1. 37 wasiBuilder := r.NewHostModuleBuilder("wasi_unstable") 38 NewFunctionExporter().ExportFunctions(wasiBuilder) 39 _, err := wasiBuilder.Instantiate(testCtx, r) 40 require.NoError(t, err) 41 42 // Instantiate our test binary, but using the old import names. 43 _, err = r.InstantiateModuleFromBinary(testCtx, exitOnStartUnstableWasm) 44 45 // Ensure the test binary worked. It should return exit code 2. 46 require.Equal(t, uint32(2), err.(*sys.ExitError).ExitCode()) 47 }) 48 49 t.Run("override function", func(t *testing.T) { 50 r := wazero.NewRuntime(testCtx) 51 defer r.Close(testCtx) 52 53 // Export the default WASI functions 54 wasiBuilder := r.NewHostModuleBuilder(ModuleName) 55 NewFunctionExporter().ExportFunctions(wasiBuilder) 56 57 // Override proc_exit to prove the point that you can add or replace 58 // functions like this. 59 wasiBuilder.NewFunctionBuilder(). 60 WithFunc(func(ctx context.Context, mod api.Module, exitCode uint32) { 61 require.Equal(t, uint32(2), exitCode) 62 // ignore the code instead! 63 mod.Close(ctx) 64 }).Export("proc_exit") 65 66 _, err := wasiBuilder.Instantiate(testCtx, r) 67 require.NoError(t, err) 68 69 // Instantiate our test binary which will use our modified WASI. 70 _, err = r.InstantiateModuleFromBinary(testCtx, exitOnStartWasm) 71 72 // Ensure the modified function was used! 73 require.Zero(t, err.(*sys.ExitError).ExitCode()) 74 }) 75 } 76 77 // maskMemory sets the first memory in the store to '?' * size, so tests can see what's written. 78 func maskMemory(t *testing.T, ctx context.Context, mod api.Module, size int) { 79 for i := uint32(0); i < uint32(size); i++ { 80 require.True(t, mod.Memory().WriteByte(ctx, i, '?')) 81 } 82 } 83 84 func requireProxyModule(t *testing.T, config wazero.ModuleConfig) (api.Module, api.Closer, *bytes.Buffer) { 85 var log bytes.Buffer 86 87 // Set context to one that has an experimental listener 88 ctx := context.WithValue(testCtx, FunctionListenerFactoryKey{}, logging.NewLoggingListenerFactory(&log)) 89 90 r := wazero.NewRuntime(ctx) 91 92 wasiModuleCompiled, err := (&builder{r}).hostModuleBuilder().Compile(ctx) 93 require.NoError(t, err) 94 95 _, err = r.InstantiateModule(ctx, wasiModuleCompiled, config) 96 require.NoError(t, err) 97 98 proxyBin := proxy.GetProxyModuleBinary(ModuleName, wasiModuleCompiled) 99 100 proxyCompiled, err := r.CompileModule(ctx, proxyBin) 101 require.NoError(t, err) 102 103 mod, err := r.InstantiateModule(ctx, proxyCompiled, config) 104 require.NoError(t, err) 105 106 return mod, r, &log 107 } 108 109 // requireErrnoNosys ensures a call of the given function returns errno. The log 110 // message returned can verify the output is wasm `-->` or a host `==>` 111 // function. 112 func requireErrnoNosys(t *testing.T, funcName string, params ...uint64) string { 113 var log bytes.Buffer 114 115 // Set context to one that has an experimental listener 116 ctx := context.WithValue(testCtx, FunctionListenerFactoryKey{}, logging.NewHostLoggingListenerFactory(&log)) 117 118 r := wazero.NewRuntime(ctx) 119 defer r.Close(ctx) 120 121 // Instantiate the wasi module. 122 wasiModuleCompiled, err := (&builder{r}).hostModuleBuilder().Compile(ctx) 123 require.NoError(t, err) 124 125 _, err = r.InstantiateModule(ctx, wasiModuleCompiled, wazero.NewModuleConfig()) 126 require.NoError(t, err) 127 128 proxyBin := proxy.GetProxyModuleBinary(ModuleName, wasiModuleCompiled) 129 130 proxyCompiled, err := r.CompileModule(ctx, proxyBin) 131 require.NoError(t, err) 132 133 mod, err := r.InstantiateModule(ctx, proxyCompiled, wazero.NewModuleConfig()) 134 require.NoError(t, err) 135 136 requireErrno(t, ErrnoNosys, mod, funcName, params...) 137 return "\n" + log.String() 138 } 139 140 func requireErrno(t *testing.T, expectedErrno Errno, mod api.Closer, funcName string, params ...uint64) { 141 results, err := mod.(api.Module).ExportedFunction(funcName).Call(testCtx, params...) 142 require.NoError(t, err) 143 errno := Errno(results[0]) 144 require.Equal(t, expectedErrno, errno, ErrnoName(errno)) 145 }