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  )