mirror of
https://github.com/rclone/rclone.git
synced 2024-11-25 08:58:26 +08:00
azureblob,memory,pcloud: fix setting of mime types
Before this change the backend was reading the mime type of the destination object instead of the source object when uploading. This changes fixes the problem and introduces an integration test for it. See: https://forum.rclone.org/t/is-there-a-way-to-get-rclone-copy-to-preserve-metadata/20682/2
This commit is contained in:
parent
19a8b66cee
commit
dfadd98969
|
@ -1453,7 +1453,7 @@ func (o *Object) Update(ctx context.Context, in io.Reader, src fs.ObjectInfo, op
|
|||
|
||||
blob := o.getBlobReference()
|
||||
httpHeaders := azblob.BlobHTTPHeaders{}
|
||||
httpHeaders.ContentType = fs.MimeType(ctx, o)
|
||||
httpHeaders.ContentType = fs.MimeType(ctx, src)
|
||||
// Compute the Content-MD5 of the file, for multiparts uploads it
|
||||
// will be set in PutBlockList API call using the 'x-ms-blob-content-md5' header
|
||||
// Note: If multipart, an MD5 checksum will also be computed for each uploaded block
|
||||
|
|
|
@ -592,7 +592,7 @@ func (o *Object) Update(ctx context.Context, in io.Reader, src fs.ObjectInfo, op
|
|||
data: data,
|
||||
hash: "",
|
||||
modTime: src.ModTime(ctx),
|
||||
mimeType: fs.MimeType(ctx, o),
|
||||
mimeType: fs.MimeType(ctx, src),
|
||||
}
|
||||
buckets.updateObjectData(bucket, bucketPath, o.od)
|
||||
return nil
|
||||
|
|
|
@ -1117,7 +1117,7 @@ func (o *Object) Update(ctx context.Context, in io.Reader, src fs.ObjectInfo, op
|
|||
Method: "PUT",
|
||||
Path: "/uploadfile",
|
||||
Body: in,
|
||||
ContentType: fs.MimeType(ctx, o),
|
||||
ContentType: fs.MimeType(ctx, src),
|
||||
ContentLength: &size,
|
||||
Parameters: url.Values{},
|
||||
TransferEncoding: []string{"identity"}, // pcloud doesn't like chunked encoding
|
||||
|
|
|
@ -153,13 +153,32 @@ func retry(t *testing.T, what string, f func() error) {
|
|||
require.NoError(t, err, what)
|
||||
}
|
||||
|
||||
// testPut puts file with random contents to the remote
|
||||
func testPut(ctx context.Context, t *testing.T, f fs.Fs, file *fstest.Item) (string, fs.Object) {
|
||||
return PutTestContents(ctx, t, f, file, random.String(100), true)
|
||||
// An fs.ObjectInfo that can override mime type
|
||||
type objectInfoWithMimeType struct {
|
||||
fs.ObjectInfo
|
||||
mimeType string
|
||||
}
|
||||
|
||||
// PutTestContents puts file with given contents to the remote and checks it but unlike TestPutLarge doesn't remove
|
||||
func PutTestContents(ctx context.Context, t *testing.T, f fs.Fs, file *fstest.Item, contents string, check bool) (string, fs.Object) {
|
||||
// Return a wrapped fs.ObjectInfo which returns the mime type given
|
||||
func overrideMimeType(o fs.ObjectInfo, mimeType string) fs.ObjectInfo {
|
||||
return &objectInfoWithMimeType{
|
||||
ObjectInfo: o,
|
||||
mimeType: mimeType,
|
||||
}
|
||||
}
|
||||
|
||||
// MimeType that was overridden
|
||||
func (o *objectInfoWithMimeType) MimeType(ctx context.Context) string {
|
||||
return o.mimeType
|
||||
}
|
||||
|
||||
// check interface
|
||||
var _ fs.MimeTyper = (*objectInfoWithMimeType)(nil)
|
||||
|
||||
// putTestContentsMimeType puts file with given contents to the remote and checks it but unlike TestPutLarge doesn't remove
|
||||
//
|
||||
// it uploads the object with the mimeType passed in if set
|
||||
func putTestContentsMimeType(ctx context.Context, t *testing.T, f fs.Fs, file *fstest.Item, contents string, check bool, mimeType string) (string, fs.Object) {
|
||||
var (
|
||||
err error
|
||||
obj fs.Object
|
||||
|
@ -172,6 +191,9 @@ func PutTestContents(ctx context.Context, t *testing.T, f fs.Fs, file *fstest.It
|
|||
|
||||
file.Size = int64(buf.Len())
|
||||
obji := object.NewStaticObjectInfo(file.Path, file.ModTime, file.Size, true, nil, nil)
|
||||
if mimeType != "" {
|
||||
obji = overrideMimeType(obji, mimeType)
|
||||
}
|
||||
obj, err = f.Put(ctx, in, obji)
|
||||
return err
|
||||
})
|
||||
|
@ -185,6 +207,21 @@ func PutTestContents(ctx context.Context, t *testing.T, f fs.Fs, file *fstest.It
|
|||
return contents, obj
|
||||
}
|
||||
|
||||
// PutTestContents puts file with given contents to the remote and checks it but unlike TestPutLarge doesn't remove
|
||||
func PutTestContents(ctx context.Context, t *testing.T, f fs.Fs, file *fstest.Item, contents string, check bool) (string, fs.Object) {
|
||||
return putTestContentsMimeType(ctx, t, f, file, contents, check, "")
|
||||
}
|
||||
|
||||
// testPut puts file with random contents to the remote
|
||||
func testPut(ctx context.Context, t *testing.T, f fs.Fs, file *fstest.Item) (string, fs.Object) {
|
||||
return PutTestContents(ctx, t, f, file, random.String(100), true)
|
||||
}
|
||||
|
||||
// testPutMimeType puts file with random contents to the remote and the mime type given
|
||||
func testPutMimeType(ctx context.Context, t *testing.T, f fs.Fs, file *fstest.Item, mimeType string) (string, fs.Object) {
|
||||
return putTestContentsMimeType(ctx, t, f, file, random.String(100), true, mimeType)
|
||||
}
|
||||
|
||||
// TestPutLarge puts file to the remote, checks it and removes it on success.
|
||||
func TestPutLarge(ctx context.Context, t *testing.T, f fs.Fs, file *fstest.Item) {
|
||||
var (
|
||||
|
@ -279,7 +316,7 @@ func stringsContains(x string, ss []string) bool {
|
|||
// - these are inside the "FsPutFiles" test.
|
||||
func Run(t *testing.T, opt *Opt) {
|
||||
var (
|
||||
remote fs.Fs
|
||||
f fs.Fs
|
||||
remoteName = opt.RemoteName
|
||||
subRemoteName string
|
||||
subRemoteLeaf string
|
||||
|
@ -288,6 +325,7 @@ func Run(t *testing.T, opt *Opt) {
|
|||
Path: "file name.txt",
|
||||
}
|
||||
file1Contents string
|
||||
file1MimeType = "text/csv"
|
||||
file2 = fstest.Item{
|
||||
ModTime: fstest.Time("2001-02-03T04:05:10.123123123Z"),
|
||||
Path: `hello? sausage/êé/Hello, 世界/ " ' @ < > & ? + ≠/z.txt`,
|
||||
|
@ -305,7 +343,7 @@ func Run(t *testing.T, opt *Opt) {
|
|||
|
||||
// Skip the test if the remote isn't configured
|
||||
skipIfNotOk := func(t *testing.T) {
|
||||
if remote == nil {
|
||||
if f == nil {
|
||||
t.Skipf("WARN: %q not configured", remoteName)
|
||||
}
|
||||
}
|
||||
|
@ -314,7 +352,7 @@ func Run(t *testing.T, opt *Opt) {
|
|||
// flag, returning a function to restore its value
|
||||
skipIfNotListR := func(t *testing.T) func() {
|
||||
skipIfNotOk(t)
|
||||
if remote.Features().ListR == nil {
|
||||
if f.Features().ListR == nil {
|
||||
t.Skip("FS has no ListR interface")
|
||||
}
|
||||
previous := ci.UseListR
|
||||
|
@ -327,8 +365,8 @@ func Run(t *testing.T, opt *Opt) {
|
|||
// Skip if remote is not SetTier and GetTier capable
|
||||
skipIfNotSetTier := func(t *testing.T) {
|
||||
skipIfNotOk(t)
|
||||
if remote.Features().SetTier == false ||
|
||||
remote.Features().GetTier == false {
|
||||
if f.Features().SetTier == false ||
|
||||
f.Features().GetTier == false {
|
||||
t.Skip("FS has no SetTier & GetTier interfaces")
|
||||
}
|
||||
}
|
||||
|
@ -374,7 +412,7 @@ func Run(t *testing.T, opt *Opt) {
|
|||
// remote - the result of fs.NewFs(TestRemote:subRemoteName)
|
||||
subRemoteName, subRemoteLeaf, err = fstest.RandomRemoteName(remoteName)
|
||||
require.NoError(t, err)
|
||||
remote, err = fs.NewFs(context.Background(), subRemoteName)
|
||||
f, err = fs.NewFs(context.Background(), subRemoteName)
|
||||
if err == fs.ErrorNotFoundInConfigFile {
|
||||
t.Logf("Didn't find %q in config file - skipping tests", remoteName)
|
||||
return
|
||||
|
@ -390,7 +428,7 @@ func Run(t *testing.T, opt *Opt) {
|
|||
if opt.SkipFsCheckWrap {
|
||||
t.Skip("Skipping FsCheckWrap on this Fs")
|
||||
}
|
||||
ft := new(fs.Features).Fill(ctx, remote)
|
||||
ft := new(fs.Features).Fill(ctx, f)
|
||||
if ft.UnWrap == nil {
|
||||
t.Skip("Not a wrapping Fs")
|
||||
}
|
||||
|
@ -418,7 +456,7 @@ func Run(t *testing.T, opt *Opt) {
|
|||
// Check to see if Fs advertises commands and they work and have docs
|
||||
t.Run("FsCommand", func(t *testing.T) {
|
||||
skipIfNotOk(t)
|
||||
doCommand := remote.Features().Command
|
||||
doCommand := f.Features().Command
|
||||
if doCommand == nil {
|
||||
t.Skip("No commands in this remote")
|
||||
}
|
||||
|
@ -434,29 +472,29 @@ func Run(t *testing.T, opt *Opt) {
|
|||
// TestFsRmdirNotFound tests deleting a non existent directory
|
||||
t.Run("FsRmdirNotFound", func(t *testing.T) {
|
||||
skipIfNotOk(t)
|
||||
if isBucketBasedButNotRoot(remote) {
|
||||
if isBucketBasedButNotRoot(f) {
|
||||
t.Skip("Skipping test as non root bucket based remote")
|
||||
}
|
||||
err := remote.Rmdir(ctx, "")
|
||||
err := f.Rmdir(ctx, "")
|
||||
assert.Error(t, err, "Expecting error on Rmdir non existent")
|
||||
})
|
||||
|
||||
// Make the directory
|
||||
err = remote.Mkdir(ctx, "")
|
||||
err = f.Mkdir(ctx, "")
|
||||
require.NoError(t, err)
|
||||
fstest.CheckListing(t, remote, []fstest.Item{})
|
||||
fstest.CheckListing(t, f, []fstest.Item{})
|
||||
|
||||
// TestFsString tests the String method
|
||||
t.Run("FsString", func(t *testing.T) {
|
||||
skipIfNotOk(t)
|
||||
str := remote.String()
|
||||
str := f.String()
|
||||
require.NotEqual(t, "", str)
|
||||
})
|
||||
|
||||
// TestFsName tests the Name method
|
||||
t.Run("FsName", func(t *testing.T) {
|
||||
skipIfNotOk(t)
|
||||
got := remote.Name()
|
||||
got := f.Name()
|
||||
want := remoteName[:strings.LastIndex(remoteName, ":")+1]
|
||||
if isLocalRemote {
|
||||
want = "local:"
|
||||
|
@ -467,8 +505,8 @@ func Run(t *testing.T, opt *Opt) {
|
|||
// TestFsRoot tests the Root method
|
||||
t.Run("FsRoot", func(t *testing.T) {
|
||||
skipIfNotOk(t)
|
||||
name := remote.Name() + ":"
|
||||
root := remote.Root()
|
||||
name := f.Name() + ":"
|
||||
root := f.Root()
|
||||
if isLocalRemote {
|
||||
// only check last path element on local
|
||||
require.Equal(t, filepath.Base(subRemoteName), filepath.Base(root))
|
||||
|
@ -480,7 +518,7 @@ func Run(t *testing.T, opt *Opt) {
|
|||
// TestFsRmdirEmpty tests deleting an empty directory
|
||||
t.Run("FsRmdirEmpty", func(t *testing.T) {
|
||||
skipIfNotOk(t)
|
||||
err := remote.Rmdir(ctx, "")
|
||||
err := f.Rmdir(ctx, "")
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
|
@ -490,41 +528,41 @@ func Run(t *testing.T, opt *Opt) {
|
|||
t.Run("FsMkdir", func(t *testing.T) {
|
||||
skipIfNotOk(t)
|
||||
|
||||
err := remote.Mkdir(ctx, "")
|
||||
err := f.Mkdir(ctx, "")
|
||||
require.NoError(t, err)
|
||||
fstest.CheckListing(t, remote, []fstest.Item{})
|
||||
fstest.CheckListing(t, f, []fstest.Item{})
|
||||
|
||||
err = remote.Mkdir(ctx, "")
|
||||
err = f.Mkdir(ctx, "")
|
||||
require.NoError(t, err)
|
||||
|
||||
// TestFsMkdirRmdirSubdir tests making and removing a sub directory
|
||||
t.Run("FsMkdirRmdirSubdir", func(t *testing.T) {
|
||||
skipIfNotOk(t)
|
||||
dir := "dir/subdir"
|
||||
err := operations.Mkdir(ctx, remote, dir)
|
||||
err := operations.Mkdir(ctx, f, dir)
|
||||
require.NoError(t, err)
|
||||
fstest.CheckListingWithPrecision(t, remote, []fstest.Item{}, []string{"dir", "dir/subdir"}, fs.GetModifyWindow(ctx, remote))
|
||||
fstest.CheckListingWithPrecision(t, f, []fstest.Item{}, []string{"dir", "dir/subdir"}, fs.GetModifyWindow(ctx, f))
|
||||
|
||||
err = operations.Rmdir(ctx, remote, dir)
|
||||
err = operations.Rmdir(ctx, f, dir)
|
||||
require.NoError(t, err)
|
||||
fstest.CheckListingWithPrecision(t, remote, []fstest.Item{}, []string{"dir"}, fs.GetModifyWindow(ctx, remote))
|
||||
fstest.CheckListingWithPrecision(t, f, []fstest.Item{}, []string{"dir"}, fs.GetModifyWindow(ctx, f))
|
||||
|
||||
err = operations.Rmdir(ctx, remote, "dir")
|
||||
err = operations.Rmdir(ctx, f, "dir")
|
||||
require.NoError(t, err)
|
||||
fstest.CheckListingWithPrecision(t, remote, []fstest.Item{}, []string{}, fs.GetModifyWindow(ctx, remote))
|
||||
fstest.CheckListingWithPrecision(t, f, []fstest.Item{}, []string{}, fs.GetModifyWindow(ctx, f))
|
||||
})
|
||||
|
||||
// TestFsListEmpty tests listing an empty directory
|
||||
t.Run("FsListEmpty", func(t *testing.T) {
|
||||
skipIfNotOk(t)
|
||||
fstest.CheckListing(t, remote, []fstest.Item{})
|
||||
fstest.CheckListing(t, f, []fstest.Item{})
|
||||
})
|
||||
|
||||
// TestFsListDirEmpty tests listing the directories from an empty directory
|
||||
TestFsListDirEmpty := func(t *testing.T) {
|
||||
skipIfNotOk(t)
|
||||
objs, dirs, err := walk.GetAll(ctx, remote, "", true, 1)
|
||||
if !remote.Features().CanHaveEmptyDirectories {
|
||||
objs, dirs, err := walk.GetAll(ctx, f, "", true, 1)
|
||||
if !f.Features().CanHaveEmptyDirectories {
|
||||
if err != fs.ErrorDirNotFound {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
@ -545,8 +583,8 @@ func Run(t *testing.T, opt *Opt) {
|
|||
// TestFsListDirNotFound tests listing the directories from an empty directory
|
||||
TestFsListDirNotFound := func(t *testing.T) {
|
||||
skipIfNotOk(t)
|
||||
objs, dirs, err := walk.GetAll(ctx, remote, "does not exist", true, 1)
|
||||
if !remote.Features().CanHaveEmptyDirectories {
|
||||
objs, dirs, err := walk.GetAll(ctx, f, "does not exist", true, 1)
|
||||
if !f.Features().CanHaveEmptyDirectories {
|
||||
if err != fs.ErrorDirNotFound {
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 0, len(objs)+len(dirs))
|
||||
|
@ -570,7 +608,7 @@ func Run(t *testing.T, opt *Opt) {
|
|||
skipIfNotOk(t)
|
||||
|
||||
// check no files or dirs as pre-requisite
|
||||
fstest.CheckListingWithPrecision(t, remote, []fstest.Item{}, []string{}, fs.GetModifyWindow(ctx, remote))
|
||||
fstest.CheckListingWithPrecision(t, f, []fstest.Item{}, []string{}, fs.GetModifyWindow(ctx, f))
|
||||
|
||||
for _, test := range []struct {
|
||||
name string
|
||||
|
@ -604,16 +642,16 @@ func Run(t *testing.T, opt *Opt) {
|
|||
fileName := encoder.Standard.Encode(test.path)
|
||||
dirName := fileName
|
||||
t.Logf("testing %q", fileName)
|
||||
assert.NoError(t, remote.Mkdir(ctx, dirName))
|
||||
assert.NoError(t, f.Mkdir(ctx, dirName))
|
||||
file := fstest.Item{
|
||||
ModTime: time.Now(),
|
||||
Path: dirName + "/" + fileName, // test creating a file and dir with that name
|
||||
}
|
||||
_, o := testPut(context.Background(), t, remote, &file)
|
||||
fstest.CheckListingWithPrecision(t, remote, []fstest.Item{file}, []string{dirName}, fs.GetModifyWindow(ctx, remote))
|
||||
_, o := testPut(context.Background(), t, f, &file)
|
||||
fstest.CheckListingWithPrecision(t, f, []fstest.Item{file}, []string{dirName}, fs.GetModifyWindow(ctx, f))
|
||||
assert.NoError(t, o.Remove(ctx))
|
||||
assert.NoError(t, remote.Rmdir(ctx, dirName))
|
||||
fstest.CheckListingWithPrecision(t, remote, []fstest.Item{}, []string{}, fs.GetModifyWindow(ctx, remote))
|
||||
assert.NoError(t, f.Rmdir(ctx, dirName))
|
||||
fstest.CheckListingWithPrecision(t, f, []fstest.Item{}, []string{}, fs.GetModifyWindow(ctx, f))
|
||||
})
|
||||
}
|
||||
})
|
||||
|
@ -622,11 +660,11 @@ func Run(t *testing.T, opt *Opt) {
|
|||
t.Run("FsNewObjectNotFound", func(t *testing.T) {
|
||||
skipIfNotOk(t)
|
||||
// Object in an existing directory
|
||||
o, err := remote.NewObject(ctx, "potato")
|
||||
o, err := f.NewObject(ctx, "potato")
|
||||
assert.Nil(t, o)
|
||||
assert.Equal(t, fs.ErrorObjectNotFound, err)
|
||||
// Now try an object in a non existing directory
|
||||
o, err = remote.NewObject(ctx, "directory/not/found/potato")
|
||||
o, err = f.NewObject(ctx, "directory/not/found/potato")
|
||||
assert.Nil(t, o)
|
||||
assert.Equal(t, fs.ErrorObjectNotFound, err)
|
||||
})
|
||||
|
@ -653,11 +691,11 @@ func Run(t *testing.T, opt *Opt) {
|
|||
in := io.MultiReader(buf, er)
|
||||
|
||||
obji := object.NewStaticObjectInfo(file2.Path, file2.ModTime, 2*N, true, nil, nil)
|
||||
_, err := remote.Put(ctx, in, obji)
|
||||
_, err := f.Put(ctx, in, obji)
|
||||
// assert.Nil(t, obj) - FIXME some remotes return the object even on nil
|
||||
assert.NotNil(t, err)
|
||||
|
||||
obj, err := remote.NewObject(ctx, file2.Path)
|
||||
obj, err := f.NewObject(ctx, file2.Path)
|
||||
assert.Nil(t, obj)
|
||||
assert.Equal(t, fs.ErrorObjectNotFound, err)
|
||||
})
|
||||
|
@ -665,7 +703,7 @@ func Run(t *testing.T, opt *Opt) {
|
|||
t.Run("FsPutZeroLength", func(t *testing.T) {
|
||||
skipIfNotOk(t)
|
||||
|
||||
TestPutLarge(ctx, t, remote, &fstest.Item{
|
||||
TestPutLarge(ctx, t, f, &fstest.Item{
|
||||
ModTime: fstest.Time("2001-02-03T04:05:06.499999999Z"),
|
||||
Path: fmt.Sprintf("zero-length-file"),
|
||||
Size: int64(0),
|
||||
|
@ -674,7 +712,7 @@ func Run(t *testing.T, opt *Opt) {
|
|||
|
||||
t.Run("FsOpenWriterAt", func(t *testing.T) {
|
||||
skipIfNotOk(t)
|
||||
openWriterAt := remote.Features().OpenWriterAt
|
||||
openWriterAt := f.Features().OpenWriterAt
|
||||
if openWriterAt == nil {
|
||||
t.Skip("FS has no OpenWriterAt interface")
|
||||
}
|
||||
|
@ -695,11 +733,11 @@ func Run(t *testing.T, opt *Opt) {
|
|||
|
||||
assert.NoError(t, out.Close())
|
||||
|
||||
obj := findObject(ctx, t, remote, path)
|
||||
obj := findObject(ctx, t, f, path)
|
||||
assert.Equal(t, "abcdefghi", readObject(ctx, t, obj, -1), "contents of file differ")
|
||||
|
||||
assert.NoError(t, obj.Remove(ctx))
|
||||
assert.NoError(t, remote.Rmdir(ctx, "writer-at-subdir"))
|
||||
assert.NoError(t, f.Rmdir(ctx, "writer-at-subdir"))
|
||||
})
|
||||
|
||||
// TestFsChangeNotify tests that changes are properly
|
||||
|
@ -710,12 +748,12 @@ func Run(t *testing.T, opt *Opt) {
|
|||
skipIfNotOk(t)
|
||||
|
||||
// Check have ChangeNotify
|
||||
doChangeNotify := remote.Features().ChangeNotify
|
||||
doChangeNotify := f.Features().ChangeNotify
|
||||
if doChangeNotify == nil {
|
||||
t.Skip("FS has no ChangeNotify interface")
|
||||
}
|
||||
|
||||
err := operations.Mkdir(ctx, remote, "dir")
|
||||
err := operations.Mkdir(ctx, f, "dir")
|
||||
require.NoError(t, err)
|
||||
|
||||
pollInterval := make(chan time.Duration)
|
||||
|
@ -739,7 +777,7 @@ func Run(t *testing.T, opt *Opt) {
|
|||
var dirs []string
|
||||
for _, idx := range []int{1, 3, 2} {
|
||||
dir := fmt.Sprintf("dir/subdir%d", idx)
|
||||
err = operations.Mkdir(ctx, remote, dir)
|
||||
err = operations.Mkdir(ctx, f, dir)
|
||||
require.NoError(t, err)
|
||||
dirs = append(dirs, dir)
|
||||
}
|
||||
|
@ -750,7 +788,7 @@ func Run(t *testing.T, opt *Opt) {
|
|||
ModTime: time.Now(),
|
||||
Path: fmt.Sprintf("dir/file%d", idx),
|
||||
}
|
||||
_, o := testPut(ctx, t, remote, &file)
|
||||
_, o := testPut(ctx, t, f, &file)
|
||||
objs = append(objs, o)
|
||||
}
|
||||
|
||||
|
@ -788,7 +826,7 @@ func Run(t *testing.T, opt *Opt) {
|
|||
}
|
||||
dirs = append(dirs, "dir")
|
||||
for _, dir := range dirs {
|
||||
assert.NoError(t, remote.Rmdir(ctx, dir))
|
||||
assert.NoError(t, f.Rmdir(ctx, dir))
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -797,9 +835,9 @@ func Run(t *testing.T, opt *Opt) {
|
|||
// Tests that require file1, file2 are within this
|
||||
t.Run("FsPutFiles", func(t *testing.T) {
|
||||
skipIfNotOk(t)
|
||||
file1Contents, _ = testPut(ctx, t, remote, &file1)
|
||||
/* file2Contents = */ testPut(ctx, t, remote, &file2)
|
||||
file1Contents, _ = testPut(ctx, t, remote, &file1)
|
||||
file1Contents, _ = testPut(ctx, t, f, &file1)
|
||||
/* file2Contents = */ testPut(ctx, t, f, &file2)
|
||||
file1Contents, _ = testPutMimeType(ctx, t, f, &file1, file1MimeType)
|
||||
// Note that the next test will check there are no duplicated file names
|
||||
|
||||
// TestFsListDirFile2 tests the files are correctly uploaded by doing
|
||||
|
@ -809,9 +847,9 @@ func Run(t *testing.T, opt *Opt) {
|
|||
list := func(dir string, expectedDirNames, expectedObjNames []string) {
|
||||
var objNames, dirNames []string
|
||||
for i := 1; i <= *fstest.ListRetries; i++ {
|
||||
objs, dirs, err := walk.GetAll(ctx, remote, dir, true, 1)
|
||||
objs, dirs, err := walk.GetAll(ctx, f, dir, true, 1)
|
||||
if errors.Cause(err) == fs.ErrorDirNotFound {
|
||||
objs, dirs, err = walk.GetAll(ctx, remote, dir, true, 1)
|
||||
objs, dirs, err = walk.GetAll(ctx, f, dir, true, 1)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
objNames = objsToNames(objs)
|
||||
|
@ -857,7 +895,7 @@ func Run(t *testing.T, opt *Opt) {
|
|||
// Test the files are all there with walk.ListR recursive listings
|
||||
t.Run("FsListR", func(t *testing.T) {
|
||||
skipIfNotOk(t)
|
||||
objs, dirs, err := walk.GetAll(ctx, remote, "", true, -1)
|
||||
objs, dirs, err := walk.GetAll(ctx, f, "", true, -1)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []string{
|
||||
"hello? sausage",
|
||||
|
@ -875,7 +913,7 @@ func Run(t *testing.T, opt *Opt) {
|
|||
// walk.ListR recursive listings on a sub dir
|
||||
t.Run("FsListRSubdir", func(t *testing.T) {
|
||||
skipIfNotOk(t)
|
||||
objs, dirs, err := walk.GetAll(ctx, remote, path.Dir(path.Dir(path.Dir(path.Dir(file2.Path)))), true, -1)
|
||||
objs, dirs, err := walk.GetAll(ctx, f, path.Dir(path.Dir(path.Dir(path.Dir(file2.Path)))), true, -1)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []string{
|
||||
"hello? sausage/êé",
|
||||
|
@ -914,7 +952,7 @@ func Run(t *testing.T, opt *Opt) {
|
|||
for i := 0; i < 2; i++ {
|
||||
dir, _ := path.Split(fileName)
|
||||
dir = dir[:len(dir)-1]
|
||||
objs, dirs, err = walk.GetAll(ctx, remote, dir, true, -1)
|
||||
objs, dirs, err = walk.GetAll(ctx, f, dir, true, -1)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
require.Len(t, objs, 1)
|
||||
|
@ -932,7 +970,7 @@ func Run(t *testing.T, opt *Opt) {
|
|||
// TestFsListLevel2 tests List works for 2 levels
|
||||
TestFsListLevel2 := func(t *testing.T) {
|
||||
skipIfNotOk(t)
|
||||
objs, dirs, err := walk.GetAll(ctx, remote, "", true, 2)
|
||||
objs, dirs, err := walk.GetAll(ctx, f, "", true, 2)
|
||||
if err == fs.ErrorLevelNotSupported {
|
||||
return
|
||||
}
|
||||
|
@ -951,27 +989,27 @@ func Run(t *testing.T, opt *Opt) {
|
|||
// TestFsListFile1 tests file present
|
||||
t.Run("FsListFile1", func(t *testing.T) {
|
||||
skipIfNotOk(t)
|
||||
fstest.CheckListing(t, remote, []fstest.Item{file1, file2})
|
||||
fstest.CheckListing(t, f, []fstest.Item{file1, file2})
|
||||
})
|
||||
|
||||
// TestFsNewObject tests NewObject
|
||||
t.Run("FsNewObject", func(t *testing.T) {
|
||||
skipIfNotOk(t)
|
||||
obj := findObject(ctx, t, remote, file1.Path)
|
||||
file1.Check(t, obj, remote.Precision())
|
||||
obj := findObject(ctx, t, f, file1.Path)
|
||||
file1.Check(t, obj, f.Precision())
|
||||
})
|
||||
|
||||
// TestFsListFile1and2 tests two files present
|
||||
t.Run("FsListFile1and2", func(t *testing.T) {
|
||||
skipIfNotOk(t)
|
||||
fstest.CheckListing(t, remote, []fstest.Item{file1, file2})
|
||||
fstest.CheckListing(t, f, []fstest.Item{file1, file2})
|
||||
})
|
||||
|
||||
// TestFsNewObjectDir tests NewObject on a directory which should produce an error
|
||||
t.Run("FsNewObjectDir", func(t *testing.T) {
|
||||
skipIfNotOk(t)
|
||||
dir := path.Dir(file2.Path)
|
||||
obj, err := remote.NewObject(ctx, dir)
|
||||
obj, err := f.NewObject(ctx, dir)
|
||||
assert.Nil(t, obj)
|
||||
assert.NotNil(t, err)
|
||||
})
|
||||
|
@ -981,7 +1019,7 @@ func Run(t *testing.T, opt *Opt) {
|
|||
skipIfNotOk(t)
|
||||
|
||||
// Check have Purge
|
||||
doPurge := remote.Features().Purge
|
||||
doPurge := f.Features().Purge
|
||||
if doPurge == nil {
|
||||
t.Skip("FS has no Purge interface")
|
||||
}
|
||||
|
@ -991,26 +1029,26 @@ func Run(t *testing.T, opt *Opt) {
|
|||
ModTime: fstest.Time("2001-02-03T04:05:06.499999999Z"),
|
||||
Path: "dirToPurge/fileToPurge.txt",
|
||||
}
|
||||
_, _ = testPut(ctx, t, remote, &fileToPurge)
|
||||
_, _ = testPut(ctx, t, f, &fileToPurge)
|
||||
|
||||
fstest.CheckListingWithPrecision(t, remote, []fstest.Item{file1, file2, fileToPurge}, []string{
|
||||
fstest.CheckListingWithPrecision(t, f, []fstest.Item{file1, file2, fileToPurge}, []string{
|
||||
"dirToPurge",
|
||||
"hello? sausage",
|
||||
"hello? sausage/êé",
|
||||
"hello? sausage/êé/Hello, 世界",
|
||||
"hello? sausage/êé/Hello, 世界/ \" ' @ < > & ? + ≠",
|
||||
}, fs.GetModifyWindow(ctx, remote))
|
||||
}, fs.GetModifyWindow(ctx, f))
|
||||
|
||||
// Now purge it
|
||||
err = operations.Purge(ctx, remote, "dirToPurge")
|
||||
err = operations.Purge(ctx, f, "dirToPurge")
|
||||
require.NoError(t, err)
|
||||
|
||||
fstest.CheckListingWithPrecision(t, remote, []fstest.Item{file1, file2}, []string{
|
||||
fstest.CheckListingWithPrecision(t, f, []fstest.Item{file1, file2}, []string{
|
||||
"hello? sausage",
|
||||
"hello? sausage/êé",
|
||||
"hello? sausage/êé/Hello, 世界",
|
||||
"hello? sausage/êé/Hello, 世界/ \" ' @ < > & ? + ≠",
|
||||
}, fs.GetModifyWindow(ctx, remote))
|
||||
}, fs.GetModifyWindow(ctx, f))
|
||||
})
|
||||
|
||||
// TestFsCopy tests Copy
|
||||
|
@ -1018,7 +1056,7 @@ func Run(t *testing.T, opt *Opt) {
|
|||
skipIfNotOk(t)
|
||||
|
||||
// Check have Copy
|
||||
doCopy := remote.Features().Copy
|
||||
doCopy := f.Features().Copy
|
||||
if doCopy == nil {
|
||||
t.Skip("FS has no Copier interface")
|
||||
}
|
||||
|
@ -1028,7 +1066,7 @@ func Run(t *testing.T, opt *Opt) {
|
|||
file2Copy.Path += "-copy"
|
||||
|
||||
// do the copy
|
||||
src := findObject(ctx, t, remote, file2.Path)
|
||||
src := findObject(ctx, t, f, file2.Path)
|
||||
dst, err := doCopy(ctx, src, file2Copy.Path)
|
||||
if err == fs.ErrorCantCopy {
|
||||
t.Skip("FS can't copy")
|
||||
|
@ -1036,7 +1074,7 @@ func Run(t *testing.T, opt *Opt) {
|
|||
require.NoError(t, err, fmt.Sprintf("Error: %#v", err))
|
||||
|
||||
// check file exists in new listing
|
||||
fstest.CheckListing(t, remote, []fstest.Item{file1, file2, file2Copy})
|
||||
fstest.CheckListing(t, f, []fstest.Item{file1, file2, file2Copy})
|
||||
|
||||
// Check dst lightly - list above has checked ModTime/Hashes
|
||||
assert.Equal(t, file2Copy.Path, dst.Remote())
|
||||
|
@ -1052,7 +1090,7 @@ func Run(t *testing.T, opt *Opt) {
|
|||
skipIfNotOk(t)
|
||||
|
||||
// Check have Move
|
||||
doMove := remote.Features().Move
|
||||
doMove := f.Features().Move
|
||||
if doMove == nil {
|
||||
t.Skip("FS has no Mover interface")
|
||||
}
|
||||
|
@ -1067,14 +1105,14 @@ func Run(t *testing.T, opt *Opt) {
|
|||
// check happy path, i.e. no naming conflicts when rename and move are two
|
||||
// separate operations
|
||||
file2Move.Path = "other.txt"
|
||||
src := findObject(ctx, t, remote, file2.Path)
|
||||
src := findObject(ctx, t, f, file2.Path)
|
||||
dst, err := doMove(ctx, src, file2Move.Path)
|
||||
if err == fs.ErrorCantMove {
|
||||
t.Skip("FS can't move")
|
||||
}
|
||||
require.NoError(t, err)
|
||||
// check file exists in new listing
|
||||
fstest.CheckListing(t, remote, []fstest.Item{file1, file2Move})
|
||||
fstest.CheckListing(t, f, []fstest.Item{file1, file2Move})
|
||||
// Check dst lightly - list above has checked ModTime/Hashes
|
||||
assert.Equal(t, file2Move.Path, dst.Remote())
|
||||
// 1: file name.txt
|
||||
|
@ -1082,30 +1120,30 @@ func Run(t *testing.T, opt *Opt) {
|
|||
|
||||
// Check conflict on "rename, then move"
|
||||
file1Move.Path = "moveTest/other.txt"
|
||||
src = findObject(ctx, t, remote, file1.Path)
|
||||
src = findObject(ctx, t, f, file1.Path)
|
||||
_, err = doMove(ctx, src, file1Move.Path)
|
||||
require.NoError(t, err)
|
||||
fstest.CheckListing(t, remote, []fstest.Item{file1Move, file2Move})
|
||||
fstest.CheckListing(t, f, []fstest.Item{file1Move, file2Move})
|
||||
// 1: moveTest/other.txt
|
||||
// 2: other.txt
|
||||
|
||||
// Check conflict on "move, then rename"
|
||||
src = findObject(ctx, t, remote, file1Move.Path)
|
||||
src = findObject(ctx, t, f, file1Move.Path)
|
||||
_, err = doMove(ctx, src, file1.Path)
|
||||
require.NoError(t, err)
|
||||
fstest.CheckListing(t, remote, []fstest.Item{file1, file2Move})
|
||||
fstest.CheckListing(t, f, []fstest.Item{file1, file2Move})
|
||||
// 1: file name.txt
|
||||
// 2: other.txt
|
||||
|
||||
src = findObject(ctx, t, remote, file2Move.Path)
|
||||
src = findObject(ctx, t, f, file2Move.Path)
|
||||
_, err = doMove(ctx, src, file2.Path)
|
||||
require.NoError(t, err)
|
||||
fstest.CheckListing(t, remote, []fstest.Item{file1, file2})
|
||||
fstest.CheckListing(t, f, []fstest.Item{file1, file2})
|
||||
// 1: file name.txt
|
||||
// 2: hello sausage?/../z.txt
|
||||
|
||||
// Tidy up moveTest directory
|
||||
require.NoError(t, remote.Rmdir(ctx, "moveTest"))
|
||||
require.NoError(t, f.Rmdir(ctx, "moveTest"))
|
||||
})
|
||||
|
||||
// Move src to this remote using server-side move operations.
|
||||
|
@ -1123,13 +1161,13 @@ func Run(t *testing.T, opt *Opt) {
|
|||
skipIfNotOk(t)
|
||||
|
||||
// Check have DirMove
|
||||
doDirMove := remote.Features().DirMove
|
||||
doDirMove := f.Features().DirMove
|
||||
if doDirMove == nil {
|
||||
t.Skip("FS has no DirMover interface")
|
||||
}
|
||||
|
||||
// Check it can't move onto itself
|
||||
err := doDirMove(ctx, remote, "", "")
|
||||
err := doDirMove(ctx, f, "", "")
|
||||
require.Equal(t, fs.ErrorDirExists, err)
|
||||
|
||||
// new remote
|
||||
|
@ -1139,12 +1177,12 @@ func Run(t *testing.T, opt *Opt) {
|
|||
|
||||
const newName = "new_name/sub_new_name"
|
||||
// try the move
|
||||
err = newRemote.Features().DirMove(ctx, remote, "", newName)
|
||||
err = newRemote.Features().DirMove(ctx, f, "", newName)
|
||||
require.NoError(t, err)
|
||||
|
||||
// check remotes
|
||||
// remote should not exist here
|
||||
_, err = remote.List(ctx, "")
|
||||
_, err = f.List(ctx, "")
|
||||
assert.Equal(t, fs.ErrorDirNotFound, errors.Cause(err))
|
||||
//fstest.CheckListingWithPrecision(t, remote, []fstest.Item{}, []string{}, remote.Precision())
|
||||
file1Copy := file1
|
||||
|
@ -1165,12 +1203,12 @@ func Run(t *testing.T, opt *Opt) {
|
|||
require.NoError(t, err)
|
||||
|
||||
// check remotes
|
||||
fstest.CheckListingWithPrecision(t, remote, []fstest.Item{file2, file1}, []string{
|
||||
fstest.CheckListingWithPrecision(t, f, []fstest.Item{file2, file1}, []string{
|
||||
"hello? sausage",
|
||||
"hello? sausage/êé",
|
||||
"hello? sausage/êé/Hello, 世界",
|
||||
"hello? sausage/êé/Hello, 世界/ \" ' @ < > & ? + ≠",
|
||||
}, remote.Precision())
|
||||
}, f.Precision())
|
||||
fstest.CheckListingWithPrecision(t, newRemote, []fstest.Item{}, []string{
|
||||
"new_name",
|
||||
}, newRemote.Precision())
|
||||
|
@ -1179,17 +1217,17 @@ func Run(t *testing.T, opt *Opt) {
|
|||
// TestFsRmdirFull tests removing a non empty directory
|
||||
t.Run("FsRmdirFull", func(t *testing.T) {
|
||||
skipIfNotOk(t)
|
||||
if isBucketBasedButNotRoot(remote) {
|
||||
if isBucketBasedButNotRoot(f) {
|
||||
t.Skip("Skipping test as non root bucket based remote")
|
||||
}
|
||||
err := remote.Rmdir(ctx, "")
|
||||
err := f.Rmdir(ctx, "")
|
||||
require.Error(t, err, "Expecting error on RMdir on non empty remote")
|
||||
})
|
||||
|
||||
// TestFsPrecision tests the Precision of the Fs
|
||||
t.Run("FsPrecision", func(t *testing.T) {
|
||||
skipIfNotOk(t)
|
||||
precision := remote.Precision()
|
||||
precision := f.Precision()
|
||||
if precision == fs.ModTimeNotSupported {
|
||||
return
|
||||
}
|
||||
|
@ -1202,7 +1240,7 @@ func Run(t *testing.T, opt *Opt) {
|
|||
// TestObjectString tests the Object String method
|
||||
t.Run("ObjectString", func(t *testing.T) {
|
||||
skipIfNotOk(t)
|
||||
obj := findObject(ctx, t, remote, file1.Path)
|
||||
obj := findObject(ctx, t, f, file1.Path)
|
||||
assert.Equal(t, file1.Path, obj.String())
|
||||
if opt.NilObject != nil {
|
||||
assert.Equal(t, "<nil>", opt.NilObject.String())
|
||||
|
@ -1212,13 +1250,13 @@ func Run(t *testing.T, opt *Opt) {
|
|||
// TestObjectFs tests the object can be found
|
||||
t.Run("ObjectFs", func(t *testing.T) {
|
||||
skipIfNotOk(t)
|
||||
obj := findObject(ctx, t, remote, file1.Path)
|
||||
obj := findObject(ctx, t, f, file1.Path)
|
||||
// If this is set we don't do the direct comparison of
|
||||
// the Fs from the object as it may be different
|
||||
if opt.SkipFsMatch {
|
||||
return
|
||||
}
|
||||
testRemote := remote
|
||||
testRemote := f
|
||||
if obj.Fs() != testRemote {
|
||||
// Check to see if this wraps something else
|
||||
if doUnWrap := testRemote.Features().UnWrap; doUnWrap != nil {
|
||||
|
@ -1231,38 +1269,44 @@ func Run(t *testing.T, opt *Opt) {
|
|||
// TestObjectRemote tests the Remote is correct
|
||||
t.Run("ObjectRemote", func(t *testing.T) {
|
||||
skipIfNotOk(t)
|
||||
obj := findObject(ctx, t, remote, file1.Path)
|
||||
obj := findObject(ctx, t, f, file1.Path)
|
||||
assert.Equal(t, file1.Path, obj.Remote())
|
||||
})
|
||||
|
||||
// TestObjectHashes checks all the hashes the object supports
|
||||
t.Run("ObjectHashes", func(t *testing.T) {
|
||||
skipIfNotOk(t)
|
||||
obj := findObject(ctx, t, remote, file1.Path)
|
||||
obj := findObject(ctx, t, f, file1.Path)
|
||||
file1.CheckHashes(t, obj)
|
||||
})
|
||||
|
||||
// TestObjectModTime tests the ModTime of the object is correct
|
||||
TestObjectModTime := func(t *testing.T) {
|
||||
skipIfNotOk(t)
|
||||
obj := findObject(ctx, t, remote, file1.Path)
|
||||
file1.CheckModTime(t, obj, obj.ModTime(ctx), remote.Precision())
|
||||
obj := findObject(ctx, t, f, file1.Path)
|
||||
file1.CheckModTime(t, obj, obj.ModTime(ctx), f.Precision())
|
||||
}
|
||||
t.Run("ObjectModTime", TestObjectModTime)
|
||||
|
||||
// TestObjectMimeType tests the MimeType of the object is correct
|
||||
t.Run("ObjectMimeType", func(t *testing.T) {
|
||||
skipIfNotOk(t)
|
||||
obj := findObject(ctx, t, remote, file1.Path)
|
||||
features := f.Features()
|
||||
obj := findObject(ctx, t, f, file1.Path)
|
||||
do, ok := obj.(fs.MimeTyper)
|
||||
require.Equal(t, features.ReadMimeType, ok, "mismatch between Object.MimeType and Features.ReadMimeType")
|
||||
if !ok {
|
||||
t.Skip("MimeType method not supported")
|
||||
}
|
||||
mimeType := do.MimeType(ctx)
|
||||
if strings.ContainsRune(mimeType, ';') {
|
||||
assert.Equal(t, "text/plain; charset=utf-8", mimeType)
|
||||
if features.WriteMimeType {
|
||||
assert.Equal(t, file1MimeType, mimeType, "can read and write mime types but failed")
|
||||
} else {
|
||||
assert.Equal(t, "text/plain", mimeType)
|
||||
if strings.ContainsRune(mimeType, ';') {
|
||||
assert.Equal(t, "text/plain; charset=utf-8", mimeType)
|
||||
} else {
|
||||
assert.Equal(t, "text/plain", mimeType)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -1270,7 +1314,7 @@ func Run(t *testing.T, opt *Opt) {
|
|||
t.Run("ObjectSetModTime", func(t *testing.T) {
|
||||
skipIfNotOk(t)
|
||||
newModTime := fstest.Time("2011-12-13T14:15:16.999999999Z")
|
||||
obj := findObject(ctx, t, remote, file1.Path)
|
||||
obj := findObject(ctx, t, f, file1.Path)
|
||||
err := obj.SetModTime(ctx, newModTime)
|
||||
if err == fs.ErrorCantSetModTime || err == fs.ErrorCantSetModTimeWithoutDelete {
|
||||
t.Log(err)
|
||||
|
@ -1278,7 +1322,7 @@ func Run(t *testing.T, opt *Opt) {
|
|||
}
|
||||
require.NoError(t, err)
|
||||
file1.ModTime = newModTime
|
||||
file1.CheckModTime(t, obj, obj.ModTime(ctx), remote.Precision())
|
||||
file1.CheckModTime(t, obj, obj.ModTime(ctx), f.Precision())
|
||||
// And make a new object and read it from there too
|
||||
TestObjectModTime(t)
|
||||
})
|
||||
|
@ -1286,21 +1330,21 @@ func Run(t *testing.T, opt *Opt) {
|
|||
// TestObjectSize tests that Size works
|
||||
t.Run("ObjectSize", func(t *testing.T) {
|
||||
skipIfNotOk(t)
|
||||
obj := findObject(ctx, t, remote, file1.Path)
|
||||
obj := findObject(ctx, t, f, file1.Path)
|
||||
assert.Equal(t, file1.Size, obj.Size())
|
||||
})
|
||||
|
||||
// TestObjectOpen tests that Open works
|
||||
t.Run("ObjectOpen", func(t *testing.T) {
|
||||
skipIfNotOk(t)
|
||||
obj := findObject(ctx, t, remote, file1.Path)
|
||||
obj := findObject(ctx, t, f, file1.Path)
|
||||
assert.Equal(t, file1Contents, readObject(ctx, t, obj, -1), "contents of file1 differ")
|
||||
})
|
||||
|
||||
// TestObjectOpenSeek tests that Open works with SeekOption
|
||||
t.Run("ObjectOpenSeek", func(t *testing.T) {
|
||||
skipIfNotOk(t)
|
||||
obj := findObject(ctx, t, remote, file1.Path)
|
||||
obj := findObject(ctx, t, f, file1.Path)
|
||||
assert.Equal(t, file1Contents[50:], readObject(ctx, t, obj, -1, &fs.SeekOption{Offset: 50}), "contents of file1 differ after seek")
|
||||
})
|
||||
|
||||
|
@ -1309,7 +1353,7 @@ func Run(t *testing.T, opt *Opt) {
|
|||
// go test -v -run 'TestIntegration/Test(Setup|Init|FsMkdir|FsPutFile1|FsPutFile2|FsUpdateFile1|ObjectOpenRange)$'
|
||||
t.Run("ObjectOpenRange", func(t *testing.T) {
|
||||
skipIfNotOk(t)
|
||||
obj := findObject(ctx, t, remote, file1.Path)
|
||||
obj := findObject(ctx, t, f, file1.Path)
|
||||
for _, test := range []struct {
|
||||
ro fs.RangeOption
|
||||
wantStart, wantEnd int
|
||||
|
@ -1330,7 +1374,7 @@ func Run(t *testing.T, opt *Opt) {
|
|||
// TestObjectPartialRead tests that reading only part of the object does the correct thing
|
||||
t.Run("ObjectPartialRead", func(t *testing.T) {
|
||||
skipIfNotOk(t)
|
||||
obj := findObject(ctx, t, remote, file1.Path)
|
||||
obj := findObject(ctx, t, f, file1.Path)
|
||||
assert.Equal(t, file1Contents[:50], readObject(ctx, t, obj, 50), "contents of file1 differ after limited read")
|
||||
})
|
||||
|
||||
|
@ -1343,18 +1387,18 @@ func Run(t *testing.T, opt *Opt) {
|
|||
in := io.TeeReader(buf, hash)
|
||||
|
||||
file1.Size = int64(buf.Len())
|
||||
obj := findObject(ctx, t, remote, file1.Path)
|
||||
obj := findObject(ctx, t, f, file1.Path)
|
||||
obji := object.NewStaticObjectInfo(file1.Path, file1.ModTime, int64(len(contents)), true, nil, obj.Fs())
|
||||
err := obj.Update(ctx, in, obji)
|
||||
require.NoError(t, err)
|
||||
file1.Hashes = hash.Sums()
|
||||
|
||||
// check the object has been updated
|
||||
file1.Check(t, obj, remote.Precision())
|
||||
file1.Check(t, obj, f.Precision())
|
||||
|
||||
// Re-read the object and check again
|
||||
obj = findObject(ctx, t, remote, file1.Path)
|
||||
file1.Check(t, obj, remote.Precision())
|
||||
obj = findObject(ctx, t, f, file1.Path)
|
||||
file1.Check(t, obj, f.Precision())
|
||||
|
||||
// check contents correct
|
||||
assert.Equal(t, contents, readObject(ctx, t, obj, -1), "contents of updated file1 differ")
|
||||
|
@ -1364,7 +1408,7 @@ func Run(t *testing.T, opt *Opt) {
|
|||
// TestObjectStorable tests that Storable works
|
||||
t.Run("ObjectStorable", func(t *testing.T) {
|
||||
skipIfNotOk(t)
|
||||
obj := findObject(ctx, t, remote, file1.Path)
|
||||
obj := findObject(ctx, t, f, file1.Path)
|
||||
require.NotNil(t, !obj.Storable(), "Expecting object to be storable")
|
||||
})
|
||||
|
||||
|
@ -1398,7 +1442,7 @@ func Run(t *testing.T, opt *Opt) {
|
|||
|
||||
// Test that things work from the root
|
||||
t.Run("FromRoot", func(t *testing.T) {
|
||||
if features := remote.Features(); features.BucketBased && !features.BucketBasedRootOK {
|
||||
if features := f.Features(); features.BucketBased && !features.BucketBasedRootOK {
|
||||
t.Skip("Can't list from root on this remote")
|
||||
}
|
||||
|
||||
|
@ -1500,7 +1544,7 @@ func Run(t *testing.T, opt *Opt) {
|
|||
t.Run("PublicLink", func(t *testing.T) {
|
||||
skipIfNotOk(t)
|
||||
|
||||
doPublicLink := remote.Features().PublicLink
|
||||
doPublicLink := f.Features().PublicLink
|
||||
if doPublicLink == nil {
|
||||
t.Skip("FS has no PublicLinker interface")
|
||||
}
|
||||
|
@ -1561,7 +1605,7 @@ func Run(t *testing.T, opt *Opt) {
|
|||
// TestSetTier tests SetTier and GetTier functionality
|
||||
t.Run("SetTier", func(t *testing.T) {
|
||||
skipIfNotSetTier(t)
|
||||
obj := findObject(ctx, t, remote, file1.Path)
|
||||
obj := findObject(ctx, t, f, file1.Path)
|
||||
setter, ok := obj.(fs.SetTierer)
|
||||
assert.NotNil(t, ok)
|
||||
getter, ok := obj.(fs.GetTierer)
|
||||
|
@ -1585,11 +1629,11 @@ func Run(t *testing.T, opt *Opt) {
|
|||
if opt.SkipObjectCheckWrap {
|
||||
t.Skip("Skipping FsCheckWrap on this Fs")
|
||||
}
|
||||
ft := new(fs.Features).Fill(ctx, remote)
|
||||
ft := new(fs.Features).Fill(ctx, f)
|
||||
if ft.UnWrap == nil {
|
||||
t.Skip("Not a wrapping Fs")
|
||||
}
|
||||
obj := findObject(ctx, t, remote, file1.Path)
|
||||
obj := findObject(ctx, t, f, file1.Path)
|
||||
_, unsupported := fs.ObjectOptionalInterfaces(obj)
|
||||
for _, name := range unsupported {
|
||||
if !stringsContains(name, opt.UnimplementableObjectMethods) {
|
||||
|
@ -1602,11 +1646,11 @@ func Run(t *testing.T, opt *Opt) {
|
|||
t.Run("ObjectRemove", func(t *testing.T) {
|
||||
skipIfNotOk(t)
|
||||
// remove file1
|
||||
obj := findObject(ctx, t, remote, file1.Path)
|
||||
obj := findObject(ctx, t, f, file1.Path)
|
||||
err := obj.Remove(ctx)
|
||||
require.NoError(t, err)
|
||||
// check listing without modtime as TestPublicLink may change the modtime
|
||||
fstest.CheckListingWithPrecision(t, remote, []fstest.Item{file2}, nil, fs.ModTimeNotSupported)
|
||||
fstest.CheckListingWithPrecision(t, f, []fstest.Item{file2}, nil, fs.ModTimeNotSupported)
|
||||
})
|
||||
|
||||
// TestAbout tests the About optional interface
|
||||
|
@ -1614,7 +1658,7 @@ func Run(t *testing.T, opt *Opt) {
|
|||
skipIfNotOk(t)
|
||||
|
||||
// Check have About
|
||||
doAbout := remote.Features().About
|
||||
doAbout := f.Features().About
|
||||
if doAbout == nil {
|
||||
t.Skip("FS does not support About")
|
||||
}
|
||||
|
@ -1633,7 +1677,7 @@ func Run(t *testing.T, opt *Opt) {
|
|||
// close to the end of suite. (See fs/operations/xtra_operations_test.go)
|
||||
t.Run("FsPutStream", func(t *testing.T) {
|
||||
skipIfNotOk(t)
|
||||
if remote.Features().PutStream == nil {
|
||||
if f.Features().PutStream == nil {
|
||||
t.Skip("FS has no PutStream interface")
|
||||
}
|
||||
|
||||
|
@ -1658,15 +1702,15 @@ func Run(t *testing.T, opt *Opt) {
|
|||
|
||||
file.Size = -1
|
||||
obji := object.NewStaticObjectInfo(file.Path, file.ModTime, file.Size, true, nil, nil)
|
||||
obj, err = remote.Features().PutStream(ctx, in, obji)
|
||||
obj, err = f.Features().PutStream(ctx, in, obji)
|
||||
return err
|
||||
})
|
||||
file.Hashes = uploadHash.Sums()
|
||||
file.Size = int64(contentSize) // use correct size when checking
|
||||
file.Check(t, obj, remote.Precision())
|
||||
file.Check(t, obj, f.Precision())
|
||||
// Re-read the object and check again
|
||||
obj = findObject(ctx, t, remote, file.Path)
|
||||
file.Check(t, obj, remote.Precision())
|
||||
obj = findObject(ctx, t, f, file.Path)
|
||||
file.Check(t, obj, f.Precision())
|
||||
require.NoError(t, obj.Remove(ctx))
|
||||
})
|
||||
}
|
||||
|
@ -1675,10 +1719,10 @@ func Run(t *testing.T, opt *Opt) {
|
|||
// TestInternal calls InternalTest() on the Fs
|
||||
t.Run("Internal", func(t *testing.T) {
|
||||
skipIfNotOk(t)
|
||||
if it, ok := remote.(InternalTester); ok {
|
||||
if it, ok := f.(InternalTester); ok {
|
||||
it.InternalTest(t)
|
||||
} else {
|
||||
t.Skipf("%T does not implement InternalTester", remote)
|
||||
t.Skipf("%T does not implement InternalTester", f)
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -1693,12 +1737,12 @@ func Run(t *testing.T, opt *Opt) {
|
|||
t.Skip("not running with -short")
|
||||
}
|
||||
|
||||
setUploadChunkSizer, _ := remote.(SetUploadChunkSizer)
|
||||
setUploadChunkSizer, _ := f.(SetUploadChunkSizer)
|
||||
if setUploadChunkSizer == nil {
|
||||
t.Skipf("%T does not implement SetUploadChunkSizer", remote)
|
||||
t.Skipf("%T does not implement SetUploadChunkSizer", f)
|
||||
}
|
||||
|
||||
setUploadCutoffer, _ := remote.(SetUploadCutoffer)
|
||||
setUploadCutoffer, _ := f.(SetUploadCutoffer)
|
||||
|
||||
minChunkSize := opt.ChunkedUpload.MinChunkSize
|
||||
if minChunkSize < 100 {
|
||||
|
@ -1782,7 +1826,7 @@ func Run(t *testing.T, opt *Opt) {
|
|||
|
||||
for _, fileSize := range testChunks {
|
||||
t.Run(fmt.Sprintf("%d", fileSize), func(t *testing.T) {
|
||||
TestPutLarge(ctx, t, remote, &fstest.Item{
|
||||
TestPutLarge(ctx, t, f, &fstest.Item{
|
||||
ModTime: fstest.Time("2001-02-03T04:05:06.499999999Z"),
|
||||
Path: fmt.Sprintf("chunked-%s-%s.bin", cs.String(), fileSize.String()),
|
||||
Size: int64(fileSize),
|
||||
|
@ -1810,7 +1854,7 @@ func Run(t *testing.T, opt *Opt) {
|
|||
in := bytes.NewBufferString(contents)
|
||||
|
||||
obji := object.NewStaticObjectInfo("unknown-size-put.txt", fstest.Time("2002-02-03T04:05:06.499999999Z"), -1, true, nil, nil)
|
||||
obj, err := remote.Put(ctx, in, obji)
|
||||
obj, err := f.Put(ctx, in, obji)
|
||||
if err == nil {
|
||||
require.NoError(t, obj.Remove(ctx), "successfully uploaded unknown-sized file but failed to remove")
|
||||
}
|
||||
|
@ -1823,7 +1867,7 @@ func Run(t *testing.T, opt *Opt) {
|
|||
Path: "unknown-size-update.txt",
|
||||
}
|
||||
|
||||
testPut(ctx, t, remote, &unknownSizeUpdateFile)
|
||||
testPut(ctx, t, f, &unknownSizeUpdateFile)
|
||||
|
||||
defer func() {
|
||||
assert.Nil(t, recover(), "Object.Update() should not panic when src.Size() == -1")
|
||||
|
@ -1832,7 +1876,7 @@ func Run(t *testing.T, opt *Opt) {
|
|||
newContents := random.String(200)
|
||||
in := bytes.NewBufferString(newContents)
|
||||
|
||||
obj := findObject(ctx, t, remote, unknownSizeUpdateFile.Path)
|
||||
obj := findObject(ctx, t, f, unknownSizeUpdateFile.Path)
|
||||
obji := object.NewStaticObjectInfo(unknownSizeUpdateFile.Path, unknownSizeUpdateFile.ModTime, -1, true, nil, obj.Fs())
|
||||
err := obj.Update(ctx, in, obji)
|
||||
if err == nil {
|
||||
|
@ -1865,16 +1909,16 @@ func Run(t *testing.T, opt *Opt) {
|
|||
})
|
||||
|
||||
// Purge the folder
|
||||
err = operations.Purge(ctx, remote, "")
|
||||
err = operations.Purge(ctx, f, "")
|
||||
if errors.Cause(err) != fs.ErrorDirNotFound {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
purged = true
|
||||
fstest.CheckListing(t, remote, []fstest.Item{})
|
||||
fstest.CheckListing(t, f, []fstest.Item{})
|
||||
|
||||
// Check purging again if not bucket based
|
||||
if !isBucketBasedButNotRoot(remote) {
|
||||
err = operations.Purge(ctx, remote, "")
|
||||
if !isBucketBasedButNotRoot(f) {
|
||||
err = operations.Purge(ctx, f, "")
|
||||
assert.Error(t, err, "Expecting error after on second purge")
|
||||
if errors.Cause(err) != fs.ErrorDirNotFound {
|
||||
t.Log("Warning: this should produce fs.ErrorDirNotFound")
|
||||
|
@ -1885,7 +1929,7 @@ func Run(t *testing.T, opt *Opt) {
|
|||
|
||||
// Check directory is purged
|
||||
if !purged {
|
||||
_ = operations.Purge(ctx, remote, "")
|
||||
_ = operations.Purge(ctx, f, "")
|
||||
}
|
||||
|
||||
// Remove the local directory so we don't clutter up /tmp
|
||||
|
|
Loading…
Reference in New Issue
Block a user