1//go:build go1.7 2// +build go1.7 3 4package jsonrpc 5 6import ( 7 "bytes" 8 "encoding/hex" 9 "io/ioutil" 10 "net/http" 11 "reflect" 12 "strings" 13 "testing" 14 15 "github.com/aws/aws-sdk-go/aws" 16 "github.com/aws/aws-sdk-go/aws/awserr" 17 "github.com/aws/aws-sdk-go/aws/request" 18 "github.com/aws/aws-sdk-go/private/protocol" 19) 20 21const unknownErrJSON = `{"__type":"UnknownError", "message":"error message", "something":123}` 22const simpleErrJSON = `{"__type":"SimpleError", "message":"some message", "foo":123}` 23const simpleCasedErrJSON = `{"__type":"SimpleError", "Message":"some message", "foo":123}` 24 25type SimpleError struct { 26 _ struct{} `type:"structure"` 27 error 28 29 Message2 *string `type:"string" locationName:"message"` 30 Foo *int64 `type:"integer" locationName:"foo"` 31} 32 33const otherErrJSON = `{"__type":"OtherError", "message":"some message"}` 34const complexCodeErrJSON = `{"__type":"foo.bar#OtherError", "message":"some message"}` 35 36type OtherError struct { 37 _ struct{} `type:"structure"` 38 error 39 40 Message2 *string `type:"string" locationName:"message"` 41} 42 43const complexErrJSON = `{"__type":"ComplexError", "message":"some message", "foo": {"bar":"abc123", "baz":123}}` 44 45type ComplexError struct { 46 _ struct{} `type:"structure"` 47 error 48 49 Message2 *string `type:"string" locationName:"message"` 50 Foo *ErrorNested `type:"structure" locationName:"foo"` 51} 52type ErrorNested struct { 53 _ struct{} `type:"structure"` 54 55 Bar *string `type:"string" locationName:"bar"` 56 Baz *int64 `type:"integer" locationName:"baz"` 57} 58 59func TestUnmarshalTypedError(t *testing.T) { 60 61 respMeta := protocol.ResponseMetadata{ 62 StatusCode: 400, 63 RequestID: "abc123", 64 } 65 66 exceptions := map[string]func(protocol.ResponseMetadata) error{ 67 "SimpleError": func(meta protocol.ResponseMetadata) error { 68 return &SimpleError{} 69 }, 70 "OtherError": func(meta protocol.ResponseMetadata) error { 71 return &OtherError{} 72 }, 73 "ComplexError": func(meta protocol.ResponseMetadata) error { 74 return &ComplexError{} 75 }, 76 } 77 78 cases := map[string]struct { 79 Response *http.Response 80 Expect error 81 Err string 82 }{ 83 "simple error": { 84 Response: &http.Response{ 85 Header: http.Header{}, 86 Body: ioutil.NopCloser(strings.NewReader(simpleErrJSON)), 87 }, 88 Expect: &SimpleError{ 89 Message2: aws.String("some message"), 90 Foo: aws.Int64(123), 91 }, 92 }, 93 "other error": { 94 Response: &http.Response{ 95 Header: http.Header{}, 96 Body: ioutil.NopCloser(strings.NewReader(otherErrJSON)), 97 }, 98 Expect: &OtherError{ 99 Message2: aws.String("some message"), 100 }, 101 }, 102 "other complex Code error": { 103 Response: &http.Response{ 104 Header: http.Header{}, 105 Body: ioutil.NopCloser(strings.NewReader(complexCodeErrJSON)), 106 }, 107 Expect: &OtherError{ 108 Message2: aws.String("some message"), 109 }, 110 }, 111 "complex error": { 112 Response: &http.Response{ 113 Header: http.Header{}, 114 Body: ioutil.NopCloser(strings.NewReader(complexErrJSON)), 115 }, 116 Expect: &ComplexError{ 117 Message2: aws.String("some message"), 118 Foo: &ErrorNested{ 119 Bar: aws.String("abc123"), 120 Baz: aws.Int64(123), 121 }, 122 }, 123 }, 124 "unknown error": { 125 Response: &http.Response{ 126 Header: http.Header{}, 127 Body: ioutil.NopCloser(strings.NewReader(unknownErrJSON)), 128 }, 129 Expect: awserr.NewRequestFailure( 130 awserr.New("UnknownError", "error message", nil), 131 respMeta.StatusCode, 132 respMeta.RequestID, 133 ), 134 }, 135 "invalid error": { 136 Response: &http.Response{ 137 StatusCode: 400, 138 Header: http.Header{}, 139 Body: ioutil.NopCloser(strings.NewReader(`{`)), 140 }, 141 Err: "failed decoding", 142 }, 143 "mixed case fields": { 144 Response: &http.Response{ 145 Header: http.Header{}, 146 Body: ioutil.NopCloser(strings.NewReader(simpleCasedErrJSON)), 147 }, 148 Expect: &SimpleError{ 149 Message2: aws.String("some message"), 150 Foo: aws.Int64(123), 151 }, 152 }, 153 } 154 155 for name, c := range cases { 156 t.Run(name, func(t *testing.T) { 157 u := NewUnmarshalTypedError(exceptions) 158 v, err := u.UnmarshalError(c.Response, respMeta) 159 160 if len(c.Err) != 0 { 161 if err == nil { 162 t.Fatalf("expect error, got none") 163 } 164 if e, a := c.Err, err.Error(); !strings.Contains(a, e) { 165 t.Fatalf("expect %v in error, got %v", e, a) 166 } 167 } else if err != nil { 168 t.Fatalf("expect no error, got %v", err) 169 } 170 171 if e, a := c.Expect, v; !reflect.DeepEqual(e, a) { 172 t.Errorf("expect %+#v, got %#+v", e, a) 173 } 174 }) 175 } 176} 177 178func TestUnmarshalError_SerializationError(t *testing.T) { 179 cases := map[string]struct { 180 Request *request.Request 181 ExpectMsg string 182 ExpectBytes []byte 183 }{ 184 "empty body": { 185 Request: &request.Request{ 186 Data: &struct{}{}, 187 HTTPResponse: &http.Response{ 188 StatusCode: 400, 189 Header: http.Header{ 190 "X-Amzn-Requestid": []string{"abc123"}, 191 }, 192 Body: ioutil.NopCloser( 193 bytes.NewReader([]byte{}), 194 ), 195 }, 196 }, 197 ExpectMsg: "error message missing", 198 }, 199 "HTML body": { 200 Request: &request.Request{ 201 Data: &struct{}{}, 202 HTTPResponse: &http.Response{ 203 StatusCode: 400, 204 Header: http.Header{ 205 "X-Amzn-Requestid": []string{"abc123"}, 206 }, 207 Body: ioutil.NopCloser( 208 bytes.NewReader([]byte(`<html></html>`)), 209 ), 210 }, 211 }, 212 ExpectBytes: []byte(`<html></html>`), 213 ExpectMsg: "failed decoding", 214 }, 215 } 216 217 for name, c := range cases { 218 t.Run(name, func(t *testing.T) { 219 req := c.Request 220 221 UnmarshalError(req) 222 if req.Error == nil { 223 t.Fatal("expect error, got none") 224 } 225 226 aerr := req.Error.(awserr.RequestFailure) 227 if e, a := request.ErrCodeSerialization, aerr.Code(); e != a { 228 t.Errorf("expect %v, got %v", e, a) 229 } 230 231 uerr := aerr.OrigErr().(awserr.UnmarshalError) 232 if e, a := c.ExpectMsg, uerr.Message(); !strings.Contains(a, e) { 233 t.Errorf("Expect %q, in %q", e, a) 234 } 235 if e, a := c.ExpectBytes, uerr.Bytes(); !bytes.Equal(e, a) { 236 t.Errorf("expect:\n%v\nactual:\n%v", hex.Dump(e), hex.Dump(a)) 237 } 238 }) 239 } 240} 241