github.com/ncw/rclone@v1.48.1-0.20190724201158-a35aa1360e3e/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/ncw/rclone/fs" 11 "github.com/ncw/rclone/fs/cache" 12 "github.com/ncw/rclone/fs/operations" 13 "github.com/ncw/rclone/fs/rc" 14 "github.com/ncw/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 } 112 out, err := call.Fn(context.Background(), in) 113 require.NoError(t, err) 114 assert.Equal(t, rc.Params(nil), out) 115 116 fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{file1}, nil, fs.ModTimeNotSupported) 117 } 118 119 // operations/delete: Remove files in the path 120 func TestRcDelete(t *testing.T) { 121 r, call := rcNewRun(t, "operations/delete") 122 defer r.Finalise() 123 124 file1 := r.WriteObject(context.Background(), "small", "1234567890", t2) // 10 bytes 125 file2 := r.WriteObject(context.Background(), "medium", "------------------------------------------------------------", t1) // 60 bytes 126 file3 := r.WriteObject(context.Background(), "large", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", t1) // 100 bytes 127 fstest.CheckItems(t, r.Fremote, file1, file2, file3) 128 129 in := rc.Params{ 130 "fs": r.FremoteName, 131 } 132 out, err := call.Fn(context.Background(), in) 133 require.NoError(t, err) 134 assert.Equal(t, rc.Params(nil), out) 135 136 fstest.CheckItems(t, r.Fremote) 137 } 138 139 // operations/deletefile: Remove the single file pointed to 140 func TestRcDeletefile(t *testing.T) { 141 r, call := rcNewRun(t, "operations/deletefile") 142 defer r.Finalise() 143 144 file1 := r.WriteObject(context.Background(), "small", "1234567890", t2) // 10 bytes 145 file2 := r.WriteObject(context.Background(), "medium", "------------------------------------------------------------", t1) // 60 bytes 146 fstest.CheckItems(t, r.Fremote, file1, file2) 147 148 in := rc.Params{ 149 "fs": r.FremoteName, 150 "remote": "small", 151 } 152 out, err := call.Fn(context.Background(), in) 153 require.NoError(t, err) 154 assert.Equal(t, rc.Params(nil), out) 155 156 fstest.CheckItems(t, r.Fremote, file2) 157 } 158 159 // operations/list: List the given remote and path in JSON format 160 func TestRcList(t *testing.T) { 161 r, call := rcNewRun(t, "operations/list") 162 defer r.Finalise() 163 164 file1 := r.WriteObject(context.Background(), "a", "a", t1) 165 file2 := r.WriteObject(context.Background(), "subdir/b", "bb", t2) 166 167 fstest.CheckItems(t, r.Fremote, file1, file2) 168 169 in := rc.Params{ 170 "fs": r.FremoteName, 171 "remote": "", 172 } 173 out, err := call.Fn(context.Background(), in) 174 require.NoError(t, err) 175 176 list := out["list"].([]*operations.ListJSONItem) 177 assert.Equal(t, 2, len(list)) 178 179 checkFile1 := func(got *operations.ListJSONItem) { 180 assert.WithinDuration(t, t1, got.ModTime.When, time.Second) 181 assert.Equal(t, "a", got.Path) 182 assert.Equal(t, "a", got.Name) 183 assert.Equal(t, int64(1), got.Size) 184 assert.Equal(t, "application/octet-stream", got.MimeType) 185 assert.Equal(t, false, got.IsDir) 186 } 187 checkFile1(list[0]) 188 189 checkSubdir := func(got *operations.ListJSONItem) { 190 assert.Equal(t, "subdir", got.Path) 191 assert.Equal(t, "subdir", got.Name) 192 assert.Equal(t, int64(-1), got.Size) 193 assert.Equal(t, "inode/directory", got.MimeType) 194 assert.Equal(t, true, got.IsDir) 195 } 196 checkSubdir(list[1]) 197 198 in = rc.Params{ 199 "fs": r.FremoteName, 200 "remote": "", 201 "opt": rc.Params{ 202 "recurse": true, 203 }, 204 } 205 out, err = call.Fn(context.Background(), in) 206 require.NoError(t, err) 207 208 list = out["list"].([]*operations.ListJSONItem) 209 assert.Equal(t, 3, len(list)) 210 checkFile1(list[0]) 211 checkSubdir(list[1]) 212 213 checkFile2 := func(got *operations.ListJSONItem) { 214 assert.WithinDuration(t, t2, got.ModTime.When, time.Second) 215 assert.Equal(t, "subdir/b", got.Path) 216 assert.Equal(t, "b", got.Name) 217 assert.Equal(t, int64(2), got.Size) 218 assert.Equal(t, "application/octet-stream", got.MimeType) 219 assert.Equal(t, false, got.IsDir) 220 } 221 checkFile2(list[2]) 222 } 223 224 // operations/mkdir: Make a destination directory or container 225 func TestRcMkdir(t *testing.T) { 226 r, call := rcNewRun(t, "operations/mkdir") 227 defer r.Finalise() 228 r.Mkdir(context.Background(), r.Fremote) 229 230 fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{}, []string{}, fs.GetModifyWindow(r.Fremote)) 231 232 in := rc.Params{ 233 "fs": r.FremoteName, 234 "remote": "subdir", 235 } 236 out, err := call.Fn(context.Background(), in) 237 require.NoError(t, err) 238 assert.Equal(t, rc.Params(nil), out) 239 240 fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{}, []string{"subdir"}, fs.GetModifyWindow(r.Fremote)) 241 } 242 243 // operations/movefile: Move a file from source remote to destination remote 244 func TestRcMovefile(t *testing.T) { 245 r, call := rcNewRun(t, "operations/movefile") 246 defer r.Finalise() 247 file1 := r.WriteFile("file1", "file1 contents", t1) 248 r.Mkdir(context.Background(), r.Fremote) 249 fstest.CheckItems(t, r.Flocal, file1) 250 fstest.CheckItems(t, r.Fremote) 251 252 in := rc.Params{ 253 "srcFs": r.LocalName, 254 "srcRemote": "file1", 255 "dstFs": r.FremoteName, 256 "dstRemote": "file1-renamed", 257 } 258 out, err := call.Fn(context.Background(), in) 259 require.NoError(t, err) 260 assert.Equal(t, rc.Params(nil), out) 261 262 fstest.CheckItems(t, r.Flocal) 263 file1.Path = "file1-renamed" 264 fstest.CheckItems(t, r.Fremote, file1) 265 } 266 267 // operations/purge: Remove a directory or container and all of its contents 268 func TestRcPurge(t *testing.T) { 269 r, call := rcNewRun(t, "operations/purge") 270 defer r.Finalise() 271 file1 := r.WriteObject(context.Background(), "subdir/file1", "subdir/file1 contents", t1) 272 273 fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{file1}, []string{"subdir"}, fs.GetModifyWindow(r.Fremote)) 274 275 in := rc.Params{ 276 "fs": r.FremoteName, 277 "remote": "subdir", 278 } 279 out, err := call.Fn(context.Background(), in) 280 require.NoError(t, err) 281 assert.Equal(t, rc.Params(nil), out) 282 283 fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{}, []string{}, fs.GetModifyWindow(r.Fremote)) 284 } 285 286 // operations/rmdir: Remove an empty directory or container 287 func TestRcRmdir(t *testing.T) { 288 r, call := rcNewRun(t, "operations/rmdir") 289 defer r.Finalise() 290 r.Mkdir(context.Background(), r.Fremote) 291 assert.NoError(t, r.Fremote.Mkdir(context.Background(), "subdir")) 292 293 fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{}, []string{"subdir"}, fs.GetModifyWindow(r.Fremote)) 294 295 in := rc.Params{ 296 "fs": r.FremoteName, 297 "remote": "subdir", 298 } 299 out, err := call.Fn(context.Background(), in) 300 require.NoError(t, err) 301 assert.Equal(t, rc.Params(nil), out) 302 303 fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{}, []string{}, fs.GetModifyWindow(r.Fremote)) 304 } 305 306 // operations/rmdirs: Remove all the empty directories in the path 307 func TestRcRmdirs(t *testing.T) { 308 r, call := rcNewRun(t, "operations/rmdirs") 309 defer r.Finalise() 310 r.Mkdir(context.Background(), r.Fremote) 311 assert.NoError(t, r.Fremote.Mkdir(context.Background(), "subdir")) 312 assert.NoError(t, r.Fremote.Mkdir(context.Background(), "subdir/subsubdir")) 313 314 fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{}, []string{"subdir", "subdir/subsubdir"}, fs.GetModifyWindow(r.Fremote)) 315 316 in := rc.Params{ 317 "fs": r.FremoteName, 318 "remote": "subdir", 319 } 320 out, err := call.Fn(context.Background(), in) 321 require.NoError(t, err) 322 assert.Equal(t, rc.Params(nil), out) 323 324 fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{}, []string{}, fs.GetModifyWindow(r.Fremote)) 325 326 assert.NoError(t, r.Fremote.Mkdir(context.Background(), "subdir")) 327 assert.NoError(t, r.Fremote.Mkdir(context.Background(), "subdir/subsubdir")) 328 329 in = rc.Params{ 330 "fs": r.FremoteName, 331 "remote": "subdir", 332 "leaveRoot": true, 333 } 334 out, err = call.Fn(context.Background(), in) 335 require.NoError(t, err) 336 assert.Equal(t, rc.Params(nil), out) 337 338 fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{}, []string{"subdir"}, fs.GetModifyWindow(r.Fremote)) 339 340 } 341 342 // operations/size: Count the number of bytes and files in remote 343 func TestRcSize(t *testing.T) { 344 r, call := rcNewRun(t, "operations/size") 345 defer r.Finalise() 346 file1 := r.WriteObject(context.Background(), "small", "1234567890", t2) // 10 bytes 347 file2 := r.WriteObject(context.Background(), "subdir/medium", "------------------------------------------------------------", t1) // 60 bytes 348 file3 := r.WriteObject(context.Background(), "subdir/subsubdir/large", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", t1) // 50 bytes 349 fstest.CheckItems(t, r.Fremote, file1, file2, file3) 350 351 in := rc.Params{ 352 "fs": r.FremoteName, 353 } 354 out, err := call.Fn(context.Background(), in) 355 require.NoError(t, err) 356 assert.Equal(t, rc.Params{ 357 "count": int64(3), 358 "bytes": int64(120), 359 }, out) 360 } 361 362 // operations/publiclink: Create or retrieve a public link to the given file or folder. 363 func TestRcPublicLink(t *testing.T) { 364 r, call := rcNewRun(t, "operations/publiclink") 365 defer r.Finalise() 366 in := rc.Params{ 367 "fs": r.FremoteName, 368 "remote": "", 369 } 370 _, err := call.Fn(context.Background(), in) 371 require.Error(t, err) 372 assert.Contains(t, err.Error(), "doesn't support public links") 373 } 374 375 // operations/fsinfo: Return information about the remote 376 func TestRcFsInfo(t *testing.T) { 377 r, call := rcNewRun(t, "operations/fsinfo") 378 defer r.Finalise() 379 in := rc.Params{ 380 "fs": r.FremoteName, 381 } 382 got, err := call.Fn(context.Background(), in) 383 require.NoError(t, err) 384 want := operations.GetFsInfo(r.Fremote) 385 assert.Equal(t, want.Name, got["Name"]) 386 assert.Equal(t, want.Root, got["Root"]) 387 assert.Equal(t, want.String, got["String"]) 388 assert.Equal(t, float64(want.Precision), got["Precision"]) 389 var hashes []interface{} 390 for _, hash := range want.Hashes { 391 hashes = append(hashes, hash) 392 } 393 assert.Equal(t, hashes, got["Hashes"]) 394 var features = map[string]interface{}{} 395 for k, v := range want.Features { 396 features[k] = v 397 } 398 assert.Equal(t, features, got["Features"]) 399 400 }