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  }