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 }