mirror of
https://github.com/rclone/rclone.git
synced 2024-12-21 19:16:29 +08:00
d50572b108
Fixes #7569
869 lines
25 KiB
Go
869 lines
25 KiB
Go
package operations_test
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"net/url"
|
|
"os"
|
|
"path"
|
|
"sort"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/rclone/rclone/fs"
|
|
"github.com/rclone/rclone/fs/cache"
|
|
"github.com/rclone/rclone/fs/hash"
|
|
"github.com/rclone/rclone/fs/operations"
|
|
"github.com/rclone/rclone/fs/rc"
|
|
"github.com/rclone/rclone/fstest"
|
|
"github.com/rclone/rclone/lib/diskusage"
|
|
"github.com/rclone/rclone/lib/rest"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func rcNewRun(t *testing.T, method string) (*fstest.Run, *rc.Call) {
|
|
if *fstest.RemoteName != "" {
|
|
t.Skip("Skipping test on non local remote")
|
|
}
|
|
r := fstest.NewRun(t)
|
|
call := rc.Calls.Get(method)
|
|
assert.NotNil(t, call)
|
|
cache.Put(r.LocalName, r.Flocal)
|
|
cache.Put(r.FremoteName, r.Fremote)
|
|
return r, call
|
|
}
|
|
|
|
// operations/about: Return the space used on the remote
|
|
func TestRcAbout(t *testing.T) {
|
|
r, call := rcNewRun(t, "operations/about")
|
|
r.Mkdir(context.Background(), r.Fremote)
|
|
|
|
// Will get an error if remote doesn't support About
|
|
expectedErr := r.Fremote.Features().About == nil
|
|
|
|
in := rc.Params{
|
|
"fs": r.FremoteName,
|
|
}
|
|
out, err := call.Fn(context.Background(), in)
|
|
if expectedErr {
|
|
assert.Error(t, err)
|
|
return
|
|
}
|
|
require.NoError(t, err)
|
|
|
|
// Can't really check the output much!
|
|
assert.NotEqual(t, int64(0), out["Total"])
|
|
}
|
|
|
|
// operations/cleanup: Remove trashed files in the remote or path
|
|
func TestRcCleanup(t *testing.T) {
|
|
r, call := rcNewRun(t, "operations/cleanup")
|
|
|
|
in := rc.Params{
|
|
"fs": r.LocalName,
|
|
}
|
|
out, err := call.Fn(context.Background(), in)
|
|
require.Error(t, err)
|
|
assert.Equal(t, rc.Params(nil), out)
|
|
assert.Contains(t, err.Error(), "doesn't support cleanup")
|
|
}
|
|
|
|
// operations/copyfile: Copy a file from source remote to destination remote
|
|
func TestRcCopyfile(t *testing.T) {
|
|
r, call := rcNewRun(t, "operations/copyfile")
|
|
file1 := r.WriteFile("file1", "file1 contents", t1)
|
|
r.Mkdir(context.Background(), r.Fremote)
|
|
r.CheckLocalItems(t, file1)
|
|
r.CheckRemoteItems(t)
|
|
|
|
in := rc.Params{
|
|
"srcFs": r.LocalName,
|
|
"srcRemote": "file1",
|
|
"dstFs": r.FremoteName,
|
|
"dstRemote": "file1-renamed",
|
|
}
|
|
out, err := call.Fn(context.Background(), in)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, rc.Params(nil), out)
|
|
|
|
r.CheckLocalItems(t, file1)
|
|
file1.Path = "file1-renamed"
|
|
r.CheckRemoteItems(t, file1)
|
|
}
|
|
|
|
// operations/copyurl: Copy the URL to the object
|
|
func TestRcCopyurl(t *testing.T) {
|
|
r, call := rcNewRun(t, "operations/copyurl")
|
|
contents := "file1 contents\n"
|
|
file1 := r.WriteFile("file1", contents, t1)
|
|
r.Mkdir(context.Background(), r.Fremote)
|
|
r.CheckRemoteItems(t)
|
|
|
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
_, err := w.Write([]byte(contents))
|
|
assert.NoError(t, err)
|
|
}))
|
|
defer ts.Close()
|
|
|
|
in := rc.Params{
|
|
"fs": r.FremoteName,
|
|
"remote": "file1",
|
|
"url": ts.URL,
|
|
"autoFilename": false,
|
|
"noClobber": false,
|
|
}
|
|
out, err := call.Fn(context.Background(), in)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, rc.Params(nil), out)
|
|
|
|
in = rc.Params{
|
|
"fs": r.FremoteName,
|
|
"remote": "file1",
|
|
"url": ts.URL,
|
|
"autoFilename": false,
|
|
"noClobber": true,
|
|
}
|
|
out, err = call.Fn(context.Background(), in)
|
|
require.Error(t, err)
|
|
assert.Equal(t, rc.Params(nil), out)
|
|
|
|
urlFileName := "filename.txt"
|
|
in = rc.Params{
|
|
"fs": r.FremoteName,
|
|
"remote": "",
|
|
"url": ts.URL + "/" + urlFileName,
|
|
"autoFilename": true,
|
|
"noClobber": false,
|
|
}
|
|
out, err = call.Fn(context.Background(), in)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, rc.Params(nil), out)
|
|
|
|
in = rc.Params{
|
|
"fs": r.FremoteName,
|
|
"remote": "",
|
|
"url": ts.URL,
|
|
"autoFilename": true,
|
|
"noClobber": false,
|
|
}
|
|
out, err = call.Fn(context.Background(), in)
|
|
require.Error(t, err)
|
|
assert.Equal(t, rc.Params(nil), out)
|
|
|
|
fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{file1, fstest.NewItem(urlFileName, contents, t1)}, nil, fs.ModTimeNotSupported)
|
|
}
|
|
|
|
// operations/delete: Remove files in the path
|
|
func TestRcDelete(t *testing.T) {
|
|
r, call := rcNewRun(t, "operations/delete")
|
|
|
|
file1 := r.WriteObject(context.Background(), "small", "1234567890", t2) // 10 bytes
|
|
file2 := r.WriteObject(context.Background(), "medium", "------------------------------------------------------------", t1) // 60 bytes
|
|
file3 := r.WriteObject(context.Background(), "large", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", t1) // 100 bytes
|
|
r.CheckRemoteItems(t, file1, file2, file3)
|
|
|
|
in := rc.Params{
|
|
"fs": r.FremoteName,
|
|
}
|
|
out, err := call.Fn(context.Background(), in)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, rc.Params(nil), out)
|
|
|
|
r.CheckRemoteItems(t)
|
|
}
|
|
|
|
// operations/deletefile: Remove the single file pointed to
|
|
func TestRcDeletefile(t *testing.T) {
|
|
r, call := rcNewRun(t, "operations/deletefile")
|
|
|
|
file1 := r.WriteObject(context.Background(), "small", "1234567890", t2) // 10 bytes
|
|
file2 := r.WriteObject(context.Background(), "medium", "------------------------------------------------------------", t1) // 60 bytes
|
|
r.CheckRemoteItems(t, file1, file2)
|
|
|
|
in := rc.Params{
|
|
"fs": r.FremoteName,
|
|
"remote": "small",
|
|
}
|
|
out, err := call.Fn(context.Background(), in)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, rc.Params(nil), out)
|
|
|
|
r.CheckRemoteItems(t, file2)
|
|
}
|
|
|
|
// operations/list: List the given remote and path in JSON format.
|
|
func TestRcList(t *testing.T) {
|
|
r, call := rcNewRun(t, "operations/list")
|
|
|
|
file1 := r.WriteObject(context.Background(), "a", "a", t1)
|
|
file2 := r.WriteObject(context.Background(), "subdir/b", "bb", t2)
|
|
|
|
r.CheckRemoteItems(t, file1, file2)
|
|
|
|
in := rc.Params{
|
|
"fs": r.FremoteName,
|
|
"remote": "",
|
|
}
|
|
out, err := call.Fn(context.Background(), in)
|
|
require.NoError(t, err)
|
|
|
|
list := out["list"].([]*operations.ListJSONItem)
|
|
assert.Equal(t, 2, len(list))
|
|
|
|
checkFile1 := func(got *operations.ListJSONItem) {
|
|
assert.WithinDuration(t, t1, got.ModTime.When, time.Second)
|
|
assert.Equal(t, "a", got.Path)
|
|
assert.Equal(t, "a", got.Name)
|
|
assert.Equal(t, int64(1), got.Size)
|
|
assert.Equal(t, "application/octet-stream", got.MimeType)
|
|
assert.Equal(t, false, got.IsDir)
|
|
}
|
|
checkFile1(list[0])
|
|
|
|
checkSubdir := func(got *operations.ListJSONItem) {
|
|
assert.Equal(t, "subdir", got.Path)
|
|
assert.Equal(t, "subdir", got.Name)
|
|
// assert.Equal(t, int64(-1), got.Size) // size can vary for directories
|
|
assert.Equal(t, "inode/directory", got.MimeType)
|
|
assert.Equal(t, true, got.IsDir)
|
|
}
|
|
checkSubdir(list[1])
|
|
|
|
in = rc.Params{
|
|
"fs": r.FremoteName,
|
|
"remote": "",
|
|
"opt": rc.Params{
|
|
"recurse": true,
|
|
},
|
|
}
|
|
out, err = call.Fn(context.Background(), in)
|
|
require.NoError(t, err)
|
|
|
|
list = out["list"].([]*operations.ListJSONItem)
|
|
assert.Equal(t, 3, len(list))
|
|
checkFile1(list[0])
|
|
checkSubdir(list[1])
|
|
|
|
checkFile2 := func(got *operations.ListJSONItem) {
|
|
assert.WithinDuration(t, t2, got.ModTime.When, time.Second)
|
|
assert.Equal(t, "subdir/b", got.Path)
|
|
assert.Equal(t, "b", got.Name)
|
|
assert.Equal(t, int64(2), got.Size)
|
|
assert.Equal(t, "application/octet-stream", got.MimeType)
|
|
assert.Equal(t, false, got.IsDir)
|
|
}
|
|
checkFile2(list[2])
|
|
}
|
|
|
|
// operations/stat: Stat the given remote and path in JSON format.
|
|
func TestRcStat(t *testing.T) {
|
|
r, call := rcNewRun(t, "operations/stat")
|
|
|
|
file1 := r.WriteObject(context.Background(), "subdir/a", "a", t1)
|
|
|
|
r.CheckRemoteItems(t, file1)
|
|
|
|
fetch := func(t *testing.T, remotePath string) *operations.ListJSONItem {
|
|
in := rc.Params{
|
|
"fs": r.FremoteName,
|
|
"remote": remotePath,
|
|
}
|
|
out, err := call.Fn(context.Background(), in)
|
|
require.NoError(t, err)
|
|
return out["item"].(*operations.ListJSONItem)
|
|
}
|
|
|
|
t.Run("Root", func(t *testing.T) {
|
|
stat := fetch(t, "")
|
|
assert.Equal(t, "", stat.Path)
|
|
assert.Equal(t, "", stat.Name)
|
|
assert.Equal(t, int64(-1), stat.Size)
|
|
assert.Equal(t, "inode/directory", stat.MimeType)
|
|
assert.Equal(t, true, stat.IsDir)
|
|
})
|
|
|
|
t.Run("File", func(t *testing.T) {
|
|
stat := fetch(t, "subdir/a")
|
|
assert.WithinDuration(t, t1, stat.ModTime.When, time.Second)
|
|
assert.Equal(t, "subdir/a", stat.Path)
|
|
assert.Equal(t, "a", stat.Name)
|
|
assert.Equal(t, int64(1), stat.Size)
|
|
assert.Equal(t, "application/octet-stream", stat.MimeType)
|
|
assert.Equal(t, false, stat.IsDir)
|
|
})
|
|
|
|
t.Run("Subdir", func(t *testing.T) {
|
|
stat := fetch(t, "subdir")
|
|
assert.Equal(t, "subdir", stat.Path)
|
|
assert.Equal(t, "subdir", stat.Name)
|
|
// assert.Equal(t, int64(-1), stat.Size) // size can vary for directories
|
|
assert.Equal(t, "inode/directory", stat.MimeType)
|
|
assert.Equal(t, true, stat.IsDir)
|
|
})
|
|
|
|
t.Run("NotFound", func(t *testing.T) {
|
|
stat := fetch(t, "notfound")
|
|
assert.Nil(t, stat)
|
|
})
|
|
}
|
|
|
|
// operations/settier: Set the storage tier of a fs
|
|
func TestRcSetTier(t *testing.T) {
|
|
ctx := context.Background()
|
|
r, call := rcNewRun(t, "operations/settier")
|
|
if !r.Fremote.Features().SetTier {
|
|
t.Skip("settier not supported")
|
|
}
|
|
file1 := r.WriteObject(context.Background(), "file1", "file1 contents", t1)
|
|
r.CheckRemoteItems(t, file1)
|
|
|
|
// Because we don't know what the current tier options here are, let's
|
|
// just get the current tier, and reuse that
|
|
o, err := r.Fremote.NewObject(ctx, file1.Path)
|
|
require.NoError(t, err)
|
|
trr, ok := o.(fs.GetTierer)
|
|
require.True(t, ok)
|
|
ctier := trr.GetTier()
|
|
in := rc.Params{
|
|
"fs": r.FremoteName,
|
|
"tier": ctier,
|
|
}
|
|
out, err := call.Fn(context.Background(), in)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, rc.Params(nil), out)
|
|
|
|
}
|
|
|
|
// operations/settier: Set the storage tier of a file
|
|
func TestRcSetTierFile(t *testing.T) {
|
|
ctx := context.Background()
|
|
r, call := rcNewRun(t, "operations/settierfile")
|
|
if !r.Fremote.Features().SetTier {
|
|
t.Skip("settier not supported")
|
|
}
|
|
file1 := r.WriteObject(context.Background(), "file1", "file1 contents", t1)
|
|
r.CheckRemoteItems(t, file1)
|
|
|
|
// Because we don't know what the current tier options here are, let's
|
|
// just get the current tier, and reuse that
|
|
o, err := r.Fremote.NewObject(ctx, file1.Path)
|
|
require.NoError(t, err)
|
|
trr, ok := o.(fs.GetTierer)
|
|
require.True(t, ok)
|
|
ctier := trr.GetTier()
|
|
in := rc.Params{
|
|
"fs": r.FremoteName,
|
|
"remote": "file1",
|
|
"tier": ctier,
|
|
}
|
|
out, err := call.Fn(context.Background(), in)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, rc.Params(nil), out)
|
|
|
|
}
|
|
|
|
// operations/mkdir: Make a destination directory or container
|
|
func TestRcMkdir(t *testing.T) {
|
|
ctx := context.Background()
|
|
r, call := rcNewRun(t, "operations/mkdir")
|
|
r.Mkdir(context.Background(), r.Fremote)
|
|
|
|
fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{}, []string{}, fs.GetModifyWindow(ctx, r.Fremote))
|
|
|
|
in := rc.Params{
|
|
"fs": r.FremoteName,
|
|
"remote": "subdir",
|
|
}
|
|
out, err := call.Fn(context.Background(), in)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, rc.Params(nil), out)
|
|
|
|
fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{}, []string{"subdir"}, fs.GetModifyWindow(ctx, r.Fremote))
|
|
}
|
|
|
|
// operations/movefile: Move a file from source remote to destination remote
|
|
func TestRcMovefile(t *testing.T) {
|
|
r, call := rcNewRun(t, "operations/movefile")
|
|
file1 := r.WriteFile("file1", "file1 contents", t1)
|
|
r.Mkdir(context.Background(), r.Fremote)
|
|
r.CheckLocalItems(t, file1)
|
|
r.CheckRemoteItems(t)
|
|
|
|
in := rc.Params{
|
|
"srcFs": r.LocalName,
|
|
"srcRemote": "file1",
|
|
"dstFs": r.FremoteName,
|
|
"dstRemote": "file1-renamed",
|
|
}
|
|
out, err := call.Fn(context.Background(), in)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, rc.Params(nil), out)
|
|
|
|
r.CheckLocalItems(t)
|
|
file1.Path = "file1-renamed"
|
|
r.CheckRemoteItems(t, file1)
|
|
}
|
|
|
|
// operations/purge: Remove a directory or container and all of its contents
|
|
func TestRcPurge(t *testing.T) {
|
|
ctx := context.Background()
|
|
r, call := rcNewRun(t, "operations/purge")
|
|
file1 := r.WriteObject(context.Background(), "subdir/file1", "subdir/file1 contents", t1)
|
|
|
|
fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{file1}, []string{"subdir"}, fs.GetModifyWindow(ctx, r.Fremote))
|
|
|
|
in := rc.Params{
|
|
"fs": r.FremoteName,
|
|
"remote": "subdir",
|
|
}
|
|
out, err := call.Fn(context.Background(), in)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, rc.Params(nil), out)
|
|
|
|
fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{}, []string{}, fs.GetModifyWindow(ctx, r.Fremote))
|
|
}
|
|
|
|
// operations/rmdir: Remove an empty directory or container
|
|
func TestRcRmdir(t *testing.T) {
|
|
ctx := context.Background()
|
|
r, call := rcNewRun(t, "operations/rmdir")
|
|
r.Mkdir(context.Background(), r.Fremote)
|
|
assert.NoError(t, r.Fremote.Mkdir(context.Background(), "subdir"))
|
|
|
|
fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{}, []string{"subdir"}, fs.GetModifyWindow(ctx, r.Fremote))
|
|
|
|
in := rc.Params{
|
|
"fs": r.FremoteName,
|
|
"remote": "subdir",
|
|
}
|
|
out, err := call.Fn(context.Background(), in)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, rc.Params(nil), out)
|
|
|
|
fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{}, []string{}, fs.GetModifyWindow(ctx, r.Fremote))
|
|
}
|
|
|
|
// operations/rmdirs: Remove all the empty directories in the path
|
|
func TestRcRmdirs(t *testing.T) {
|
|
ctx := context.Background()
|
|
r, call := rcNewRun(t, "operations/rmdirs")
|
|
r.Mkdir(context.Background(), r.Fremote)
|
|
assert.NoError(t, r.Fremote.Mkdir(context.Background(), "subdir"))
|
|
assert.NoError(t, r.Fremote.Mkdir(context.Background(), "subdir/subsubdir"))
|
|
|
|
fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{}, []string{"subdir", "subdir/subsubdir"}, fs.GetModifyWindow(ctx, r.Fremote))
|
|
|
|
in := rc.Params{
|
|
"fs": r.FremoteName,
|
|
"remote": "subdir",
|
|
}
|
|
out, err := call.Fn(context.Background(), in)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, rc.Params(nil), out)
|
|
|
|
fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{}, []string{}, fs.GetModifyWindow(ctx, r.Fremote))
|
|
|
|
assert.NoError(t, r.Fremote.Mkdir(context.Background(), "subdir"))
|
|
assert.NoError(t, r.Fremote.Mkdir(context.Background(), "subdir/subsubdir"))
|
|
|
|
in = rc.Params{
|
|
"fs": r.FremoteName,
|
|
"remote": "subdir",
|
|
"leaveRoot": true,
|
|
}
|
|
out, err = call.Fn(context.Background(), in)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, rc.Params(nil), out)
|
|
|
|
fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{}, []string{"subdir"}, fs.GetModifyWindow(ctx, r.Fremote))
|
|
|
|
}
|
|
|
|
// operations/size: Count the number of bytes and files in remote
|
|
func TestRcSize(t *testing.T) {
|
|
r, call := rcNewRun(t, "operations/size")
|
|
file1 := r.WriteObject(context.Background(), "small", "1234567890", t2) // 10 bytes
|
|
file2 := r.WriteObject(context.Background(), "subdir/medium", "------------------------------------------------------------", t1) // 60 bytes
|
|
file3 := r.WriteObject(context.Background(), "subdir/subsubdir/large", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", t1) // 50 bytes
|
|
r.CheckRemoteItems(t, file1, file2, file3)
|
|
|
|
in := rc.Params{
|
|
"fs": r.FremoteName,
|
|
}
|
|
out, err := call.Fn(context.Background(), in)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, rc.Params{
|
|
"count": int64(3),
|
|
"bytes": int64(120),
|
|
"sizeless": int64(0),
|
|
}, out)
|
|
}
|
|
|
|
// operations/publiclink: Create or retrieve a public link to the given file or folder.
|
|
func TestRcPublicLink(t *testing.T) {
|
|
r, call := rcNewRun(t, "operations/publiclink")
|
|
in := rc.Params{
|
|
"fs": r.FremoteName,
|
|
"remote": "",
|
|
"expire": "5m",
|
|
"unlink": false,
|
|
}
|
|
_, err := call.Fn(context.Background(), in)
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "doesn't support public links")
|
|
}
|
|
|
|
// operations/fsinfo: Return information about the remote
|
|
func TestRcFsInfo(t *testing.T) {
|
|
r, call := rcNewRun(t, "operations/fsinfo")
|
|
in := rc.Params{
|
|
"fs": r.FremoteName,
|
|
}
|
|
got, err := call.Fn(context.Background(), in)
|
|
require.NoError(t, err)
|
|
want := operations.GetFsInfo(r.Fremote)
|
|
assert.Equal(t, want.Name, got["Name"])
|
|
assert.Equal(t, want.Root, got["Root"])
|
|
assert.Equal(t, want.String, got["String"])
|
|
assert.Equal(t, float64(want.Precision), got["Precision"])
|
|
var hashes []interface{}
|
|
for _, hash := range want.Hashes {
|
|
hashes = append(hashes, hash)
|
|
}
|
|
assert.Equal(t, hashes, got["Hashes"])
|
|
var features = map[string]interface{}{}
|
|
for k, v := range want.Features {
|
|
features[k] = v
|
|
}
|
|
assert.Equal(t, features, got["Features"])
|
|
|
|
}
|
|
|
|
// operations/uploadfile : Tests if upload file succeeds
|
|
func TestUploadFile(t *testing.T) {
|
|
r, call := rcNewRun(t, "operations/uploadfile")
|
|
ctx := context.Background()
|
|
|
|
testFileName := "uploadfile-test.txt"
|
|
testFileContent := "Hello World"
|
|
r.WriteFile(testFileName, testFileContent, t1)
|
|
testItem1 := fstest.NewItem(testFileName, testFileContent, t1)
|
|
testItem2 := fstest.NewItem(path.Join("subdir", testFileName), testFileContent, t1)
|
|
|
|
currentFile, err := os.Open(path.Join(r.LocalName, testFileName))
|
|
require.NoError(t, err)
|
|
|
|
defer func() {
|
|
assert.NoError(t, currentFile.Close())
|
|
}()
|
|
|
|
formReader, contentType, _, err := rest.MultipartUpload(ctx, currentFile, url.Values{}, "file", testFileName)
|
|
require.NoError(t, err)
|
|
|
|
httpReq := httptest.NewRequest("POST", "/", formReader)
|
|
httpReq.Header.Add("Content-Type", contentType)
|
|
|
|
in := rc.Params{
|
|
"_request": httpReq,
|
|
"fs": r.FremoteName,
|
|
"remote": "",
|
|
}
|
|
|
|
_, err = call.Fn(context.Background(), in)
|
|
require.NoError(t, err)
|
|
|
|
fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{testItem1}, nil, fs.ModTimeNotSupported)
|
|
|
|
assert.NoError(t, r.Fremote.Mkdir(context.Background(), "subdir"))
|
|
|
|
currentFile2, err := os.Open(path.Join(r.LocalName, testFileName))
|
|
require.NoError(t, err)
|
|
|
|
defer func() {
|
|
assert.NoError(t, currentFile2.Close())
|
|
}()
|
|
|
|
formReader, contentType, _, err = rest.MultipartUpload(ctx, currentFile2, url.Values{}, "file", testFileName)
|
|
require.NoError(t, err)
|
|
|
|
httpReq = httptest.NewRequest("POST", "/", formReader)
|
|
httpReq.Header.Add("Content-Type", contentType)
|
|
|
|
in = rc.Params{
|
|
"_request": httpReq,
|
|
"fs": r.FremoteName,
|
|
"remote": "subdir",
|
|
}
|
|
|
|
_, err = call.Fn(context.Background(), in)
|
|
require.NoError(t, err)
|
|
|
|
fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{testItem1, testItem2}, nil, fs.ModTimeNotSupported)
|
|
|
|
}
|
|
|
|
// operations/command: Runs a backend command
|
|
func TestRcCommand(t *testing.T) {
|
|
r, call := rcNewRun(t, "backend/command")
|
|
in := rc.Params{
|
|
"fs": r.FremoteName,
|
|
"command": "noop",
|
|
"opt": map[string]string{
|
|
"echo": "true",
|
|
"blue": "",
|
|
},
|
|
"arg": []string{
|
|
"path1",
|
|
"path2",
|
|
},
|
|
}
|
|
got, err := call.Fn(context.Background(), in)
|
|
if err != nil {
|
|
assert.False(t, r.Fremote.Features().IsLocal, "mustn't fail on local remote")
|
|
assert.Contains(t, err.Error(), "command not found")
|
|
return
|
|
}
|
|
want := rc.Params{"result": map[string]interface{}{
|
|
"arg": []string{
|
|
"path1",
|
|
"path2",
|
|
},
|
|
"name": "noop",
|
|
"opt": map[string]string{
|
|
"blue": "",
|
|
"echo": "true",
|
|
},
|
|
}}
|
|
assert.Equal(t, want, got)
|
|
errTxt := "explosion in the sausage factory"
|
|
in["opt"].(map[string]string)["error"] = errTxt
|
|
_, err = call.Fn(context.Background(), in)
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), errTxt)
|
|
}
|
|
|
|
// operations/command: Runs a backend command
|
|
func TestRcDu(t *testing.T) {
|
|
ctx := context.Background()
|
|
_, call := rcNewRun(t, "core/du")
|
|
in := rc.Params{}
|
|
out, err := call.Fn(ctx, in)
|
|
if err == diskusage.ErrUnsupported {
|
|
t.Skip(err)
|
|
}
|
|
assert.NotEqual(t, "", out["dir"])
|
|
info := out["info"].(diskusage.Info)
|
|
assert.True(t, info.Total != 0)
|
|
assert.True(t, info.Total > info.Free)
|
|
assert.True(t, info.Total > info.Available)
|
|
assert.True(t, info.Free >= info.Available)
|
|
}
|
|
|
|
// operations/check: check the source and destination are the same
|
|
func TestRcCheck(t *testing.T) {
|
|
ctx := context.Background()
|
|
r, call := rcNewRun(t, "operations/check")
|
|
r.Mkdir(ctx, r.Fremote)
|
|
|
|
MD5SUMS := `
|
|
0ef726ce9b1a7692357ff70dd321d595 file1
|
|
deadbeefcafe00000000000000000000 subdir/file2
|
|
0386a8b8fcf672c326845c00ba41b9e2 subdir/subsubdir/file4
|
|
`
|
|
|
|
file1 := r.WriteBoth(ctx, "file1", "file1 contents", t1)
|
|
file2 := r.WriteFile("subdir/file2", MD5SUMS, t2)
|
|
file3 := r.WriteObject(ctx, "subdir/subsubdir/file3", "file3 contents", t3)
|
|
file4a := r.WriteFile("subdir/subsubdir/file4", "file4 contents", t3)
|
|
file4b := r.WriteObject(ctx, "subdir/subsubdir/file4", "file4 different contents", t3)
|
|
// operations.HashLister(ctx, hash.MD5, false, false, r.Fremote, os.Stdout)
|
|
|
|
r.CheckLocalItems(t, file1, file2, file4a)
|
|
r.CheckRemoteItems(t, file1, file3, file4b)
|
|
|
|
pstring := func(items ...fstest.Item) *[]string {
|
|
xs := make([]string, len(items))
|
|
for i, item := range items {
|
|
xs[i] = item.Path
|
|
}
|
|
return &xs
|
|
}
|
|
|
|
for _, testName := range []string{"Normal", "Download"} {
|
|
t.Run(testName, func(t *testing.T) {
|
|
in := rc.Params{
|
|
"srcFs": r.LocalName,
|
|
"dstFs": r.FremoteName,
|
|
"combined": true,
|
|
"missingOnSrc": true,
|
|
"missingOnDst": true,
|
|
"match": true,
|
|
"differ": true,
|
|
"error": true,
|
|
}
|
|
if testName == "Download" {
|
|
in["download"] = true
|
|
}
|
|
out, err := call.Fn(ctx, in)
|
|
require.NoError(t, err)
|
|
|
|
combined := []string{
|
|
"= " + file1.Path,
|
|
"+ " + file2.Path,
|
|
"- " + file3.Path,
|
|
"* " + file4a.Path,
|
|
}
|
|
sort.Strings(combined)
|
|
sort.Strings(*out["combined"].(*[]string))
|
|
want := rc.Params{
|
|
"missingOnSrc": pstring(file3),
|
|
"missingOnDst": pstring(file2),
|
|
"differ": pstring(file4a),
|
|
"error": pstring(),
|
|
"match": pstring(file1),
|
|
"combined": &combined,
|
|
"status": "3 differences found",
|
|
"success": false,
|
|
}
|
|
if testName == "Normal" {
|
|
want["hashType"] = "md5"
|
|
}
|
|
|
|
assert.Equal(t, want, out)
|
|
})
|
|
}
|
|
|
|
t.Run("CheckFile", func(t *testing.T) {
|
|
// The checksum file is treated as the source and srcFs is not used
|
|
in := rc.Params{
|
|
"dstFs": r.FremoteName,
|
|
"combined": true,
|
|
"missingOnSrc": true,
|
|
"missingOnDst": true,
|
|
"match": true,
|
|
"differ": true,
|
|
"error": true,
|
|
"checkFileFs": r.LocalName,
|
|
"checkFileRemote": file2.Path,
|
|
"checkFileHash": "md5",
|
|
}
|
|
out, err := call.Fn(ctx, in)
|
|
require.NoError(t, err)
|
|
|
|
combined := []string{
|
|
"= " + file1.Path,
|
|
"+ " + file2.Path,
|
|
"- " + file3.Path,
|
|
"* " + file4a.Path,
|
|
}
|
|
sort.Strings(combined)
|
|
sort.Strings(*out["combined"].(*[]string))
|
|
if strings.HasPrefix(out["status"].(string), "file not in") {
|
|
out["status"] = "file not in"
|
|
}
|
|
want := rc.Params{
|
|
"missingOnSrc": pstring(file3),
|
|
"missingOnDst": pstring(file2),
|
|
"differ": pstring(file4a),
|
|
"error": pstring(),
|
|
"match": pstring(file1),
|
|
"combined": &combined,
|
|
"hashType": "md5",
|
|
"status": "file not in",
|
|
"success": false,
|
|
}
|
|
|
|
assert.Equal(t, want, out)
|
|
})
|
|
|
|
}
|
|
|
|
// operations/hashsum: hashsum a directory
|
|
func TestRcHashsum(t *testing.T) {
|
|
ctx := context.Background()
|
|
r, call := rcNewRun(t, "operations/hashsum")
|
|
r.Mkdir(ctx, r.Fremote)
|
|
|
|
file1Contents := "file1 contents"
|
|
file1 := r.WriteBoth(ctx, "hashsum-file1", file1Contents, t1)
|
|
r.CheckLocalItems(t, file1)
|
|
r.CheckRemoteItems(t, file1)
|
|
|
|
hasher := hash.NewMultiHasher()
|
|
_, err := hasher.Write([]byte(file1Contents))
|
|
require.NoError(t, err)
|
|
|
|
for _, test := range []struct {
|
|
ht hash.Type
|
|
base64 bool
|
|
download bool
|
|
}{
|
|
{
|
|
ht: r.Fremote.Hashes().GetOne(),
|
|
}, {
|
|
ht: r.Fremote.Hashes().GetOne(),
|
|
base64: true,
|
|
}, {
|
|
ht: hash.Whirlpool,
|
|
base64: false,
|
|
download: true,
|
|
}, {
|
|
ht: hash.Whirlpool,
|
|
base64: true,
|
|
download: true,
|
|
},
|
|
} {
|
|
t.Run(fmt.Sprintf("hash=%v,base64=%v,download=%v", test.ht, test.base64, test.download), func(t *testing.T) {
|
|
file1Hash, err := hasher.SumString(test.ht, test.base64)
|
|
require.NoError(t, err)
|
|
|
|
in := rc.Params{
|
|
"fs": r.FremoteName,
|
|
"hashType": test.ht.String(),
|
|
"base64": test.base64,
|
|
"download": test.download,
|
|
}
|
|
|
|
out, err := call.Fn(ctx, in)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, test.ht.String(), out["hashType"])
|
|
want := []string{
|
|
fmt.Sprintf("%s hashsum-file1", file1Hash),
|
|
}
|
|
assert.Equal(t, want, out["hashsum"])
|
|
})
|
|
}
|
|
}
|
|
|
|
// operations/hashsum: hashsum a single file
|
|
func TestRcHashsumFile(t *testing.T) {
|
|
ctx := context.Background()
|
|
r, call := rcNewRun(t, "operations/hashsum")
|
|
r.Mkdir(ctx, r.Fremote)
|
|
|
|
file1Contents := "file1 contents"
|
|
file1 := r.WriteBoth(ctx, "hashsum-file1", file1Contents, t1)
|
|
file2Contents := "file2 contents"
|
|
file2 := r.WriteBoth(ctx, "hashsum-file2", file2Contents, t1)
|
|
r.CheckLocalItems(t, file1, file2)
|
|
r.CheckRemoteItems(t, file1, file2)
|
|
|
|
// Make an fs pointing to just the file
|
|
fsString := path.Join(r.FremoteName, file1.Path)
|
|
|
|
in := rc.Params{
|
|
"fs": fsString,
|
|
"hashType": "MD5",
|
|
"download": true,
|
|
}
|
|
|
|
out, err := call.Fn(ctx, in)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "md5", out["hashType"])
|
|
assert.Equal(t, []string{"0ef726ce9b1a7692357ff70dd321d595 hashsum-file1"}, out["hashsum"])
|
|
}
|