mirror of https://github.com/restic/restic.git
423 lines
10 KiB
Go
423 lines
10 KiB
Go
package autorest
|
|
|
|
// Copyright 2017 Microsoft Corporation
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"encoding/xml"
|
|
"fmt"
|
|
"net/http"
|
|
"net/url"
|
|
"reflect"
|
|
"sort"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/Azure/go-autorest/autorest/mocks"
|
|
)
|
|
|
|
const (
|
|
jsonT = `
|
|
{
|
|
"name":"Rob Pike",
|
|
"age":42
|
|
}`
|
|
xmlT = `<?xml version="1.0" encoding="UTF-8"?>
|
|
<Person>
|
|
<Name>Rob Pike</Name>
|
|
<Age>42</Age>
|
|
</Person>`
|
|
)
|
|
|
|
func TestNewDecoderCreatesJSONDecoder(t *testing.T) {
|
|
d := NewDecoder(EncodedAsJSON, strings.NewReader(jsonT))
|
|
_, ok := d.(*json.Decoder)
|
|
if d == nil || !ok {
|
|
t.Fatal("autorest: NewDecoder failed to create a JSON decoder when requested")
|
|
}
|
|
}
|
|
|
|
func TestNewDecoderCreatesXMLDecoder(t *testing.T) {
|
|
d := NewDecoder(EncodedAsXML, strings.NewReader(xmlT))
|
|
_, ok := d.(*xml.Decoder)
|
|
if d == nil || !ok {
|
|
t.Fatal("autorest: NewDecoder failed to create an XML decoder when requested")
|
|
}
|
|
}
|
|
|
|
func TestNewDecoderReturnsNilForUnknownEncoding(t *testing.T) {
|
|
d := NewDecoder("unknown", strings.NewReader(xmlT))
|
|
if d != nil {
|
|
t.Fatal("autorest: NewDecoder created a decoder for an unknown encoding")
|
|
}
|
|
}
|
|
|
|
func TestCopyAndDecodeDecodesJSON(t *testing.T) {
|
|
_, err := CopyAndDecode(EncodedAsJSON, strings.NewReader(jsonT), &mocks.T{})
|
|
if err != nil {
|
|
t.Fatalf("autorest: CopyAndDecode returned an error with valid JSON - %v", err)
|
|
}
|
|
}
|
|
|
|
func TestCopyAndDecodeDecodesXML(t *testing.T) {
|
|
_, err := CopyAndDecode(EncodedAsXML, strings.NewReader(xmlT), &mocks.T{})
|
|
if err != nil {
|
|
t.Fatalf("autorest: CopyAndDecode returned an error with valid XML - %v", err)
|
|
}
|
|
}
|
|
|
|
func TestCopyAndDecodeReturnsJSONDecodingErrors(t *testing.T) {
|
|
_, err := CopyAndDecode(EncodedAsJSON, strings.NewReader(jsonT[0:len(jsonT)-2]), &mocks.T{})
|
|
if err == nil {
|
|
t.Fatalf("autorest: CopyAndDecode failed to return an error with invalid JSON")
|
|
}
|
|
}
|
|
|
|
func TestCopyAndDecodeReturnsXMLDecodingErrors(t *testing.T) {
|
|
_, err := CopyAndDecode(EncodedAsXML, strings.NewReader(xmlT[0:len(xmlT)-2]), &mocks.T{})
|
|
if err == nil {
|
|
t.Fatalf("autorest: CopyAndDecode failed to return an error with invalid XML")
|
|
}
|
|
}
|
|
|
|
func TestCopyAndDecodeAlwaysReturnsACopy(t *testing.T) {
|
|
b, _ := CopyAndDecode(EncodedAsJSON, strings.NewReader(jsonT), &mocks.T{})
|
|
if b.String() != jsonT {
|
|
t.Fatalf("autorest: CopyAndDecode failed to return a valid copy of the data - %v", b.String())
|
|
}
|
|
}
|
|
|
|
func TestTeeReadCloser_Copies(t *testing.T) {
|
|
v := &mocks.T{}
|
|
r := mocks.NewResponseWithContent(jsonT)
|
|
b := &bytes.Buffer{}
|
|
|
|
r.Body = TeeReadCloser(r.Body, b)
|
|
|
|
err := Respond(r,
|
|
ByUnmarshallingJSON(v),
|
|
ByClosing())
|
|
if err != nil {
|
|
t.Fatalf("autorest: TeeReadCloser returned an unexpected error -- %v", err)
|
|
}
|
|
if b.String() != jsonT {
|
|
t.Fatalf("autorest: TeeReadCloser failed to copy the bytes read")
|
|
}
|
|
}
|
|
|
|
func TestTeeReadCloser_PassesReadErrors(t *testing.T) {
|
|
v := &mocks.T{}
|
|
r := mocks.NewResponseWithContent(jsonT)
|
|
|
|
r.Body.(*mocks.Body).Close()
|
|
r.Body = TeeReadCloser(r.Body, &bytes.Buffer{})
|
|
|
|
err := Respond(r,
|
|
ByUnmarshallingJSON(v),
|
|
ByClosing())
|
|
if err == nil {
|
|
t.Fatalf("autorest: TeeReadCloser failed to return the expected error")
|
|
}
|
|
}
|
|
|
|
func TestTeeReadCloser_ClosesWrappedReader(t *testing.T) {
|
|
v := &mocks.T{}
|
|
r := mocks.NewResponseWithContent(jsonT)
|
|
|
|
b := r.Body.(*mocks.Body)
|
|
r.Body = TeeReadCloser(r.Body, &bytes.Buffer{})
|
|
err := Respond(r,
|
|
ByUnmarshallingJSON(v),
|
|
ByClosing())
|
|
if err != nil {
|
|
t.Fatalf("autorest: TeeReadCloser returned an unexpected error -- %v", err)
|
|
}
|
|
if b.IsOpen() {
|
|
t.Fatalf("autorest: TeeReadCloser failed to close the nested io.ReadCloser")
|
|
}
|
|
}
|
|
|
|
func TestContainsIntFindsValue(t *testing.T) {
|
|
ints := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
|
|
v := 5
|
|
if !containsInt(ints, v) {
|
|
t.Fatalf("autorest: containsInt failed to find %v in %v", v, ints)
|
|
}
|
|
}
|
|
|
|
func TestContainsIntDoesNotFindValue(t *testing.T) {
|
|
ints := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
|
|
v := 42
|
|
if containsInt(ints, v) {
|
|
t.Fatalf("autorest: containsInt unexpectedly found %v in %v", v, ints)
|
|
}
|
|
}
|
|
|
|
func TestContainsIntAcceptsEmptyList(t *testing.T) {
|
|
ints := make([]int, 10)
|
|
if containsInt(ints, 42) {
|
|
t.Fatalf("autorest: containsInt failed to handle an empty list")
|
|
}
|
|
}
|
|
|
|
func TestContainsIntAcceptsNilList(t *testing.T) {
|
|
var ints []int
|
|
if containsInt(ints, 42) {
|
|
t.Fatalf("autorest: containsInt failed to handle an nil list")
|
|
}
|
|
}
|
|
|
|
func TestEscapeStrings(t *testing.T) {
|
|
m := map[string]string{
|
|
"string": "a long string with = odd characters",
|
|
"int": "42",
|
|
"nil": "",
|
|
}
|
|
r := map[string]string{
|
|
"string": "a+long+string+with+%3D+odd+characters",
|
|
"int": "42",
|
|
"nil": "",
|
|
}
|
|
v := escapeValueStrings(m)
|
|
if !reflect.DeepEqual(v, r) {
|
|
t.Fatalf("autorest: ensureValueStrings returned %v\n", v)
|
|
}
|
|
}
|
|
|
|
func TestEnsureStrings(t *testing.T) {
|
|
m := map[string]interface{}{
|
|
"string": "string",
|
|
"int": 42,
|
|
"nil": nil,
|
|
"bytes": []byte{255, 254, 253},
|
|
}
|
|
r := map[string]string{
|
|
"string": "string",
|
|
"int": "42",
|
|
"nil": "",
|
|
"bytes": string([]byte{255, 254, 253}),
|
|
}
|
|
v := ensureValueStrings(m)
|
|
if !reflect.DeepEqual(v, r) {
|
|
t.Fatalf("autorest: ensureValueStrings returned %v\n", v)
|
|
}
|
|
}
|
|
|
|
func ExampleString() {
|
|
m := []string{
|
|
"string1",
|
|
"string2",
|
|
"string3",
|
|
}
|
|
|
|
fmt.Println(String(m, ","))
|
|
// Output: string1,string2,string3
|
|
}
|
|
|
|
func TestStringWithValidString(t *testing.T) {
|
|
i := 123
|
|
if got, want := String(i), "123"; got != want {
|
|
t.Logf("got: %q\nwant: %q", got, want)
|
|
t.Fail()
|
|
}
|
|
}
|
|
|
|
func TestStringWithStringSlice(t *testing.T) {
|
|
s := []string{"string1", "string2"}
|
|
if got, want := String(s, ","), "string1,string2"; got != want {
|
|
t.Logf("got: %q\nwant: %q", got, want)
|
|
t.Fail()
|
|
}
|
|
}
|
|
|
|
func TestStringWithEnum(t *testing.T) {
|
|
type TestEnumType string
|
|
s := TestEnumType("string1")
|
|
if got, want := String(s), "string1"; got != want {
|
|
t.Logf("got: %q\nwant: %q", got, want)
|
|
t.Fail()
|
|
}
|
|
}
|
|
|
|
func TestStringWithEnumSlice(t *testing.T) {
|
|
type TestEnumType string
|
|
s := []TestEnumType{"string1", "string2"}
|
|
if got, want := String(s, ","), "string1,string2"; got != want {
|
|
t.Logf("got: %q\nwant: %q", got, want)
|
|
t.Fail()
|
|
}
|
|
}
|
|
|
|
func ExampleAsStringSlice() {
|
|
type TestEnumType string
|
|
|
|
a := []TestEnumType{"value1", "value2"}
|
|
b, _ := AsStringSlice(a)
|
|
for _, c := range b {
|
|
fmt.Println(c)
|
|
}
|
|
// Output:
|
|
// value1
|
|
// value2
|
|
}
|
|
|
|
func TestEncodeWithValidPath(t *testing.T) {
|
|
s := Encode("Path", "Hello Gopher")
|
|
if s != "Hello%20Gopher" {
|
|
t.Fatalf("autorest: Encode method failed for valid path encoding. Got: %v; Want: %v", s, "Hello%20Gopher")
|
|
}
|
|
}
|
|
|
|
func TestEncodeWithValidQuery(t *testing.T) {
|
|
s := Encode("Query", "Hello Gopher")
|
|
if s != "Hello+Gopher" {
|
|
t.Fatalf("autorest: Encode method failed for valid query encoding. Got: '%v'; Want: 'Hello+Gopher'", s)
|
|
}
|
|
}
|
|
|
|
func TestEncodeWithValidNotPathQuery(t *testing.T) {
|
|
s := Encode("Host", "Hello Gopher")
|
|
if s != "Hello Gopher" {
|
|
t.Fatalf("autorest: Encode method failed for parameter not query or path. Got: '%v'; Want: 'Hello Gopher'", s)
|
|
}
|
|
}
|
|
|
|
func TestMapToValues(t *testing.T) {
|
|
m := map[string]interface{}{
|
|
"a": "a",
|
|
"b": 2,
|
|
}
|
|
v := url.Values{}
|
|
v.Add("a", "a")
|
|
v.Add("b", "2")
|
|
if !isEqual(v, MapToValues(m)) {
|
|
t.Fatalf("autorest: MapToValues method failed to return correct values - expected(%v) got(%v)", v, MapToValues(m))
|
|
}
|
|
}
|
|
|
|
func TestMapToValuesWithArrayValues(t *testing.T) {
|
|
m := map[string]interface{}{
|
|
"a": []string{"a", "b"},
|
|
"b": 2,
|
|
"c": []int{3, 4},
|
|
}
|
|
v := url.Values{}
|
|
v.Add("a", "a")
|
|
v.Add("a", "b")
|
|
v.Add("b", "2")
|
|
v.Add("c", "3")
|
|
v.Add("c", "4")
|
|
|
|
if !isEqual(v, MapToValues(m)) {
|
|
t.Fatalf("autorest: MapToValues method failed to return correct values - expected(%v) got(%v)", v, MapToValues(m))
|
|
}
|
|
}
|
|
|
|
func isEqual(v, u url.Values) bool {
|
|
for key, value := range v {
|
|
if len(u[key]) == 0 {
|
|
return false
|
|
}
|
|
sort.Strings(value)
|
|
sort.Strings(u[key])
|
|
for i := range value {
|
|
if value[i] != u[key][i] {
|
|
return false
|
|
}
|
|
}
|
|
u.Del(key)
|
|
}
|
|
if len(u) > 0 {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
func doEnsureBodyClosed(t *testing.T) SendDecorator {
|
|
return func(s Sender) Sender {
|
|
return SenderFunc(func(r *http.Request) (*http.Response, error) {
|
|
resp, err := s.Do(r)
|
|
if resp != nil && resp.Body != nil && resp.Body.(*mocks.Body).IsOpen() {
|
|
t.Fatal("autorest: Expected Body to be closed -- it was left open")
|
|
}
|
|
return resp, err
|
|
})
|
|
}
|
|
}
|
|
|
|
type mockAuthorizer struct{}
|
|
|
|
func (ma mockAuthorizer) WithAuthorization() PrepareDecorator {
|
|
return WithHeader(headerAuthorization, mocks.TestAuthorizationHeader)
|
|
}
|
|
|
|
type mockFailingAuthorizer struct{}
|
|
|
|
func (mfa mockFailingAuthorizer) WithAuthorization() PrepareDecorator {
|
|
return func(p Preparer) Preparer {
|
|
return PreparerFunc(func(r *http.Request) (*http.Request, error) {
|
|
return r, fmt.Errorf("ERROR: mockFailingAuthorizer returned expected error")
|
|
})
|
|
}
|
|
}
|
|
|
|
type mockInspector struct {
|
|
wasInvoked bool
|
|
}
|
|
|
|
func (mi *mockInspector) WithInspection() PrepareDecorator {
|
|
return func(p Preparer) Preparer {
|
|
return PreparerFunc(func(r *http.Request) (*http.Request, error) {
|
|
mi.wasInvoked = true
|
|
return p.Prepare(r)
|
|
})
|
|
}
|
|
}
|
|
|
|
func (mi *mockInspector) ByInspecting() RespondDecorator {
|
|
return func(r Responder) Responder {
|
|
return ResponderFunc(func(resp *http.Response) error {
|
|
mi.wasInvoked = true
|
|
return r.Respond(resp)
|
|
})
|
|
}
|
|
}
|
|
|
|
func withMessage(output *string, msg string) SendDecorator {
|
|
return func(s Sender) Sender {
|
|
return SenderFunc(func(r *http.Request) (*http.Response, error) {
|
|
resp, err := s.Do(r)
|
|
if err == nil {
|
|
*output += msg
|
|
}
|
|
return resp, err
|
|
})
|
|
}
|
|
}
|
|
|
|
func withErrorRespondDecorator(e *error) RespondDecorator {
|
|
return func(r Responder) Responder {
|
|
return ResponderFunc(func(resp *http.Response) error {
|
|
err := r.Respond(resp)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
*e = fmt.Errorf("autorest: Faux Respond Error")
|
|
return *e
|
|
})
|
|
}
|
|
}
|