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