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