mirror of
https://github.com/rclone/rclone.git
synced 2024-11-22 14:51:48 +08:00
d0888edc0a
Fix spelling of: above, already, anonymous, associated, authentication, bandwidth, because, between, blocks, calculate, candidates, cautious, changelog, cleaner, clipboard, command, completely, concurrently, considered, constructs, corrupt, current, daemon, dependencies, deprecated, directory, dispatcher, download, eligible, ellipsis, encrypter, endpoint, entrieslist, essentially, existing writers, existing, expires, filesystem, flushing, frequently, hierarchy, however, implementation, implements, inaccurate, individually, insensitive, longer, maximum, metadata, modified, multipart, namedirfirst, nextcloud, obscured, opened, optional, owncloud, pacific, passphrase, password, permanently, persimmon, positive, potato, protocol, quota, receiving, recommends, referring, requires, revisited, satisfied, satisfies, satisfy, semver, serialized, session, storage, strategies, stringlist, successful, supported, surprise, temporarily, temporary, transactions, unneeded, update, uploads, wrapped Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>
422 lines
10 KiB
Go
422 lines
10 KiB
Go
// Test suite for vfs
|
|
|
|
package vfs
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/pkg/errors"
|
|
_ "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 = 10 * 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, cleanup func()) {
|
|
r = fstest.NewRun(t)
|
|
vfs = New(r.Fremote, opt)
|
|
cleanup = func() {
|
|
cleanupVFS(t, vfs)
|
|
r.Finalise()
|
|
}
|
|
return r, vfs, cleanup
|
|
}
|
|
|
|
// Create a new VFS with default options
|
|
func newTestVFS(t *testing.T) (r *fstest.Run, vfs *VFS, cleanup func()) {
|
|
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, cleanup := 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)
|
|
|
|
cleanup()
|
|
|
|
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, cleanup := newTestVFSOpt(t, &opt)
|
|
defer cleanup()
|
|
|
|
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, cleanup := newTestVFS(t)
|
|
defer cleanup()
|
|
|
|
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, cleanup := newTestVFS(t)
|
|
defer cleanup()
|
|
|
|
file1 := r.WriteObject(context.Background(), "file1", "file1 contents", t1)
|
|
file2 := r.WriteObject(context.Background(), "dir/file2", "file2 contents", t2)
|
|
fstest.CheckItems(t, r.Fremote, 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, cleanup := newTestVFS(t)
|
|
defer cleanup()
|
|
|
|
file1 := r.WriteObject(context.Background(), "file1", "file1 contents", t1)
|
|
file2 := r.WriteObject(context.Background(), "dir/file2", "file2 contents", t2)
|
|
fstest.CheckItems(t, r.Fremote, 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, cleanup := newTestVFS(t)
|
|
defer cleanup()
|
|
|
|
file1 := r.WriteObject(context.Background(), "file1", "file1 contents", t1)
|
|
file2 := r.WriteObject(context.Background(), "dir/file2", "file2 contents", t2)
|
|
fstest.CheckItems(t, r.Fremote, 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.Cause(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, cleanup := newTestVFS(t)
|
|
defer cleanup()
|
|
|
|
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)
|
|
fstest.CheckItems(t, r.Fremote, file1)
|
|
|
|
err := vfs.Rename("dir/file2", "dir/file1")
|
|
require.NoError(t, err)
|
|
file1.Path = "dir/file1"
|
|
fstest.CheckItems(t, r.Fremote, file1)
|
|
|
|
err = vfs.Rename("dir/file1", "file0")
|
|
require.NoError(t, err)
|
|
file1.Path = "file0"
|
|
fstest.CheckItems(t, r.Fremote, 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, cleanup := newTestVFS(t)
|
|
defer cleanup()
|
|
|
|
// 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 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")
|
|
})
|
|
}
|
|
}
|