rclone/fs/cache/cache_test.go
Nick Craig-Wood 8d5bc7f28b fs/cache: fix moveto/copyto remote:file remote:file2
Before this change, if the cache was given a source `remote:file` it
stored `remote:` with the error `fs.ErrorIsFile` attached. This meant
that if it `remote:` was subsequently looked up it would return the
`fs.ErrorIsFile` error.

This broke `moveto remote:file remote:file2` as moveto would lookup
`remote:` from the second argument and erroneously get the
`fs.ErrorIsFile` error.

This likely broke other commands too.

This was broken in

4c9836035 fs/cache: Add Pin and Unpin and canonicalised lookup

Which was released in v1.52.0

The fix is to make a new cache entry for `remote:` with no error
attached in the case that the original call returned `fs.ErrorIsFile`.
2020-07-02 10:55:36 +01:00

181 lines
3.4 KiB
Go

package cache
import (
"errors"
"testing"
"github.com/rclone/rclone/fs"
"github.com/rclone/rclone/fstest/mockfs"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
var (
called = 0
errSentinel = errors.New("an error")
)
func mockNewFs(t *testing.T) (func(), func(path string) (fs.Fs, error)) {
called = 0
create := func(path string) (f fs.Fs, err error) {
assert.Equal(t, 0, called)
called++
switch path {
case "mock:/":
return mockfs.NewFs("mock", "/"), nil
case "mock:/file.txt", "mock:file.txt":
return mockfs.NewFs("mock", "/"), fs.ErrorIsFile
case "mock:/error":
return nil, errSentinel
}
t.Fatalf("Unknown path %q", path)
panic("unreachable")
}
cleanup := func() {
c.Clear()
}
return cleanup, create
}
func TestGet(t *testing.T) {
cleanup, create := mockNewFs(t)
defer cleanup()
assert.Equal(t, 0, c.Entries())
f, err := GetFn("mock:/", create)
require.NoError(t, err)
assert.Equal(t, 1, c.Entries())
f2, err := GetFn("mock:/", create)
require.NoError(t, err)
assert.Equal(t, f, f2)
}
func TestGetFile(t *testing.T) {
cleanup, create := mockNewFs(t)
defer cleanup()
assert.Equal(t, 0, c.Entries())
f, err := GetFn("mock:/file.txt", create)
require.Equal(t, fs.ErrorIsFile, err)
require.NotNil(t, f)
assert.Equal(t, 2, c.Entries())
f2, err := GetFn("mock:/file.txt", create)
require.Equal(t, fs.ErrorIsFile, err)
require.NotNil(t, f2)
assert.Equal(t, f, f2)
// check parent is there too
f2, err = GetFn("mock:/", create)
require.Nil(t, err)
require.NotNil(t, f2)
assert.Equal(t, f, f2)
}
func TestGetFile2(t *testing.T) {
cleanup, create := mockNewFs(t)
defer cleanup()
assert.Equal(t, 0, c.Entries())
f, err := GetFn("mock:file.txt", create)
require.Equal(t, fs.ErrorIsFile, err)
require.NotNil(t, f)
assert.Equal(t, 2, c.Entries())
f2, err := GetFn("mock:file.txt", create)
require.Equal(t, fs.ErrorIsFile, err)
require.NotNil(t, f2)
assert.Equal(t, f, f2)
// check parent is there too
f2, err = GetFn("mock:/", create)
require.Nil(t, err)
require.NotNil(t, f2)
assert.Equal(t, f, f2)
}
func TestGetError(t *testing.T) {
cleanup, create := mockNewFs(t)
defer cleanup()
assert.Equal(t, 0, c.Entries())
f, err := GetFn("mock:/error", create)
require.Equal(t, errSentinel, err)
require.Equal(t, nil, f)
assert.Equal(t, 0, c.Entries())
}
func TestPut(t *testing.T) {
cleanup, create := mockNewFs(t)
defer cleanup()
f := mockfs.NewFs("mock", "/alien")
assert.Equal(t, 0, c.Entries())
Put("mock:/alien", f)
assert.Equal(t, 1, c.Entries())
fNew, err := GetFn("mock:/alien", create)
require.NoError(t, err)
require.Equal(t, f, fNew)
assert.Equal(t, 1, c.Entries())
// Check canonicalisation
Put("mock:/alien/", f)
fNew, err = GetFn("mock:/alien/", create)
require.NoError(t, err)
require.Equal(t, f, fNew)
assert.Equal(t, 1, c.Entries())
}
func TestPin(t *testing.T) {
cleanup, create := mockNewFs(t)
defer cleanup()
// Test pinning and unpinning non existent
f := mockfs.NewFs("mock", "/alien")
Pin(f)
Unpin(f)
// Now test pinning an existing
f2, err := GetFn("mock:/", create)
require.NoError(t, err)
Pin(f2)
Unpin(f2)
}
func TestClear(t *testing.T) {
cleanup, create := mockNewFs(t)
defer cleanup()
// Create something
_, err := GetFn("mock:/", create)
require.NoError(t, err)
assert.Equal(t, 1, c.Entries())
Clear()
assert.Equal(t, 0, c.Entries())
}