github.com/artpar/rclone@v1.67.3/backend/cache/cache_upload_test.go (about)

     1  //go:build !plan9 && !js && !race
     2  
     3  package cache_test
     4  
     5  import (
     6  	"context"
     7  	"fmt"
     8  	"math/rand"
     9  	"os"
    10  	"path"
    11  	"strconv"
    12  	"testing"
    13  	"time"
    14  
    15  	"github.com/artpar/rclone/backend/cache"
    16  	_ "github.com/artpar/rclone/backend/drive"
    17  	"github.com/artpar/rclone/fs"
    18  	"github.com/stretchr/testify/require"
    19  )
    20  
    21  func TestInternalUploadTempDirCreated(t *testing.T) {
    22  	id := fmt.Sprintf("tiutdc%v", time.Now().Unix())
    23  	runInstance.newCacheFs(t, remoteName, id, false, true,
    24  		map[string]string{"tmp_upload_path": path.Join(runInstance.tmpUploadDir, id)})
    25  
    26  	_, err := os.Stat(path.Join(runInstance.tmpUploadDir, id))
    27  	require.NoError(t, err)
    28  }
    29  
    30  func testInternalUploadQueueOneFile(t *testing.T, id string, rootFs fs.Fs, boltDb *cache.Persistent) {
    31  	// create some rand test data
    32  	testSize := int64(524288000)
    33  	testReader := runInstance.randomReader(t, testSize)
    34  	bu := runInstance.listenForBackgroundUpload(t, rootFs, "one")
    35  	runInstance.writeRemoteReader(t, rootFs, "one", testReader)
    36  	// validate that it exists in temp fs
    37  	ti, err := os.Stat(path.Join(runInstance.tmpUploadDir, id, runInstance.encryptRemoteIfNeeded(t, "one")))
    38  	require.NoError(t, err)
    39  
    40  	if runInstance.rootIsCrypt {
    41  		require.Equal(t, int64(524416032), ti.Size())
    42  	} else {
    43  		require.Equal(t, testSize, ti.Size())
    44  	}
    45  	de1, err := runInstance.list(t, rootFs, "")
    46  	require.NoError(t, err)
    47  	require.Len(t, de1, 1)
    48  
    49  	runInstance.completeBackgroundUpload(t, "one", bu)
    50  	// check if it was removed from temp fs
    51  	_, err = os.Stat(path.Join(runInstance.tmpUploadDir, id, runInstance.encryptRemoteIfNeeded(t, "one")))
    52  	require.True(t, os.IsNotExist(err))
    53  
    54  	// check if it can be read
    55  	data2, err := runInstance.readDataFromRemote(t, rootFs, "one", 0, int64(1024), false)
    56  	require.NoError(t, err)
    57  	require.Len(t, data2, 1024)
    58  }
    59  
    60  func TestInternalUploadQueueOneFileNoRest(t *testing.T) {
    61  	id := fmt.Sprintf("tiuqofnr%v", time.Now().Unix())
    62  	rootFs, boltDb := runInstance.newCacheFs(t, remoteName, id, true, true,
    63  		map[string]string{"tmp_upload_path": path.Join(runInstance.tmpUploadDir, id), "tmp_wait_time": "0s"})
    64  
    65  	testInternalUploadQueueOneFile(t, id, rootFs, boltDb)
    66  }
    67  
    68  func TestInternalUploadQueueOneFileWithRest(t *testing.T) {
    69  	id := fmt.Sprintf("tiuqofwr%v", time.Now().Unix())
    70  	rootFs, boltDb := runInstance.newCacheFs(t, remoteName, id, true, true,
    71  		map[string]string{"tmp_upload_path": path.Join(runInstance.tmpUploadDir, id), "tmp_wait_time": "1m"})
    72  
    73  	testInternalUploadQueueOneFile(t, id, rootFs, boltDb)
    74  }
    75  
    76  func TestInternalUploadMoveExistingFile(t *testing.T) {
    77  	id := fmt.Sprintf("tiumef%v", time.Now().Unix())
    78  	rootFs, _ := runInstance.newCacheFs(t, remoteName, id, true, true,
    79  		map[string]string{"tmp_upload_path": path.Join(runInstance.tmpUploadDir, id), "tmp_wait_time": "3s"})
    80  
    81  	err := rootFs.Mkdir(context.Background(), "one")
    82  	require.NoError(t, err)
    83  	err = rootFs.Mkdir(context.Background(), "one/test")
    84  	require.NoError(t, err)
    85  	err = rootFs.Mkdir(context.Background(), "second")
    86  	require.NoError(t, err)
    87  
    88  	// create some rand test data
    89  	testSize := int64(10485760)
    90  	testReader := runInstance.randomReader(t, testSize)
    91  	runInstance.writeObjectReader(t, rootFs, "one/test/data.bin", testReader)
    92  	runInstance.completeAllBackgroundUploads(t, rootFs, "one/test/data.bin")
    93  
    94  	de1, err := runInstance.list(t, rootFs, "one/test")
    95  	require.NoError(t, err)
    96  	require.Len(t, de1, 1)
    97  
    98  	time.Sleep(time.Second * 5)
    99  	//_ = os.Remove(path.Join(runInstance.tmpUploadDir, id, runInstance.encryptRemoteIfNeeded(t, "one/test")))
   100  	//require.NoError(t, err)
   101  
   102  	err = runInstance.dirMove(t, rootFs, "one/test", "second/test")
   103  	require.NoError(t, err)
   104  
   105  	// check if it can be read
   106  	de1, err = runInstance.list(t, rootFs, "second/test")
   107  	require.NoError(t, err)
   108  	require.Len(t, de1, 1)
   109  }
   110  
   111  func TestInternalUploadTempPathCleaned(t *testing.T) {
   112  	id := fmt.Sprintf("tiutpc%v", time.Now().Unix())
   113  	rootFs, _ := runInstance.newCacheFs(t, remoteName, id, true, true,
   114  		map[string]string{"cache-tmp-upload-path": path.Join(runInstance.tmpUploadDir, id), "cache-tmp-wait-time": "5s"})
   115  
   116  	err := rootFs.Mkdir(context.Background(), "one")
   117  	require.NoError(t, err)
   118  	err = rootFs.Mkdir(context.Background(), "one/test")
   119  	require.NoError(t, err)
   120  	err = rootFs.Mkdir(context.Background(), "second")
   121  	require.NoError(t, err)
   122  
   123  	// create some rand test data
   124  	testSize := int64(1048576)
   125  	testReader := runInstance.randomReader(t, testSize)
   126  	testReader2 := runInstance.randomReader(t, testSize)
   127  	runInstance.writeObjectReader(t, rootFs, "one/test/data.bin", testReader)
   128  	runInstance.writeObjectReader(t, rootFs, "second/data.bin", testReader2)
   129  
   130  	runInstance.completeAllBackgroundUploads(t, rootFs, "one/test/data.bin")
   131  	_, err = os.Stat(path.Join(runInstance.tmpUploadDir, id, runInstance.encryptRemoteIfNeeded(t, "one/test")))
   132  	require.True(t, os.IsNotExist(err))
   133  	_, err = os.Stat(path.Join(runInstance.tmpUploadDir, id, runInstance.encryptRemoteIfNeeded(t, "one")))
   134  	require.True(t, os.IsNotExist(err))
   135  	_, err = os.Stat(path.Join(runInstance.tmpUploadDir, id, runInstance.encryptRemoteIfNeeded(t, "second")))
   136  	require.False(t, os.IsNotExist(err))
   137  
   138  	runInstance.completeAllBackgroundUploads(t, rootFs, "second/data.bin")
   139  	_, err = os.Stat(path.Join(runInstance.tmpUploadDir, id, runInstance.encryptRemoteIfNeeded(t, "second/data.bin")))
   140  	require.True(t, os.IsNotExist(err))
   141  
   142  	de1, err := runInstance.list(t, rootFs, "one/test")
   143  	require.NoError(t, err)
   144  	require.Len(t, de1, 1)
   145  
   146  	// check if it can be read
   147  	de1, err = runInstance.list(t, rootFs, "second")
   148  	require.NoError(t, err)
   149  	require.Len(t, de1, 1)
   150  }
   151  
   152  func TestInternalUploadQueueMoreFiles(t *testing.T) {
   153  	id := fmt.Sprintf("tiuqmf%v", time.Now().Unix())
   154  	rootFs, _ := runInstance.newCacheFs(t, remoteName, id, true, true,
   155  		map[string]string{"tmp_upload_path": path.Join(runInstance.tmpUploadDir, id), "tmp_wait_time": "1s"})
   156  
   157  	err := rootFs.Mkdir(context.Background(), "test")
   158  	require.NoError(t, err)
   159  	minSize := 5242880
   160  	maxSize := 10485760
   161  	totalFiles := 10
   162  	randInstance := rand.New(rand.NewSource(time.Now().Unix()))
   163  
   164  	lastFile := ""
   165  	for i := 0; i < totalFiles; i++ {
   166  		size := int64(randInstance.Intn(maxSize-minSize) + minSize)
   167  		testReader := runInstance.randomReader(t, size)
   168  		remote := "test/" + strconv.Itoa(i) + ".bin"
   169  		runInstance.writeRemoteReader(t, rootFs, remote, testReader)
   170  
   171  		// validate that it exists in temp fs
   172  		ti, err := os.Stat(path.Join(runInstance.tmpUploadDir, id, runInstance.encryptRemoteIfNeeded(t, remote)))
   173  		require.NoError(t, err)
   174  		require.Equal(t, size, runInstance.cleanSize(t, ti.Size()))
   175  
   176  		if runInstance.wrappedIsExternal && i < totalFiles-1 {
   177  			time.Sleep(time.Second * 3)
   178  		}
   179  		lastFile = remote
   180  	}
   181  
   182  	// check if cache lists all files, likely temp upload didn't finish yet
   183  	de1, err := runInstance.list(t, rootFs, "test")
   184  	require.NoError(t, err)
   185  	require.Len(t, de1, totalFiles)
   186  
   187  	// wait for background uploader to do its thing
   188  	runInstance.completeAllBackgroundUploads(t, rootFs, lastFile)
   189  
   190  	// retry until we have no more temp files and fail if they don't go down to 0
   191  	_, err = os.Stat(path.Join(runInstance.tmpUploadDir, id, runInstance.encryptRemoteIfNeeded(t, "test")))
   192  	require.True(t, os.IsNotExist(err))
   193  
   194  	// check if cache lists all files
   195  	de1, err = runInstance.list(t, rootFs, "test")
   196  	require.NoError(t, err)
   197  	require.Len(t, de1, totalFiles)
   198  }
   199  
   200  func TestInternalUploadTempFileOperations(t *testing.T) {
   201  	id := "tiutfo"
   202  	rootFs, boltDb := runInstance.newCacheFs(t, remoteName, id, true, true,
   203  		map[string]string{"tmp_upload_path": path.Join(runInstance.tmpUploadDir, id), "tmp_wait_time": "1h"})
   204  
   205  	boltDb.PurgeTempUploads()
   206  
   207  	// create some rand test data
   208  	runInstance.mkdir(t, rootFs, "test")
   209  	runInstance.writeRemoteString(t, rootFs, "test/one", "one content")
   210  
   211  	// check if it can be read
   212  	data1, err := runInstance.readDataFromRemote(t, rootFs, "test/one", 0, int64(len([]byte("one content"))), false)
   213  	require.NoError(t, err)
   214  	require.Equal(t, []byte("one content"), data1)
   215  	// validate that it exists in temp fs
   216  	_, err = os.Stat(path.Join(runInstance.tmpUploadDir, id, runInstance.encryptRemoteIfNeeded(t, "test/one")))
   217  	require.NoError(t, err)
   218  
   219  	// test DirMove - allowed
   220  	err = runInstance.dirMove(t, rootFs, "test", "second")
   221  	if err != errNotSupported {
   222  		require.NoError(t, err)
   223  		_, err = rootFs.NewObject(context.Background(), "test/one")
   224  		require.Error(t, err)
   225  		_, err = rootFs.NewObject(context.Background(), "second/one")
   226  		require.NoError(t, err)
   227  		// validate that it exists in temp fs
   228  		_, err = os.Stat(path.Join(runInstance.tmpUploadDir, id, runInstance.encryptRemoteIfNeeded(t, "test/one")))
   229  		require.Error(t, err)
   230  		_, err = os.Stat(path.Join(runInstance.tmpUploadDir, id, runInstance.encryptRemoteIfNeeded(t, "second/one")))
   231  		require.NoError(t, err)
   232  		_, err = boltDb.SearchPendingUpload(runInstance.encryptRemoteIfNeeded(t, path.Join(id, "test/one")))
   233  		require.Error(t, err)
   234  		var started bool
   235  		started, err = boltDb.SearchPendingUpload(runInstance.encryptRemoteIfNeeded(t, path.Join(id, "second/one")))
   236  		require.NoError(t, err)
   237  		require.False(t, started)
   238  		runInstance.mkdir(t, rootFs, "test")
   239  		runInstance.writeRemoteString(t, rootFs, "test/one", "one content")
   240  	}
   241  
   242  	// test Rmdir - allowed
   243  	err = runInstance.rm(t, rootFs, "test")
   244  	require.Error(t, err)
   245  	require.Contains(t, err.Error(), "directory not empty")
   246  	_, err = rootFs.NewObject(context.Background(), "test/one")
   247  	require.NoError(t, err)
   248  	// validate that it exists in temp fs
   249  	_, err = os.Stat(path.Join(runInstance.tmpUploadDir, id, runInstance.encryptRemoteIfNeeded(t, "test/one")))
   250  	require.NoError(t, err)
   251  	started, err := boltDb.SearchPendingUpload(runInstance.encryptRemoteIfNeeded(t, path.Join(id, "test/one")))
   252  	require.False(t, started)
   253  	require.NoError(t, err)
   254  
   255  	// test Move/Rename -- allowed
   256  	err = runInstance.move(t, rootFs, path.Join("test", "one"), path.Join("test", "second"))
   257  	if err != errNotSupported {
   258  		require.NoError(t, err)
   259  		// try to read from it
   260  		_, err = rootFs.NewObject(context.Background(), "test/one")
   261  		require.Error(t, err)
   262  		_, err = rootFs.NewObject(context.Background(), "test/second")
   263  		require.NoError(t, err)
   264  		data2, err := runInstance.readDataFromRemote(t, rootFs, "test/second", 0, int64(len([]byte("one content"))), false)
   265  		require.NoError(t, err)
   266  		require.Equal(t, []byte("one content"), data2)
   267  		// validate that it exists in temp fs
   268  		_, err = os.Stat(path.Join(runInstance.tmpUploadDir, id, runInstance.encryptRemoteIfNeeded(t, "test/one")))
   269  		require.Error(t, err)
   270  		_, err = os.Stat(path.Join(runInstance.tmpUploadDir, id, runInstance.encryptRemoteIfNeeded(t, "test/second")))
   271  		require.NoError(t, err)
   272  		runInstance.writeRemoteString(t, rootFs, "test/one", "one content")
   273  	}
   274  
   275  	// test Copy -- allowed
   276  	err = runInstance.copy(t, rootFs, path.Join("test", "one"), path.Join("test", "third"))
   277  	if err != errNotSupported {
   278  		require.NoError(t, err)
   279  		_, err = rootFs.NewObject(context.Background(), "test/one")
   280  		require.NoError(t, err)
   281  		_, err = rootFs.NewObject(context.Background(), "test/third")
   282  		require.NoError(t, err)
   283  		data2, err := runInstance.readDataFromRemote(t, rootFs, "test/third", 0, int64(len([]byte("one content"))), false)
   284  		require.NoError(t, err)
   285  		require.Equal(t, []byte("one content"), data2)
   286  		// validate that it exists in temp fs
   287  		_, err = os.Stat(path.Join(runInstance.tmpUploadDir, id, runInstance.encryptRemoteIfNeeded(t, "test/one")))
   288  		require.NoError(t, err)
   289  		_, err = os.Stat(path.Join(runInstance.tmpUploadDir, id, runInstance.encryptRemoteIfNeeded(t, "test/third")))
   290  		require.NoError(t, err)
   291  	}
   292  
   293  	// test Remove -- allowed
   294  	err = runInstance.rm(t, rootFs, "test/one")
   295  	require.NoError(t, err)
   296  	_, err = rootFs.NewObject(context.Background(), "test/one")
   297  	require.Error(t, err)
   298  	// validate that it doesn't exist in temp fs
   299  	_, err = os.Stat(path.Join(runInstance.tmpUploadDir, id, runInstance.encryptRemoteIfNeeded(t, "test/one")))
   300  	require.Error(t, err)
   301  	runInstance.writeRemoteString(t, rootFs, "test/one", "one content")
   302  
   303  	// test Update -- allowed
   304  	firstModTime, err := runInstance.modTime(t, rootFs, "test/one")
   305  	require.NoError(t, err)
   306  	err = runInstance.updateData(t, rootFs, "test/one", "one content", " updated")
   307  	require.NoError(t, err)
   308  	obj2, err := rootFs.NewObject(context.Background(), "test/one")
   309  	require.NoError(t, err)
   310  	data2 := runInstance.readDataFromObj(t, obj2, 0, int64(len("one content updated")), false)
   311  	require.Equal(t, "one content updated", string(data2))
   312  	tmpInfo, err := os.Stat(path.Join(runInstance.tmpUploadDir, id, runInstance.encryptRemoteIfNeeded(t, "test/one")))
   313  	require.NoError(t, err)
   314  	if runInstance.rootIsCrypt {
   315  		require.Equal(t, int64(67), tmpInfo.Size())
   316  	} else {
   317  		require.Equal(t, int64(len(data2)), tmpInfo.Size())
   318  	}
   319  
   320  	// test SetModTime -- allowed
   321  	secondModTime, err := runInstance.modTime(t, rootFs, "test/one")
   322  	require.NoError(t, err)
   323  	require.NotEqual(t, secondModTime, firstModTime)
   324  	require.NotEqual(t, time.Time{}, firstModTime)
   325  	require.NotEqual(t, time.Time{}, secondModTime)
   326  }
   327  
   328  func TestInternalUploadUploadingFileOperations(t *testing.T) {
   329  	id := "tiuufo"
   330  	rootFs, boltDb := runInstance.newCacheFs(t, remoteName, id, true, true,
   331  		map[string]string{"tmp_upload_path": path.Join(runInstance.tmpUploadDir, id), "tmp_wait_time": "1h"})
   332  
   333  	boltDb.PurgeTempUploads()
   334  
   335  	// create some rand test data
   336  	runInstance.mkdir(t, rootFs, "test")
   337  	runInstance.writeRemoteString(t, rootFs, "test/one", "one content")
   338  
   339  	// check if it can be read
   340  	data1, err := runInstance.readDataFromRemote(t, rootFs, "test/one", 0, int64(len([]byte("one content"))), false)
   341  	require.NoError(t, err)
   342  	require.Equal(t, []byte("one content"), data1)
   343  	// validate that it exists in temp fs
   344  	_, err = os.Stat(path.Join(runInstance.tmpUploadDir, id, runInstance.encryptRemoteIfNeeded(t, "test/one")))
   345  	require.NoError(t, err)
   346  
   347  	err = boltDb.SetPendingUploadToStarted(runInstance.encryptRemoteIfNeeded(t, path.Join(rootFs.Root(), "test/one")))
   348  	require.NoError(t, err)
   349  
   350  	// test DirMove
   351  	err = runInstance.dirMove(t, rootFs, "test", "second")
   352  	if err != errNotSupported {
   353  		require.Error(t, err)
   354  		_, err = rootFs.NewObject(context.Background(), "test/one")
   355  		require.NoError(t, err)
   356  		// validate that it exists in temp fs
   357  		_, err = os.Stat(path.Join(runInstance.tmpUploadDir, id, runInstance.encryptRemoteIfNeeded(t, "test/one")))
   358  		require.NoError(t, err)
   359  		_, err = os.Stat(path.Join(runInstance.tmpUploadDir, id, runInstance.encryptRemoteIfNeeded(t, "second/one")))
   360  		require.Error(t, err)
   361  	}
   362  
   363  	// test Rmdir
   364  	err = runInstance.rm(t, rootFs, "test")
   365  	require.Error(t, err)
   366  	_, err = rootFs.NewObject(context.Background(), "test/one")
   367  	require.NoError(t, err)
   368  	// validate that it doesn't exist in temp fs
   369  	_, err = os.Stat(path.Join(runInstance.tmpUploadDir, id, runInstance.encryptRemoteIfNeeded(t, "test/one")))
   370  	require.NoError(t, err)
   371  
   372  	// test Move/Rename
   373  	err = runInstance.move(t, rootFs, path.Join("test", "one"), path.Join("test", "second"))
   374  	if err != errNotSupported {
   375  		require.Error(t, err)
   376  		// try to read from it
   377  		_, err = rootFs.NewObject(context.Background(), "test/one")
   378  		require.NoError(t, err)
   379  		_, err = rootFs.NewObject(context.Background(), "test/second")
   380  		require.Error(t, err)
   381  		// validate that it exists in temp fs
   382  		_, err = os.Stat(path.Join(runInstance.tmpUploadDir, id, runInstance.encryptRemoteIfNeeded(t, "test/one")))
   383  		require.NoError(t, err)
   384  		_, err = os.Stat(path.Join(runInstance.tmpUploadDir, id, runInstance.encryptRemoteIfNeeded(t, "test/second")))
   385  		require.Error(t, err)
   386  	}
   387  
   388  	// test Copy -- allowed
   389  	err = runInstance.copy(t, rootFs, path.Join("test", "one"), path.Join("test", "third"))
   390  	if err != errNotSupported {
   391  		require.NoError(t, err)
   392  		_, err = rootFs.NewObject(context.Background(), "test/one")
   393  		require.NoError(t, err)
   394  		_, err = rootFs.NewObject(context.Background(), "test/third")
   395  		require.NoError(t, err)
   396  		data2, err := runInstance.readDataFromRemote(t, rootFs, "test/third", 0, int64(len([]byte("one content"))), false)
   397  		require.NoError(t, err)
   398  		require.Equal(t, []byte("one content"), data2)
   399  		// validate that it exists in temp fs
   400  		_, err = os.Stat(path.Join(runInstance.tmpUploadDir, id, runInstance.encryptRemoteIfNeeded(t, "test/one")))
   401  		require.NoError(t, err)
   402  		_, err = os.Stat(path.Join(runInstance.tmpUploadDir, id, runInstance.encryptRemoteIfNeeded(t, "test/third")))
   403  		require.NoError(t, err)
   404  	}
   405  
   406  	// test Remove
   407  	err = runInstance.rm(t, rootFs, "test/one")
   408  	require.Error(t, err)
   409  	_, err = rootFs.NewObject(context.Background(), "test/one")
   410  	require.NoError(t, err)
   411  	// validate that it doesn't exist in temp fs
   412  	_, err = os.Stat(path.Join(runInstance.tmpUploadDir, id, runInstance.encryptRemoteIfNeeded(t, "test/one")))
   413  	require.NoError(t, err)
   414  	runInstance.writeRemoteString(t, rootFs, "test/one", "one content")
   415  
   416  	// test Update - this seems to work. Why? FIXME
   417  	//firstModTime, err := runInstance.modTime(t, rootFs, "test/one")
   418  	//require.NoError(t, err)
   419  	//err = runInstance.updateData(t, rootFs, "test/one", "one content", " updated", func() {
   420  	//	data2 := runInstance.readDataFromRemote(t, rootFs, "test/one", 0, int64(len("one content updated")), true)
   421  	//	require.Equal(t, "one content", string(data2))
   422  	//
   423  	//	tmpInfo, err := os.Stat(path.Join(runInstance.tmpUploadDir, id, runInstance.encryptRemoteIfNeeded(t, "test/one")))
   424  	//	require.NoError(t, err)
   425  	//	if runInstance.rootIsCrypt {
   426  	//		require.Equal(t, int64(67), tmpInfo.Size())
   427  	//	} else {
   428  	//		require.Equal(t, int64(len(data2)), tmpInfo.Size())
   429  	//	}
   430  	//})
   431  	//require.Error(t, err)
   432  
   433  	// test SetModTime -- seems to work cause of previous
   434  	//secondModTime, err := runInstance.modTime(t, rootFs, "test/one")
   435  	//require.NoError(t, err)
   436  	//require.Equal(t, secondModTime, firstModTime)
   437  	//require.NotEqual(t, time.Time{}, firstModTime)
   438  	//require.NotEqual(t, time.Time{}, secondModTime)
   439  }