github.com/rclone/rclone@v1.66.1-0.20240517100346-7b89735ae726/backend/swift/swift_test.go (about) 1 // Test Swift filesystem interface 2 package swift 3 4 import ( 5 "bytes" 6 "context" 7 "errors" 8 "io" 9 "testing" 10 11 "github.com/ncw/swift/v2" 12 "github.com/rclone/rclone/fs" 13 "github.com/rclone/rclone/fs/hash" 14 "github.com/rclone/rclone/fs/object" 15 "github.com/rclone/rclone/fstest" 16 "github.com/rclone/rclone/fstest/fstests" 17 "github.com/rclone/rclone/lib/random" 18 "github.com/rclone/rclone/lib/readers" 19 "github.com/stretchr/testify/assert" 20 "github.com/stretchr/testify/require" 21 ) 22 23 // TestIntegration runs integration tests against the remote 24 func TestIntegration(t *testing.T) { 25 fstests.Run(t, &fstests.Opt{ 26 RemoteName: "TestSwiftAIO:", 27 NilObject: (*Object)(nil), 28 }) 29 } 30 31 func (f *Fs) SetUploadChunkSize(cs fs.SizeSuffix) (fs.SizeSuffix, error) { 32 return f.setUploadChunkSize(cs) 33 } 34 35 var _ fstests.SetUploadChunkSizer = (*Fs)(nil) 36 37 // Check that PutStream works with NoChunk as it is the major code 38 // deviation 39 func (f *Fs) testNoChunk(t *testing.T) { 40 ctx := context.Background() 41 f.opt.NoChunk = true 42 defer func() { 43 f.opt.NoChunk = false 44 }() 45 46 file := fstest.Item{ 47 ModTime: fstest.Time("2001-02-03T04:05:06.499999999Z"), 48 Path: "piped data no chunk.txt", 49 Size: -1, // use unknown size during upload 50 } 51 52 const contentSize = 100 53 54 contents := random.String(contentSize) 55 buf := bytes.NewBufferString(contents) 56 uploadHash := hash.NewMultiHasher() 57 in := io.TeeReader(buf, uploadHash) 58 59 file.Size = -1 60 obji := object.NewStaticObjectInfo(file.Path, file.ModTime, file.Size, true, nil, nil) 61 obj, err := f.Features().PutStream(ctx, in, obji) 62 require.NoError(t, err) 63 64 file.Hashes = uploadHash.Sums() 65 file.Size = int64(contentSize) // use correct size when checking 66 file.Check(t, obj, f.Precision()) 67 68 // Re-read the object and check again 69 obj, err = f.NewObject(ctx, file.Path) 70 require.NoError(t, err) 71 file.Check(t, obj, f.Precision()) 72 73 // Delete the object 74 assert.NoError(t, obj.Remove(ctx)) 75 } 76 77 // Additional tests that aren't in the framework 78 func (f *Fs) InternalTest(t *testing.T) { 79 t.Run("NoChunk", f.testNoChunk) 80 t.Run("WithChunk", f.testWithChunk) 81 t.Run("WithChunkFail", f.testWithChunkFail) 82 t.Run("CopyLargeObject", f.testCopyLargeObject) 83 } 84 85 func (f *Fs) testWithChunk(t *testing.T) { 86 preConfChunkSize := f.opt.ChunkSize 87 preConfChunk := f.opt.NoChunk 88 f.opt.NoChunk = false 89 f.opt.ChunkSize = 1024 * fs.SizeSuffixBase 90 defer func() { 91 //restore old config after test 92 f.opt.ChunkSize = preConfChunkSize 93 f.opt.NoChunk = preConfChunk 94 }() 95 96 file := fstest.Item{ 97 ModTime: fstest.Time("2020-12-31T04:05:06.499999999Z"), 98 Path: "piped data chunk.txt", 99 Size: -1, // use unknown size during upload 100 } 101 const contentSize = 2048 102 contents := random.String(contentSize) 103 buf := bytes.NewBufferString(contents) 104 uploadHash := hash.NewMultiHasher() 105 in := io.TeeReader(buf, uploadHash) 106 107 file.Size = -1 108 obji := object.NewStaticObjectInfo(file.Path, file.ModTime, file.Size, true, nil, nil) 109 ctx := context.TODO() 110 obj, err := f.Features().PutStream(ctx, in, obji) 111 require.NoError(t, err) 112 require.NotEmpty(t, obj) 113 } 114 115 func (f *Fs) testWithChunkFail(t *testing.T) { 116 preConfChunkSize := f.opt.ChunkSize 117 preConfChunk := f.opt.NoChunk 118 f.opt.NoChunk = false 119 f.opt.ChunkSize = 1024 * fs.SizeSuffixBase 120 segmentContainer := f.root + "_segments" 121 if !f.opt.UseSegmentsContainer.Value { 122 segmentContainer = f.root 123 } 124 defer func() { 125 //restore config 126 f.opt.ChunkSize = preConfChunkSize 127 f.opt.NoChunk = preConfChunk 128 }() 129 path := "piped data chunk with error.txt" 130 file := fstest.Item{ 131 ModTime: fstest.Time("2021-01-04T03:46:00.499999999Z"), 132 Path: path, 133 Size: -1, // use unknown size during upload 134 } 135 const contentSize = 4096 136 const errPosition = 3072 137 contents := random.String(contentSize) 138 buf := bytes.NewBufferString(contents[:errPosition]) 139 errMessage := "potato" 140 er := &readers.ErrorReader{Err: errors.New(errMessage)} 141 in := io.NopCloser(io.MultiReader(buf, er)) 142 143 file.Size = contentSize 144 obji := object.NewStaticObjectInfo(file.Path, file.ModTime, file.Size, true, nil, nil) 145 ctx := context.TODO() 146 _, err := f.Features().PutStream(ctx, in, obji) 147 // error is potato 148 require.NotNil(t, err) 149 require.Equal(t, errMessage, err.Error()) 150 _, _, err = f.c.Object(ctx, f.rootContainer, path) 151 assert.Equal(t, swift.ObjectNotFound, err) 152 prefix := path 153 if !f.opt.UseSegmentsContainer.Value { 154 prefix = segmentsDirectory + "/" + prefix 155 } 156 objs, err := f.c.Objects(ctx, segmentContainer, &swift.ObjectsOpts{ 157 Prefix: prefix, 158 }) 159 require.NoError(t, err) 160 require.Empty(t, objs) 161 } 162 163 func (f *Fs) testCopyLargeObject(t *testing.T) { 164 preConfChunkSize := f.opt.ChunkSize 165 preConfChunk := f.opt.NoChunk 166 f.opt.NoChunk = false 167 f.opt.ChunkSize = 1024 * fs.SizeSuffixBase 168 defer func() { 169 //restore old config after test 170 f.opt.ChunkSize = preConfChunkSize 171 f.opt.NoChunk = preConfChunk 172 }() 173 174 file := fstest.Item{ 175 ModTime: fstest.Time("2020-12-31T04:05:06.499999999Z"), 176 Path: "large.txt", 177 Size: -1, // use unknown size during upload 178 } 179 const contentSize = 2048 180 contents := random.String(contentSize) 181 buf := bytes.NewBufferString(contents) 182 uploadHash := hash.NewMultiHasher() 183 in := io.TeeReader(buf, uploadHash) 184 185 file.Size = -1 186 obji := object.NewStaticObjectInfo(file.Path, file.ModTime, file.Size, true, nil, nil) 187 ctx := context.TODO() 188 obj, err := f.Features().PutStream(ctx, in, obji) 189 require.NoError(t, err) 190 require.NotEmpty(t, obj) 191 remoteTarget := "large.txt (copy)" 192 objTarget, err := f.Features().Copy(ctx, obj, remoteTarget) 193 require.NoError(t, err) 194 require.NotEmpty(t, objTarget) 195 require.Equal(t, obj.Size(), objTarget.Size()) 196 } 197 198 var _ fstests.InternalTester = (*Fs)(nil)