123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492 |
- // Test suite for vfs
- package vfs
- import (
- "context"
- "errors"
- "fmt"
- "io"
- "os"
- "testing"
- "time"
- _ "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/vfscommon"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
- )
- // Some times used in the tests
- var (
- t1 = fstest.Time("2001-02-03T04:05:06.499999999Z")
- t2 = fstest.Time("2011-12-25T12:59:59.123456789Z")
- t3 = fstest.Time("2011-12-30T12:59:59.000000000Z")
- )
- // Constants uses in the tests
- const (
- writeBackDelay = 100 * time.Millisecond // A short writeback delay for testing
- waitForWritersDelay = 30 * time.Second // time to wait for existing writers
- )
- // TestMain drives the tests
- func TestMain(m *testing.M) {
- fstest.TestMain(m)
- }
- // Clean up a test VFS
- func cleanupVFS(t *testing.T, vfs *VFS) {
- vfs.WaitForWriters(waitForWritersDelay)
- err := vfs.CleanUp()
- require.NoError(t, err)
- vfs.Shutdown()
- }
- // Create a new VFS
- func newTestVFSOpt(t *testing.T, opt *vfscommon.Options) (r *fstest.Run, vfs *VFS) {
- r = fstest.NewRun(t)
- vfs = New(r.Fremote, opt)
- t.Cleanup(func() {
- cleanupVFS(t, vfs)
- })
- return r, vfs
- }
- // Create a new VFS with default options
- func newTestVFS(t *testing.T) (r *fstest.Run, vfs *VFS) {
- return newTestVFSOpt(t, nil)
- }
- // Check baseHandle performs as advertised
- func TestVFSbaseHandle(t *testing.T) {
- fh := baseHandle{}
- err := fh.Chdir()
- assert.Equal(t, ENOSYS, err)
- err = fh.Chmod(0)
- assert.Equal(t, ENOSYS, err)
- err = fh.Chown(0, 0)
- assert.Equal(t, ENOSYS, err)
- err = fh.Close()
- assert.Equal(t, ENOSYS, err)
- fd := fh.Fd()
- assert.Equal(t, uintptr(0), fd)
- name := fh.Name()
- assert.Equal(t, "", name)
- _, err = fh.Read(nil)
- assert.Equal(t, ENOSYS, err)
- _, err = fh.ReadAt(nil, 0)
- assert.Equal(t, ENOSYS, err)
- _, err = fh.Readdir(0)
- assert.Equal(t, ENOSYS, err)
- _, err = fh.Readdirnames(0)
- assert.Equal(t, ENOSYS, err)
- _, err = fh.Seek(0, io.SeekStart)
- assert.Equal(t, ENOSYS, err)
- _, err = fh.Stat()
- assert.Equal(t, ENOSYS, err)
- err = fh.Sync()
- assert.Equal(t, nil, err)
- err = fh.Truncate(0)
- assert.Equal(t, ENOSYS, err)
- _, err = fh.Write(nil)
- assert.Equal(t, ENOSYS, err)
- _, err = fh.WriteAt(nil, 0)
- assert.Equal(t, ENOSYS, err)
- _, err = fh.WriteString("")
- assert.Equal(t, ENOSYS, err)
- err = fh.Flush()
- assert.Equal(t, ENOSYS, err)
- err = fh.Release()
- assert.Equal(t, ENOSYS, err)
- node := fh.Node()
- assert.Nil(t, node)
- }
- // TestNew sees if the New command works properly
- func TestVFSNew(t *testing.T) {
- // Check active cache has this many entries
- checkActiveCacheEntries := func(i int) {
- _, count := activeCacheEntries()
- assert.Equal(t, i, count)
- }
- checkActiveCacheEntries(0)
- r, vfs := newTestVFS(t)
- // Check making a VFS with nil options
- var defaultOpt = vfscommon.DefaultOpt
- defaultOpt.DirPerms |= os.ModeDir
- assert.Equal(t, vfs.Opt, defaultOpt)
- assert.Equal(t, vfs.f, r.Fremote)
- checkActiveCacheEntries(1)
- // Check that we get the same VFS if we ask for it again with
- // the same options
- vfs2 := New(r.Fremote, nil)
- assert.Equal(t, fmt.Sprintf("%p", vfs), fmt.Sprintf("%p", vfs2))
- checkActiveCacheEntries(1)
- // Shut the new VFS down and check the cache still has stuff in
- vfs2.Shutdown()
- checkActiveCacheEntries(1)
- cleanupVFS(t, vfs)
- checkActiveCacheEntries(0)
- }
- // TestNew sees if the New command works properly
- func TestVFSNewWithOpts(t *testing.T) {
- var opt = vfscommon.DefaultOpt
- opt.DirPerms = 0777
- opt.FilePerms = 0666
- opt.Umask = 0002
- _, vfs := newTestVFSOpt(t, &opt)
- assert.Equal(t, os.FileMode(0775)|os.ModeDir, vfs.Opt.DirPerms)
- assert.Equal(t, os.FileMode(0664), vfs.Opt.FilePerms)
- }
- // TestRoot checks root directory is present and correct
- func TestVFSRoot(t *testing.T) {
- _, vfs := newTestVFS(t)
- root, err := vfs.Root()
- require.NoError(t, err)
- assert.Equal(t, vfs.root, root)
- assert.True(t, root.IsDir())
- assert.Equal(t, vfs.Opt.DirPerms.Perm(), root.Mode().Perm())
- }
- func TestVFSStat(t *testing.T) {
- r, vfs := newTestVFS(t)
- file1 := r.WriteObject(context.Background(), "file1", "file1 contents", t1)
- file2 := r.WriteObject(context.Background(), "dir/file2", "file2 contents", t2)
- r.CheckRemoteItems(t, file1, file2)
- node, err := vfs.Stat("file1")
- require.NoError(t, err)
- assert.True(t, node.IsFile())
- assert.Equal(t, "file1", node.Name())
- node, err = vfs.Stat("dir")
- require.NoError(t, err)
- assert.True(t, node.IsDir())
- assert.Equal(t, "dir", node.Name())
- node, err = vfs.Stat("dir/file2")
- require.NoError(t, err)
- assert.True(t, node.IsFile())
- assert.Equal(t, "file2", node.Name())
- _, err = vfs.Stat("not found")
- assert.Equal(t, os.ErrNotExist, err)
- _, err = vfs.Stat("dir/not found")
- assert.Equal(t, os.ErrNotExist, err)
- _, err = vfs.Stat("not found/not found")
- assert.Equal(t, os.ErrNotExist, err)
- _, err = vfs.Stat("file1/under a file")
- assert.Equal(t, os.ErrNotExist, err)
- }
- func TestVFSStatParent(t *testing.T) {
- r, vfs := newTestVFS(t)
- file1 := r.WriteObject(context.Background(), "file1", "file1 contents", t1)
- file2 := r.WriteObject(context.Background(), "dir/file2", "file2 contents", t2)
- r.CheckRemoteItems(t, file1, file2)
- node, leaf, err := vfs.StatParent("file1")
- require.NoError(t, err)
- assert.True(t, node.IsDir())
- assert.Equal(t, "/", node.Name())
- assert.Equal(t, "file1", leaf)
- node, leaf, err = vfs.StatParent("dir/file2")
- require.NoError(t, err)
- assert.True(t, node.IsDir())
- assert.Equal(t, "dir", node.Name())
- assert.Equal(t, "file2", leaf)
- node, leaf, err = vfs.StatParent("not found")
- require.NoError(t, err)
- assert.True(t, node.IsDir())
- assert.Equal(t, "/", node.Name())
- assert.Equal(t, "not found", leaf)
- _, _, err = vfs.StatParent("not found dir/not found")
- assert.Equal(t, os.ErrNotExist, err)
- _, _, err = vfs.StatParent("file1/under a file")
- assert.Equal(t, os.ErrExist, err)
- }
- func TestVFSOpenFile(t *testing.T) {
- r, vfs := newTestVFS(t)
- file1 := r.WriteObject(context.Background(), "file1", "file1 contents", t1)
- file2 := r.WriteObject(context.Background(), "dir/file2", "file2 contents", t2)
- r.CheckRemoteItems(t, file1, file2)
- fd, err := vfs.OpenFile("file1", os.O_RDONLY, 0777)
- require.NoError(t, err)
- assert.NotNil(t, fd)
- require.NoError(t, fd.Close())
- fd, err = vfs.OpenFile("dir", os.O_RDONLY, 0777)
- require.NoError(t, err)
- assert.NotNil(t, fd)
- require.NoError(t, fd.Close())
- fd, err = vfs.OpenFile("dir/new_file.txt", os.O_RDONLY, 0777)
- assert.Equal(t, os.ErrNotExist, err)
- assert.Nil(t, fd)
- fd, err = vfs.OpenFile("dir/new_file.txt", os.O_WRONLY|os.O_CREATE, 0777)
- require.NoError(t, err)
- assert.NotNil(t, fd)
- err = fd.Close()
- if !errors.Is(err, fs.ErrorCantUploadEmptyFiles) {
- require.NoError(t, err)
- }
- fd, err = vfs.OpenFile("not found/new_file.txt", os.O_WRONLY|os.O_CREATE, 0777)
- assert.Equal(t, os.ErrNotExist, err)
- assert.Nil(t, fd)
- }
- func TestVFSRename(t *testing.T) {
- r, vfs := newTestVFS(t)
- features := r.Fremote.Features()
- if features.Move == nil && features.Copy == nil {
- t.Skip("skip as can't rename files")
- }
- file1 := r.WriteObject(context.Background(), "dir/file2", "file2 contents", t2)
- r.CheckRemoteItems(t, file1)
- err := vfs.Rename("dir/file2", "dir/file1")
- require.NoError(t, err)
- file1.Path = "dir/file1"
- r.CheckRemoteItems(t, file1)
- err = vfs.Rename("dir/file1", "file0")
- require.NoError(t, err)
- file1.Path = "file0"
- r.CheckRemoteItems(t, file1)
- err = vfs.Rename("not found/file0", "file0")
- assert.Equal(t, os.ErrNotExist, err)
- err = vfs.Rename("file0", "not found/file0")
- assert.Equal(t, os.ErrNotExist, err)
- }
- func TestVFSStatfs(t *testing.T) {
- r, vfs := newTestVFS(t)
- // pre-conditions
- assert.Nil(t, vfs.usage)
- assert.True(t, vfs.usageTime.IsZero())
- aboutSupported := r.Fremote.Features().About != nil
- // read
- total, used, free := vfs.Statfs()
- if !aboutSupported {
- assert.Equal(t, int64(unknownFreeBytes), total)
- assert.Equal(t, int64(unknownFreeBytes), free)
- assert.Equal(t, int64(0), used)
- return // can't test anything else if About not supported
- }
- require.NotNil(t, vfs.usage)
- assert.False(t, vfs.usageTime.IsZero())
- if vfs.usage.Total != nil {
- assert.Equal(t, *vfs.usage.Total, total)
- } else {
- assert.True(t, total >= int64(unknownFreeBytes))
- }
- if vfs.usage.Free != nil {
- assert.Equal(t, *vfs.usage.Free, free)
- } else {
- if vfs.usage.Total != nil && vfs.usage.Used != nil {
- assert.Equal(t, free, total-used)
- } else {
- assert.True(t, free >= int64(unknownFreeBytes))
- }
- }
- if vfs.usage.Used != nil {
- assert.Equal(t, *vfs.usage.Used, used)
- } else {
- assert.Equal(t, int64(0), used)
- }
- // read cached
- oldUsage := vfs.usage
- oldTime := vfs.usageTime
- total2, used2, free2 := vfs.Statfs()
- assert.Equal(t, oldUsage, vfs.usage)
- assert.Equal(t, total, total2)
- assert.Equal(t, used, used2)
- assert.Equal(t, free, free2)
- assert.Equal(t, oldTime, vfs.usageTime)
- }
- func TestVFSMkdir(t *testing.T) {
- r, vfs := newTestVFS(t)
- if !r.Fremote.Features().CanHaveEmptyDirectories {
- return // can't test if can't have empty directories
- }
- r.CheckRemoteListing(t, nil, []string{})
- // Try making the root
- err := vfs.Mkdir("", 0777)
- require.NoError(t, err)
- r.CheckRemoteListing(t, nil, []string{})
- // Try making a sub directory
- err = vfs.Mkdir("a", 0777)
- require.NoError(t, err)
- r.CheckRemoteListing(t, nil, []string{"a"})
- // Try making an existing directory
- err = vfs.Mkdir("a", 0777)
- require.NoError(t, err)
- r.CheckRemoteListing(t, nil, []string{"a"})
- // Try making a new directory
- err = vfs.Mkdir("b/", 0777)
- require.NoError(t, err)
- r.CheckRemoteListing(t, nil, []string{"a", "b"})
- // Try making a new directory
- err = vfs.Mkdir("/c", 0777)
- require.NoError(t, err)
- r.CheckRemoteListing(t, nil, []string{"a", "b", "c"})
- // Try making a new directory
- err = vfs.Mkdir("/d/", 0777)
- require.NoError(t, err)
- r.CheckRemoteListing(t, nil, []string{"a", "b", "c", "d"})
- }
- func TestVFSMkdirAll(t *testing.T) {
- r, vfs := newTestVFS(t)
- if !r.Fremote.Features().CanHaveEmptyDirectories {
- return // can't test if can't have empty directories
- }
- r.CheckRemoteListing(t, nil, []string{})
- // Try making the root
- err := vfs.MkdirAll("", 0777)
- require.NoError(t, err)
- r.CheckRemoteListing(t, nil, []string{})
- // Try making a sub directory
- err = vfs.MkdirAll("a/b/c/d", 0777)
- require.NoError(t, err)
- r.CheckRemoteListing(t, nil, []string{"a", "a/b", "a/b/c", "a/b/c/d"})
- // Try making an existing directory
- err = vfs.MkdirAll("a/b/c", 0777)
- require.NoError(t, err)
- r.CheckRemoteListing(t, nil, []string{"a", "a/b", "a/b/c", "a/b/c/d"})
- // Try making an existing directory
- err = vfs.MkdirAll("/a/b/c/", 0777)
- require.NoError(t, err)
- r.CheckRemoteListing(t, nil, []string{"a", "a/b", "a/b/c", "a/b/c/d"})
- }
- func TestFillInMissingSizes(t *testing.T) {
- const unknownFree = 10
- for _, test := range []struct {
- total, free, used int64
- wantTotal, wantUsed, wantFree int64
- }{
- {
- total: 20, free: 5, used: 15,
- wantTotal: 20, wantFree: 5, wantUsed: 15,
- },
- {
- total: 20, free: 5, used: -1,
- wantTotal: 20, wantFree: 5, wantUsed: 15,
- },
- {
- total: 20, free: -1, used: 15,
- wantTotal: 20, wantFree: 5, wantUsed: 15,
- },
- {
- total: 20, free: -1, used: -1,
- wantTotal: 20, wantFree: 20, wantUsed: 0,
- },
- {
- total: -1, free: 5, used: 15,
- wantTotal: 20, wantFree: 5, wantUsed: 15,
- },
- {
- total: -1, free: 15, used: -1,
- wantTotal: 15, wantFree: 15, wantUsed: 0,
- },
- {
- total: -1, free: -1, used: 15,
- wantTotal: 25, wantFree: 10, wantUsed: 15,
- },
- {
- total: -1, free: -1, used: -1,
- wantTotal: 10, wantFree: 10, wantUsed: 0,
- },
- } {
- t.Run(fmt.Sprintf("total=%d,free=%d,used=%d", test.total, test.free, test.used), func(t *testing.T) {
- gotTotal, gotUsed, gotFree := fillInMissingSizes(test.total, test.used, test.free, unknownFree)
- assert.Equal(t, test.wantTotal, gotTotal, "total")
- assert.Equal(t, test.wantUsed, gotUsed, "used")
- assert.Equal(t, test.wantFree, gotFree, "free")
- })
- }
- }
|