Adds test to verify cross-process file system cache works (#753)
Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>
This commit is contained in:
66
internal/integration_test/filecache/filecache_test.go
Normal file
66
internal/integration_test/filecache/filecache_test.go
Normal file
@@ -0,0 +1,66 @@
|
||||
package filecache
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/tetratelabs/wazero/experimental"
|
||||
"github.com/tetratelabs/wazero/internal/engine/compiler"
|
||||
"github.com/tetratelabs/wazero/internal/integration_test/spectest"
|
||||
v1 "github.com/tetratelabs/wazero/internal/integration_test/spectest/v1"
|
||||
"github.com/tetratelabs/wazero/internal/platform"
|
||||
"github.com/tetratelabs/wazero/internal/testing/require"
|
||||
)
|
||||
|
||||
func TestSpecTestCompilerCache(t *testing.T) {
|
||||
if !platform.CompilerSupported() {
|
||||
return
|
||||
}
|
||||
|
||||
const cachePathKey = "FILE_CACHE_DIR"
|
||||
cacheDir := os.Getenv(cachePathKey)
|
||||
if len(cacheDir) == 0 {
|
||||
// This case, this is the parent of the test.
|
||||
cacheDir = t.TempDir()
|
||||
|
||||
// Before running test, no file should exist in the directory.
|
||||
files, err := os.ReadDir(cacheDir)
|
||||
require.NoError(t, err)
|
||||
require.True(t, len(files) == 0)
|
||||
|
||||
// Get the executable path of this test.
|
||||
testExecutable, err := os.Executable()
|
||||
require.NoError(t, err)
|
||||
|
||||
// Execute this test multiple times with the env $cachePathKey=cacheDir, so that
|
||||
// the subsequent execution of this test will enter the following "else" block.
|
||||
var exp []string
|
||||
buf := bytes.NewBuffer(nil)
|
||||
for i := 0; i < 5; i++ {
|
||||
cmd := exec.Command(testExecutable)
|
||||
cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", cachePathKey, cacheDir))
|
||||
cmd.Stdout = buf
|
||||
cmd.Stderr = buf
|
||||
err = cmd.Run()
|
||||
require.NoError(t, err)
|
||||
exp = append(exp, "PASS\n")
|
||||
}
|
||||
|
||||
// Ensures that the tests actually run 5 times.
|
||||
require.Equal(t, strings.Join(exp, ""), buf.String())
|
||||
|
||||
// Check the number of cache files is greater than zero.
|
||||
files, err = os.ReadDir(cacheDir)
|
||||
require.NoError(t, err)
|
||||
require.True(t, len(files) > 0)
|
||||
} else {
|
||||
// Run the spectest with the file cache.
|
||||
ctx := experimental.WithCompilationCacheDirName(context.Background(), cacheDir)
|
||||
spectest.Run(t, v1.Testcases, ctx, compiler.NewEngine, v1.EnabledFeatures)
|
||||
}
|
||||
}
|
||||
@@ -24,9 +24,6 @@ import (
|
||||
"github.com/tetratelabs/wazero/internal/watzero"
|
||||
)
|
||||
|
||||
// testCtx is an arbitrary, non-default context. Non-nil also prevents linter errors.
|
||||
var testCtx = context.WithValue(context.Background(), struct{}{}, "arbitrary")
|
||||
|
||||
// TODO: complete porting this to wazero API
|
||||
type (
|
||||
testbase struct {
|
||||
@@ -323,7 +320,7 @@ func (c command) expectedError() (err error) {
|
||||
//
|
||||
// See https://github.com/WebAssembly/spec/blob/wg-1.0/test/core/imports.wast
|
||||
// See https://github.com/WebAssembly/spec/blob/wg-1.0/interpreter/script/js.ml#L13-L25
|
||||
func addSpectestModule(t *testing.T, s *wasm.Store, ns *wasm.Namespace) {
|
||||
func addSpectestModule(t *testing.T, ctx context.Context, s *wasm.Store, ns *wasm.Namespace) {
|
||||
w, err := watzero.Wat2Wasm(`(module $spectest
|
||||
(; TODO
|
||||
(global (export "global_i32") i32)
|
||||
@@ -401,10 +398,10 @@ func addSpectestModule(t *testing.T, s *wasm.Store, ns *wasm.Namespace) {
|
||||
|
||||
maybeSetMemoryCap(mod)
|
||||
mod.BuildFunctionDefinitions()
|
||||
err = s.Engine.CompileModule(testCtx, mod)
|
||||
err = s.Engine.CompileModule(ctx, mod)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = s.Instantiate(testCtx, ns, mod, mod.NameSection.ModuleName, sys.DefaultContext(nil), nil)
|
||||
_, err = s.Instantiate(ctx, ns, mod, mod.NameSection.ModuleName, sys.DefaultContext(nil), nil)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
@@ -417,7 +414,7 @@ func maybeSetMemoryCap(mod *wasm.Module) {
|
||||
|
||||
// Run runs all the test inside the testDataFS file system where all the cases are described
|
||||
// via JSON files created from wast2json.
|
||||
func Run(t *testing.T, testDataFS embed.FS, newEngine func(context.Context, wasm.Features) wasm.Engine, enabledFeatures wasm.Features) {
|
||||
func Run(t *testing.T, testDataFS embed.FS, ctx context.Context, newEngine func(context.Context, wasm.Features) wasm.Engine, enabledFeatures wasm.Features) {
|
||||
files, err := testDataFS.ReadDir("testdata")
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -443,8 +440,8 @@ func Run(t *testing.T, testDataFS embed.FS, newEngine func(context.Context, wasm
|
||||
wastName := basename(base.SourceFile)
|
||||
|
||||
t.Run(wastName, func(t *testing.T) {
|
||||
s, ns := wasm.NewStore(enabledFeatures, newEngine(testCtx, enabledFeatures))
|
||||
addSpectestModule(t, s, ns)
|
||||
s, ns := wasm.NewStore(enabledFeatures, newEngine(ctx, enabledFeatures))
|
||||
addSpectestModule(t, ctx, s, ns)
|
||||
|
||||
var lastInstantiatedModuleName string
|
||||
for _, c := range base.Commands {
|
||||
@@ -467,10 +464,10 @@ func Run(t *testing.T, testDataFS embed.FS, newEngine func(context.Context, wasm
|
||||
|
||||
maybeSetMemoryCap(mod)
|
||||
mod.BuildFunctionDefinitions()
|
||||
err = s.Engine.CompileModule(testCtx, mod)
|
||||
err = s.Engine.CompileModule(ctx, mod)
|
||||
require.NoError(t, err, msg)
|
||||
|
||||
_, err = s.Instantiate(testCtx, ns, mod, moduleName, nil, nil)
|
||||
_, err = s.Instantiate(ctx, ns, mod, moduleName, nil, nil)
|
||||
lastInstantiatedModuleName = moduleName
|
||||
require.NoError(t, err)
|
||||
case "register":
|
||||
@@ -492,7 +489,7 @@ func Run(t *testing.T, testDataFS embed.FS, newEngine func(context.Context, wasm
|
||||
if c.Action.Module != "" {
|
||||
msg += " in module " + c.Action.Module
|
||||
}
|
||||
vals, types, err := callFunction(ns, moduleName, c.Action.Field, args...)
|
||||
vals, types, err := callFunction(ns, ctx, moduleName, c.Action.Field, args...)
|
||||
require.NoError(t, err, msg)
|
||||
require.Equal(t, len(exps), len(vals), msg)
|
||||
laneTypes := map[int]string{}
|
||||
@@ -526,7 +523,7 @@ func Run(t *testing.T, testDataFS embed.FS, newEngine func(context.Context, wasm
|
||||
expType = wasm.ValueTypeF64
|
||||
}
|
||||
require.Equal(t, expType, global.Type(), msg)
|
||||
require.Equal(t, exps[0], global.Get(testCtx), msg)
|
||||
require.Equal(t, exps[0], global.Get(ctx), msg)
|
||||
default:
|
||||
t.Fatalf("unsupported action type type: %v", c)
|
||||
}
|
||||
@@ -535,7 +532,7 @@ func Run(t *testing.T, testDataFS embed.FS, newEngine func(context.Context, wasm
|
||||
// We don't support direct loading of wast yet.
|
||||
buf, err := testDataFS.ReadFile(testdataPath(c.Filename))
|
||||
require.NoError(t, err, msg)
|
||||
requireInstantiationError(t, s, ns, buf, msg)
|
||||
requireInstantiationError(t, ctx, s, ns, buf, msg)
|
||||
}
|
||||
case "assert_trap":
|
||||
moduleName := lastInstantiatedModuleName
|
||||
@@ -549,7 +546,7 @@ func Run(t *testing.T, testDataFS embed.FS, newEngine func(context.Context, wasm
|
||||
if c.Action.Module != "" {
|
||||
msg += " in module " + c.Action.Module
|
||||
}
|
||||
_, _, err := callFunction(ns, moduleName, c.Action.Field, args...)
|
||||
_, _, err := callFunction(ns, ctx, moduleName, c.Action.Field, args...)
|
||||
require.ErrorIs(t, err, c.expectedError(), msg)
|
||||
default:
|
||||
t.Fatalf("unsupported action type type: %v", c)
|
||||
@@ -561,7 +558,7 @@ func Run(t *testing.T, testDataFS embed.FS, newEngine func(context.Context, wasm
|
||||
}
|
||||
buf, err := testDataFS.ReadFile(testdataPath(c.Filename))
|
||||
require.NoError(t, err, msg)
|
||||
requireInstantiationError(t, s, ns, buf, msg)
|
||||
requireInstantiationError(t, ctx, s, ns, buf, msg)
|
||||
case "assert_exhaustion":
|
||||
moduleName := lastInstantiatedModuleName
|
||||
switch c.Action.ActionType {
|
||||
@@ -571,7 +568,7 @@ func Run(t *testing.T, testDataFS embed.FS, newEngine func(context.Context, wasm
|
||||
if c.Action.Module != "" {
|
||||
msg += " in module " + c.Action.Module
|
||||
}
|
||||
_, _, err := callFunction(ns, moduleName, c.Action.Field, args...)
|
||||
_, _, err := callFunction(ns, ctx, moduleName, c.Action.Field, args...)
|
||||
require.ErrorIs(t, err, wasmruntime.ErrRuntimeCallStackOverflow, msg)
|
||||
default:
|
||||
t.Fatalf("unsupported action type type: %v", c)
|
||||
@@ -583,7 +580,7 @@ func Run(t *testing.T, testDataFS embed.FS, newEngine func(context.Context, wasm
|
||||
}
|
||||
buf, err := testDataFS.ReadFile(testdataPath(c.Filename))
|
||||
require.NoError(t, err, msg)
|
||||
requireInstantiationError(t, s, ns, buf, msg)
|
||||
requireInstantiationError(t, ctx, s, ns, buf, msg)
|
||||
case "assert_uninstantiable":
|
||||
buf, err := testDataFS.ReadFile(testdataPath(c.Filename))
|
||||
require.NoError(t, err, msg)
|
||||
@@ -605,13 +602,13 @@ func Run(t *testing.T, testDataFS embed.FS, newEngine func(context.Context, wasm
|
||||
|
||||
maybeSetMemoryCap(mod)
|
||||
mod.BuildFunctionDefinitions()
|
||||
err = s.Engine.CompileModule(testCtx, mod)
|
||||
err = s.Engine.CompileModule(ctx, mod)
|
||||
require.NoError(t, err, msg)
|
||||
|
||||
_, err = s.Instantiate(testCtx, ns, mod, t.Name(), nil, nil)
|
||||
_, err = s.Instantiate(ctx, ns, mod, t.Name(), nil, nil)
|
||||
require.NoError(t, err, msg)
|
||||
} else {
|
||||
requireInstantiationError(t, s, ns, buf, msg)
|
||||
requireInstantiationError(t, ctx, s, ns, buf, msg)
|
||||
}
|
||||
|
||||
default:
|
||||
@@ -623,7 +620,7 @@ func Run(t *testing.T, testDataFS embed.FS, newEngine func(context.Context, wasm
|
||||
}
|
||||
}
|
||||
|
||||
func requireInstantiationError(t *testing.T, s *wasm.Store, ns *wasm.Namespace, buf []byte, msg string) {
|
||||
func requireInstantiationError(t *testing.T, ctx context.Context, s *wasm.Store, ns *wasm.Namespace, buf []byte, msg string) {
|
||||
mod, err := binaryformat.DecodeModule(buf, s.EnabledFeatures, wasm.MemorySizer)
|
||||
if err != nil {
|
||||
return
|
||||
@@ -638,12 +635,12 @@ func requireInstantiationError(t *testing.T, s *wasm.Store, ns *wasm.Namespace,
|
||||
|
||||
maybeSetMemoryCap(mod)
|
||||
mod.BuildFunctionDefinitions()
|
||||
err = s.Engine.CompileModule(testCtx, mod)
|
||||
err = s.Engine.CompileModule(ctx, mod)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = s.Instantiate(testCtx, ns, mod, t.Name(), nil, nil)
|
||||
_, err = s.Instantiate(ctx, ns, mod, t.Name(), nil, nil)
|
||||
require.Error(t, err, msg)
|
||||
}
|
||||
|
||||
@@ -831,9 +828,9 @@ func f64Equal(expected, actual float64) (matched bool) {
|
||||
|
||||
// callFunction is inlined here as the spectest needs to validate the signature was correct
|
||||
// TODO: This is likely already covered with unit tests!
|
||||
func callFunction(ns *wasm.Namespace, moduleName, funcName string, params ...uint64) ([]uint64, []wasm.ValueType, error) {
|
||||
func callFunction(ns *wasm.Namespace, ctx context.Context, moduleName, funcName string, params ...uint64) ([]uint64, []wasm.ValueType, error) {
|
||||
fn := ns.Module(moduleName).ExportedFunction(funcName)
|
||||
results, err := fn.Call(testCtx, params...)
|
||||
results, err := fn.Call(ctx, params...)
|
||||
return results, fn.Definition().ResultTypes(), err
|
||||
}
|
||||
|
||||
|
||||
@@ -1,33 +1,26 @@
|
||||
package spectest
|
||||
package v1
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/tetratelabs/wazero/internal/engine/compiler"
|
||||
"github.com/tetratelabs/wazero/internal/engine/interpreter"
|
||||
"github.com/tetratelabs/wazero/internal/integration_test/spectest"
|
||||
"github.com/tetratelabs/wazero/internal/platform"
|
||||
"github.com/tetratelabs/wazero/internal/wasm"
|
||||
)
|
||||
|
||||
//go:embed testdata/*.wasm
|
||||
//go:embed testdata/*.json
|
||||
var testcases embed.FS
|
||||
|
||||
const enabledFeatures = wasm.Features20191205
|
||||
|
||||
func TestCompiler(t *testing.T) {
|
||||
if !platform.CompilerSupported() {
|
||||
t.Skip()
|
||||
}
|
||||
spectest.Run(t, testcases, compiler.NewEngine, enabledFeatures)
|
||||
spectest.Run(t, Testcases, context.Background(), compiler.NewEngine, EnabledFeatures)
|
||||
}
|
||||
|
||||
func TestInterpreter(t *testing.T) {
|
||||
spectest.Run(t, testcases, interpreter.NewEngine, enabledFeatures)
|
||||
spectest.Run(t, Testcases, context.Background(), interpreter.NewEngine, EnabledFeatures)
|
||||
}
|
||||
|
||||
func TestBinaryEncoder(t *testing.T) {
|
||||
spectest.TestBinaryEncoder(t, testcases, enabledFeatures)
|
||||
spectest.TestBinaryEncoder(t, Testcases, EnabledFeatures)
|
||||
}
|
||||
|
||||
16
internal/integration_test/spectest/v1/spectest.go
Normal file
16
internal/integration_test/spectest/v1/spectest.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"embed"
|
||||
|
||||
"github.com/tetratelabs/wazero/internal/wasm"
|
||||
)
|
||||
|
||||
// Testcases is exported for cross-process file cache tests.
|
||||
//
|
||||
//go:embed testdata/*.wasm
|
||||
//go:embed testdata/*.json
|
||||
var Testcases embed.FS
|
||||
|
||||
// EnabledFeatures is exported for cross-process file cache tests.
|
||||
const EnabledFeatures = wasm.Features20191205
|
||||
@@ -1,6 +1,7 @@
|
||||
package spectest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"embed"
|
||||
"testing"
|
||||
|
||||
@@ -21,9 +22,9 @@ func TestCompiler(t *testing.T) {
|
||||
if !platform.CompilerSupported() {
|
||||
t.Skip()
|
||||
}
|
||||
spectest.Run(t, testcases, compiler.NewEngine, enabledFeatures)
|
||||
spectest.Run(t, testcases, context.Background(), compiler.NewEngine, enabledFeatures)
|
||||
}
|
||||
|
||||
func TestInterpreter(t *testing.T) {
|
||||
spectest.Run(t, testcases, interpreter.NewEngine, enabledFeatures)
|
||||
spectest.Run(t, testcases, context.Background(), interpreter.NewEngine, enabledFeatures)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user