Files
wazero/wasi_test.go
Crypt Keeper a1dc1f56a0 wasi: stops enforcing _start function export (#409)
Currently, we have custom code in wapc-go because our library forces a
failure when a module that uses WASI doesn't define a "_start" function.
Using the same pragmatism that resulted in us not enforcing the WASI
table, this makes the "_start" function optional. This doesn't add a
flag as the spec is not a proper version anyway (snapshot-01), so
there's no need to further complicate configuration.

If a "_start" function exists, we enforce it is of the proper signature
and succeeds. Otherwise, we allow it to be absent.

Signed-off-by: Adrian Cole <adrian@tetrate.io>
Co-authored-by: Takeshi Yoneda <takeshi@tetrate.io>
2022-03-25 07:34:30 +08:00

94 lines
2.6 KiB
Go

package wazero
import (
"bytes"
"context"
_ "embed"
"testing"
"github.com/stretchr/testify/require"
"github.com/tetratelabs/wazero/wasm"
)
// TestStartWASICommand_DoesntEnforce_Start ensures wapc-go work when modules import WASI, but don't export "_start".
func TestStartWASICommand_DoesntEnforce_Start(t *testing.T) {
r := NewRuntime()
wasi, err := r.InstantiateModule(WASISnapshotPreview1())
require.NoError(t, err)
defer wasi.Close()
// Start the module as a WASI command. This will fail if the context wasn't as intended.
mod, err := StartWASICommandFromSource(r, []byte(`(module $wasi_test.go
(memory 1)
(export "memory" (memory 0))
)`))
require.NoError(t, err)
require.NoError(t, mod.Close())
}
func TestStartWASICommand_UsesRuntimeContext(t *testing.T) {
type key string
config := NewRuntimeConfig().WithContext(context.WithValue(context.Background(), key("wa"), "zero"))
r := NewRuntimeWithConfig(config)
// Define a function that will be re-exported as the WASI function: _start
var calledStart bool
start := func(ctx wasm.Module) {
calledStart = true
require.Equal(t, config.ctx, ctx.Context())
}
host, err := r.NewModuleBuilder("").ExportFunction("start", start).Instantiate()
require.NoError(t, err)
defer host.Close()
wasi, err := r.InstantiateModule(WASISnapshotPreview1())
require.NoError(t, err)
defer wasi.Close()
// Start the module as a WASI command. This will fail if the context wasn't as intended.
mod, err := StartWASICommandFromSource(r, []byte(`(module $wasi_test.go
(import "" "start" (func $start))
(memory 1)
(export "_start" (func $start))
(export "memory" (memory 0))
)`))
require.NoError(t, err)
defer mod.Close()
require.True(t, calledStart)
}
// wasiArg was compiled from examples/testdata/wasi_arg.wat
//go:embed examples/testdata/wasi_arg.wasm
var wasiArg []byte
func TestStartWASICommandWithConfig(t *testing.T) {
r := NewRuntime()
stdout := bytes.NewBuffer(nil)
// Configure WASI to write stdout to a buffer, so that we can verify it later.
sys := NewSysConfig().WithStdout(stdout)
wasi, err := r.InstantiateModule(WASISnapshotPreview1())
require.NoError(t, err)
defer wasi.Close()
m, err := r.CompileModule(wasiArg)
require.NoError(t, err)
// Re-use the same module many times.
for _, tc := range []string{"a", "b", "c"} {
mod, err := StartWASICommandWithConfig(r, m.WithName(tc), sys.WithArgs(tc))
require.NoError(t, err)
// Ensure the scoped configuration applied. As the args are null-terminated, we append zero (NUL).
require.Equal(t, append([]byte(tc), 0), stdout.Bytes())
stdout.Reset()
require.NoError(t, mod.Close())
}
}