1 package wasi_snapshot_preview1_test
2
3 import (
4 "bytes"
5 "context"
6 _ "embed"
7 "testing"
8 "time"
9
10 "github.com/tetratelabs/wazero"
11 "github.com/tetratelabs/wazero/api"
12 "github.com/tetratelabs/wazero/experimental"
13 "github.com/tetratelabs/wazero/experimental/logging"
14 "github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1"
15 "github.com/tetratelabs/wazero/internal/testing/proxy"
16 "github.com/tetratelabs/wazero/internal/testing/require"
17 "github.com/tetratelabs/wazero/internal/wasip1"
18 "github.com/tetratelabs/wazero/sys"
19 )
20
21
22 var testCtx = context.WithValue(context.Background(), struct{}{}, "arbitrary")
23
24 const testMemoryPageSize = 1
25
26
27
28
29
30
31 var exitOnStartUnstableWasm []byte
32
33 func TestNewFunctionExporter(t *testing.T) {
34 t.Run("export as wasi_unstable", func(t *testing.T) {
35 r := wazero.NewRuntime(testCtx)
36 defer r.Close(testCtx)
37
38
39
40 wasiBuilder := r.NewHostModuleBuilder("wasi_unstable")
41 wasi_snapshot_preview1.NewFunctionExporter().ExportFunctions(wasiBuilder)
42 _, err := wasiBuilder.Instantiate(testCtx)
43 require.NoError(t, err)
44
45
46 _, err = r.Instantiate(testCtx, exitOnStartUnstableWasm)
47
48
49 require.Equal(t, uint32(2), err.(*sys.ExitError).ExitCode())
50 })
51
52 t.Run("override function", func(t *testing.T) {
53 r := wazero.NewRuntime(testCtx)
54 defer r.Close(testCtx)
55
56
57 wasiBuilder := r.NewHostModuleBuilder(wasi_snapshot_preview1.ModuleName)
58 wasi_snapshot_preview1.NewFunctionExporter().ExportFunctions(wasiBuilder)
59
60
61
62 wasiBuilder.NewFunctionBuilder().
63 WithFunc(func(ctx context.Context, mod api.Module, exitCode uint32) {
64 require.Equal(t, uint32(2), exitCode)
65
66 mod.Close(ctx)
67 }).Export("proc_exit")
68
69 _, err := wasiBuilder.Instantiate(testCtx)
70 require.NoError(t, err)
71
72
73 _, err = r.Instantiate(testCtx, exitOnStartWasm)
74
75
76 require.Nil(t, err)
77 })
78 }
79
80
81 func maskMemory(t *testing.T, mod api.Module, size int) {
82 for i := uint32(0); i < uint32(size); i++ {
83 require.True(t, mod.Memory().WriteByte(i, '?'))
84 }
85 }
86
87 func requireProxyModule(t *testing.T, config wazero.ModuleConfig) (api.Module, api.Closer, *bytes.Buffer) {
88 return requireProxyModuleWithContext(testCtx, t, config)
89 }
90
91 func requireProxyModuleWithContext(ctx context.Context, t *testing.T, config wazero.ModuleConfig) (api.Module, api.Closer, *bytes.Buffer) {
92 var log bytes.Buffer
93
94
95 ctx = context.WithValue(ctx, experimental.FunctionListenerFactoryKey{},
96 proxy.NewLoggingListenerFactory(&log, logging.LogScopeAll))
97
98 r := wazero.NewRuntime(ctx)
99
100 wasiModuleCompiled, err := wasi_snapshot_preview1.NewBuilder(r).Compile(ctx)
101 require.NoError(t, err)
102
103 _, err = r.InstantiateModule(ctx, wasiModuleCompiled, config)
104 require.NoError(t, err)
105
106 proxyBin := proxy.NewModuleBinary(wasi_snapshot_preview1.ModuleName, wasiModuleCompiled)
107
108 proxyCompiled, err := r.CompileModule(ctx, proxyBin)
109 require.NoError(t, err)
110
111 mod, err := r.InstantiateModule(ctx, proxyCompiled, config)
112 require.NoError(t, err)
113
114 return mod, r, &log
115 }
116
117
118
119
120 func requireErrnoNosys(t *testing.T, funcName string, params ...uint64) string {
121 var log bytes.Buffer
122
123
124 ctx := context.WithValue(testCtx, experimental.FunctionListenerFactoryKey{},
125 proxy.NewLoggingListenerFactory(&log, logging.LogScopeAll))
126
127 r := wazero.NewRuntime(ctx)
128 defer r.Close(ctx)
129
130
131 wasiModuleCompiled, err := wasi_snapshot_preview1.NewBuilder(r).Compile(ctx)
132 require.NoError(t, err)
133
134 _, err = r.InstantiateModule(ctx, wasiModuleCompiled, wazero.NewModuleConfig())
135 require.NoError(t, err)
136
137 proxyBin := proxy.NewModuleBinary(wasi_snapshot_preview1.ModuleName, wasiModuleCompiled)
138
139 proxyCompiled, err := r.CompileModule(ctx, proxyBin)
140 require.NoError(t, err)
141
142 mod, err := r.InstantiateModule(ctx, proxyCompiled, wazero.NewModuleConfig())
143 require.NoError(t, err)
144
145 requireErrnoResult(t, wasip1.ErrnoNosys, mod, funcName, params...)
146 return "\n" + log.String()
147 }
148
149 func requireErrnoResult(t *testing.T, expectedErrno wasip1.Errno, mod api.Closer, funcName string, params ...uint64) {
150 results, err := mod.(api.Module).ExportedFunction(funcName).Call(testCtx, params...)
151 require.NoError(t, err)
152 errno := wasip1.Errno(results[0])
153 require.Equal(t, expectedErrno, errno, "want %s but have %s", wasip1.ErrnoName(expectedErrno), wasip1.ErrnoName(errno))
154 }
155
156 func newBlockingReader(t *testing.T) blockingReader {
157 timeout, cancelFunc := context.WithTimeout(testCtx, 5*time.Second)
158 t.Cleanup(cancelFunc)
159 return blockingReader{ctx: timeout}
160 }
161
162
163
164 type blockingReader struct {
165 ctx context.Context
166 }
167
168
169 func (b blockingReader) Read(buf []byte) (n int, err error) {
170 <-b.ctx.Done()
171 return 0, nil
172 }
173
View as plain text