1package autorest 2 3// Copyright 2017 Microsoft Corporation 4// 5// Licensed under the Apache License, Version 2.0 (the "License"); 6// you may not use this file except in compliance with the License. 7// You may obtain a copy of the License at 8// 9// http://www.apache.org/licenses/LICENSE-2.0 10// 11// Unless required by applicable law or agreed to in writing, software 12// distributed under the License is distributed on an "AS IS" BASIS, 13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14// See the License for the specific language governing permissions and 15// limitations under the License. 16 17import ( 18 "bytes" 19 "encoding/json" 20 "encoding/xml" 21 "errors" 22 "fmt" 23 "net/http" 24 "net/url" 25 "reflect" 26 "sort" 27 "strings" 28 "testing" 29 30 "github.com/Azure/go-autorest/autorest/mocks" 31) 32 33const ( 34 jsonT = ` 35 { 36 "name":"Rob Pike", 37 "age":42 38 }` 39 xmlT = `<?xml version="1.0" encoding="UTF-8"?> 40 <Person> 41 <Name>Rob Pike</Name> 42 <Age>42</Age> 43 </Person>` 44) 45 46func TestNewDecoderCreatesJSONDecoder(t *testing.T) { 47 d := NewDecoder(EncodedAsJSON, strings.NewReader(jsonT)) 48 _, ok := d.(*json.Decoder) 49 if d == nil || !ok { 50 t.Fatal("autorest: NewDecoder failed to create a JSON decoder when requested") 51 } 52} 53 54func TestNewDecoderCreatesXMLDecoder(t *testing.T) { 55 d := NewDecoder(EncodedAsXML, strings.NewReader(xmlT)) 56 _, ok := d.(*xml.Decoder) 57 if d == nil || !ok { 58 t.Fatal("autorest: NewDecoder failed to create an XML decoder when requested") 59 } 60} 61 62func TestNewDecoderReturnsNilForUnknownEncoding(t *testing.T) { 63 d := NewDecoder("unknown", strings.NewReader(xmlT)) 64 if d != nil { 65 t.Fatal("autorest: NewDecoder created a decoder for an unknown encoding") 66 } 67} 68 69func TestCopyAndDecodeDecodesJSON(t *testing.T) { 70 _, err := CopyAndDecode(EncodedAsJSON, strings.NewReader(jsonT), &mocks.T{}) 71 if err != nil { 72 t.Fatalf("autorest: CopyAndDecode returned an error with valid JSON - %v", err) 73 } 74} 75 76func TestCopyAndDecodeDecodesXML(t *testing.T) { 77 _, err := CopyAndDecode(EncodedAsXML, strings.NewReader(xmlT), &mocks.T{}) 78 if err != nil { 79 t.Fatalf("autorest: CopyAndDecode returned an error with valid XML - %v", err) 80 } 81} 82 83func TestCopyAndDecodeReturnsJSONDecodingErrors(t *testing.T) { 84 _, err := CopyAndDecode(EncodedAsJSON, strings.NewReader(jsonT[0:len(jsonT)-2]), &mocks.T{}) 85 if err == nil { 86 t.Fatalf("autorest: CopyAndDecode failed to return an error with invalid JSON") 87 } 88} 89 90func TestCopyAndDecodeReturnsXMLDecodingErrors(t *testing.T) { 91 _, err := CopyAndDecode(EncodedAsXML, strings.NewReader(xmlT[0:len(xmlT)-2]), &mocks.T{}) 92 if err == nil { 93 t.Fatalf("autorest: CopyAndDecode failed to return an error with invalid XML") 94 } 95} 96 97func TestCopyAndDecodeAlwaysReturnsACopy(t *testing.T) { 98 b, _ := CopyAndDecode(EncodedAsJSON, strings.NewReader(jsonT), &mocks.T{}) 99 if b.String() != jsonT { 100 t.Fatalf("autorest: CopyAndDecode failed to return a valid copy of the data - %v", b.String()) 101 } 102} 103 104func TestTeeReadCloser_Copies(t *testing.T) { 105 v := &mocks.T{} 106 r := mocks.NewResponseWithContent(jsonT) 107 b := &bytes.Buffer{} 108 109 r.Body = TeeReadCloser(r.Body, b) 110 111 err := Respond(r, 112 ByUnmarshallingJSON(v), 113 ByClosing()) 114 if err != nil { 115 t.Fatalf("autorest: TeeReadCloser returned an unexpected error -- %v", err) 116 } 117 if b.String() != jsonT { 118 t.Fatalf("autorest: TeeReadCloser failed to copy the bytes read") 119 } 120} 121 122func TestTeeReadCloser_PassesReadErrors(t *testing.T) { 123 v := &mocks.T{} 124 r := mocks.NewResponseWithContent(jsonT) 125 126 r.Body.(*mocks.Body).Close() 127 r.Body = TeeReadCloser(r.Body, &bytes.Buffer{}) 128 129 err := Respond(r, 130 ByUnmarshallingJSON(v), 131 ByClosing()) 132 if err == nil { 133 t.Fatalf("autorest: TeeReadCloser failed to return the expected error") 134 } 135} 136 137func TestTeeReadCloser_ClosesWrappedReader(t *testing.T) { 138 v := &mocks.T{} 139 r := mocks.NewResponseWithContent(jsonT) 140 141 b := r.Body.(*mocks.Body) 142 r.Body = TeeReadCloser(r.Body, &bytes.Buffer{}) 143 err := Respond(r, 144 ByUnmarshallingJSON(v), 145 ByClosing()) 146 if err != nil { 147 t.Fatalf("autorest: TeeReadCloser returned an unexpected error -- %v", err) 148 } 149 if b.IsOpen() { 150 t.Fatalf("autorest: TeeReadCloser failed to close the nested io.ReadCloser") 151 } 152} 153 154func TestContainsIntFindsValue(t *testing.T) { 155 ints := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} 156 v := 5 157 if !containsInt(ints, v) { 158 t.Fatalf("autorest: containsInt failed to find %v in %v", v, ints) 159 } 160} 161 162func TestContainsIntDoesNotFindValue(t *testing.T) { 163 ints := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} 164 v := 42 165 if containsInt(ints, v) { 166 t.Fatalf("autorest: containsInt unexpectedly found %v in %v", v, ints) 167 } 168} 169 170func TestContainsIntAcceptsEmptyList(t *testing.T) { 171 ints := make([]int, 10) 172 if containsInt(ints, 42) { 173 t.Fatalf("autorest: containsInt failed to handle an empty list") 174 } 175} 176 177func TestContainsIntAcceptsNilList(t *testing.T) { 178 var ints []int 179 if containsInt(ints, 42) { 180 t.Fatalf("autorest: containsInt failed to handle an nil list") 181 } 182} 183 184func TestEscapeStrings(t *testing.T) { 185 m := map[string]string{ 186 "string": "a long string with = odd characters", 187 "int": "42", 188 "nil": "", 189 } 190 r := map[string]string{ 191 "string": "a+long+string+with+%3D+odd+characters", 192 "int": "42", 193 "nil": "", 194 } 195 v := escapeValueStrings(m) 196 if !reflect.DeepEqual(v, r) { 197 t.Fatalf("autorest: ensureValueStrings returned %v\n", v) 198 } 199} 200 201func TestEnsureStrings(t *testing.T) { 202 m := map[string]interface{}{ 203 "string": "string", 204 "int": 42, 205 "nil": nil, 206 "bytes": []byte{255, 254, 253}, 207 } 208 r := map[string]string{ 209 "string": "string", 210 "int": "42", 211 "nil": "", 212 "bytes": string([]byte{255, 254, 253}), 213 } 214 v := ensureValueStrings(m) 215 if !reflect.DeepEqual(v, r) { 216 t.Fatalf("autorest: ensureValueStrings returned %v\n", v) 217 } 218} 219 220func ExampleString() { 221 m := []string{ 222 "string1", 223 "string2", 224 "string3", 225 } 226 227 fmt.Println(String(m, ",")) 228 // Output: string1,string2,string3 229} 230 231func TestStringWithValidString(t *testing.T) { 232 i := 123 233 if got, want := String(i), "123"; got != want { 234 t.Logf("got: %q\nwant: %q", got, want) 235 t.Fail() 236 } 237} 238 239func TestStringWithStringSlice(t *testing.T) { 240 s := []string{"string1", "string2"} 241 if got, want := String(s, ","), "string1,string2"; got != want { 242 t.Logf("got: %q\nwant: %q", got, want) 243 t.Fail() 244 } 245} 246 247func TestStringWithEnum(t *testing.T) { 248 type TestEnumType string 249 s := TestEnumType("string1") 250 if got, want := String(s), "string1"; got != want { 251 t.Logf("got: %q\nwant: %q", got, want) 252 t.Fail() 253 } 254} 255 256func TestStringWithEnumSlice(t *testing.T) { 257 type TestEnumType string 258 s := []TestEnumType{"string1", "string2"} 259 if got, want := String(s, ","), "string1,string2"; got != want { 260 t.Logf("got: %q\nwant: %q", got, want) 261 t.Fail() 262 } 263} 264 265func ExampleAsStringSlice() { 266 type TestEnumType string 267 268 a := []TestEnumType{"value1", "value2"} 269 b, _ := AsStringSlice(a) 270 for _, c := range b { 271 fmt.Println(c) 272 } 273 // Output: 274 // value1 275 // value2 276} 277 278func TestEncodeWithValidPath(t *testing.T) { 279 s := Encode("Path", "Hello Gopher") 280 if s != "Hello%20Gopher" { 281 t.Fatalf("autorest: Encode method failed for valid path encoding. Got: %v; Want: %v", s, "Hello%20Gopher") 282 } 283} 284 285func TestEncodeWithValidQuery(t *testing.T) { 286 s := Encode("Query", "Hello Gopher") 287 if s != "Hello+Gopher" { 288 t.Fatalf("autorest: Encode method failed for valid query encoding. Got: '%v'; Want: 'Hello+Gopher'", s) 289 } 290} 291 292func TestEncodeWithValidNotPathQuery(t *testing.T) { 293 s := Encode("Host", "Hello Gopher") 294 if s != "Hello Gopher" { 295 t.Fatalf("autorest: Encode method failed for parameter not query or path. Got: '%v'; Want: 'Hello Gopher'", s) 296 } 297} 298 299func TestMapToValues(t *testing.T) { 300 m := map[string]interface{}{ 301 "a": "a", 302 "b": 2, 303 } 304 v := url.Values{} 305 v.Add("a", "a") 306 v.Add("b", "2") 307 if !isEqual(v, MapToValues(m)) { 308 t.Fatalf("autorest: MapToValues method failed to return correct values - expected(%v) got(%v)", v, MapToValues(m)) 309 } 310} 311 312func TestMapToValuesWithArrayValues(t *testing.T) { 313 m := map[string]interface{}{ 314 "a": []string{"a", "b"}, 315 "b": 2, 316 "c": []int{3, 4}, 317 } 318 v := url.Values{} 319 v.Add("a", "a") 320 v.Add("a", "b") 321 v.Add("b", "2") 322 v.Add("c", "3") 323 v.Add("c", "4") 324 325 if !isEqual(v, MapToValues(m)) { 326 t.Fatalf("autorest: MapToValues method failed to return correct values - expected(%v) got(%v)", v, MapToValues(m)) 327 } 328} 329 330type someTempError struct{} 331 332func (s someTempError) Error() string { 333 return "temporary error" 334} 335func (s someTempError) Timeout() bool { 336 return true 337} 338func (s someTempError) Temporary() bool { 339 return true 340} 341 342func TestIsTemporaryNetworkErrorTrue(t *testing.T) { 343 if !IsTemporaryNetworkError(someTempError{}) { 344 t.Fatal("expected someTempError to be a temporary network error") 345 } 346 if !IsTemporaryNetworkError(errors.New("non-temporary network error")) { 347 t.Fatal("expected random error to be a temporary network error") 348 } 349} 350 351type someFatalError struct{} 352 353func (s someFatalError) Error() string { 354 return "fatal error" 355} 356func (s someFatalError) Timeout() bool { 357 return false 358} 359func (s someFatalError) Temporary() bool { 360 return false 361} 362 363func TestIsTemporaryNetworkErrorFalse(t *testing.T) { 364 if IsTemporaryNetworkError(someFatalError{}) { 365 t.Fatal("expected someFatalError to be a fatal network error") 366 } 367} 368 369func isEqual(v, u url.Values) bool { 370 for key, value := range v { 371 if len(u[key]) == 0 { 372 return false 373 } 374 sort.Strings(value) 375 sort.Strings(u[key]) 376 for i := range value { 377 if value[i] != u[key][i] { 378 return false 379 } 380 } 381 u.Del(key) 382 } 383 if len(u) > 0 { 384 return false 385 } 386 return true 387} 388 389func doEnsureBodyClosed(t *testing.T) SendDecorator { 390 return func(s Sender) Sender { 391 return SenderFunc(func(r *http.Request) (*http.Response, error) { 392 resp, err := s.Do(r) 393 if resp != nil && resp.Body != nil && resp.Body.(*mocks.Body).IsOpen() { 394 t.Fatal("autorest: Expected Body to be closed -- it was left open") 395 } 396 return resp, err 397 }) 398 } 399} 400 401type mockAuthorizer struct{} 402 403func (ma mockAuthorizer) WithAuthorization() PrepareDecorator { 404 return WithHeader(headerAuthorization, mocks.TestAuthorizationHeader) 405} 406 407type mockFailingAuthorizer struct{} 408 409func (mfa mockFailingAuthorizer) WithAuthorization() PrepareDecorator { 410 return func(p Preparer) Preparer { 411 return PreparerFunc(func(r *http.Request) (*http.Request, error) { 412 return r, fmt.Errorf("ERROR: mockFailingAuthorizer returned expected error") 413 }) 414 } 415} 416 417type mockInspector struct { 418 wasInvoked bool 419} 420 421func (mi *mockInspector) WithInspection() PrepareDecorator { 422 return func(p Preparer) Preparer { 423 return PreparerFunc(func(r *http.Request) (*http.Request, error) { 424 mi.wasInvoked = true 425 return p.Prepare(r) 426 }) 427 } 428} 429 430func (mi *mockInspector) ByInspecting() RespondDecorator { 431 return func(r Responder) Responder { 432 return ResponderFunc(func(resp *http.Response) error { 433 mi.wasInvoked = true 434 return r.Respond(resp) 435 }) 436 } 437} 438 439func withMessage(output *string, msg string) SendDecorator { 440 return func(s Sender) Sender { 441 return SenderFunc(func(r *http.Request) (*http.Response, error) { 442 resp, err := s.Do(r) 443 if err == nil { 444 *output += msg 445 } 446 return resp, err 447 }) 448 } 449} 450 451func withErrorRespondDecorator(e *error) RespondDecorator { 452 return func(r Responder) Responder { 453 return ResponderFunc(func(resp *http.Response) error { 454 err := r.Respond(resp) 455 if err != nil { 456 return err 457 } 458 *e = fmt.Errorf("autorest: Faux Respond Error") 459 return *e 460 }) 461 } 462} 463