diff --git a/client/keys_test.go b/client/keys_test.go index 1ab0937a1..d2428c72d 100644 --- a/client/keys_test.go +++ b/client/keys_test.go @@ -224,7 +224,7 @@ func assertResponse(got http.Request, wantURL *url.URL, wantHeader http.Header, } } else { if wantBody == nil { - return fmt.Errorf("want.Body=%v got.Body=%v", wantBody, got.Body) + return fmt.Errorf("want.Body=%v got.Body=%s", wantBody, got.Body) } else { gotBytes, err := ioutil.ReadAll(got.Body) if err != nil { @@ -232,7 +232,7 @@ func assertResponse(got http.Request, wantURL *url.URL, wantHeader http.Header, } if !reflect.DeepEqual(wantBody, gotBytes) { - return fmt.Errorf("want.Body=%v got.Body=%v", wantBody, gotBytes) + return fmt.Errorf("want.Body=%s got.Body=%s", wantBody, gotBytes) } } } diff --git a/client/members.go b/client/members.go index 0b551878b..d178b9a76 100644 --- a/client/members.go +++ b/client/members.go @@ -26,6 +26,7 @@ import ( "time" "github.com/coreos/etcd/etcdserver/etcdhttp/httptypes" + "github.com/coreos/etcd/pkg/types" ) var ( @@ -82,7 +83,12 @@ func (m *httpMembersAPI) List() ([]httptypes.Member, error) { } func (m *httpMembersAPI) Add(peerURL string) (*httptypes.Member, error) { - req := &membersAPIActionAdd{peerURL: peerURL} + urls, err := types.NewURLs([]string{peerURL}) + if err != nil { + return nil, err + } + + req := &membersAPIActionAdd{peerURLs: urls} code, body, err := m.client.doWithTimeout(req) if err != nil { return nil, err @@ -128,11 +134,11 @@ func (d *membersAPIActionRemove) httpRequest(ep url.URL) *http.Request { } type membersAPIActionAdd struct { - peerURL string + peerURLs types.URLs } func (a *membersAPIActionAdd) httpRequest(ep url.URL) *http.Request { - m := httptypes.Member{PeerURLs: []string{a.peerURL}} + m := httptypes.MemberCreateRequest{PeerURLs: a.peerURLs} b, _ := json.Marshal(&m) req, _ := http.NewRequest("POST", ep.String(), bytes.NewReader(b)) req.Header.Set("Content-Type", "application/json") diff --git a/client/members_test.go b/client/members_test.go index b8cdd2bc4..e003be2e5 100644 --- a/client/members_test.go +++ b/client/members_test.go @@ -20,20 +20,66 @@ import ( "net/http" "net/url" "testing" + + "github.com/coreos/etcd/pkg/types" ) -func TestMembersAPIListAction(t *testing.T) { +func TestMembersAPIActionList(t *testing.T) { ep := url.URL{Scheme: "http", Host: "example.com/v2/members"} + act := &membersAPIActionList{} + wantURL := &url.URL{ Scheme: "http", Host: "example.com", Path: "/v2/members", } - act := &membersAPIActionList{} got := *act.httpRequest(ep) err := assertResponse(got, wantURL, http.Header{}, nil) if err != nil { - t.Errorf(err.Error()) + t.Error(err.Error()) + } +} + +func TestMembersAPIActionAdd(t *testing.T) { + ep := url.URL{Scheme: "http", Host: "example.com/v2/admin/members"} + act := &membersAPIActionAdd{ + peerURLs: types.URLs([]url.URL{ + url.URL{Scheme: "https", Host: "127.0.0.1:8081"}, + url.URL{Scheme: "http", Host: "127.0.0.1:8080"}, + }), + } + + wantURL := &url.URL{ + Scheme: "http", + Host: "example.com", + Path: "/v2/admin/members", + } + wantHeader := http.Header{ + "Content-Type": []string{"application/json"}, + } + wantBody := []byte(`{"peerURLs":["https://127.0.0.1:8081","http://127.0.0.1:8080"]}`) + + got := *act.httpRequest(ep) + err := assertResponse(got, wantURL, wantHeader, wantBody) + if err != nil { + t.Error(err.Error()) + } +} + +func TestMembersAPIActionRemove(t *testing.T) { + ep := url.URL{Scheme: "http", Host: "example.com/v2/members"} + act := &membersAPIActionRemove{memberID: "XXX"} + + wantURL := &url.URL{ + Scheme: "http", + Host: "example.com", + Path: "/v2/members/XXX", + } + + got := *act.httpRequest(ep) + err := assertResponse(got, wantURL, http.Header{}, nil) + if err != nil { + t.Error(err.Error()) } } diff --git a/etcdserver/etcdhttp/httptypes/member.go b/etcdserver/etcdhttp/httptypes/member.go index 06fd0ccb8..6d8554ed0 100644 --- a/etcdserver/etcdhttp/httptypes/member.go +++ b/etcdserver/etcdhttp/httptypes/member.go @@ -33,6 +33,20 @@ type MemberCreateRequest struct { PeerURLs types.URLs } +func (m *MemberCreateRequest) MarshalJSON() ([]byte, error) { + s := struct { + PeerURLs []string `json:"peerURLs"` + }{ + PeerURLs: make([]string, len(m.PeerURLs)), + } + + for i, u := range m.PeerURLs { + s.PeerURLs[i] = u.String() + } + + return json.Marshal(&s) +} + func (m *MemberCreateRequest) UnmarshalJSON(data []byte) error { s := struct { PeerURLs []string `json:"peerURLs"` diff --git a/etcdserver/etcdhttp/httptypes/member_test.go b/etcdserver/etcdhttp/httptypes/member_test.go index 2b07c28b0..823f44630 100644 --- a/etcdserver/etcdhttp/httptypes/member_test.go +++ b/etcdserver/etcdhttp/httptypes/member_test.go @@ -199,3 +199,22 @@ func TestMemberCreateRequestUnmarshalFail(t *testing.T) { } } } + +func TestMemberCreateRequestMarshal(t *testing.T) { + req := 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"}, + }), + } + want := []byte(`{"peerURLs":["http://127.0.0.1:8081","https://127.0.0.1:8080"]}`) + + got, err := json.Marshal(&req) + if err != nil { + t.Fatalf("Marshal returned unexpected err=%v", err) + } + + if !reflect.DeepEqual(want, got) { + t.Fatalf("Failed to marshal MemberCreateRequest: want=%s, got=%s", want, got) + } +}