From fd39cbc1932b1fe3be85c42613417cc35e11b6d1 Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Thu, 16 Apr 2020 13:33:46 +0100 Subject: [PATCH] vfstests: move functional tests from mountlib and make them work with VFS The tests are now run for the mount commands and for the plain VFS. This makes the tests much easier to debug when running with a VFS than through a mount. --- cmd/cmount/mount_test.go | 4 +- cmd/mount/mount_test.go | 4 +- cmd/mount2/mount_test.go | 4 +- .../mountlib/mounttest => vfs/vfstest}/dir.go | 25 ++-- .../mounttest => vfs/vfstest}/edge_cases.go | 5 +- .../mounttest => vfs/vfstest}/file.go | 23 ++-- {cmd/mountlib/mounttest => vfs/vfstest}/fs.go | 66 +++++++--- vfs/vfstest/os.go | 116 ++++++++++++++++++ .../mounttest => vfs/vfstest}/read.go | 11 +- .../vfstest}/read_non_unix.go | 2 +- .../mounttest => vfs/vfstest}/read_unix.go | 6 +- vfs/vfstest/vfs.go | 20 +++ .../mounttest => vfs/vfstest}/write.go | 5 +- .../vfstest}/write_non_unix.go | 2 +- .../mounttest => vfs/vfstest}/write_unix.go | 3 +- vfs/vfstest_test.go | 30 +++++ 16 files changed, 259 insertions(+), 67 deletions(-) rename {cmd/mountlib/mounttest => vfs/vfstest}/dir.go (89%) rename {cmd/mountlib/mounttest => vfs/vfstest}/edge_cases.go (95%) rename {cmd/mountlib/mounttest => vfs/vfstest}/file.go (69%) rename {cmd/mountlib/mounttest => vfs/vfstest}/fs.go (89%) create mode 100644 vfs/vfstest/os.go rename {cmd/mountlib/mounttest => vfs/vfstest}/read.go (93%) rename {cmd/mountlib/mounttest => vfs/vfstest}/read_non_unix.go (92%) rename {cmd/mountlib/mounttest => vfs/vfstest}/read_unix.go (92%) create mode 100644 vfs/vfstest/vfs.go rename {cmd/mountlib/mounttest => vfs/vfstest}/write.go (98%) rename {cmd/mountlib/mounttest => vfs/vfstest}/write_non_unix.go (97%) rename {cmd/mountlib/mounttest => vfs/vfstest}/write_unix.go (97%) create mode 100644 vfs/vfstest_test.go diff --git a/cmd/cmount/mount_test.go b/cmd/cmount/mount_test.go index 2bff49ee7..bb8b507b8 100644 --- a/cmd/cmount/mount_test.go +++ b/cmd/cmount/mount_test.go @@ -11,9 +11,9 @@ package cmount import ( "testing" - "github.com/rclone/rclone/cmd/mountlib/mounttest" + "github.com/rclone/rclone/vfs/vfstest" ) func TestMount(t *testing.T) { - mounttest.RunTests(t, mount) + vfstest.RunTests(t, false, mount) } diff --git a/cmd/mount/mount_test.go b/cmd/mount/mount_test.go index da9827c7d..14a56e5f1 100644 --- a/cmd/mount/mount_test.go +++ b/cmd/mount/mount_test.go @@ -6,12 +6,12 @@ import ( "runtime" "testing" - "github.com/rclone/rclone/cmd/mountlib/mounttest" + "github.com/rclone/rclone/vfs/vfstest" ) func TestMount(t *testing.T) { if runtime.NumCPU() <= 2 { t.Skip("FIXME skipping mount tests as they lock up on <= 2 CPUs - See: https://github.com/rclone/rclone/issues/3154") } - mounttest.RunTests(t, mount) + vfstest.RunTests(t, false, mount) } diff --git a/cmd/mount2/mount_test.go b/cmd/mount2/mount_test.go index 32bd83b7d..4cc2e91dc 100644 --- a/cmd/mount2/mount_test.go +++ b/cmd/mount2/mount_test.go @@ -5,9 +5,9 @@ package mount2 import ( "testing" - "github.com/rclone/rclone/cmd/mountlib/mounttest" + "github.com/rclone/rclone/vfs/vfstest" ) func TestMount(t *testing.T) { - mounttest.RunTests(t, mount) + vfstest.RunTests(t, false, mount) } diff --git a/cmd/mountlib/mounttest/dir.go b/vfs/vfstest/dir.go similarity index 89% rename from cmd/mountlib/mounttest/dir.go rename to vfs/vfstest/dir.go index 4645aa53d..d182cd24c 100644 --- a/cmd/mountlib/mounttest/dir.go +++ b/vfs/vfstest/dir.go @@ -1,8 +1,7 @@ -package mounttest +package vfstest import ( "context" - "os" "testing" "time" @@ -37,7 +36,7 @@ func TestDirCreateAndRemoveDir(t *testing.T) { run.checkDir(t, "dir/|dir/subdir/") // Check we can't delete a directory with stuff in - err := os.Remove(run.path("dir")) + err := run.os.Remove(run.path("dir")) assert.Error(t, err, "file exists") // Now delete subdir then dir - should produce no errors @@ -56,7 +55,7 @@ func TestDirCreateAndRemoveFile(t *testing.T) { run.checkDir(t, "dir/|dir/file 6") // Check we can't delete a directory with stuff in - err := os.Remove(run.path("dir")) + err := run.os.Remove(run.path("dir")) assert.Error(t, err, "file exists") // Now delete file @@ -75,14 +74,14 @@ func TestDirRenameFile(t *testing.T) { run.createFile(t, "file", "potato") run.checkDir(t, "dir/|file 6") - err := os.Rename(run.path("file"), run.path("file2")) + err := run.os.Rename(run.path("file"), run.path("file2")) require.NoError(t, err) run.checkDir(t, "dir/|file2 6") data := run.readFile(t, "file2") assert.Equal(t, "potato", data) - err = os.Rename(run.path("file2"), run.path("dir/file3")) + err = run.os.Rename(run.path("file2"), run.path("dir/file3")) require.NoError(t, err) run.checkDir(t, "dir/|dir/file3 6") @@ -103,11 +102,11 @@ func TestDirRenameEmptyDir(t *testing.T) { run.mkdir(t, "dir1") run.checkDir(t, "dir/|dir1/") - err := os.Rename(run.path("dir1"), run.path("dir/dir2")) + err := run.os.Rename(run.path("dir1"), run.path("dir/dir2")) require.NoError(t, err) run.checkDir(t, "dir/|dir/dir2/") - err = os.Rename(run.path("dir/dir2"), run.path("dir/dir3")) + err = run.os.Rename(run.path("dir/dir2"), run.path("dir/dir3")) require.NoError(t, err) run.checkDir(t, "dir/|dir/dir3/") @@ -125,11 +124,11 @@ func TestDirRenameFullDir(t *testing.T) { run.createFile(t, "dir1/potato.txt", "maris piper") run.checkDir(t, "dir/|dir1/|dir1/potato.txt 11") - err := os.Rename(run.path("dir1"), run.path("dir/dir2")) + err := run.os.Rename(run.path("dir1"), run.path("dir/dir2")) require.NoError(t, err) run.checkDir(t, "dir/|dir/dir2/|dir/dir2/potato.txt 11") - err = os.Rename(run.path("dir/dir2"), run.path("dir/dir3")) + err = run.os.Rename(run.path("dir/dir2"), run.path("dir/dir3")) require.NoError(t, err) run.checkDir(t, "dir/|dir/dir3/|dir/dir3/potato.txt 11") @@ -145,10 +144,10 @@ func TestDirModTime(t *testing.T) { run.mkdir(t, "dir") mtime := time.Date(2012, time.November, 18, 17, 32, 31, 0, time.UTC) - err := os.Chtimes(run.path("dir"), mtime, mtime) + err := run.os.Chtimes(run.path("dir"), mtime, mtime) require.NoError(t, err) - info, err := os.Stat(run.path("dir")) + info, err := run.os.Stat(run.path("dir")) require.NoError(t, err) // avoid errors because of timezone differences @@ -214,7 +213,7 @@ func TestDirCacheFlushOnDirRename(t *testing.T) { run.readLocal(t, localDm, "") assert.Equal(t, dm, localDm, "expected vs fuse mount") - err = os.Rename(run.path("dir"), run.path("rid")) + err = run.os.Rename(run.path("dir"), run.path("rid")) require.NoError(t, err) dm = newDirMap("rid/|rid/subdir/|rid/file 1") diff --git a/cmd/mountlib/mounttest/edge_cases.go b/vfs/vfstest/edge_cases.go similarity index 95% rename from cmd/mountlib/mounttest/edge_cases.go rename to vfs/vfstest/edge_cases.go index a206d9e5f..a54b8cc90 100644 --- a/cmd/mountlib/mounttest/edge_cases.go +++ b/vfs/vfstest/edge_cases.go @@ -1,7 +1,6 @@ -package mounttest +package vfstest import ( - "os" "runtime" "testing" @@ -43,7 +42,7 @@ func TestRenameOpenHandle(t *testing.T) { require.NoError(t, err) // attempt to rename open file - err = os.Rename(path, path+"bla") + err = run.os.Rename(path, path+"bla") require.NoError(t, err) // close open writers to allow rename on remote to go through diff --git a/cmd/mountlib/mounttest/file.go b/vfs/vfstest/file.go similarity index 69% rename from cmd/mountlib/mounttest/file.go rename to vfs/vfstest/file.go index 9fd55ce75..a4e490f0e 100644 --- a/cmd/mountlib/mounttest/file.go +++ b/vfs/vfstest/file.go @@ -1,4 +1,4 @@ -package mounttest +package vfstest import ( "os" @@ -6,6 +6,7 @@ import ( "testing" "time" + "github.com/rclone/rclone/vfs" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -17,10 +18,10 @@ func TestFileModTime(t *testing.T) { run.createFile(t, "file", "123") mtime := time.Date(2012, time.November, 18, 17, 32, 31, 0, time.UTC) - err := os.Chtimes(run.path("file"), mtime, mtime) + err := run.os.Chtimes(run.path("file"), mtime, mtime) require.NoError(t, err) - info, err := os.Stat(run.path("file")) + info, err := run.os.Stat(run.path("file")) require.NoError(t, err) // avoid errors because of timezone differences @@ -29,14 +30,14 @@ func TestFileModTime(t *testing.T) { run.rm(t, "file") } -// os.Create without opening for write too -func osCreate(name string) (*os.File, error) { - return os.OpenFile(name, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666) +// run.os.Create without opening for write too +func osCreate(name string) (vfs.OsFiler, error) { + return run.os.OpenFile(name, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666) } -// os.Create with append -func osAppend(name string) (*os.File, error) { - return os.OpenFile(name, os.O_WRONLY|os.O_APPEND, 0666) +// run.os.Create with append +func osAppend(name string) (vfs.OsFiler, error) { + return run.os.OpenFile(name, os.O_WRONLY|os.O_APPEND, 0666) } // TestFileModTimeWithOpenWriters tests mod time on open files @@ -55,7 +56,7 @@ func TestFileModTimeWithOpenWriters(t *testing.T) { _, err = f.Write([]byte{104, 105}) require.NoError(t, err) - err = os.Chtimes(filepath, mtime, mtime) + err = run.os.Chtimes(filepath, mtime, mtime) require.NoError(t, err) err = f.Close() @@ -63,7 +64,7 @@ func TestFileModTimeWithOpenWriters(t *testing.T) { run.waitForWriters() - info, err := os.Stat(filepath) + info, err := run.os.Stat(filepath) require.NoError(t, err) // avoid errors because of timezone differences diff --git a/cmd/mountlib/mounttest/fs.go b/vfs/vfstest/fs.go similarity index 89% rename from cmd/mountlib/mounttest/fs.go rename to vfs/vfstest/fs.go index 38d7fdc92..b4e397207 100644 --- a/cmd/mountlib/mounttest/fs.go +++ b/vfs/vfstest/fs.go @@ -1,6 +1,6 @@ // Test suite for rclonefs -package mounttest +package vfstest import ( "context" @@ -23,7 +23,6 @@ import ( "github.com/rclone/rclone/fs" "github.com/rclone/rclone/fs/walk" "github.com/rclone/rclone/fstest" - "github.com/rclone/rclone/lib/file" "github.com/rclone/rclone/vfs" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -33,7 +32,7 @@ type ( // UnmountFn is called to unmount the file system UnmountFn func() error // MountFn is called to mount the file system - MountFn func(f fs.Fs, mountpoint string) (*vfs.VFS, <-chan error, func() error, error) + MountFn func(f fs.Fs, mountpoint string) (vfs *vfs.VFS, unmountResult <-chan error, unmount func() error, err error) ) var ( @@ -41,7 +40,9 @@ var ( ) // RunTests runs all the tests against all the VFS cache modes -func RunTests(t *testing.T, fn MountFn) { +// +// If useVFS is set then it runs the tests against a VFS rather than amount +func RunTests(t *testing.T, useVFS bool, fn MountFn) { mountFn = fn flag.Parse() cacheModes := []vfs.CacheMode{ @@ -50,7 +51,7 @@ func RunTests(t *testing.T, fn MountFn) { vfs.CacheModeWrites, vfs.CacheModeFull, } - run = newRun() + run = newRun(useVFS) for _, cacheMode := range cacheModes { run.cacheMode(cacheMode) log.Printf("Starting test run with cache mode %v", cacheMode) @@ -92,7 +93,9 @@ func RunTests(t *testing.T, fn MountFn) { // Run holds the remotes for a test run type Run struct { + os Oser vfs *vfs.VFS + useVFS bool // set if we are testing a VFS not a mount mountPath string fremote fs.Fs fremoteName string @@ -111,11 +114,11 @@ var run *Run // r.fremote is an empty remote Fs // // Finalise() will tidy them away when done. -func newRun() *Run { +func newRun(useVFS bool) *Run { r := &Run{ + useVFS: useVFS, umountResult: make(chan error, 1), } - fstest.Initialise() var err error @@ -129,7 +132,9 @@ func newRun() *Run { log.Fatalf("Failed to open mkdir %q: %v", *fstest.RemoteName, err) } - r.mountPath = findMountPath() + if !r.useVFS { + r.mountPath = findMountPath() + } // Mount it up r.mount() @@ -169,6 +174,12 @@ func (r *Run) mount() { } else { log.Printf("mount OK") } + if r.useVFS { + r.os = vfsOs{r.vfs} + } else { + r.os = realOs{} + } + } func (r *Run) umount() { @@ -238,18 +249,31 @@ func (r *Run) skipIfNoFUSE(t *testing.T) { } } +func (r *Run) skipIfVFS(t *testing.T) { + if r.useVFS { + t.Skip("Not running under VFS") + } +} + // Finalise cleans the remote and unmounts func (r *Run) Finalise() { r.umount() r.cleanRemote() - err := os.RemoveAll(r.mountPath) - if err != nil { - log.Printf("Failed to clean mountPath %q: %v", r.mountPath, err) + if r.useVFS { + // FIXME + } else { + err := os.RemoveAll(r.mountPath) + if err != nil { + log.Printf("Failed to clean mountPath %q: %v", r.mountPath, err) + } } } // path returns an OS local path for filepath func (r *Run) path(filePath string) string { + if r.useVFS { + return filePath + } // return windows drive letter root as E:\ if filePath == "" && runtime.GOOS == "windows" { return run.mountPath + `\` @@ -284,7 +308,7 @@ func (dm dirMap) filesOnly() dirMap { // reads the local tree into dir func (r *Run) readLocal(t *testing.T, dir dirMap, filePath string) { realPath := r.path(filePath) - files, err := ioutil.ReadDir(realPath) + files, err := r.os.ReadDir(realPath) require.NoError(t, err) for _, fi := range files { name := path.Join(filePath, fi.Name()) @@ -353,13 +377,13 @@ func (r *Run) waitForWriters() { // If there is an error writing then writeFile // deletes it an existing file and tries again. func writeFile(filename string, data []byte, perm os.FileMode) error { - f, err := file.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm) + f, err := run.os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm) if err != nil { - err = os.Remove(filename) + err = run.os.Remove(filename) if err != nil { return err } - f, err = file.OpenFile(filename, os.O_WRONLY|os.O_CREATE, perm) + f, err = run.os.OpenFile(filename, os.O_WRONLY|os.O_CREATE, perm) if err != nil { return err } @@ -383,7 +407,7 @@ func (r *Run) createFile(t *testing.T, filepath string, contents string) { func (r *Run) readFile(t *testing.T, filepath string) string { filepath = r.path(filepath) - result, err := ioutil.ReadFile(filepath) + result, err := run.os.ReadFile(filepath) require.NoError(t, err) time.Sleep(100 * time.Millisecond) // FIXME wait for Release return string(result) @@ -391,18 +415,18 @@ func (r *Run) readFile(t *testing.T, filepath string) string { func (r *Run) mkdir(t *testing.T, filepath string) { filepath = r.path(filepath) - err := os.Mkdir(filepath, 0700) + err := run.os.Mkdir(filepath, 0700) require.NoError(t, err) } func (r *Run) rm(t *testing.T, filepath string) { filepath = r.path(filepath) - err := os.Remove(filepath) + err := run.os.Remove(filepath) require.NoError(t, err) // Wait for file to disappear from listing for i := 0; i < 100; i++ { - _, err := os.Stat(filepath) + _, err := run.os.Stat(filepath) if os.IsNotExist(err) { return } @@ -413,13 +437,14 @@ func (r *Run) rm(t *testing.T, filepath string) { func (r *Run) rmdir(t *testing.T, filepath string) { filepath = r.path(filepath) - err := os.Remove(filepath) + err := run.os.Remove(filepath) require.NoError(t, err) } // TestMount checks that the Fs is mounted by seeing if the mountpoint // is in the mount output func TestMount(t *testing.T) { + run.skipIfVFS(t) run.skipIfNoFUSE(t) if runtime.GOOS == "windows" { t.Skip("not running on windows") @@ -432,6 +457,7 @@ func TestMount(t *testing.T) { // TestRoot checks root directory is present and correct func TestRoot(t *testing.T) { + run.skipIfVFS(t) run.skipIfNoFUSE(t) fi, err := os.Lstat(run.mountPath) diff --git a/vfs/vfstest/os.go b/vfs/vfstest/os.go new file mode 100644 index 000000000..a27f3ead2 --- /dev/null +++ b/vfs/vfstest/os.go @@ -0,0 +1,116 @@ +package vfstest + +import ( + "io/ioutil" + "os" + "time" + + "github.com/rclone/rclone/lib/file" + "github.com/rclone/rclone/vfs" +) + +// Oser defines the things that the "os" package can do +// +// This covers what the VFS can do also +type Oser interface { + Chtimes(name string, atime time.Time, mtime time.Time) error + Create(name string) (vfs.Handle, error) + Mkdir(name string, perm os.FileMode) error + Open(name string) (vfs.Handle, error) + OpenFile(name string, flags int, perm os.FileMode) (fd vfs.Handle, err error) + ReadDir(dirname string) ([]os.FileInfo, error) + ReadFile(filename string) (b []byte, err error) + Remove(name string) error + Rename(oldName, newName string) error + Stat(path string) (os.FileInfo, error) +} + +// realOs is an implementation of Oser backed by the "os" package +type realOs struct { +} + +// realOsFile is an implementation of vfs.Handle +type realOsFile struct { + *os.File +} + +// Flush +func (f realOsFile) Flush() error { + return nil +} + +// Release +func (f realOsFile) Release() error { + return f.File.Close() +} + +// Node +func (f realOsFile) Node() vfs.Node { + return nil +} + +// Chtimes +func (r realOs) Chtimes(name string, atime time.Time, mtime time.Time) error { + return os.Chtimes(name, atime, mtime) +} + +// Create +func (r realOs) Create(name string) (vfs.Handle, error) { + fd, err := file.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666) + if err != nil { + return nil, err + } + return realOsFile{File: fd}, err +} + +// Mkdir +func (r realOs) Mkdir(name string, perm os.FileMode) error { + return os.Mkdir(name, perm) +} + +// Open +func (r realOs) Open(name string) (vfs.Handle, error) { + fd, err := os.Open(name) + if err != nil { + return nil, err + } + return realOsFile{File: fd}, err +} + +// OpenFile +func (r realOs) OpenFile(name string, flags int, perm os.FileMode) (vfs.Handle, error) { + fd, err := file.OpenFile(name, flags, perm) + if err != nil { + return nil, err + } + return realOsFile{File: fd}, err +} + +// ReadDir +func (r realOs) ReadDir(dirname string) ([]os.FileInfo, error) { + return ioutil.ReadDir(dirname) +} + +// ReadFile +func (r realOs) ReadFile(filename string) (b []byte, err error) { + return ioutil.ReadFile(filename) +} + +// Remove +func (r realOs) Remove(name string) error { + return os.Remove(name) +} + +// Rename +func (r realOs) Rename(oldName, newName string) error { + return os.Rename(oldName, newName) +} + +// Stat +func (r realOs) Stat(path string) (os.FileInfo, error) { + return os.Stat(path) +} + +// Check interfaces +var _ Oser = &realOs{} +var _ vfs.Handle = &realOsFile{} diff --git a/cmd/mountlib/mounttest/read.go b/vfs/vfstest/read.go similarity index 93% rename from cmd/mountlib/mounttest/read.go rename to vfs/vfstest/read.go index d68616c80..cfa905f72 100644 --- a/cmd/mountlib/mounttest/read.go +++ b/vfs/vfstest/read.go @@ -1,9 +1,8 @@ -package mounttest +package vfstest import ( "io" "io/ioutil" - "os" "testing" "time" @@ -19,7 +18,7 @@ func TestReadByByte(t *testing.T) { run.checkDir(t, "testfile 10") for i := 0; i < len(data); i++ { - fd, err := os.Open(run.path("testfile")) + fd, err := run.os.Open(run.path("testfile")) assert.NoError(t, err) for j := 0; j < i; j++ { buf := make([]byte, 1) @@ -50,7 +49,7 @@ func TestReadChecksum(t *testing.T) { // The hash comparison would fail in Flush, if we did not // ensure we read the whole file - fd, err := os.Open(run.path("bigfile")) + fd, err := run.os.Open(run.path("bigfile")) assert.NoError(t, err) buf := make([]byte, 10) _, err = io.ReadFull(fd, buf) @@ -60,7 +59,7 @@ func TestReadChecksum(t *testing.T) { // The hash comparison would fail, because we only read parts // of the file - fd, err = os.Open(run.path("bigfile")) + fd, err = run.os.Open(run.path("bigfile")) assert.NoError(t, err) // read at start _, err = io.ReadFull(fd, buf) @@ -85,7 +84,7 @@ func TestReadSeek(t *testing.T) { run.createFile(t, "testfile", string(data)) run.checkDir(t, "testfile 10") - fd, err := os.Open(run.path("testfile")) + fd, err := run.os.Open(run.path("testfile")) assert.NoError(t, err) // Seek to half way diff --git a/cmd/mountlib/mounttest/read_non_unix.go b/vfs/vfstest/read_non_unix.go similarity index 92% rename from cmd/mountlib/mounttest/read_non_unix.go rename to vfs/vfstest/read_non_unix.go index 6545a8fec..a874d4017 100644 --- a/cmd/mountlib/mounttest/read_non_unix.go +++ b/vfs/vfstest/read_non_unix.go @@ -1,6 +1,6 @@ // +build !linux,!darwin,!freebsd -package mounttest +package vfstest import ( "runtime" diff --git a/cmd/mountlib/mounttest/read_unix.go b/vfs/vfstest/read_unix.go similarity index 92% rename from cmd/mountlib/mounttest/read_unix.go rename to vfs/vfstest/read_unix.go index a1c47c7f5..c56f47ac3 100644 --- a/cmd/mountlib/mounttest/read_unix.go +++ b/vfs/vfstest/read_unix.go @@ -1,9 +1,8 @@ // +build linux darwin freebsd -package mounttest +package vfstest import ( - "os" "syscall" "testing" @@ -12,11 +11,12 @@ import ( // TestReadFileDoubleClose tests double close on read func TestReadFileDoubleClose(t *testing.T) { + run.skipIfVFS(t) run.skipIfNoFUSE(t) run.createFile(t, "testdoubleclose", "hello") - in, err := os.Open(run.path("testdoubleclose")) + in, err := run.os.Open(run.path("testdoubleclose")) assert.NoError(t, err) fd := in.Fd() diff --git a/vfs/vfstest/vfs.go b/vfs/vfstest/vfs.go new file mode 100644 index 000000000..382fb8844 --- /dev/null +++ b/vfs/vfstest/vfs.go @@ -0,0 +1,20 @@ +package vfstest + +import ( + "os" + + "github.com/rclone/rclone/vfs" +) + +// vfsOs is an implementation of Oser backed by the "vfs" package +type vfsOs struct { + *vfs.VFS +} + +// Stat +func (v vfsOs) Stat(path string) (os.FileInfo, error) { + return v.VFS.Stat(path) +} + +// Check interfaces +var _ Oser = vfsOs{} diff --git a/cmd/mountlib/mounttest/write.go b/vfs/vfstest/write.go similarity index 98% rename from cmd/mountlib/mounttest/write.go rename to vfs/vfstest/write.go index 2173eb90b..2ec68b311 100644 --- a/cmd/mountlib/mounttest/write.go +++ b/vfs/vfstest/write.go @@ -1,4 +1,4 @@ -package mounttest +package vfstest import ( "os" @@ -89,6 +89,7 @@ func TestWriteFileFsync(t *testing.T) { // TestWriteFileDup tests behavior of mmap() in Python by using dup() on a file handle func TestWriteFileDup(t *testing.T) { + run.skipIfVFS(t) run.skipIfNoFUSE(t) if run.vfs.Opt.CacheMode < vfs.CacheModeWrites { @@ -169,7 +170,7 @@ func TestWriteFileAppend(t *testing.T) { err = fh.Close() require.NoError(t, err) - info, err := os.Stat(filepath) + info, err := run.os.Stat(filepath) require.NoError(t, err) require.EqualValues(t, len(testData)+len(appendData), info.Size()) diff --git a/cmd/mountlib/mounttest/write_non_unix.go b/vfs/vfstest/write_non_unix.go similarity index 97% rename from cmd/mountlib/mounttest/write_non_unix.go rename to vfs/vfstest/write_non_unix.go index 17e865e4d..dc07983a4 100644 --- a/cmd/mountlib/mounttest/write_non_unix.go +++ b/vfs/vfstest/write_non_unix.go @@ -1,6 +1,6 @@ // +build !linux,!darwin,!freebsd -package mounttest +package vfstest import ( "runtime" diff --git a/cmd/mountlib/mounttest/write_unix.go b/vfs/vfstest/write_unix.go similarity index 97% rename from cmd/mountlib/mounttest/write_unix.go rename to vfs/vfstest/write_unix.go index 4eecc7a58..822590ba9 100644 --- a/cmd/mountlib/mounttest/write_unix.go +++ b/vfs/vfstest/write_unix.go @@ -1,6 +1,6 @@ // +build linux darwin freebsd -package mounttest +package vfstest import ( "runtime" @@ -14,6 +14,7 @@ import ( // TestWriteFileDoubleClose tests double close on write func TestWriteFileDoubleClose(t *testing.T) { + run.skipIfVFS(t) run.skipIfNoFUSE(t) if runtime.GOOS == "darwin" { t.Skip("Skipping test on OSX") diff --git a/vfs/vfstest_test.go b/vfs/vfstest_test.go new file mode 100644 index 000000000..35612c92e --- /dev/null +++ b/vfs/vfstest_test.go @@ -0,0 +1,30 @@ +// Run the more functional vfstest package on the vfs + +package vfs_test + +import ( + "testing" + + _ "github.com/rclone/rclone/backend/all" // import all the backends + "github.com/rclone/rclone/fs" + "github.com/rclone/rclone/fstest" + "github.com/rclone/rclone/vfs" + "github.com/rclone/rclone/vfs/vfstest" +) + +// TestExt runs more functional tests all the tests against all the +// VFS cache modes +func TestFunctional(t *testing.T) { + if *fstest.RemoteName != "" { + t.Skip("Skip on non local") + } + vfstest.RunTests(t, true, func(f fs.Fs, mountpoint string) (VFS *vfs.VFS, unmountResult <-chan error, unmount func() error, err error) { + unmountResultChan := make(chan (error), 1) + unmount = func() error { + unmountResultChan <- nil + return nil + } + VFS = vfs.New(f, nil) + return VFS, unmountResultChan, unmount, nil + }) +}