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

     1  package operations_test
     2  
     3  import (
     4  	"context"
     5  	"net/http"
     6  	"net/http/httptest"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/rclone/rclone/fs"
    11  	"github.com/rclone/rclone/fs/cache"
    12  	"github.com/rclone/rclone/fs/operations"
    13  	"github.com/rclone/rclone/fs/rc"
    14  	"github.com/rclone/rclone/fstest"
    15  	"github.com/stretchr/testify/assert"
    16  	"github.com/stretchr/testify/require"
    17  )
    18  
    19  func rcNewRun(t *testing.T, method string) (*fstest.Run, *rc.Call) {
    20  	if *fstest.RemoteName != "" {
    21  		t.Skip("Skipping test on non local remote")
    22  	}
    23  	r := fstest.NewRun(t)
    24  	call := rc.Calls.Get(method)
    25  	assert.NotNil(t, call)
    26  	cache.Put(r.LocalName, r.Flocal)
    27  	cache.Put(r.FremoteName, r.Fremote)
    28  	return r, call
    29  }
    30  
    31  // operations/about: Return the space used on the remote
    32  func TestRcAbout(t *testing.T) {
    33  	r, call := rcNewRun(t, "operations/about")
    34  	defer r.Finalise()
    35  	r.Mkdir(context.Background(), r.Fremote)
    36  
    37  	// Will get an error if remote doesn't support About
    38  	expectedErr := r.Fremote.Features().About == nil
    39  
    40  	in := rc.Params{
    41  		"fs": r.FremoteName,
    42  	}
    43  	out, err := call.Fn(context.Background(), in)
    44  	if expectedErr {
    45  		assert.Error(t, err)
    46  		return
    47  	}
    48  	require.NoError(t, err)
    49  
    50  	// Can't really check the output much!
    51  	assert.NotEqual(t, int64(0), out["Total"])
    52  }
    53  
    54  // operations/cleanup: Remove trashed files in the remote or path
    55  func TestRcCleanup(t *testing.T) {
    56  	r, call := rcNewRun(t, "operations/cleanup")
    57  	defer r.Finalise()
    58  
    59  	in := rc.Params{
    60  		"fs": r.LocalName,
    61  	}
    62  	out, err := call.Fn(context.Background(), in)
    63  	require.Error(t, err)
    64  	assert.Equal(t, rc.Params(nil), out)
    65  	assert.Contains(t, err.Error(), "doesn't support cleanup")
    66  }
    67  
    68  // operations/copyfile: Copy a file from source remote to destination remote
    69  func TestRcCopyfile(t *testing.T) {
    70  	r, call := rcNewRun(t, "operations/copyfile")
    71  	defer r.Finalise()
    72  	file1 := r.WriteFile("file1", "file1 contents", t1)
    73  	r.Mkdir(context.Background(), r.Fremote)
    74  	fstest.CheckItems(t, r.Flocal, file1)
    75  	fstest.CheckItems(t, r.Fremote)
    76  
    77  	in := rc.Params{
    78  		"srcFs":     r.LocalName,
    79  		"srcRemote": "file1",
    80  		"dstFs":     r.FremoteName,
    81  		"dstRemote": "file1-renamed",
    82  	}
    83  	out, err := call.Fn(context.Background(), in)
    84  	require.NoError(t, err)
    85  	assert.Equal(t, rc.Params(nil), out)
    86  
    87  	fstest.CheckItems(t, r.Flocal, file1)
    88  	file1.Path = "file1-renamed"
    89  	fstest.CheckItems(t, r.Fremote, file1)
    90  }
    91  
    92  // operations/copyurl: Copy the URL to the object
    93  func TestRcCopyurl(t *testing.T) {
    94  	r, call := rcNewRun(t, "operations/copyurl")
    95  	defer r.Finalise()
    96  	contents := "file1 contents\n"
    97  	file1 := r.WriteFile("file1", contents, t1)
    98  	r.Mkdir(context.Background(), r.Fremote)
    99  	fstest.CheckItems(t, r.Fremote)
   100  
   101  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   102  		_, err := w.Write([]byte(contents))
   103  		assert.NoError(t, err)
   104  	}))
   105  	defer ts.Close()
   106  
   107  	in := rc.Params{
   108  		"fs":           r.FremoteName,
   109  		"remote":       "file1",
   110  		"url":          ts.URL,
   111  		"autoFilename": false,
   112  		"noClobber":    false,
   113  	}
   114  	out, err := call.Fn(context.Background(), in)
   115  	require.NoError(t, err)
   116  	assert.Equal(t, rc.Params(nil), out)
   117  
   118  	in = rc.Params{
   119  		"fs":           r.FremoteName,
   120  		"remote":       "file1",
   121  		"url":          ts.URL,
   122  		"autoFilename": false,
   123  		"noClobber":    true,
   124  	}
   125  	out, err = call.Fn(context.Background(), in)
   126  	require.Error(t, err)
   127  	assert.Equal(t, rc.Params(nil), out)
   128  
   129  	urlFileName := "filename.txt"
   130  	in = rc.Params{
   131  		"fs":           r.FremoteName,
   132  		"remote":       "",
   133  		"url":          ts.URL + "/" + urlFileName,
   134  		"autoFilename": true,
   135  		"noClobber":    false,
   136  	}
   137  	out, err = call.Fn(context.Background(), in)
   138  	require.NoError(t, err)
   139  	assert.Equal(t, rc.Params(nil), out)
   140  
   141  	in = rc.Params{
   142  		"fs":           r.FremoteName,
   143  		"remote":       "",
   144  		"url":          ts.URL,
   145  		"autoFilename": true,
   146  		"noClobber":    false,
   147  	}
   148  	out, err = call.Fn(context.Background(), in)
   149  	require.Error(t, err)
   150  	assert.Equal(t, rc.Params(nil), out)
   151  
   152  	fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{file1, fstest.NewItem(urlFileName, contents, t1)}, nil, fs.ModTimeNotSupported)
   153  }
   154  
   155  // operations/delete: Remove files in the path
   156  func TestRcDelete(t *testing.T) {
   157  	r, call := rcNewRun(t, "operations/delete")
   158  	defer r.Finalise()
   159  
   160  	file1 := r.WriteObject(context.Background(), "small", "1234567890", t2)                                                                                           // 10 bytes
   161  	file2 := r.WriteObject(context.Background(), "medium", "------------------------------------------------------------", t1)                                        // 60 bytes
   162  	file3 := r.WriteObject(context.Background(), "large", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", t1) // 100 bytes
   163  	fstest.CheckItems(t, r.Fremote, file1, file2, file3)
   164  
   165  	in := rc.Params{
   166  		"fs": r.FremoteName,
   167  	}
   168  	out, err := call.Fn(context.Background(), in)
   169  	require.NoError(t, err)
   170  	assert.Equal(t, rc.Params(nil), out)
   171  
   172  	fstest.CheckItems(t, r.Fremote)
   173  }
   174  
   175  // operations/deletefile: Remove the single file pointed to
   176  func TestRcDeletefile(t *testing.T) {
   177  	r, call := rcNewRun(t, "operations/deletefile")
   178  	defer r.Finalise()
   179  
   180  	file1 := r.WriteObject(context.Background(), "small", "1234567890", t2)                                                    // 10 bytes
   181  	file2 := r.WriteObject(context.Background(), "medium", "------------------------------------------------------------", t1) // 60 bytes
   182  	fstest.CheckItems(t, r.Fremote, file1, file2)
   183  
   184  	in := rc.Params{
   185  		"fs":     r.FremoteName,
   186  		"remote": "small",
   187  	}
   188  	out, err := call.Fn(context.Background(), in)
   189  	require.NoError(t, err)
   190  	assert.Equal(t, rc.Params(nil), out)
   191  
   192  	fstest.CheckItems(t, r.Fremote, file2)
   193  }
   194  
   195  // operations/list: List the given remote and path in JSON format
   196  func TestRcList(t *testing.T) {
   197  	r, call := rcNewRun(t, "operations/list")
   198  	defer r.Finalise()
   199  
   200  	file1 := r.WriteObject(context.Background(), "a", "a", t1)
   201  	file2 := r.WriteObject(context.Background(), "subdir/b", "bb", t2)
   202  
   203  	fstest.CheckItems(t, r.Fremote, file1, file2)
   204  
   205  	in := rc.Params{
   206  		"fs":     r.FremoteName,
   207  		"remote": "",
   208  	}
   209  	out, err := call.Fn(context.Background(), in)
   210  	require.NoError(t, err)
   211  
   212  	list := out["list"].([]*operations.ListJSONItem)
   213  	assert.Equal(t, 2, len(list))
   214  
   215  	checkFile1 := func(got *operations.ListJSONItem) {
   216  		assert.WithinDuration(t, t1, got.ModTime.When, time.Second)
   217  		assert.Equal(t, "a", got.Path)
   218  		assert.Equal(t, "a", got.Name)
   219  		assert.Equal(t, int64(1), got.Size)
   220  		assert.Equal(t, "application/octet-stream", got.MimeType)
   221  		assert.Equal(t, false, got.IsDir)
   222  	}
   223  	checkFile1(list[0])
   224  
   225  	checkSubdir := func(got *operations.ListJSONItem) {
   226  		assert.Equal(t, "subdir", got.Path)
   227  		assert.Equal(t, "subdir", got.Name)
   228  		assert.Equal(t, int64(-1), got.Size)
   229  		assert.Equal(t, "inode/directory", got.MimeType)
   230  		assert.Equal(t, true, got.IsDir)
   231  	}
   232  	checkSubdir(list[1])
   233  
   234  	in = rc.Params{
   235  		"fs":     r.FremoteName,
   236  		"remote": "",
   237  		"opt": rc.Params{
   238  			"recurse": true,
   239  		},
   240  	}
   241  	out, err = call.Fn(context.Background(), in)
   242  	require.NoError(t, err)
   243  
   244  	list = out["list"].([]*operations.ListJSONItem)
   245  	assert.Equal(t, 3, len(list))
   246  	checkFile1(list[0])
   247  	checkSubdir(list[1])
   248  
   249  	checkFile2 := func(got *operations.ListJSONItem) {
   250  		assert.WithinDuration(t, t2, got.ModTime.When, time.Second)
   251  		assert.Equal(t, "subdir/b", got.Path)
   252  		assert.Equal(t, "b", got.Name)
   253  		assert.Equal(t, int64(2), got.Size)
   254  		assert.Equal(t, "application/octet-stream", got.MimeType)
   255  		assert.Equal(t, false, got.IsDir)
   256  	}
   257  	checkFile2(list[2])
   258  }
   259  
   260  // operations/mkdir: Make a destination directory or container
   261  func TestRcMkdir(t *testing.T) {
   262  	r, call := rcNewRun(t, "operations/mkdir")
   263  	defer r.Finalise()
   264  	r.Mkdir(context.Background(), r.Fremote)
   265  
   266  	fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{}, []string{}, fs.GetModifyWindow(r.Fremote))
   267  
   268  	in := rc.Params{
   269  		"fs":     r.FremoteName,
   270  		"remote": "subdir",
   271  	}
   272  	out, err := call.Fn(context.Background(), in)
   273  	require.NoError(t, err)
   274  	assert.Equal(t, rc.Params(nil), out)
   275  
   276  	fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{}, []string{"subdir"}, fs.GetModifyWindow(r.Fremote))
   277  }
   278  
   279  // operations/movefile: Move a file from source remote to destination remote
   280  func TestRcMovefile(t *testing.T) {
   281  	r, call := rcNewRun(t, "operations/movefile")
   282  	defer r.Finalise()
   283  	file1 := r.WriteFile("file1", "file1 contents", t1)
   284  	r.Mkdir(context.Background(), r.Fremote)
   285  	fstest.CheckItems(t, r.Flocal, file1)
   286  	fstest.CheckItems(t, r.Fremote)
   287  
   288  	in := rc.Params{
   289  		"srcFs":     r.LocalName,
   290  		"srcRemote": "file1",
   291  		"dstFs":     r.FremoteName,
   292  		"dstRemote": "file1-renamed",
   293  	}
   294  	out, err := call.Fn(context.Background(), in)
   295  	require.NoError(t, err)
   296  	assert.Equal(t, rc.Params(nil), out)
   297  
   298  	fstest.CheckItems(t, r.Flocal)
   299  	file1.Path = "file1-renamed"
   300  	fstest.CheckItems(t, r.Fremote, file1)
   301  }
   302  
   303  // operations/purge: Remove a directory or container and all of its contents
   304  func TestRcPurge(t *testing.T) {
   305  	r, call := rcNewRun(t, "operations/purge")
   306  	defer r.Finalise()
   307  	file1 := r.WriteObject(context.Background(), "subdir/file1", "subdir/file1 contents", t1)
   308  
   309  	fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{file1}, []string{"subdir"}, fs.GetModifyWindow(r.Fremote))
   310  
   311  	in := rc.Params{
   312  		"fs":     r.FremoteName,
   313  		"remote": "subdir",
   314  	}
   315  	out, err := call.Fn(context.Background(), in)
   316  	require.NoError(t, err)
   317  	assert.Equal(t, rc.Params(nil), out)
   318  
   319  	fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{}, []string{}, fs.GetModifyWindow(r.Fremote))
   320  }
   321  
   322  // operations/rmdir: Remove an empty directory or container
   323  func TestRcRmdir(t *testing.T) {
   324  	r, call := rcNewRun(t, "operations/rmdir")
   325  	defer r.Finalise()
   326  	r.Mkdir(context.Background(), r.Fremote)
   327  	assert.NoError(t, r.Fremote.Mkdir(context.Background(), "subdir"))
   328  
   329  	fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{}, []string{"subdir"}, fs.GetModifyWindow(r.Fremote))
   330  
   331  	in := rc.Params{
   332  		"fs":     r.FremoteName,
   333  		"remote": "subdir",
   334  	}
   335  	out, err := call.Fn(context.Background(), in)
   336  	require.NoError(t, err)
   337  	assert.Equal(t, rc.Params(nil), out)
   338  
   339  	fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{}, []string{}, fs.GetModifyWindow(r.Fremote))
   340  }
   341  
   342  // operations/rmdirs: Remove all the empty directories in the path
   343  func TestRcRmdirs(t *testing.T) {
   344  	r, call := rcNewRun(t, "operations/rmdirs")
   345  	defer r.Finalise()
   346  	r.Mkdir(context.Background(), r.Fremote)
   347  	assert.NoError(t, r.Fremote.Mkdir(context.Background(), "subdir"))
   348  	assert.NoError(t, r.Fremote.Mkdir(context.Background(), "subdir/subsubdir"))
   349  
   350  	fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{}, []string{"subdir", "subdir/subsubdir"}, fs.GetModifyWindow(r.Fremote))
   351  
   352  	in := rc.Params{
   353  		"fs":     r.FremoteName,
   354  		"remote": "subdir",
   355  	}
   356  	out, err := call.Fn(context.Background(), in)
   357  	require.NoError(t, err)
   358  	assert.Equal(t, rc.Params(nil), out)
   359  
   360  	fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{}, []string{}, fs.GetModifyWindow(r.Fremote))
   361  
   362  	assert.NoError(t, r.Fremote.Mkdir(context.Background(), "subdir"))
   363  	assert.NoError(t, r.Fremote.Mkdir(context.Background(), "subdir/subsubdir"))
   364  
   365  	in = rc.Params{
   366  		"fs":        r.FremoteName,
   367  		"remote":    "subdir",
   368  		"leaveRoot": true,
   369  	}
   370  	out, err = call.Fn(context.Background(), in)
   371  	require.NoError(t, err)
   372  	assert.Equal(t, rc.Params(nil), out)
   373  
   374  	fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{}, []string{"subdir"}, fs.GetModifyWindow(r.Fremote))
   375  
   376  }
   377  
   378  // operations/size: Count the number of bytes and files in remote
   379  func TestRcSize(t *testing.T) {
   380  	r, call := rcNewRun(t, "operations/size")
   381  	defer r.Finalise()
   382  	file1 := r.WriteObject(context.Background(), "small", "1234567890", t2)                                                           // 10 bytes
   383  	file2 := r.WriteObject(context.Background(), "subdir/medium", "------------------------------------------------------------", t1) // 60 bytes
   384  	file3 := r.WriteObject(context.Background(), "subdir/subsubdir/large", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", t1)  // 50 bytes
   385  	fstest.CheckItems(t, r.Fremote, file1, file2, file3)
   386  
   387  	in := rc.Params{
   388  		"fs": r.FremoteName,
   389  	}
   390  	out, err := call.Fn(context.Background(), in)
   391  	require.NoError(t, err)
   392  	assert.Equal(t, rc.Params{
   393  		"count": int64(3),
   394  		"bytes": int64(120),
   395  	}, out)
   396  }
   397  
   398  // operations/publiclink: Create or retrieve a public link to the given file or folder.
   399  func TestRcPublicLink(t *testing.T) {
   400  	r, call := rcNewRun(t, "operations/publiclink")
   401  	defer r.Finalise()
   402  	in := rc.Params{
   403  		"fs":     r.FremoteName,
   404  		"remote": "",
   405  	}
   406  	_, err := call.Fn(context.Background(), in)
   407  	require.Error(t, err)
   408  	assert.Contains(t, err.Error(), "doesn't support public links")
   409  }
   410  
   411  // operations/fsinfo: Return information about the remote
   412  func TestRcFsInfo(t *testing.T) {
   413  	r, call := rcNewRun(t, "operations/fsinfo")
   414  	defer r.Finalise()
   415  	in := rc.Params{
   416  		"fs": r.FremoteName,
   417  	}
   418  	got, err := call.Fn(context.Background(), in)
   419  	require.NoError(t, err)
   420  	want := operations.GetFsInfo(r.Fremote)
   421  	assert.Equal(t, want.Name, got["Name"])
   422  	assert.Equal(t, want.Root, got["Root"])
   423  	assert.Equal(t, want.String, got["String"])
   424  	assert.Equal(t, float64(want.Precision), got["Precision"])
   425  	var hashes []interface{}
   426  	for _, hash := range want.Hashes {
   427  		hashes = append(hashes, hash)
   428  	}
   429  	assert.Equal(t, hashes, got["Hashes"])
   430  	var features = map[string]interface{}{}
   431  	for k, v := range want.Features {
   432  		features[k] = v
   433  	}
   434  	assert.Equal(t, features, got["Features"])
   435  
   436  }
   437  
   438  // operations/command: Runs a backend command
   439  func TestRcCommand(t *testing.T) {
   440  	r, call := rcNewRun(t, "backend/command")
   441  	defer r.Finalise()
   442  	in := rc.Params{
   443  		"fs":      r.FremoteName,
   444  		"command": "noop",
   445  		"opt": map[string]string{
   446  			"echo": "true",
   447  			"blue": "",
   448  		},
   449  		"arg": []string{
   450  			"path1",
   451  			"path2",
   452  		},
   453  	}
   454  	got, err := call.Fn(context.Background(), in)
   455  	if err != nil {
   456  		assert.False(t, r.Fremote.Features().IsLocal, "mustn't fail on local remote")
   457  		assert.Contains(t, err.Error(), "command not found")
   458  		return
   459  	}
   460  	want := rc.Params{"result": map[string]interface{}{
   461  		"arg": []string{
   462  			"path1",
   463  			"path2",
   464  		},
   465  		"name": "noop",
   466  		"opt": map[string]string{
   467  			"blue": "",
   468  			"echo": "true",
   469  		},
   470  	}}
   471  	assert.Equal(t, want, got)
   472  	errTxt := "explosion in the sausage factory"
   473  	in["opt"].(map[string]string)["error"] = errTxt
   474  	_, err = call.Fn(context.Background(), in)
   475  	assert.Error(t, err)
   476  	assert.Contains(t, err.Error(), errTxt)
   477  }