mirror of
https://github.com/ncruces/go-sqlite3.git
synced 2026-01-11 21:49:13 +00:00
Pass mptest crash.
This commit is contained in:
19
module.go
19
module.go
@@ -4,6 +4,7 @@ package sqlite3
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"io"
|
||||
"math"
|
||||
"os"
|
||||
"runtime"
|
||||
@@ -80,12 +81,13 @@ type module struct {
|
||||
ctx context.Context
|
||||
mem memory
|
||||
api sqliteAPI
|
||||
vfs io.Closer
|
||||
}
|
||||
|
||||
func newModule(mod api.Module) (m *module, err error) {
|
||||
m = &module{}
|
||||
m.mem = memory{mod}
|
||||
m.ctx = context.Background()
|
||||
m.ctx, m.vfs = vfsContext(context.Background())
|
||||
|
||||
getFun := func(name string) api.Function {
|
||||
f := mod.ExportedFunction(name)
|
||||
@@ -156,13 +158,15 @@ func newModule(mod api.Module) (m *module, err error) {
|
||||
interrupt: getVal("sqlite3_interrupt_offset"),
|
||||
}
|
||||
if err != nil {
|
||||
m = nil
|
||||
return nil, err
|
||||
}
|
||||
return
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (m *module) close() error {
|
||||
return m.mem.mod.Close(m.ctx)
|
||||
err := m.mem.mod.Close(m.ctx)
|
||||
m.vfs.Close()
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *module) error(rc uint64, handle uint32, sql ...string) error {
|
||||
@@ -178,18 +182,18 @@ func (m *module) error(rc uint64, handle uint32, sql ...string) error {
|
||||
|
||||
var r []uint64
|
||||
|
||||
r, _ = m.api.errstr.Call(m.ctx, rc)
|
||||
r = m.call(m.api.errstr, rc)
|
||||
if r != nil {
|
||||
err.str = m.mem.readString(uint32(r[0]), _MAX_STRING)
|
||||
}
|
||||
|
||||
r, _ = m.api.errmsg.Call(m.ctx, uint64(handle))
|
||||
r = m.call(m.api.errmsg, uint64(handle))
|
||||
if r != nil {
|
||||
err.msg = m.mem.readString(uint32(r[0]), _MAX_STRING)
|
||||
}
|
||||
|
||||
if sql != nil {
|
||||
r, _ = m.api.erroff.Call(m.ctx, uint64(handle))
|
||||
r = m.call(m.api.erroff, uint64(handle))
|
||||
if r != nil && r[0] != math.MaxUint32 {
|
||||
err.sql = sql[0][r[0]:]
|
||||
}
|
||||
@@ -205,6 +209,7 @@ func (m *module) error(rc uint64, handle uint32, sql ...string) error {
|
||||
func (m *module) call(fn api.Function, params ...uint64) []uint64 {
|
||||
r, err := fn.Call(m.ctx, params...)
|
||||
if err != nil {
|
||||
m.vfs.Close()
|
||||
panic(err)
|
||||
}
|
||||
return r
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"embed"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
@@ -33,6 +34,9 @@ var scripts embed.FS
|
||||
//go:linkname vfsNewEnvModuleBuilder github.com/ncruces/go-sqlite3.vfsNewEnvModuleBuilder
|
||||
func vfsNewEnvModuleBuilder(r wazero.Runtime) wazero.HostModuleBuilder
|
||||
|
||||
//go:linkname vfsContext github.com/ncruces/go-sqlite3.vfsContext
|
||||
func vfsContext(ctx context.Context) (context.Context, io.Closer)
|
||||
|
||||
var (
|
||||
rt wazero.Runtime
|
||||
module wazero.CompiledModule
|
||||
@@ -83,40 +87,56 @@ func system(ctx context.Context, mod api.Module, ptr uint32) uint32 {
|
||||
args = args[:len(args)-1]
|
||||
|
||||
cfg := config(ctx).WithArgs(args...)
|
||||
go rt.InstantiateModule(ctx, module, cfg)
|
||||
go func() {
|
||||
ctx, vfs := vfsContext(ctx)
|
||||
rt.InstantiateModule(ctx, module, cfg)
|
||||
vfs.Close()
|
||||
}()
|
||||
return 0
|
||||
}
|
||||
|
||||
func Test_config01(t *testing.T) {
|
||||
ctx := newContext(t)
|
||||
ctx, vfs := vfsContext(newContext(t))
|
||||
name := filepath.Join(t.TempDir(), "test.db")
|
||||
cfg := config(ctx).WithArgs("mptest", name, "config01.test")
|
||||
_, err := rt.InstantiateModule(ctx, module, cfg)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
vfs.Close()
|
||||
}
|
||||
|
||||
func Test_config02(t *testing.T) {
|
||||
t.Skip() // TODO: remove
|
||||
ctx := newContext(t)
|
||||
if testing.Short() {
|
||||
t.Skip("skipping in short mode")
|
||||
}
|
||||
if os.Getenv("CI") != "" {
|
||||
t.Skip("skipping in CI")
|
||||
}
|
||||
|
||||
ctx, vfs := vfsContext(newContext(t))
|
||||
name := filepath.Join(t.TempDir(), "test.db")
|
||||
cfg := config(ctx).WithArgs("mptest", name, "config02.test")
|
||||
_, err := rt.InstantiateModule(ctx, module, cfg)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
vfs.Close()
|
||||
}
|
||||
|
||||
func Test_crash01(t *testing.T) {
|
||||
t.Skip() // TODO: remove
|
||||
ctx := newContext(t)
|
||||
if testing.Short() {
|
||||
t.Skip("skipping in short mode")
|
||||
}
|
||||
|
||||
ctx, vfs := vfsContext(newContext(t))
|
||||
name := filepath.Join(t.TempDir(), "test.db")
|
||||
cfg := config(ctx).WithArgs("mptest", name, "crash01.test")
|
||||
_, err := rt.InstantiateModule(ctx, module, cfg)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
vfs.Close()
|
||||
}
|
||||
|
||||
func Test_multiwrite01(t *testing.T) {
|
||||
@@ -124,13 +144,14 @@ func Test_multiwrite01(t *testing.T) {
|
||||
t.Skip("skipping in short mode")
|
||||
}
|
||||
|
||||
ctx := newContext(t)
|
||||
ctx, vfs := vfsContext(newContext(t))
|
||||
name := filepath.Join(t.TempDir(), "test.db")
|
||||
cfg := config(ctx).WithArgs("mptest", name, "multiwrite01.test")
|
||||
_, err := rt.InstantiateModule(ctx, module, cfg)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
vfs.Close()
|
||||
}
|
||||
|
||||
func newContext(t *testing.T) context.Context {
|
||||
|
||||
2
tests/mptest/testdata/.gitattributes
vendored
2
tests/mptest/testdata/.gitattributes
vendored
@@ -1,2 +1,2 @@
|
||||
mptest.wasm filter=lfs diff=lfs merge=lfs -text
|
||||
*.test* -crlf
|
||||
*.*test -crlf
|
||||
1
tests/mptest/testdata/build.sh
vendored
1
tests/mptest/testdata/build.sh
vendored
@@ -19,6 +19,7 @@ zig cc --target=wasm32-wasi -flto -g0 -Os \
|
||||
-mbulk-memory -mreference-types \
|
||||
-mnontrapping-fptoint -msign-ext \
|
||||
-D_HAVE_SQLITE_CONFIG_H \
|
||||
-DSQLITE_DEFAULT_SYNCHRONOUS=0 \
|
||||
-DSQLITE_DEFAULT_LOCKING_MODE=0 \
|
||||
-DHAVE_USLEEP -DSQLITE_NO_SYNC \
|
||||
-DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \
|
||||
|
||||
4
tests/mptest/testdata/mptest.wasm
vendored
4
tests/mptest/testdata/mptest.wasm
vendored
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:e155ad9a9723b2eb2c0d187cbd079f4111931064a62ba0cb30ff4e4242bf5efd
|
||||
size 1077263
|
||||
oid sha256:3960b873a7dab969a66f7859d491cec0dd4e6c0c9f83eab449fb15ec5ebdfd8f
|
||||
size 1077281
|
||||
|
||||
16
vfs.go
16
vfs.go
@@ -232,8 +232,7 @@ func vfsOpen(ctx context.Context, mod api.Module, pVfs, zName, pFile uint32, fla
|
||||
vfsOS.DeleteOnClose(file)
|
||||
}
|
||||
|
||||
id := vfsGetFileID(file)
|
||||
vfsFilePtr{mod, pFile}.SetID(id).SetLock(_NO_LOCK)
|
||||
vfsFileOpen(ctx, mod, pFile, file)
|
||||
|
||||
if pOutFlags != 0 {
|
||||
memory{mod}.writeUint32(pOutFlags, uint32(flags))
|
||||
@@ -242,8 +241,7 @@ func vfsOpen(ctx context.Context, mod api.Module, pVfs, zName, pFile uint32, fla
|
||||
}
|
||||
|
||||
func vfsClose(ctx context.Context, mod api.Module, pFile uint32) uint32 {
|
||||
id := vfsFilePtr{mod, pFile}.ID()
|
||||
err := vfsCloseFile(id)
|
||||
err := vfsFileClose(ctx, mod, pFile)
|
||||
if err != nil {
|
||||
return uint32(IOERR_CLOSE)
|
||||
}
|
||||
@@ -253,7 +251,7 @@ func vfsClose(ctx context.Context, mod api.Module, pFile uint32) uint32 {
|
||||
func vfsRead(ctx context.Context, mod api.Module, pFile, zBuf, iAmt uint32, iOfst uint64) uint32 {
|
||||
buf := memory{mod}.view(zBuf, uint64(iAmt))
|
||||
|
||||
file := vfsFilePtr{mod, pFile}.OSFile()
|
||||
file := vfsFileGet(ctx, mod, pFile)
|
||||
n, err := file.ReadAt(buf, int64(iOfst))
|
||||
if n == int(iAmt) {
|
||||
return _OK
|
||||
@@ -270,7 +268,7 @@ func vfsRead(ctx context.Context, mod api.Module, pFile, zBuf, iAmt uint32, iOfs
|
||||
func vfsWrite(ctx context.Context, mod api.Module, pFile, zBuf, iAmt uint32, iOfst uint64) uint32 {
|
||||
buf := memory{mod}.view(zBuf, uint64(iAmt))
|
||||
|
||||
file := vfsFilePtr{mod, pFile}.OSFile()
|
||||
file := vfsFileGet(ctx, mod, pFile)
|
||||
_, err := file.WriteAt(buf, int64(iOfst))
|
||||
if err != nil {
|
||||
return uint32(IOERR_WRITE)
|
||||
@@ -279,7 +277,7 @@ func vfsWrite(ctx context.Context, mod api.Module, pFile, zBuf, iAmt uint32, iOf
|
||||
}
|
||||
|
||||
func vfsTruncate(ctx context.Context, mod api.Module, pFile uint32, nByte uint64) uint32 {
|
||||
file := vfsFilePtr{mod, pFile}.OSFile()
|
||||
file := vfsFileGet(ctx, mod, pFile)
|
||||
err := file.Truncate(int64(nByte))
|
||||
if err != nil {
|
||||
return uint32(IOERR_TRUNCATE)
|
||||
@@ -288,7 +286,7 @@ func vfsTruncate(ctx context.Context, mod api.Module, pFile uint32, nByte uint64
|
||||
}
|
||||
|
||||
func vfsSync(ctx context.Context, mod api.Module, pFile, flags uint32) uint32 {
|
||||
file := vfsFilePtr{mod, pFile}.OSFile()
|
||||
file := vfsFileGet(ctx, mod, pFile)
|
||||
err := file.Sync()
|
||||
if err != nil {
|
||||
return uint32(IOERR_FSYNC)
|
||||
@@ -300,7 +298,7 @@ func vfsFileSize(ctx context.Context, mod api.Module, pFile, pSize uint32) uint3
|
||||
// This uses [os.File.Seek] because we don't care about the offset for reading/writing.
|
||||
// But consider using [os.File.Stat] instead (as other VFSes do).
|
||||
|
||||
file := vfsFilePtr{mod, pFile}.OSFile()
|
||||
file := vfsFileGet(ctx, mod, pFile)
|
||||
off, err := file.Seek(0, io.SeekEnd)
|
||||
if err != nil {
|
||||
return uint32(IOERR_SEEK)
|
||||
|
||||
92
vfs_files.go
92
vfs_files.go
@@ -1,69 +1,79 @@
|
||||
package sqlite3
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
)
|
||||
|
||||
var (
|
||||
vfsOpenFiles []*os.File
|
||||
vfsOpenFilesMtx sync.Mutex
|
||||
)
|
||||
type vfsKey struct{}
|
||||
|
||||
func vfsGetFileID(file *os.File) uint32 {
|
||||
vfsOpenFilesMtx.Lock()
|
||||
defer vfsOpenFilesMtx.Unlock()
|
||||
type vfsState struct {
|
||||
files []*os.File
|
||||
}
|
||||
|
||||
func (vfs *vfsState) Close() error {
|
||||
for _, f := range vfs.files {
|
||||
if f != nil {
|
||||
f.Close()
|
||||
}
|
||||
}
|
||||
vfs.files = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func vfsContext(ctx context.Context) (context.Context, io.Closer) {
|
||||
vfs := &vfsState{}
|
||||
return context.WithValue(ctx, vfsKey{}, vfs), vfs
|
||||
}
|
||||
|
||||
func vfsFileNewID(ctx context.Context, file *os.File) uint32 {
|
||||
vfs := ctx.Value(vfsKey{}).(*vfsState)
|
||||
|
||||
// Find an empty slot.
|
||||
for id, ptr := range vfsOpenFiles {
|
||||
for id, ptr := range vfs.files {
|
||||
if ptr == nil {
|
||||
vfsOpenFiles[id] = file
|
||||
vfs.files[id] = file
|
||||
return uint32(id)
|
||||
}
|
||||
}
|
||||
|
||||
// Add a new slot.
|
||||
vfsOpenFiles = append(vfsOpenFiles, file)
|
||||
return uint32(len(vfsOpenFiles) - 1)
|
||||
vfs.files = append(vfs.files, file)
|
||||
return uint32(len(vfs.files) - 1)
|
||||
}
|
||||
|
||||
func vfsCloseFile(id uint32) error {
|
||||
vfsOpenFilesMtx.Lock()
|
||||
defer vfsOpenFilesMtx.Unlock()
|
||||
func vfsFileOpen(ctx context.Context, mod api.Module, pFile uint32, file *os.File) {
|
||||
mem := memory{mod}
|
||||
id := vfsFileNewID(ctx, file)
|
||||
mem.writeUint32(pFile+ptrlen, id)
|
||||
mem.writeUint32(pFile+2*ptrlen, _NO_LOCK)
|
||||
}
|
||||
|
||||
file := vfsOpenFiles[id]
|
||||
vfsOpenFiles[id] = nil
|
||||
func vfsFileClose(ctx context.Context, mod api.Module, pFile uint32) error {
|
||||
mem := memory{mod}
|
||||
id := mem.readUint32(pFile + ptrlen)
|
||||
vfs := ctx.Value(vfsKey{}).(*vfsState)
|
||||
file := vfs.files[id]
|
||||
vfs.files[id] = nil
|
||||
return file.Close()
|
||||
}
|
||||
|
||||
type vfsFilePtr struct {
|
||||
api.Module
|
||||
ptr uint32
|
||||
func vfsFileGet(ctx context.Context, mod api.Module, pFile uint32) *os.File {
|
||||
mem := memory{mod}
|
||||
id := mem.readUint32(pFile + ptrlen)
|
||||
vfs := ctx.Value(vfsKey{}).(*vfsState)
|
||||
return vfs.files[id]
|
||||
}
|
||||
|
||||
func (p vfsFilePtr) OSFile() *os.File {
|
||||
id := p.ID()
|
||||
vfsOpenFilesMtx.Lock()
|
||||
defer vfsOpenFilesMtx.Unlock()
|
||||
return vfsOpenFiles[id]
|
||||
func vfsFileLockState(ctx context.Context, mod api.Module, pFile uint32) vfsLockState {
|
||||
mem := memory{mod}
|
||||
return vfsLockState(mem.readUint32(pFile + 2*ptrlen))
|
||||
}
|
||||
|
||||
func (p vfsFilePtr) ID() uint32 {
|
||||
return memory{p}.readUint32(p.ptr + ptrlen)
|
||||
}
|
||||
|
||||
func (p vfsFilePtr) Lock() vfsLockState {
|
||||
return vfsLockState(memory{p}.readUint32(p.ptr + 2*ptrlen))
|
||||
}
|
||||
|
||||
func (p vfsFilePtr) SetID(id uint32) vfsFilePtr {
|
||||
memory{p}.writeUint32(p.ptr+ptrlen, id)
|
||||
return p
|
||||
}
|
||||
|
||||
func (p vfsFilePtr) SetLock(lock vfsLockState) vfsFilePtr {
|
||||
memory{p}.writeUint32(p.ptr+2*ptrlen, uint32(lock))
|
||||
return p
|
||||
func vfsFileSetLockState(ctx context.Context, mod api.Module, pFile uint32, lock vfsLockState) {
|
||||
mem := memory{mod}
|
||||
mem.writeUint32(pFile+2*ptrlen, uint32(lock))
|
||||
}
|
||||
|
||||
27
vfs_lock.go
27
vfs_lock.go
@@ -61,9 +61,8 @@ func vfsLock(ctx context.Context, mod api.Module, pFile uint32, eLock vfsLockSta
|
||||
panic(assertErr())
|
||||
}
|
||||
|
||||
ptr := vfsFilePtr{mod, pFile}
|
||||
file := ptr.OSFile()
|
||||
cLock := ptr.Lock()
|
||||
file := vfsFileGet(ctx, mod, pFile)
|
||||
cLock := vfsFileLockState(ctx, mod, pFile)
|
||||
|
||||
switch {
|
||||
case cLock < _NO_LOCK || cLock > _EXCLUSIVE_LOCK:
|
||||
@@ -95,7 +94,7 @@ func vfsLock(ctx context.Context, mod api.Module, pFile uint32, eLock vfsLockSta
|
||||
if rc := vfsOS.GetSharedLock(file); rc != _OK {
|
||||
return uint32(rc)
|
||||
}
|
||||
ptr.SetLock(_SHARED_LOCK)
|
||||
vfsFileSetLockState(ctx, mod, pFile, _SHARED_LOCK)
|
||||
return _OK
|
||||
|
||||
case _RESERVED_LOCK:
|
||||
@@ -106,7 +105,7 @@ func vfsLock(ctx context.Context, mod api.Module, pFile uint32, eLock vfsLockSta
|
||||
if rc := vfsOS.GetReservedLock(file); rc != _OK {
|
||||
return uint32(rc)
|
||||
}
|
||||
ptr.SetLock(_RESERVED_LOCK)
|
||||
vfsFileSetLockState(ctx, mod, pFile, _RESERVED_LOCK)
|
||||
return _OK
|
||||
|
||||
case _EXCLUSIVE_LOCK:
|
||||
@@ -119,12 +118,12 @@ func vfsLock(ctx context.Context, mod api.Module, pFile uint32, eLock vfsLockSta
|
||||
if rc := vfsOS.GetPendingLock(file); rc != _OK {
|
||||
return uint32(rc)
|
||||
}
|
||||
ptr.SetLock(_PENDING_LOCK)
|
||||
vfsFileSetLockState(ctx, mod, pFile, _PENDING_LOCK)
|
||||
}
|
||||
if rc := vfsOS.GetExclusiveLock(file); rc != _OK {
|
||||
return uint32(rc)
|
||||
}
|
||||
ptr.SetLock(_EXCLUSIVE_LOCK)
|
||||
vfsFileSetLockState(ctx, mod, pFile, _EXCLUSIVE_LOCK)
|
||||
return _OK
|
||||
|
||||
default:
|
||||
@@ -138,9 +137,8 @@ func vfsUnlock(ctx context.Context, mod api.Module, pFile uint32, eLock vfsLockS
|
||||
panic(assertErr())
|
||||
}
|
||||
|
||||
ptr := vfsFilePtr{mod, pFile}
|
||||
file := ptr.OSFile()
|
||||
cLock := ptr.Lock()
|
||||
file := vfsFileGet(ctx, mod, pFile)
|
||||
cLock := vfsFileLockState(ctx, mod, pFile)
|
||||
|
||||
// Connection state check.
|
||||
if cLock < _NO_LOCK || cLock > _EXCLUSIVE_LOCK {
|
||||
@@ -157,12 +155,12 @@ func vfsUnlock(ctx context.Context, mod api.Module, pFile uint32, eLock vfsLockS
|
||||
if rc := vfsOS.DowngradeLock(file, cLock); rc != _OK {
|
||||
return uint32(rc)
|
||||
}
|
||||
ptr.SetLock(_SHARED_LOCK)
|
||||
vfsFileSetLockState(ctx, mod, pFile, _SHARED_LOCK)
|
||||
return _OK
|
||||
|
||||
case _NO_LOCK:
|
||||
rc := vfsOS.ReleaseLock(file, cLock)
|
||||
ptr.SetLock(_NO_LOCK)
|
||||
vfsFileSetLockState(ctx, mod, pFile, _NO_LOCK)
|
||||
return uint32(rc)
|
||||
|
||||
default:
|
||||
@@ -171,14 +169,13 @@ func vfsUnlock(ctx context.Context, mod api.Module, pFile uint32, eLock vfsLockS
|
||||
}
|
||||
|
||||
func vfsCheckReservedLock(ctx context.Context, mod api.Module, pFile, pResOut uint32) uint32 {
|
||||
ptr := vfsFilePtr{mod, pFile}
|
||||
cLock := ptr.Lock()
|
||||
cLock := vfsFileLockState(ctx, mod, pFile)
|
||||
|
||||
if cLock > _SHARED_LOCK {
|
||||
panic(assertErr())
|
||||
}
|
||||
|
||||
file := ptr.OSFile()
|
||||
file := vfsFileGet(ctx, mod, pFile)
|
||||
|
||||
locked, rc := vfsOS.CheckReservedLock(file)
|
||||
var res uint32
|
||||
|
||||
@@ -38,10 +38,13 @@ func Test_vfsLock(t *testing.T) {
|
||||
pOutput = 32
|
||||
)
|
||||
mem := newMemory(128)
|
||||
vfsFilePtr{mem.mod, pFile1}.SetID(vfsGetFileID(file1)).SetLock(_NO_LOCK)
|
||||
vfsFilePtr{mem.mod, pFile2}.SetID(vfsGetFileID(file2)).SetLock(_NO_LOCK)
|
||||
ctx, vfs := vfsContext(context.TODO())
|
||||
defer vfs.Close()
|
||||
|
||||
rc := vfsCheckReservedLock(context.TODO(), mem.mod, pFile1, pOutput)
|
||||
vfsFileOpen(ctx, mem.mod, pFile1, file1)
|
||||
vfsFileOpen(ctx, mem.mod, pFile2, file2)
|
||||
|
||||
rc := vfsCheckReservedLock(ctx, mem.mod, pFile1, pOutput)
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
@@ -49,12 +52,12 @@ func Test_vfsLock(t *testing.T) {
|
||||
t.Error("file was locked")
|
||||
}
|
||||
|
||||
rc = vfsLock(context.TODO(), mem.mod, pFile2, _SHARED_LOCK)
|
||||
rc = vfsLock(ctx, mem.mod, pFile2, _SHARED_LOCK)
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
|
||||
rc = vfsCheckReservedLock(context.TODO(), mem.mod, pFile1, pOutput)
|
||||
rc = vfsCheckReservedLock(ctx, mem.mod, pFile1, pOutput)
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
@@ -62,16 +65,16 @@ func Test_vfsLock(t *testing.T) {
|
||||
t.Error("file was locked")
|
||||
}
|
||||
|
||||
rc = vfsLock(context.TODO(), mem.mod, pFile2, _RESERVED_LOCK)
|
||||
rc = vfsLock(ctx, mem.mod, pFile2, _RESERVED_LOCK)
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
rc = vfsLock(context.TODO(), mem.mod, pFile2, _SHARED_LOCK)
|
||||
rc = vfsLock(ctx, mem.mod, pFile2, _SHARED_LOCK)
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
|
||||
rc = vfsCheckReservedLock(context.TODO(), mem.mod, pFile1, pOutput)
|
||||
rc = vfsCheckReservedLock(ctx, mem.mod, pFile1, pOutput)
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
@@ -79,12 +82,12 @@ func Test_vfsLock(t *testing.T) {
|
||||
t.Error("file wasn't locked")
|
||||
}
|
||||
|
||||
rc = vfsLock(context.TODO(), mem.mod, pFile2, _EXCLUSIVE_LOCK)
|
||||
rc = vfsLock(ctx, mem.mod, pFile2, _EXCLUSIVE_LOCK)
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
|
||||
rc = vfsCheckReservedLock(context.TODO(), mem.mod, pFile1, pOutput)
|
||||
rc = vfsCheckReservedLock(ctx, mem.mod, pFile1, pOutput)
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
@@ -92,12 +95,12 @@ func Test_vfsLock(t *testing.T) {
|
||||
t.Error("file wasn't locked")
|
||||
}
|
||||
|
||||
rc = vfsLock(context.TODO(), mem.mod, pFile1, _SHARED_LOCK)
|
||||
rc = vfsLock(ctx, mem.mod, pFile1, _SHARED_LOCK)
|
||||
if rc == _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
|
||||
rc = vfsCheckReservedLock(context.TODO(), mem.mod, pFile1, pOutput)
|
||||
rc = vfsCheckReservedLock(ctx, mem.mod, pFile1, pOutput)
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
@@ -105,12 +108,12 @@ func Test_vfsLock(t *testing.T) {
|
||||
t.Error("file wasn't locked")
|
||||
}
|
||||
|
||||
rc = vfsUnlock(context.TODO(), mem.mod, pFile2, _SHARED_LOCK)
|
||||
rc = vfsUnlock(ctx, mem.mod, pFile2, _SHARED_LOCK)
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
|
||||
rc = vfsCheckReservedLock(context.TODO(), mem.mod, pFile1, pOutput)
|
||||
rc = vfsCheckReservedLock(ctx, mem.mod, pFile1, pOutput)
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
@@ -118,7 +121,7 @@ func Test_vfsLock(t *testing.T) {
|
||||
t.Error("file was locked")
|
||||
}
|
||||
|
||||
rc = vfsLock(context.TODO(), mem.mod, pFile1, _SHARED_LOCK)
|
||||
rc = vfsLock(ctx, mem.mod, pFile1, _SHARED_LOCK)
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
|
||||
54
vfs_test.go
54
vfs_test.go
@@ -16,15 +16,17 @@ import (
|
||||
|
||||
func Test_vfsExit(t *testing.T) {
|
||||
mem := newMemory(128)
|
||||
ctx := context.TODO()
|
||||
defer func() { _ = recover() }()
|
||||
vfsExit(context.TODO(), mem.mod, 1)
|
||||
vfsExit(ctx, mem.mod, 1)
|
||||
t.Error("want panic")
|
||||
}
|
||||
|
||||
func Test_vfsLocaltime(t *testing.T) {
|
||||
mem := newMemory(128)
|
||||
ctx := context.TODO()
|
||||
|
||||
rc := vfsLocaltime(context.TODO(), mem.mod, 0, 4)
|
||||
rc := vfsLocaltime(ctx, mem.mod, 0, 4)
|
||||
if rc != 0 {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
@@ -71,24 +73,26 @@ func Test_vfsRandomness(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_vfsSleep(t *testing.T) {
|
||||
start := time.Now()
|
||||
ctx := context.TODO()
|
||||
|
||||
rc := vfsSleep(context.TODO(), 0, 123456)
|
||||
now := time.Now()
|
||||
rc := vfsSleep(ctx, 0, 123456)
|
||||
if rc != 0 {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
|
||||
want := 123456 * time.Microsecond
|
||||
if got := time.Since(start); got < want {
|
||||
if got := time.Since(now); got < want {
|
||||
t.Errorf("got %v, want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_vfsCurrentTime(t *testing.T) {
|
||||
mem := newMemory(128)
|
||||
ctx := context.TODO()
|
||||
|
||||
now := time.Now()
|
||||
rc := vfsCurrentTime(context.TODO(), mem.mod, 0, 4)
|
||||
rc := vfsCurrentTime(ctx, mem.mod, 0, 4)
|
||||
if rc != 0 {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
@@ -101,10 +105,11 @@ func Test_vfsCurrentTime(t *testing.T) {
|
||||
|
||||
func Test_vfsCurrentTime64(t *testing.T) {
|
||||
mem := newMemory(128)
|
||||
ctx := context.TODO()
|
||||
|
||||
now := time.Now()
|
||||
time.Sleep(time.Millisecond)
|
||||
rc := vfsCurrentTime64(context.TODO(), mem.mod, 0, 4)
|
||||
rc := vfsCurrentTime64(ctx, mem.mod, 0, 4)
|
||||
if rc != 0 {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
@@ -119,13 +124,14 @@ func Test_vfsCurrentTime64(t *testing.T) {
|
||||
func Test_vfsFullPathname(t *testing.T) {
|
||||
mem := newMemory(128 + _MAX_PATHNAME)
|
||||
mem.writeString(4, ".")
|
||||
ctx := context.TODO()
|
||||
|
||||
rc := vfsFullPathname(context.TODO(), mem.mod, 0, 4, 0, 8)
|
||||
rc := vfsFullPathname(ctx, mem.mod, 0, 4, 0, 8)
|
||||
if rc != uint32(CANTOPEN_FULLPATH) {
|
||||
t.Errorf("returned %d, want %d", rc, CANTOPEN_FULLPATH)
|
||||
}
|
||||
|
||||
rc = vfsFullPathname(context.TODO(), mem.mod, 0, 4, _MAX_PATHNAME, 8)
|
||||
rc = vfsFullPathname(ctx, mem.mod, 0, 4, _MAX_PATHNAME, 8)
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
@@ -147,8 +153,9 @@ func Test_vfsDelete(t *testing.T) {
|
||||
|
||||
mem := newMemory(128 + _MAX_PATHNAME)
|
||||
mem.writeString(4, name)
|
||||
ctx := context.TODO()
|
||||
|
||||
rc := vfsDelete(context.TODO(), mem.mod, 0, 4, 1)
|
||||
rc := vfsDelete(ctx, mem.mod, 0, 4, 1)
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
@@ -157,7 +164,7 @@ func Test_vfsDelete(t *testing.T) {
|
||||
t.Fatal("did not delete the file")
|
||||
}
|
||||
|
||||
rc = vfsDelete(context.TODO(), mem.mod, 0, 4, 1)
|
||||
rc = vfsDelete(ctx, mem.mod, 0, 4, 1)
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
@@ -177,8 +184,9 @@ func Test_vfsAccess(t *testing.T) {
|
||||
|
||||
mem := newMemory(128 + _MAX_PATHNAME)
|
||||
mem.writeString(8, dir)
|
||||
ctx := context.TODO()
|
||||
|
||||
rc := vfsAccess(context.TODO(), mem.mod, 0, 8, _ACCESS_EXISTS, 4)
|
||||
rc := vfsAccess(ctx, mem.mod, 0, 8, _ACCESS_EXISTS, 4)
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
@@ -186,7 +194,7 @@ func Test_vfsAccess(t *testing.T) {
|
||||
t.Error("directory did not exist")
|
||||
}
|
||||
|
||||
rc = vfsAccess(context.TODO(), mem.mod, 0, 8, _ACCESS_READWRITE, 4)
|
||||
rc = vfsAccess(ctx, mem.mod, 0, 8, _ACCESS_READWRITE, 4)
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
@@ -195,7 +203,7 @@ func Test_vfsAccess(t *testing.T) {
|
||||
}
|
||||
|
||||
mem.writeString(8, file)
|
||||
rc = vfsAccess(context.TODO(), mem.mod, 0, 8, _ACCESS_READWRITE, 4)
|
||||
rc = vfsAccess(ctx, mem.mod, 0, 8, _ACCESS_READWRITE, 4)
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
@@ -206,9 +214,11 @@ func Test_vfsAccess(t *testing.T) {
|
||||
|
||||
func Test_vfsFile(t *testing.T) {
|
||||
mem := newMemory(128)
|
||||
ctx, vfs := vfsContext(context.TODO())
|
||||
defer vfs.Close()
|
||||
|
||||
// Open a temporary file.
|
||||
rc := vfsOpen(context.TODO(), mem.mod, 0, 0, 4, OPEN_CREATE|OPEN_EXCLUSIVE|OPEN_READWRITE|OPEN_DELETEONCLOSE, 0)
|
||||
rc := vfsOpen(ctx, mem.mod, 0, 0, 4, OPEN_CREATE|OPEN_EXCLUSIVE|OPEN_READWRITE|OPEN_DELETEONCLOSE, 0)
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
@@ -216,13 +226,13 @@ func Test_vfsFile(t *testing.T) {
|
||||
// Write stuff.
|
||||
text := "Hello world!"
|
||||
mem.writeString(16, text)
|
||||
rc = vfsWrite(context.TODO(), mem.mod, 4, 16, uint32(len(text)), 0)
|
||||
rc = vfsWrite(ctx, mem.mod, 4, 16, uint32(len(text)), 0)
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
|
||||
// Check file size.
|
||||
rc = vfsFileSize(context.TODO(), mem.mod, 4, 16)
|
||||
rc = vfsFileSize(ctx, mem.mod, 4, 16)
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
@@ -231,7 +241,7 @@ func Test_vfsFile(t *testing.T) {
|
||||
}
|
||||
|
||||
// Partial read at offset.
|
||||
rc = vfsRead(context.TODO(), mem.mod, 4, 16, uint32(len(text)), 4)
|
||||
rc = vfsRead(ctx, mem.mod, 4, 16, uint32(len(text)), 4)
|
||||
if rc != uint32(IOERR_SHORT_READ) {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
@@ -240,13 +250,13 @@ func Test_vfsFile(t *testing.T) {
|
||||
}
|
||||
|
||||
// Truncate the file.
|
||||
rc = vfsTruncate(context.TODO(), mem.mod, 4, 4)
|
||||
rc = vfsTruncate(ctx, mem.mod, 4, 4)
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
|
||||
// Check file size.
|
||||
rc = vfsFileSize(context.TODO(), mem.mod, 4, 16)
|
||||
rc = vfsFileSize(ctx, mem.mod, 4, 16)
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
@@ -255,7 +265,7 @@ func Test_vfsFile(t *testing.T) {
|
||||
}
|
||||
|
||||
// Read at offset.
|
||||
rc = vfsRead(context.TODO(), mem.mod, 4, 32, 4, 0)
|
||||
rc = vfsRead(ctx, mem.mod, 4, 32, 4, 0)
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
@@ -264,7 +274,7 @@ func Test_vfsFile(t *testing.T) {
|
||||
}
|
||||
|
||||
// Close the file.
|
||||
rc = vfsClose(context.TODO(), mem.mod, 4)
|
||||
rc = vfsClose(ctx, mem.mod, 4)
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user