55 "fmt"
66 "net/http"
77 "net/http/httptest"
8+ "strconv"
9+ "strings"
810 "testing"
911 "time"
1012
@@ -14,7 +16,10 @@ import (
1416 "github.com/aws/aws-sdk-go-v2/service/s3"
1517)
1618
17- const errMsg = `<Error><Code>ErrorCode</Code><Message>message body</Message><RequestId>requestID</RequestId><HostId>hostID=</HostId></Error>`
19+ const (
20+ errMsg = `<Error><Code>ErrorCode</Code><Message>message body</Message><RequestId>requestID</RequestId><HostId>hostID=</HostId></Error>`
21+ xmlPreambleMsg = `<?xml version="1.0" encoding="UTF-8"?>`
22+ )
1823
1924var lastModifiedTime = time .Date (2009 , 11 , 23 , 0 , 0 , 0 , 0 , time .UTC )
2025
@@ -173,3 +178,159 @@ func newCopyTestSvc(errMsg string) *s3.Client {
173178
174179 return svc
175180}
181+
182+ func TestStatusOKPayloadHandling (t * testing.T ) {
183+ cases := map [string ]struct {
184+ Header http.Header
185+ Payloads [][]byte
186+ OpCall func (api * s3.Client ) error
187+ Err string
188+ }{
189+ "200 error" : {
190+ Header : http.Header {
191+ "Content-Length" : []string {strconv .Itoa (len (errMsg ))},
192+ },
193+ Payloads : [][]byte {[]byte (errMsg )},
194+ OpCall : func (c * s3.Client ) error {
195+ req := c .CopyObjectRequest (& s3.CopyObjectInput {
196+ Bucket : aws .String ("bucketname" ),
197+ CopySource : aws .String ("bucketname/doesnotexist.txt" ),
198+ Key : aws .String ("destination.txt" ),
199+ })
200+ _ , err := req .Send (context .Background ())
201+ return err
202+ },
203+ Err : "ErrorCode: message body" ,
204+ },
205+ "200 error partial response" : {
206+ Header : http.Header {
207+ "Content-Length" : []string {strconv .Itoa (len (errMsg ))},
208+ },
209+ Payloads : [][]byte {
210+ []byte (errMsg [:20 ]),
211+ },
212+ OpCall : func (c * s3.Client ) error {
213+ req := c .CopyObjectRequest (& s3.CopyObjectInput {
214+ Bucket : aws .String ("bucketname" ),
215+ CopySource : aws .String ("bucketname/doesnotexist.txt" ),
216+ Key : aws .String ("destination.txt" ),
217+ })
218+ _ , err := req .Send (context .Background ())
219+ return err
220+ },
221+ Err : "unexpected EOF" ,
222+ },
223+ "200 error multipart" : {
224+ Header : http.Header {
225+ "Transfer-Encoding" : []string {"chunked" },
226+ },
227+ Payloads : [][]byte {
228+ []byte (errMsg [:20 ]),
229+ []byte (errMsg [20 :]),
230+ },
231+ OpCall : func (c * s3.Client ) error {
232+ req := c .CopyObjectRequest (& s3.CopyObjectInput {
233+ Bucket : aws .String ("bucketname" ),
234+ CopySource : aws .String ("bucketname/doesnotexist.txt" ),
235+ Key : aws .String ("destination.txt" ),
236+ })
237+ _ , err := req .Send (context .Background ())
238+ return err
239+ },
240+ Err : "ErrorCode: message body" ,
241+ },
242+ "200 error multipart partial response" : {
243+ Header : http.Header {
244+ "Transfer-Encoding" : []string {"chunked" },
245+ },
246+ Payloads : [][]byte {
247+ []byte (errMsg [:20 ]),
248+ },
249+ OpCall : func (c * s3.Client ) error {
250+ req := c .CopyObjectRequest (& s3.CopyObjectInput {
251+ Bucket : aws .String ("bucketname" ),
252+ CopySource : aws .String ("bucketname/doesnotexist.txt" ),
253+ Key : aws .String ("destination.txt" ),
254+ })
255+ _ , err := req .Send (context .Background ())
256+ return err
257+ },
258+ Err : "XML syntax error" ,
259+ },
260+ "200 error multipart no payload" : {
261+ Header : http.Header {
262+ "Transfer-Encoding" : []string {"chunked" },
263+ },
264+ Payloads : [][]byte {},
265+ OpCall : func (c * s3.Client ) error {
266+ req := c .CopyObjectRequest (& s3.CopyObjectInput {
267+ Bucket : aws .String ("bucketname" ),
268+ CopySource : aws .String ("bucketname/doesnotexist.txt" ),
269+ Key : aws .String ("destination.txt" ),
270+ })
271+ _ , err := req .Send (context .Background ())
272+ return err
273+ },
274+ Err : "empty response payload" ,
275+ },
276+ "response with only xml preamble" : {
277+ Header : http.Header {
278+ "Transfer-Encoding" : []string {"chunked" },
279+ },
280+ Payloads : [][]byte {
281+ []byte (xmlPreambleMsg ),
282+ },
283+ OpCall : func (c * s3.Client ) error {
284+ req := c .CopyObjectRequest (& s3.CopyObjectInput {
285+ Bucket : aws .String ("bucketname" ),
286+ CopySource : aws .String ("bucketname/doesnotexist.txt" ),
287+ Key : aws .String ("destination.txt" ),
288+ })
289+ _ , err := req .Send (context .Background ())
290+ return err
291+ },
292+ Err : "empty response payload" ,
293+ },
294+ }
295+
296+ for name , c := range cases {
297+ t .Run (name , func (t * testing.T ) {
298+ srv := httptest .NewServer (http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
299+ ww := w .(interface {
300+ http.ResponseWriter
301+ http.Flusher
302+ })
303+
304+ for k , vs := range c .Header {
305+ for _ , v := range vs {
306+ ww .Header ().Add (k , v )
307+ }
308+ }
309+ ww .WriteHeader (http .StatusOK )
310+ ww .Flush ()
311+
312+ for _ , p := range c .Payloads {
313+ ww .Write (p )
314+ ww .Flush ()
315+ }
316+ }))
317+ defer srv .Close ()
318+
319+ cfg := unit .Config ()
320+ cfg .EndpointResolver = aws .ResolveWithEndpointURL (srv .URL )
321+ svc := s3 .New (cfg )
322+ svc .ForcePathStyle = true
323+ err := c .OpCall (svc )
324+ if len (c .Err ) != 0 {
325+ if err == nil {
326+ t .Fatalf ("expect error, got none" )
327+ }
328+ if e , a := c .Err , err .Error (); ! strings .Contains (a , e ) {
329+ t .Fatalf ("expect %v error in, %v" , e , a )
330+ }
331+ } else if err != nil {
332+ t .Fatalf ("expect no error, got %v" , err )
333+ }
334+ })
335+ }
336+ }
0 commit comments