github.com/ncw/rclone@v1.48.1-0.20190724201158-a35aa1360e3e/fs/operations/operations_test.go (about)

     1  // Integration tests - test rclone by doing real transactions to a
     2  // storage provider to and from the local disk.
     3  //
     4  // By default it will use a local fs, however you can provide a
     5  // -remote option to use a different remote.  The test_all.go script
     6  // is a wrapper to call this for all the test remotes.
     7  //
     8  // FIXME not safe for concurrent running of tests until fs.Config is
     9  // no longer a global
    10  //
    11  // NB When writing tests
    12  //
    13  // Make sure every series of writes to the remote has a
    14  // fstest.CheckItems() before use.  This make sure the directory
    15  // listing is now consistent and stops cascading errors.
    16  //
    17  // Call accounting.Stats.ResetCounters() before every fs.Sync() as it
    18  // uses the error count internally.
    19  
    20  package operations_test
    21  
    22  import (
    23  	"bytes"
    24  	"context"
    25  	"errors"
    26  	"fmt"
    27  	"io"
    28  	"io/ioutil"
    29  	"log"
    30  	"net/http"
    31  	"net/http/httptest"
    32  	"os"
    33  	"regexp"
    34  	"strings"
    35  	"testing"
    36  	"time"
    37  
    38  	_ "github.com/ncw/rclone/backend/all" // import all backends
    39  	"github.com/ncw/rclone/fs"
    40  	"github.com/ncw/rclone/fs/accounting"
    41  	"github.com/ncw/rclone/fs/filter"
    42  	"github.com/ncw/rclone/fs/fshttp"
    43  	"github.com/ncw/rclone/fs/hash"
    44  	"github.com/ncw/rclone/fs/operations"
    45  	"github.com/ncw/rclone/fstest"
    46  	"github.com/stretchr/testify/assert"
    47  	"github.com/stretchr/testify/require"
    48  )
    49  
    50  // Some times used in the tests
    51  var (
    52  	t1 = fstest.Time("2001-02-03T04:05:06.499999999Z")
    53  	t2 = fstest.Time("2011-12-25T12:59:59.123456789Z")
    54  	t3 = fstest.Time("2011-12-30T12:59:59.000000000Z")
    55  )
    56  
    57  // TestMain drives the tests
    58  func TestMain(m *testing.M) {
    59  	fstest.TestMain(m)
    60  }
    61  
    62  func TestMkdir(t *testing.T) {
    63  	r := fstest.NewRun(t)
    64  	defer r.Finalise()
    65  
    66  	err := operations.Mkdir(context.Background(), r.Fremote, "")
    67  	require.NoError(t, err)
    68  	fstest.CheckListing(t, r.Fremote, []fstest.Item{})
    69  
    70  	err = operations.Mkdir(context.Background(), r.Fremote, "")
    71  	require.NoError(t, err)
    72  }
    73  
    74  func TestLsd(t *testing.T) {
    75  	r := fstest.NewRun(t)
    76  	defer r.Finalise()
    77  	file1 := r.WriteObject(context.Background(), "sub dir/hello world", "hello world", t1)
    78  
    79  	fstest.CheckItems(t, r.Fremote, file1)
    80  
    81  	var buf bytes.Buffer
    82  	err := operations.ListDir(context.Background(), r.Fremote, &buf)
    83  	require.NoError(t, err)
    84  	res := buf.String()
    85  	assert.Contains(t, res, "sub dir\n")
    86  }
    87  
    88  func TestLs(t *testing.T) {
    89  	r := fstest.NewRun(t)
    90  	defer r.Finalise()
    91  	file1 := r.WriteBoth(context.Background(), "potato2", "------------------------------------------------------------", t1)
    92  	file2 := r.WriteBoth(context.Background(), "empty space", "-", t2)
    93  
    94  	fstest.CheckItems(t, r.Fremote, file1, file2)
    95  
    96  	var buf bytes.Buffer
    97  	err := operations.List(context.Background(), r.Fremote, &buf)
    98  	require.NoError(t, err)
    99  	res := buf.String()
   100  	assert.Contains(t, res, "        1 empty space\n")
   101  	assert.Contains(t, res, "       60 potato2\n")
   102  }
   103  
   104  func TestLsWithFilesFrom(t *testing.T) {
   105  	r := fstest.NewRun(t)
   106  	defer r.Finalise()
   107  	file1 := r.WriteBoth(context.Background(), "potato2", "------------------------------------------------------------", t1)
   108  	file2 := r.WriteBoth(context.Background(), "empty space", "-", t2)
   109  
   110  	fstest.CheckItems(t, r.Fremote, file1, file2)
   111  
   112  	// Set the --files-from equivalent
   113  	f, err := filter.NewFilter(nil)
   114  	require.NoError(t, err)
   115  	require.NoError(t, f.AddFile("potato2"))
   116  	require.NoError(t, f.AddFile("notfound"))
   117  
   118  	// Monkey patch the active filter
   119  	oldFilter := filter.Active
   120  	filter.Active = f
   121  	defer func() {
   122  		filter.Active = oldFilter
   123  	}()
   124  
   125  	var buf bytes.Buffer
   126  	err = operations.List(context.Background(), r.Fremote, &buf)
   127  	require.NoError(t, err)
   128  	assert.Equal(t, "       60 potato2\n", buf.String())
   129  
   130  	// Now try with --no-traverse
   131  	oldNoTraverse := fs.Config.NoTraverse
   132  	fs.Config.NoTraverse = true
   133  	defer func() {
   134  		fs.Config.NoTraverse = oldNoTraverse
   135  	}()
   136  
   137  	buf.Reset()
   138  	err = operations.List(context.Background(), r.Fremote, &buf)
   139  	require.NoError(t, err)
   140  	assert.Equal(t, "       60 potato2\n", buf.String())
   141  }
   142  
   143  func TestLsLong(t *testing.T) {
   144  	r := fstest.NewRun(t)
   145  	defer r.Finalise()
   146  	file1 := r.WriteBoth(context.Background(), "potato2", "------------------------------------------------------------", t1)
   147  	file2 := r.WriteBoth(context.Background(), "empty space", "-", t2)
   148  
   149  	fstest.CheckItems(t, r.Fremote, file1, file2)
   150  
   151  	var buf bytes.Buffer
   152  	err := operations.ListLong(context.Background(), r.Fremote, &buf)
   153  	require.NoError(t, err)
   154  	res := buf.String()
   155  	lines := strings.Split(strings.Trim(res, "\n"), "\n")
   156  	assert.Equal(t, 2, len(lines))
   157  
   158  	timeFormat := "2006-01-02 15:04:05.000000000"
   159  	precision := r.Fremote.Precision()
   160  	location := time.Now().Location()
   161  	checkTime := func(m, filename string, expected time.Time) {
   162  		modTime, err := time.ParseInLocation(timeFormat, m, location) // parse as localtime
   163  		if err != nil {
   164  			t.Errorf("Error parsing %q: %v", m, err)
   165  		} else {
   166  			dt, ok := fstest.CheckTimeEqualWithPrecision(expected, modTime, precision)
   167  			if !ok {
   168  				t.Errorf("%s: Modification time difference too big |%s| > %s (%s vs %s) (precision %s)", filename, dt, precision, modTime, expected, precision)
   169  			}
   170  		}
   171  	}
   172  
   173  	m1 := regexp.MustCompile(`(?m)^        1 (\d{4}-\d\d-\d\d \d\d:\d\d:\d\d\.\d{9}) empty space$`)
   174  	if ms := m1.FindStringSubmatch(res); ms == nil {
   175  		t.Errorf("empty space missing: %q", res)
   176  	} else {
   177  		checkTime(ms[1], "empty space", t2.Local())
   178  	}
   179  
   180  	m2 := regexp.MustCompile(`(?m)^       60 (\d{4}-\d\d-\d\d \d\d:\d\d:\d\d\.\d{9}) potato2$`)
   181  	if ms := m2.FindStringSubmatch(res); ms == nil {
   182  		t.Errorf("potato2 missing: %q", res)
   183  	} else {
   184  		checkTime(ms[1], "potato2", t1.Local())
   185  	}
   186  }
   187  
   188  func TestHashSums(t *testing.T) {
   189  	r := fstest.NewRun(t)
   190  	defer r.Finalise()
   191  	file1 := r.WriteBoth(context.Background(), "potato2", "------------------------------------------------------------", t1)
   192  	file2 := r.WriteBoth(context.Background(), "empty space", "-", t2)
   193  
   194  	fstest.CheckItems(t, r.Fremote, file1, file2)
   195  
   196  	// MD5 Sum
   197  
   198  	var buf bytes.Buffer
   199  	err := operations.Md5sum(context.Background(), r.Fremote, &buf)
   200  	require.NoError(t, err)
   201  	res := buf.String()
   202  	if !strings.Contains(res, "336d5ebc5436534e61d16e63ddfca327  empty space\n") &&
   203  		!strings.Contains(res, "                     UNSUPPORTED  empty space\n") &&
   204  		!strings.Contains(res, "                                  empty space\n") {
   205  		t.Errorf("empty space missing: %q", res)
   206  	}
   207  	if !strings.Contains(res, "d6548b156ea68a4e003e786df99eee76  potato2\n") &&
   208  		!strings.Contains(res, "                     UNSUPPORTED  potato2\n") &&
   209  		!strings.Contains(res, "                                  potato2\n") {
   210  		t.Errorf("potato2 missing: %q", res)
   211  	}
   212  
   213  	// SHA1 Sum
   214  
   215  	buf.Reset()
   216  	err = operations.Sha1sum(context.Background(), r.Fremote, &buf)
   217  	require.NoError(t, err)
   218  	res = buf.String()
   219  	if !strings.Contains(res, "3bc15c8aae3e4124dd409035f32ea2fd6835efc9  empty space\n") &&
   220  		!strings.Contains(res, "                             UNSUPPORTED  empty space\n") &&
   221  		!strings.Contains(res, "                                          empty space\n") {
   222  		t.Errorf("empty space missing: %q", res)
   223  	}
   224  	if !strings.Contains(res, "9dc7f7d3279715991a22853f5981df582b7f9f6d  potato2\n") &&
   225  		!strings.Contains(res, "                             UNSUPPORTED  potato2\n") &&
   226  		!strings.Contains(res, "                                          potato2\n") {
   227  		t.Errorf("potato2 missing: %q", res)
   228  	}
   229  
   230  	// Dropbox Hash Sum
   231  
   232  	buf.Reset()
   233  	err = operations.DropboxHashSum(context.Background(), r.Fremote, &buf)
   234  	require.NoError(t, err)
   235  	res = buf.String()
   236  	if !strings.Contains(res, "fc62b10ec59efa8041f5a6c924d7c91572c1bbda280d9e01312b660804df1d47  empty space\n") &&
   237  		!strings.Contains(res, "                                                     UNSUPPORTED  empty space\n") &&
   238  		!strings.Contains(res, "                                                                  empty space\n") {
   239  		t.Errorf("empty space missing: %q", res)
   240  	}
   241  	if !strings.Contains(res, "a979481df794fed9c3990a6a422e0b1044ac802c15fab13af9c687f8bdbee01a  potato2\n") &&
   242  		!strings.Contains(res, "                                                     UNSUPPORTED  potato2\n") &&
   243  		!strings.Contains(res, "                                                                  potato2\n") {
   244  		t.Errorf("potato2 missing: %q", res)
   245  	}
   246  }
   247  
   248  func TestSuffixName(t *testing.T) {
   249  	origSuffix, origKeepExt := fs.Config.Suffix, fs.Config.SuffixKeepExtension
   250  	defer func() {
   251  		fs.Config.Suffix, fs.Config.SuffixKeepExtension = origSuffix, origKeepExt
   252  	}()
   253  	for _, test := range []struct {
   254  		remote  string
   255  		suffix  string
   256  		keepExt bool
   257  		want    string
   258  	}{
   259  		{"test.txt", "", false, "test.txt"},
   260  		{"test.txt", "", true, "test.txt"},
   261  		{"test.txt", "-suffix", false, "test.txt-suffix"},
   262  		{"test.txt", "-suffix", true, "test-suffix.txt"},
   263  		{"test.txt.csv", "-suffix", false, "test.txt.csv-suffix"},
   264  		{"test.txt.csv", "-suffix", true, "test.txt-suffix.csv"},
   265  		{"test", "-suffix", false, "test-suffix"},
   266  		{"test", "-suffix", true, "test-suffix"},
   267  	} {
   268  		fs.Config.Suffix = test.suffix
   269  		fs.Config.SuffixKeepExtension = test.keepExt
   270  		got := operations.SuffixName(test.remote)
   271  		assert.Equal(t, test.want, got, fmt.Sprintf("%+v", test))
   272  	}
   273  }
   274  
   275  func TestCount(t *testing.T) {
   276  	r := fstest.NewRun(t)
   277  	defer r.Finalise()
   278  	file1 := r.WriteBoth(context.Background(), "potato2", "------------------------------------------------------------", t1)
   279  	file2 := r.WriteBoth(context.Background(), "empty space", "-", t2)
   280  	file3 := r.WriteBoth(context.Background(), "sub dir/potato3", "hello", t2)
   281  
   282  	fstest.CheckItems(t, r.Fremote, file1, file2, file3)
   283  
   284  	// Check the MaxDepth too
   285  	fs.Config.MaxDepth = 1
   286  	defer func() { fs.Config.MaxDepth = -1 }()
   287  
   288  	objects, size, err := operations.Count(context.Background(), r.Fremote)
   289  	require.NoError(t, err)
   290  	assert.Equal(t, int64(2), objects)
   291  	assert.Equal(t, int64(61), size)
   292  }
   293  
   294  func TestDelete(t *testing.T) {
   295  	r := fstest.NewRun(t)
   296  	defer r.Finalise()
   297  	file1 := r.WriteObject(context.Background(), "small", "1234567890", t2)                                                                                           // 10 bytes
   298  	file2 := r.WriteObject(context.Background(), "medium", "------------------------------------------------------------", t1)                                        // 60 bytes
   299  	file3 := r.WriteObject(context.Background(), "large", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", t1) // 100 bytes
   300  	fstest.CheckItems(t, r.Fremote, file1, file2, file3)
   301  
   302  	filter.Active.Opt.MaxSize = 60
   303  	defer func() {
   304  		filter.Active.Opt.MaxSize = -1
   305  	}()
   306  
   307  	err := operations.Delete(context.Background(), r.Fremote)
   308  	require.NoError(t, err)
   309  	fstest.CheckItems(t, r.Fremote, file3)
   310  }
   311  
   312  func testCheck(t *testing.T, checkFunction func(ctx context.Context, fdst, fsrc fs.Fs, oneway bool) error) {
   313  	r := fstest.NewRun(t)
   314  	defer r.Finalise()
   315  
   316  	check := func(i int, wantErrors int64, wantChecks int64, oneway bool) {
   317  		fs.Debugf(r.Fremote, "%d: Starting check test", i)
   318  		accounting.Stats.ResetCounters()
   319  		var buf bytes.Buffer
   320  		log.SetOutput(&buf)
   321  		defer func() {
   322  			log.SetOutput(os.Stderr)
   323  		}()
   324  		err := checkFunction(context.Background(), r.Fremote, r.Flocal, oneway)
   325  		gotErrors := accounting.Stats.GetErrors()
   326  		gotChecks := accounting.Stats.GetChecks()
   327  		if wantErrors == 0 && err != nil {
   328  			t.Errorf("%d: Got error when not expecting one: %v", i, err)
   329  		}
   330  		if wantErrors != 0 && err == nil {
   331  			t.Errorf("%d: No error when expecting one", i)
   332  		}
   333  		if wantErrors != gotErrors {
   334  			t.Errorf("%d: Expecting %d errors but got %d", i, wantErrors, gotErrors)
   335  		}
   336  		if gotChecks > 0 && !strings.Contains(buf.String(), "matching files") {
   337  			t.Errorf("%d: Total files matching line missing", i)
   338  		}
   339  		if wantChecks != gotChecks {
   340  			t.Errorf("%d: Expecting %d total matching files but got %d", i, wantChecks, gotChecks)
   341  		}
   342  		fs.Debugf(r.Fremote, "%d: Ending check test", i)
   343  	}
   344  
   345  	file1 := r.WriteBoth(context.Background(), "rutabaga", "is tasty", t3)
   346  	fstest.CheckItems(t, r.Fremote, file1)
   347  	fstest.CheckItems(t, r.Flocal, file1)
   348  	check(1, 0, 1, false)
   349  
   350  	file2 := r.WriteFile("potato2", "------------------------------------------------------------", t1)
   351  	fstest.CheckItems(t, r.Flocal, file1, file2)
   352  	check(2, 1, 1, false)
   353  
   354  	file3 := r.WriteObject(context.Background(), "empty space", "-", t2)
   355  	fstest.CheckItems(t, r.Fremote, file1, file3)
   356  	check(3, 2, 1, false)
   357  
   358  	file2r := file2
   359  	if fs.Config.SizeOnly {
   360  		file2r = r.WriteObject(context.Background(), "potato2", "--Some-Differences-But-Size-Only-Is-Enabled-----------------", t1)
   361  	} else {
   362  		r.WriteObject(context.Background(), "potato2", "------------------------------------------------------------", t1)
   363  	}
   364  	fstest.CheckItems(t, r.Fremote, file1, file2r, file3)
   365  	check(4, 1, 2, false)
   366  
   367  	r.WriteFile("empty space", "-", t2)
   368  	fstest.CheckItems(t, r.Flocal, file1, file2, file3)
   369  	check(5, 0, 3, false)
   370  
   371  	file4 := r.WriteObject(context.Background(), "remotepotato", "------------------------------------------------------------", t1)
   372  	fstest.CheckItems(t, r.Fremote, file1, file2r, file3, file4)
   373  	check(6, 1, 3, false)
   374  	check(7, 0, 3, true)
   375  }
   376  
   377  func TestCheck(t *testing.T) {
   378  	testCheck(t, operations.Check)
   379  }
   380  
   381  func TestCheckFsError(t *testing.T) {
   382  	dstFs, err := fs.NewFs("non-existent")
   383  	if err != nil {
   384  		t.Fatal(err)
   385  	}
   386  	srcFs, err := fs.NewFs("non-existent")
   387  	if err != nil {
   388  		t.Fatal(err)
   389  	}
   390  	err = operations.Check(context.Background(), dstFs, srcFs, false)
   391  	require.Error(t, err)
   392  }
   393  
   394  func TestCheckDownload(t *testing.T) {
   395  	testCheck(t, operations.CheckDownload)
   396  }
   397  
   398  func TestCheckSizeOnly(t *testing.T) {
   399  	fs.Config.SizeOnly = true
   400  	defer func() { fs.Config.SizeOnly = false }()
   401  	TestCheck(t)
   402  }
   403  
   404  func TestCat(t *testing.T) {
   405  	r := fstest.NewRun(t)
   406  	defer r.Finalise()
   407  	file1 := r.WriteBoth(context.Background(), "file1", "ABCDEFGHIJ", t1)
   408  	file2 := r.WriteBoth(context.Background(), "file2", "012345678", t2)
   409  
   410  	fstest.CheckItems(t, r.Fremote, file1, file2)
   411  
   412  	for _, test := range []struct {
   413  		offset int64
   414  		count  int64
   415  		a      string
   416  		b      string
   417  	}{
   418  		{0, -1, "ABCDEFGHIJ", "012345678"},
   419  		{0, 5, "ABCDE", "01234"},
   420  		{-3, -1, "HIJ", "678"},
   421  		{1, 3, "BCD", "123"},
   422  	} {
   423  		var buf bytes.Buffer
   424  		err := operations.Cat(context.Background(), r.Fremote, &buf, test.offset, test.count)
   425  		require.NoError(t, err)
   426  		res := buf.String()
   427  
   428  		if res != test.a+test.b && res != test.b+test.a {
   429  			t.Errorf("Incorrect output from Cat(%d,%d): %q", test.offset, test.count, res)
   430  		}
   431  	}
   432  }
   433  
   434  func TestRcat(t *testing.T) {
   435  	checkSumBefore := fs.Config.CheckSum
   436  	defer func() { fs.Config.CheckSum = checkSumBefore }()
   437  
   438  	check := func(withChecksum bool) {
   439  		fs.Config.CheckSum = withChecksum
   440  		prefix := "no_checksum_"
   441  		if withChecksum {
   442  			prefix = "with_checksum_"
   443  		}
   444  
   445  		r := fstest.NewRun(t)
   446  		defer r.Finalise()
   447  
   448  		fstest.CheckListing(t, r.Fremote, []fstest.Item{})
   449  
   450  		data1 := "this is some really nice test data"
   451  		path1 := prefix + "small_file_from_pipe"
   452  
   453  		data2 := string(make([]byte, fs.Config.StreamingUploadCutoff+1))
   454  		path2 := prefix + "big_file_from_pipe"
   455  
   456  		in := ioutil.NopCloser(strings.NewReader(data1))
   457  		_, err := operations.Rcat(context.Background(), r.Fremote, path1, in, t1)
   458  		require.NoError(t, err)
   459  
   460  		in = ioutil.NopCloser(strings.NewReader(data2))
   461  		_, err = operations.Rcat(context.Background(), r.Fremote, path2, in, t2)
   462  		require.NoError(t, err)
   463  
   464  		file1 := fstest.NewItem(path1, data1, t1)
   465  		file2 := fstest.NewItem(path2, data2, t2)
   466  		fstest.CheckItems(t, r.Fremote, file1, file2)
   467  	}
   468  
   469  	check(true)
   470  	check(false)
   471  }
   472  
   473  func TestPurge(t *testing.T) {
   474  	r := fstest.NewRunIndividual(t) // make new container (azureblob has delayed mkdir after rmdir)
   475  	defer r.Finalise()
   476  	r.Mkdir(context.Background(), r.Fremote)
   477  
   478  	// Make some files and dirs
   479  	r.ForceMkdir(context.Background(), r.Fremote)
   480  	file1 := r.WriteObject(context.Background(), "A1/B1/C1/one", "aaa", t1)
   481  	//..and dirs we expect to delete
   482  	require.NoError(t, operations.Mkdir(context.Background(), r.Fremote, "A2"))
   483  	require.NoError(t, operations.Mkdir(context.Background(), r.Fremote, "A1/B2"))
   484  	require.NoError(t, operations.Mkdir(context.Background(), r.Fremote, "A1/B2/C2"))
   485  	require.NoError(t, operations.Mkdir(context.Background(), r.Fremote, "A1/B1/C3"))
   486  	require.NoError(t, operations.Mkdir(context.Background(), r.Fremote, "A3"))
   487  	require.NoError(t, operations.Mkdir(context.Background(), r.Fremote, "A3/B3"))
   488  	require.NoError(t, operations.Mkdir(context.Background(), r.Fremote, "A3/B3/C4"))
   489  	//..and one more file at the end
   490  	file2 := r.WriteObject(context.Background(), "A1/two", "bbb", t2)
   491  
   492  	fstest.CheckListingWithPrecision(
   493  		t,
   494  		r.Fremote,
   495  		[]fstest.Item{
   496  			file1, file2,
   497  		},
   498  		[]string{
   499  			"A1",
   500  			"A1/B1",
   501  			"A1/B1/C1",
   502  			"A2",
   503  			"A1/B2",
   504  			"A1/B2/C2",
   505  			"A1/B1/C3",
   506  			"A3",
   507  			"A3/B3",
   508  			"A3/B3/C4",
   509  		},
   510  		fs.GetModifyWindow(r.Fremote),
   511  	)
   512  
   513  	require.NoError(t, operations.Purge(context.Background(), r.Fremote, "A1/B1"))
   514  
   515  	fstest.CheckListingWithPrecision(
   516  		t,
   517  		r.Fremote,
   518  		[]fstest.Item{
   519  			file2,
   520  		},
   521  		[]string{
   522  			"A1",
   523  			"A2",
   524  			"A1/B2",
   525  			"A1/B2/C2",
   526  			"A3",
   527  			"A3/B3",
   528  			"A3/B3/C4",
   529  		},
   530  		fs.GetModifyWindow(r.Fremote),
   531  	)
   532  
   533  	require.NoError(t, operations.Purge(context.Background(), r.Fremote, ""))
   534  
   535  	fstest.CheckListingWithPrecision(
   536  		t,
   537  		r.Fremote,
   538  		[]fstest.Item{},
   539  		[]string{},
   540  		fs.GetModifyWindow(r.Fremote),
   541  	)
   542  
   543  }
   544  
   545  func TestRmdirsNoLeaveRoot(t *testing.T) {
   546  	r := fstest.NewRun(t)
   547  	defer r.Finalise()
   548  	r.Mkdir(context.Background(), r.Fremote)
   549  
   550  	// Make some files and dirs we expect to keep
   551  	r.ForceMkdir(context.Background(), r.Fremote)
   552  	file1 := r.WriteObject(context.Background(), "A1/B1/C1/one", "aaa", t1)
   553  	//..and dirs we expect to delete
   554  	require.NoError(t, operations.Mkdir(context.Background(), r.Fremote, "A2"))
   555  	require.NoError(t, operations.Mkdir(context.Background(), r.Fremote, "A1/B2"))
   556  	require.NoError(t, operations.Mkdir(context.Background(), r.Fremote, "A1/B2/C2"))
   557  	require.NoError(t, operations.Mkdir(context.Background(), r.Fremote, "A1/B1/C3"))
   558  	require.NoError(t, operations.Mkdir(context.Background(), r.Fremote, "A3"))
   559  	require.NoError(t, operations.Mkdir(context.Background(), r.Fremote, "A3/B3"))
   560  	require.NoError(t, operations.Mkdir(context.Background(), r.Fremote, "A3/B3/C4"))
   561  	//..and one more file at the end
   562  	file2 := r.WriteObject(context.Background(), "A1/two", "bbb", t2)
   563  
   564  	fstest.CheckListingWithPrecision(
   565  		t,
   566  		r.Fremote,
   567  		[]fstest.Item{
   568  			file1, file2,
   569  		},
   570  		[]string{
   571  			"A1",
   572  			"A1/B1",
   573  			"A1/B1/C1",
   574  			"A2",
   575  			"A1/B2",
   576  			"A1/B2/C2",
   577  			"A1/B1/C3",
   578  			"A3",
   579  			"A3/B3",
   580  			"A3/B3/C4",
   581  		},
   582  		fs.GetModifyWindow(r.Fremote),
   583  	)
   584  
   585  	require.NoError(t, operations.Rmdirs(context.Background(), r.Fremote, "A3/B3/C4", false))
   586  
   587  	fstest.CheckListingWithPrecision(
   588  		t,
   589  		r.Fremote,
   590  		[]fstest.Item{
   591  			file1, file2,
   592  		},
   593  		[]string{
   594  			"A1",
   595  			"A1/B1",
   596  			"A1/B1/C1",
   597  			"A2",
   598  			"A1/B2",
   599  			"A1/B2/C2",
   600  			"A1/B1/C3",
   601  			"A3",
   602  			"A3/B3",
   603  		},
   604  		fs.GetModifyWindow(r.Fremote),
   605  	)
   606  
   607  	require.NoError(t, operations.Rmdirs(context.Background(), r.Fremote, "", false))
   608  
   609  	fstest.CheckListingWithPrecision(
   610  		t,
   611  		r.Fremote,
   612  		[]fstest.Item{
   613  			file1, file2,
   614  		},
   615  		[]string{
   616  			"A1",
   617  			"A1/B1",
   618  			"A1/B1/C1",
   619  		},
   620  		fs.GetModifyWindow(r.Fremote),
   621  	)
   622  
   623  }
   624  
   625  func TestRmdirsLeaveRoot(t *testing.T) {
   626  	r := fstest.NewRun(t)
   627  	defer r.Finalise()
   628  	r.Mkdir(context.Background(), r.Fremote)
   629  
   630  	r.ForceMkdir(context.Background(), r.Fremote)
   631  
   632  	require.NoError(t, operations.Mkdir(context.Background(), r.Fremote, "A1"))
   633  	require.NoError(t, operations.Mkdir(context.Background(), r.Fremote, "A1/B1"))
   634  	require.NoError(t, operations.Mkdir(context.Background(), r.Fremote, "A1/B1/C1"))
   635  
   636  	fstest.CheckListingWithPrecision(
   637  		t,
   638  		r.Fremote,
   639  		[]fstest.Item{},
   640  		[]string{
   641  			"A1",
   642  			"A1/B1",
   643  			"A1/B1/C1",
   644  		},
   645  		fs.GetModifyWindow(r.Fremote),
   646  	)
   647  
   648  	require.NoError(t, operations.Rmdirs(context.Background(), r.Fremote, "A1", true))
   649  
   650  	fstest.CheckListingWithPrecision(
   651  		t,
   652  		r.Fremote,
   653  		[]fstest.Item{},
   654  		[]string{
   655  			"A1",
   656  		},
   657  		fs.GetModifyWindow(r.Fremote),
   658  	)
   659  }
   660  
   661  func TestRcatSize(t *testing.T) {
   662  	r := fstest.NewRun(t)
   663  	defer r.Finalise()
   664  
   665  	const body = "------------------------------------------------------------"
   666  	file1 := r.WriteFile("potato1", body, t1)
   667  	file2 := r.WriteFile("potato2", body, t2)
   668  	// Test with known length
   669  	bodyReader := ioutil.NopCloser(strings.NewReader(body))
   670  	obj, err := operations.RcatSize(context.Background(), r.Fremote, file1.Path, bodyReader, int64(len(body)), file1.ModTime)
   671  	require.NoError(t, err)
   672  	assert.Equal(t, int64(len(body)), obj.Size())
   673  	assert.Equal(t, file1.Path, obj.Remote())
   674  
   675  	// Test with unknown length
   676  	bodyReader = ioutil.NopCloser(strings.NewReader(body)) // reset Reader
   677  	ioutil.NopCloser(strings.NewReader(body))
   678  	obj, err = operations.RcatSize(context.Background(), r.Fremote, file2.Path, bodyReader, -1, file2.ModTime)
   679  	require.NoError(t, err)
   680  	assert.Equal(t, int64(len(body)), obj.Size())
   681  	assert.Equal(t, file2.Path, obj.Remote())
   682  
   683  	// Check files exist
   684  	fstest.CheckItems(t, r.Fremote, file1, file2)
   685  }
   686  
   687  func TestCopyURL(t *testing.T) {
   688  	r := fstest.NewRun(t)
   689  	defer r.Finalise()
   690  
   691  	contents := "file contents\n"
   692  	file1 := r.WriteFile("file1", contents, t1)
   693  	file2 := r.WriteFile("file2", contents, t1)
   694  	r.Mkdir(context.Background(), r.Fremote)
   695  	fstest.CheckItems(t, r.Fremote)
   696  
   697  	// check when reading from regular HTTP server
   698  	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   699  		_, err := w.Write([]byte(contents))
   700  		assert.NoError(t, err)
   701  	})
   702  	ts := httptest.NewServer(handler)
   703  	defer ts.Close()
   704  
   705  	o, err := operations.CopyURL(context.Background(), r.Fremote, "file1", ts.URL)
   706  	require.NoError(t, err)
   707  	assert.Equal(t, int64(len(contents)), o.Size())
   708  
   709  	fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{file1}, nil, fs.ModTimeNotSupported)
   710  
   711  	// check when reading from unverified HTTPS server
   712  	fs.Config.InsecureSkipVerify = true
   713  	fshttp.ResetTransport()
   714  	defer func() {
   715  		fs.Config.InsecureSkipVerify = false
   716  		fshttp.ResetTransport()
   717  	}()
   718  	tss := httptest.NewTLSServer(handler)
   719  	defer tss.Close()
   720  
   721  	o, err = operations.CopyURL(context.Background(), r.Fremote, "file2", tss.URL)
   722  	require.NoError(t, err)
   723  	assert.Equal(t, int64(len(contents)), o.Size())
   724  	fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{file1, file2}, nil, fs.ModTimeNotSupported)
   725  }
   726  
   727  func TestMoveFile(t *testing.T) {
   728  	r := fstest.NewRun(t)
   729  	defer r.Finalise()
   730  
   731  	file1 := r.WriteFile("file1", "file1 contents", t1)
   732  	fstest.CheckItems(t, r.Flocal, file1)
   733  
   734  	file2 := file1
   735  	file2.Path = "sub/file2"
   736  
   737  	err := operations.MoveFile(context.Background(), r.Fremote, r.Flocal, file2.Path, file1.Path)
   738  	require.NoError(t, err)
   739  	fstest.CheckItems(t, r.Flocal)
   740  	fstest.CheckItems(t, r.Fremote, file2)
   741  
   742  	r.WriteFile("file1", "file1 contents", t1)
   743  	fstest.CheckItems(t, r.Flocal, file1)
   744  
   745  	err = operations.MoveFile(context.Background(), r.Fremote, r.Flocal, file2.Path, file1.Path)
   746  	require.NoError(t, err)
   747  	fstest.CheckItems(t, r.Flocal)
   748  	fstest.CheckItems(t, r.Fremote, file2)
   749  
   750  	err = operations.MoveFile(context.Background(), r.Fremote, r.Fremote, file2.Path, file2.Path)
   751  	require.NoError(t, err)
   752  	fstest.CheckItems(t, r.Flocal)
   753  	fstest.CheckItems(t, r.Fremote, file2)
   754  }
   755  
   756  func TestCaseInsensitiveMoveFile(t *testing.T) {
   757  	r := fstest.NewRun(t)
   758  	defer r.Finalise()
   759  	if !r.Fremote.Features().CaseInsensitive {
   760  		return
   761  	}
   762  
   763  	file1 := r.WriteFile("file1", "file1 contents", t1)
   764  	fstest.CheckItems(t, r.Flocal, file1)
   765  
   766  	file2 := file1
   767  	file2.Path = "sub/file2"
   768  
   769  	err := operations.MoveFile(context.Background(), r.Fremote, r.Flocal, file2.Path, file1.Path)
   770  	require.NoError(t, err)
   771  	fstest.CheckItems(t, r.Flocal)
   772  	fstest.CheckItems(t, r.Fremote, file2)
   773  
   774  	r.WriteFile("file1", "file1 contents", t1)
   775  	fstest.CheckItems(t, r.Flocal, file1)
   776  
   777  	err = operations.MoveFile(context.Background(), r.Fremote, r.Flocal, file2.Path, file1.Path)
   778  	require.NoError(t, err)
   779  	fstest.CheckItems(t, r.Flocal)
   780  	fstest.CheckItems(t, r.Fremote, file2)
   781  
   782  	file2Capitalized := file2
   783  	file2Capitalized.Path = "sub/File2"
   784  
   785  	err = operations.MoveFile(context.Background(), r.Fremote, r.Fremote, file2Capitalized.Path, file2.Path)
   786  	require.NoError(t, err)
   787  	fstest.CheckItems(t, r.Flocal)
   788  	fstest.CheckItems(t, r.Fremote, file2Capitalized)
   789  }
   790  
   791  func TestMoveFileBackupDir(t *testing.T) {
   792  	r := fstest.NewRun(t)
   793  	defer r.Finalise()
   794  	if !operations.CanServerSideMove(r.Fremote) {
   795  		t.Skip("Skipping test as remote does not support server side move or copy")
   796  	}
   797  
   798  	oldBackupDir := fs.Config.BackupDir
   799  	fs.Config.BackupDir = r.FremoteName + "/backup"
   800  	defer func() {
   801  		fs.Config.BackupDir = oldBackupDir
   802  	}()
   803  
   804  	file1 := r.WriteFile("dst/file1", "file1 contents", t1)
   805  	fstest.CheckItems(t, r.Flocal, file1)
   806  
   807  	file1old := r.WriteObject(context.Background(), "dst/file1", "file1 contents old", t1)
   808  	fstest.CheckItems(t, r.Fremote, file1old)
   809  
   810  	err := operations.MoveFile(context.Background(), r.Fremote, r.Flocal, file1.Path, file1.Path)
   811  	require.NoError(t, err)
   812  	fstest.CheckItems(t, r.Flocal)
   813  	file1old.Path = "backup/dst/file1"
   814  	fstest.CheckItems(t, r.Fremote, file1old, file1)
   815  }
   816  
   817  func TestCopyFile(t *testing.T) {
   818  	r := fstest.NewRun(t)
   819  	defer r.Finalise()
   820  
   821  	file1 := r.WriteFile("file1", "file1 contents", t1)
   822  	fstest.CheckItems(t, r.Flocal, file1)
   823  
   824  	file2 := file1
   825  	file2.Path = "sub/file2"
   826  
   827  	err := operations.CopyFile(context.Background(), r.Fremote, r.Flocal, file2.Path, file1.Path)
   828  	require.NoError(t, err)
   829  	fstest.CheckItems(t, r.Flocal, file1)
   830  	fstest.CheckItems(t, r.Fremote, file2)
   831  
   832  	err = operations.CopyFile(context.Background(), r.Fremote, r.Flocal, file2.Path, file1.Path)
   833  	require.NoError(t, err)
   834  	fstest.CheckItems(t, r.Flocal, file1)
   835  	fstest.CheckItems(t, r.Fremote, file2)
   836  
   837  	err = operations.CopyFile(context.Background(), r.Fremote, r.Fremote, file2.Path, file2.Path)
   838  	require.NoError(t, err)
   839  	fstest.CheckItems(t, r.Flocal, file1)
   840  	fstest.CheckItems(t, r.Fremote, file2)
   841  }
   842  
   843  func TestCopyFileBackupDir(t *testing.T) {
   844  	r := fstest.NewRun(t)
   845  	defer r.Finalise()
   846  	if !operations.CanServerSideMove(r.Fremote) {
   847  		t.Skip("Skipping test as remote does not support server side move or copy")
   848  	}
   849  
   850  	oldBackupDir := fs.Config.BackupDir
   851  	fs.Config.BackupDir = r.FremoteName + "/backup"
   852  	defer func() {
   853  		fs.Config.BackupDir = oldBackupDir
   854  	}()
   855  
   856  	file1 := r.WriteFile("dst/file1", "file1 contents", t1)
   857  	fstest.CheckItems(t, r.Flocal, file1)
   858  
   859  	file1old := r.WriteObject(context.Background(), "dst/file1", "file1 contents old", t1)
   860  	fstest.CheckItems(t, r.Fremote, file1old)
   861  
   862  	err := operations.CopyFile(context.Background(), r.Fremote, r.Flocal, file1.Path, file1.Path)
   863  	require.NoError(t, err)
   864  	fstest.CheckItems(t, r.Flocal, file1)
   865  	file1old.Path = "backup/dst/file1"
   866  	fstest.CheckItems(t, r.Fremote, file1old, file1)
   867  }
   868  
   869  // Test with CompareDest set
   870  func TestCopyFileCompareDest(t *testing.T) {
   871  	r := fstest.NewRun(t)
   872  	defer r.Finalise()
   873  
   874  	fs.Config.CompareDest = r.FremoteName + "/CompareDest"
   875  	defer func() {
   876  		fs.Config.CompareDest = ""
   877  	}()
   878  	fdst, err := fs.NewFs(r.FremoteName + "/dst")
   879  	require.NoError(t, err)
   880  
   881  	// check empty dest, empty compare
   882  	file1 := r.WriteFile("one", "one", t1)
   883  	fstest.CheckItems(t, r.Flocal, file1)
   884  
   885  	err = operations.CopyFile(context.Background(), fdst, r.Flocal, file1.Path, file1.Path)
   886  	require.NoError(t, err)
   887  
   888  	file1dst := file1
   889  	file1dst.Path = "dst/one"
   890  
   891  	fstest.CheckItems(t, r.Fremote, file1dst)
   892  
   893  	// check old dest, empty compare
   894  	file1b := r.WriteFile("one", "onet2", t2)
   895  	fstest.CheckItems(t, r.Fremote, file1dst)
   896  	fstest.CheckItems(t, r.Flocal, file1b)
   897  
   898  	err = operations.CopyFile(context.Background(), fdst, r.Flocal, file1b.Path, file1b.Path)
   899  	require.NoError(t, err)
   900  
   901  	file1bdst := file1b
   902  	file1bdst.Path = "dst/one"
   903  
   904  	fstest.CheckItems(t, r.Fremote, file1bdst)
   905  
   906  	// check old dest, new compare
   907  	file3 := r.WriteObject(context.Background(), "dst/one", "one", t1)
   908  	file2 := r.WriteObject(context.Background(), "CompareDest/one", "onet2", t2)
   909  	file1c := r.WriteFile("one", "onet2", t2)
   910  	fstest.CheckItems(t, r.Fremote, file2, file3)
   911  	fstest.CheckItems(t, r.Flocal, file1c)
   912  
   913  	err = operations.CopyFile(context.Background(), fdst, r.Flocal, file1c.Path, file1c.Path)
   914  	require.NoError(t, err)
   915  
   916  	fstest.CheckItems(t, r.Fremote, file2, file3)
   917  
   918  	// check empty dest, new compare
   919  	file4 := r.WriteObject(context.Background(), "CompareDest/two", "two", t2)
   920  	file5 := r.WriteFile("two", "two", t2)
   921  	fstest.CheckItems(t, r.Fremote, file2, file3, file4)
   922  	fstest.CheckItems(t, r.Flocal, file1c, file5)
   923  
   924  	err = operations.CopyFile(context.Background(), fdst, r.Flocal, file5.Path, file5.Path)
   925  	require.NoError(t, err)
   926  
   927  	fstest.CheckItems(t, r.Fremote, file2, file3, file4)
   928  
   929  	// check new dest, new compare
   930  	err = operations.CopyFile(context.Background(), fdst, r.Flocal, file5.Path, file5.Path)
   931  	require.NoError(t, err)
   932  
   933  	fstest.CheckItems(t, r.Fremote, file2, file3, file4)
   934  
   935  	// check empty dest, old compare
   936  	file5b := r.WriteFile("two", "twot3", t3)
   937  	fstest.CheckItems(t, r.Fremote, file2, file3, file4)
   938  	fstest.CheckItems(t, r.Flocal, file1c, file5b)
   939  
   940  	err = operations.CopyFile(context.Background(), fdst, r.Flocal, file5b.Path, file5b.Path)
   941  	require.NoError(t, err)
   942  
   943  	file5bdst := file5b
   944  	file5bdst.Path = "dst/two"
   945  
   946  	fstest.CheckItems(t, r.Fremote, file2, file3, file4, file5bdst)
   947  }
   948  
   949  // Test with CopyDest set
   950  func TestCopyFileCopyDest(t *testing.T) {
   951  	r := fstest.NewRun(t)
   952  	defer r.Finalise()
   953  
   954  	if r.Fremote.Features().Copy == nil {
   955  		t.Skip("Skipping test as remote does not support server side copy")
   956  	}
   957  
   958  	fs.Config.CopyDest = r.FremoteName + "/CopyDest"
   959  	defer func() {
   960  		fs.Config.CopyDest = ""
   961  	}()
   962  
   963  	fdst, err := fs.NewFs(r.FremoteName + "/dst")
   964  	require.NoError(t, err)
   965  
   966  	// check empty dest, empty copy
   967  	file1 := r.WriteFile("one", "one", t1)
   968  	fstest.CheckItems(t, r.Flocal, file1)
   969  
   970  	err = operations.CopyFile(context.Background(), fdst, r.Flocal, file1.Path, file1.Path)
   971  	require.NoError(t, err)
   972  
   973  	file1dst := file1
   974  	file1dst.Path = "dst/one"
   975  
   976  	fstest.CheckItems(t, r.Fremote, file1dst)
   977  
   978  	// check old dest, empty copy
   979  	file1b := r.WriteFile("one", "onet2", t2)
   980  	fstest.CheckItems(t, r.Fremote, file1dst)
   981  	fstest.CheckItems(t, r.Flocal, file1b)
   982  
   983  	err = operations.CopyFile(context.Background(), fdst, r.Flocal, file1b.Path, file1b.Path)
   984  	require.NoError(t, err)
   985  
   986  	file1bdst := file1b
   987  	file1bdst.Path = "dst/one"
   988  
   989  	fstest.CheckItems(t, r.Fremote, file1bdst)
   990  
   991  	// check old dest, new copy, backup-dir
   992  
   993  	fs.Config.BackupDir = r.FremoteName + "/BackupDir"
   994  
   995  	file3 := r.WriteObject(context.Background(), "dst/one", "one", t1)
   996  	file2 := r.WriteObject(context.Background(), "CopyDest/one", "onet2", t2)
   997  	file1c := r.WriteFile("one", "onet2", t2)
   998  	fstest.CheckItems(t, r.Fremote, file2, file3)
   999  	fstest.CheckItems(t, r.Flocal, file1c)
  1000  
  1001  	err = operations.CopyFile(context.Background(), fdst, r.Flocal, file1c.Path, file1c.Path)
  1002  	require.NoError(t, err)
  1003  
  1004  	file2dst := file2
  1005  	file2dst.Path = "dst/one"
  1006  	file3.Path = "BackupDir/one"
  1007  
  1008  	fstest.CheckItems(t, r.Fremote, file2, file2dst, file3)
  1009  	fs.Config.BackupDir = ""
  1010  
  1011  	// check empty dest, new copy
  1012  	file4 := r.WriteObject(context.Background(), "CopyDest/two", "two", t2)
  1013  	file5 := r.WriteFile("two", "two", t2)
  1014  	fstest.CheckItems(t, r.Fremote, file2, file2dst, file3, file4)
  1015  	fstest.CheckItems(t, r.Flocal, file1c, file5)
  1016  
  1017  	err = operations.CopyFile(context.Background(), fdst, r.Flocal, file5.Path, file5.Path)
  1018  	require.NoError(t, err)
  1019  
  1020  	file4dst := file4
  1021  	file4dst.Path = "dst/two"
  1022  
  1023  	fstest.CheckItems(t, r.Fremote, file2, file2dst, file3, file4, file4dst)
  1024  
  1025  	// check new dest, new copy
  1026  	err = operations.CopyFile(context.Background(), fdst, r.Flocal, file5.Path, file5.Path)
  1027  	require.NoError(t, err)
  1028  
  1029  	fstest.CheckItems(t, r.Fremote, file2, file2dst, file3, file4, file4dst)
  1030  
  1031  	// check empty dest, old copy
  1032  	file6 := r.WriteObject(context.Background(), "CopyDest/three", "three", t2)
  1033  	file7 := r.WriteFile("three", "threet3", t3)
  1034  	fstest.CheckItems(t, r.Fremote, file2, file2dst, file3, file4, file4dst, file6)
  1035  	fstest.CheckItems(t, r.Flocal, file1c, file5, file7)
  1036  
  1037  	err = operations.CopyFile(context.Background(), fdst, r.Flocal, file7.Path, file7.Path)
  1038  	require.NoError(t, err)
  1039  
  1040  	file7dst := file7
  1041  	file7dst.Path = "dst/three"
  1042  
  1043  	fstest.CheckItems(t, r.Fremote, file2, file2dst, file3, file4, file4dst, file6, file7dst)
  1044  }
  1045  
  1046  // testFsInfo is for unit testing fs.Info
  1047  type testFsInfo struct {
  1048  	name      string
  1049  	root      string
  1050  	stringVal string
  1051  	precision time.Duration
  1052  	hashes    hash.Set
  1053  	features  fs.Features
  1054  }
  1055  
  1056  // Name of the remote (as passed into NewFs)
  1057  func (i *testFsInfo) Name() string { return i.name }
  1058  
  1059  // Root of the remote (as passed into NewFs)
  1060  func (i *testFsInfo) Root() string { return i.root }
  1061  
  1062  // String returns a description of the FS
  1063  func (i *testFsInfo) String() string { return i.stringVal }
  1064  
  1065  // Precision of the ModTimes in this Fs
  1066  func (i *testFsInfo) Precision() time.Duration { return i.precision }
  1067  
  1068  // Returns the supported hash types of the filesystem
  1069  func (i *testFsInfo) Hashes() hash.Set { return i.hashes }
  1070  
  1071  // Returns the supported hash types of the filesystem
  1072  func (i *testFsInfo) Features() *fs.Features { return &i.features }
  1073  
  1074  func TestSameConfig(t *testing.T) {
  1075  	a := &testFsInfo{name: "name", root: "root"}
  1076  	for _, test := range []struct {
  1077  		name     string
  1078  		root     string
  1079  		expected bool
  1080  	}{
  1081  		{"name", "root", true},
  1082  		{"name", "rooty", true},
  1083  		{"namey", "root", false},
  1084  		{"namey", "roott", false},
  1085  	} {
  1086  		b := &testFsInfo{name: test.name, root: test.root}
  1087  		actual := operations.SameConfig(a, b)
  1088  		assert.Equal(t, test.expected, actual)
  1089  		actual = operations.SameConfig(b, a)
  1090  		assert.Equal(t, test.expected, actual)
  1091  	}
  1092  }
  1093  
  1094  func TestSame(t *testing.T) {
  1095  	a := &testFsInfo{name: "name", root: "root"}
  1096  	for _, test := range []struct {
  1097  		name     string
  1098  		root     string
  1099  		expected bool
  1100  	}{
  1101  		{"name", "root", true},
  1102  		{"name", "rooty", false},
  1103  		{"namey", "root", false},
  1104  		{"namey", "roott", false},
  1105  	} {
  1106  		b := &testFsInfo{name: test.name, root: test.root}
  1107  		actual := operations.Same(a, b)
  1108  		assert.Equal(t, test.expected, actual)
  1109  		actual = operations.Same(b, a)
  1110  		assert.Equal(t, test.expected, actual)
  1111  	}
  1112  }
  1113  
  1114  func TestOverlapping(t *testing.T) {
  1115  	a := &testFsInfo{name: "name", root: "root"}
  1116  	slash := string(os.PathSeparator) // native path separator
  1117  	for _, test := range []struct {
  1118  		name     string
  1119  		root     string
  1120  		expected bool
  1121  	}{
  1122  		{"name", "root", true},
  1123  		{"namey", "root", false},
  1124  		{"name", "rooty", false},
  1125  		{"namey", "rooty", false},
  1126  		{"name", "roo", false},
  1127  		{"name", "root/toot", true},
  1128  		{"name", "root/toot/", true},
  1129  		{"name", "root" + slash + "toot", true},
  1130  		{"name", "root" + slash + "toot" + slash, true},
  1131  		{"name", "", true},
  1132  		{"name", "/", true},
  1133  	} {
  1134  		b := &testFsInfo{name: test.name, root: test.root}
  1135  		what := fmt.Sprintf("(%q,%q) vs (%q,%q)", a.name, a.root, b.name, b.root)
  1136  		actual := operations.Overlapping(a, b)
  1137  		assert.Equal(t, test.expected, actual, what)
  1138  		actual = operations.Overlapping(b, a)
  1139  		assert.Equal(t, test.expected, actual, what)
  1140  	}
  1141  }
  1142  
  1143  type errorReader struct {
  1144  	err error
  1145  }
  1146  
  1147  func (er errorReader) Read(p []byte) (n int, err error) {
  1148  	return 0, er.err
  1149  }
  1150  
  1151  func TestCheckEqualReaders(t *testing.T) {
  1152  	b65a := make([]byte, 65*1024)
  1153  	b65b := make([]byte, 65*1024)
  1154  	b65b[len(b65b)-1] = 1
  1155  	b66 := make([]byte, 66*1024)
  1156  
  1157  	differ, err := operations.CheckEqualReaders(bytes.NewBuffer(b65a), bytes.NewBuffer(b65a))
  1158  	assert.NoError(t, err)
  1159  	assert.Equal(t, differ, false)
  1160  
  1161  	differ, err = operations.CheckEqualReaders(bytes.NewBuffer(b65a), bytes.NewBuffer(b65b))
  1162  	assert.NoError(t, err)
  1163  	assert.Equal(t, differ, true)
  1164  
  1165  	differ, err = operations.CheckEqualReaders(bytes.NewBuffer(b65a), bytes.NewBuffer(b66))
  1166  	assert.NoError(t, err)
  1167  	assert.Equal(t, differ, true)
  1168  
  1169  	differ, err = operations.CheckEqualReaders(bytes.NewBuffer(b66), bytes.NewBuffer(b65a))
  1170  	assert.NoError(t, err)
  1171  	assert.Equal(t, differ, true)
  1172  
  1173  	myErr := errors.New("sentinel")
  1174  	wrap := func(b []byte) io.Reader {
  1175  		r := bytes.NewBuffer(b)
  1176  		e := errorReader{myErr}
  1177  		return io.MultiReader(r, e)
  1178  	}
  1179  
  1180  	differ, err = operations.CheckEqualReaders(wrap(b65a), bytes.NewBuffer(b65a))
  1181  	assert.Equal(t, myErr, err)
  1182  	assert.Equal(t, differ, true)
  1183  
  1184  	differ, err = operations.CheckEqualReaders(wrap(b65a), bytes.NewBuffer(b65b))
  1185  	assert.Equal(t, myErr, err)
  1186  	assert.Equal(t, differ, true)
  1187  
  1188  	differ, err = operations.CheckEqualReaders(wrap(b65a), bytes.NewBuffer(b66))
  1189  	assert.Equal(t, myErr, err)
  1190  	assert.Equal(t, differ, true)
  1191  
  1192  	differ, err = operations.CheckEqualReaders(wrap(b66), bytes.NewBuffer(b65a))
  1193  	assert.Equal(t, myErr, err)
  1194  	assert.Equal(t, differ, true)
  1195  
  1196  	differ, err = operations.CheckEqualReaders(bytes.NewBuffer(b65a), wrap(b65a))
  1197  	assert.Equal(t, myErr, err)
  1198  	assert.Equal(t, differ, true)
  1199  
  1200  	differ, err = operations.CheckEqualReaders(bytes.NewBuffer(b65a), wrap(b65b))
  1201  	assert.Equal(t, myErr, err)
  1202  	assert.Equal(t, differ, true)
  1203  
  1204  	differ, err = operations.CheckEqualReaders(bytes.NewBuffer(b65a), wrap(b66))
  1205  	assert.Equal(t, myErr, err)
  1206  	assert.Equal(t, differ, true)
  1207  
  1208  	differ, err = operations.CheckEqualReaders(bytes.NewBuffer(b66), wrap(b65a))
  1209  	assert.Equal(t, myErr, err)
  1210  	assert.Equal(t, differ, true)
  1211  }
  1212  
  1213  func TestListFormat(t *testing.T) {
  1214  	item0 := &operations.ListJSONItem{
  1215  		Path:      "a",
  1216  		Name:      "a",
  1217  		Encrypted: "encryptedFileName",
  1218  		Size:      1,
  1219  		MimeType:  "application/octet-stream",
  1220  		ModTime: operations.Timestamp{
  1221  			When:   t1,
  1222  			Format: "2006-01-02T15:04:05.000000000Z07:00"},
  1223  		IsDir: false,
  1224  		Hashes: map[string]string{
  1225  			"MD5":          "0cc175b9c0f1b6a831c399e269772661",
  1226  			"SHA-1":        "86f7e437faa5a7fce15d1ddcb9eaeaea377667b8",
  1227  			"DropboxHash":  "bf5d3affb73efd2ec6c36ad3112dd933efed63c4e1cbffcfa88e2759c144f2d8",
  1228  			"QuickXorHash": "6100000000000000000000000100000000000000"},
  1229  		ID:     "fileID",
  1230  		OrigID: "fileOrigID",
  1231  	}
  1232  
  1233  	item1 := &operations.ListJSONItem{
  1234  		Path:      "subdir",
  1235  		Name:      "subdir",
  1236  		Encrypted: "encryptedDirName",
  1237  		Size:      -1,
  1238  		MimeType:  "inode/directory",
  1239  		ModTime: operations.Timestamp{
  1240  			When:   t2,
  1241  			Format: "2006-01-02T15:04:05.000000000Z07:00"},
  1242  		IsDir:  true,
  1243  		Hashes: map[string]string(nil),
  1244  		ID:     "dirID",
  1245  		OrigID: "dirOrigID",
  1246  	}
  1247  
  1248  	var list operations.ListFormat
  1249  	list.AddPath()
  1250  	list.SetDirSlash(false)
  1251  	assert.Equal(t, "subdir", list.Format(item1))
  1252  
  1253  	list.SetDirSlash(true)
  1254  	assert.Equal(t, "subdir/", list.Format(item1))
  1255  
  1256  	list.SetOutput(nil)
  1257  	assert.Equal(t, "", list.Format(item1))
  1258  
  1259  	list.AppendOutput(func(item *operations.ListJSONItem) string { return "a" })
  1260  	list.AppendOutput(func(item *operations.ListJSONItem) string { return "b" })
  1261  	assert.Equal(t, "ab", list.Format(item1))
  1262  	list.SetSeparator(":::")
  1263  	assert.Equal(t, "a:::b", list.Format(item1))
  1264  
  1265  	list.SetOutput(nil)
  1266  	list.AddModTime()
  1267  	assert.Equal(t, t1.Local().Format("2006-01-02 15:04:05"), list.Format(item0))
  1268  
  1269  	list.SetOutput(nil)
  1270  	list.SetSeparator("|")
  1271  	list.AddID()
  1272  	list.AddOrigID()
  1273  	assert.Equal(t, "fileID|fileOrigID", list.Format(item0))
  1274  	assert.Equal(t, "dirID|dirOrigID", list.Format(item1))
  1275  
  1276  	list.SetOutput(nil)
  1277  	list.AddMimeType()
  1278  	assert.Contains(t, list.Format(item0), "/")
  1279  	assert.Equal(t, "inode/directory", list.Format(item1))
  1280  
  1281  	list.SetOutput(nil)
  1282  	list.AddPath()
  1283  	list.SetAbsolute(true)
  1284  	assert.Equal(t, "/a", list.Format(item0))
  1285  	list.SetAbsolute(false)
  1286  	assert.Equal(t, "a", list.Format(item0))
  1287  
  1288  	list.SetOutput(nil)
  1289  	list.AddSize()
  1290  	assert.Equal(t, "1", list.Format(item0))
  1291  
  1292  	list.AddPath()
  1293  	list.AddModTime()
  1294  	list.SetDirSlash(true)
  1295  	list.SetSeparator("__SEP__")
  1296  	assert.Equal(t, "1__SEP__a__SEP__"+t1.Local().Format("2006-01-02 15:04:05"), list.Format(item0))
  1297  	assert.Equal(t, "-1__SEP__subdir/__SEP__"+t2.Local().Format("2006-01-02 15:04:05"), list.Format(item1))
  1298  
  1299  	for _, test := range []struct {
  1300  		ht   hash.Type
  1301  		want string
  1302  	}{
  1303  		{hash.MD5, "0cc175b9c0f1b6a831c399e269772661"},
  1304  		{hash.SHA1, "86f7e437faa5a7fce15d1ddcb9eaeaea377667b8"},
  1305  		{hash.Dropbox, "bf5d3affb73efd2ec6c36ad3112dd933efed63c4e1cbffcfa88e2759c144f2d8"},
  1306  	} {
  1307  		list.SetOutput(nil)
  1308  		list.AddHash(test.ht)
  1309  		assert.Equal(t, test.want, list.Format(item0))
  1310  	}
  1311  
  1312  	list.SetOutput(nil)
  1313  	list.SetSeparator("|")
  1314  	list.SetCSV(true)
  1315  	list.AddSize()
  1316  	list.AddPath()
  1317  	list.AddModTime()
  1318  	list.SetDirSlash(true)
  1319  	assert.Equal(t, "1|a|"+t1.Local().Format("2006-01-02 15:04:05"), list.Format(item0))
  1320  	assert.Equal(t, "-1|subdir/|"+t2.Local().Format("2006-01-02 15:04:05"), list.Format(item1))
  1321  
  1322  	list.SetOutput(nil)
  1323  	list.SetSeparator("|")
  1324  	list.AddPath()
  1325  	list.AddEncrypted()
  1326  	assert.Equal(t, "a|encryptedFileName", list.Format(item0))
  1327  	assert.Equal(t, "subdir/|encryptedDirName/", list.Format(item1))
  1328  
  1329  }
  1330  
  1331  func TestDirMove(t *testing.T) {
  1332  	r := fstest.NewRun(t)
  1333  	defer r.Finalise()
  1334  
  1335  	r.Mkdir(context.Background(), r.Fremote)
  1336  
  1337  	// Make some files and dirs
  1338  	r.ForceMkdir(context.Background(), r.Fremote)
  1339  	files := []fstest.Item{
  1340  		r.WriteObject(context.Background(), "A1/one", "one", t1),
  1341  		r.WriteObject(context.Background(), "A1/two", "two", t2),
  1342  		r.WriteObject(context.Background(), "A1/B1/three", "three", t3),
  1343  		r.WriteObject(context.Background(), "A1/B1/C1/four", "four", t1),
  1344  		r.WriteObject(context.Background(), "A1/B1/C2/five", "five", t2),
  1345  	}
  1346  	require.NoError(t, operations.Mkdir(context.Background(), r.Fremote, "A1/B2"))
  1347  	require.NoError(t, operations.Mkdir(context.Background(), r.Fremote, "A1/B1/C3"))
  1348  
  1349  	fstest.CheckListingWithPrecision(
  1350  		t,
  1351  		r.Fremote,
  1352  		files,
  1353  		[]string{
  1354  			"A1",
  1355  			"A1/B1",
  1356  			"A1/B2",
  1357  			"A1/B1/C1",
  1358  			"A1/B1/C2",
  1359  			"A1/B1/C3",
  1360  		},
  1361  		fs.GetModifyWindow(r.Fremote),
  1362  	)
  1363  
  1364  	require.NoError(t, operations.DirMove(context.Background(), r.Fremote, "A1", "A2"))
  1365  
  1366  	for i := range files {
  1367  		files[i].Path = strings.Replace(files[i].Path, "A1/", "A2/", -1)
  1368  		files[i].WinPath = ""
  1369  	}
  1370  
  1371  	fstest.CheckListingWithPrecision(
  1372  		t,
  1373  		r.Fremote,
  1374  		files,
  1375  		[]string{
  1376  			"A2",
  1377  			"A2/B1",
  1378  			"A2/B2",
  1379  			"A2/B1/C1",
  1380  			"A2/B1/C2",
  1381  			"A2/B1/C3",
  1382  		},
  1383  		fs.GetModifyWindow(r.Fremote),
  1384  	)
  1385  
  1386  	// Disable DirMove
  1387  	features := r.Fremote.Features()
  1388  	oldDirMove := features.DirMove
  1389  	features.DirMove = nil
  1390  	defer func() {
  1391  		features.DirMove = oldDirMove
  1392  	}()
  1393  
  1394  	require.NoError(t, operations.DirMove(context.Background(), r.Fremote, "A2", "A3"))
  1395  
  1396  	for i := range files {
  1397  		files[i].Path = strings.Replace(files[i].Path, "A2/", "A3/", -1)
  1398  		files[i].WinPath = ""
  1399  	}
  1400  
  1401  	fstest.CheckListingWithPrecision(
  1402  		t,
  1403  		r.Fremote,
  1404  		files,
  1405  		[]string{
  1406  			"A3",
  1407  			"A3/B1",
  1408  			"A3/B2",
  1409  			"A3/B1/C1",
  1410  			"A3/B1/C2",
  1411  			"A3/B1/C3",
  1412  		},
  1413  		fs.GetModifyWindow(r.Fremote),
  1414  	)
  1415  
  1416  }
  1417  
  1418  func TestGetFsInfo(t *testing.T) {
  1419  	r := fstest.NewRun(t)
  1420  	defer r.Finalise()
  1421  
  1422  	f := r.Fremote
  1423  	info := operations.GetFsInfo(f)
  1424  	assert.Equal(t, f.Name(), info.Name)
  1425  	assert.Equal(t, f.Root(), info.Root)
  1426  	assert.Equal(t, f.String(), info.String)
  1427  	assert.Equal(t, f.Precision(), info.Precision)
  1428  	hashSet := hash.NewHashSet()
  1429  	for _, hashName := range info.Hashes {
  1430  		var ht hash.Type
  1431  		require.NoError(t, ht.Set(hashName))
  1432  		hashSet.Add(ht)
  1433  	}
  1434  	assert.Equal(t, f.Hashes(), hashSet)
  1435  	assert.Equal(t, f.Features().Enabled(), info.Features)
  1436  }