diff --git a/backend/b2/b2.go b/backend/b2/b2.go index 5981a40e8..73b9e700b 100644 --- a/backend/b2/b2.go +++ b/backend/b2/b2.go @@ -1332,7 +1332,11 @@ func (f *Fs) copy(ctx context.Context, dstObj *Object, srcObj *Object, newInfo * if err != nil { return err } - return up.Copy(ctx) + err = up.Copy(ctx) + if err != nil { + return err + } + return dstObj.decodeMetaDataFileInfo(up.info) } dstBucket, dstPath := dstObj.split() diff --git a/backend/b2/b2_internal_test.go b/backend/b2/b2_internal_test.go index 74072d552..34a01eec6 100644 --- a/backend/b2/b2_internal_test.go +++ b/backend/b2/b2_internal_test.go @@ -1,10 +1,15 @@ package b2 import ( + "context" "testing" "time" "github.com/rclone/rclone/fstest" + "github.com/rclone/rclone/fstest/fstests" + "github.com/rclone/rclone/lib/random" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) // Test b2 string encoding @@ -168,3 +173,52 @@ func TestParseTimeString(t *testing.T) { } } + +// The integration tests do a reasonable job of testing the normal +// copy but don't test the chunked copy. +func (f *Fs) InternalTestChunkedCopy(t *testing.T) { + ctx := context.Background() + + contents := random.String(8 * 1024 * 1024) + item := fstest.NewItem("chunked-copy", contents, fstest.Time("2001-05-06T04:05:06.499999999Z")) + src := fstests.PutTestContents(ctx, t, f, &item, contents, true) + defer func() { + assert.NoError(t, src.Remove(ctx)) + }() + + var itemCopy = item + itemCopy.Path += ".copy" + + // Set copy cutoff to mininum value so we make chunks + origCutoff := f.opt.CopyCutoff + f.opt.CopyCutoff = 5 * 1024 * 1024 + defer func() { + f.opt.CopyCutoff = origCutoff + }() + + // Do the copy + dst, err := f.Copy(ctx, src, itemCopy.Path) + require.NoError(t, err) + defer func() { + assert.NoError(t, dst.Remove(ctx)) + }() + + // Check size + assert.Equal(t, src.Size(), dst.Size()) + + // Check modtime + srcModTime := src.ModTime(ctx) + dstModTime := dst.ModTime(ctx) + assert.True(t, srcModTime.Equal(dstModTime)) + + // Make sure contents are correct + gotContents := fstests.ReadObject(ctx, t, dst, -1) + assert.Equal(t, contents, gotContents) +} + +// -run TestIntegration/FsMkdir/FsPutFiles/Internal +func (f *Fs) InternalTest(t *testing.T) { + t.Run("ChunkedCopy", f.InternalTestChunkedCopy) +} + +var _ fstests.InternalTester = (*Fs)(nil) diff --git a/backend/b2/upload.go b/backend/b2/upload.go index 9fe58295c..a8897dcaf 100644 --- a/backend/b2/upload.go +++ b/backend/b2/upload.go @@ -456,7 +456,7 @@ func (up *largeUpload) Copy(ctx context.Context) (err error) { remaining = up.size ) g.SetLimit(up.f.opt.UploadConcurrency) - for part := 0; part <= up.parts; part++ { + for part := 0; part < up.parts; part++ { // Fail fast, in case an errgroup managed function returns an error // gCtx is cancelled. There is no point in copying all the other parts. if gCtx.Err() != nil {