浏览代码

httptypes: use MemberCollection for JSON (de)serialization

Brian Waldon 11 年之前
父节点
当前提交
14795d8ed9

+ 1 - 1
client/members.go

@@ -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 {

+ 23 - 6
etcdserver/etcdhttp/client.go

@@ -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
+}

+ 3 - 9
etcdserver/etcdhttp/client_test.go

@@ -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"},
 	}

+ 36 - 6
etcdserver/etcdhttp/httptypes/member.go

@@ -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 []Member
+
+func (c *MemberCollection) MarshalJSON() ([]byte, error) {
+	d := struct {
+		Members []Member `json:"members"`
+	}{
+		Members: []Member(*c),
+	}
+
+	return json.Marshal(d)
 }
 
-type MemberCollection struct {
-	Members []Member
+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
 }

+ 55 - 42
etcdserver/etcdhttp/httptypes/member_test.go

@@ -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",
-				},
-				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",
+	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",
+						},
+					},
 				},
-			},
+			),
 		},
 	}
 
-	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)
+		}
 	}
 }