github.com/ncruces/go-sqlite3@v0.15.1-0.20240520133447-53eef1510ff0/vfs/lock_test.go (about)

     1  package vfs
     2  
     3  import (
     4  	"context"
     5  	"os"
     6  	"path/filepath"
     7  	"testing"
     8  
     9  	"github.com/ncruces/go-sqlite3/internal/util"
    10  	"github.com/tetratelabs/wazero/experimental/wazerotest"
    11  )
    12  
    13  func Test_vfsLock(t *testing.T) {
    14  	if !SupportsFileLocking {
    15  		t.Skip("skipping without locks")
    16  	}
    17  
    18  	name := filepath.Join(t.TempDir(), "test.db")
    19  
    20  	// Create a temporary file.
    21  	file1, err := os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666)
    22  	if err != nil {
    23  		t.Fatal(err)
    24  	}
    25  	defer file1.Close()
    26  
    27  	// Open the temporary file again.
    28  	file2, err := os.OpenFile(name, os.O_RDWR, 0)
    29  	if err != nil {
    30  		t.Fatal(err)
    31  	}
    32  	defer file2.Close()
    33  
    34  	const (
    35  		pFile1  = 4
    36  		pFile2  = 16
    37  		pOutput = 32
    38  	)
    39  	mod := wazerotest.NewModule(wazerotest.NewMemory(wazerotest.PageSize))
    40  	ctx := util.NewContext(context.TODO())
    41  
    42  	vfsFileRegister(ctx, mod, pFile1, &vfsFile{File: file1})
    43  	vfsFileRegister(ctx, mod, pFile2, &vfsFile{File: file2})
    44  
    45  	rc := vfsCheckReservedLock(ctx, mod, pFile1, pOutput)
    46  	if rc != _OK {
    47  		t.Fatal("returned", rc)
    48  	}
    49  	if got := util.ReadUint32(mod, pOutput); got != 0 {
    50  		t.Error("file was locked")
    51  	}
    52  	rc = vfsCheckReservedLock(ctx, mod, pFile2, pOutput)
    53  	if rc != _OK {
    54  		t.Fatal("returned", rc)
    55  	}
    56  	if got := util.ReadUint32(mod, pOutput); got != 0 {
    57  		t.Error("file was locked")
    58  	}
    59  	rc = vfsFileControl(ctx, mod, pFile2, _FCNTL_LOCKSTATE, pOutput)
    60  	if rc != _OK {
    61  		t.Fatal("returned", rc)
    62  	}
    63  	if got := util.ReadUint32(mod, pOutput); got != uint32(LOCK_NONE) {
    64  		t.Error("invalid lock state", got)
    65  	}
    66  
    67  	rc = vfsLock(ctx, mod, pFile2, LOCK_SHARED)
    68  	if rc != _OK {
    69  		t.Fatal("returned", rc)
    70  	}
    71  
    72  	rc = vfsCheckReservedLock(ctx, mod, pFile1, pOutput)
    73  	if rc != _OK {
    74  		t.Fatal("returned", rc)
    75  	}
    76  	if got := util.ReadUint32(mod, pOutput); got != 0 {
    77  		t.Error("file was locked")
    78  	}
    79  	rc = vfsCheckReservedLock(ctx, mod, pFile2, pOutput)
    80  	if rc != _OK {
    81  		t.Fatal("returned", rc)
    82  	}
    83  	if got := util.ReadUint32(mod, pOutput); got != 0 {
    84  		t.Error("file was locked")
    85  	}
    86  	rc = vfsFileControl(ctx, mod, pFile2, _FCNTL_LOCKSTATE, pOutput)
    87  	if rc != _OK {
    88  		t.Fatal("returned", rc)
    89  	}
    90  	if got := util.ReadUint32(mod, pOutput); got != uint32(LOCK_SHARED) {
    91  		t.Error("invalid lock state", got)
    92  	}
    93  
    94  	rc = vfsLock(ctx, mod, pFile2, LOCK_RESERVED)
    95  	if rc != _OK {
    96  		t.Fatal("returned", rc)
    97  	}
    98  	rc = vfsLock(ctx, mod, pFile2, LOCK_SHARED)
    99  	if rc != _OK {
   100  		t.Fatal("returned", rc)
   101  	}
   102  
   103  	rc = vfsCheckReservedLock(ctx, mod, pFile1, pOutput)
   104  	if rc != _OK {
   105  		t.Fatal("returned", rc)
   106  	}
   107  	if got := util.ReadUint32(mod, pOutput); got == 0 {
   108  		t.Log("file wasn't locked, locking is incompatible with SQLite")
   109  	}
   110  	rc = vfsCheckReservedLock(ctx, mod, pFile2, pOutput)
   111  	if rc != _OK {
   112  		t.Fatal("returned", rc)
   113  	}
   114  	if got := util.ReadUint32(mod, pOutput); got == 0 {
   115  		t.Error("file wasn't locked")
   116  	}
   117  	rc = vfsFileControl(ctx, mod, pFile2, _FCNTL_LOCKSTATE, pOutput)
   118  	if rc != _OK {
   119  		t.Fatal("returned", rc)
   120  	}
   121  	if got := util.ReadUint32(mod, pOutput); got != uint32(LOCK_RESERVED) {
   122  		t.Error("invalid lock state", got)
   123  	}
   124  
   125  	rc = vfsLock(ctx, mod, pFile2, LOCK_EXCLUSIVE)
   126  	if rc != _OK {
   127  		t.Fatal("returned", rc)
   128  	}
   129  
   130  	rc = vfsCheckReservedLock(ctx, mod, pFile1, pOutput)
   131  	if rc != _OK {
   132  		t.Fatal("returned", rc)
   133  	}
   134  	if got := util.ReadUint32(mod, pOutput); got == 0 {
   135  		t.Log("file wasn't locked, locking is incompatible with SQLite")
   136  	}
   137  	rc = vfsCheckReservedLock(ctx, mod, pFile2, pOutput)
   138  	if rc != _OK {
   139  		t.Fatal("returned", rc)
   140  	}
   141  	if got := util.ReadUint32(mod, pOutput); got == 0 {
   142  		t.Error("file wasn't locked")
   143  	}
   144  	rc = vfsFileControl(ctx, mod, pFile2, _FCNTL_LOCKSTATE, pOutput)
   145  	if rc != _OK {
   146  		t.Fatal("returned", rc)
   147  	}
   148  	if got := util.ReadUint32(mod, pOutput); got != uint32(LOCK_EXCLUSIVE) {
   149  		t.Error("invalid lock state", got)
   150  	}
   151  
   152  	rc = vfsLock(ctx, mod, pFile1, LOCK_SHARED)
   153  	if rc == _OK {
   154  		t.Fatal("returned", rc)
   155  	}
   156  
   157  	rc = vfsCheckReservedLock(ctx, mod, pFile1, pOutput)
   158  	if rc != _OK {
   159  		t.Fatal("returned", rc)
   160  	}
   161  	if got := util.ReadUint32(mod, pOutput); got == 0 {
   162  		t.Log("file wasn't locked, locking is incompatible with SQLite")
   163  	}
   164  	rc = vfsCheckReservedLock(ctx, mod, pFile2, pOutput)
   165  	if rc != _OK {
   166  		t.Fatal("returned", rc)
   167  	}
   168  	if got := util.ReadUint32(mod, pOutput); got == 0 {
   169  		t.Error("file wasn't locked")
   170  	}
   171  	rc = vfsFileControl(ctx, mod, pFile1, _FCNTL_LOCKSTATE, pOutput)
   172  	if rc != _OK {
   173  		t.Fatal("returned", rc)
   174  	}
   175  	if got := util.ReadUint32(mod, pOutput); got != uint32(LOCK_NONE) {
   176  		t.Error("invalid lock state", got)
   177  	}
   178  
   179  	rc = vfsUnlock(ctx, mod, pFile2, LOCK_SHARED)
   180  	if rc != _OK {
   181  		t.Fatal("returned", rc)
   182  	}
   183  
   184  	rc = vfsCheckReservedLock(ctx, mod, pFile1, pOutput)
   185  	if rc != _OK {
   186  		t.Fatal("returned", rc)
   187  	}
   188  	if got := util.ReadUint32(mod, pOutput); got != 0 {
   189  		t.Error("file was locked")
   190  	}
   191  	rc = vfsCheckReservedLock(ctx, mod, pFile2, pOutput)
   192  	if rc != _OK {
   193  		t.Fatal("returned", rc)
   194  	}
   195  	if got := util.ReadUint32(mod, pOutput); got != 0 {
   196  		t.Error("file was locked")
   197  	}
   198  
   199  	rc = vfsLock(ctx, mod, pFile1, LOCK_SHARED)
   200  	if rc != _OK {
   201  		t.Fatal("returned", rc)
   202  	}
   203  	rc = vfsFileControl(ctx, mod, pFile1, _FCNTL_LOCKSTATE, pOutput)
   204  	if rc != _OK {
   205  		t.Fatal("returned", rc)
   206  	}
   207  	if got := util.ReadUint32(mod, pOutput); got != uint32(LOCK_SHARED) {
   208  		t.Error("invalid lock state", got)
   209  	}
   210  }