github.com/10XDev/rclone@v1.52.3-0.20200626220027-16af9ab76b2a/fs/sync/sync_test.go (about)

     1  // Test sync/copy/move
     2  
     3  package sync
     4  
     5  import (
     6  	"context"
     7  	"fmt"
     8  	"runtime"
     9  	"strings"
    10  	"testing"
    11  	"time"
    12  
    13  	"github.com/pkg/errors"
    14  	_ "github.com/rclone/rclone/backend/all" // import all backends
    15  	"github.com/rclone/rclone/fs"
    16  	"github.com/rclone/rclone/fs/accounting"
    17  	"github.com/rclone/rclone/fs/filter"
    18  	"github.com/rclone/rclone/fs/fserrors"
    19  	"github.com/rclone/rclone/fs/hash"
    20  	"github.com/rclone/rclone/fs/operations"
    21  	"github.com/rclone/rclone/fstest"
    22  	"github.com/stretchr/testify/assert"
    23  	"github.com/stretchr/testify/require"
    24  	"golang.org/x/text/unicode/norm"
    25  )
    26  
    27  // Some times used in the tests
    28  var (
    29  	t1 = fstest.Time("2001-02-03T04:05:06.499999999Z")
    30  	t2 = fstest.Time("2011-12-25T12:59:59.123456789Z")
    31  	t3 = fstest.Time("2011-12-30T12:59:59.000000000Z")
    32  )
    33  
    34  // TestMain drives the tests
    35  func TestMain(m *testing.M) {
    36  	fstest.TestMain(m)
    37  }
    38  
    39  // Check dry run is working
    40  func TestCopyWithDryRun(t *testing.T) {
    41  	r := fstest.NewRun(t)
    42  	defer r.Finalise()
    43  	file1 := r.WriteFile("sub dir/hello world", "hello world", t1)
    44  	r.Mkdir(context.Background(), r.Fremote)
    45  
    46  	fs.Config.DryRun = true
    47  	err := CopyDir(context.Background(), r.Fremote, r.Flocal, false)
    48  	fs.Config.DryRun = false
    49  	require.NoError(t, err)
    50  
    51  	fstest.CheckItems(t, r.Flocal, file1)
    52  	fstest.CheckItems(t, r.Fremote)
    53  }
    54  
    55  // Now without dry run
    56  func TestCopy(t *testing.T) {
    57  	r := fstest.NewRun(t)
    58  	defer r.Finalise()
    59  	file1 := r.WriteFile("sub dir/hello world", "hello world", t1)
    60  	r.Mkdir(context.Background(), r.Fremote)
    61  
    62  	err := CopyDir(context.Background(), r.Fremote, r.Flocal, false)
    63  	require.NoError(t, err)
    64  
    65  	fstest.CheckItems(t, r.Flocal, file1)
    66  	fstest.CheckItems(t, r.Fremote, file1)
    67  }
    68  
    69  func TestCopyMissingDirectory(t *testing.T) {
    70  	r := fstest.NewRun(t)
    71  	defer r.Finalise()
    72  	r.Mkdir(context.Background(), r.Fremote)
    73  
    74  	nonExistingFs, err := fs.NewFs("/non-existing")
    75  	if err != nil {
    76  		t.Fatal(err)
    77  	}
    78  
    79  	err = CopyDir(context.Background(), r.Fremote, nonExistingFs, false)
    80  	require.Error(t, err)
    81  }
    82  
    83  // Now with --no-traverse
    84  func TestCopyNoTraverse(t *testing.T) {
    85  	r := fstest.NewRun(t)
    86  	defer r.Finalise()
    87  
    88  	fs.Config.NoTraverse = true
    89  	defer func() { fs.Config.NoTraverse = false }()
    90  
    91  	file1 := r.WriteFile("sub dir/hello world", "hello world", t1)
    92  
    93  	err := CopyDir(context.Background(), r.Fremote, r.Flocal, false)
    94  	require.NoError(t, err)
    95  
    96  	fstest.CheckItems(t, r.Flocal, file1)
    97  	fstest.CheckItems(t, r.Fremote, file1)
    98  }
    99  
   100  // Now with --check-first
   101  func TestCopyCheckFirst(t *testing.T) {
   102  	r := fstest.NewRun(t)
   103  	defer r.Finalise()
   104  
   105  	fs.Config.CheckFirst = true
   106  	defer func() { fs.Config.CheckFirst = false }()
   107  
   108  	file1 := r.WriteFile("sub dir/hello world", "hello world", t1)
   109  
   110  	err := CopyDir(context.Background(), r.Fremote, r.Flocal, false)
   111  	require.NoError(t, err)
   112  
   113  	fstest.CheckItems(t, r.Flocal, file1)
   114  	fstest.CheckItems(t, r.Fremote, file1)
   115  }
   116  
   117  // Now with --no-traverse
   118  func TestSyncNoTraverse(t *testing.T) {
   119  	r := fstest.NewRun(t)
   120  	defer r.Finalise()
   121  
   122  	fs.Config.NoTraverse = true
   123  	defer func() { fs.Config.NoTraverse = false }()
   124  
   125  	file1 := r.WriteFile("sub dir/hello world", "hello world", t1)
   126  
   127  	accounting.GlobalStats().ResetCounters()
   128  	err := Sync(context.Background(), r.Fremote, r.Flocal, false)
   129  	require.NoError(t, err)
   130  
   131  	fstest.CheckItems(t, r.Flocal, file1)
   132  	fstest.CheckItems(t, r.Fremote, file1)
   133  }
   134  
   135  // Test copy with depth
   136  func TestCopyWithDepth(t *testing.T) {
   137  	r := fstest.NewRun(t)
   138  	defer r.Finalise()
   139  	file1 := r.WriteFile("sub dir/hello world", "hello world", t1)
   140  	file2 := r.WriteFile("hello world2", "hello world2", t2)
   141  
   142  	// Check the MaxDepth too
   143  	fs.Config.MaxDepth = 1
   144  	defer func() { fs.Config.MaxDepth = -1 }()
   145  
   146  	err := CopyDir(context.Background(), r.Fremote, r.Flocal, false)
   147  	require.NoError(t, err)
   148  
   149  	fstest.CheckItems(t, r.Flocal, file1, file2)
   150  	fstest.CheckItems(t, r.Fremote, file2)
   151  }
   152  
   153  // Test copy with files from
   154  func testCopyWithFilesFrom(t *testing.T, noTraverse bool) {
   155  	r := fstest.NewRun(t)
   156  	defer r.Finalise()
   157  	file1 := r.WriteFile("potato2", "hello world", t1)
   158  	file2 := r.WriteFile("hello world2", "hello world2", t2)
   159  
   160  	// Set the --files-from equivalent
   161  	f, err := filter.NewFilter(nil)
   162  	require.NoError(t, err)
   163  	require.NoError(t, f.AddFile("potato2"))
   164  	require.NoError(t, f.AddFile("notfound"))
   165  
   166  	// Monkey patch the active filter
   167  	oldFilter := filter.Active
   168  	oldNoTraverse := fs.Config.NoTraverse
   169  	filter.Active = f
   170  	fs.Config.NoTraverse = noTraverse
   171  	unpatch := func() {
   172  		filter.Active = oldFilter
   173  		fs.Config.NoTraverse = oldNoTraverse
   174  	}
   175  	defer unpatch()
   176  
   177  	err = CopyDir(context.Background(), r.Fremote, r.Flocal, false)
   178  	require.NoError(t, err)
   179  	unpatch()
   180  
   181  	fstest.CheckItems(t, r.Flocal, file1, file2)
   182  	fstest.CheckItems(t, r.Fremote, file1)
   183  }
   184  func TestCopyWithFilesFrom(t *testing.T)              { testCopyWithFilesFrom(t, false) }
   185  func TestCopyWithFilesFromAndNoTraverse(t *testing.T) { testCopyWithFilesFrom(t, true) }
   186  
   187  // Test copy empty directories
   188  func TestCopyEmptyDirectories(t *testing.T) {
   189  	r := fstest.NewRun(t)
   190  	defer r.Finalise()
   191  	file1 := r.WriteFile("sub dir/hello world", "hello world", t1)
   192  	err := operations.Mkdir(context.Background(), r.Flocal, "sub dir2")
   193  	require.NoError(t, err)
   194  	r.Mkdir(context.Background(), r.Fremote)
   195  
   196  	err = CopyDir(context.Background(), r.Fremote, r.Flocal, true)
   197  	require.NoError(t, err)
   198  
   199  	fstest.CheckListingWithPrecision(
   200  		t,
   201  		r.Fremote,
   202  		[]fstest.Item{
   203  			file1,
   204  		},
   205  		[]string{
   206  			"sub dir",
   207  			"sub dir2",
   208  		},
   209  		fs.GetModifyWindow(r.Fremote),
   210  	)
   211  }
   212  
   213  // Test move empty directories
   214  func TestMoveEmptyDirectories(t *testing.T) {
   215  	r := fstest.NewRun(t)
   216  	defer r.Finalise()
   217  	file1 := r.WriteFile("sub dir/hello world", "hello world", t1)
   218  	err := operations.Mkdir(context.Background(), r.Flocal, "sub dir2")
   219  	require.NoError(t, err)
   220  	r.Mkdir(context.Background(), r.Fremote)
   221  
   222  	err = MoveDir(context.Background(), r.Fremote, r.Flocal, false, true)
   223  	require.NoError(t, err)
   224  
   225  	fstest.CheckListingWithPrecision(
   226  		t,
   227  		r.Fremote,
   228  		[]fstest.Item{
   229  			file1,
   230  		},
   231  		[]string{
   232  			"sub dir",
   233  			"sub dir2",
   234  		},
   235  		fs.GetModifyWindow(r.Fremote),
   236  	)
   237  }
   238  
   239  // Test sync empty directories
   240  func TestSyncEmptyDirectories(t *testing.T) {
   241  	r := fstest.NewRun(t)
   242  	defer r.Finalise()
   243  	file1 := r.WriteFile("sub dir/hello world", "hello world", t1)
   244  	err := operations.Mkdir(context.Background(), r.Flocal, "sub dir2")
   245  	require.NoError(t, err)
   246  	r.Mkdir(context.Background(), r.Fremote)
   247  
   248  	err = Sync(context.Background(), r.Fremote, r.Flocal, true)
   249  	require.NoError(t, err)
   250  
   251  	fstest.CheckListingWithPrecision(
   252  		t,
   253  		r.Fremote,
   254  		[]fstest.Item{
   255  			file1,
   256  		},
   257  		[]string{
   258  			"sub dir",
   259  			"sub dir2",
   260  		},
   261  		fs.GetModifyWindow(r.Fremote),
   262  	)
   263  }
   264  
   265  // Test a server side copy if possible, or the backup path if not
   266  func TestServerSideCopy(t *testing.T) {
   267  	r := fstest.NewRun(t)
   268  	defer r.Finalise()
   269  	file1 := r.WriteObject(context.Background(), "sub dir/hello world", "hello world", t1)
   270  	fstest.CheckItems(t, r.Fremote, file1)
   271  
   272  	FremoteCopy, _, finaliseCopy, err := fstest.RandomRemote()
   273  	require.NoError(t, err)
   274  	defer finaliseCopy()
   275  	t.Logf("Server side copy (if possible) %v -> %v", r.Fremote, FremoteCopy)
   276  
   277  	err = CopyDir(context.Background(), FremoteCopy, r.Fremote, false)
   278  	require.NoError(t, err)
   279  
   280  	fstest.CheckItems(t, FremoteCopy, file1)
   281  }
   282  
   283  // Check that if the local file doesn't exist when we copy it up,
   284  // nothing happens to the remote file
   285  func TestCopyAfterDelete(t *testing.T) {
   286  	r := fstest.NewRun(t)
   287  	defer r.Finalise()
   288  	file1 := r.WriteObject(context.Background(), "sub dir/hello world", "hello world", t1)
   289  	fstest.CheckItems(t, r.Flocal)
   290  	fstest.CheckItems(t, r.Fremote, file1)
   291  
   292  	err := operations.Mkdir(context.Background(), r.Flocal, "")
   293  	require.NoError(t, err)
   294  
   295  	err = CopyDir(context.Background(), r.Fremote, r.Flocal, false)
   296  	require.NoError(t, err)
   297  
   298  	fstest.CheckItems(t, r.Flocal)
   299  	fstest.CheckItems(t, r.Fremote, file1)
   300  }
   301  
   302  // Check the copy downloading a file
   303  func TestCopyRedownload(t *testing.T) {
   304  	r := fstest.NewRun(t)
   305  	defer r.Finalise()
   306  	file1 := r.WriteObject(context.Background(), "sub dir/hello world", "hello world", t1)
   307  	fstest.CheckItems(t, r.Fremote, file1)
   308  
   309  	err := CopyDir(context.Background(), r.Flocal, r.Fremote, false)
   310  	require.NoError(t, err)
   311  
   312  	// Test with combined precision of local and remote as we copied it there and back
   313  	fstest.CheckListingWithPrecision(t, r.Flocal, []fstest.Item{file1}, nil, fs.GetModifyWindow(r.Flocal, r.Fremote))
   314  }
   315  
   316  // Create a file and sync it. Change the last modified date and resync.
   317  // If we're only doing sync by size and checksum, we expect nothing to
   318  // to be transferred on the second sync.
   319  func TestSyncBasedOnCheckSum(t *testing.T) {
   320  	r := fstest.NewRun(t)
   321  	defer r.Finalise()
   322  	fs.Config.CheckSum = true
   323  	defer func() { fs.Config.CheckSum = false }()
   324  
   325  	file1 := r.WriteFile("check sum", "-", t1)
   326  	fstest.CheckItems(t, r.Flocal, file1)
   327  
   328  	accounting.GlobalStats().ResetCounters()
   329  	err := Sync(context.Background(), r.Fremote, r.Flocal, false)
   330  	require.NoError(t, err)
   331  
   332  	// We should have transferred exactly one file.
   333  	assert.Equal(t, toyFileTransfers(r), accounting.GlobalStats().GetTransfers())
   334  	fstest.CheckItems(t, r.Fremote, file1)
   335  
   336  	// Change last modified date only
   337  	file2 := r.WriteFile("check sum", "-", t2)
   338  	fstest.CheckItems(t, r.Flocal, file2)
   339  
   340  	accounting.GlobalStats().ResetCounters()
   341  	err = Sync(context.Background(), r.Fremote, r.Flocal, false)
   342  	require.NoError(t, err)
   343  
   344  	// We should have transferred no files
   345  	assert.Equal(t, int64(0), accounting.GlobalStats().GetTransfers())
   346  	fstest.CheckItems(t, r.Flocal, file2)
   347  	fstest.CheckItems(t, r.Fremote, file1)
   348  }
   349  
   350  // Create a file and sync it. Change the last modified date and the
   351  // file contents but not the size.  If we're only doing sync by size
   352  // only, we expect nothing to to be transferred on the second sync.
   353  func TestSyncSizeOnly(t *testing.T) {
   354  	r := fstest.NewRun(t)
   355  	defer r.Finalise()
   356  	fs.Config.SizeOnly = true
   357  	defer func() { fs.Config.SizeOnly = false }()
   358  
   359  	file1 := r.WriteFile("sizeonly", "potato", t1)
   360  	fstest.CheckItems(t, r.Flocal, file1)
   361  
   362  	accounting.GlobalStats().ResetCounters()
   363  	err := Sync(context.Background(), r.Fremote, r.Flocal, false)
   364  	require.NoError(t, err)
   365  
   366  	// We should have transferred exactly one file.
   367  	assert.Equal(t, toyFileTransfers(r), accounting.GlobalStats().GetTransfers())
   368  	fstest.CheckItems(t, r.Fremote, file1)
   369  
   370  	// Update mtime, md5sum but not length of file
   371  	file2 := r.WriteFile("sizeonly", "POTATO", t2)
   372  	fstest.CheckItems(t, r.Flocal, file2)
   373  
   374  	accounting.GlobalStats().ResetCounters()
   375  	err = Sync(context.Background(), r.Fremote, r.Flocal, false)
   376  	require.NoError(t, err)
   377  
   378  	// We should have transferred no files
   379  	assert.Equal(t, int64(0), accounting.GlobalStats().GetTransfers())
   380  	fstest.CheckItems(t, r.Flocal, file2)
   381  	fstest.CheckItems(t, r.Fremote, file1)
   382  }
   383  
   384  // Create a file and sync it. Keep the last modified date but change
   385  // the size.  With --ignore-size we expect nothing to to be
   386  // transferred on the second sync.
   387  func TestSyncIgnoreSize(t *testing.T) {
   388  	r := fstest.NewRun(t)
   389  	defer r.Finalise()
   390  	fs.Config.IgnoreSize = true
   391  	defer func() { fs.Config.IgnoreSize = false }()
   392  
   393  	file1 := r.WriteFile("ignore-size", "contents", t1)
   394  	fstest.CheckItems(t, r.Flocal, file1)
   395  
   396  	accounting.GlobalStats().ResetCounters()
   397  	err := Sync(context.Background(), r.Fremote, r.Flocal, false)
   398  	require.NoError(t, err)
   399  
   400  	// We should have transferred exactly one file.
   401  	assert.Equal(t, toyFileTransfers(r), accounting.GlobalStats().GetTransfers())
   402  	fstest.CheckItems(t, r.Fremote, file1)
   403  
   404  	// Update size but not date of file
   405  	file2 := r.WriteFile("ignore-size", "longer contents but same date", t1)
   406  	fstest.CheckItems(t, r.Flocal, file2)
   407  
   408  	accounting.GlobalStats().ResetCounters()
   409  	err = Sync(context.Background(), r.Fremote, r.Flocal, false)
   410  	require.NoError(t, err)
   411  
   412  	// We should have transferred no files
   413  	assert.Equal(t, int64(0), accounting.GlobalStats().GetTransfers())
   414  	fstest.CheckItems(t, r.Flocal, file2)
   415  	fstest.CheckItems(t, r.Fremote, file1)
   416  }
   417  
   418  func TestSyncIgnoreTimes(t *testing.T) {
   419  	r := fstest.NewRun(t)
   420  	defer r.Finalise()
   421  	file1 := r.WriteBoth(context.Background(), "existing", "potato", t1)
   422  	fstest.CheckItems(t, r.Fremote, file1)
   423  
   424  	accounting.GlobalStats().ResetCounters()
   425  	err := Sync(context.Background(), r.Fremote, r.Flocal, false)
   426  	require.NoError(t, err)
   427  
   428  	// We should have transferred exactly 0 files because the
   429  	// files were identical.
   430  	assert.Equal(t, int64(0), accounting.GlobalStats().GetTransfers())
   431  
   432  	fs.Config.IgnoreTimes = true
   433  	defer func() { fs.Config.IgnoreTimes = false }()
   434  
   435  	accounting.GlobalStats().ResetCounters()
   436  	err = Sync(context.Background(), r.Fremote, r.Flocal, false)
   437  	require.NoError(t, err)
   438  
   439  	// We should have transferred exactly one file even though the
   440  	// files were identical.
   441  	assert.Equal(t, toyFileTransfers(r), accounting.GlobalStats().GetTransfers())
   442  
   443  	fstest.CheckItems(t, r.Flocal, file1)
   444  	fstest.CheckItems(t, r.Fremote, file1)
   445  }
   446  
   447  func TestSyncIgnoreExisting(t *testing.T) {
   448  	r := fstest.NewRun(t)
   449  	defer r.Finalise()
   450  	file1 := r.WriteFile("existing", "potato", t1)
   451  
   452  	fs.Config.IgnoreExisting = true
   453  	defer func() { fs.Config.IgnoreExisting = false }()
   454  
   455  	accounting.GlobalStats().ResetCounters()
   456  	err := Sync(context.Background(), r.Fremote, r.Flocal, false)
   457  	require.NoError(t, err)
   458  	fstest.CheckItems(t, r.Flocal, file1)
   459  	fstest.CheckItems(t, r.Fremote, file1)
   460  
   461  	// Change everything
   462  	r.WriteFile("existing", "newpotatoes", t2)
   463  	accounting.GlobalStats().ResetCounters()
   464  	err = Sync(context.Background(), r.Fremote, r.Flocal, false)
   465  	require.NoError(t, err)
   466  	// Items should not change
   467  	fstest.CheckItems(t, r.Fremote, file1)
   468  }
   469  
   470  func TestSyncIgnoreErrors(t *testing.T) {
   471  	r := fstest.NewRun(t)
   472  	fs.Config.IgnoreErrors = true
   473  	defer func() {
   474  		fs.Config.IgnoreErrors = false
   475  		r.Finalise()
   476  	}()
   477  	file1 := r.WriteFile("a/potato2", "------------------------------------------------------------", t1)
   478  	file2 := r.WriteObject(context.Background(), "b/potato", "SMALLER BUT SAME DATE", t2)
   479  	file3 := r.WriteBoth(context.Background(), "c/non empty space", "AhHa!", t2)
   480  	require.NoError(t, operations.Mkdir(context.Background(), r.Fremote, "d"))
   481  
   482  	fstest.CheckListingWithPrecision(
   483  		t,
   484  		r.Flocal,
   485  		[]fstest.Item{
   486  			file1,
   487  			file3,
   488  		},
   489  		[]string{
   490  			"a",
   491  			"c",
   492  		},
   493  		fs.GetModifyWindow(r.Fremote),
   494  	)
   495  	fstest.CheckListingWithPrecision(
   496  		t,
   497  		r.Fremote,
   498  		[]fstest.Item{
   499  			file2,
   500  			file3,
   501  		},
   502  		[]string{
   503  			"b",
   504  			"c",
   505  			"d",
   506  		},
   507  		fs.GetModifyWindow(r.Fremote),
   508  	)
   509  
   510  	accounting.GlobalStats().ResetCounters()
   511  	_ = fs.CountError(errors.New("boom"))
   512  	assert.NoError(t, Sync(context.Background(), r.Fremote, r.Flocal, false))
   513  
   514  	fstest.CheckListingWithPrecision(
   515  		t,
   516  		r.Flocal,
   517  		[]fstest.Item{
   518  			file1,
   519  			file3,
   520  		},
   521  		[]string{
   522  			"a",
   523  			"c",
   524  		},
   525  		fs.GetModifyWindow(r.Fremote),
   526  	)
   527  	fstest.CheckListingWithPrecision(
   528  		t,
   529  		r.Fremote,
   530  		[]fstest.Item{
   531  			file1,
   532  			file3,
   533  		},
   534  		[]string{
   535  			"a",
   536  			"c",
   537  		},
   538  		fs.GetModifyWindow(r.Fremote),
   539  	)
   540  }
   541  
   542  func TestSyncAfterChangingModtimeOnly(t *testing.T) {
   543  	r := fstest.NewRun(t)
   544  	defer r.Finalise()
   545  	file1 := r.WriteFile("empty space", "-", t2)
   546  	file2 := r.WriteObject(context.Background(), "empty space", "-", t1)
   547  
   548  	fstest.CheckItems(t, r.Flocal, file1)
   549  	fstest.CheckItems(t, r.Fremote, file2)
   550  
   551  	fs.Config.DryRun = true
   552  	defer func() { fs.Config.DryRun = false }()
   553  
   554  	accounting.GlobalStats().ResetCounters()
   555  	err := Sync(context.Background(), r.Fremote, r.Flocal, false)
   556  	require.NoError(t, err)
   557  
   558  	fstest.CheckItems(t, r.Flocal, file1)
   559  	fstest.CheckItems(t, r.Fremote, file2)
   560  
   561  	fs.Config.DryRun = false
   562  
   563  	accounting.GlobalStats().ResetCounters()
   564  	err = Sync(context.Background(), r.Fremote, r.Flocal, false)
   565  	require.NoError(t, err)
   566  
   567  	fstest.CheckItems(t, r.Flocal, file1)
   568  	fstest.CheckItems(t, r.Fremote, file1)
   569  }
   570  
   571  func TestSyncAfterChangingModtimeOnlyWithNoUpdateModTime(t *testing.T) {
   572  	r := fstest.NewRun(t)
   573  	defer r.Finalise()
   574  
   575  	if r.Fremote.Hashes().Count() == 0 {
   576  		t.Logf("Can't check this if no hashes supported")
   577  		return
   578  	}
   579  
   580  	fs.Config.NoUpdateModTime = true
   581  	defer func() {
   582  		fs.Config.NoUpdateModTime = false
   583  	}()
   584  
   585  	file1 := r.WriteFile("empty space", "-", t2)
   586  	file2 := r.WriteObject(context.Background(), "empty space", "-", t1)
   587  
   588  	fstest.CheckItems(t, r.Flocal, file1)
   589  	fstest.CheckItems(t, r.Fremote, file2)
   590  
   591  	accounting.GlobalStats().ResetCounters()
   592  	err := Sync(context.Background(), r.Fremote, r.Flocal, false)
   593  	require.NoError(t, err)
   594  
   595  	fstest.CheckItems(t, r.Flocal, file1)
   596  	fstest.CheckItems(t, r.Fremote, file2)
   597  }
   598  
   599  func TestSyncDoesntUpdateModtime(t *testing.T) {
   600  	r := fstest.NewRun(t)
   601  	defer r.Finalise()
   602  	if fs.GetModifyWindow(r.Fremote) == fs.ModTimeNotSupported {
   603  		t.Skip("Can't run this test on fs which doesn't support mod time")
   604  	}
   605  
   606  	file1 := r.WriteFile("foo", "foo", t2)
   607  	file2 := r.WriteObject(context.Background(), "foo", "bar", t1)
   608  
   609  	fstest.CheckItems(t, r.Flocal, file1)
   610  	fstest.CheckItems(t, r.Fremote, file2)
   611  
   612  	accounting.GlobalStats().ResetCounters()
   613  	err := Sync(context.Background(), r.Fremote, r.Flocal, false)
   614  	require.NoError(t, err)
   615  
   616  	fstest.CheckItems(t, r.Flocal, file1)
   617  	fstest.CheckItems(t, r.Fremote, file1)
   618  
   619  	// We should have transferred exactly one file, not set the mod time
   620  	assert.Equal(t, toyFileTransfers(r), accounting.GlobalStats().GetTransfers())
   621  }
   622  
   623  func TestSyncAfterAddingAFile(t *testing.T) {
   624  	r := fstest.NewRun(t)
   625  	defer r.Finalise()
   626  	file1 := r.WriteBoth(context.Background(), "empty space", "-", t2)
   627  	file2 := r.WriteFile("potato", "------------------------------------------------------------", t3)
   628  
   629  	fstest.CheckItems(t, r.Flocal, file1, file2)
   630  	fstest.CheckItems(t, r.Fremote, file1)
   631  
   632  	accounting.GlobalStats().ResetCounters()
   633  	err := Sync(context.Background(), r.Fremote, r.Flocal, false)
   634  	require.NoError(t, err)
   635  	fstest.CheckItems(t, r.Flocal, file1, file2)
   636  	fstest.CheckItems(t, r.Fremote, file1, file2)
   637  }
   638  
   639  func TestSyncAfterChangingFilesSizeOnly(t *testing.T) {
   640  	r := fstest.NewRun(t)
   641  	defer r.Finalise()
   642  	file1 := r.WriteObject(context.Background(), "potato", "------------------------------------------------------------", t3)
   643  	file2 := r.WriteFile("potato", "smaller but same date", t3)
   644  	fstest.CheckItems(t, r.Fremote, file1)
   645  	fstest.CheckItems(t, r.Flocal, file2)
   646  
   647  	accounting.GlobalStats().ResetCounters()
   648  	err := Sync(context.Background(), r.Fremote, r.Flocal, false)
   649  	require.NoError(t, err)
   650  	fstest.CheckItems(t, r.Flocal, file2)
   651  	fstest.CheckItems(t, r.Fremote, file2)
   652  }
   653  
   654  // Sync after changing a file's contents, changing modtime but length
   655  // remaining the same
   656  func TestSyncAfterChangingContentsOnly(t *testing.T) {
   657  	r := fstest.NewRun(t)
   658  	defer r.Finalise()
   659  	var file1 fstest.Item
   660  	if r.Fremote.Precision() == fs.ModTimeNotSupported {
   661  		t.Logf("ModTimeNotSupported so forcing file to be a different size")
   662  		file1 = r.WriteObject(context.Background(), "potato", "different size to make sure it syncs", t3)
   663  	} else {
   664  		file1 = r.WriteObject(context.Background(), "potato", "smaller but same date", t3)
   665  	}
   666  	file2 := r.WriteFile("potato", "SMALLER BUT SAME DATE", t2)
   667  	fstest.CheckItems(t, r.Fremote, file1)
   668  	fstest.CheckItems(t, r.Flocal, file2)
   669  
   670  	accounting.GlobalStats().ResetCounters()
   671  	err := Sync(context.Background(), r.Fremote, r.Flocal, false)
   672  	require.NoError(t, err)
   673  	fstest.CheckItems(t, r.Flocal, file2)
   674  	fstest.CheckItems(t, r.Fremote, file2)
   675  }
   676  
   677  // Sync after removing a file and adding a file --dry-run
   678  func TestSyncAfterRemovingAFileAndAddingAFileDryRun(t *testing.T) {
   679  	r := fstest.NewRun(t)
   680  	defer r.Finalise()
   681  	file1 := r.WriteFile("potato2", "------------------------------------------------------------", t1)
   682  	file2 := r.WriteObject(context.Background(), "potato", "SMALLER BUT SAME DATE", t2)
   683  	file3 := r.WriteBoth(context.Background(), "empty space", "-", t2)
   684  
   685  	fs.Config.DryRun = true
   686  	accounting.GlobalStats().ResetCounters()
   687  	err := Sync(context.Background(), r.Fremote, r.Flocal, false)
   688  	fs.Config.DryRun = false
   689  	require.NoError(t, err)
   690  
   691  	fstest.CheckItems(t, r.Flocal, file3, file1)
   692  	fstest.CheckItems(t, r.Fremote, file3, file2)
   693  }
   694  
   695  // Sync after removing a file and adding a file
   696  func TestSyncAfterRemovingAFileAndAddingAFile(t *testing.T) {
   697  	r := fstest.NewRun(t)
   698  	defer r.Finalise()
   699  	file1 := r.WriteFile("potato2", "------------------------------------------------------------", t1)
   700  	file2 := r.WriteObject(context.Background(), "potato", "SMALLER BUT SAME DATE", t2)
   701  	file3 := r.WriteBoth(context.Background(), "empty space", "-", t2)
   702  	fstest.CheckItems(t, r.Fremote, file2, file3)
   703  	fstest.CheckItems(t, r.Flocal, file1, file3)
   704  
   705  	accounting.GlobalStats().ResetCounters()
   706  	err := Sync(context.Background(), r.Fremote, r.Flocal, false)
   707  	require.NoError(t, err)
   708  	fstest.CheckItems(t, r.Flocal, file1, file3)
   709  	fstest.CheckItems(t, r.Fremote, file1, file3)
   710  }
   711  
   712  // Sync after removing a file and adding a file
   713  func TestSyncAfterRemovingAFileAndAddingAFileSubDir(t *testing.T) {
   714  	r := fstest.NewRun(t)
   715  	defer r.Finalise()
   716  	file1 := r.WriteFile("a/potato2", "------------------------------------------------------------", t1)
   717  	file2 := r.WriteObject(context.Background(), "b/potato", "SMALLER BUT SAME DATE", t2)
   718  	file3 := r.WriteBoth(context.Background(), "c/non empty space", "AhHa!", t2)
   719  	require.NoError(t, operations.Mkdir(context.Background(), r.Fremote, "d"))
   720  	require.NoError(t, operations.Mkdir(context.Background(), r.Fremote, "d/e"))
   721  
   722  	fstest.CheckListingWithPrecision(
   723  		t,
   724  		r.Flocal,
   725  		[]fstest.Item{
   726  			file1,
   727  			file3,
   728  		},
   729  		[]string{
   730  			"a",
   731  			"c",
   732  		},
   733  		fs.GetModifyWindow(r.Fremote),
   734  	)
   735  	fstest.CheckListingWithPrecision(
   736  		t,
   737  		r.Fremote,
   738  		[]fstest.Item{
   739  			file2,
   740  			file3,
   741  		},
   742  		[]string{
   743  			"b",
   744  			"c",
   745  			"d",
   746  			"d/e",
   747  		},
   748  		fs.GetModifyWindow(r.Fremote),
   749  	)
   750  
   751  	accounting.GlobalStats().ResetCounters()
   752  	err := Sync(context.Background(), r.Fremote, r.Flocal, false)
   753  	require.NoError(t, err)
   754  
   755  	fstest.CheckListingWithPrecision(
   756  		t,
   757  		r.Flocal,
   758  		[]fstest.Item{
   759  			file1,
   760  			file3,
   761  		},
   762  		[]string{
   763  			"a",
   764  			"c",
   765  		},
   766  		fs.GetModifyWindow(r.Fremote),
   767  	)
   768  	fstest.CheckListingWithPrecision(
   769  		t,
   770  		r.Fremote,
   771  		[]fstest.Item{
   772  			file1,
   773  			file3,
   774  		},
   775  		[]string{
   776  			"a",
   777  			"c",
   778  		},
   779  		fs.GetModifyWindow(r.Fremote),
   780  	)
   781  }
   782  
   783  // Sync after removing a file and adding a file with IO Errors
   784  func TestSyncAfterRemovingAFileAndAddingAFileSubDirWithErrors(t *testing.T) {
   785  	r := fstest.NewRun(t)
   786  	defer r.Finalise()
   787  	file1 := r.WriteFile("a/potato2", "------------------------------------------------------------", t1)
   788  	file2 := r.WriteObject(context.Background(), "b/potato", "SMALLER BUT SAME DATE", t2)
   789  	file3 := r.WriteBoth(context.Background(), "c/non empty space", "AhHa!", t2)
   790  	require.NoError(t, operations.Mkdir(context.Background(), r.Fremote, "d"))
   791  
   792  	fstest.CheckListingWithPrecision(
   793  		t,
   794  		r.Flocal,
   795  		[]fstest.Item{
   796  			file1,
   797  			file3,
   798  		},
   799  		[]string{
   800  			"a",
   801  			"c",
   802  		},
   803  		fs.GetModifyWindow(r.Fremote),
   804  	)
   805  	fstest.CheckListingWithPrecision(
   806  		t,
   807  		r.Fremote,
   808  		[]fstest.Item{
   809  			file2,
   810  			file3,
   811  		},
   812  		[]string{
   813  			"b",
   814  			"c",
   815  			"d",
   816  		},
   817  		fs.GetModifyWindow(r.Fremote),
   818  	)
   819  
   820  	accounting.GlobalStats().ResetCounters()
   821  	_ = fs.CountError(errors.New("boom"))
   822  	err := Sync(context.Background(), r.Fremote, r.Flocal, false)
   823  	assert.Equal(t, fs.ErrorNotDeleting, err)
   824  
   825  	fstest.CheckListingWithPrecision(
   826  		t,
   827  		r.Flocal,
   828  		[]fstest.Item{
   829  			file1,
   830  			file3,
   831  		},
   832  		[]string{
   833  			"a",
   834  			"c",
   835  		},
   836  		fs.GetModifyWindow(r.Fremote),
   837  	)
   838  	fstest.CheckListingWithPrecision(
   839  		t,
   840  		r.Fremote,
   841  		[]fstest.Item{
   842  			file1,
   843  			file2,
   844  			file3,
   845  		},
   846  		[]string{
   847  			"a",
   848  			"b",
   849  			"c",
   850  			"d",
   851  		},
   852  		fs.GetModifyWindow(r.Fremote),
   853  	)
   854  }
   855  
   856  // Sync test delete after
   857  func TestSyncDeleteAfter(t *testing.T) {
   858  	// This is the default so we've checked this already
   859  	// check it is the default
   860  	require.Equal(t, fs.Config.DeleteMode, fs.DeleteModeAfter, "Didn't default to --delete-after")
   861  }
   862  
   863  // Sync test delete during
   864  func TestSyncDeleteDuring(t *testing.T) {
   865  	fs.Config.DeleteMode = fs.DeleteModeDuring
   866  	defer func() {
   867  		fs.Config.DeleteMode = fs.DeleteModeDefault
   868  	}()
   869  
   870  	TestSyncAfterRemovingAFileAndAddingAFile(t)
   871  }
   872  
   873  // Sync test delete before
   874  func TestSyncDeleteBefore(t *testing.T) {
   875  	fs.Config.DeleteMode = fs.DeleteModeBefore
   876  	defer func() {
   877  		fs.Config.DeleteMode = fs.DeleteModeDefault
   878  	}()
   879  
   880  	TestSyncAfterRemovingAFileAndAddingAFile(t)
   881  }
   882  
   883  // Copy test delete before - shouldn't delete anything
   884  func TestCopyDeleteBefore(t *testing.T) {
   885  	r := fstest.NewRun(t)
   886  	defer r.Finalise()
   887  
   888  	fs.Config.DeleteMode = fs.DeleteModeBefore
   889  	defer func() {
   890  		fs.Config.DeleteMode = fs.DeleteModeDefault
   891  	}()
   892  
   893  	file1 := r.WriteObject(context.Background(), "potato", "hopefully not deleted", t1)
   894  	file2 := r.WriteFile("potato2", "hopefully copied in", t1)
   895  	fstest.CheckItems(t, r.Fremote, file1)
   896  	fstest.CheckItems(t, r.Flocal, file2)
   897  
   898  	accounting.GlobalStats().ResetCounters()
   899  	err := CopyDir(context.Background(), r.Fremote, r.Flocal, false)
   900  	require.NoError(t, err)
   901  
   902  	fstest.CheckItems(t, r.Fremote, file1, file2)
   903  	fstest.CheckItems(t, r.Flocal, file2)
   904  }
   905  
   906  // Test with exclude
   907  func TestSyncWithExclude(t *testing.T) {
   908  	r := fstest.NewRun(t)
   909  	defer r.Finalise()
   910  	file1 := r.WriteBoth(context.Background(), "potato2", "------------------------------------------------------------", t1)
   911  	file2 := r.WriteBoth(context.Background(), "empty space", "-", t2)
   912  	file3 := r.WriteFile("enormous", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", t1) // 100 bytes
   913  	fstest.CheckItems(t, r.Fremote, file1, file2)
   914  	fstest.CheckItems(t, r.Flocal, file1, file2, file3)
   915  
   916  	filter.Active.Opt.MaxSize = 40
   917  	defer func() {
   918  		filter.Active.Opt.MaxSize = -1
   919  	}()
   920  
   921  	accounting.GlobalStats().ResetCounters()
   922  	err := Sync(context.Background(), r.Fremote, r.Flocal, false)
   923  	require.NoError(t, err)
   924  	fstest.CheckItems(t, r.Fremote, file2, file1)
   925  
   926  	// Now sync the other way round and check enormous doesn't get
   927  	// deleted as it is excluded from the sync
   928  	accounting.GlobalStats().ResetCounters()
   929  	err = Sync(context.Background(), r.Flocal, r.Fremote, false)
   930  	require.NoError(t, err)
   931  	fstest.CheckItems(t, r.Flocal, file2, file1, file3)
   932  }
   933  
   934  // Test with exclude and delete excluded
   935  func TestSyncWithExcludeAndDeleteExcluded(t *testing.T) {
   936  	r := fstest.NewRun(t)
   937  	defer r.Finalise()
   938  	file1 := r.WriteBoth(context.Background(), "potato2", "------------------------------------------------------------", t1) // 60 bytes
   939  	file2 := r.WriteBoth(context.Background(), "empty space", "-", t2)
   940  	file3 := r.WriteBoth(context.Background(), "enormous", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", t1) // 100 bytes
   941  	fstest.CheckItems(t, r.Fremote, file1, file2, file3)
   942  	fstest.CheckItems(t, r.Flocal, file1, file2, file3)
   943  
   944  	filter.Active.Opt.MaxSize = 40
   945  	filter.Active.Opt.DeleteExcluded = true
   946  	defer func() {
   947  		filter.Active.Opt.MaxSize = -1
   948  		filter.Active.Opt.DeleteExcluded = false
   949  	}()
   950  
   951  	accounting.GlobalStats().ResetCounters()
   952  	err := Sync(context.Background(), r.Fremote, r.Flocal, false)
   953  	require.NoError(t, err)
   954  	fstest.CheckItems(t, r.Fremote, file2)
   955  
   956  	// Check sync the other way round to make sure enormous gets
   957  	// deleted even though it is excluded
   958  	accounting.GlobalStats().ResetCounters()
   959  	err = Sync(context.Background(), r.Flocal, r.Fremote, false)
   960  	require.NoError(t, err)
   961  	fstest.CheckItems(t, r.Flocal, file2)
   962  }
   963  
   964  // Test with UpdateOlder set
   965  func TestSyncWithUpdateOlder(t *testing.T) {
   966  	r := fstest.NewRun(t)
   967  	defer r.Finalise()
   968  	if fs.GetModifyWindow(r.Fremote) == fs.ModTimeNotSupported {
   969  		t.Skip("Can't run this test on fs which doesn't support mod time")
   970  	}
   971  	t2plus := t2.Add(time.Second / 2)
   972  	t2minus := t2.Add(time.Second / 2)
   973  	oneF := r.WriteFile("one", "one", t1)
   974  	twoF := r.WriteFile("two", "two", t3)
   975  	threeF := r.WriteFile("three", "three", t2)
   976  	fourF := r.WriteFile("four", "four", t2)
   977  	fiveF := r.WriteFile("five", "five", t2)
   978  	fstest.CheckItems(t, r.Flocal, oneF, twoF, threeF, fourF, fiveF)
   979  	oneO := r.WriteObject(context.Background(), "one", "ONE", t2)
   980  	twoO := r.WriteObject(context.Background(), "two", "TWO", t2)
   981  	threeO := r.WriteObject(context.Background(), "three", "THREE", t2plus)
   982  	fourO := r.WriteObject(context.Background(), "four", "FOURFOUR", t2minus)
   983  	fstest.CheckItems(t, r.Fremote, oneO, twoO, threeO, fourO)
   984  
   985  	fs.Config.UpdateOlder = true
   986  	oldModifyWindow := fs.Config.ModifyWindow
   987  	fs.Config.ModifyWindow = fs.ModTimeNotSupported
   988  	defer func() {
   989  		fs.Config.UpdateOlder = false
   990  		fs.Config.ModifyWindow = oldModifyWindow
   991  	}()
   992  
   993  	err := Sync(context.Background(), r.Fremote, r.Flocal, false)
   994  	require.NoError(t, err)
   995  	fstest.CheckItems(t, r.Fremote, oneO, twoF, threeO, fourF, fiveF)
   996  
   997  	if r.Fremote.Hashes().Count() == 0 {
   998  		t.Logf("Skip test with --checksum as no hashes supported")
   999  		return
  1000  	}
  1001  
  1002  	// now enable checksum
  1003  	fs.Config.CheckSum = true
  1004  	defer func() { fs.Config.CheckSum = false }()
  1005  
  1006  	err = Sync(context.Background(), r.Fremote, r.Flocal, false)
  1007  	require.NoError(t, err)
  1008  	fstest.CheckItems(t, r.Fremote, oneO, twoF, threeF, fourF, fiveF)
  1009  }
  1010  
  1011  // Test with a max transfer duration
  1012  func TestSyncWithMaxDuration(t *testing.T) {
  1013  	if *fstest.RemoteName != "" {
  1014  		t.Skip("Skipping test on non local remote")
  1015  	}
  1016  	r := fstest.NewRun(t)
  1017  	defer r.Finalise()
  1018  
  1019  	maxDuration := 250 * time.Millisecond
  1020  	fs.Config.MaxDuration = maxDuration
  1021  	bytesPerSecond := 300
  1022  	accounting.SetBwLimit(fs.SizeSuffix(bytesPerSecond))
  1023  	oldTransfers := fs.Config.Transfers
  1024  	fs.Config.Transfers = 1
  1025  	defer func() {
  1026  		fs.Config.MaxDuration = 0 // reset back to default
  1027  		fs.Config.Transfers = oldTransfers
  1028  		accounting.SetBwLimit(fs.SizeSuffix(0))
  1029  	}()
  1030  
  1031  	// 5 files of 60 bytes at 60 bytes/s 5 seconds
  1032  	testFiles := make([]fstest.Item, 5)
  1033  	for i := 0; i < len(testFiles); i++ {
  1034  		testFiles[i] = r.WriteFile(fmt.Sprintf("file%d", i), "------------------------------------------------------------", t1)
  1035  	}
  1036  
  1037  	fstest.CheckListing(t, r.Flocal, testFiles)
  1038  
  1039  	accounting.GlobalStats().ResetCounters()
  1040  	startTime := time.Now()
  1041  	err := Sync(context.Background(), r.Fremote, r.Flocal, false)
  1042  	require.Equal(t, context.DeadlineExceeded, errors.Cause(err))
  1043  	err = accounting.GlobalStats().GetLastError()
  1044  	require.NoError(t, err)
  1045  
  1046  	elapsed := time.Since(startTime)
  1047  	maxTransferTime := (time.Duration(len(testFiles)) * 60 * time.Second) / time.Duration(bytesPerSecond)
  1048  
  1049  	what := fmt.Sprintf("expecting elapsed time %v between %v and %v", elapsed, maxDuration, maxTransferTime)
  1050  	require.True(t, elapsed >= maxDuration, what)
  1051  	require.True(t, elapsed < 5*time.Second, what)
  1052  	// we must not have transferred all files during the session
  1053  	require.True(t, accounting.GlobalStats().GetTransfers() < int64(len(testFiles)))
  1054  }
  1055  
  1056  // Test with TrackRenames set
  1057  func TestSyncWithTrackRenames(t *testing.T) {
  1058  	r := fstest.NewRun(t)
  1059  	defer r.Finalise()
  1060  
  1061  	fs.Config.TrackRenames = true
  1062  	defer func() {
  1063  		fs.Config.TrackRenames = false
  1064  	}()
  1065  
  1066  	haveHash := r.Fremote.Hashes().Overlap(r.Flocal.Hashes()).GetOne() != hash.None
  1067  	canTrackRenames := haveHash && operations.CanServerSideMove(r.Fremote)
  1068  	t.Logf("Can track renames: %v", canTrackRenames)
  1069  
  1070  	f1 := r.WriteFile("potato", "Potato Content", t1)
  1071  	f2 := r.WriteFile("yam", "Yam Content", t2)
  1072  
  1073  	accounting.GlobalStats().ResetCounters()
  1074  	require.NoError(t, Sync(context.Background(), r.Fremote, r.Flocal, false))
  1075  
  1076  	fstest.CheckItems(t, r.Fremote, f1, f2)
  1077  	fstest.CheckItems(t, r.Flocal, f1, f2)
  1078  
  1079  	// Now rename locally.
  1080  	f2 = r.RenameFile(f2, "yaml")
  1081  
  1082  	accounting.GlobalStats().ResetCounters()
  1083  	require.NoError(t, Sync(context.Background(), r.Fremote, r.Flocal, false))
  1084  
  1085  	fstest.CheckItems(t, r.Fremote, f1, f2)
  1086  
  1087  	// Check we renamed something if we should have
  1088  	if canTrackRenames {
  1089  		renames := accounting.GlobalStats().Renames(0)
  1090  		assert.Equal(t, canTrackRenames, renames != 0, fmt.Sprintf("canTrackRenames=%v, renames=%d", canTrackRenames, renames))
  1091  	}
  1092  }
  1093  
  1094  func TestParseRenamesStrategyModtime(t *testing.T) {
  1095  	for _, test := range []struct {
  1096  		in      string
  1097  		want    trackRenamesStrategy
  1098  		wantErr bool
  1099  	}{
  1100  		{"", 0, false},
  1101  		{"modtime", trackRenamesStrategyModtime, false},
  1102  		{"hash", trackRenamesStrategyHash, false},
  1103  		{"size", 0, false},
  1104  		{"modtime,hash", trackRenamesStrategyModtime | trackRenamesStrategyHash, false},
  1105  		{"hash,modtime,size", trackRenamesStrategyModtime | trackRenamesStrategyHash, false},
  1106  		{"size,boom", 0, true},
  1107  	} {
  1108  		got, err := parseTrackRenamesStrategy(test.in)
  1109  		assert.Equal(t, test.want, got, test.in)
  1110  		assert.Equal(t, test.wantErr, err != nil, test.in)
  1111  	}
  1112  }
  1113  
  1114  func TestRenamesStrategyModtime(t *testing.T) {
  1115  	both := trackRenamesStrategyHash | trackRenamesStrategyModtime
  1116  	hash := trackRenamesStrategyHash
  1117  	modTime := trackRenamesStrategyModtime
  1118  
  1119  	assert.True(t, both.hash())
  1120  	assert.True(t, both.modTime())
  1121  	assert.True(t, hash.hash())
  1122  	assert.False(t, hash.modTime())
  1123  	assert.False(t, modTime.hash())
  1124  	assert.True(t, modTime.modTime())
  1125  }
  1126  
  1127  func TestSyncWithTrackRenamesStrategyModtime(t *testing.T) {
  1128  	r := fstest.NewRun(t)
  1129  	defer r.Finalise()
  1130  
  1131  	fs.Config.TrackRenames = true
  1132  	fs.Config.TrackRenamesStrategy = "modtime"
  1133  	defer func() {
  1134  		fs.Config.TrackRenames = false
  1135  		fs.Config.TrackRenamesStrategy = "hash"
  1136  	}()
  1137  
  1138  	canTrackRenames := operations.CanServerSideMove(r.Fremote) && r.Fremote.Precision() != fs.ModTimeNotSupported
  1139  	t.Logf("Can track renames: %v", canTrackRenames)
  1140  
  1141  	f1 := r.WriteFile("potato", "Potato Content", t1)
  1142  	f2 := r.WriteFile("yam", "Yam Content", t2)
  1143  
  1144  	accounting.GlobalStats().ResetCounters()
  1145  	require.NoError(t, Sync(context.Background(), r.Fremote, r.Flocal, false))
  1146  
  1147  	fstest.CheckItems(t, r.Fremote, f1, f2)
  1148  	fstest.CheckItems(t, r.Flocal, f1, f2)
  1149  
  1150  	// Now rename locally.
  1151  	f2 = r.RenameFile(f2, "yaml")
  1152  
  1153  	accounting.GlobalStats().ResetCounters()
  1154  	require.NoError(t, Sync(context.Background(), r.Fremote, r.Flocal, false))
  1155  
  1156  	fstest.CheckItems(t, r.Fremote, f1, f2)
  1157  
  1158  	// Check we renamed something if we should have
  1159  	if canTrackRenames {
  1160  		renames := accounting.GlobalStats().Renames(0)
  1161  		assert.Equal(t, canTrackRenames, renames != 0, fmt.Sprintf("canTrackRenames=%v, renames=%d", canTrackRenames, renames))
  1162  	}
  1163  }
  1164  
  1165  func toyFileTransfers(r *fstest.Run) int64 {
  1166  	remote := r.Fremote.Name()
  1167  	transfers := 1
  1168  	if strings.HasPrefix(remote, "TestChunker") && strings.HasSuffix(remote, "S3") {
  1169  		transfers++ // Extra Copy because S3 emulates Move as Copy+Delete.
  1170  	}
  1171  	return int64(transfers)
  1172  }
  1173  
  1174  // Test a server side move if possible, or the backup path if not
  1175  func testServerSideMove(t *testing.T, r *fstest.Run, withFilter, testDeleteEmptyDirs bool) {
  1176  	FremoteMove, _, finaliseMove, err := fstest.RandomRemote()
  1177  	require.NoError(t, err)
  1178  	defer finaliseMove()
  1179  
  1180  	file1 := r.WriteBoth(context.Background(), "potato2", "------------------------------------------------------------", t1)
  1181  	file2 := r.WriteBoth(context.Background(), "empty space", "-", t2)
  1182  	file3u := r.WriteBoth(context.Background(), "potato3", "------------------------------------------------------------ UPDATED", t2)
  1183  
  1184  	if testDeleteEmptyDirs {
  1185  		err := operations.Mkdir(context.Background(), r.Fremote, "tomatoDir")
  1186  		require.NoError(t, err)
  1187  	}
  1188  
  1189  	fstest.CheckItems(t, r.Fremote, file2, file1, file3u)
  1190  
  1191  	t.Logf("Server side move (if possible) %v -> %v", r.Fremote, FremoteMove)
  1192  
  1193  	// Write just one file in the new remote
  1194  	r.WriteObjectTo(context.Background(), FremoteMove, "empty space", "-", t2, false)
  1195  	file3 := r.WriteObjectTo(context.Background(), FremoteMove, "potato3", "------------------------------------------------------------", t1, false)
  1196  	fstest.CheckItems(t, FremoteMove, file2, file3)
  1197  
  1198  	// Do server side move
  1199  	accounting.GlobalStats().ResetCounters()
  1200  	err = MoveDir(context.Background(), FremoteMove, r.Fremote, testDeleteEmptyDirs, false)
  1201  	require.NoError(t, err)
  1202  
  1203  	if withFilter {
  1204  		fstest.CheckItems(t, r.Fremote, file2)
  1205  	} else {
  1206  		fstest.CheckItems(t, r.Fremote)
  1207  	}
  1208  
  1209  	if testDeleteEmptyDirs {
  1210  		fstest.CheckListingWithPrecision(t, r.Fremote, nil, []string{}, fs.GetModifyWindow(r.Fremote))
  1211  	}
  1212  
  1213  	fstest.CheckItems(t, FremoteMove, file2, file1, file3u)
  1214  
  1215  	// Create a new empty remote for stuff to be moved into
  1216  	FremoteMove2, _, finaliseMove2, err := fstest.RandomRemote()
  1217  	require.NoError(t, err)
  1218  	defer finaliseMove2()
  1219  
  1220  	if testDeleteEmptyDirs {
  1221  		err := operations.Mkdir(context.Background(), FremoteMove, "tomatoDir")
  1222  		require.NoError(t, err)
  1223  	}
  1224  
  1225  	// Move it back to a new empty remote, dst does not exist this time
  1226  	accounting.GlobalStats().ResetCounters()
  1227  	err = MoveDir(context.Background(), FremoteMove2, FremoteMove, testDeleteEmptyDirs, false)
  1228  	require.NoError(t, err)
  1229  
  1230  	if withFilter {
  1231  		fstest.CheckItems(t, FremoteMove2, file1, file3u)
  1232  		fstest.CheckItems(t, FremoteMove, file2)
  1233  	} else {
  1234  		fstest.CheckItems(t, FremoteMove2, file2, file1, file3u)
  1235  		fstest.CheckItems(t, FremoteMove)
  1236  	}
  1237  
  1238  	if testDeleteEmptyDirs {
  1239  		fstest.CheckListingWithPrecision(t, FremoteMove, nil, []string{}, fs.GetModifyWindow(r.Fremote))
  1240  	}
  1241  }
  1242  
  1243  // Test move
  1244  func TestMoveWithDeleteEmptySrcDirs(t *testing.T) {
  1245  	r := fstest.NewRun(t)
  1246  	defer r.Finalise()
  1247  	file1 := r.WriteFile("sub dir/hello world", "hello world", t1)
  1248  	file2 := r.WriteFile("nested/sub dir/file", "nested", t1)
  1249  	r.Mkdir(context.Background(), r.Fremote)
  1250  
  1251  	// run move with --delete-empty-src-dirs
  1252  	err := MoveDir(context.Background(), r.Fremote, r.Flocal, true, false)
  1253  	require.NoError(t, err)
  1254  
  1255  	fstest.CheckListingWithPrecision(
  1256  		t,
  1257  		r.Flocal,
  1258  		nil,
  1259  		[]string{},
  1260  		fs.GetModifyWindow(r.Flocal),
  1261  	)
  1262  	fstest.CheckItems(t, r.Fremote, file1, file2)
  1263  }
  1264  
  1265  func TestMoveWithoutDeleteEmptySrcDirs(t *testing.T) {
  1266  	r := fstest.NewRun(t)
  1267  	defer r.Finalise()
  1268  	file1 := r.WriteFile("sub dir/hello world", "hello world", t1)
  1269  	file2 := r.WriteFile("nested/sub dir/file", "nested", t1)
  1270  	r.Mkdir(context.Background(), r.Fremote)
  1271  
  1272  	err := MoveDir(context.Background(), r.Fremote, r.Flocal, false, false)
  1273  	require.NoError(t, err)
  1274  
  1275  	fstest.CheckListingWithPrecision(
  1276  		t,
  1277  		r.Flocal,
  1278  		nil,
  1279  		[]string{
  1280  			"sub dir",
  1281  			"nested",
  1282  			"nested/sub dir",
  1283  		},
  1284  		fs.GetModifyWindow(r.Flocal),
  1285  	)
  1286  	fstest.CheckItems(t, r.Fremote, file1, file2)
  1287  }
  1288  
  1289  // Test a server side move if possible, or the backup path if not
  1290  func TestServerSideMove(t *testing.T) {
  1291  	r := fstest.NewRun(t)
  1292  	defer r.Finalise()
  1293  	testServerSideMove(t, r, false, false)
  1294  }
  1295  
  1296  // Test a server side move if possible, or the backup path if not
  1297  func TestServerSideMoveWithFilter(t *testing.T) {
  1298  	r := fstest.NewRun(t)
  1299  	defer r.Finalise()
  1300  
  1301  	filter.Active.Opt.MinSize = 40
  1302  	defer func() {
  1303  		filter.Active.Opt.MinSize = -1
  1304  	}()
  1305  
  1306  	testServerSideMove(t, r, true, false)
  1307  }
  1308  
  1309  // Test a server side move if possible
  1310  func TestServerSideMoveDeleteEmptySourceDirs(t *testing.T) {
  1311  	r := fstest.NewRun(t)
  1312  	defer r.Finalise()
  1313  	testServerSideMove(t, r, false, true)
  1314  }
  1315  
  1316  // Test a server side move with overlap
  1317  func TestServerSideMoveOverlap(t *testing.T) {
  1318  	r := fstest.NewRun(t)
  1319  	defer r.Finalise()
  1320  
  1321  	if r.Fremote.Features().DirMove != nil {
  1322  		t.Skip("Skipping test as remote supports DirMove")
  1323  	}
  1324  
  1325  	subRemoteName := r.FremoteName + "/rclone-move-test"
  1326  	FremoteMove, err := fs.NewFs(subRemoteName)
  1327  	require.NoError(t, err)
  1328  
  1329  	file1 := r.WriteObject(context.Background(), "potato2", "------------------------------------------------------------", t1)
  1330  	fstest.CheckItems(t, r.Fremote, file1)
  1331  
  1332  	// Subdir move with no filters should return ErrorCantMoveOverlapping
  1333  	err = MoveDir(context.Background(), FremoteMove, r.Fremote, false, false)
  1334  	assert.EqualError(t, err, fs.ErrorOverlapping.Error())
  1335  
  1336  	// Now try with a filter which should also fail with ErrorCantMoveOverlapping
  1337  	filter.Active.Opt.MinSize = 40
  1338  	defer func() {
  1339  		filter.Active.Opt.MinSize = -1
  1340  	}()
  1341  	err = MoveDir(context.Background(), FremoteMove, r.Fremote, false, false)
  1342  	assert.EqualError(t, err, fs.ErrorOverlapping.Error())
  1343  }
  1344  
  1345  // Test a sync with overlap
  1346  func TestSyncOverlap(t *testing.T) {
  1347  	r := fstest.NewRun(t)
  1348  	defer r.Finalise()
  1349  
  1350  	subRemoteName := r.FremoteName + "/rclone-sync-test"
  1351  	FremoteSync, err := fs.NewFs(subRemoteName)
  1352  	require.NoError(t, err)
  1353  
  1354  	checkErr := func(err error) {
  1355  		require.Error(t, err)
  1356  		assert.True(t, fserrors.IsFatalError(err))
  1357  		assert.Equal(t, fs.ErrorOverlapping.Error(), err.Error())
  1358  	}
  1359  
  1360  	checkErr(Sync(context.Background(), FremoteSync, r.Fremote, false))
  1361  	checkErr(Sync(context.Background(), r.Fremote, FremoteSync, false))
  1362  	checkErr(Sync(context.Background(), r.Fremote, r.Fremote, false))
  1363  	checkErr(Sync(context.Background(), FremoteSync, FremoteSync, false))
  1364  }
  1365  
  1366  // Test with CompareDest set
  1367  func TestSyncCompareDest(t *testing.T) {
  1368  	r := fstest.NewRun(t)
  1369  	defer r.Finalise()
  1370  
  1371  	fs.Config.CompareDest = r.FremoteName + "/CompareDest"
  1372  	defer func() {
  1373  		fs.Config.CompareDest = ""
  1374  	}()
  1375  
  1376  	fdst, err := fs.NewFs(r.FremoteName + "/dst")
  1377  	require.NoError(t, err)
  1378  
  1379  	// check empty dest, empty compare
  1380  	file1 := r.WriteFile("one", "one", t1)
  1381  	fstest.CheckItems(t, r.Flocal, file1)
  1382  
  1383  	accounting.GlobalStats().ResetCounters()
  1384  	err = Sync(context.Background(), fdst, r.Flocal, false)
  1385  	require.NoError(t, err)
  1386  
  1387  	file1dst := file1
  1388  	file1dst.Path = "dst/one"
  1389  
  1390  	fstest.CheckItems(t, r.Fremote, file1dst)
  1391  
  1392  	// check old dest, empty compare
  1393  	file1b := r.WriteFile("one", "onet2", t2)
  1394  	fstest.CheckItems(t, r.Fremote, file1dst)
  1395  	fstest.CheckItems(t, r.Flocal, file1b)
  1396  
  1397  	accounting.GlobalStats().ResetCounters()
  1398  	err = Sync(context.Background(), fdst, r.Flocal, false)
  1399  	require.NoError(t, err)
  1400  
  1401  	file1bdst := file1b
  1402  	file1bdst.Path = "dst/one"
  1403  
  1404  	fstest.CheckItems(t, r.Fremote, file1bdst)
  1405  
  1406  	// check old dest, new compare
  1407  	file3 := r.WriteObject(context.Background(), "dst/one", "one", t1)
  1408  	file2 := r.WriteObject(context.Background(), "CompareDest/one", "onet2", t2)
  1409  	file1c := r.WriteFile("one", "onet2", t2)
  1410  	fstest.CheckItems(t, r.Fremote, file2, file3)
  1411  	fstest.CheckItems(t, r.Flocal, file1c)
  1412  
  1413  	accounting.GlobalStats().ResetCounters()
  1414  	err = Sync(context.Background(), fdst, r.Flocal, false)
  1415  	require.NoError(t, err)
  1416  
  1417  	fstest.CheckItems(t, r.Fremote, file2, file3)
  1418  
  1419  	// check empty dest, new compare
  1420  	file4 := r.WriteObject(context.Background(), "CompareDest/two", "two", t2)
  1421  	file5 := r.WriteFile("two", "two", t2)
  1422  	fstest.CheckItems(t, r.Fremote, file2, file3, file4)
  1423  	fstest.CheckItems(t, r.Flocal, file1c, file5)
  1424  
  1425  	accounting.GlobalStats().ResetCounters()
  1426  	err = Sync(context.Background(), fdst, r.Flocal, false)
  1427  	require.NoError(t, err)
  1428  
  1429  	fstest.CheckItems(t, r.Fremote, file2, file3, file4)
  1430  
  1431  	// check new dest, new compare
  1432  	accounting.GlobalStats().ResetCounters()
  1433  	err = Sync(context.Background(), fdst, r.Flocal, false)
  1434  	require.NoError(t, err)
  1435  
  1436  	fstest.CheckItems(t, r.Fremote, file2, file3, file4)
  1437  
  1438  	// check empty dest, old compare
  1439  	file5b := r.WriteFile("two", "twot3", t3)
  1440  	fstest.CheckItems(t, r.Fremote, file2, file3, file4)
  1441  	fstest.CheckItems(t, r.Flocal, file1c, file5b)
  1442  
  1443  	accounting.GlobalStats().ResetCounters()
  1444  	err = Sync(context.Background(), fdst, r.Flocal, false)
  1445  	require.NoError(t, err)
  1446  
  1447  	file5bdst := file5b
  1448  	file5bdst.Path = "dst/two"
  1449  
  1450  	fstest.CheckItems(t, r.Fremote, file2, file3, file4, file5bdst)
  1451  }
  1452  
  1453  // Test with CopyDest set
  1454  func TestSyncCopyDest(t *testing.T) {
  1455  	r := fstest.NewRun(t)
  1456  	defer r.Finalise()
  1457  
  1458  	if r.Fremote.Features().Copy == nil {
  1459  		t.Skip("Skipping test as remote does not support server side copy")
  1460  	}
  1461  
  1462  	fs.Config.CopyDest = r.FremoteName + "/CopyDest"
  1463  	defer func() {
  1464  		fs.Config.CopyDest = ""
  1465  	}()
  1466  
  1467  	fdst, err := fs.NewFs(r.FremoteName + "/dst")
  1468  	require.NoError(t, err)
  1469  
  1470  	// check empty dest, empty copy
  1471  	file1 := r.WriteFile("one", "one", t1)
  1472  	fstest.CheckItems(t, r.Flocal, file1)
  1473  
  1474  	accounting.GlobalStats().ResetCounters()
  1475  	err = Sync(context.Background(), fdst, r.Flocal, false)
  1476  	require.NoError(t, err)
  1477  
  1478  	file1dst := file1
  1479  	file1dst.Path = "dst/one"
  1480  
  1481  	fstest.CheckItems(t, r.Fremote, file1dst)
  1482  
  1483  	// check old dest, empty copy
  1484  	file1b := r.WriteFile("one", "onet2", t2)
  1485  	fstest.CheckItems(t, r.Fremote, file1dst)
  1486  	fstest.CheckItems(t, r.Flocal, file1b)
  1487  
  1488  	accounting.GlobalStats().ResetCounters()
  1489  	err = Sync(context.Background(), fdst, r.Flocal, false)
  1490  	require.NoError(t, err)
  1491  
  1492  	file1bdst := file1b
  1493  	file1bdst.Path = "dst/one"
  1494  
  1495  	fstest.CheckItems(t, r.Fremote, file1bdst)
  1496  
  1497  	// check old dest, new copy, backup-dir
  1498  
  1499  	fs.Config.BackupDir = r.FremoteName + "/BackupDir"
  1500  
  1501  	file3 := r.WriteObject(context.Background(), "dst/one", "one", t1)
  1502  	file2 := r.WriteObject(context.Background(), "CopyDest/one", "onet2", t2)
  1503  	file1c := r.WriteFile("one", "onet2", t2)
  1504  	fstest.CheckItems(t, r.Fremote, file2, file3)
  1505  	fstest.CheckItems(t, r.Flocal, file1c)
  1506  
  1507  	accounting.GlobalStats().ResetCounters()
  1508  	err = Sync(context.Background(), fdst, r.Flocal, false)
  1509  	require.NoError(t, err)
  1510  
  1511  	file2dst := file2
  1512  	file2dst.Path = "dst/one"
  1513  	file3.Path = "BackupDir/one"
  1514  
  1515  	fstest.CheckItems(t, r.Fremote, file2, file2dst, file3)
  1516  	fs.Config.BackupDir = ""
  1517  
  1518  	// check empty dest, new copy
  1519  	file4 := r.WriteObject(context.Background(), "CopyDest/two", "two", t2)
  1520  	file5 := r.WriteFile("two", "two", t2)
  1521  	fstest.CheckItems(t, r.Fremote, file2, file2dst, file3, file4)
  1522  	fstest.CheckItems(t, r.Flocal, file1c, file5)
  1523  
  1524  	accounting.GlobalStats().ResetCounters()
  1525  	err = Sync(context.Background(), fdst, r.Flocal, false)
  1526  	require.NoError(t, err)
  1527  
  1528  	file4dst := file4
  1529  	file4dst.Path = "dst/two"
  1530  
  1531  	fstest.CheckItems(t, r.Fremote, file2, file2dst, file3, file4, file4dst)
  1532  
  1533  	// check new dest, new copy
  1534  	accounting.GlobalStats().ResetCounters()
  1535  	err = Sync(context.Background(), fdst, r.Flocal, false)
  1536  	require.NoError(t, err)
  1537  
  1538  	fstest.CheckItems(t, r.Fremote, file2, file2dst, file3, file4, file4dst)
  1539  
  1540  	// check empty dest, old copy
  1541  	file6 := r.WriteObject(context.Background(), "CopyDest/three", "three", t2)
  1542  	file7 := r.WriteFile("three", "threet3", t3)
  1543  	fstest.CheckItems(t, r.Fremote, file2, file2dst, file3, file4, file4dst, file6)
  1544  	fstest.CheckItems(t, r.Flocal, file1c, file5, file7)
  1545  
  1546  	accounting.GlobalStats().ResetCounters()
  1547  	err = Sync(context.Background(), fdst, r.Flocal, false)
  1548  	require.NoError(t, err)
  1549  
  1550  	file7dst := file7
  1551  	file7dst.Path = "dst/three"
  1552  
  1553  	fstest.CheckItems(t, r.Fremote, file2, file2dst, file3, file4, file4dst, file6, file7dst)
  1554  }
  1555  
  1556  // Test with BackupDir set
  1557  func testSyncBackupDir(t *testing.T, suffix string, suffixKeepExtension bool) {
  1558  	r := fstest.NewRun(t)
  1559  	defer r.Finalise()
  1560  
  1561  	if !operations.CanServerSideMove(r.Fremote) {
  1562  		t.Skip("Skipping test as remote does not support server side move")
  1563  	}
  1564  	r.Mkdir(context.Background(), r.Fremote)
  1565  
  1566  	fs.Config.BackupDir = r.FremoteName + "/backup"
  1567  	fs.Config.Suffix = suffix
  1568  	fs.Config.SuffixKeepExtension = suffixKeepExtension
  1569  	defer func() {
  1570  		fs.Config.BackupDir = ""
  1571  		fs.Config.Suffix = ""
  1572  		fs.Config.SuffixKeepExtension = false
  1573  	}()
  1574  
  1575  	// Make the setup so we have one, two, three in the dest
  1576  	// and one (different), two (same) in the source
  1577  	file1 := r.WriteObject(context.Background(), "dst/one", "one", t1)
  1578  	file2 := r.WriteObject(context.Background(), "dst/two", "two", t1)
  1579  	file3 := r.WriteObject(context.Background(), "dst/three.txt", "three", t1)
  1580  	file2a := r.WriteFile("two", "two", t1)
  1581  	file1a := r.WriteFile("one", "oneA", t2)
  1582  
  1583  	fstest.CheckItems(t, r.Fremote, file1, file2, file3)
  1584  	fstest.CheckItems(t, r.Flocal, file1a, file2a)
  1585  
  1586  	fdst, err := fs.NewFs(r.FremoteName + "/dst")
  1587  	require.NoError(t, err)
  1588  
  1589  	accounting.GlobalStats().ResetCounters()
  1590  	err = Sync(context.Background(), fdst, r.Flocal, false)
  1591  	require.NoError(t, err)
  1592  
  1593  	// one should be moved to the backup dir and the new one installed
  1594  	file1.Path = "backup/one" + suffix
  1595  	file1a.Path = "dst/one"
  1596  	// two should be unchanged
  1597  	// three should be moved to the backup dir
  1598  	if suffixKeepExtension {
  1599  		file3.Path = "backup/three" + suffix + ".txt"
  1600  	} else {
  1601  		file3.Path = "backup/three.txt" + suffix
  1602  	}
  1603  
  1604  	fstest.CheckItems(t, r.Fremote, file1, file2, file3, file1a)
  1605  
  1606  	// Now check what happens if we do it again
  1607  	// Restore a different three and update one in the source
  1608  	file3a := r.WriteObject(context.Background(), "dst/three.txt", "threeA", t2)
  1609  	file1b := r.WriteFile("one", "oneBB", t3)
  1610  	fstest.CheckItems(t, r.Fremote, file1, file2, file3, file1a, file3a)
  1611  
  1612  	// This should delete three and overwrite one again, checking
  1613  	// the files got overwritten correctly in backup-dir
  1614  	accounting.GlobalStats().ResetCounters()
  1615  	err = Sync(context.Background(), fdst, r.Flocal, false)
  1616  	require.NoError(t, err)
  1617  
  1618  	// one should be moved to the backup dir and the new one installed
  1619  	file1a.Path = "backup/one" + suffix
  1620  	file1b.Path = "dst/one"
  1621  	// two should be unchanged
  1622  	// three should be moved to the backup dir
  1623  	if suffixKeepExtension {
  1624  		file3a.Path = "backup/three" + suffix + ".txt"
  1625  	} else {
  1626  		file3a.Path = "backup/three.txt" + suffix
  1627  	}
  1628  
  1629  	fstest.CheckItems(t, r.Fremote, file1b, file2, file3a, file1a)
  1630  }
  1631  func TestSyncBackupDir(t *testing.T)           { testSyncBackupDir(t, "", false) }
  1632  func TestSyncBackupDirWithSuffix(t *testing.T) { testSyncBackupDir(t, ".bak", false) }
  1633  func TestSyncBackupDirWithSuffixKeepExtension(t *testing.T) {
  1634  	testSyncBackupDir(t, "-2019-01-01", true)
  1635  }
  1636  
  1637  // Test with Suffix set
  1638  func testSyncSuffix(t *testing.T, suffix string, suffixKeepExtension bool) {
  1639  	r := fstest.NewRun(t)
  1640  	defer r.Finalise()
  1641  
  1642  	if !operations.CanServerSideMove(r.Fremote) {
  1643  		t.Skip("Skipping test as remote does not support server side move")
  1644  	}
  1645  	r.Mkdir(context.Background(), r.Fremote)
  1646  
  1647  	fs.Config.Suffix = suffix
  1648  	fs.Config.SuffixKeepExtension = suffixKeepExtension
  1649  	defer func() {
  1650  		fs.Config.BackupDir = ""
  1651  		fs.Config.Suffix = ""
  1652  		fs.Config.SuffixKeepExtension = false
  1653  	}()
  1654  
  1655  	// Make the setup so we have one, two, three in the dest
  1656  	// and one (different), two (same) in the source
  1657  	file1 := r.WriteObject(context.Background(), "dst/one", "one", t1)
  1658  	file2 := r.WriteObject(context.Background(), "dst/two", "two", t1)
  1659  	file3 := r.WriteObject(context.Background(), "dst/three.txt", "three", t1)
  1660  	file2a := r.WriteFile("two", "two", t1)
  1661  	file1a := r.WriteFile("one", "oneA", t2)
  1662  	file3a := r.WriteFile("three.txt", "threeA", t1)
  1663  
  1664  	fstest.CheckItems(t, r.Fremote, file1, file2, file3)
  1665  	fstest.CheckItems(t, r.Flocal, file1a, file2a, file3a)
  1666  
  1667  	fdst, err := fs.NewFs(r.FremoteName + "/dst")
  1668  	require.NoError(t, err)
  1669  
  1670  	accounting.GlobalStats().ResetCounters()
  1671  	err = operations.CopyFile(context.Background(), fdst, r.Flocal, "one", "one")
  1672  	require.NoError(t, err)
  1673  	err = operations.CopyFile(context.Background(), fdst, r.Flocal, "two", "two")
  1674  	require.NoError(t, err)
  1675  	err = operations.CopyFile(context.Background(), fdst, r.Flocal, "three.txt", "three.txt")
  1676  	require.NoError(t, err)
  1677  
  1678  	// one should be moved to the backup dir and the new one installed
  1679  	file1.Path = "dst/one" + suffix
  1680  	file1a.Path = "dst/one"
  1681  	// two should be unchanged
  1682  	// three should be moved to the backup dir
  1683  	if suffixKeepExtension {
  1684  		file3.Path = "dst/three" + suffix + ".txt"
  1685  	} else {
  1686  		file3.Path = "dst/three.txt" + suffix
  1687  	}
  1688  	file3a.Path = "dst/three.txt"
  1689  
  1690  	fstest.CheckItems(t, r.Fremote, file1, file2, file3, file1a, file3a)
  1691  
  1692  	// Now check what happens if we do it again
  1693  	// Restore a different three and update one in the source
  1694  	file3b := r.WriteFile("three.txt", "threeBDifferentSize", t3)
  1695  	file1b := r.WriteFile("one", "oneBB", t3)
  1696  	fstest.CheckItems(t, r.Fremote, file1, file2, file3, file1a, file3a)
  1697  
  1698  	// This should delete three and overwrite one again, checking
  1699  	// the files got overwritten correctly in backup-dir
  1700  	accounting.GlobalStats().ResetCounters()
  1701  	err = operations.CopyFile(context.Background(), fdst, r.Flocal, "one", "one")
  1702  	require.NoError(t, err)
  1703  	err = operations.CopyFile(context.Background(), fdst, r.Flocal, "two", "two")
  1704  	require.NoError(t, err)
  1705  	err = operations.CopyFile(context.Background(), fdst, r.Flocal, "three.txt", "three.txt")
  1706  	require.NoError(t, err)
  1707  
  1708  	// one should be moved to the backup dir and the new one installed
  1709  	file1a.Path = "dst/one" + suffix
  1710  	file1b.Path = "dst/one"
  1711  	// two should be unchanged
  1712  	// three should be moved to the backup dir
  1713  	if suffixKeepExtension {
  1714  		file3a.Path = "dst/three" + suffix + ".txt"
  1715  	} else {
  1716  		file3a.Path = "dst/three.txt" + suffix
  1717  	}
  1718  	file3b.Path = "dst/three.txt"
  1719  
  1720  	fstest.CheckItems(t, r.Fremote, file1b, file3b, file2, file3a, file1a)
  1721  }
  1722  func TestSyncSuffix(t *testing.T)              { testSyncSuffix(t, ".bak", false) }
  1723  func TestSyncSuffixKeepExtension(t *testing.T) { testSyncSuffix(t, "-2019-01-01", true) }
  1724  
  1725  // Check we can sync two files with differing UTF-8 representations
  1726  func TestSyncUTFNorm(t *testing.T) {
  1727  	if runtime.GOOS == "darwin" {
  1728  		t.Skip("Can't test UTF normalization on OS X")
  1729  	}
  1730  
  1731  	r := fstest.NewRun(t)
  1732  	defer r.Finalise()
  1733  
  1734  	// Two strings with different unicode normalization (from OS X)
  1735  	Encoding1 := "Testêé"
  1736  	Encoding2 := "Testêé"
  1737  	assert.NotEqual(t, Encoding1, Encoding2)
  1738  	assert.Equal(t, norm.NFC.String(Encoding1), norm.NFC.String(Encoding2))
  1739  
  1740  	file1 := r.WriteFile(Encoding1, "This is a test", t1)
  1741  	fstest.CheckItems(t, r.Flocal, file1)
  1742  
  1743  	file2 := r.WriteObject(context.Background(), Encoding2, "This is a old test", t2)
  1744  	fstest.CheckItems(t, r.Fremote, file2)
  1745  
  1746  	accounting.GlobalStats().ResetCounters()
  1747  	err := Sync(context.Background(), r.Fremote, r.Flocal, false)
  1748  	require.NoError(t, err)
  1749  
  1750  	// We should have transferred exactly one file, but kept the
  1751  	// normalized state of the file.
  1752  	assert.Equal(t, toyFileTransfers(r), accounting.GlobalStats().GetTransfers())
  1753  	fstest.CheckItems(t, r.Flocal, file1)
  1754  	file1.Path = file2.Path
  1755  	fstest.CheckItems(t, r.Fremote, file1)
  1756  }
  1757  
  1758  // Test --immutable
  1759  func TestSyncImmutable(t *testing.T) {
  1760  	r := fstest.NewRun(t)
  1761  	defer r.Finalise()
  1762  
  1763  	fs.Config.Immutable = true
  1764  	defer func() { fs.Config.Immutable = false }()
  1765  
  1766  	// Create file on source
  1767  	file1 := r.WriteFile("existing", "potato", t1)
  1768  	fstest.CheckItems(t, r.Flocal, file1)
  1769  	fstest.CheckItems(t, r.Fremote)
  1770  
  1771  	// Should succeed
  1772  	accounting.GlobalStats().ResetCounters()
  1773  	err := Sync(context.Background(), r.Fremote, r.Flocal, false)
  1774  	require.NoError(t, err)
  1775  	fstest.CheckItems(t, r.Flocal, file1)
  1776  	fstest.CheckItems(t, r.Fremote, file1)
  1777  
  1778  	// Modify file data and timestamp on source
  1779  	file2 := r.WriteFile("existing", "tomatoes", t2)
  1780  	fstest.CheckItems(t, r.Flocal, file2)
  1781  	fstest.CheckItems(t, r.Fremote, file1)
  1782  
  1783  	// Should fail with ErrorImmutableModified and not modify local or remote files
  1784  	accounting.GlobalStats().ResetCounters()
  1785  	err = Sync(context.Background(), r.Fremote, r.Flocal, false)
  1786  	assert.EqualError(t, err, fs.ErrorImmutableModified.Error())
  1787  	fstest.CheckItems(t, r.Flocal, file2)
  1788  	fstest.CheckItems(t, r.Fremote, file1)
  1789  }
  1790  
  1791  // Test --ignore-case-sync
  1792  func TestSyncIgnoreCase(t *testing.T) {
  1793  	r := fstest.NewRun(t)
  1794  	defer r.Finalise()
  1795  
  1796  	// Only test if filesystems are case sensitive
  1797  	if r.Fremote.Features().CaseInsensitive || r.Flocal.Features().CaseInsensitive {
  1798  		t.Skip("Skipping test as local or remote are case-insensitive")
  1799  	}
  1800  
  1801  	fs.Config.IgnoreCaseSync = true
  1802  	defer func() { fs.Config.IgnoreCaseSync = false }()
  1803  
  1804  	// Create files with different filename casing
  1805  	file1 := r.WriteFile("existing", "potato", t1)
  1806  	fstest.CheckItems(t, r.Flocal, file1)
  1807  	file2 := r.WriteObject(context.Background(), "EXISTING", "potato", t1)
  1808  	fstest.CheckItems(t, r.Fremote, file2)
  1809  
  1810  	// Should not copy files that are differently-cased but otherwise identical
  1811  	accounting.GlobalStats().ResetCounters()
  1812  	err := Sync(context.Background(), r.Fremote, r.Flocal, false)
  1813  	require.NoError(t, err)
  1814  	fstest.CheckItems(t, r.Flocal, file1)
  1815  	fstest.CheckItems(t, r.Fremote, file2)
  1816  }
  1817  
  1818  // Test that aborting on max upload works
  1819  func TestAbort(t *testing.T) {
  1820  	r := fstest.NewRun(t)
  1821  	defer r.Finalise()
  1822  
  1823  	if r.Fremote.Name() != "local" {
  1824  		t.Skip("This test only runs on local")
  1825  	}
  1826  
  1827  	oldMaxTransfer := fs.Config.MaxTransfer
  1828  	oldTransfers := fs.Config.Transfers
  1829  	oldCheckers := fs.Config.Checkers
  1830  	fs.Config.MaxTransfer = 3 * 1024
  1831  	fs.Config.Transfers = 1
  1832  	fs.Config.Checkers = 1
  1833  	defer func() {
  1834  		fs.Config.MaxTransfer = oldMaxTransfer
  1835  		fs.Config.Transfers = oldTransfers
  1836  		fs.Config.Checkers = oldCheckers
  1837  	}()
  1838  
  1839  	// Create file on source
  1840  	file1 := r.WriteFile("file1", string(make([]byte, 5*1024)), t1)
  1841  	file2 := r.WriteFile("file2", string(make([]byte, 2*1024)), t1)
  1842  	file3 := r.WriteFile("file3", string(make([]byte, 3*1024)), t1)
  1843  	fstest.CheckItems(t, r.Flocal, file1, file2, file3)
  1844  	fstest.CheckItems(t, r.Fremote)
  1845  
  1846  	accounting.GlobalStats().ResetCounters()
  1847  
  1848  	err := Sync(context.Background(), r.Fremote, r.Flocal, false)
  1849  	expectedErr := fserrors.FsError(accounting.ErrorMaxTransferLimitReachedFatal)
  1850  	fserrors.Count(expectedErr)
  1851  	assert.Equal(t, expectedErr, err)
  1852  }