...

Source file src/github.com/Azure/go-autorest/autorest/utility_test.go

Documentation: github.com/Azure/go-autorest/autorest

     1  package 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  
    17  import (
    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  
    35  const (
    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  
    48  func 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  
    56  func 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  
    64  func 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  
    71  func 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  
    78  func 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  
    85  func 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  
    92  func 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  
    99  func 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  
   106  func 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  
   124  func 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  
   139  func 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  
   156  func 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  
   164  func 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  
   172  func 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  
   179  func 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  
   186  func 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  
   203  func 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  
   222  func ExampleString() {
   223  	m := []string{
   224  		"string1",
   225  		"string2",
   226  		"string3",
   227  	}
   228  
   229  	fmt.Println(String(m, ","))
   230  	// Output: string1,string2,string3
   231  }
   232  
   233  func 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  
   241  func 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  
   249  func 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  
   258  func 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  
   267  func 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  
   276  func 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  
   289  func 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  
   296  func 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  
   303  func 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  
   310  func 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  
   323  func 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  
   341  type someTempError struct{}
   342  
   343  func (s someTempError) Error() string {
   344  	return "temporary error"
   345  }
   346  func (s someTempError) Timeout() bool {
   347  	return true
   348  }
   349  func (s someTempError) Temporary() bool {
   350  	return true
   351  }
   352  
   353  func 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  
   362  type someFatalError struct{}
   363  
   364  func (s someFatalError) Error() string {
   365  	return "fatal error"
   366  }
   367  func (s someFatalError) Timeout() bool {
   368  	return false
   369  }
   370  func (s someFatalError) Temporary() bool {
   371  	return false
   372  }
   373  
   374  func TestIsTemporaryNetworkErrorFalse(t *testing.T) {
   375  	if IsTemporaryNetworkError(someFatalError{}) {
   376  		t.Fatal("expected someFatalError to be a fatal network error")
   377  	}
   378  }
   379  
   380  type tokenRefreshError struct{}
   381  
   382  func (t tokenRefreshError) Error() string {
   383  	return "empty"
   384  }
   385  
   386  func (t tokenRefreshError) Response() *http.Response {
   387  	return nil
   388  }
   389  
   390  var _ adal.TokenRefreshError = (*tokenRefreshError)(nil)
   391  
   392  func 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  
   411  func 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  
   431  func 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  
   443  type mockAuthorizer struct{}
   444  
   445  func (ma mockAuthorizer) WithAuthorization() PrepareDecorator {
   446  	return WithHeader(headerAuthorization, mocks.TestAuthorizationHeader)
   447  }
   448  
   449  type mockFailingAuthorizer struct{}
   450  
   451  func (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  
   459  type mockInspector struct {
   460  	wasInvoked bool
   461  }
   462  
   463  func (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  
   472  func (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  
   481  func 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  
   493  func 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  
   506  type mockDrain struct {
   507  	read   bool
   508  	closed bool
   509  }
   510  
   511  func (md *mockDrain) Read(b []byte) (int, error) {
   512  	md.read = true
   513  	b = append(b, 0xff)
   514  	return 1, io.EOF
   515  }
   516  
   517  func (md *mockDrain) Close() error {
   518  	md.closed = true
   519  	return nil
   520  }
   521  
   522  func 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  

View as plain text