github.com/ncw/rclone@v1.48.1-0.20190724201158-a35aa1360e3e/backend/cache/cache_internal_test.go (about) 1 // +build !plan9 2 3 package cache_test 4 5 import ( 6 "bytes" 7 "context" 8 "encoding/base64" 9 goflag "flag" 10 "fmt" 11 "io" 12 "io/ioutil" 13 "log" 14 "math/rand" 15 "os" 16 "path" 17 "path/filepath" 18 "runtime" 19 "runtime/debug" 20 "strconv" 21 "strings" 22 "testing" 23 "time" 24 25 "github.com/ncw/rclone/backend/cache" 26 "github.com/ncw/rclone/backend/crypt" 27 _ "github.com/ncw/rclone/backend/drive" 28 "github.com/ncw/rclone/backend/local" 29 "github.com/ncw/rclone/fs" 30 "github.com/ncw/rclone/fs/config" 31 "github.com/ncw/rclone/fs/config/configmap" 32 "github.com/ncw/rclone/fs/object" 33 "github.com/ncw/rclone/fs/rc" 34 "github.com/ncw/rclone/fstest" 35 "github.com/ncw/rclone/vfs" 36 "github.com/ncw/rclone/vfs/vfsflags" 37 "github.com/pkg/errors" 38 "github.com/stretchr/testify/assert" 39 "github.com/stretchr/testify/require" 40 ) 41 42 const ( 43 // these 2 passwords are test random 44 cryptPassword1 = "3XcvMMdsV3d-HGAReTMdNH-5FcX5q32_lUeA" // oGJdUbQc7s8 45 cryptPassword2 = "NlgTBEIe-qibA7v-FoMfuX6Cw8KlLai_aMvV" // mv4mZW572HM 46 cryptedTextBase64 = "UkNMT05FAAC320i2xIee0BiNyknSPBn+Qcw3q9FhIFp3tvq6qlqvbsno3PnxmEFeJG3jDBnR/wku2gHWeQ==" // one content 47 cryptedText2Base64 = "UkNMT05FAAATcQkVsgjBh8KafCKcr0wdTa1fMmV0U8hsCLGFoqcvxKVmvv7wx3Hf5EXxFcki2FFV4sdpmSrb9Q==" // updated content 48 cryptedText3Base64 = "UkNMT05FAAB/f7YtYKbPfmk9+OX/ffN3qG3OEdWT+z74kxCX9V/YZwJ4X2DN3HOnUC3gKQ4Gcoud5UtNvQ==" // test content 49 letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" 50 ) 51 52 var ( 53 remoteName string 54 mountDir string 55 uploadDir string 56 useMount bool 57 runInstance *run 58 errNotSupported = errors.New("not supported") 59 decryptedToEncryptedRemotes = map[string]string{ 60 "one": "lm4u7jjt3c85bf56vjqgeenuno", 61 "second": "qvt1ochrkcfbptp5mu9ugb2l14", 62 "test": "jn4tegjtpqro30t3o11thb4b5s", 63 "test2": "qakvqnh8ttei89e0gc76crpql4", 64 "data.bin": "0q2847tfko6mhj3dag3r809qbc", 65 "ticw/data.bin": "5mv97b0ule6pht33srae5pice8/0q2847tfko6mhj3dag3r809qbc", 66 "tiuufo/test/one": "vi6u1olqhirqv14cd8qlej1mgo/jn4tegjtpqro30t3o11thb4b5s/lm4u7jjt3c85bf56vjqgeenuno", 67 "tiuufo/test/second": "vi6u1olqhirqv14cd8qlej1mgo/jn4tegjtpqro30t3o11thb4b5s/qvt1ochrkcfbptp5mu9ugb2l14", 68 "tiutfo/test/one": "legd371aa8ol36tjfklt347qnc/jn4tegjtpqro30t3o11thb4b5s/lm4u7jjt3c85bf56vjqgeenuno", 69 "tiutfo/second/one": "legd371aa8ol36tjfklt347qnc/qvt1ochrkcfbptp5mu9ugb2l14/lm4u7jjt3c85bf56vjqgeenuno", 70 "second/one": "qvt1ochrkcfbptp5mu9ugb2l14/lm4u7jjt3c85bf56vjqgeenuno", 71 "test/one": "jn4tegjtpqro30t3o11thb4b5s/lm4u7jjt3c85bf56vjqgeenuno", 72 "test/second": "jn4tegjtpqro30t3o11thb4b5s/qvt1ochrkcfbptp5mu9ugb2l14", 73 "one/test": "lm4u7jjt3c85bf56vjqgeenuno/jn4tegjtpqro30t3o11thb4b5s", 74 "one/test/data.bin": "lm4u7jjt3c85bf56vjqgeenuno/jn4tegjtpqro30t3o11thb4b5s/0q2847tfko6mhj3dag3r809qbc", 75 "second/test/data.bin": "qvt1ochrkcfbptp5mu9ugb2l14/jn4tegjtpqro30t3o11thb4b5s/0q2847tfko6mhj3dag3r809qbc", 76 "test/third": "jn4tegjtpqro30t3o11thb4b5s/2nd7fjiop5h3ihfj1vl953aa5g", 77 "test/0.bin": "jn4tegjtpqro30t3o11thb4b5s/e6frddt058b6kvbpmlstlndmtk", 78 "test/1.bin": "jn4tegjtpqro30t3o11thb4b5s/kck472nt1k7qbmob0mt1p1crgc", 79 "test/2.bin": "jn4tegjtpqro30t3o11thb4b5s/744oe9ven2rmak4u27if51qk24", 80 "test/3.bin": "jn4tegjtpqro30t3o11thb4b5s/2bjd8kef0u5lmsu6qhqll34bcs", 81 "test/4.bin": "jn4tegjtpqro30t3o11thb4b5s/cvjs73iv0a82v0c7r67avllh7s", 82 "test/5.bin": "jn4tegjtpqro30t3o11thb4b5s/0plkdo790b6bnmt33qsdqmhv9c", 83 "test/6.bin": "jn4tegjtpqro30t3o11thb4b5s/s5r633srnjtbh83893jovjt5d0", 84 "test/7.bin": "jn4tegjtpqro30t3o11thb4b5s/6rq45tr9bjsammku622flmqsu4", 85 "test/8.bin": "jn4tegjtpqro30t3o11thb4b5s/37bc6tcl3e31qb8cadvjb749vk", 86 "test/9.bin": "jn4tegjtpqro30t3o11thb4b5s/t4pr35hnls32789o8fk0chk1ec", 87 } 88 ) 89 90 func init() { 91 goflag.StringVar(&remoteName, "remote-internal", "TestInternalCache", "Remote to test with, defaults to local filesystem") 92 goflag.StringVar(&mountDir, "mount-dir-internal", "", "") 93 goflag.StringVar(&uploadDir, "upload-dir-internal", "", "") 94 goflag.BoolVar(&useMount, "cache-use-mount", false, "Test only with mount") 95 } 96 97 // TestMain drives the tests 98 func TestMain(m *testing.M) { 99 goflag.Parse() 100 var rc int 101 102 log.Printf("Running with the following params: \n remote: %v, \n mount: %v", remoteName, useMount) 103 runInstance = newRun() 104 rc = m.Run() 105 os.Exit(rc) 106 } 107 108 func TestInternalListRootAndInnerRemotes(t *testing.T) { 109 id := fmt.Sprintf("tilrair%v", time.Now().Unix()) 110 rootFs, boltDb := runInstance.newCacheFs(t, remoteName, id, true, true, nil, nil) 111 defer runInstance.cleanupFs(t, rootFs, boltDb) 112 113 // Instantiate inner fs 114 innerFolder := "inner" 115 runInstance.mkdir(t, rootFs, innerFolder) 116 rootFs2, boltDb2 := runInstance.newCacheFs(t, remoteName, id+"/"+innerFolder, true, true, nil, nil) 117 defer runInstance.cleanupFs(t, rootFs2, boltDb2) 118 119 runInstance.writeObjectString(t, rootFs2, "one", "content") 120 listRoot, err := runInstance.list(t, rootFs, "") 121 require.NoError(t, err) 122 listRootInner, err := runInstance.list(t, rootFs, innerFolder) 123 require.NoError(t, err) 124 listInner, err := rootFs2.List(context.Background(), "") 125 require.NoError(t, err) 126 127 require.Len(t, listRoot, 1) 128 require.Len(t, listRootInner, 1) 129 require.Len(t, listInner, 1) 130 } 131 132 /* TODO: is this testing something? 133 func TestInternalVfsCache(t *testing.T) { 134 vfsflags.Opt.DirCacheTime = time.Second * 30 135 testSize := int64(524288000) 136 137 vfsflags.Opt.CacheMode = vfs.CacheModeWrites 138 id := "tiuufo" 139 rootFs, boltDb := runInstance.newCacheFs(t, remoteName, id, true, true, nil, map[string]string{"writes": "true", "info_age": "1h"}) 140 defer runInstance.cleanupFs(t, rootFs, boltDb) 141 142 err := rootFs.Mkdir(context.Background(), "test") 143 require.NoError(t, err) 144 runInstance.writeObjectString(t, rootFs, "test/second", "content") 145 _, err = rootFs.List(context.Background(), "test") 146 require.NoError(t, err) 147 148 testReader := runInstance.randomReader(t, testSize) 149 writeCh := make(chan interface{}) 150 //write2Ch := make(chan interface{}) 151 readCh := make(chan interface{}) 152 cacheCh := make(chan interface{}) 153 // write the main file 154 go func() { 155 defer func() { 156 writeCh <- true 157 }() 158 159 log.Printf("========== started writing file 'test/one'") 160 runInstance.writeRemoteReader(t, rootFs, "test/one", testReader) 161 log.Printf("========== done writing file 'test/one'") 162 }() 163 // routine to check which cache has what, autostarts 164 go func() { 165 for { 166 select { 167 case <-cacheCh: 168 log.Printf("========== finished checking caches") 169 return 170 default: 171 } 172 li2 := [2]string{path.Join("test", "one"), path.Join("test", "second")} 173 for _, r := range li2 { 174 var err error 175 ci, err := ioutil.ReadDir(path.Join(runInstance.chunkPath, runInstance.encryptRemoteIfNeeded(t, path.Join(id, r)))) 176 if err != nil || len(ci) == 0 { 177 log.Printf("========== '%v' not in cache", r) 178 } else { 179 log.Printf("========== '%v' IN CACHE", r) 180 } 181 _, err = os.Stat(path.Join(runInstance.vfsCachePath, id, r)) 182 if err != nil { 183 log.Printf("========== '%v' not in vfs", r) 184 } else { 185 log.Printf("========== '%v' IN VFS", r) 186 } 187 } 188 time.Sleep(time.Second * 10) 189 } 190 }() 191 // routine to list, autostarts 192 go func() { 193 for { 194 select { 195 case <-readCh: 196 log.Printf("========== finished checking listings and readings") 197 return 198 default: 199 } 200 li, err := runInstance.list(t, rootFs, "test") 201 if err != nil { 202 log.Printf("========== error listing 'test' folder: %v", err) 203 } else { 204 log.Printf("========== list 'test' folder count: %v", len(li)) 205 } 206 207 time.Sleep(time.Second * 10) 208 } 209 }() 210 211 // wait for main file to be written 212 <-writeCh 213 log.Printf("========== waiting for VFS to expire") 214 time.Sleep(time.Second * 120) 215 216 // try a final read 217 li2 := [2]string{"test/one", "test/second"} 218 for _, r := range li2 { 219 _, err := runInstance.readDataFromRemote(t, rootFs, r, int64(0), int64(2), false) 220 if err != nil { 221 log.Printf("========== error reading '%v': %v", r, err) 222 } else { 223 log.Printf("========== read '%v'", r) 224 } 225 } 226 // close the cache and list checkers 227 cacheCh <- true 228 readCh <- true 229 } 230 */ 231 232 func TestInternalObjWrapFsFound(t *testing.T) { 233 id := fmt.Sprintf("tiowff%v", time.Now().Unix()) 234 rootFs, boltDb := runInstance.newCacheFs(t, remoteName, id, true, true, nil, nil) 235 defer runInstance.cleanupFs(t, rootFs, boltDb) 236 237 cfs, err := runInstance.getCacheFs(rootFs) 238 require.NoError(t, err) 239 wrappedFs := cfs.UnWrap() 240 241 var testData []byte 242 if runInstance.rootIsCrypt { 243 testData, err = base64.StdEncoding.DecodeString(cryptedTextBase64) 244 require.NoError(t, err) 245 } else { 246 testData = []byte("test content") 247 } 248 249 runInstance.writeObjectBytes(t, wrappedFs, runInstance.encryptRemoteIfNeeded(t, "test"), testData) 250 listRoot, err := runInstance.list(t, rootFs, "") 251 require.NoError(t, err) 252 require.Len(t, listRoot, 1) 253 254 cachedData, err := runInstance.readDataFromRemote(t, rootFs, "test", 0, int64(len([]byte("test content"))), false) 255 require.NoError(t, err) 256 require.Equal(t, "test content", string(cachedData)) 257 258 err = runInstance.rm(t, rootFs, "test") 259 require.NoError(t, err) 260 listRoot, err = runInstance.list(t, rootFs, "") 261 require.NoError(t, err) 262 require.Len(t, listRoot, 0) 263 } 264 265 func TestInternalObjNotFound(t *testing.T) { 266 id := fmt.Sprintf("tionf%v", time.Now().Unix()) 267 rootFs, boltDb := runInstance.newCacheFs(t, remoteName, id, false, true, nil, nil) 268 defer runInstance.cleanupFs(t, rootFs, boltDb) 269 270 obj, err := rootFs.NewObject(context.Background(), "404") 271 require.Error(t, err) 272 require.Nil(t, obj) 273 } 274 275 func TestInternalRemoteWrittenFileFoundInMount(t *testing.T) { 276 if !runInstance.useMount { 277 t.Skip("test needs mount mode") 278 } 279 id := fmt.Sprintf("tirwffim%v", time.Now().Unix()) 280 rootFs, boltDb := runInstance.newCacheFs(t, remoteName, id, true, true, nil, nil) 281 defer runInstance.cleanupFs(t, rootFs, boltDb) 282 283 cfs, err := runInstance.getCacheFs(rootFs) 284 require.NoError(t, err) 285 286 var testData []byte 287 if runInstance.rootIsCrypt { 288 testData, err = base64.StdEncoding.DecodeString(cryptedTextBase64) 289 require.NoError(t, err) 290 } else { 291 testData = []byte("test content") 292 } 293 294 runInstance.writeObjectBytes(t, cfs.UnWrap(), runInstance.encryptRemoteIfNeeded(t, "test"), testData) 295 data, err := runInstance.readDataFromRemote(t, rootFs, "test", 0, int64(len([]byte("test content"))), false) 296 require.NoError(t, err) 297 require.Equal(t, "test content", string(data)) 298 } 299 300 func TestInternalCachedWrittenContentMatches(t *testing.T) { 301 id := fmt.Sprintf("ticwcm%v", time.Now().Unix()) 302 rootFs, boltDb := runInstance.newCacheFs(t, remoteName, id, false, true, nil, nil) 303 defer runInstance.cleanupFs(t, rootFs, boltDb) 304 305 cfs, err := runInstance.getCacheFs(rootFs) 306 require.NoError(t, err) 307 chunkSize := cfs.ChunkSize() 308 309 // create some rand test data 310 testData := randStringBytes(int(chunkSize*4 + chunkSize/2)) 311 312 // write the object 313 runInstance.writeRemoteBytes(t, rootFs, "data.bin", testData) 314 315 // check sample of data from in-file 316 sampleStart := chunkSize / 2 317 sampleEnd := chunkSize 318 testSample := testData[sampleStart:sampleEnd] 319 checkSample, err := runInstance.readDataFromRemote(t, rootFs, "data.bin", sampleStart, sampleEnd, false) 320 require.NoError(t, err) 321 require.Equal(t, int64(len(checkSample)), sampleEnd-sampleStart) 322 require.Equal(t, checkSample, testSample) 323 } 324 325 func TestInternalDoubleWrittenContentMatches(t *testing.T) { 326 id := fmt.Sprintf("tidwcm%v", time.Now().Unix()) 327 rootFs, boltDb := runInstance.newCacheFs(t, remoteName, id, false, true, nil, nil) 328 defer runInstance.cleanupFs(t, rootFs, boltDb) 329 330 // write the object 331 runInstance.writeRemoteString(t, rootFs, "one", "one content") 332 err := runInstance.updateData(t, rootFs, "one", "one content", " updated") 333 require.NoError(t, err) 334 err = runInstance.updateData(t, rootFs, "one", "one content updated", " double") 335 require.NoError(t, err) 336 337 // check sample of data from in-file 338 data, err := runInstance.readDataFromRemote(t, rootFs, "one", int64(0), int64(len("one content updated double")), true) 339 require.NoError(t, err) 340 require.Equal(t, "one content updated double", string(data)) 341 } 342 343 func TestInternalCachedUpdatedContentMatches(t *testing.T) { 344 id := fmt.Sprintf("ticucm%v", time.Now().Unix()) 345 rootFs, boltDb := runInstance.newCacheFs(t, remoteName, id, false, true, nil, nil) 346 defer runInstance.cleanupFs(t, rootFs, boltDb) 347 var err error 348 349 // create some rand test data 350 var testData1 []byte 351 var testData2 []byte 352 if runInstance.rootIsCrypt { 353 testData1, err = base64.StdEncoding.DecodeString(cryptedTextBase64) 354 require.NoError(t, err) 355 testData2, err = base64.StdEncoding.DecodeString(cryptedText2Base64) 356 require.NoError(t, err) 357 } else { 358 testData1 = []byte(fstest.RandomString(100)) 359 testData2 = []byte(fstest.RandomString(200)) 360 } 361 362 // write the object 363 o := runInstance.updateObjectRemote(t, rootFs, "data.bin", testData1, testData2) 364 require.Equal(t, o.Size(), int64(len(testData2))) 365 366 // check data from in-file 367 checkSample, err := runInstance.readDataFromRemote(t, rootFs, "data.bin", 0, int64(len(testData2)), false) 368 require.NoError(t, err) 369 require.Equal(t, checkSample, testData2) 370 } 371 372 func TestInternalWrappedWrittenContentMatches(t *testing.T) { 373 id := fmt.Sprintf("tiwwcm%v", time.Now().Unix()) 374 vfsflags.Opt.DirCacheTime = time.Second 375 rootFs, boltDb := runInstance.newCacheFs(t, remoteName, id, true, true, nil, nil) 376 defer runInstance.cleanupFs(t, rootFs, boltDb) 377 if runInstance.rootIsCrypt { 378 t.Skip("test skipped with crypt remote") 379 } 380 381 cfs, err := runInstance.getCacheFs(rootFs) 382 require.NoError(t, err) 383 chunkSize := cfs.ChunkSize() 384 385 // create some rand test data 386 testSize := chunkSize*4 + chunkSize/2 387 testData := randStringBytes(int(testSize)) 388 389 // write the object 390 o := runInstance.writeObjectBytes(t, cfs.UnWrap(), "data.bin", testData) 391 require.Equal(t, o.Size(), testSize) 392 time.Sleep(time.Second * 3) 393 394 checkSample, err := runInstance.readDataFromRemote(t, rootFs, "data.bin", 0, testSize, false) 395 require.NoError(t, err) 396 require.Equal(t, int64(len(checkSample)), o.Size()) 397 398 for i := 0; i < len(checkSample); i++ { 399 require.Equal(t, testData[i], checkSample[i]) 400 } 401 } 402 403 func TestInternalLargeWrittenContentMatches(t *testing.T) { 404 id := fmt.Sprintf("tilwcm%v", time.Now().Unix()) 405 vfsflags.Opt.DirCacheTime = time.Second 406 rootFs, boltDb := runInstance.newCacheFs(t, remoteName, id, true, true, nil, nil) 407 defer runInstance.cleanupFs(t, rootFs, boltDb) 408 if runInstance.rootIsCrypt { 409 t.Skip("test skipped with crypt remote") 410 } 411 412 cfs, err := runInstance.getCacheFs(rootFs) 413 require.NoError(t, err) 414 chunkSize := cfs.ChunkSize() 415 416 // create some rand test data 417 testSize := chunkSize*10 + chunkSize/2 418 testData := randStringBytes(int(testSize)) 419 420 // write the object 421 runInstance.writeObjectBytes(t, cfs.UnWrap(), "data.bin", testData) 422 time.Sleep(time.Second * 3) 423 424 readData, err := runInstance.readDataFromRemote(t, rootFs, "data.bin", 0, testSize, false) 425 require.NoError(t, err) 426 for i := 0; i < len(readData); i++ { 427 require.Equalf(t, testData[i], readData[i], "at byte %v", i) 428 } 429 } 430 431 func TestInternalWrappedFsChangeNotSeen(t *testing.T) { 432 id := fmt.Sprintf("tiwfcns%v", time.Now().Unix()) 433 rootFs, boltDb := runInstance.newCacheFs(t, remoteName, id, false, true, nil, nil) 434 defer runInstance.cleanupFs(t, rootFs, boltDb) 435 436 cfs, err := runInstance.getCacheFs(rootFs) 437 require.NoError(t, err) 438 chunkSize := cfs.ChunkSize() 439 440 // create some rand test data 441 testData := randStringBytes(int(chunkSize*4 + chunkSize/2)) 442 runInstance.writeRemoteBytes(t, rootFs, "data.bin", testData) 443 444 // update in the wrapped fs 445 originalSize, err := runInstance.size(t, rootFs, "data.bin") 446 require.NoError(t, err) 447 log.Printf("original size: %v", originalSize) 448 449 o, err := cfs.UnWrap().NewObject(context.Background(), runInstance.encryptRemoteIfNeeded(t, "data.bin")) 450 require.NoError(t, err) 451 expectedSize := int64(len([]byte("test content"))) 452 var data2 []byte 453 if runInstance.rootIsCrypt { 454 data2, err = base64.StdEncoding.DecodeString(cryptedText3Base64) 455 require.NoError(t, err) 456 expectedSize = expectedSize + 1 // FIXME newline gets in, likely test data issue 457 } else { 458 data2 = []byte("test content") 459 } 460 objInfo := object.NewStaticObjectInfo(runInstance.encryptRemoteIfNeeded(t, "data.bin"), time.Now(), int64(len(data2)), true, nil, cfs.UnWrap()) 461 err = o.Update(context.Background(), bytes.NewReader(data2), objInfo) 462 require.NoError(t, err) 463 require.Equal(t, int64(len(data2)), o.Size()) 464 log.Printf("updated size: %v", len(data2)) 465 466 // get a new instance from the cache 467 if runInstance.wrappedIsExternal { 468 err = runInstance.retryBlock(func() error { 469 coSize, err := runInstance.size(t, rootFs, "data.bin") 470 if err != nil { 471 return err 472 } 473 if coSize != expectedSize { 474 return errors.Errorf("%v <> %v", coSize, expectedSize) 475 } 476 return nil 477 }, 12, time.Second*10) 478 require.NoError(t, err) 479 } else { 480 coSize, err := runInstance.size(t, rootFs, "data.bin") 481 require.NoError(t, err) 482 require.NotEqual(t, coSize, expectedSize) 483 } 484 } 485 486 func TestInternalMoveWithNotify(t *testing.T) { 487 id := fmt.Sprintf("timwn%v", time.Now().Unix()) 488 rootFs, boltDb := runInstance.newCacheFs(t, remoteName, id, false, true, nil, nil) 489 defer runInstance.cleanupFs(t, rootFs, boltDb) 490 if !runInstance.wrappedIsExternal { 491 t.Skipf("Not external") 492 } 493 494 cfs, err := runInstance.getCacheFs(rootFs) 495 require.NoError(t, err) 496 497 srcName := runInstance.encryptRemoteIfNeeded(t, "test") + "/" + runInstance.encryptRemoteIfNeeded(t, "one") + "/" + runInstance.encryptRemoteIfNeeded(t, "data.bin") 498 dstName := runInstance.encryptRemoteIfNeeded(t, "test") + "/" + runInstance.encryptRemoteIfNeeded(t, "second") + "/" + runInstance.encryptRemoteIfNeeded(t, "data.bin") 499 // create some rand test data 500 var testData []byte 501 if runInstance.rootIsCrypt { 502 testData, err = base64.StdEncoding.DecodeString(cryptedTextBase64) 503 require.NoError(t, err) 504 } else { 505 testData = []byte("test content") 506 } 507 _ = cfs.UnWrap().Mkdir(context.Background(), runInstance.encryptRemoteIfNeeded(t, "test")) 508 _ = cfs.UnWrap().Mkdir(context.Background(), runInstance.encryptRemoteIfNeeded(t, "test/one")) 509 _ = cfs.UnWrap().Mkdir(context.Background(), runInstance.encryptRemoteIfNeeded(t, "test/second")) 510 srcObj := runInstance.writeObjectBytes(t, cfs.UnWrap(), srcName, testData) 511 512 // list in mount 513 _, err = runInstance.list(t, rootFs, "test") 514 require.NoError(t, err) 515 _, err = runInstance.list(t, rootFs, "test/one") 516 require.NoError(t, err) 517 518 // move file 519 _, err = cfs.UnWrap().Features().Move(context.Background(), srcObj, dstName) 520 require.NoError(t, err) 521 522 err = runInstance.retryBlock(func() error { 523 li, err := runInstance.list(t, rootFs, "test") 524 if err != nil { 525 log.Printf("err: %v", err) 526 return err 527 } 528 if len(li) != 2 { 529 log.Printf("not expected listing /test: %v", li) 530 return errors.Errorf("not expected listing /test: %v", li) 531 } 532 533 li, err = runInstance.list(t, rootFs, "test/one") 534 if err != nil { 535 log.Printf("err: %v", err) 536 return err 537 } 538 if len(li) != 0 { 539 log.Printf("not expected listing /test/one: %v", li) 540 return errors.Errorf("not expected listing /test/one: %v", li) 541 } 542 543 li, err = runInstance.list(t, rootFs, "test/second") 544 if err != nil { 545 log.Printf("err: %v", err) 546 return err 547 } 548 if len(li) != 1 { 549 log.Printf("not expected listing /test/second: %v", li) 550 return errors.Errorf("not expected listing /test/second: %v", li) 551 } 552 if fi, ok := li[0].(os.FileInfo); ok { 553 if fi.Name() != "data.bin" { 554 log.Printf("not expected name: %v", fi.Name()) 555 return errors.Errorf("not expected name: %v", fi.Name()) 556 } 557 } else if di, ok := li[0].(fs.DirEntry); ok { 558 if di.Remote() != "test/second/data.bin" { 559 log.Printf("not expected remote: %v", di.Remote()) 560 return errors.Errorf("not expected remote: %v", di.Remote()) 561 } 562 } else { 563 log.Printf("unexpected listing: %v", li) 564 return errors.Errorf("unexpected listing: %v", li) 565 } 566 567 log.Printf("complete listing: %v", li) 568 return nil 569 }, 12, time.Second*10) 570 require.NoError(t, err) 571 } 572 573 func TestInternalNotifyCreatesEmptyParts(t *testing.T) { 574 id := fmt.Sprintf("tincep%v", time.Now().Unix()) 575 rootFs, boltDb := runInstance.newCacheFs(t, remoteName, id, false, true, nil, nil) 576 defer runInstance.cleanupFs(t, rootFs, boltDb) 577 if !runInstance.wrappedIsExternal { 578 t.Skipf("Not external") 579 } 580 cfs, err := runInstance.getCacheFs(rootFs) 581 require.NoError(t, err) 582 583 srcName := runInstance.encryptRemoteIfNeeded(t, "test") + "/" + runInstance.encryptRemoteIfNeeded(t, "one") + "/" + runInstance.encryptRemoteIfNeeded(t, "test") 584 dstName := runInstance.encryptRemoteIfNeeded(t, "test") + "/" + runInstance.encryptRemoteIfNeeded(t, "one") + "/" + runInstance.encryptRemoteIfNeeded(t, "test2") 585 // create some rand test data 586 var testData []byte 587 if runInstance.rootIsCrypt { 588 testData, err = base64.StdEncoding.DecodeString(cryptedTextBase64) 589 require.NoError(t, err) 590 } else { 591 testData = []byte("test content") 592 } 593 err = rootFs.Mkdir(context.Background(), "test") 594 require.NoError(t, err) 595 err = rootFs.Mkdir(context.Background(), "test/one") 596 require.NoError(t, err) 597 srcObj := runInstance.writeObjectBytes(t, cfs.UnWrap(), srcName, testData) 598 599 // list in mount 600 _, err = runInstance.list(t, rootFs, "test") 601 require.NoError(t, err) 602 _, err = runInstance.list(t, rootFs, "test/one") 603 require.NoError(t, err) 604 605 found := boltDb.HasEntry(path.Join(cfs.Root(), runInstance.encryptRemoteIfNeeded(t, "test"))) 606 require.True(t, found) 607 boltDb.Purge() 608 found = boltDb.HasEntry(path.Join(cfs.Root(), runInstance.encryptRemoteIfNeeded(t, "test"))) 609 require.False(t, found) 610 611 // move file 612 _, err = cfs.UnWrap().Features().Move(context.Background(), srcObj, dstName) 613 require.NoError(t, err) 614 615 err = runInstance.retryBlock(func() error { 616 found = boltDb.HasEntry(path.Join(cfs.Root(), runInstance.encryptRemoteIfNeeded(t, "test"))) 617 if !found { 618 log.Printf("not found /test") 619 return errors.Errorf("not found /test") 620 } 621 found = boltDb.HasEntry(path.Join(cfs.Root(), runInstance.encryptRemoteIfNeeded(t, "test"), runInstance.encryptRemoteIfNeeded(t, "one"))) 622 if !found { 623 log.Printf("not found /test/one") 624 return errors.Errorf("not found /test/one") 625 } 626 found = boltDb.HasEntry(path.Join(cfs.Root(), runInstance.encryptRemoteIfNeeded(t, "test"), runInstance.encryptRemoteIfNeeded(t, "one"), runInstance.encryptRemoteIfNeeded(t, "test2"))) 627 if !found { 628 log.Printf("not found /test/one/test2") 629 return errors.Errorf("not found /test/one/test2") 630 } 631 li, err := runInstance.list(t, rootFs, "test/one") 632 if err != nil { 633 log.Printf("err: %v", err) 634 return err 635 } 636 if len(li) != 1 { 637 log.Printf("not expected listing /test/one: %v", li) 638 return errors.Errorf("not expected listing /test/one: %v", li) 639 } 640 if fi, ok := li[0].(os.FileInfo); ok { 641 if fi.Name() != "test2" { 642 log.Printf("not expected name: %v", fi.Name()) 643 return errors.Errorf("not expected name: %v", fi.Name()) 644 } 645 } else if di, ok := li[0].(fs.DirEntry); ok { 646 if di.Remote() != "test/one/test2" { 647 log.Printf("not expected remote: %v", di.Remote()) 648 return errors.Errorf("not expected remote: %v", di.Remote()) 649 } 650 } else { 651 log.Printf("unexpected listing: %v", li) 652 return errors.Errorf("unexpected listing: %v", li) 653 } 654 log.Printf("complete listing /test/one/test2") 655 return nil 656 }, 12, time.Second*10) 657 require.NoError(t, err) 658 } 659 660 func TestInternalChangeSeenAfterDirCacheFlush(t *testing.T) { 661 id := fmt.Sprintf("ticsadcf%v", time.Now().Unix()) 662 rootFs, boltDb := runInstance.newCacheFs(t, remoteName, id, false, true, nil, nil) 663 defer runInstance.cleanupFs(t, rootFs, boltDb) 664 665 cfs, err := runInstance.getCacheFs(rootFs) 666 require.NoError(t, err) 667 chunkSize := cfs.ChunkSize() 668 669 // create some rand test data 670 testData := randStringBytes(int(chunkSize*4 + chunkSize/2)) 671 runInstance.writeRemoteBytes(t, rootFs, "data.bin", testData) 672 673 // update in the wrapped fs 674 o, err := cfs.UnWrap().NewObject(context.Background(), runInstance.encryptRemoteIfNeeded(t, "data.bin")) 675 require.NoError(t, err) 676 wrappedTime := time.Now().Add(-1 * time.Hour) 677 err = o.SetModTime(context.Background(), wrappedTime) 678 require.NoError(t, err) 679 680 // get a new instance from the cache 681 co, err := rootFs.NewObject(context.Background(), "data.bin") 682 require.NoError(t, err) 683 require.NotEqual(t, o.ModTime(context.Background()).String(), co.ModTime(context.Background()).String()) 684 685 cfs.DirCacheFlush() // flush the cache 686 687 // get a new instance from the cache 688 co, err = rootFs.NewObject(context.Background(), "data.bin") 689 require.NoError(t, err) 690 require.Equal(t, wrappedTime.Unix(), co.ModTime(context.Background()).Unix()) 691 } 692 693 func TestInternalChangeSeenAfterRc(t *testing.T) { 694 cacheExpire := rc.Calls.Get("cache/expire") 695 assert.NotNil(t, cacheExpire) 696 697 id := fmt.Sprintf("ticsarc%v", time.Now().Unix()) 698 rootFs, boltDb := runInstance.newCacheFs(t, remoteName, id, false, true, nil, nil) 699 defer runInstance.cleanupFs(t, rootFs, boltDb) 700 701 if !runInstance.useMount { 702 t.Skipf("needs mount") 703 } 704 if !runInstance.wrappedIsExternal { 705 t.Skipf("needs drive") 706 } 707 708 cfs, err := runInstance.getCacheFs(rootFs) 709 require.NoError(t, err) 710 chunkSize := cfs.ChunkSize() 711 712 // create some rand test data 713 testData := randStringBytes(int(chunkSize*4 + chunkSize/2)) 714 runInstance.writeRemoteBytes(t, rootFs, "data.bin", testData) 715 716 // update in the wrapped fs 717 o, err := cfs.UnWrap().NewObject(context.Background(), runInstance.encryptRemoteIfNeeded(t, "data.bin")) 718 require.NoError(t, err) 719 wrappedTime := time.Now().Add(-1 * time.Hour) 720 err = o.SetModTime(context.Background(), wrappedTime) 721 require.NoError(t, err) 722 723 // get a new instance from the cache 724 co, err := rootFs.NewObject(context.Background(), "data.bin") 725 require.NoError(t, err) 726 require.NotEqual(t, o.ModTime(context.Background()).String(), co.ModTime(context.Background()).String()) 727 728 // Call the rc function 729 m, err := cacheExpire.Fn(context.Background(), rc.Params{"remote": "data.bin"}) 730 require.NoError(t, err) 731 require.Contains(t, m, "status") 732 require.Contains(t, m, "message") 733 require.Equal(t, "ok", m["status"]) 734 require.Contains(t, m["message"], "cached file cleared") 735 736 // get a new instance from the cache 737 co, err = rootFs.NewObject(context.Background(), "data.bin") 738 require.NoError(t, err) 739 require.Equal(t, wrappedTime.Unix(), co.ModTime(context.Background()).Unix()) 740 _, err = runInstance.list(t, rootFs, "") 741 require.NoError(t, err) 742 743 // create some rand test data 744 testData2 := randStringBytes(int(chunkSize)) 745 runInstance.writeObjectBytes(t, cfs.UnWrap(), runInstance.encryptRemoteIfNeeded(t, "test2"), testData2) 746 747 // list should have 1 item only 748 li1, err := runInstance.list(t, rootFs, "") 749 require.NoError(t, err) 750 require.Len(t, li1, 1) 751 752 // Call the rc function 753 m, err = cacheExpire.Fn(context.Background(), rc.Params{"remote": "/"}) 754 require.NoError(t, err) 755 require.Contains(t, m, "status") 756 require.Contains(t, m, "message") 757 require.Equal(t, "ok", m["status"]) 758 require.Contains(t, m["message"], "cached directory cleared") 759 760 // list should have 2 items now 761 li2, err := runInstance.list(t, rootFs, "") 762 require.NoError(t, err) 763 require.Len(t, li2, 2) 764 } 765 766 func TestInternalCacheWrites(t *testing.T) { 767 id := "ticw" 768 rootFs, boltDb := runInstance.newCacheFs(t, remoteName, id, false, true, nil, map[string]string{"writes": "true"}) 769 defer runInstance.cleanupFs(t, rootFs, boltDb) 770 771 cfs, err := runInstance.getCacheFs(rootFs) 772 require.NoError(t, err) 773 chunkSize := cfs.ChunkSize() 774 775 // create some rand test data 776 earliestTime := time.Now() 777 testData := randStringBytes(int(chunkSize*4 + chunkSize/2)) 778 runInstance.writeRemoteBytes(t, rootFs, "data.bin", testData) 779 expectedTs := time.Now() 780 ts, err := boltDb.GetChunkTs(runInstance.encryptRemoteIfNeeded(t, path.Join(rootFs.Root(), "data.bin")), 0) 781 require.NoError(t, err) 782 require.WithinDuration(t, expectedTs, ts, expectedTs.Sub(earliestTime)) 783 } 784 785 func TestInternalMaxChunkSizeRespected(t *testing.T) { 786 id := fmt.Sprintf("timcsr%v", time.Now().Unix()) 787 rootFs, boltDb := runInstance.newCacheFs(t, remoteName, id, false, true, nil, map[string]string{"workers": "1"}) 788 defer runInstance.cleanupFs(t, rootFs, boltDb) 789 790 cfs, err := runInstance.getCacheFs(rootFs) 791 require.NoError(t, err) 792 chunkSize := cfs.ChunkSize() 793 totalChunks := 20 794 795 // create some rand test data 796 testData := randStringBytes(int(int64(totalChunks-1)*chunkSize + chunkSize/2)) 797 runInstance.writeRemoteBytes(t, rootFs, "data.bin", testData) 798 o, err := cfs.NewObject(context.Background(), runInstance.encryptRemoteIfNeeded(t, "data.bin")) 799 require.NoError(t, err) 800 co, ok := o.(*cache.Object) 801 require.True(t, ok) 802 803 for i := 0; i < 4; i++ { // read first 4 804 _ = runInstance.readDataFromObj(t, co, chunkSize*int64(i), chunkSize*int64(i+1), false) 805 } 806 cfs.CleanUpCache(true) 807 // the last 2 **must** be in the cache 808 require.True(t, boltDb.HasChunk(co, chunkSize*2)) 809 require.True(t, boltDb.HasChunk(co, chunkSize*3)) 810 811 for i := 4; i < 6; i++ { // read next 2 812 _ = runInstance.readDataFromObj(t, co, chunkSize*int64(i), chunkSize*int64(i+1), false) 813 } 814 cfs.CleanUpCache(true) 815 // the last 2 **must** be in the cache 816 require.True(t, boltDb.HasChunk(co, chunkSize*4)) 817 require.True(t, boltDb.HasChunk(co, chunkSize*5)) 818 } 819 820 func TestInternalExpiredEntriesRemoved(t *testing.T) { 821 id := fmt.Sprintf("tieer%v", time.Now().Unix()) 822 vfsflags.Opt.DirCacheTime = time.Second * 4 // needs to be lower than the defined 823 rootFs, boltDb := runInstance.newCacheFs(t, remoteName, id, true, true, map[string]string{"info_age": "5s"}, nil) 824 defer runInstance.cleanupFs(t, rootFs, boltDb) 825 cfs, err := runInstance.getCacheFs(rootFs) 826 require.NoError(t, err) 827 828 // create some rand test data 829 runInstance.writeRemoteString(t, rootFs, "one", "one content") 830 runInstance.mkdir(t, rootFs, "test") 831 runInstance.writeRemoteString(t, rootFs, "test/second", "second content") 832 833 l, err := runInstance.list(t, rootFs, "test") 834 require.NoError(t, err) 835 require.Len(t, l, 1) 836 837 err = cfs.UnWrap().Mkdir(context.Background(), runInstance.encryptRemoteIfNeeded(t, "test/third")) 838 require.NoError(t, err) 839 840 l, err = runInstance.list(t, rootFs, "test") 841 require.NoError(t, err) 842 require.Len(t, l, 1) 843 844 err = runInstance.retryBlock(func() error { 845 l, err = runInstance.list(t, rootFs, "test") 846 if err != nil { 847 return err 848 } 849 if len(l) != 2 { 850 return errors.New("list is not 2") 851 } 852 return nil 853 }, 10, time.Second) 854 require.NoError(t, err) 855 } 856 857 func TestInternalBug2117(t *testing.T) { 858 vfsflags.Opt.DirCacheTime = time.Second * 10 859 860 id := fmt.Sprintf("tib2117%v", time.Now().Unix()) 861 rootFs, boltDb := runInstance.newCacheFs(t, remoteName, id, false, true, nil, 862 map[string]string{"info_age": "72h", "chunk_clean_interval": "15m"}) 863 defer runInstance.cleanupFs(t, rootFs, boltDb) 864 865 if runInstance.rootIsCrypt { 866 t.Skipf("skipping crypt") 867 } 868 869 cfs, err := runInstance.getCacheFs(rootFs) 870 require.NoError(t, err) 871 872 err = cfs.UnWrap().Mkdir(context.Background(), "test") 873 require.NoError(t, err) 874 for i := 1; i <= 4; i++ { 875 err = cfs.UnWrap().Mkdir(context.Background(), fmt.Sprintf("test/dir%d", i)) 876 require.NoError(t, err) 877 878 for j := 1; j <= 4; j++ { 879 err = cfs.UnWrap().Mkdir(context.Background(), fmt.Sprintf("test/dir%d/dir%d", i, j)) 880 require.NoError(t, err) 881 882 runInstance.writeObjectString(t, cfs.UnWrap(), fmt.Sprintf("test/dir%d/dir%d/test.txt", i, j), "test") 883 } 884 } 885 886 di, err := runInstance.list(t, rootFs, "test/dir1/dir2") 887 require.NoError(t, err) 888 log.Printf("len: %v", len(di)) 889 require.Len(t, di, 1) 890 891 time.Sleep(time.Second * 30) 892 893 di, err = runInstance.list(t, rootFs, "test/dir1/dir2") 894 require.NoError(t, err) 895 log.Printf("len: %v", len(di)) 896 require.Len(t, di, 1) 897 898 di, err = runInstance.list(t, rootFs, "test/dir1") 899 require.NoError(t, err) 900 log.Printf("len: %v", len(di)) 901 require.Len(t, di, 4) 902 903 di, err = runInstance.list(t, rootFs, "test") 904 require.NoError(t, err) 905 log.Printf("len: %v", len(di)) 906 require.Len(t, di, 4) 907 } 908 909 // run holds the remotes for a test run 910 type run struct { 911 okDiff time.Duration 912 runDefaultCfgMap configmap.Simple 913 mntDir string 914 tmpUploadDir string 915 useMount bool 916 isMounted bool 917 rootIsCrypt bool 918 wrappedIsExternal bool 919 unmountFn func() error 920 unmountRes chan error 921 vfs *vfs.VFS 922 tempFiles []*os.File 923 dbPath string 924 chunkPath string 925 vfsCachePath string 926 } 927 928 func newRun() *run { 929 var err error 930 r := &run{ 931 okDiff: time.Second * 9, // really big diff here but the build machines seem to be slow. need a different way for this 932 useMount: useMount, 933 isMounted: false, 934 } 935 936 // Read in all the defaults for all the options 937 fsInfo, err := fs.Find("cache") 938 if err != nil { 939 panic(fmt.Sprintf("Couldn't find cache remote: %v", err)) 940 } 941 r.runDefaultCfgMap = configmap.Simple{} 942 for _, option := range fsInfo.Options { 943 r.runDefaultCfgMap.Set(option.Name, fmt.Sprint(option.Default)) 944 } 945 946 if mountDir == "" { 947 if runtime.GOOS != "windows" { 948 r.mntDir, err = ioutil.TempDir("", "rclonecache-mount") 949 if err != nil { 950 log.Fatalf("Failed to create mount dir: %v", err) 951 return nil 952 } 953 } else { 954 // Find a free drive letter 955 drive := "" 956 for letter := 'E'; letter <= 'Z'; letter++ { 957 drive = string(letter) + ":" 958 _, err := os.Stat(drive + "\\") 959 if os.IsNotExist(err) { 960 goto found 961 } 962 } 963 log.Print("Couldn't find free drive letter for test") 964 found: 965 r.mntDir = drive 966 } 967 } else { 968 r.mntDir = mountDir 969 } 970 log.Printf("Mount Dir: %v", r.mntDir) 971 972 if uploadDir == "" { 973 r.tmpUploadDir, err = ioutil.TempDir("", "rclonecache-tmp") 974 if err != nil { 975 log.Fatalf("Failed to create temp dir: %v", err) 976 } 977 } else { 978 r.tmpUploadDir = uploadDir 979 } 980 log.Printf("Temp Upload Dir: %v", r.tmpUploadDir) 981 982 return r 983 } 984 985 func (r *run) encryptRemoteIfNeeded(t *testing.T, remote string) string { 986 if !runInstance.rootIsCrypt || len(decryptedToEncryptedRemotes) == 0 { 987 return remote 988 } 989 990 enc, ok := decryptedToEncryptedRemotes[remote] 991 if !ok { 992 t.Fatalf("Failed to find decrypted -> encrypted mapping for '%v'", remote) 993 return remote 994 } 995 return enc 996 } 997 998 func (r *run) newCacheFs(t *testing.T, remote, id string, needRemote, purge bool, cfg map[string]string, flags map[string]string) (fs.Fs, *cache.Persistent) { 999 fstest.Initialise() 1000 remoteExists := false 1001 for _, s := range config.FileSections() { 1002 if s == remote { 1003 remoteExists = true 1004 } 1005 } 1006 if !remoteExists && needRemote { 1007 t.Skipf("Need remote (%v) to exist", remote) 1008 return nil, nil 1009 } 1010 1011 // if the remote doesn't exist, create a new one with a local one for it 1012 // identify which is the cache remote (it can be wrapped by a crypt too) 1013 rootIsCrypt := false 1014 cacheRemote := remote 1015 if !remoteExists { 1016 localRemote := remote + "-local" 1017 config.FileSet(localRemote, "type", "local") 1018 config.FileSet(localRemote, "nounc", "true") 1019 config.FileSet(remote, "type", "cache") 1020 config.FileSet(remote, "remote", localRemote+":/var/tmp/"+localRemote) 1021 } else { 1022 remoteType := config.FileGet(remote, "type", "") 1023 if remoteType == "" { 1024 t.Skipf("skipped due to invalid remote type for %v", remote) 1025 return nil, nil 1026 } 1027 if remoteType != "cache" { 1028 if remoteType == "crypt" { 1029 rootIsCrypt = true 1030 config.FileSet(remote, "password", cryptPassword1) 1031 config.FileSet(remote, "password2", cryptPassword2) 1032 } 1033 remoteRemote := config.FileGet(remote, "remote", "") 1034 if remoteRemote == "" { 1035 t.Skipf("skipped due to invalid remote wrapper for %v", remote) 1036 return nil, nil 1037 } 1038 remoteRemoteParts := strings.Split(remoteRemote, ":") 1039 remoteWrapping := remoteRemoteParts[0] 1040 remoteType := config.FileGet(remoteWrapping, "type", "") 1041 if remoteType != "cache" { 1042 t.Skipf("skipped due to invalid remote type for %v: '%v'", remoteWrapping, remoteType) 1043 return nil, nil 1044 } 1045 cacheRemote = remoteWrapping 1046 } 1047 } 1048 runInstance.rootIsCrypt = rootIsCrypt 1049 runInstance.dbPath = filepath.Join(config.CacheDir, "cache-backend", cacheRemote+".db") 1050 runInstance.chunkPath = filepath.Join(config.CacheDir, "cache-backend", cacheRemote) 1051 runInstance.vfsCachePath = filepath.Join(config.CacheDir, "vfs", remote) 1052 boltDb, err := cache.GetPersistent(runInstance.dbPath, runInstance.chunkPath, &cache.Features{PurgeDb: true}) 1053 require.NoError(t, err) 1054 1055 fs.Config.LowLevelRetries = 1 1056 1057 m := configmap.Simple{} 1058 for k, v := range r.runDefaultCfgMap { 1059 m.Set(k, v) 1060 } 1061 for k, v := range flags { 1062 m.Set(k, v) 1063 } 1064 1065 // Instantiate root 1066 if purge { 1067 boltDb.PurgeTempUploads() 1068 _ = os.RemoveAll(path.Join(runInstance.tmpUploadDir, id)) 1069 } 1070 f, err := cache.NewFs(remote, id, m) 1071 require.NoError(t, err) 1072 cfs, err := r.getCacheFs(f) 1073 require.NoError(t, err) 1074 _, isCache := cfs.Features().UnWrap().(*cache.Fs) 1075 _, isCrypt := cfs.Features().UnWrap().(*crypt.Fs) 1076 _, isLocal := cfs.Features().UnWrap().(*local.Fs) 1077 if isCache || isCrypt || isLocal { 1078 r.wrappedIsExternal = false 1079 } else { 1080 r.wrappedIsExternal = true 1081 } 1082 1083 if purge { 1084 _ = f.Features().Purge(context.Background()) 1085 require.NoError(t, err) 1086 } 1087 err = f.Mkdir(context.Background(), "") 1088 require.NoError(t, err) 1089 if r.useMount && !r.isMounted { 1090 r.mountFs(t, f) 1091 } 1092 1093 return f, boltDb 1094 } 1095 1096 func (r *run) cleanupFs(t *testing.T, f fs.Fs, b *cache.Persistent) { 1097 if r.useMount && r.isMounted { 1098 r.unmountFs(t, f) 1099 } 1100 1101 err := f.Features().Purge(context.Background()) 1102 require.NoError(t, err) 1103 cfs, err := r.getCacheFs(f) 1104 require.NoError(t, err) 1105 cfs.StopBackgroundRunners() 1106 1107 if r.useMount && runtime.GOOS != "windows" { 1108 err = os.RemoveAll(r.mntDir) 1109 require.NoError(t, err) 1110 } 1111 err = os.RemoveAll(r.tmpUploadDir) 1112 require.NoError(t, err) 1113 1114 for _, f := range r.tempFiles { 1115 _ = f.Close() 1116 _ = os.Remove(f.Name()) 1117 } 1118 r.tempFiles = nil 1119 debug.FreeOSMemory() 1120 } 1121 1122 func (r *run) randomReader(t *testing.T, size int64) io.ReadCloser { 1123 chunk := int64(1024) 1124 cnt := size / chunk 1125 left := size % chunk 1126 f, err := ioutil.TempFile("", "rclonecache-tempfile") 1127 require.NoError(t, err) 1128 1129 for i := 0; i < int(cnt); i++ { 1130 data := randStringBytes(int(chunk)) 1131 _, _ = f.Write(data) 1132 } 1133 data := randStringBytes(int(left)) 1134 _, _ = f.Write(data) 1135 _, _ = f.Seek(int64(0), io.SeekStart) 1136 r.tempFiles = append(r.tempFiles, f) 1137 1138 return f 1139 } 1140 1141 func (r *run) writeRemoteRandomBytes(t *testing.T, f fs.Fs, p string, size int64) string { 1142 remote := path.Join(p, strconv.Itoa(rand.Int())+".bin") 1143 // create some rand test data 1144 testData := randStringBytes(int(size)) 1145 1146 r.writeRemoteBytes(t, f, remote, testData) 1147 return remote 1148 } 1149 1150 func (r *run) writeObjectRandomBytes(t *testing.T, f fs.Fs, p string, size int64) fs.Object { 1151 remote := path.Join(p, strconv.Itoa(rand.Int())+".bin") 1152 // create some rand test data 1153 testData := randStringBytes(int(size)) 1154 1155 return r.writeObjectBytes(t, f, remote, testData) 1156 } 1157 1158 func (r *run) writeRemoteString(t *testing.T, f fs.Fs, remote, content string) { 1159 r.writeRemoteBytes(t, f, remote, []byte(content)) 1160 } 1161 1162 func (r *run) writeObjectString(t *testing.T, f fs.Fs, remote, content string) fs.Object { 1163 return r.writeObjectBytes(t, f, remote, []byte(content)) 1164 } 1165 1166 func (r *run) writeRemoteBytes(t *testing.T, f fs.Fs, remote string, data []byte) { 1167 var err error 1168 1169 if r.useMount { 1170 err = r.retryBlock(func() error { 1171 return ioutil.WriteFile(path.Join(r.mntDir, remote), data, 0600) 1172 }, 3, time.Second*3) 1173 require.NoError(t, err) 1174 r.vfs.WaitForWriters(10 * time.Second) 1175 } else { 1176 r.writeObjectBytes(t, f, remote, data) 1177 } 1178 } 1179 1180 func (r *run) writeRemoteReader(t *testing.T, f fs.Fs, remote string, in io.ReadCloser) { 1181 defer func() { 1182 _ = in.Close() 1183 }() 1184 1185 if r.useMount { 1186 out, err := os.Create(path.Join(r.mntDir, remote)) 1187 require.NoError(t, err) 1188 defer func() { 1189 _ = out.Close() 1190 }() 1191 1192 _, err = io.Copy(out, in) 1193 require.NoError(t, err) 1194 r.vfs.WaitForWriters(10 * time.Second) 1195 } else { 1196 r.writeObjectReader(t, f, remote, in) 1197 } 1198 } 1199 1200 func (r *run) writeObjectBytes(t *testing.T, f fs.Fs, remote string, data []byte) fs.Object { 1201 in := bytes.NewReader(data) 1202 _ = r.writeObjectReader(t, f, remote, in) 1203 o, err := f.NewObject(context.Background(), remote) 1204 require.NoError(t, err) 1205 require.Equal(t, int64(len(data)), o.Size()) 1206 return o 1207 } 1208 1209 func (r *run) writeObjectReader(t *testing.T, f fs.Fs, remote string, in io.Reader) fs.Object { 1210 modTime := time.Now() 1211 objInfo := object.NewStaticObjectInfo(remote, modTime, -1, true, nil, f) 1212 obj, err := f.Put(context.Background(), in, objInfo) 1213 require.NoError(t, err) 1214 if r.useMount { 1215 r.vfs.WaitForWriters(10 * time.Second) 1216 } 1217 1218 return obj 1219 } 1220 1221 func (r *run) updateObjectRemote(t *testing.T, f fs.Fs, remote string, data1 []byte, data2 []byte) fs.Object { 1222 var err error 1223 var obj fs.Object 1224 1225 if r.useMount { 1226 err = ioutil.WriteFile(path.Join(r.mntDir, remote), data1, 0600) 1227 require.NoError(t, err) 1228 r.vfs.WaitForWriters(10 * time.Second) 1229 err = ioutil.WriteFile(path.Join(r.mntDir, remote), data2, 0600) 1230 require.NoError(t, err) 1231 r.vfs.WaitForWriters(10 * time.Second) 1232 obj, err = f.NewObject(context.Background(), remote) 1233 } else { 1234 in1 := bytes.NewReader(data1) 1235 in2 := bytes.NewReader(data2) 1236 objInfo1 := object.NewStaticObjectInfo(remote, time.Now(), int64(len(data1)), true, nil, f) 1237 objInfo2 := object.NewStaticObjectInfo(remote, time.Now(), int64(len(data2)), true, nil, f) 1238 1239 obj, err = f.Put(context.Background(), in1, objInfo1) 1240 require.NoError(t, err) 1241 obj, err = f.NewObject(context.Background(), remote) 1242 require.NoError(t, err) 1243 err = obj.Update(context.Background(), in2, objInfo2) 1244 } 1245 require.NoError(t, err) 1246 1247 return obj 1248 } 1249 1250 func (r *run) readDataFromRemote(t *testing.T, f fs.Fs, remote string, offset, end int64, noLengthCheck bool) ([]byte, error) { 1251 size := end - offset 1252 checkSample := make([]byte, size) 1253 1254 if r.useMount { 1255 f, err := os.Open(path.Join(r.mntDir, remote)) 1256 defer func() { 1257 _ = f.Close() 1258 }() 1259 if err != nil { 1260 return checkSample, err 1261 } 1262 _, _ = f.Seek(offset, io.SeekStart) 1263 totalRead, err := io.ReadFull(f, checkSample) 1264 checkSample = checkSample[:totalRead] 1265 if err == io.EOF || err == io.ErrUnexpectedEOF { 1266 err = nil 1267 } 1268 if err != nil { 1269 return checkSample, err 1270 } 1271 } else { 1272 co, err := f.NewObject(context.Background(), remote) 1273 if err != nil { 1274 return checkSample, err 1275 } 1276 checkSample = r.readDataFromObj(t, co, offset, end, noLengthCheck) 1277 } 1278 if !noLengthCheck && size != int64(len(checkSample)) { 1279 return checkSample, errors.Errorf("read size doesn't match expected: %v <> %v", len(checkSample), size) 1280 } 1281 return checkSample, nil 1282 } 1283 1284 func (r *run) readDataFromObj(t *testing.T, o fs.Object, offset, end int64, noLengthCheck bool) []byte { 1285 size := end - offset 1286 checkSample := make([]byte, size) 1287 reader, err := o.Open(context.Background(), &fs.SeekOption{Offset: offset}) 1288 require.NoError(t, err) 1289 totalRead, err := io.ReadFull(reader, checkSample) 1290 if (err == io.EOF || err == io.ErrUnexpectedEOF) && noLengthCheck { 1291 err = nil 1292 checkSample = checkSample[:totalRead] 1293 } 1294 require.NoError(t, err, "with string -%v-", string(checkSample)) 1295 _ = reader.Close() 1296 return checkSample 1297 } 1298 1299 func (r *run) mkdir(t *testing.T, f fs.Fs, remote string) { 1300 var err error 1301 if r.useMount { 1302 err = os.Mkdir(path.Join(r.mntDir, remote), 0700) 1303 } else { 1304 err = f.Mkdir(context.Background(), remote) 1305 } 1306 require.NoError(t, err) 1307 } 1308 1309 func (r *run) rm(t *testing.T, f fs.Fs, remote string) error { 1310 var err error 1311 1312 if r.useMount { 1313 err = os.Remove(path.Join(r.mntDir, remote)) 1314 } else { 1315 var obj fs.Object 1316 obj, err = f.NewObject(context.Background(), remote) 1317 if err != nil { 1318 err = f.Rmdir(context.Background(), remote) 1319 } else { 1320 err = obj.Remove(context.Background()) 1321 } 1322 } 1323 1324 return err 1325 } 1326 1327 func (r *run) list(t *testing.T, f fs.Fs, remote string) ([]interface{}, error) { 1328 var err error 1329 var l []interface{} 1330 if r.useMount { 1331 var list []os.FileInfo 1332 list, err = ioutil.ReadDir(path.Join(r.mntDir, remote)) 1333 for _, ll := range list { 1334 l = append(l, ll) 1335 } 1336 } else { 1337 var list fs.DirEntries 1338 list, err = f.List(context.Background(), remote) 1339 for _, ll := range list { 1340 l = append(l, ll) 1341 } 1342 } 1343 return l, err 1344 } 1345 1346 func (r *run) listPath(t *testing.T, f fs.Fs, remote string) []string { 1347 var err error 1348 var l []string 1349 if r.useMount { 1350 var list []os.FileInfo 1351 list, err = ioutil.ReadDir(path.Join(r.mntDir, remote)) 1352 for _, ll := range list { 1353 l = append(l, ll.Name()) 1354 } 1355 } else { 1356 var list fs.DirEntries 1357 list, err = f.List(context.Background(), remote) 1358 for _, ll := range list { 1359 l = append(l, ll.Remote()) 1360 } 1361 } 1362 require.NoError(t, err) 1363 return l 1364 } 1365 1366 func (r *run) copyFile(t *testing.T, f fs.Fs, src, dst string) error { 1367 in, err := os.Open(src) 1368 if err != nil { 1369 return err 1370 } 1371 defer func() { 1372 _ = in.Close() 1373 }() 1374 1375 out, err := os.Create(dst) 1376 if err != nil { 1377 return err 1378 } 1379 defer func() { 1380 _ = out.Close() 1381 }() 1382 1383 _, err = io.Copy(out, in) 1384 return err 1385 } 1386 1387 func (r *run) dirMove(t *testing.T, rootFs fs.Fs, src, dst string) error { 1388 var err error 1389 1390 if runInstance.useMount { 1391 err = os.Rename(path.Join(runInstance.mntDir, src), path.Join(runInstance.mntDir, dst)) 1392 if err != nil { 1393 return err 1394 } 1395 r.vfs.WaitForWriters(10 * time.Second) 1396 } else if rootFs.Features().DirMove != nil { 1397 err = rootFs.Features().DirMove(context.Background(), rootFs, src, dst) 1398 if err != nil { 1399 return err 1400 } 1401 } else { 1402 t.Logf("DirMove not supported by %v", rootFs) 1403 return errNotSupported 1404 } 1405 1406 return err 1407 } 1408 1409 func (r *run) move(t *testing.T, rootFs fs.Fs, src, dst string) error { 1410 var err error 1411 1412 if runInstance.useMount { 1413 err = os.Rename(path.Join(runInstance.mntDir, src), path.Join(runInstance.mntDir, dst)) 1414 if err != nil { 1415 return err 1416 } 1417 r.vfs.WaitForWriters(10 * time.Second) 1418 } else if rootFs.Features().Move != nil { 1419 obj1, err := rootFs.NewObject(context.Background(), src) 1420 if err != nil { 1421 return err 1422 } 1423 _, err = rootFs.Features().Move(context.Background(), obj1, dst) 1424 if err != nil { 1425 return err 1426 } 1427 } else { 1428 t.Logf("Move not supported by %v", rootFs) 1429 return errNotSupported 1430 } 1431 1432 return err 1433 } 1434 1435 func (r *run) copy(t *testing.T, rootFs fs.Fs, src, dst string) error { 1436 var err error 1437 1438 if r.useMount { 1439 err = r.copyFile(t, rootFs, path.Join(r.mntDir, src), path.Join(r.mntDir, dst)) 1440 if err != nil { 1441 return err 1442 } 1443 r.vfs.WaitForWriters(10 * time.Second) 1444 } else if rootFs.Features().Copy != nil { 1445 obj, err := rootFs.NewObject(context.Background(), src) 1446 if err != nil { 1447 return err 1448 } 1449 _, err = rootFs.Features().Copy(context.Background(), obj, dst) 1450 if err != nil { 1451 return err 1452 } 1453 } else { 1454 t.Logf("Copy not supported by %v", rootFs) 1455 return errNotSupported 1456 } 1457 1458 return err 1459 } 1460 1461 func (r *run) modTime(t *testing.T, rootFs fs.Fs, src string) (time.Time, error) { 1462 var err error 1463 1464 if r.useMount { 1465 fi, err := os.Stat(path.Join(runInstance.mntDir, src)) 1466 if err != nil { 1467 return time.Time{}, err 1468 } 1469 return fi.ModTime(), nil 1470 } 1471 obj1, err := rootFs.NewObject(context.Background(), src) 1472 if err != nil { 1473 return time.Time{}, err 1474 } 1475 return obj1.ModTime(context.Background()), nil 1476 } 1477 1478 func (r *run) size(t *testing.T, rootFs fs.Fs, src string) (int64, error) { 1479 var err error 1480 1481 if r.useMount { 1482 fi, err := os.Stat(path.Join(runInstance.mntDir, src)) 1483 if err != nil { 1484 return int64(0), err 1485 } 1486 return fi.Size(), nil 1487 } 1488 obj1, err := rootFs.NewObject(context.Background(), src) 1489 if err != nil { 1490 return int64(0), err 1491 } 1492 return obj1.Size(), nil 1493 } 1494 1495 func (r *run) updateData(t *testing.T, rootFs fs.Fs, src, data, append string) error { 1496 var err error 1497 1498 if r.useMount { 1499 var f *os.File 1500 f, err = os.OpenFile(path.Join(runInstance.mntDir, src), os.O_TRUNC|os.O_CREATE|os.O_WRONLY, 0644) 1501 if err != nil { 1502 return err 1503 } 1504 defer func() { 1505 _ = f.Close() 1506 r.vfs.WaitForWriters(10 * time.Second) 1507 }() 1508 _, err = f.WriteString(data + append) 1509 } else { 1510 var obj1 fs.Object 1511 obj1, err = rootFs.NewObject(context.Background(), src) 1512 if err != nil { 1513 return err 1514 } 1515 data1 := []byte(data + append) 1516 r := bytes.NewReader(data1) 1517 objInfo1 := object.NewStaticObjectInfo(src, time.Now(), int64(len(data1)), true, nil, rootFs) 1518 err = obj1.Update(context.Background(), r, objInfo1) 1519 } 1520 1521 return err 1522 } 1523 1524 func (r *run) cleanSize(t *testing.T, size int64) int64 { 1525 if r.rootIsCrypt { 1526 denominator := int64(65536 + 16) 1527 size = size - 32 1528 quotient := size / denominator 1529 remainder := size % denominator 1530 return (quotient*65536 + remainder - 16) 1531 } 1532 1533 return size 1534 } 1535 1536 func (r *run) listenForBackgroundUpload(t *testing.T, f fs.Fs, remote string) chan error { 1537 cfs, err := r.getCacheFs(f) 1538 require.NoError(t, err) 1539 buCh := cfs.GetBackgroundUploadChannel() 1540 require.NotNil(t, buCh) 1541 maxDuration := time.Minute * 3 1542 if r.wrappedIsExternal { 1543 maxDuration = time.Minute * 10 1544 } 1545 1546 waitCh := make(chan error) 1547 go func() { 1548 var err error 1549 var state cache.BackgroundUploadState 1550 1551 for i := 0; i < 2; i++ { 1552 select { 1553 case state = <-buCh: 1554 // continue 1555 case <-time.After(maxDuration): 1556 waitCh <- errors.Errorf("Timed out waiting for background upload: %v", remote) 1557 return 1558 } 1559 checkRemote := state.Remote 1560 if r.rootIsCrypt { 1561 cryptFs := f.(*crypt.Fs) 1562 checkRemote, err = cryptFs.DecryptFileName(checkRemote) 1563 if err != nil { 1564 waitCh <- err 1565 return 1566 } 1567 } 1568 if checkRemote == remote && cache.BackgroundUploadStarted != state.Status { 1569 waitCh <- state.Error 1570 return 1571 } 1572 } 1573 waitCh <- errors.Errorf("Too many attempts to wait for the background upload: %v", remote) 1574 }() 1575 return waitCh 1576 } 1577 1578 func (r *run) completeBackgroundUpload(t *testing.T, remote string, waitCh chan error) { 1579 var err error 1580 maxDuration := time.Minute * 3 1581 if r.wrappedIsExternal { 1582 maxDuration = time.Minute * 10 1583 } 1584 select { 1585 case err = <-waitCh: 1586 // continue 1587 case <-time.After(maxDuration): 1588 t.Fatalf("Timed out waiting to complete the background upload %v", remote) 1589 return 1590 } 1591 require.NoError(t, err) 1592 } 1593 1594 func (r *run) completeAllBackgroundUploads(t *testing.T, f fs.Fs, lastRemote string) { 1595 var state cache.BackgroundUploadState 1596 var err error 1597 1598 maxDuration := time.Minute * 5 1599 if r.wrappedIsExternal { 1600 maxDuration = time.Minute * 15 1601 } 1602 cfs, err := r.getCacheFs(f) 1603 require.NoError(t, err) 1604 buCh := cfs.GetBackgroundUploadChannel() 1605 require.NotNil(t, buCh) 1606 1607 for { 1608 select { 1609 case state = <-buCh: 1610 checkRemote := state.Remote 1611 if r.rootIsCrypt { 1612 cryptFs := f.(*crypt.Fs) 1613 checkRemote, err = cryptFs.DecryptFileName(checkRemote) 1614 require.NoError(t, err) 1615 } 1616 if checkRemote == lastRemote && cache.BackgroundUploadCompleted == state.Status { 1617 require.NoError(t, state.Error) 1618 return 1619 } 1620 case <-time.After(maxDuration): 1621 t.Fatalf("Timed out waiting to complete the background upload %v", lastRemote) 1622 return 1623 } 1624 } 1625 } 1626 1627 func (r *run) retryBlock(block func() error, maxRetries int, rate time.Duration) error { 1628 var err error 1629 for i := 0; i < maxRetries; i++ { 1630 err = block() 1631 if err == nil { 1632 return nil 1633 } 1634 time.Sleep(rate) 1635 } 1636 return err 1637 } 1638 1639 func (r *run) getCacheFs(f fs.Fs) (*cache.Fs, error) { 1640 cfs, ok := f.(*cache.Fs) 1641 if ok { 1642 return cfs, nil 1643 } 1644 if f.Features().UnWrap != nil { 1645 cfs, ok := f.Features().UnWrap().(*cache.Fs) 1646 if ok { 1647 return cfs, nil 1648 } 1649 } 1650 return nil, errors.New("didn't found a cache fs") 1651 } 1652 1653 func randStringBytes(n int) []byte { 1654 b := make([]byte, n) 1655 for i := range b { 1656 b[i] = letterBytes[rand.Intn(len(letterBytes))] 1657 } 1658 return b 1659 } 1660 1661 var ( 1662 _ fs.Fs = (*cache.Fs)(nil) 1663 _ fs.Fs = (*local.Fs)(nil) 1664 )