pkg/types: add URLs tests

This commit is contained in:
Yicheng Qin 2015-01-10 14:02:32 -08:00
parent 886a6a6194
commit 190fd446f9
6 changed files with 233 additions and 62 deletions

View File

@ -37,6 +37,7 @@ import (
"github.com/coreos/etcd/etcdserver"
"github.com/coreos/etcd/etcdserver/etcdhttp/httptypes"
"github.com/coreos/etcd/etcdserver/etcdserverpb"
"github.com/coreos/etcd/pkg/testutil"
"github.com/coreos/etcd/pkg/types"
"github.com/coreos/etcd/raft/raftpb"
"github.com/coreos/etcd/store"
@ -54,7 +55,7 @@ func mustMarshalEvent(t *testing.T, ev *store.Event) string {
// mustNewForm takes a set of Values and constructs a PUT *http.Request,
// with a URL constructed from appending the given path to the standard keysPrefix
func mustNewForm(t *testing.T, p string, vals url.Values) *http.Request {
u := mustNewURL(t, path.Join(keysPrefix, p))
u := testutil.MustNewURL(t, path.Join(keysPrefix, p))
req, err := http.NewRequest("PUT", u.String(), strings.NewReader(vals.Encode()))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
if err != nil {
@ -66,7 +67,7 @@ func mustNewForm(t *testing.T, p string, vals url.Values) *http.Request {
// mustNewPostForm takes a set of Values and constructs a POST *http.Request,
// with a URL constructed from appending the given path to the standard keysPrefix
func mustNewPostForm(t *testing.T, p string, vals url.Values) *http.Request {
u := mustNewURL(t, path.Join(keysPrefix, p))
u := testutil.MustNewURL(t, path.Join(keysPrefix, p))
req, err := http.NewRequest("POST", u.String(), strings.NewReader(vals.Encode()))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
if err != nil {
@ -84,7 +85,7 @@ func mustNewRequest(t *testing.T, p string) *http.Request {
func mustNewMethodRequest(t *testing.T, m, p string) *http.Request {
return &http.Request{
Method: m,
URL: mustNewURL(t, path.Join(keysPrefix, p)),
URL: testutil.MustNewURL(t, path.Join(keysPrefix, p)),
}
}
@ -186,7 +187,7 @@ func TestBadParseRequest(t *testing.T) {
{
// bad key prefix
&http.Request{
URL: mustNewURL(t, "/badprefix/"),
URL: testutil.MustNewURL(t, "/badprefix/"),
},
etcdErr.EcodeInvalidForm,
},
@ -582,7 +583,7 @@ func TestServeMembers(t *testing.T) {
}
for i, tt := range tests {
req, err := http.NewRequest("GET", mustNewURL(t, tt.path).String(), nil)
req, err := http.NewRequest("GET", testutil.MustNewURL(t, tt.path).String(), nil)
if err != nil {
t.Fatal(err)
}
@ -633,7 +634,7 @@ func TestServeLeader(t *testing.T) {
}
for i, tt := range tests {
req, err := http.NewRequest("GET", mustNewURL(t, tt.path).String(), nil)
req, err := http.NewRequest("GET", testutil.MustNewURL(t, tt.path).String(), nil)
if err != nil {
t.Fatal(err)
}
@ -658,7 +659,7 @@ func TestServeLeader(t *testing.T) {
}
func TestServeMembersCreate(t *testing.T) {
u := mustNewURL(t, membersPrefix)
u := testutil.MustNewURL(t, membersPrefix)
b := []byte(`{"peerURLs":["http://127.0.0.1:1"]}`)
req, err := http.NewRequest("POST", u.String(), bytes.NewReader(b))
if err != nil {
@ -712,7 +713,7 @@ func TestServeMembersCreate(t *testing.T) {
func TestServeMembersDelete(t *testing.T) {
req := &http.Request{
Method: "DELETE",
URL: mustNewURL(t, path.Join(membersPrefix, "BEEF")),
URL: testutil.MustNewURL(t, path.Join(membersPrefix, "BEEF")),
}
s := &serverRecorder{}
h := &membersHandler{
@ -743,7 +744,7 @@ func TestServeMembersDelete(t *testing.T) {
}
func TestServeMembersUpdate(t *testing.T) {
u := mustNewURL(t, path.Join(membersPrefix, "1"))
u := testutil.MustNewURL(t, path.Join(membersPrefix, "1"))
b := []byte(`{"peerURLs":["http://127.0.0.1:1"]}`)
req, err := http.NewRequest("PUT", u.String(), bytes.NewReader(b))
if err != nil {
@ -812,7 +813,7 @@ func TestServeMembersFail(t *testing.T) {
{
// parse body error
&http.Request{
URL: mustNewURL(t, membersPrefix),
URL: testutil.MustNewURL(t, membersPrefix),
Method: "POST",
Body: ioutil.NopCloser(strings.NewReader("bad json")),
Header: map[string][]string{"Content-Type": []string{"application/json"}},
@ -824,7 +825,7 @@ func TestServeMembersFail(t *testing.T) {
{
// bad content type
&http.Request{
URL: mustNewURL(t, membersPrefix),
URL: testutil.MustNewURL(t, membersPrefix),
Method: "POST",
Body: ioutil.NopCloser(strings.NewReader(`{"PeerURLs": ["http://127.0.0.1:1"]}`)),
Header: map[string][]string{"Content-Type": []string{"application/bad"}},
@ -836,7 +837,7 @@ func TestServeMembersFail(t *testing.T) {
{
// bad url
&http.Request{
URL: mustNewURL(t, membersPrefix),
URL: testutil.MustNewURL(t, membersPrefix),
Method: "POST",
Body: ioutil.NopCloser(strings.NewReader(`{"PeerURLs": ["http://a"]}`)),
Header: map[string][]string{"Content-Type": []string{"application/json"}},
@ -848,7 +849,7 @@ func TestServeMembersFail(t *testing.T) {
{
// etcdserver.AddMember error
&http.Request{
URL: mustNewURL(t, membersPrefix),
URL: testutil.MustNewURL(t, membersPrefix),
Method: "POST",
Body: ioutil.NopCloser(strings.NewReader(`{"PeerURLs": ["http://127.0.0.1:1"]}`)),
Header: map[string][]string{"Content-Type": []string{"application/json"}},
@ -862,7 +863,7 @@ func TestServeMembersFail(t *testing.T) {
{
// etcdserver.AddMember error
&http.Request{
URL: mustNewURL(t, membersPrefix),
URL: testutil.MustNewURL(t, membersPrefix),
Method: "POST",
Body: ioutil.NopCloser(strings.NewReader(`{"PeerURLs": ["http://127.0.0.1:1"]}`)),
Header: map[string][]string{"Content-Type": []string{"application/json"}},
@ -876,7 +877,7 @@ func TestServeMembersFail(t *testing.T) {
{
// etcdserver.AddMember error
&http.Request{
URL: mustNewURL(t, membersPrefix),
URL: testutil.MustNewURL(t, membersPrefix),
Method: "POST",
Body: ioutil.NopCloser(strings.NewReader(`{"PeerURLs": ["http://127.0.0.1:1"]}`)),
Header: map[string][]string{"Content-Type": []string{"application/json"}},
@ -890,7 +891,7 @@ func TestServeMembersFail(t *testing.T) {
{
// etcdserver.RemoveMember error with arbitrary server error
&http.Request{
URL: mustNewURL(t, path.Join(membersPrefix, "1")),
URL: testutil.MustNewURL(t, path.Join(membersPrefix, "1")),
Method: "DELETE",
},
&errServer{
@ -902,7 +903,7 @@ func TestServeMembersFail(t *testing.T) {
{
// etcdserver.RemoveMember error with previously removed ID
&http.Request{
URL: mustNewURL(t, path.Join(membersPrefix, "0")),
URL: testutil.MustNewURL(t, path.Join(membersPrefix, "0")),
Method: "DELETE",
},
&errServer{
@ -914,7 +915,7 @@ func TestServeMembersFail(t *testing.T) {
{
// etcdserver.RemoveMember error with nonexistent ID
&http.Request{
URL: mustNewURL(t, path.Join(membersPrefix, "0")),
URL: testutil.MustNewURL(t, path.Join(membersPrefix, "0")),
Method: "DELETE",
},
&errServer{
@ -926,7 +927,7 @@ func TestServeMembersFail(t *testing.T) {
{
// etcdserver.RemoveMember error with badly formed ID
&http.Request{
URL: mustNewURL(t, path.Join(membersPrefix, "bad_id")),
URL: testutil.MustNewURL(t, path.Join(membersPrefix, "bad_id")),
Method: "DELETE",
},
nil,
@ -936,7 +937,7 @@ func TestServeMembersFail(t *testing.T) {
{
// etcdserver.RemoveMember with no ID
&http.Request{
URL: mustNewURL(t, membersPrefix),
URL: testutil.MustNewURL(t, membersPrefix),
Method: "DELETE",
},
nil,
@ -946,7 +947,7 @@ func TestServeMembersFail(t *testing.T) {
{
// parse body error
&http.Request{
URL: mustNewURL(t, path.Join(membersPrefix, "0")),
URL: testutil.MustNewURL(t, path.Join(membersPrefix, "0")),
Method: "PUT",
Body: ioutil.NopCloser(strings.NewReader("bad json")),
Header: map[string][]string{"Content-Type": []string{"application/json"}},
@ -958,7 +959,7 @@ func TestServeMembersFail(t *testing.T) {
{
// bad content type
&http.Request{
URL: mustNewURL(t, path.Join(membersPrefix, "0")),
URL: testutil.MustNewURL(t, path.Join(membersPrefix, "0")),
Method: "PUT",
Body: ioutil.NopCloser(strings.NewReader(`{"PeerURLs": ["http://127.0.0.1:1"]}`)),
Header: map[string][]string{"Content-Type": []string{"application/bad"}},
@ -970,7 +971,7 @@ func TestServeMembersFail(t *testing.T) {
{
// bad url
&http.Request{
URL: mustNewURL(t, path.Join(membersPrefix, "0")),
URL: testutil.MustNewURL(t, path.Join(membersPrefix, "0")),
Method: "PUT",
Body: ioutil.NopCloser(strings.NewReader(`{"PeerURLs": ["http://a"]}`)),
Header: map[string][]string{"Content-Type": []string{"application/json"}},
@ -982,7 +983,7 @@ func TestServeMembersFail(t *testing.T) {
{
// etcdserver.UpdateMember error
&http.Request{
URL: mustNewURL(t, path.Join(membersPrefix, "0")),
URL: testutil.MustNewURL(t, path.Join(membersPrefix, "0")),
Method: "PUT",
Body: ioutil.NopCloser(strings.NewReader(`{"PeerURLs": ["http://127.0.0.1:1"]}`)),
Header: map[string][]string{"Content-Type": []string{"application/json"}},
@ -996,7 +997,7 @@ func TestServeMembersFail(t *testing.T) {
{
// etcdserver.UpdateMember error
&http.Request{
URL: mustNewURL(t, path.Join(membersPrefix, "0")),
URL: testutil.MustNewURL(t, path.Join(membersPrefix, "0")),
Method: "PUT",
Body: ioutil.NopCloser(strings.NewReader(`{"PeerURLs": ["http://127.0.0.1:1"]}`)),
Header: map[string][]string{"Content-Type": []string{"application/json"}},
@ -1010,7 +1011,7 @@ func TestServeMembersFail(t *testing.T) {
{
// etcdserver.UpdateMember error
&http.Request{
URL: mustNewURL(t, path.Join(membersPrefix, "0")),
URL: testutil.MustNewURL(t, path.Join(membersPrefix, "0")),
Method: "PUT",
Body: ioutil.NopCloser(strings.NewReader(`{"PeerURLs": ["http://127.0.0.1:1"]}`)),
Header: map[string][]string{"Content-Type": []string{"application/json"}},
@ -1024,7 +1025,7 @@ func TestServeMembersFail(t *testing.T) {
{
// etcdserver.UpdateMember error with badly formed ID
&http.Request{
URL: mustNewURL(t, path.Join(membersPrefix, "bad_id")),
URL: testutil.MustNewURL(t, path.Join(membersPrefix, "bad_id")),
Method: "PUT",
},
nil,
@ -1034,7 +1035,7 @@ func TestServeMembersFail(t *testing.T) {
{
// etcdserver.UpdateMember with no ID
&http.Request{
URL: mustNewURL(t, membersPrefix),
URL: testutil.MustNewURL(t, membersPrefix),
Method: "PUT",
},
nil,

View File

@ -20,7 +20,6 @@ import (
"errors"
"net/http"
"net/http/httptest"
"net/url"
"sort"
"testing"
@ -32,14 +31,6 @@ import (
"github.com/coreos/etcd/raft/raftpb"
)
func mustNewURL(t *testing.T, s string) *url.URL {
u, err := url.Parse(s)
if err != nil {
t.Fatalf("error creating URL from %q: %v", s, err)
}
return u
}
type fakeCluster struct {
id uint64
clientURLs []string

View File

@ -25,6 +25,7 @@ import (
"testing"
"github.com/coreos/etcd/etcdserver"
"github.com/coreos/etcd/pkg/testutil"
"github.com/coreos/etcd/rafthttp"
)
@ -110,7 +111,7 @@ func TestServeMembersGet(t *testing.T) {
}
for i, tt := range tests {
req, err := http.NewRequest("GET", mustNewURL(t, tt.path).String(), nil)
req, err := http.NewRequest("GET", testutil.MustNewURL(t, tt.path).String(), nil)
if err != nil {
t.Fatal(err)
}

View File

@ -20,8 +20,6 @@ import (
"net/url"
"runtime"
"testing"
"github.com/coreos/etcd/pkg/types"
)
// WARNING: This is a hack.
@ -37,9 +35,18 @@ func MustNewURLs(t *testing.T, urls []string) []url.URL {
if urls == nil {
return nil
}
u, err := types.NewURLs(urls)
var us []url.URL
for _, url := range urls {
u := MustNewURL(t, url)
us = append(us, *u)
}
return us
}
func MustNewURL(t *testing.T, s string) *url.URL {
u, err := url.Parse(s)
if err != nil {
t.Fatalf("unexpected new urls error: %v", err)
t.Fatalf("parse %v error: %v", s, err)
}
return u
}

View File

@ -27,26 +27,6 @@ import (
type URLs []url.URL
func (us URLs) String() string {
return strings.Join(us.StringSlice(), ",")
}
func (us *URLs) Sort() {
sort.Sort(us)
}
func (us URLs) Len() int { return len(us) }
func (us URLs) Less(i, j int) bool { return us[i].String() < us[j].String() }
func (us URLs) Swap(i, j int) { us[i], us[j] = us[j], us[i] }
func (us URLs) StringSlice() []string {
out := make([]string, len(us))
for i := range us {
out[i] = us[i].String()
}
return out
}
func NewURLs(strs []string) (URLs, error) {
all := make([]url.URL, len(strs))
if len(all) == 0 {
@ -74,3 +54,23 @@ func NewURLs(strs []string) (URLs, error) {
return us, nil
}
func (us URLs) String() string {
return strings.Join(us.StringSlice(), ",")
}
func (us *URLs) Sort() {
sort.Sort(us)
}
func (us URLs) Len() int { return len(us) }
func (us URLs) Less(i, j int) bool { return us[i].String() < us[j].String() }
func (us URLs) Swap(i, j int) { us[i], us[j] = us[j], us[i] }
func (us URLs) StringSlice() []string {
out := make([]string, len(us))
for i := range us {
out[i] = us[i].String()
}
return out
}

171
pkg/types/urls_test.go Normal file
View File

@ -0,0 +1,171 @@
/*
Copyright 2014 CoreOS, Inc.
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.
*/
package types
import (
"reflect"
"testing"
"github.com/coreos/etcd/pkg/testutil"
)
func TestNewURLs(t *testing.T) {
tests := []struct {
strs []string
wurls URLs
}{
{
[]string{"http://127.0.0.1:4001"},
testutil.MustNewURLs(t, []string{"http://127.0.0.1:4001"}),
},
// it can trim space
{
[]string{" http://127.0.0.1:4001 "},
testutil.MustNewURLs(t, []string{"http://127.0.0.1:4001"}),
},
// it does sort
{
[]string{
"http://127.0.0.2:4001",
"http://127.0.0.1:4001",
},
testutil.MustNewURLs(t, []string{
"http://127.0.0.1:4001",
"http://127.0.0.2:4001",
}),
},
}
for i, tt := range tests {
urls, _ := NewURLs(tt.strs)
if !reflect.DeepEqual(urls, tt.wurls) {
t.Errorf("#%d: urls = %+v, want %+v", i, urls, tt.wurls)
}
}
}
func TestURLsString(t *testing.T) {
tests := []struct {
us URLs
wstr string
}{
{
URLs{},
"",
},
{
testutil.MustNewURLs(t, []string{"http://127.0.0.1:4001"}),
"http://127.0.0.1:4001",
},
{
testutil.MustNewURLs(t, []string{
"http://127.0.0.1:4001",
"http://127.0.0.2:4001",
}),
"http://127.0.0.1:4001,http://127.0.0.2:4001",
},
{
testutil.MustNewURLs(t, []string{
"http://127.0.0.2:4001",
"http://127.0.0.1:4001",
}),
"http://127.0.0.2:4001,http://127.0.0.1:4001",
},
}
for i, tt := range tests {
g := tt.us.String()
if g != tt.wstr {
t.Errorf("#%d: string = %s, want %s", i, g, tt.wstr)
}
}
}
func TestURLsSort(t *testing.T) {
g := testutil.MustNewURLs(t, []string{
"http://127.0.0.4:4001",
"http://127.0.0.2:4001",
"http://127.0.0.1:4001",
"http://127.0.0.3:4001",
})
w := testutil.MustNewURLs(t, []string{
"http://127.0.0.1:4001",
"http://127.0.0.2:4001",
"http://127.0.0.3:4001",
"http://127.0.0.4:4001",
})
gurls := URLs(g)
gurls.Sort()
if !reflect.DeepEqual(g, w) {
t.Errorf("URLs after sort = %#v, want %#v", g, w)
}
}
func TestURLsStringSlice(t *testing.T) {
tests := []struct {
us URLs
wstr []string
}{
{
URLs{},
[]string{},
},
{
testutil.MustNewURLs(t, []string{"http://127.0.0.1:4001"}),
[]string{"http://127.0.0.1:4001"},
},
{
testutil.MustNewURLs(t, []string{
"http://127.0.0.1:4001",
"http://127.0.0.2:4001",
}),
[]string{"http://127.0.0.1:4001", "http://127.0.0.2:4001"},
},
{
testutil.MustNewURLs(t, []string{
"http://127.0.0.2:4001",
"http://127.0.0.1:4001",
}),
[]string{"http://127.0.0.2:4001", "http://127.0.0.1:4001"},
},
}
for i, tt := range tests {
g := tt.us.StringSlice()
if !reflect.DeepEqual(g, tt.wstr) {
t.Errorf("#%d: string slice = %+v, want %+v", i, g, tt.wstr)
}
}
}
func TestNewURLsFail(t *testing.T) {
tests := [][]string{
// no urls given
{},
// missing protocol scheme
{"://127.0.0.1:4001"},
// unsupported scheme
{"mailto://127.0.0.1:4001"},
// not conform to host:port
{"http://127.0.0.1"},
// contain a path
{"http://127.0.0.1:4001/path"},
}
for i, tt := range tests {
_, err := NewURLs(tt)
if err == nil {
t.Errorf("#%d: err = nil, but error", i)
}
}
}