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