github.com/aavshr/aws-sdk-go@v1.41.3/service/s3/unmarshal_error_test.go (about) 1 package s3_test 2 3 import ( 4 "bytes" 5 "fmt" 6 "io/ioutil" 7 "net/http" 8 "strings" 9 "testing" 10 "time" 11 12 "github.com/aavshr/aws-sdk-go/aws" 13 "github.com/aavshr/aws-sdk-go/aws/awserr" 14 "github.com/aavshr/aws-sdk-go/aws/request" 15 "github.com/aavshr/aws-sdk-go/awstesting/unit" 16 "github.com/aavshr/aws-sdk-go/service/s3" 17 ) 18 19 type testErrorCase struct { 20 RespFn func() *http.Response 21 ReqID, HostID string 22 Code, Msg string 23 WithoutStatusMsg bool 24 } 25 26 var testUnmarshalCases = []testErrorCase{ 27 { 28 RespFn: func() *http.Response { 29 return &http.Response{ 30 StatusCode: 301, 31 Header: http.Header{ 32 "X-Amz-Request-Id": []string{"abc123"}, 33 "X-Amz-Id-2": []string{"321cba"}, 34 }, 35 Body: ioutil.NopCloser(bytes.NewReader(nil)), 36 ContentLength: -1, 37 } 38 }, 39 ReqID: "abc123", 40 HostID: "321cba", 41 Code: "BucketRegionError", Msg: "incorrect region, the bucket is not in 'mock-region' region", 42 }, 43 { 44 RespFn: func() *http.Response { 45 return &http.Response{ 46 StatusCode: 403, 47 Header: http.Header{ 48 "X-Amz-Request-Id": []string{"abc123"}, 49 "X-Amz-Id-2": []string{"321cba"}, 50 }, 51 Body: ioutil.NopCloser(bytes.NewReader(nil)), 52 ContentLength: 0, 53 } 54 }, 55 ReqID: "abc123", 56 HostID: "321cba", 57 Code: "Forbidden", Msg: "Forbidden", 58 }, 59 { 60 RespFn: func() *http.Response { 61 return &http.Response{ 62 StatusCode: 400, 63 Header: http.Header{ 64 "X-Amz-Request-Id": []string{"abc123"}, 65 "X-Amz-Id-2": []string{"321cba"}, 66 }, 67 Body: ioutil.NopCloser(bytes.NewReader(nil)), 68 ContentLength: 0, 69 } 70 }, 71 ReqID: "abc123", 72 HostID: "321cba", 73 Code: "BadRequest", Msg: "Bad Request", 74 }, 75 { 76 RespFn: func() *http.Response { 77 return &http.Response{ 78 StatusCode: 404, 79 Header: http.Header{ 80 "X-Amz-Request-Id": []string{"abc123"}, 81 "X-Amz-Id-2": []string{"321cba"}, 82 }, 83 Body: ioutil.NopCloser(bytes.NewReader(nil)), 84 ContentLength: 0, 85 } 86 }, 87 ReqID: "abc123", 88 HostID: "321cba", 89 Code: "NotFound", Msg: "Not Found", 90 }, 91 { 92 // SDK only reads request ID and host ID from the header. The values 93 // in message body are ignored. 94 RespFn: func() *http.Response { 95 body := `<Error><Code>SomeException</Code><Message>Exception message</Message><RequestId>ignored-request-id</RequestId><HostId>ignored-host-id</HostId></Error>` 96 return &http.Response{ 97 StatusCode: 500, 98 Header: http.Header{ 99 "X-Amz-Request-Id": []string{"taken-request-id"}, 100 "X-Amz-Id-2": []string{"taken-host-id"}, 101 }, 102 Body: ioutil.NopCloser(strings.NewReader(body)), 103 ContentLength: int64(len(body)), 104 } 105 }, 106 ReqID: "taken-request-id", 107 HostID: "taken-host-id", 108 Code: "SomeException", Msg: "Exception message", 109 }, 110 { 111 RespFn: func() *http.Response { 112 return &http.Response{ 113 StatusCode: 404, 114 Header: http.Header{ 115 "X-Amz-Request-Id": []string{"abc123"}, 116 "X-Amz-Id-2": []string{"321cba"}, 117 }, 118 Body: ioutil.NopCloser(bytes.NewReader(nil)), 119 ContentLength: -1, 120 } 121 }, 122 ReqID: "abc123", 123 HostID: "321cba", 124 Code: "NotFound", Msg: "Not Found", WithoutStatusMsg: true, 125 }, 126 { 127 RespFn: func() *http.Response { 128 return &http.Response{ 129 StatusCode: 404, 130 Header: http.Header{ 131 "X-Amz-Request-Id": []string{"abc123"}, 132 "X-Amz-Id-2": []string{"321cba"}, 133 }, 134 Body: ioutil.NopCloser(bytes.NewReader(nil)), 135 ContentLength: -1, 136 } 137 }, 138 ReqID: "abc123", 139 HostID: "321cba", 140 Code: "NotFound", Msg: "Not Found", 141 }, 142 } 143 144 func TestUnmarshalError(t *testing.T) { 145 for i, c := range testUnmarshalCases { 146 s := s3.New(unit.Session) 147 s.Handlers.Send.Clear() 148 s.Handlers.Send.PushBack(func(r *request.Request) { 149 r.HTTPResponse = c.RespFn() 150 if !c.WithoutStatusMsg { 151 r.HTTPResponse.Status = fmt.Sprintf("%d%s", 152 r.HTTPResponse.StatusCode, 153 http.StatusText(r.HTTPResponse.StatusCode)) 154 } 155 }) 156 _, err := s.PutBucketAcl(&s3.PutBucketAclInput{ 157 Bucket: aws.String("bucket"), ACL: aws.String("public-read"), 158 }) 159 160 if err == nil { 161 t.Fatalf("%d, expected error, got nil", i) 162 } 163 if e, a := c.Code, err.(awserr.Error).Code(); e != a { 164 t.Errorf("%d, Code: expect %s, got %s", i, e, a) 165 } 166 if e, a := c.Msg, err.(awserr.Error).Message(); !strings.Contains(a, e) { 167 t.Errorf("%d, Message: expect %s, got %s", i, e, a) 168 } 169 if e, a := c.ReqID, err.(awserr.RequestFailure).RequestID(); e != a { 170 t.Errorf("%d, RequestID: expect %s, got %s", i, e, a) 171 } 172 if e, a := c.HostID, err.(s3.RequestFailure).HostID(); e != a { 173 t.Errorf("%d, HostID: expect %s, got %s", i, e, a) 174 } 175 } 176 } 177 178 const completeMultiResp = ` 179 163 180 <?xml version="1.0" encoding="UTF-8"?> 181 182 <CompleteMultipartUploadResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><Location>https://bucket.s3-us-west-2.amazonaws.com/key</Location><Bucket>bucket</Bucket><Key>key</Key><ETag>"a7d414b9133d6483d9a1c4e04e856e3b-2"</ETag></CompleteMultipartUploadResult> 183 0 184 ` 185 186 func Test200NoErrorUnmarshalError(t *testing.T) { 187 s := s3.New(unit.Session) 188 s.Handlers.Send.Clear() 189 s.Handlers.Send.PushBack(func(r *request.Request) { 190 r.HTTPResponse = &http.Response{ 191 StatusCode: 200, 192 Header: http.Header{ 193 "X-Amz-Request-Id": []string{"abc123"}, 194 "X-Amz-Id-2": []string{"321cba"}, 195 }, 196 Body: ioutil.NopCloser(strings.NewReader(completeMultiResp)), 197 ContentLength: -1, 198 } 199 r.HTTPResponse.Status = http.StatusText(r.HTTPResponse.StatusCode) 200 }) 201 _, err := s.CompleteMultipartUpload(&s3.CompleteMultipartUploadInput{ 202 Bucket: aws.String("bucket"), Key: aws.String("key"), 203 UploadId: aws.String("id"), 204 MultipartUpload: &s3.CompletedMultipartUpload{Parts: []*s3.CompletedPart{ 205 {ETag: aws.String("etag"), PartNumber: aws.Int64(1)}, 206 }}, 207 }) 208 209 if err != nil { 210 t.Fatalf("expect no error, got %v", err) 211 } 212 } 213 214 const completeMultiErrResp = `<Error><Code>SomeException</Code><Message>Exception message</Message></Error>` 215 216 func Test200WithErrorUnmarshalError(t *testing.T) { 217 const expectAttempts = 4 218 s := s3.New(unit.Session, &aws.Config{ 219 MaxRetries: aws.Int(expectAttempts - 1), 220 SleepDelay: func(time.Duration) {}, 221 }) 222 223 var attempts int 224 s.Handlers.Send.Clear() 225 s.Handlers.Send.PushBack(func(r *request.Request) { 226 attempts++ 227 228 r.HTTPResponse = &http.Response{ 229 StatusCode: 200, 230 Header: http.Header{ 231 "X-Amz-Request-Id": []string{"abc123"}, 232 "X-Amz-Id-2": []string{"321cba"}, 233 }, 234 Body: ioutil.NopCloser(strings.NewReader(completeMultiErrResp)), 235 ContentLength: -1, 236 } 237 r.HTTPResponse.Status = http.StatusText(r.HTTPResponse.StatusCode) 238 }) 239 240 _, err := s.CompleteMultipartUpload(&s3.CompleteMultipartUploadInput{ 241 Bucket: aws.String("bucket"), Key: aws.String("key"), 242 UploadId: aws.String("id"), 243 MultipartUpload: &s3.CompletedMultipartUpload{Parts: []*s3.CompletedPart{ 244 {ETag: aws.String("etag"), PartNumber: aws.Int64(1)}, 245 }}, 246 }) 247 248 if err == nil { 249 t.Fatalf("expected error, got nil") 250 } 251 if e, a := expectAttempts, attempts; e != a { 252 t.Errorf("expect %v attempts, got %v", e, a) 253 } 254 if e, a := "SomeException", err.(awserr.Error).Code(); e != a { 255 t.Errorf("Code: expect %s, got %s", e, a) 256 } 257 if e, a := "Exception message", err.(awserr.Error).Message(); e != a { 258 t.Errorf("Message: expect %s, got %s", e, a) 259 } 260 if e, a := "abc123", err.(s3.RequestFailure).RequestID(); e != a { 261 t.Errorf("RequestID: expect %s, got %s", e, a) 262 } 263 if e, a := "321cba", err.(s3.RequestFailure).HostID(); e != a { 264 t.Errorf("HostID: expect %s, got %s", e, a) 265 } 266 }