mirror of https://github.com/k3s-io/k3s
parent
eb1ea26995
commit
a555758b39
|
@ -62,16 +62,6 @@
|
||||||
"Comment": "v0.1-62-g8d75e11",
|
"Comment": "v0.1-62-g8d75e11",
|
||||||
"Rev": "8d75e11374a1928608c906fe745b538483e7aeb2"
|
"Rev": "8d75e11374a1928608c906fe745b538483e7aeb2"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"ImportPath": "github.com/coreos/etcd/etcdserver/etcdhttp/httptypes",
|
|
||||||
"Comment": "v2.0.4-288-g866a9d4",
|
|
||||||
"Rev": "866a9d4e41401657ea44bf539b2c5561d6fdcd67"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/coreos/etcd/pkg/types",
|
|
||||||
"Comment": "v2.0.4-288-g866a9d4",
|
|
||||||
"Rev": "866a9d4e41401657ea44bf539b2c5561d6fdcd67"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/coreos/go-etcd/etcd",
|
"ImportPath": "github.com/coreos/go-etcd/etcd",
|
||||||
"Comment": "v2.0.0-3-g0424b5f",
|
"Comment": "v2.0.0-3-g0424b5f",
|
||||||
|
|
19
Godeps/_workspace/src/github.com/coreos/etcd/etcdserver/etcdhttp/httptypes/doc.go
generated
vendored
19
Godeps/_workspace/src/github.com/coreos/etcd/etcdserver/etcdhttp/httptypes/doc.go
generated
vendored
|
@ -1,19 +0,0 @@
|
||||||
// Copyright 2015 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 httptypes defines how etcd's HTTP API entities are serialized to and deserialized from JSON.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package httptypes
|
|
49
Godeps/_workspace/src/github.com/coreos/etcd/etcdserver/etcdhttp/httptypes/errors.go
generated
vendored
49
Godeps/_workspace/src/github.com/coreos/etcd/etcdserver/etcdhttp/httptypes/errors.go
generated
vendored
|
@ -1,49 +0,0 @@
|
||||||
// Copyright 2015 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 httptypes
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
type HTTPError struct {
|
|
||||||
Message string `json:"message"`
|
|
||||||
// HTTP return code
|
|
||||||
Code int `json:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e HTTPError) Error() string {
|
|
||||||
return e.Message
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(xiangli): handle http write errors
|
|
||||||
func (e HTTPError) WriteTo(w http.ResponseWriter) {
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
w.WriteHeader(e.Code)
|
|
||||||
b, err := json.Marshal(e)
|
|
||||||
if err != nil {
|
|
||||||
log.Panicf("marshal HTTPError should never fail: %v", err)
|
|
||||||
}
|
|
||||||
w.Write(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewHTTPError(code int, m string) *HTTPError {
|
|
||||||
return &HTTPError{
|
|
||||||
Message: m,
|
|
||||||
Code: code,
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,47 +0,0 @@
|
||||||
// Copyright 2015 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 httptypes
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
"net/http/httptest"
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestHTTPErrorWriteTo(t *testing.T) {
|
|
||||||
err := NewHTTPError(http.StatusBadRequest, "what a bad request you made!")
|
|
||||||
rr := httptest.NewRecorder()
|
|
||||||
err.WriteTo(rr)
|
|
||||||
|
|
||||||
wcode := http.StatusBadRequest
|
|
||||||
wheader := http.Header(map[string][]string{
|
|
||||||
"Content-Type": []string{"application/json"},
|
|
||||||
})
|
|
||||||
wbody := `{"message":"what a bad request you made!"}`
|
|
||||||
|
|
||||||
if wcode != rr.Code {
|
|
||||||
t.Errorf("HTTP status code %d, want %d", rr.Code, wcode)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !reflect.DeepEqual(wheader, rr.HeaderMap) {
|
|
||||||
t.Errorf("HTTP headers %v, want %v", rr.HeaderMap, wheader)
|
|
||||||
}
|
|
||||||
|
|
||||||
gbody := rr.Body.String()
|
|
||||||
if wbody != gbody {
|
|
||||||
t.Errorf("HTTP body %q, want %q", gbody, wbody)
|
|
||||||
}
|
|
||||||
}
|
|
67
Godeps/_workspace/src/github.com/coreos/etcd/etcdserver/etcdhttp/httptypes/member.go
generated
vendored
67
Godeps/_workspace/src/github.com/coreos/etcd/etcdserver/etcdhttp/httptypes/member.go
generated
vendored
|
@ -1,67 +0,0 @@
|
||||||
// Copyright 2015 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 httptypes
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
|
|
||||||
"github.com/coreos/etcd/pkg/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Member struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
PeerURLs []string `json:"peerURLs"`
|
|
||||||
ClientURLs []string `json:"clientURLs"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type MemberCreateRequest struct {
|
|
||||||
PeerURLs types.URLs
|
|
||||||
}
|
|
||||||
|
|
||||||
type MemberUpdateRequest struct {
|
|
||||||
MemberCreateRequest
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MemberCreateRequest) UnmarshalJSON(data []byte) error {
|
|
||||||
s := struct {
|
|
||||||
PeerURLs []string `json:"peerURLs"`
|
|
||||||
}{}
|
|
||||||
|
|
||||||
err := json.Unmarshal(data, &s)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
urls, err := types.NewURLs(s.PeerURLs)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
m.PeerURLs = urls
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type MemberCollection []Member
|
|
||||||
|
|
||||||
func (c *MemberCollection) MarshalJSON() ([]byte, error) {
|
|
||||||
d := struct {
|
|
||||||
Members []Member `json:"members"`
|
|
||||||
}{
|
|
||||||
Members: []Member(*c),
|
|
||||||
}
|
|
||||||
|
|
||||||
return json.Marshal(d)
|
|
||||||
}
|
|
135
Godeps/_workspace/src/github.com/coreos/etcd/etcdserver/etcdhttp/httptypes/member_test.go
generated
vendored
135
Godeps/_workspace/src/github.com/coreos/etcd/etcdserver/etcdhttp/httptypes/member_test.go
generated
vendored
|
@ -1,135 +0,0 @@
|
||||||
// Copyright 2015 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 httptypes
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"net/url"
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/coreos/etcd/pkg/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestMemberUnmarshal(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
body []byte
|
|
||||||
wantMember Member
|
|
||||||
wantError bool
|
|
||||||
}{
|
|
||||||
// no URLs, just check ID & Name
|
|
||||||
{
|
|
||||||
body: []byte(`{"id": "c", "name": "dungarees"}`),
|
|
||||||
wantMember: Member{ID: "c", Name: "dungarees", PeerURLs: nil, ClientURLs: nil},
|
|
||||||
},
|
|
||||||
|
|
||||||
// both client and peer URLs
|
|
||||||
{
|
|
||||||
body: []byte(`{"peerURLs": ["http://127.0.0.1:4001"], "clientURLs": ["http://127.0.0.1:4001"]}`),
|
|
||||||
wantMember: Member{
|
|
||||||
PeerURLs: []string{
|
|
||||||
"http://127.0.0.1:4001",
|
|
||||||
},
|
|
||||||
ClientURLs: []string{
|
|
||||||
"http://127.0.0.1:4001",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
// multiple peer URLs
|
|
||||||
{
|
|
||||||
body: []byte(`{"peerURLs": ["http://127.0.0.1:4001", "https://example.com"]}`),
|
|
||||||
wantMember: Member{
|
|
||||||
PeerURLs: []string{
|
|
||||||
"http://127.0.0.1:4001",
|
|
||||||
"https://example.com",
|
|
||||||
},
|
|
||||||
ClientURLs: nil,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
// multiple client URLs
|
|
||||||
{
|
|
||||||
body: []byte(`{"clientURLs": ["http://127.0.0.1:4001", "https://example.com"]}`),
|
|
||||||
wantMember: Member{
|
|
||||||
PeerURLs: nil,
|
|
||||||
ClientURLs: []string{
|
|
||||||
"http://127.0.0.1:4001",
|
|
||||||
"https://example.com",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
// invalid JSON
|
|
||||||
{
|
|
||||||
body: []byte(`{"peerU`),
|
|
||||||
wantError: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, tt := range tests {
|
|
||||||
got := Member{}
|
|
||||||
err := json.Unmarshal(tt.body, &got)
|
|
||||||
if tt.wantError != (err != nil) {
|
|
||||||
t.Errorf("#%d: want error %t, got %v", i, tt.wantError, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if !reflect.DeepEqual(tt.wantMember, got) {
|
|
||||||
t.Errorf("#%d: incorrect output: want=%#v, got=%#v", i, tt.wantMember, got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMemberCreateRequestUnmarshal(t *testing.T) {
|
|
||||||
body := []byte(`{"peerURLs": ["http://127.0.0.1:8081", "https://127.0.0.1:8080"]}`)
|
|
||||||
want := MemberCreateRequest{
|
|
||||||
PeerURLs: types.URLs([]url.URL{
|
|
||||||
url.URL{Scheme: "http", Host: "127.0.0.1:8081"},
|
|
||||||
url.URL{Scheme: "https", Host: "127.0.0.1:8080"},
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
|
|
||||||
var req MemberCreateRequest
|
|
||||||
if err := json.Unmarshal(body, &req); err != nil {
|
|
||||||
t.Fatalf("Unmarshal returned unexpected err=%v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !reflect.DeepEqual(want, req) {
|
|
||||||
t.Fatalf("Failed to unmarshal MemberCreateRequest: want=%#v, got=%#v", want, req)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMemberCreateRequestUnmarshalFail(t *testing.T) {
|
|
||||||
tests := [][]byte{
|
|
||||||
// invalid JSON
|
|
||||||
[]byte(``),
|
|
||||||
[]byte(`{`),
|
|
||||||
|
|
||||||
// spot-check validation done in types.NewURLs
|
|
||||||
[]byte(`{"peerURLs": "foo"}`),
|
|
||||||
[]byte(`{"peerURLs": ["."]}`),
|
|
||||||
[]byte(`{"peerURLs": []}`),
|
|
||||||
[]byte(`{"peerURLs": ["http://127.0.0.1:4001/foo"]}`),
|
|
||||||
[]byte(`{"peerURLs": ["http://127.0.0.1"]}`),
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, tt := range tests {
|
|
||||||
var req MemberCreateRequest
|
|
||||||
if err := json.Unmarshal(tt, &req); err == nil {
|
|
||||||
t.Errorf("#%d: expected err, got nil", i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
// Copyright 2015 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 (
|
|
||||||
"strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ID represents a generic identifier which is canonically
|
|
||||||
// stored as a uint64 but is typically represented as a
|
|
||||||
// base-16 string for input/output
|
|
||||||
type ID uint64
|
|
||||||
|
|
||||||
func (i ID) String() string {
|
|
||||||
return strconv.FormatUint(uint64(i), 16)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IDFromString attempts to create an ID from a base-16 string.
|
|
||||||
func IDFromString(s string) (ID, error) {
|
|
||||||
i, err := strconv.ParseUint(s, 16, 64)
|
|
||||||
return ID(i), err
|
|
||||||
}
|
|
||||||
|
|
||||||
// IDSlice implements the sort interface
|
|
||||||
type IDSlice []ID
|
|
||||||
|
|
||||||
func (p IDSlice) Len() int { return len(p) }
|
|
||||||
func (p IDSlice) Less(i, j int) bool { return uint64(p[i]) < uint64(p[j]) }
|
|
||||||
func (p IDSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
|
|
|
@ -1,95 +0,0 @@
|
||||||
// Copyright 2015 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"
|
|
||||||
"sort"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestIDString(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
input ID
|
|
||||||
want string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
input: 12,
|
|
||||||
want: "c",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: 4918257920282737594,
|
|
||||||
want: "444129853c343bba",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, tt := range tests {
|
|
||||||
got := tt.input.String()
|
|
||||||
if tt.want != got {
|
|
||||||
t.Errorf("#%d: ID.String failure: want=%v, got=%v", i, tt.want, got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestIDFromString(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
input string
|
|
||||||
want ID
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
input: "17",
|
|
||||||
want: 23,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: "612840dae127353",
|
|
||||||
want: 437557308098245459,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, tt := range tests {
|
|
||||||
got, err := IDFromString(tt.input)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("#%d: IDFromString failure: err=%v", i, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if tt.want != got {
|
|
||||||
t.Errorf("#%d: IDFromString failure: want=%v, got=%v", i, tt.want, got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestIDFromStringFail(t *testing.T) {
|
|
||||||
tests := []string{
|
|
||||||
"",
|
|
||||||
"XXX",
|
|
||||||
"612840dae127353612840dae127353",
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, tt := range tests {
|
|
||||||
_, err := IDFromString(tt)
|
|
||||||
if err == nil {
|
|
||||||
t.Fatalf("#%d: IDFromString expected error, but err=nil", i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestIDSlice(t *testing.T) {
|
|
||||||
g := []ID{10, 500, 5, 1, 100, 25}
|
|
||||||
w := []ID{1, 5, 10, 25, 100, 500}
|
|
||||||
sort.Sort(IDSlice(g))
|
|
||||||
if !reflect.DeepEqual(g, w) {
|
|
||||||
t.Errorf("slice after sort = %#v, want %#v", g, w)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,178 +0,0 @@
|
||||||
// Copyright 2015 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"
|
|
||||||
"sort"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Set interface {
|
|
||||||
Add(string)
|
|
||||||
Remove(string)
|
|
||||||
Contains(string) bool
|
|
||||||
Equals(Set) bool
|
|
||||||
Length() int
|
|
||||||
Values() []string
|
|
||||||
Copy() Set
|
|
||||||
Sub(Set) Set
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewUnsafeSet(values ...string) *unsafeSet {
|
|
||||||
set := &unsafeSet{make(map[string]struct{})}
|
|
||||||
for _, v := range values {
|
|
||||||
set.Add(v)
|
|
||||||
}
|
|
||||||
return set
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewThreadsafeSet(values ...string) *tsafeSet {
|
|
||||||
us := NewUnsafeSet(values...)
|
|
||||||
return &tsafeSet{us, sync.RWMutex{}}
|
|
||||||
}
|
|
||||||
|
|
||||||
type unsafeSet struct {
|
|
||||||
d map[string]struct{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add adds a new value to the set (no-op if the value is already present)
|
|
||||||
func (us *unsafeSet) Add(value string) {
|
|
||||||
us.d[value] = struct{}{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove removes the given value from the set
|
|
||||||
func (us *unsafeSet) Remove(value string) {
|
|
||||||
delete(us.d, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Contains returns whether the set contains the given value
|
|
||||||
func (us *unsafeSet) Contains(value string) (exists bool) {
|
|
||||||
_, exists = us.d[value]
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// ContainsAll returns whether the set contains all given values
|
|
||||||
func (us *unsafeSet) ContainsAll(values []string) bool {
|
|
||||||
for _, s := range values {
|
|
||||||
if !us.Contains(s) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Equals returns whether the contents of two sets are identical
|
|
||||||
func (us *unsafeSet) Equals(other Set) bool {
|
|
||||||
v1 := sort.StringSlice(us.Values())
|
|
||||||
v2 := sort.StringSlice(other.Values())
|
|
||||||
v1.Sort()
|
|
||||||
v2.Sort()
|
|
||||||
return reflect.DeepEqual(v1, v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Length returns the number of elements in the set
|
|
||||||
func (us *unsafeSet) Length() int {
|
|
||||||
return len(us.d)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Values returns the values of the Set in an unspecified order.
|
|
||||||
func (us *unsafeSet) Values() (values []string) {
|
|
||||||
values = make([]string, 0)
|
|
||||||
for val, _ := range us.d {
|
|
||||||
values = append(values, val)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy creates a new Set containing the values of the first
|
|
||||||
func (us *unsafeSet) Copy() Set {
|
|
||||||
cp := NewUnsafeSet()
|
|
||||||
for val, _ := range us.d {
|
|
||||||
cp.Add(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
return cp
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sub removes all elements in other from the set
|
|
||||||
func (us *unsafeSet) Sub(other Set) Set {
|
|
||||||
oValues := other.Values()
|
|
||||||
result := us.Copy().(*unsafeSet)
|
|
||||||
|
|
||||||
for _, val := range oValues {
|
|
||||||
if _, ok := result.d[val]; !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
delete(result.d, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
type tsafeSet struct {
|
|
||||||
us *unsafeSet
|
|
||||||
m sync.RWMutex
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ts *tsafeSet) Add(value string) {
|
|
||||||
ts.m.Lock()
|
|
||||||
defer ts.m.Unlock()
|
|
||||||
ts.us.Add(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ts *tsafeSet) Remove(value string) {
|
|
||||||
ts.m.Lock()
|
|
||||||
defer ts.m.Unlock()
|
|
||||||
ts.us.Remove(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ts *tsafeSet) Contains(value string) (exists bool) {
|
|
||||||
ts.m.RLock()
|
|
||||||
defer ts.m.RUnlock()
|
|
||||||
return ts.us.Contains(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ts *tsafeSet) Equals(other Set) bool {
|
|
||||||
ts.m.RLock()
|
|
||||||
defer ts.m.RUnlock()
|
|
||||||
return ts.us.Equals(other)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ts *tsafeSet) Length() int {
|
|
||||||
ts.m.RLock()
|
|
||||||
defer ts.m.RUnlock()
|
|
||||||
return ts.us.Length()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ts *tsafeSet) Values() (values []string) {
|
|
||||||
ts.m.RLock()
|
|
||||||
defer ts.m.RUnlock()
|
|
||||||
return ts.us.Values()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ts *tsafeSet) Copy() Set {
|
|
||||||
ts.m.RLock()
|
|
||||||
defer ts.m.RUnlock()
|
|
||||||
usResult := ts.us.Copy().(*unsafeSet)
|
|
||||||
return &tsafeSet{usResult, sync.RWMutex{}}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ts *tsafeSet) Sub(other Set) Set {
|
|
||||||
ts.m.RLock()
|
|
||||||
defer ts.m.RUnlock()
|
|
||||||
usResult := ts.us.Sub(other).(*unsafeSet)
|
|
||||||
return &tsafeSet{usResult, sync.RWMutex{}}
|
|
||||||
}
|
|
|
@ -1,186 +0,0 @@
|
||||||
// Copyright 2015 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"
|
|
||||||
"sort"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestUnsafeSet(t *testing.T) {
|
|
||||||
driveSetTests(t, NewUnsafeSet())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestThreadsafeSet(t *testing.T) {
|
|
||||||
driveSetTests(t, NewThreadsafeSet())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that two slices contents are equal; order is irrelevant
|
|
||||||
func equal(a, b []string) bool {
|
|
||||||
as := sort.StringSlice(a)
|
|
||||||
bs := sort.StringSlice(b)
|
|
||||||
as.Sort()
|
|
||||||
bs.Sort()
|
|
||||||
return reflect.DeepEqual(as, bs)
|
|
||||||
}
|
|
||||||
|
|
||||||
func driveSetTests(t *testing.T, s Set) {
|
|
||||||
// Verify operations on an empty set
|
|
||||||
eValues := []string{}
|
|
||||||
values := s.Values()
|
|
||||||
if !reflect.DeepEqual(values, eValues) {
|
|
||||||
t.Fatalf("Expect values=%v got %v", eValues, values)
|
|
||||||
}
|
|
||||||
if l := s.Length(); l != 0 {
|
|
||||||
t.Fatalf("Expected length=0, got %d", l)
|
|
||||||
}
|
|
||||||
for _, v := range []string{"foo", "bar", "baz"} {
|
|
||||||
if s.Contains(v) {
|
|
||||||
t.Fatalf("Expect s.Contains(%q) to be fale, got true", v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add three items, ensure they show up
|
|
||||||
s.Add("foo")
|
|
||||||
s.Add("bar")
|
|
||||||
s.Add("baz")
|
|
||||||
|
|
||||||
eValues = []string{"foo", "bar", "baz"}
|
|
||||||
values = s.Values()
|
|
||||||
if !equal(values, eValues) {
|
|
||||||
t.Fatalf("Expect values=%v got %v", eValues, values)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, v := range eValues {
|
|
||||||
if !s.Contains(v) {
|
|
||||||
t.Fatalf("Expect s.Contains(%q) to be true, got false", v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if l := s.Length(); l != 3 {
|
|
||||||
t.Fatalf("Expected length=3, got %d", l)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the same item a second time, ensuring it is not duplicated
|
|
||||||
s.Add("foo")
|
|
||||||
|
|
||||||
values = s.Values()
|
|
||||||
if !equal(values, eValues) {
|
|
||||||
t.Fatalf("Expect values=%v got %v", eValues, values)
|
|
||||||
}
|
|
||||||
if l := s.Length(); l != 3 {
|
|
||||||
t.Fatalf("Expected length=3, got %d", l)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove all items, ensure they are gone
|
|
||||||
s.Remove("foo")
|
|
||||||
s.Remove("bar")
|
|
||||||
s.Remove("baz")
|
|
||||||
|
|
||||||
eValues = []string{}
|
|
||||||
values = s.Values()
|
|
||||||
if !equal(values, eValues) {
|
|
||||||
t.Fatalf("Expect values=%v got %v", eValues, values)
|
|
||||||
}
|
|
||||||
|
|
||||||
if l := s.Length(); l != 0 {
|
|
||||||
t.Fatalf("Expected length=0, got %d", l)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create new copies of the set, and ensure they are unlinked to the
|
|
||||||
// original Set by making modifications
|
|
||||||
s.Add("foo")
|
|
||||||
s.Add("bar")
|
|
||||||
cp1 := s.Copy()
|
|
||||||
cp2 := s.Copy()
|
|
||||||
s.Remove("foo")
|
|
||||||
cp3 := s.Copy()
|
|
||||||
cp1.Add("baz")
|
|
||||||
|
|
||||||
for i, tt := range []struct {
|
|
||||||
want []string
|
|
||||||
got []string
|
|
||||||
}{
|
|
||||||
{[]string{"bar"}, s.Values()},
|
|
||||||
{[]string{"foo", "bar", "baz"}, cp1.Values()},
|
|
||||||
{[]string{"foo", "bar"}, cp2.Values()},
|
|
||||||
{[]string{"bar"}, cp3.Values()},
|
|
||||||
} {
|
|
||||||
if !equal(tt.want, tt.got) {
|
|
||||||
t.Fatalf("case %d: expect values=%v got %v", i, tt.want, tt.got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, tt := range []struct {
|
|
||||||
want bool
|
|
||||||
got bool
|
|
||||||
}{
|
|
||||||
{true, s.Equals(cp3)},
|
|
||||||
{true, cp3.Equals(s)},
|
|
||||||
{false, s.Equals(cp2)},
|
|
||||||
{false, s.Equals(cp1)},
|
|
||||||
{false, cp1.Equals(s)},
|
|
||||||
{false, cp2.Equals(s)},
|
|
||||||
{false, cp2.Equals(cp1)},
|
|
||||||
} {
|
|
||||||
if tt.got != tt.want {
|
|
||||||
t.Fatalf("case %d: want %t, got %t", i, tt.want, tt.got)
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Subtract values from a Set, ensuring a new Set is created and
|
|
||||||
// the original Sets are unmodified
|
|
||||||
sub1 := cp1.Sub(s)
|
|
||||||
sub2 := cp2.Sub(cp1)
|
|
||||||
|
|
||||||
for i, tt := range []struct {
|
|
||||||
want []string
|
|
||||||
got []string
|
|
||||||
}{
|
|
||||||
{[]string{"foo", "bar", "baz"}, cp1.Values()},
|
|
||||||
{[]string{"foo", "bar"}, cp2.Values()},
|
|
||||||
{[]string{"bar"}, s.Values()},
|
|
||||||
{[]string{"foo", "baz"}, sub1.Values()},
|
|
||||||
{[]string{}, sub2.Values()},
|
|
||||||
} {
|
|
||||||
if !equal(tt.want, tt.got) {
|
|
||||||
t.Fatalf("case %d: expect values=%v got %v", i, tt.want, tt.got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUnsafeSetContainsAll(t *testing.T) {
|
|
||||||
vals := []string{"foo", "bar", "baz"}
|
|
||||||
s := NewUnsafeSet(vals...)
|
|
||||||
|
|
||||||
tests := []struct {
|
|
||||||
strs []string
|
|
||||||
wcontain bool
|
|
||||||
}{
|
|
||||||
{[]string{}, true},
|
|
||||||
{vals[:1], true},
|
|
||||||
{vals[:2], true},
|
|
||||||
{vals, true},
|
|
||||||
{[]string{"cuz"}, false},
|
|
||||||
{[]string{vals[0], "cuz"}, false},
|
|
||||||
}
|
|
||||||
for i, tt := range tests {
|
|
||||||
if g := s.ContainsAll(tt.strs); g != tt.wcontain {
|
|
||||||
t.Errorf("#%d: ok = %v, want %v", i, g, tt.wcontain)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
// Copyright 2015 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
|
|
||||||
|
|
||||||
// Uint64Slice implements sort interface
|
|
||||||
type Uint64Slice []uint64
|
|
||||||
|
|
||||||
func (p Uint64Slice) Len() int { return len(p) }
|
|
||||||
func (p Uint64Slice) Less(i, j int) bool { return p[i] < p[j] }
|
|
||||||
func (p Uint64Slice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
|
|
|
@ -1,30 +0,0 @@
|
||||||
// Copyright 2015 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"
|
|
||||||
"sort"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestUint64Slice(t *testing.T) {
|
|
||||||
g := Uint64Slice{10, 500, 5, 1, 100, 25}
|
|
||||||
w := Uint64Slice{1, 5, 10, 25, 100, 500}
|
|
||||||
sort.Sort(g)
|
|
||||||
if !reflect.DeepEqual(g, w) {
|
|
||||||
t.Errorf("slice after sort = %#v, want %#v", g, w)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,74 +0,0 @@
|
||||||
// Copyright 2015 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 (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
"net/url"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
type URLs []url.URL
|
|
||||||
|
|
||||||
func NewURLs(strs []string) (URLs, error) {
|
|
||||||
all := make([]url.URL, len(strs))
|
|
||||||
if len(all) == 0 {
|
|
||||||
return nil, errors.New("no valid URLs given")
|
|
||||||
}
|
|
||||||
for i, in := range strs {
|
|
||||||
in = strings.TrimSpace(in)
|
|
||||||
u, err := url.Parse(in)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if u.Scheme != "http" && u.Scheme != "https" {
|
|
||||||
return nil, fmt.Errorf("URL scheme must be http or https: %s", in)
|
|
||||||
}
|
|
||||||
if _, _, err := net.SplitHostPort(u.Host); err != nil {
|
|
||||||
return nil, fmt.Errorf(`URL address does not have the form "host:port": %s`, in)
|
|
||||||
}
|
|
||||||
if u.Path != "" {
|
|
||||||
return nil, fmt.Errorf("URL must not contain a path: %s", in)
|
|
||||||
}
|
|
||||||
all[i] = *u
|
|
||||||
}
|
|
||||||
us := URLs(all)
|
|
||||||
us.Sort()
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
|
@ -1,169 +0,0 @@
|
||||||
// Copyright 2015 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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue