Files
wazero/config_test.go
2022-03-24 15:35:17 +08:00

337 lines
9.1 KiB
Go

package wazero
import (
"io"
"math"
"testing"
"testing/fstest"
"github.com/stretchr/testify/require"
internalwasm "github.com/tetratelabs/wazero/internal/wasm"
)
func TestRuntimeConfig_Features(t *testing.T) {
tests := []struct {
name string
feature internalwasm.Features
expectDefault bool
setFeature func(*RuntimeConfig, bool) *RuntimeConfig
}{
{
name: "mutable-global",
feature: internalwasm.FeatureMutableGlobal,
expectDefault: true,
setFeature: func(c *RuntimeConfig, v bool) *RuntimeConfig {
return c.WithFeatureMutableGlobal(v)
},
},
{
name: "sign-extension-ops",
feature: internalwasm.FeatureSignExtensionOps,
expectDefault: false,
setFeature: func(c *RuntimeConfig, v bool) *RuntimeConfig {
return c.WithFeatureSignExtensionOps(v)
},
},
}
for _, tt := range tests {
tc := tt
t.Run(tc.name, func(t *testing.T) {
c := NewRuntimeConfig()
require.Equal(t, tc.expectDefault, c.enabledFeatures.Get(tc.feature))
// Set to false even if it was initially false.
c = tc.setFeature(c, false)
require.False(t, c.enabledFeatures.Get(tc.feature))
// Set true makes it true
c = tc.setFeature(c, true)
require.True(t, c.enabledFeatures.Get(tc.feature))
// Set false makes it false again
c = tc.setFeature(c, false)
require.False(t, c.enabledFeatures.Get(tc.feature))
})
}
}
func TestSysConfig_toSysContext(t *testing.T) {
testFS := fstest.MapFS{}
testFS2 := fstest.MapFS{}
tests := []struct {
name string
input *SysConfig
expected *internalwasm.SysContext
}{
{
name: "empty",
input: NewSysConfig(),
expected: requireSysContext(t,
math.MaxUint32, // max
nil, // args
nil, // environ
nil, // stdin
nil, // stdout
nil, // stderr
nil, // openedFiles
),
},
{
name: "WithArgs",
input: NewSysConfig().WithArgs("a", "bc"),
expected: requireSysContext(t,
math.MaxUint32, // max
[]string{"a", "bc"}, // args
nil, // environ
nil, // stdin
nil, // stdout
nil, // stderr
nil, // openedFiles
),
},
{
name: "WithArgs - empty ok", // Particularly argv[0] can be empty, and we have no rules about others.
input: NewSysConfig().WithArgs("", "bc"),
expected: requireSysContext(t,
math.MaxUint32, // max
[]string{"", "bc"}, // args
nil, // environ
nil, // stdin
nil, // stdout
nil, // stderr
nil, // openedFiles
),
},
{
name: "WithArgs - second call overwrites",
input: NewSysConfig().WithArgs("a", "bc").WithArgs("bc", "a"),
expected: requireSysContext(t,
math.MaxUint32, // max
[]string{"bc", "a"}, // args
nil, // environ
nil, // stdin
nil, // stdout
nil, // stderr
nil, // openedFiles
),
},
{
name: "WithEnv",
input: NewSysConfig().WithEnv("a", "b"),
expected: requireSysContext(t,
math.MaxUint32, // max
nil, // args
[]string{"a=b"}, // environ
nil, // stdin
nil, // stdout
nil, // stderr
nil, // openedFiles
),
},
{
name: "WithEnv - empty value",
input: NewSysConfig().WithEnv("a", ""),
expected: requireSysContext(t,
math.MaxUint32, // max
nil, // args
[]string{"a="}, // environ
nil, // stdin
nil, // stdout
nil, // stderr
nil, // openedFiles
),
},
{
name: "WithEnv twice",
input: NewSysConfig().WithEnv("a", "b").WithEnv("c", "de"),
expected: requireSysContext(t,
math.MaxUint32, // max
nil, // args
[]string{"a=b", "c=de"}, // environ
nil, // stdin
nil, // stdout
nil, // stderr
nil, // openedFiles
),
},
{
name: "WithEnv overwrites",
input: NewSysConfig().WithEnv("a", "bc").WithEnv("c", "de").WithEnv("a", "de"),
expected: requireSysContext(t,
math.MaxUint32, // max
nil, // args
[]string{"a=de", "c=de"}, // environ
nil, // stdin
nil, // stdout
nil, // stderr
nil, // openedFiles
),
},
{
name: "WithEnv twice",
input: NewSysConfig().WithEnv("a", "b").WithEnv("c", "de"),
expected: requireSysContext(t,
math.MaxUint32, // max
nil, // args
[]string{"a=b", "c=de"}, // environ
nil, // stdin
nil, // stdout
nil, // stderr
nil, // openedFiles
),
},
{
name: "WithFS",
input: NewSysConfig().WithFS(testFS),
expected: requireSysContext(t,
math.MaxUint32, // max
nil, // args
nil, // environ
nil, // stdin
nil, // stdout
nil, // stderr
map[uint32]*internalwasm.FileEntry{ // openedFiles
3: {Path: "/", FS: testFS},
4: {Path: ".", FS: testFS},
},
),
},
{
name: "WithFS - overwrites",
input: NewSysConfig().WithFS(testFS).WithFS(testFS2),
expected: requireSysContext(t,
math.MaxUint32, // max
nil, // args
nil, // environ
nil, // stdin
nil, // stdout
nil, // stderr
map[uint32]*internalwasm.FileEntry{ // openedFiles
3: {Path: "/", FS: testFS2},
4: {Path: ".", FS: testFS2},
},
),
},
{
name: "WithWorkDirFS",
input: NewSysConfig().WithWorkDirFS(testFS),
expected: requireSysContext(t,
math.MaxUint32, // max
nil, // args
nil, // environ
nil, // stdin
nil, // stdout
nil, // stderr
map[uint32]*internalwasm.FileEntry{ // openedFiles
3: {Path: ".", FS: testFS},
},
),
},
{
name: "WithFS and WithWorkDirFS",
input: NewSysConfig().WithFS(testFS).WithWorkDirFS(testFS2),
expected: requireSysContext(t,
math.MaxUint32, // max
nil, // args
nil, // environ
nil, // stdin
nil, // stdout
nil, // stderr
map[uint32]*internalwasm.FileEntry{ // openedFiles
3: {Path: "/", FS: testFS},
4: {Path: ".", FS: testFS2},
},
),
},
{
name: "WithWorkDirFS and WithFS",
input: NewSysConfig().WithWorkDirFS(testFS).WithFS(testFS2),
expected: requireSysContext(t,
math.MaxUint32, // max
nil, // args
nil, // environ
nil, // stdin
nil, // stdout
nil, // stderr
map[uint32]*internalwasm.FileEntry{ // openedFiles
3: {Path: ".", FS: testFS},
4: {Path: "/", FS: testFS2},
},
),
},
}
for _, tt := range tests {
tc := tt
t.Run(tc.name, func(t *testing.T) {
sys, err := tc.input.toSysContext()
require.NoError(t, err)
require.Equal(t, tc.expected, sys)
})
}
}
func TestSysConfig_toSysContext_Errors(t *testing.T) {
tests := []struct {
name string
input *SysConfig
expectedErr string
}{
{
name: "WithArgs - arg contains NUL",
input: NewSysConfig().WithArgs("", string([]byte{'a', 0})),
expectedErr: "args invalid: contains NUL character",
},
{
name: "WithEnv - key contains NUL",
input: NewSysConfig().WithEnv(string([]byte{'a', 0}), "a"),
expectedErr: "environ invalid: contains NUL character",
},
{
name: "WithEnv - value contains NUL",
input: NewSysConfig().WithEnv("a", string([]byte{'a', 0})),
expectedErr: "environ invalid: contains NUL character",
},
{
name: "WithEnv - key contains equals",
input: NewSysConfig().WithEnv("a=", "a"),
expectedErr: "environ invalid: key contains '=' character",
},
{
name: "WithEnv - empty key",
input: NewSysConfig().WithEnv("", "a"),
expectedErr: "environ invalid: empty key",
},
{
name: "WithFS - nil",
input: NewSysConfig().WithFS(nil),
expectedErr: "FS for / is nil",
},
{
name: "WithWorkDirFS - nil",
input: NewSysConfig().WithWorkDirFS(nil),
expectedErr: "FS for . is nil",
},
}
for _, tt := range tests {
tc := tt
t.Run(tc.name, func(t *testing.T) {
_, err := tc.input.toSysContext()
require.EqualError(t, err, tc.expectedErr)
})
}
}
// requireSysContext ensures internalwasm.NewSysContext doesn't return an error, which makes it usable in test matrices.
func requireSysContext(t *testing.T, max uint32, args, environ []string, stdin io.Reader, stdout, stderr io.Writer, openedFiles map[uint32]*internalwasm.FileEntry) *internalwasm.SysContext {
sys, err := internalwasm.NewSysContext(max, args, environ, stdin, stdout, stderr, openedFiles)
require.NoError(t, err)
return sys
}