func testTruncate(t *testing.T, toSize int64) { t.Parallel() f := &truncate{} mnt, err := fstestutil.MountedT(t, childMapFS{"child": f}) if err != nil { t.Fatal(err) } defer mnt.Close() err = os.Truncate(mnt.Dir+"/child", toSize) if err != nil { t.Fatalf("Truncate: %v", err) } gotr := f.RecordedSetattr() if gotr == (fuse.SetattrRequest{}) { t.Fatalf("no recorded SetattrRequest") } if g, e := gotr.Size, uint64(toSize); g != e { t.Errorf("got Size = %q; want %q", g, e) } if g, e := gotr.Valid&^fuse.SetattrLockOwner, fuse.SetattrSize; g != e { t.Errorf("got Valid = %q; want %q", g, e) } t.Logf("Got request: %#v", gotr) }
func TestMountOptionDefaultPermissions(t *testing.T) { if runtime.GOOS == "freebsd" { t.Skip("FreeBSD does not support DefaultPermissions") } t.Parallel() mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{ fstestutil.ChildMap{"child": unwritableFile{}}, }, fuse.DefaultPermissions(), ) if err != nil { t.Fatal(err) } defer mnt.Close() // This will be prevented by kernel-level access checking when // DefaultPermissions is used. f, err := os.OpenFile(mnt.Dir+"/child", os.O_WRONLY, 0000) if err == nil { f.Close() t.Fatal("expected an error") } if !os.IsPermission(err) { t.Fatalf("expected a permission error, got %T: %v", err, err) } }
func TestSetxattr(t *testing.T) { t.Parallel() f := &setxattr{} mnt, err := fstestutil.MountedT(t, childMapFS{"child": f}) if err != nil { t.Fatal(err) } defer mnt.Close() err = syscallx.Setxattr(mnt.Dir+"/child", "greeting", []byte("hello, world"), 0) if err != nil { t.Errorf("unexpected error: %v", err) return } // fuse.SetxattrRequest contains a byte slice and thus cannot be // directly compared got := f.RecordedSetxattr() if g, e := got.Name, "greeting"; g != e { t.Errorf("Setxattr incorrect name: %q != %q", g, e) } if g, e := got.Flags, uint32(0); g != e { t.Errorf("Setxattr incorrect flags: %d != %d", g, e) } if g, e := string(got.Xattr), "hello, world"; g != e { t.Errorf("Setxattr incorrect data: %q != %q", g, e) } }
func TestSymlink(t *testing.T) { t.Parallel() f := &symlink1{} mnt, err := fstestutil.MountedT(t, simpleFS{f}) if err != nil { t.Fatal(err) } defer mnt.Close() const target = "/some-target" err = os.Symlink(target, mnt.Dir+"/symlink.file") if err != nil { t.Fatalf("os.Symlink: %v", err) } want := fuse.SymlinkRequest{NewName: "symlink.file", Target: target} if g, e := f.RecordedSymlink(), want; g != e { t.Errorf("symlink saw %+v, want %+v", g, e) } gotName, err := os.Readlink(mnt.Dir + "/symlink.file") if err != nil { t.Fatalf("os.Readlink: %v", err) } if gotName != target { t.Errorf("os.Readlink = %q; want %q", gotName, target) } }
func TestListxattr(t *testing.T) { t.Parallel() f := &listxattr{} mnt, err := fstestutil.MountedT(t, childMapFS{"child": f}) if err != nil { t.Fatal(err) } defer mnt.Close() buf := make([]byte, 8192) n, err := syscallx.Listxattr(mnt.Dir+"/child", buf) if err != nil { t.Errorf("unexpected error: %v", err) return } buf = buf[:n] if g, e := string(buf), "one\x00two\x00"; g != e { t.Errorf("wrong listxattr content: %#v != %#v", g, e) } want := fuse.ListxattrRequest{ Size: 8192, } if g, e := f.RecordedListxattr(), want; g != e { t.Fatalf("listxattr saw %+v, want %+v", g, e) } }
func TestTruncateWithOpen(t *testing.T) { t.Parallel() f := &truncateWithOpen{} mnt, err := fstestutil.MountedT(t, childMapFS{"child": f}) if err != nil { t.Fatal(err) } defer mnt.Close() fil, err := os.OpenFile(mnt.Dir+"/child", os.O_WRONLY|os.O_TRUNC, 0666) if err != nil { t.Error(err) return } fil.Close() gotr := f.RecordedSetattr() if gotr == (fuse.SetattrRequest{}) { t.Fatalf("no recorded SetattrRequest") } if g, e := gotr.Size, uint64(0); g != e { t.Errorf("got Size = %q; want %q", g, e) } // osxfuse sets SetattrHandle here, linux does not if g, e := gotr.Valid&^(fuse.SetattrLockOwner|fuse.SetattrHandle), fuse.SetattrSize; g != e { t.Errorf("got Valid = %q; want %q", g, e) } t.Logf("Got request: %#v", gotr) }
func TestReadDir(t *testing.T) { t.Parallel() f := &readdir{} mnt, err := fstestutil.MountedT(t, simpleFS{f}) if err != nil { t.Fatal(err) } defer mnt.Close() fil, err := os.Open(mnt.Dir) if err != nil { t.Error(err) return } defer fil.Close() // go Readdir is just Readdirnames + Lstat, there's no point in // testing that here; we have no consumption API for the real // dirent data names, err := fil.Readdirnames(100) if err != nil { t.Error(err) return } t.Logf("Got readdir: %q", names) if len(names) != 3 || names[0] != "one" || names[1] != "three" || names[2] != "two" { t.Errorf(`expected 3 entries of "one", "three", "two", got: %q`, names) return } }
func TestMountOptionSubtype(t *testing.T) { if runtime.GOOS == "darwin" { t.Skip("OS X does not support Subtype") } if runtime.GOOS == "freebsd" { t.Skip("FreeBSD does not support Subtype") } t.Parallel() const name = "FuseTestMarker" mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.Dir{}}, fuse.Subtype(name), ) if err != nil { t.Fatal(err) } defer mnt.Close() info, err := fstestutil.GetMountInfo(mnt.Dir) if err != nil { t.Fatal(err) } if g, e := info.Type, "fuse."+name; g != e { t.Errorf("wrong Subtype: %q != %q", g, e) } }
func TestJunkType(t *testing.T) { tmp := tempdir.New(t) defer tmp.Cleanup() setup_fs := func() fs.FS { chunkStore := &mock.InMemory{} dir := setup_dir(t, chunkStore, []*wire.Dirent{ &wire.Dirent{ Name: "junk", }, }) filesys, err := newFS(chunkStore, dir.Type.Dir) if err != nil { t.Fatalf("cannot serve snapshot as FUSE: %v", err) } return filesys } filesys := setup_fs() mnt, err := fstestutil.MountedT(t, filesys) if err != nil { t.Fatalf("Mount fail: %v\n", err) } defer mnt.Close() junk_path := path.Join(mnt.Dir, "junk") _, err = os.Stat(junk_path) if err == nil { t.Fatalf("junk getattr must fail") } else if err.(*os.PathError).Err != syscall.EIO { t.Errorf("junk stat gave bad error: %v", err) } }
func TestStat(t *testing.T) { mnt, err := fstestutil.MountedT(t, &NzbFS{"testdb"}) if err != nil { t.Error(err) } defer mnt.Close() var stat syscall.Stat_t err = syscall.Lstat(path.Join(mnt.Dir, "hello"), &stat) if err != nil { t.Error(err) } if (stat.Mode & syscall.S_IFREG) == 0 { t.Error("hello file was not reported as a file") } err = syscall.Lstat(path.Join(mnt.Dir, "noexist"), &stat) if err == nil { t.Error("Should have failed on nonexistant file") } err = syscall.Lstat(path.Join(mnt.Dir, "foo"), &stat) if err != nil { t.Error(err) } if (stat.Mode & syscall.S_IFDIR) == 0 { t.Error("foo directory was not reported as a directory") } }
func BenchmarkCreate(b *testing.B) { f := &benchCreateDir{} mnt, err := fstestutil.MountedT(b, fstestutil.SimpleFS{f}, nil) if err != nil { b.Fatal(err) } defer mnt.Close() // prepare file names to decrease test overhead names := make([]string, 0, b.N) for i := 0; i < b.N; i++ { // zero-padded so cost stays the same on every iteration names = append(names, mnt.Dir+"/"+fmt.Sprintf("%08x", i)) } b.ResetTimer() for i := 0; i < b.N; i++ { f, err := os.Create(names[i]) if err != nil { b.Fatalf("WriteFile: %v", err) } f.Close() } b.StopTimer() }
func TestRead(t *testing.T) { mnt, err := fstestutil.MountedT(t, &NzbFS{"testdb"}) if err != nil { t.Error(err) } defer mnt.Close() file, err := os.Open(path.Join(mnt.Dir, "hello")) defer file.Close() if err != nil { t.Error(err) } buf := make([]byte, 10) n, err := file.Read(buf) if err != nil { t.Error(err) } if n != 6 { t.Error("Returned incorrect length:", n) } if string(buf[:n]) == "there" { t.Error("Got incorrect data after Read()") } }
func TestStatRoot(t *testing.T) { t.Parallel() mnt, err := fstestutil.MountedT(t, root{}) if err != nil { t.Fatal(err) } defer mnt.Close() fi, err := os.Stat(mnt.Dir) if err != nil { t.Fatalf("root getattr failed with %v", err) } mode := fi.Mode() if (mode & os.ModeType) != os.ModeDir { t.Errorf("root is not a directory: %#v", fi) } if mode.Perm() != 0555 { t.Errorf("root has weird access mode: %v", mode.Perm()) } switch stat := fi.Sys().(type) { case *syscall.Stat_t: if stat.Ino != 1 { t.Errorf("root has wrong inode: %v", stat.Ino) } if stat.Nlink != 1 { t.Errorf("root has wrong link count: %v", stat.Nlink) } if stat.Uid != 0 { t.Errorf("root has wrong uid: %d", stat.Uid) } if stat.Gid != 0 { t.Errorf("root has wrong gid: %d", stat.Gid) } } }
func TestMountOptionReadOnly(t *testing.T) { t.Parallel() mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{createrDir{}}, fuse.ReadOnly(), ) if err != nil { t.Fatal(err) } defer mnt.Close() // This will be prevented by kernel-level access checking when // ReadOnly is used. f, err := os.Create(mnt.Dir + "/child") if err == nil { f.Close() t.Fatal("expected an error") } perr, ok := err.(*os.PathError) if !ok { t.Fatalf("expected PathError, got %T: %v", err, err) } if perr.Err != syscall.EROFS { t.Fatalf("expected EROFS, got %T: %v", err, err) } }
func TestCreateWriteRemove(t *testing.T) { t.Parallel() f := &create3{} mnt, err := fstestutil.MountedT(t, simpleFS{f}) if err != nil { t.Fatal(err) } defer mnt.Close() err = ioutil.WriteFile(mnt.Dir+"/foo", []byte(hi), 0666) if err != nil { t.Fatalf("create3 WriteFile: %v", err) } if got := string(f.f.RecordedWriteData()); got != hi { t.Fatalf("create3 write = %q, want %q", got, hi) } err = os.Remove(mnt.Dir + "/foo") if err != nil { t.Fatalf("Remove: %v", err) } err = os.Remove(mnt.Dir + "/foo") if err == nil { t.Fatalf("second Remove = nil; want some error") } }
func TestMountOptionDaemonTimeout(t *testing.T) { if runtime.GOOS != "darwin" && runtime.GOOS != "freebsd" { return } if testing.Short() { t.Skip("skipping time-based test in short mode") } t.Parallel() mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{slowCreaterDir{}}, nil, fuse.DaemonTimeout("2"), ) // This should fail by the kernel timing out the request. f, err := os.Create(mnt.Dir + "/child") if err == nil { f.Close() t.Fatal("expected an error") } perr, ok := err.(*os.PathError) if !ok { t.Fatalf("expected PathError, got %T: %v", err, err) } if perr.Err == syscall.ENAMETOOLONG { t.Fatalf("expected other than ENAMETOOLONG, got %T: %v", err, err) } }
func TestMknod(t *testing.T) { t.Parallel() if os.Getuid() != 0 { t.Skip("skipping unless root") } f := &mknod1{} mnt, err := fstestutil.MountedT(t, simpleFS{f}) if err != nil { t.Fatal(err) } defer mnt.Close() defer syscall.Umask(syscall.Umask(0)) err = syscall.Mknod(mnt.Dir+"/node", syscall.S_IFIFO|0666, 123) if err != nil { t.Fatalf("Mknod: %v", err) } want := fuse.MknodRequest{ Name: "node", Mode: os.FileMode(os.ModeNamedPipe | 0666), Rdev: uint32(123), } if runtime.GOOS == "linux" { // Linux fuse doesn't echo back the rdev if the node // isn't a device (we're using a FIFO here, as that // bit is portable.) want.Rdev = 0 } if g, e := f.RecordedMknod(), want; g != e { t.Fatalf("mknod saw %+v, want %+v", g, e) } }
func TestCreate(t *testing.T) { t.Parallel() f := &create1{} mnt, err := fstestutil.MountedT(t, simpleFS{f}) if err != nil { t.Fatal(err) } defer mnt.Close() // uniform umask needed to make os.Create's 0666 into something // reproducible defer syscall.Umask(syscall.Umask(0022)) ff, err := os.Create(mnt.Dir + "/foo") if err != nil { t.Fatalf("create1 WriteFile: %v", err) } defer ff.Close() err = syscall.Fsync(int(ff.Fd())) if err != nil { t.Fatalf("Fsync = %v", err) } if f.f.RecordedFsync() == (fuse.FsyncRequest{}) { t.Errorf("never received expected fsync call") } ff.Close() }
func TestInterrupt(t *testing.T) { t.Parallel() f := &interrupt{} f.hanging = make(chan struct{}, 1) mnt, err := fstestutil.MountedT(t, childMapFS{"child": f}) if err != nil { t.Fatal(err) } defer mnt.Close() // start a subprocess that can hang until signaled cmd := exec.Command("cat", mnt.Dir+"/child") err = cmd.Start() if err != nil { t.Errorf("interrupt: cannot start cat: %v", err) return } // try to clean up if child is still alive when returning defer cmd.Process.Kill() // wait till we're sure it's hanging in read <-f.hanging err = cmd.Process.Signal(os.Interrupt) if err != nil { t.Errorf("interrupt: cannot interrupt cat: %v", err) return } p, err := cmd.Process.Wait() if err != nil { t.Errorf("interrupt: cat bork: %v", err) return } switch ws := p.Sys().(type) { case syscall.WaitStatus: if ws.CoreDump() { t.Errorf("interrupt: didn't expect cat to dump core: %v", ws) } if ws.Exited() { t.Errorf("interrupt: didn't expect cat to exit normally: %v", ws) } if !ws.Signaled() { t.Errorf("interrupt: expected cat to get a signal: %v", ws) } else { if ws.Signal() != os.Interrupt { t.Errorf("interrupt: cat got wrong signal: %v", ws) } } default: t.Logf("interrupt: this platform has no test coverage") } }
func TestReadAllWithHandleRead(t *testing.T) { t.Parallel() mnt, err := fstestutil.MountedT(t, childMapFS{"child": readWithHandleRead{}}) if err != nil { t.Fatal(err) } defer mnt.Close() testReadAll(t, mnt.Dir+"/child") }
func withMount(t testing.TB, db *bolt.DB, fn func(mntpath string)) { filesys := &FS{ db: db, } mnt, err := fstestutil.MountedT(t, filesys) if err != nil { t.Fatal(err) } defer mnt.Close() fn(mnt.Dir) }
func TestTwoLevels(t *testing.T) { tmp := tempdir.New(t) defer tmp.Cleanup() setup_fs := func() fs.FS { chunkStore := &mock.InMemory{} greeting := setup_greeting(t, chunkStore) dir1 := setup_dir(t, chunkStore, []*wire.Dirent{ &wire.Dirent{ Name: "hello", Type: wire.Type{ File: &wire.File{ Manifest: wirecas.FromBlob(greeting), }, }, // Space: uint64(len(GREETING)), // Written: TIME_1, }, }) dir1.Name = "second" dir2 := setup_dir(t, chunkStore, []*wire.Dirent{dir1}) filesys, err := newFS(chunkStore, dir2.Type.Dir) if err != nil { t.Fatalf("cannot serve snapshot as FUSE: %v", err) } return filesys } filesys := setup_fs() mnt, err := fstestutil.MountedT(t, filesys) if err != nil { t.Fatalf("Mount fail: %v\n", err) } defer mnt.Close() hello_path := path.Join(mnt.Dir, "second", "hello") f, err := os.Open(hello_path) if err != nil { t.Fatalf("hello open failed with %v", err) } buf, err := ioutil.ReadAll(f) if err != nil { t.Errorf("hello read failed with %v", err) } if string(buf) != GREETING { t.Errorf("hello read wrong content: %q", string(buf)) } err = f.Close() if err != nil { t.Fatalf("hello close failed with %v", err) } }
func TestMountOptionAllowRootThenAllowOther(t *testing.T) { t.Parallel() mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.Dir{}}, fuse.AllowRoot(), fuse.AllowOther(), ) if err == nil { mnt.Close() } if g, e := err, fuse.ErrCannotCombineAllowOtherAndAllowRoot; g != e { t.Fatalf("wrong error: %v != %v", g, e) } }
func TestOpen(t *testing.T) { t.Parallel() f := &open{} mnt, err := fstestutil.MountedT(t, childMapFS{"child": f}) if err != nil { t.Fatal(err) } defer mnt.Close() // node: mode only matters with O_CREATE fil, err := os.OpenFile(mnt.Dir+"/child", os.O_WRONLY|os.O_APPEND, 0) if err == nil { t.Error("Open err == nil, expected ENAMETOOLONG") fil.Close() return } switch err2 := err.(type) { case *os.PathError: if err2.Err == syscall.ENAMETOOLONG { break } t.Errorf("unexpected inner error: %#v", err2) default: t.Errorf("unexpected error: %v", err) } want := fuse.OpenRequest{Dir: false, Flags: fuse.OpenWriteOnly | fuse.OpenAppend} if runtime.GOOS == "darwin" { // osxfuse does not let O_APPEND through at all // // https://code.google.com/p/macfuse/issues/detail?id=233 // https://code.google.com/p/macfuse/issues/detail?id=132 // https://code.google.com/p/macfuse/issues/detail?id=133 want.Flags &^= fuse.OpenAppend } got := f.RecordedOpen() if runtime.GOOS == "linux" { // Linux <3.7 accidentally leaks O_CLOEXEC through to FUSE; // avoid spurious test failures got.Flags &^= fuse.OpenFlags(syscall.O_CLOEXEC) } if g, e := got, want; g != e { t.Errorf("open saw %v, want %v", g, e) return } }
func TestExchangeDataNotSupported(t *testing.T) { t.Parallel() mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{&fstestutil.ChildMap{ "one": &exchangeData{}, "two": &exchangeData{}, }}, nil) if err != nil { t.Fatal(err) } defer mnt.Close() if err := unix.Exchangedata(mnt.Dir+"/one", mnt.Dir+"/two", 0); err != unix.ENOTSUP { t.Fatalf("expected ENOTSUP from exchangedata: %v", err) } }
func TestMountOptionCommaError(t *testing.T) { t.Parallel() // this test is not tied to any specific option, it just needs // some string content var evil = "FuseTest,Marker" mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.Dir{}}, nil, fuse.ForTestSetMountOption("fusetest", evil), ) if err == nil { mnt.Close() t.Fatal("expected an error about commas") } if g, e := err.Error(), `mount options cannot contain commas on `+runtime.GOOS+`: "fusetest"="FuseTest,Marker"`; g != e { t.Fatalf("wrong error: %q != %q", g, e) } }
func TestListxattrSize(t *testing.T) { t.Parallel() f := &listxattrSize{} mnt, err := fstestutil.MountedT(t, childMapFS{"child": f}) if err != nil { t.Fatal(err) } defer mnt.Close() n, err := syscallx.Listxattr(mnt.Dir+"/child", nil) if err != nil { t.Errorf("Listxattr unexpected error: %v", err) return } if g, e := n, len("one\x00two\x00"); g != e { t.Errorf("Getxattr incorrect size: %d != %d", g, e) } }
func TestDataHandle(t *testing.T) { t.Parallel() f := &dataHandleTest{} mnt, err := fstestutil.MountedT(t, childMapFS{"child": f}) if err != nil { t.Fatal(err) } defer mnt.Close() data, err := ioutil.ReadFile(mnt.Dir + "/child") if err != nil { t.Errorf("readAll: %v", err) return } if string(data) != hi { t.Errorf("readAll = %q, want %q", data, hi) } }
func TestRelease(t *testing.T) { t.Parallel() r := &release{} mnt, err := fstestutil.MountedT(t, childMapFS{"child": r}) if err != nil { t.Fatal(err) } defer mnt.Close() f, err := os.Open(mnt.Dir + "/child") if err != nil { t.Fatal(err) } f.Close() if !r.WaitForRelease(1 * time.Second) { t.Error("Close did not Release in time") } }
func TestStatfs(t *testing.T) { t.Parallel() mnt, err := fstestutil.MountedT(t, testStatFS{}) if err != nil { t.Fatal(err) } defer mnt.Close() { var st syscall.Statfs_t err = syscall.Statfs(mnt.Dir, &st) if err != nil { t.Errorf("Statfs failed: %v", err) } t.Logf("Statfs got: %#v", st) if g, e := st.Blocks, uint64(42); g != e { t.Errorf("got Blocks = %d; want %d", g, e) } if g, e := st.Files, uint64(13); g != e { t.Errorf("got Files = %d; want %d", g, e) } } { var st syscall.Statfs_t f, err := os.Open(mnt.Dir) if err != nil { t.Errorf("Open for fstatfs failed: %v", err) } defer f.Close() err = syscall.Fstatfs(int(f.Fd()), &st) if err != nil { t.Errorf("Fstatfs failed: %v", err) } t.Logf("Fstatfs got: %#v", st) if g, e := st.Blocks, uint64(42); g != e { t.Errorf("got Blocks = %d; want %d", g, e) } if g, e := st.Files, uint64(13); g != e { t.Errorf("got Files = %d; want %d", g, e) } } }