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