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