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  )