github.com/ncruces/go-sqlite3@v0.15.1-0.20240520133447-53eef1510ff0/vfs/vfs_test.go (about) 1 package vfs 2 3 import ( 4 "bytes" 5 "context" 6 "errors" 7 "io/fs" 8 "math" 9 "os" 10 "os/user" 11 "path/filepath" 12 "syscall" 13 "testing" 14 "time" 15 16 "github.com/ncruces/go-sqlite3/internal/util" 17 "github.com/ncruces/julianday" 18 "github.com/tetratelabs/wazero/experimental/wazerotest" 19 ) 20 21 func Test_vfsLocaltime(t *testing.T) { 22 mod := wazerotest.NewModule(wazerotest.NewMemory(wazerotest.PageSize)) 23 ctx := context.TODO() 24 25 tm := time.Now() 26 rc := vfsLocaltime(ctx, mod, 4, tm.Unix()) 27 if rc != 0 { 28 t.Fatal("returned", rc) 29 } 30 31 if s := util.ReadUint32(mod, 4+0*4); int(s) != tm.Second() { 32 t.Error("wrong second") 33 } 34 if m := util.ReadUint32(mod, 4+1*4); int(m) != tm.Minute() { 35 t.Error("wrong minute") 36 } 37 if h := util.ReadUint32(mod, 4+2*4); int(h) != tm.Hour() { 38 t.Error("wrong hour") 39 } 40 if d := util.ReadUint32(mod, 4+3*4); int(d) != tm.Day() { 41 t.Error("wrong day") 42 } 43 if m := util.ReadUint32(mod, 4+4*4); time.Month(1+m) != tm.Month() { 44 t.Error("wrong month") 45 } 46 if y := util.ReadUint32(mod, 4+5*4); 1900+int(y) != tm.Year() { 47 t.Error("wrong year") 48 } 49 if w := util.ReadUint32(mod, 4+6*4); time.Weekday(w) != tm.Weekday() { 50 t.Error("wrong weekday") 51 } 52 if d := util.ReadUint32(mod, 4+7*4); int(d) != tm.YearDay()-1 { 53 t.Error("wrong yearday") 54 } 55 } 56 57 func Test_vfsRandomness(t *testing.T) { 58 mod := wazerotest.NewModule(wazerotest.NewMemory(wazerotest.PageSize)) 59 ctx := context.TODO() 60 61 rc := vfsRandomness(ctx, mod, 0, 16, 4) 62 if rc != 16 { 63 t.Fatal("returned", rc) 64 } 65 66 var zero [16]byte 67 if got := util.View(mod, 4, 16); bytes.Equal(got, zero[:]) { 68 t.Fatal("all zero") 69 } 70 } 71 72 func Test_vfsSleep(t *testing.T) { 73 mod := wazerotest.NewModule(wazerotest.NewMemory(wazerotest.PageSize)) 74 ctx := context.TODO() 75 76 now := time.Now() 77 rc := vfsSleep(ctx, mod, 0, 123456) 78 if rc != 0 { 79 t.Fatal("returned", rc) 80 } 81 82 want := 123456 * time.Microsecond 83 if got := time.Since(now); got < want { 84 t.Errorf("got %v, want %v", got, want) 85 } 86 } 87 88 func Test_vfsCurrentTime64(t *testing.T) { 89 mod := wazerotest.NewModule(wazerotest.NewMemory(wazerotest.PageSize)) 90 ctx := context.TODO() 91 92 now := time.Now() 93 time.Sleep(time.Millisecond) 94 rc := vfsCurrentTime64(ctx, mod, 0, 4) 95 if rc != 0 { 96 t.Fatal("returned", rc) 97 } 98 99 day, nsec := julianday.Date(now) 100 want := day*86_400_000 + nsec/1_000_000 101 if got := util.ReadUint64(mod, 4); float32(got) != float32(want) { 102 t.Errorf("got %v, want %v", got, want) 103 } 104 } 105 106 func Test_vfsFullPathname(t *testing.T) { 107 mod := wazerotest.NewModule(wazerotest.NewMemory(wazerotest.PageSize)) 108 util.WriteString(mod, 4, ".") 109 ctx := context.TODO() 110 111 rc := vfsFullPathname(ctx, mod, 0, 4, 0, 8) 112 if rc != _CANTOPEN_FULLPATH { 113 t.Errorf("returned %d, want %d", rc, _CANTOPEN_FULLPATH) 114 } 115 116 rc = vfsFullPathname(ctx, mod, 0, 4, _MAX_PATHNAME, 8) 117 if rc != _OK { 118 t.Fatal("returned", rc) 119 } 120 121 want, _ := filepath.Abs(".") 122 if got := util.ReadString(mod, 8, _MAX_PATHNAME); got != want { 123 t.Errorf("got %v, want %v", got, want) 124 } 125 } 126 127 func Test_vfsDelete(t *testing.T) { 128 name := filepath.Join(t.TempDir(), "test.db") 129 130 file, err := os.Create(name) 131 if err != nil { 132 t.Fatal(err) 133 } 134 file.Close() 135 136 mod := wazerotest.NewModule(wazerotest.NewMemory(wazerotest.PageSize)) 137 util.WriteString(mod, 4, name) 138 ctx := context.TODO() 139 140 rc := vfsDelete(ctx, mod, 0, 4, 1) 141 if rc != _OK { 142 t.Fatal("returned", rc) 143 } 144 145 if _, err := os.Stat(name); !errors.Is(err, fs.ErrNotExist) { 146 t.Fatal("did not delete the file") 147 } 148 149 rc = vfsDelete(ctx, mod, 0, 4, 1) 150 if rc != _IOERR_DELETE_NOENT { 151 t.Fatal("returned", rc) 152 } 153 } 154 155 func Test_vfsAccess(t *testing.T) { 156 dir := t.TempDir() 157 file := filepath.Join(dir, "test.db") 158 if f, err := os.Create(file); err != nil { 159 t.Fatal(err) 160 } else { 161 f.Close() 162 } 163 if err := os.Chmod(file, syscall.S_IRUSR); err != nil { 164 t.Fatal(err) 165 } 166 167 mod := wazerotest.NewModule(wazerotest.NewMemory(wazerotest.PageSize)) 168 util.WriteString(mod, 8, dir) 169 ctx := context.TODO() 170 171 rc := vfsAccess(ctx, mod, 0, 8, ACCESS_EXISTS, 4) 172 if rc != _OK { 173 t.Fatal("returned", rc) 174 } 175 if got := util.ReadUint32(mod, 4); got != 1 { 176 t.Error("directory did not exist") 177 } 178 179 rc = vfsAccess(ctx, mod, 0, 8, ACCESS_READWRITE, 4) 180 if rc != _OK { 181 t.Fatal("returned", rc) 182 } 183 if got := util.ReadUint32(mod, 4); got != 1 { 184 t.Error("can't access directory") 185 } 186 187 util.WriteString(mod, 8, file) 188 rc = vfsAccess(ctx, mod, 0, 8, ACCESS_READ, 4) 189 if rc != _OK { 190 t.Fatal("returned", rc) 191 } 192 if got := util.ReadUint32(mod, 4); got != 1 { 193 t.Error("can't access file") 194 } 195 196 if usr, err := user.Current(); err == nil && usr.Uid == "0" { 197 t.Skip("skipping as root") 198 } 199 200 util.WriteString(mod, 8, file) 201 rc = vfsAccess(ctx, mod, 0, 8, ACCESS_READWRITE, 4) 202 if rc != _OK { 203 t.Fatal("returned", rc) 204 } 205 if got := util.ReadUint32(mod, 4); got != 0 { 206 t.Error("can access file") 207 } 208 } 209 210 func Test_vfsFile(t *testing.T) { 211 mod := wazerotest.NewModule(wazerotest.NewMemory(wazerotest.PageSize)) 212 ctx := util.NewContext(context.TODO()) 213 214 // Open a temporary file. 215 rc := vfsOpen(ctx, mod, 0, 0, 4, OPEN_CREATE|OPEN_EXCLUSIVE|OPEN_READWRITE|OPEN_DELETEONCLOSE, 0, 0) 216 if rc != _OK { 217 t.Fatal("returned", rc) 218 } 219 220 // Check sector size. 221 if size := vfsSectorSize(ctx, mod, 4); size != _DEFAULT_SECTOR_SIZE { 222 t.Fatal("returned", size) 223 } 224 225 // Write stuff. 226 text := "Hello world!" 227 util.WriteString(mod, 16, text) 228 rc = vfsWrite(ctx, mod, 4, 16, int32(len(text)), 0) 229 if rc != _OK { 230 t.Fatal("returned", rc) 231 } 232 233 // Check file size. 234 rc = vfsFileSize(ctx, mod, 4, 16) 235 if rc != _OK { 236 t.Fatal("returned", rc) 237 } 238 if got := util.ReadUint32(mod, 16); got != uint32(len(text)) { 239 t.Errorf("got %d", got) 240 } 241 242 // Partial read at offset. 243 rc = vfsRead(ctx, mod, 4, 16, int32(len(text)), 4) 244 if rc != _IOERR_SHORT_READ { 245 t.Fatal("returned", rc) 246 } 247 if got := util.ReadString(mod, 16, 64); got != text[4:] { 248 t.Errorf("got %q", got) 249 } 250 251 // Truncate the file. 252 rc = vfsTruncate(ctx, mod, 4, 4) 253 if rc != _OK { 254 t.Fatal("returned", rc) 255 } 256 257 // Check file size. 258 rc = vfsFileSize(ctx, mod, 4, 16) 259 if rc != _OK { 260 t.Fatal("returned", rc) 261 } 262 if got := util.ReadUint32(mod, 16); got != 4 { 263 t.Errorf("got %d", got) 264 } 265 266 // Read at offset. 267 rc = vfsRead(ctx, mod, 4, 32, 4, 0) 268 if rc != _OK { 269 t.Fatal("returned", rc) 270 } 271 if got := util.ReadString(mod, 32, 64); got != text[:4] { 272 t.Errorf("got %q", got) 273 } 274 275 // Close the file. 276 rc = vfsClose(ctx, mod, 4) 277 if rc != _OK { 278 t.Fatal("returned", rc) 279 } 280 } 281 282 func Test_vfsFile_psow(t *testing.T) { 283 mod := wazerotest.NewModule(wazerotest.NewMemory(wazerotest.PageSize)) 284 ctx := util.NewContext(context.TODO()) 285 286 // Open a temporary file. 287 rc := vfsOpen(ctx, mod, 0, 0, 4, OPEN_CREATE|OPEN_EXCLUSIVE|OPEN_READWRITE|OPEN_DELETEONCLOSE, 0, 0) 288 if rc != _OK { 289 t.Fatal("returned", rc) 290 } 291 292 // Read powersafe overwrite. 293 util.WriteUint32(mod, 16, math.MaxUint32) 294 rc = vfsFileControl(ctx, mod, 4, _FCNTL_POWERSAFE_OVERWRITE, 16) 295 if rc != _OK { 296 t.Fatal("returned", rc) 297 } 298 if got := util.ReadUint32(mod, 16); got == 0 { 299 t.Error("psow disabled") 300 } 301 302 // Unset powersafe overwrite. 303 util.WriteUint32(mod, 16, 0) 304 rc = vfsFileControl(ctx, mod, 4, _FCNTL_POWERSAFE_OVERWRITE, 16) 305 if rc != _OK { 306 t.Fatal("returned", rc) 307 } 308 309 // Read powersafe overwrite. 310 util.WriteUint32(mod, 16, math.MaxUint32) 311 rc = vfsFileControl(ctx, mod, 4, _FCNTL_POWERSAFE_OVERWRITE, 16) 312 if rc != _OK { 313 t.Fatal("returned", rc) 314 } 315 if got := util.ReadUint32(mod, 16); got != 0 { 316 t.Error("psow enabled") 317 } 318 319 // Set powersafe overwrite. 320 util.WriteUint32(mod, 16, 1) 321 rc = vfsFileControl(ctx, mod, 4, _FCNTL_POWERSAFE_OVERWRITE, 16) 322 if rc != _OK { 323 t.Fatal("returned", rc) 324 } 325 326 // Read powersafe overwrite. 327 util.WriteUint32(mod, 16, math.MaxUint32) 328 rc = vfsFileControl(ctx, mod, 4, _FCNTL_POWERSAFE_OVERWRITE, 16) 329 if rc != _OK { 330 t.Fatal("returned", rc) 331 } 332 if got := util.ReadUint32(mod, 16); got == 0 { 333 t.Error("psow disabled") 334 } 335 336 // Close the file. 337 rc = vfsClose(ctx, mod, 4) 338 if rc != _OK { 339 t.Fatal("returned", rc) 340 } 341 }