github.com/artpar/rclone@v1.67.3/backend/crypt/crypt_internal_test.go (about) 1 package crypt 2 3 import ( 4 "bytes" 5 "context" 6 "crypto/md5" 7 "fmt" 8 "io" 9 "testing" 10 "time" 11 12 "github.com/artpar/rclone/fs" 13 "github.com/artpar/rclone/fs/hash" 14 "github.com/artpar/rclone/fs/object" 15 "github.com/artpar/rclone/lib/random" 16 "github.com/stretchr/testify/assert" 17 "github.com/stretchr/testify/require" 18 ) 19 20 // Create a temporary local fs to upload things from 21 22 func makeTempLocalFs(t *testing.T) (localFs fs.Fs) { 23 localFs, err := fs.TemporaryLocalFs(context.Background()) 24 require.NoError(t, err) 25 t.Cleanup(func() { 26 require.NoError(t, localFs.Rmdir(context.Background(), "")) 27 }) 28 return localFs 29 } 30 31 // Upload a file to a remote 32 func uploadFile(t *testing.T, f fs.Fs, remote, contents string) (obj fs.Object) { 33 inBuf := bytes.NewBufferString(contents) 34 t1 := time.Date(2012, time.December, 17, 18, 32, 31, 0, time.UTC) 35 upSrc := object.NewStaticObjectInfo(remote, t1, int64(len(contents)), true, nil, nil) 36 obj, err := f.Put(context.Background(), inBuf, upSrc) 37 require.NoError(t, err) 38 t.Cleanup(func() { 39 require.NoError(t, obj.Remove(context.Background())) 40 }) 41 return obj 42 } 43 44 // Test the ObjectInfo 45 func testObjectInfo(t *testing.T, f *Fs, wrap bool) { 46 var ( 47 contents = random.String(100) 48 path = "hash_test_object" 49 ctx = context.Background() 50 ) 51 if wrap { 52 path = "_wrap" 53 } 54 55 localFs := makeTempLocalFs(t) 56 57 obj := uploadFile(t, localFs, path, contents) 58 59 // encrypt the data 60 inBuf := bytes.NewBufferString(contents) 61 var outBuf bytes.Buffer 62 enc, err := f.cipher.newEncrypter(inBuf, nil) 63 require.NoError(t, err) 64 nonce := enc.nonce // read the nonce at the start 65 _, err = io.Copy(&outBuf, enc) 66 require.NoError(t, err) 67 68 var oi fs.ObjectInfo = obj 69 if wrap { 70 // wrap the object in an fs.ObjectUnwrapper if required 71 oi = fs.NewOverrideRemote(oi, "new_remote") 72 } 73 74 // wrap the object in a crypt for upload using the nonce we 75 // saved from the encrypter 76 src := f.newObjectInfo(oi, nonce) 77 78 // Test ObjectInfo methods 79 if !f.opt.NoDataEncryption { 80 assert.Equal(t, int64(outBuf.Len()), src.Size()) 81 } 82 assert.Equal(t, f, src.Fs()) 83 assert.NotEqual(t, path, src.Remote()) 84 85 // Test ObjectInfo.Hash 86 wantHash := md5.Sum(outBuf.Bytes()) 87 gotHash, err := src.Hash(ctx, hash.MD5) 88 require.NoError(t, err) 89 assert.Equal(t, fmt.Sprintf("%x", wantHash), gotHash) 90 } 91 92 func testComputeHash(t *testing.T, f *Fs) { 93 var ( 94 contents = random.String(100) 95 path = "compute_hash_test" 96 ctx = context.Background() 97 hashType = f.Fs.Hashes().GetOne() 98 ) 99 100 if hashType == hash.None { 101 t.Skipf("%v: does not support hashes", f.Fs) 102 } 103 104 localFs := makeTempLocalFs(t) 105 106 // Upload a file to localFs as a test object 107 localObj := uploadFile(t, localFs, path, contents) 108 109 // Upload the same data to the remote Fs also 110 remoteObj := uploadFile(t, f, path, contents) 111 112 // Calculate the expected Hash of the remote object 113 computedHash, err := f.ComputeHash(ctx, remoteObj.(*Object), localObj, hashType) 114 require.NoError(t, err) 115 116 // Test computed hash matches remote object hash 117 remoteObjHash, err := remoteObj.(*Object).Object.Hash(ctx, hashType) 118 require.NoError(t, err) 119 assert.Equal(t, remoteObjHash, computedHash) 120 } 121 122 // InternalTest is called by fstests.Run to extra tests 123 func (f *Fs) InternalTest(t *testing.T) { 124 t.Run("ObjectInfo", func(t *testing.T) { testObjectInfo(t, f, false) }) 125 t.Run("ObjectInfoWrap", func(t *testing.T) { testObjectInfo(t, f, true) }) 126 t.Run("ComputeHash", func(t *testing.T) { testComputeHash(t, f) }) 127 }