github.com/artpar/rclone@v1.67.3/fs/object/object_test.go (about) 1 package object_test 2 3 import ( 4 "bytes" 5 "context" 6 "io" 7 "testing" 8 "time" 9 10 "github.com/artpar/rclone/fs" 11 "github.com/artpar/rclone/fs/hash" 12 "github.com/artpar/rclone/fs/object" 13 "github.com/stretchr/testify/assert" 14 ) 15 16 func TestStaticObject(t *testing.T) { 17 now := time.Now() 18 remote := "path/to/object" 19 size := int64(1024) 20 21 o := object.NewStaticObjectInfo(remote, now, size, true, nil, object.MemoryFs) 22 23 assert.Equal(t, object.MemoryFs, o.Fs()) 24 assert.Equal(t, remote, o.Remote()) 25 assert.Equal(t, remote, o.String()) 26 assert.Equal(t, now, o.ModTime(context.Background())) 27 assert.Equal(t, size, o.Size()) 28 assert.Equal(t, true, o.Storable()) 29 30 Hash, err := o.Hash(context.Background(), hash.MD5) 31 assert.NoError(t, err) 32 assert.Equal(t, "", Hash) 33 34 o = object.NewStaticObjectInfo(remote, now, size, true, nil, nil) 35 _, err = o.Hash(context.Background(), hash.MD5) 36 assert.Equal(t, hash.ErrUnsupported, err) 37 38 hs := map[hash.Type]string{ 39 hash.MD5: "potato", 40 } 41 o = object.NewStaticObjectInfo(remote, now, size, true, hs, nil) 42 Hash, err = o.Hash(context.Background(), hash.MD5) 43 assert.NoError(t, err) 44 assert.Equal(t, "potato", Hash) 45 _, err = o.Hash(context.Background(), hash.SHA1) 46 assert.Equal(t, hash.ErrUnsupported, err) 47 } 48 49 func TestMemoryFs(t *testing.T) { 50 f := object.MemoryFs 51 assert.Equal(t, "memory", f.Name()) 52 assert.Equal(t, "", f.Root()) 53 assert.Equal(t, "memory", f.String()) 54 assert.Equal(t, time.Nanosecond, f.Precision()) 55 assert.Equal(t, hash.Supported(), f.Hashes()) 56 assert.Equal(t, &fs.Features{}, f.Features()) 57 58 entries, err := f.List(context.Background(), "") 59 assert.NoError(t, err) 60 assert.Nil(t, entries) 61 62 o, err := f.NewObject(context.Background(), "obj") 63 assert.Equal(t, fs.ErrorObjectNotFound, err) 64 assert.Nil(t, o) 65 66 buf := bytes.NewBufferString("potato") 67 now := time.Now() 68 src := object.NewStaticObjectInfo("remote", now, int64(buf.Len()), true, nil, nil) 69 o, err = f.Put(context.Background(), buf, src) 70 assert.NoError(t, err) 71 hash, err := o.Hash(context.Background(), hash.SHA1) 72 assert.NoError(t, err) 73 assert.Equal(t, "3e2e95f5ad970eadfa7e17eaf73da97024aa5359", hash) 74 75 err = f.Mkdir(context.Background(), "dir") 76 assert.Error(t, err) 77 78 err = f.Rmdir(context.Background(), "dir") 79 assert.Equal(t, fs.ErrorDirNotFound, err) 80 } 81 82 func TestMemoryObject(t *testing.T) { 83 remote := "path/to/object" 84 now := time.Now() 85 content := []byte("potatoXXXXXXXXXXXXX") 86 content = content[:6] // make some extra cap 87 88 o := object.NewMemoryObject(remote, now, content) 89 90 assert.Equal(t, content, o.Content()) 91 assert.Equal(t, object.MemoryFs, o.Fs()) 92 assert.Equal(t, remote, o.Remote()) 93 assert.Equal(t, remote, o.String()) 94 assert.Equal(t, now, o.ModTime(context.Background())) 95 assert.Equal(t, int64(len(content)), o.Size()) 96 assert.Equal(t, true, o.Storable()) 97 98 Hash, err := o.Hash(context.Background(), hash.MD5) 99 assert.NoError(t, err) 100 assert.Equal(t, "8ee2027983915ec78acc45027d874316", Hash) 101 102 Hash, err = o.Hash(context.Background(), hash.SHA1) 103 assert.NoError(t, err) 104 assert.Equal(t, "3e2e95f5ad970eadfa7e17eaf73da97024aa5359", Hash) 105 106 newNow := now.Add(time.Minute) 107 err = o.SetModTime(context.Background(), newNow) 108 assert.NoError(t, err) 109 assert.Equal(t, newNow, o.ModTime(context.Background())) 110 111 checkOpen := func(rc io.ReadCloser, expected string) { 112 actual, err := io.ReadAll(rc) 113 assert.NoError(t, err) 114 err = rc.Close() 115 assert.NoError(t, err) 116 assert.Equal(t, expected, string(actual)) 117 } 118 119 checkContent := func(o fs.Object, expected string) { 120 rc, err := o.Open(context.Background()) 121 assert.NoError(t, err) 122 checkOpen(rc, expected) 123 } 124 125 checkContent(o, string(content)) 126 127 rc, err := o.Open(context.Background(), &fs.RangeOption{Start: 1, End: 3}) 128 assert.NoError(t, err) 129 checkOpen(rc, "ot") 130 131 rc, err = o.Open(context.Background(), &fs.SeekOption{Offset: 3}) 132 assert.NoError(t, err) 133 checkOpen(rc, "ato") 134 135 // check it fits within the buffer 136 newNow = now.Add(2 * time.Minute) 137 newContent := bytes.NewBufferString("Rutabaga") 138 assert.True(t, newContent.Len() < cap(content)) // fits within cap(content) 139 src := object.NewStaticObjectInfo(remote, newNow, int64(newContent.Len()), true, nil, nil) 140 err = o.Update(context.Background(), newContent, src) 141 assert.NoError(t, err) 142 checkContent(o, "Rutabaga") 143 assert.Equal(t, newNow, o.ModTime(context.Background())) 144 assert.Equal(t, "Rutaba", string(content)) // check we re-used the buffer 145 146 // not within the buffer 147 newStr := "0123456789" 148 newStr = newStr + newStr + newStr + newStr + newStr + newStr + newStr + newStr + newStr + newStr 149 newContent = bytes.NewBufferString(newStr) 150 assert.True(t, newContent.Len() > cap(content)) // does not fit within cap(content) 151 src = object.NewStaticObjectInfo(remote, newNow, int64(newContent.Len()), true, nil, nil) 152 err = o.Update(context.Background(), newContent, src) 153 assert.NoError(t, err) 154 checkContent(o, newStr) 155 assert.Equal(t, "Rutaba", string(content)) // check we didn't reuse the buffer 156 157 // now try streaming 158 newStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 159 newContent = bytes.NewBufferString(newStr) 160 src = object.NewStaticObjectInfo(remote, newNow, -1, true, nil, nil) 161 err = o.Update(context.Background(), newContent, src) 162 assert.NoError(t, err) 163 checkContent(o, newStr) 164 165 // and zero length 166 newStr = "" 167 newContent = bytes.NewBufferString(newStr) 168 src = object.NewStaticObjectInfo(remote, newNow, 0, true, nil, nil) 169 err = o.Update(context.Background(), newContent, src) 170 assert.NoError(t, err) 171 checkContent(o, newStr) 172 173 err = o.Remove(context.Background()) 174 assert.Error(t, err) 175 }