2023-05-19 03:04:07 +01:00
|
|
|
package sqlite3vfs
|
2023-01-30 08:12:12 +00:00
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
|
|
|
|
"os"
|
2023-02-20 13:30:01 +00:00
|
|
|
"path/filepath"
|
2023-01-30 08:12:12 +00:00
|
|
|
"runtime"
|
|
|
|
|
"testing"
|
2023-03-29 15:01:25 +01:00
|
|
|
|
|
|
|
|
"github.com/ncruces/go-sqlite3/internal/util"
|
2023-01-30 08:12:12 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func Test_vfsLock(t *testing.T) {
|
|
|
|
|
switch runtime.GOOS {
|
2023-03-17 17:13:03 +00:00
|
|
|
case "linux", "darwin", "windows":
|
2023-02-23 13:29:51 +00:00
|
|
|
break
|
2023-01-30 08:12:12 +00:00
|
|
|
default:
|
2023-03-01 12:16:36 +00:00
|
|
|
t.Skip("OS lacks OFD locks")
|
2023-01-30 08:12:12 +00:00
|
|
|
}
|
|
|
|
|
|
2023-02-20 13:30:01 +00:00
|
|
|
name := filepath.Join(t.TempDir(), "test.db")
|
|
|
|
|
|
2023-02-10 17:14:43 +00:00
|
|
|
// Create a temporary file.
|
2023-02-20 13:30:01 +00:00
|
|
|
file1, err := os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666)
|
2023-01-30 08:12:12 +00:00
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
defer file1.Close()
|
|
|
|
|
|
2023-02-10 17:14:43 +00:00
|
|
|
// Open the temporary file again.
|
2023-01-30 08:12:12 +00:00
|
|
|
file2, err := os.OpenFile(name, os.O_RDWR, 0)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
defer file2.Close()
|
|
|
|
|
|
2023-02-10 17:14:43 +00:00
|
|
|
const (
|
|
|
|
|
pFile1 = 4
|
|
|
|
|
pFile2 = 16
|
|
|
|
|
pOutput = 32
|
|
|
|
|
)
|
2023-03-29 15:01:25 +01:00
|
|
|
mod := util.NewMockModule(128)
|
2023-05-19 03:04:07 +01:00
|
|
|
ctx, vfs := NewContext(context.TODO())
|
2023-03-07 03:51:07 +00:00
|
|
|
defer vfs.Close()
|
2023-02-10 17:14:43 +00:00
|
|
|
|
2023-05-18 16:00:34 +01:00
|
|
|
vfsFileRegister(ctx, mod, pFile1, &vfsFile{File: file1})
|
|
|
|
|
vfsFileRegister(ctx, mod, pFile2, &vfsFile{File: file2})
|
2023-03-07 03:51:07 +00:00
|
|
|
|
2023-03-29 15:01:25 +01:00
|
|
|
rc := vfsCheckReservedLock(ctx, mod, pFile1, pOutput)
|
2023-01-30 08:12:12 +00:00
|
|
|
if rc != _OK {
|
|
|
|
|
t.Fatal("returned", rc)
|
|
|
|
|
}
|
2023-03-29 15:01:25 +01:00
|
|
|
if got := util.ReadUint32(mod, pOutput); got != 0 {
|
2023-01-30 08:12:12 +00:00
|
|
|
t.Error("file was locked")
|
|
|
|
|
}
|
2023-03-29 15:01:25 +01:00
|
|
|
rc = vfsCheckReservedLock(ctx, mod, pFile2, pOutput)
|
2023-03-23 11:26:19 +00:00
|
|
|
if rc != _OK {
|
|
|
|
|
t.Fatal("returned", rc)
|
|
|
|
|
}
|
2023-03-29 15:01:25 +01:00
|
|
|
if got := util.ReadUint32(mod, pOutput); got != 0 {
|
2023-03-23 11:26:19 +00:00
|
|
|
t.Error("file was locked")
|
|
|
|
|
}
|
2023-05-19 14:45:40 +01:00
|
|
|
rc = vfsFileControl(ctx, mod, pFile2, _FCNTL_LOCKSTATE, pOutput)
|
|
|
|
|
if rc != _OK {
|
|
|
|
|
t.Fatal("returned", rc)
|
|
|
|
|
}
|
|
|
|
|
if got := util.ReadUint32(mod, pOutput); got != uint32(LOCK_NONE) {
|
|
|
|
|
t.Error("invalid lock state", got)
|
|
|
|
|
}
|
2023-01-30 08:12:12 +00:00
|
|
|
|
2023-05-19 03:04:07 +01:00
|
|
|
rc = vfsLock(ctx, mod, pFile2, LOCK_SHARED)
|
2023-01-30 08:12:12 +00:00
|
|
|
if rc != _OK {
|
|
|
|
|
t.Fatal("returned", rc)
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 15:01:25 +01:00
|
|
|
rc = vfsCheckReservedLock(ctx, mod, pFile1, pOutput)
|
2023-01-30 08:12:12 +00:00
|
|
|
if rc != _OK {
|
|
|
|
|
t.Fatal("returned", rc)
|
|
|
|
|
}
|
2023-03-29 15:01:25 +01:00
|
|
|
if got := util.ReadUint32(mod, pOutput); got != 0 {
|
2023-01-30 08:12:12 +00:00
|
|
|
t.Error("file was locked")
|
|
|
|
|
}
|
2023-03-29 15:01:25 +01:00
|
|
|
rc = vfsCheckReservedLock(ctx, mod, pFile2, pOutput)
|
2023-03-23 11:26:19 +00:00
|
|
|
if rc != _OK {
|
|
|
|
|
t.Fatal("returned", rc)
|
|
|
|
|
}
|
2023-03-29 15:01:25 +01:00
|
|
|
if got := util.ReadUint32(mod, pOutput); got != 0 {
|
2023-03-23 11:26:19 +00:00
|
|
|
t.Error("file was locked")
|
|
|
|
|
}
|
2023-05-19 14:45:40 +01:00
|
|
|
rc = vfsFileControl(ctx, mod, pFile2, _FCNTL_LOCKSTATE, pOutput)
|
|
|
|
|
if rc != _OK {
|
|
|
|
|
t.Fatal("returned", rc)
|
|
|
|
|
}
|
|
|
|
|
if got := util.ReadUint32(mod, pOutput); got != uint32(LOCK_SHARED) {
|
|
|
|
|
t.Error("invalid lock state", got)
|
|
|
|
|
}
|
2023-01-30 08:12:12 +00:00
|
|
|
|
2023-05-19 03:04:07 +01:00
|
|
|
rc = vfsLock(ctx, mod, pFile2, LOCK_RESERVED)
|
2023-02-10 17:14:43 +00:00
|
|
|
if rc != _OK {
|
|
|
|
|
t.Fatal("returned", rc)
|
|
|
|
|
}
|
2023-05-19 03:04:07 +01:00
|
|
|
rc = vfsLock(ctx, mod, pFile2, LOCK_SHARED)
|
2023-01-30 08:12:12 +00:00
|
|
|
if rc != _OK {
|
|
|
|
|
t.Fatal("returned", rc)
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 15:01:25 +01:00
|
|
|
rc = vfsCheckReservedLock(ctx, mod, pFile1, pOutput)
|
2023-01-30 08:12:12 +00:00
|
|
|
if rc != _OK {
|
|
|
|
|
t.Fatal("returned", rc)
|
|
|
|
|
}
|
2023-03-29 15:01:25 +01:00
|
|
|
if got := util.ReadUint32(mod, pOutput); got == 0 {
|
2023-01-30 08:12:12 +00:00
|
|
|
t.Error("file wasn't locked")
|
|
|
|
|
}
|
2023-03-29 15:01:25 +01:00
|
|
|
rc = vfsCheckReservedLock(ctx, mod, pFile2, pOutput)
|
2023-03-23 11:26:19 +00:00
|
|
|
if rc != _OK {
|
|
|
|
|
t.Fatal("returned", rc)
|
|
|
|
|
}
|
2023-03-29 15:01:25 +01:00
|
|
|
if got := util.ReadUint32(mod, pOutput); got == 0 {
|
2023-03-23 11:26:19 +00:00
|
|
|
t.Error("file wasn't locked")
|
|
|
|
|
}
|
2023-05-19 14:45:40 +01:00
|
|
|
rc = vfsFileControl(ctx, mod, pFile2, _FCNTL_LOCKSTATE, pOutput)
|
|
|
|
|
if rc != _OK {
|
|
|
|
|
t.Fatal("returned", rc)
|
|
|
|
|
}
|
|
|
|
|
if got := util.ReadUint32(mod, pOutput); got != uint32(LOCK_RESERVED) {
|
|
|
|
|
t.Error("invalid lock state", got)
|
|
|
|
|
}
|
2023-02-10 17:14:43 +00:00
|
|
|
|
2023-05-19 03:04:07 +01:00
|
|
|
rc = vfsLock(ctx, mod, pFile2, LOCK_EXCLUSIVE)
|
2023-02-10 17:14:43 +00:00
|
|
|
if rc != _OK {
|
|
|
|
|
t.Fatal("returned", rc)
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 15:01:25 +01:00
|
|
|
rc = vfsCheckReservedLock(ctx, mod, pFile1, pOutput)
|
2023-02-10 17:14:43 +00:00
|
|
|
if rc != _OK {
|
|
|
|
|
t.Fatal("returned", rc)
|
|
|
|
|
}
|
2023-03-29 15:01:25 +01:00
|
|
|
if got := util.ReadUint32(mod, pOutput); got == 0 {
|
2023-02-10 17:14:43 +00:00
|
|
|
t.Error("file wasn't locked")
|
|
|
|
|
}
|
2023-03-29 15:01:25 +01:00
|
|
|
rc = vfsCheckReservedLock(ctx, mod, pFile2, pOutput)
|
2023-03-23 11:26:19 +00:00
|
|
|
if rc != _OK {
|
|
|
|
|
t.Fatal("returned", rc)
|
|
|
|
|
}
|
2023-03-29 15:01:25 +01:00
|
|
|
if got := util.ReadUint32(mod, pOutput); got == 0 {
|
2023-03-23 11:26:19 +00:00
|
|
|
t.Error("file wasn't locked")
|
|
|
|
|
}
|
2023-05-19 14:45:40 +01:00
|
|
|
rc = vfsFileControl(ctx, mod, pFile2, _FCNTL_LOCKSTATE, pOutput)
|
|
|
|
|
if rc != _OK {
|
|
|
|
|
t.Fatal("returned", rc)
|
|
|
|
|
}
|
|
|
|
|
if got := util.ReadUint32(mod, pOutput); got != uint32(LOCK_EXCLUSIVE) {
|
|
|
|
|
t.Error("invalid lock state", got)
|
|
|
|
|
}
|
2023-02-10 17:14:43 +00:00
|
|
|
|
2023-05-19 03:04:07 +01:00
|
|
|
rc = vfsLock(ctx, mod, pFile1, LOCK_SHARED)
|
2023-02-10 17:14:43 +00:00
|
|
|
if rc == _OK {
|
|
|
|
|
t.Fatal("returned", rc)
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 15:01:25 +01:00
|
|
|
rc = vfsCheckReservedLock(ctx, mod, pFile1, pOutput)
|
2023-02-23 13:29:51 +00:00
|
|
|
if rc != _OK {
|
|
|
|
|
t.Fatal("returned", rc)
|
|
|
|
|
}
|
2023-03-29 15:01:25 +01:00
|
|
|
if got := util.ReadUint32(mod, pOutput); got == 0 {
|
2023-02-23 13:29:51 +00:00
|
|
|
t.Error("file wasn't locked")
|
|
|
|
|
}
|
2023-03-29 15:01:25 +01:00
|
|
|
rc = vfsCheckReservedLock(ctx, mod, pFile2, pOutput)
|
2023-03-23 11:26:19 +00:00
|
|
|
if rc != _OK {
|
|
|
|
|
t.Fatal("returned", rc)
|
|
|
|
|
}
|
2023-03-29 15:01:25 +01:00
|
|
|
if got := util.ReadUint32(mod, pOutput); got == 0 {
|
2023-03-23 11:26:19 +00:00
|
|
|
t.Error("file wasn't locked")
|
|
|
|
|
}
|
2023-05-19 14:45:40 +01:00
|
|
|
rc = vfsFileControl(ctx, mod, pFile1, _FCNTL_LOCKSTATE, pOutput)
|
|
|
|
|
if rc != _OK {
|
|
|
|
|
t.Fatal("returned", rc)
|
|
|
|
|
}
|
|
|
|
|
if got := util.ReadUint32(mod, pOutput); got != uint32(LOCK_NONE) {
|
|
|
|
|
t.Error("invalid lock state", got)
|
|
|
|
|
}
|
2023-02-23 13:29:51 +00:00
|
|
|
|
2023-05-19 03:04:07 +01:00
|
|
|
rc = vfsUnlock(ctx, mod, pFile2, LOCK_SHARED)
|
2023-02-10 17:14:43 +00:00
|
|
|
if rc != _OK {
|
|
|
|
|
t.Fatal("returned", rc)
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 15:01:25 +01:00
|
|
|
rc = vfsCheckReservedLock(ctx, mod, pFile1, pOutput)
|
2023-02-23 13:29:51 +00:00
|
|
|
if rc != _OK {
|
|
|
|
|
t.Fatal("returned", rc)
|
|
|
|
|
}
|
2023-03-29 15:01:25 +01:00
|
|
|
if got := util.ReadUint32(mod, pOutput); got != 0 {
|
2023-02-23 13:29:51 +00:00
|
|
|
t.Error("file was locked")
|
|
|
|
|
}
|
2023-03-29 15:01:25 +01:00
|
|
|
rc = vfsCheckReservedLock(ctx, mod, pFile2, pOutput)
|
2023-03-23 11:26:19 +00:00
|
|
|
if rc != _OK {
|
|
|
|
|
t.Fatal("returned", rc)
|
|
|
|
|
}
|
2023-03-29 15:01:25 +01:00
|
|
|
if got := util.ReadUint32(mod, pOutput); got != 0 {
|
2023-03-23 11:26:19 +00:00
|
|
|
t.Error("file was locked")
|
|
|
|
|
}
|
2023-02-23 13:29:51 +00:00
|
|
|
|
2023-05-19 03:04:07 +01:00
|
|
|
rc = vfsLock(ctx, mod, pFile1, LOCK_SHARED)
|
2023-02-10 17:14:43 +00:00
|
|
|
if rc != _OK {
|
|
|
|
|
t.Fatal("returned", rc)
|
|
|
|
|
}
|
2023-05-19 14:45:40 +01:00
|
|
|
rc = vfsFileControl(ctx, mod, pFile1, _FCNTL_LOCKSTATE, pOutput)
|
|
|
|
|
if rc != _OK {
|
|
|
|
|
t.Fatal("returned", rc)
|
|
|
|
|
}
|
|
|
|
|
if got := util.ReadUint32(mod, pOutput); got != uint32(LOCK_SHARED) {
|
|
|
|
|
t.Error("invalid lock state", got)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rc = vfsFileControl(ctx, mod, pFile1, _FCNTL_LOCK_TIMEOUT, 1)
|
|
|
|
|
if rc != _OK {
|
|
|
|
|
t.Fatal("returned", rc)
|
|
|
|
|
}
|
2023-01-30 08:12:12 +00:00
|
|
|
}
|