httptypes: use MemberCollection for JSON (de)serialization

This commit is contained in:
Brian Waldon 2014-10-27 09:37:43 -07:00
parent 7545152318
commit 14795d8ed9
5 changed files with 118 additions and 64 deletions

View File

@ -80,7 +80,7 @@ func (m *httpMembersAPI) List() ([]httptypes.Member, error) {
return nil, err
}
return mCollection.Members, nil
return []httptypes.Member(mCollection), nil
}
type httpMembersAPIResponse struct {

View File

@ -33,6 +33,7 @@ import (
"github.com/coreos/etcd/Godeps/_workspace/src/github.com/jonboulle/clockwork"
etcdErr "github.com/coreos/etcd/error"
"github.com/coreos/etcd/etcdserver"
"github.com/coreos/etcd/etcdserver/etcdhttp/httptypes"
"github.com/coreos/etcd/etcdserver/etcdserverpb"
"github.com/coreos/etcd/pkg/types"
"github.com/coreos/etcd/store"
@ -162,13 +163,9 @@ func (h *adminMembersHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
http.NotFound(w, r)
return
}
ms := struct {
Members []*etcdserver.Member `json:"members"`
}{
Members: h.clusterInfo.Members(),
}
mc := newMemberCollection(h.clusterInfo.Members())
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(ms); err != nil {
if err := json.NewEncoder(w).Encode(mc); err != nil {
log.Printf("etcdhttp: %v", err)
}
case "POST":
@ -518,3 +515,23 @@ func getBool(form url.Values, key string) (b bool, err error) {
}
return
}
func newMemberCollection(ms []*etcdserver.Member) httptypes.MemberCollection {
c := httptypes.MemberCollection(make([]httptypes.Member, len(ms)))
for i, m := range ms {
tm := httptypes.Member{
ID: m.ID,
Name: m.Name,
PeerURLs: make([]string, len(m.PeerURLs)),
ClientURLs: make([]string, len(m.ClientURLs)),
}
copy(m.PeerURLs, tm.PeerURLs)
copy(m.ClientURLs, tm.ClientURLs)
c[i] = tm
}
return c
}

View File

@ -561,17 +561,11 @@ func TestServeAdminMembers(t *testing.T) {
clusterInfo: cluster,
}
msb, err := json.Marshal(
struct {
Members []etcdserver.Member `json:"members"`
}{
Members: []etcdserver.Member{memb1, memb2},
},
)
mcb, err := json.Marshal(newMemberCollection([]*etcdserver.Member{&memb1, &memb2}))
if err != nil {
t.Fatal(err)
}
wms := string(msb) + "\n"
wmc := string(mcb) + "\n"
tests := []struct {
path string
@ -579,7 +573,7 @@ func TestServeAdminMembers(t *testing.T) {
wct string
wbody string
}{
{adminMembersPrefix, http.StatusOK, "application/json", wms},
{adminMembersPrefix, http.StatusOK, "application/json", wmc},
{path.Join(adminMembersPrefix, "100"), http.StatusNotFound, "text/plain; charset=utf-8", "404 page not found\n"},
{path.Join(adminMembersPrefix, "foobar"), http.StatusNotFound, "text/plain; charset=utf-8", "404 page not found\n"},
}

View File

@ -16,13 +16,43 @@
package httptypes
import (
"encoding/json"
)
type Member struct {
ID uint64
Name string
PeerURLs []string
ClientURLs []string
ID uint64 `json:"id"`
Name string `json:"name"`
PeerURLs []string `json:"peerURLs"`
ClientURLs []string `json:"clientURLs"`
}
type MemberCollection struct {
Members []Member
type MemberCollection []Member
func (c *MemberCollection) MarshalJSON() ([]byte, error) {
d := struct {
Members []Member `json:"members"`
}{
Members: []Member(*c),
}
return json.Marshal(d)
}
func (c *MemberCollection) UnmarshalJSON(data []byte) error {
d := struct {
Members []Member
}{}
if err := json.Unmarshal(data, &d); err != nil {
return err
}
if d.Members == nil {
*c = make([]Member, 0)
return nil
}
*c = d.Members
return nil
}

View File

@ -93,52 +93,65 @@ func TestMemberUnmarshal(t *testing.T) {
}
func TestMemberCollectionUnmarshal(t *testing.T) {
body := []byte(`{"members":[{"id":176869799018424574,"peerURLs":["http://127.0.0.1:7003"],"name":"node3","clientURLs":["http://127.0.0.1:4003"]},{"id":297577273835923749,"peerURLs":["http://127.0.0.1:2380","http://127.0.0.1:7001"],"name":"node1","clientURLs":["http://127.0.0.1:2379","http://127.0.0.1:4001"]},{"id":10666918107976480891,"peerURLs":["http://127.0.0.1:7002"],"name":"node2","clientURLs":["http://127.0.0.1:4002"]}]}`)
want := MemberCollection{
Members: []Member{
{
ID: 176869799018424574,
Name: "node3",
PeerURLs: []string{
"http://127.0.0.1:7003",
tests := []struct {
body []byte
want MemberCollection
}{
{
body: []byte(`{"members":[]}`),
want: MemberCollection([]Member{}),
},
{
body: []byte(`{"members":[{"id":176869799018424574,"peerURLs":["http://127.0.0.1:7003"],"name":"node3","clientURLs":["http://127.0.0.1:4003"]},{"id":297577273835923749,"peerURLs":["http://127.0.0.1:2380","http://127.0.0.1:7001"],"name":"node1","clientURLs":["http://127.0.0.1:2379","http://127.0.0.1:4001"]},{"id":10666918107976480891,"peerURLs":["http://127.0.0.1:7002"],"name":"node2","clientURLs":["http://127.0.0.1:4002"]}]}`),
want: MemberCollection(
[]Member{
{
ID: 176869799018424574,
Name: "node3",
PeerURLs: []string{
"http://127.0.0.1:7003",
},
ClientURLs: []string{
"http://127.0.0.1:4003",
},
},
{
ID: 297577273835923749,
Name: "node1",
PeerURLs: []string{
"http://127.0.0.1:2380",
"http://127.0.0.1:7001",
},
ClientURLs: []string{
"http://127.0.0.1:2379",
"http://127.0.0.1:4001",
},
},
{
ID: 10666918107976480891,
Name: "node2",
PeerURLs: []string{
"http://127.0.0.1:7002",
},
ClientURLs: []string{
"http://127.0.0.1:4002",
},
},
},
ClientURLs: []string{
"http://127.0.0.1:4003",
},
},
{
ID: 297577273835923749,
Name: "node1",
PeerURLs: []string{
"http://127.0.0.1:2380",
"http://127.0.0.1:7001",
},
ClientURLs: []string{
"http://127.0.0.1:2379",
"http://127.0.0.1:4001",
},
},
{
ID: 10666918107976480891,
Name: "node2",
PeerURLs: []string{
"http://127.0.0.1:7002",
},
ClientURLs: []string{
"http://127.0.0.1:4002",
},
},
),
},
}
got := MemberCollection{}
err := json.Unmarshal(body, &got)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
for i, tt := range tests {
var got MemberCollection
err := json.Unmarshal(tt.body, &got)
if err != nil {
t.Errorf("#%d: unexpected error: %v", i, err)
continue
}
if !reflect.DeepEqual(want, got) {
t.Errorf("Incorrect output: want=%#v, got=%#v", want, got)
if !reflect.DeepEqual(tt.want, got) {
t.Errorf("#%d: incorrect output: want=%#v, got=%#v", i, tt.want, got)
}
}
}