forked from TrueCloudLab/restic
291 lines
6.4 KiB
Go
291 lines
6.4 KiB
Go
// Copyright 2011 Google Inc. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package googleapi
|
|
|
|
import (
|
|
"encoding/json"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"net/url"
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
type ExpandTest struct {
|
|
in string
|
|
expansions map[string]string
|
|
want string
|
|
}
|
|
|
|
var expandTests = []ExpandTest{
|
|
// no expansions
|
|
{
|
|
"http://www.golang.org/",
|
|
map[string]string{},
|
|
"http://www.golang.org/",
|
|
},
|
|
// one expansion, no escaping
|
|
{
|
|
"http://www.golang.org/{bucket}/delete",
|
|
map[string]string{
|
|
"bucket": "red",
|
|
},
|
|
"http://www.golang.org/red/delete",
|
|
},
|
|
// one expansion, with hex escapes
|
|
{
|
|
"http://www.golang.org/{bucket}/delete",
|
|
map[string]string{
|
|
"bucket": "red/blue",
|
|
},
|
|
"http://www.golang.org/red%2Fblue/delete",
|
|
},
|
|
// one expansion, with space
|
|
{
|
|
"http://www.golang.org/{bucket}/delete",
|
|
map[string]string{
|
|
"bucket": "red or blue",
|
|
},
|
|
"http://www.golang.org/red%20or%20blue/delete",
|
|
},
|
|
// expansion not found
|
|
{
|
|
"http://www.golang.org/{object}/delete",
|
|
map[string]string{
|
|
"bucket": "red or blue",
|
|
},
|
|
"http://www.golang.org//delete",
|
|
},
|
|
// multiple expansions
|
|
{
|
|
"http://www.golang.org/{one}/{two}/{three}/get",
|
|
map[string]string{
|
|
"one": "ONE",
|
|
"two": "TWO",
|
|
"three": "THREE",
|
|
},
|
|
"http://www.golang.org/ONE/TWO/THREE/get",
|
|
},
|
|
// utf-8 characters
|
|
{
|
|
"http://www.golang.org/{bucket}/get",
|
|
map[string]string{
|
|
"bucket": "£100",
|
|
},
|
|
"http://www.golang.org/%C2%A3100/get",
|
|
},
|
|
// punctuations
|
|
{
|
|
"http://www.golang.org/{bucket}/get",
|
|
map[string]string{
|
|
"bucket": `/\@:,.`,
|
|
},
|
|
"http://www.golang.org/%2F%5C%40%3A%2C./get",
|
|
},
|
|
// mis-matched brackets
|
|
{
|
|
"http://www.golang.org/{bucket/get",
|
|
map[string]string{
|
|
"bucket": "red",
|
|
},
|
|
"http://www.golang.org/%7Bbucket/get",
|
|
},
|
|
// "+" prefix for suppressing escape
|
|
// See also: http://tools.ietf.org/html/rfc6570#section-3.2.3
|
|
{
|
|
"http://www.golang.org/{+topic}",
|
|
map[string]string{
|
|
"topic": "/topics/myproject/mytopic",
|
|
},
|
|
// The double slashes here look weird, but it's intentional
|
|
"http://www.golang.org//topics/myproject/mytopic",
|
|
},
|
|
}
|
|
|
|
func TestExpand(t *testing.T) {
|
|
for i, test := range expandTests {
|
|
u := url.URL{
|
|
Path: test.in,
|
|
}
|
|
Expand(&u, test.expansions)
|
|
got := u.EscapedPath()
|
|
if got != test.want {
|
|
t.Errorf("got %q expected %q in test %d", got, test.want, i+1)
|
|
}
|
|
}
|
|
}
|
|
|
|
type CheckResponseTest struct {
|
|
in *http.Response
|
|
bodyText string
|
|
want error
|
|
errText string
|
|
}
|
|
|
|
var checkResponseTests = []CheckResponseTest{
|
|
{
|
|
&http.Response{
|
|
StatusCode: http.StatusOK,
|
|
},
|
|
"",
|
|
nil,
|
|
"",
|
|
},
|
|
{
|
|
&http.Response{
|
|
StatusCode: http.StatusInternalServerError,
|
|
},
|
|
`{"error":{}}`,
|
|
&Error{
|
|
Code: http.StatusInternalServerError,
|
|
Body: `{"error":{}}`,
|
|
},
|
|
`googleapi: got HTTP response code 500 with body: {"error":{}}`,
|
|
},
|
|
{
|
|
&http.Response{
|
|
StatusCode: http.StatusNotFound,
|
|
},
|
|
`{"error":{"message":"Error message for StatusNotFound."}}`,
|
|
&Error{
|
|
Code: http.StatusNotFound,
|
|
Message: "Error message for StatusNotFound.",
|
|
Body: `{"error":{"message":"Error message for StatusNotFound."}}`,
|
|
},
|
|
"googleapi: Error 404: Error message for StatusNotFound.",
|
|
},
|
|
{
|
|
&http.Response{
|
|
StatusCode: http.StatusBadRequest,
|
|
},
|
|
`{"error":"invalid_token","error_description":"Invalid Value"}`,
|
|
&Error{
|
|
Code: http.StatusBadRequest,
|
|
Body: `{"error":"invalid_token","error_description":"Invalid Value"}`,
|
|
},
|
|
`googleapi: got HTTP response code 400 with body: {"error":"invalid_token","error_description":"Invalid Value"}`,
|
|
},
|
|
{
|
|
&http.Response{
|
|
StatusCode: http.StatusBadRequest,
|
|
},
|
|
`{"error":{"errors":[{"domain":"usageLimits","reason":"keyInvalid","message":"Bad Request"}],"code":400,"message":"Bad Request"}}`,
|
|
&Error{
|
|
Code: http.StatusBadRequest,
|
|
Errors: []ErrorItem{
|
|
{
|
|
Reason: "keyInvalid",
|
|
Message: "Bad Request",
|
|
},
|
|
},
|
|
Body: `{"error":{"errors":[{"domain":"usageLimits","reason":"keyInvalid","message":"Bad Request"}],"code":400,"message":"Bad Request"}}`,
|
|
Message: "Bad Request",
|
|
},
|
|
"googleapi: Error 400: Bad Request, keyInvalid",
|
|
},
|
|
}
|
|
|
|
func TestCheckResponse(t *testing.T) {
|
|
for _, test := range checkResponseTests {
|
|
res := test.in
|
|
if test.bodyText != "" {
|
|
res.Body = ioutil.NopCloser(strings.NewReader(test.bodyText))
|
|
}
|
|
g := CheckResponse(res)
|
|
if !reflect.DeepEqual(g, test.want) {
|
|
t.Errorf("CheckResponse: got %v, want %v", g, test.want)
|
|
gotJson, err := json.Marshal(g)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
wantJson, err := json.Marshal(test.want)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
t.Errorf("json(got): %q\njson(want): %q", string(gotJson), string(wantJson))
|
|
}
|
|
if g != nil && g.Error() != test.errText {
|
|
t.Errorf("CheckResponse: unexpected error message.\nGot: %q\nwant: %q", g, test.errText)
|
|
}
|
|
}
|
|
}
|
|
|
|
type VariantPoint struct {
|
|
Type string
|
|
Coordinates []float64
|
|
}
|
|
|
|
type VariantTest struct {
|
|
in map[string]interface{}
|
|
result bool
|
|
want VariantPoint
|
|
}
|
|
|
|
var coords = []interface{}{1.0, 2.0}
|
|
|
|
var variantTests = []VariantTest{
|
|
{
|
|
in: map[string]interface{}{
|
|
"type": "Point",
|
|
"coordinates": coords,
|
|
},
|
|
result: true,
|
|
want: VariantPoint{
|
|
Type: "Point",
|
|
Coordinates: []float64{1.0, 2.0},
|
|
},
|
|
},
|
|
{
|
|
in: map[string]interface{}{
|
|
"type": "Point",
|
|
"bogus": coords,
|
|
},
|
|
result: true,
|
|
want: VariantPoint{
|
|
Type: "Point",
|
|
},
|
|
},
|
|
}
|
|
|
|
func TestVariantType(t *testing.T) {
|
|
for _, test := range variantTests {
|
|
if g := VariantType(test.in); g != test.want.Type {
|
|
t.Errorf("VariantType(%v): got %v, want %v", test.in, g, test.want.Type)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestConvertVariant(t *testing.T) {
|
|
for _, test := range variantTests {
|
|
g := VariantPoint{}
|
|
r := ConvertVariant(test.in, &g)
|
|
if r != test.result {
|
|
t.Errorf("ConvertVariant(%v): got %v, want %v", test.in, r, test.result)
|
|
}
|
|
if !reflect.DeepEqual(g, test.want) {
|
|
t.Errorf("ConvertVariant(%v): got %v, want %v", test.in, g, test.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestRoundChunkSize(t *testing.T) {
|
|
type testCase struct {
|
|
in int
|
|
want int
|
|
}
|
|
for _, tc := range []testCase{
|
|
{0, 0},
|
|
{256*1024 - 1, 256 * 1024},
|
|
{256 * 1024, 256 * 1024},
|
|
{256*1024 + 1, 2 * 256 * 1024},
|
|
} {
|
|
mo := &MediaOptions{}
|
|
ChunkSize(tc.in).setOptions(mo)
|
|
if got := mo.ChunkSize; got != tc.want {
|
|
t.Errorf("rounding chunk size: got: %v; want %v", got, tc.want)
|
|
}
|
|
}
|
|
}
|