go.etcd.io/etcd@v3.3.27+incompatible/etcdserver/api/etcdhttp/peer_test.go (about) 1 // Copyright 2015 The etcd Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package etcdhttp 16 17 import ( 18 "encoding/json" 19 "io/ioutil" 20 "net/http" 21 "net/http/httptest" 22 "path" 23 "sort" 24 "testing" 25 26 "github.com/coreos/etcd/etcdserver/membership" 27 "github.com/coreos/etcd/pkg/testutil" 28 "github.com/coreos/etcd/pkg/types" 29 "github.com/coreos/etcd/rafthttp" 30 "github.com/coreos/go-semver/semver" 31 ) 32 33 type fakeCluster struct { 34 id uint64 35 clientURLs []string 36 members map[uint64]*membership.Member 37 } 38 39 func (c *fakeCluster) ID() types.ID { return types.ID(c.id) } 40 func (c *fakeCluster) ClientURLs() []string { return c.clientURLs } 41 func (c *fakeCluster) Members() []*membership.Member { 42 var ms membership.MembersByID 43 for _, m := range c.members { 44 ms = append(ms, m) 45 } 46 sort.Sort(ms) 47 return []*membership.Member(ms) 48 } 49 func (c *fakeCluster) Member(id types.ID) *membership.Member { return c.members[uint64(id)] } 50 func (c *fakeCluster) Version() *semver.Version { return nil } 51 52 // TestNewPeerHandlerOnRaftPrefix tests that NewPeerHandler returns a handler that 53 // handles raft-prefix requests well. 54 func TestNewPeerHandlerOnRaftPrefix(t *testing.T) { 55 h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 56 w.Write([]byte("test data")) 57 }) 58 ph := newPeerHandler(&fakeCluster{}, h, nil) 59 srv := httptest.NewServer(ph) 60 defer srv.Close() 61 62 tests := []string{ 63 rafthttp.RaftPrefix, 64 rafthttp.RaftPrefix + "/hello", 65 } 66 for i, tt := range tests { 67 resp, err := http.Get(srv.URL + tt) 68 if err != nil { 69 t.Fatalf("unexpected http.Get error: %v", err) 70 } 71 body, err := ioutil.ReadAll(resp.Body) 72 if err != nil { 73 t.Fatalf("unexpected ioutil.ReadAll error: %v", err) 74 } 75 if w := "test data"; string(body) != w { 76 t.Errorf("#%d: body = %s, want %s", i, body, w) 77 } 78 } 79 } 80 81 func TestServeMembersFails(t *testing.T) { 82 tests := []struct { 83 method string 84 wcode int 85 }{ 86 { 87 "POST", 88 http.StatusMethodNotAllowed, 89 }, 90 { 91 "DELETE", 92 http.StatusMethodNotAllowed, 93 }, 94 { 95 "BAD", 96 http.StatusMethodNotAllowed, 97 }, 98 } 99 for i, tt := range tests { 100 rw := httptest.NewRecorder() 101 h := &peerMembersHandler{cluster: nil} 102 h.ServeHTTP(rw, &http.Request{Method: tt.method}) 103 if rw.Code != tt.wcode { 104 t.Errorf("#%d: code=%d, want %d", i, rw.Code, tt.wcode) 105 } 106 } 107 } 108 109 func TestServeMembersGet(t *testing.T) { 110 memb1 := membership.Member{ID: 1, Attributes: membership.Attributes{ClientURLs: []string{"http://localhost:8080"}}} 111 memb2 := membership.Member{ID: 2, Attributes: membership.Attributes{ClientURLs: []string{"http://localhost:8081"}}} 112 cluster := &fakeCluster{ 113 id: 1, 114 members: map[uint64]*membership.Member{1: &memb1, 2: &memb2}, 115 } 116 h := &peerMembersHandler{cluster: cluster} 117 msb, err := json.Marshal([]membership.Member{memb1, memb2}) 118 if err != nil { 119 t.Fatal(err) 120 } 121 wms := string(msb) + "\n" 122 123 tests := []struct { 124 path string 125 wcode int 126 wct string 127 wbody string 128 }{ 129 {peerMembersPrefix, http.StatusOK, "application/json", wms}, 130 {path.Join(peerMembersPrefix, "bad"), http.StatusBadRequest, "text/plain; charset=utf-8", "bad path\n"}, 131 } 132 133 for i, tt := range tests { 134 req, err := http.NewRequest("GET", testutil.MustNewURL(t, tt.path).String(), nil) 135 if err != nil { 136 t.Fatal(err) 137 } 138 rw := httptest.NewRecorder() 139 h.ServeHTTP(rw, req) 140 141 if rw.Code != tt.wcode { 142 t.Errorf("#%d: code=%d, want %d", i, rw.Code, tt.wcode) 143 } 144 if gct := rw.Header().Get("Content-Type"); gct != tt.wct { 145 t.Errorf("#%d: content-type = %s, want %s", i, gct, tt.wct) 146 } 147 if rw.Body.String() != tt.wbody { 148 t.Errorf("#%d: body = %s, want %s", i, rw.Body.String(), tt.wbody) 149 } 150 gcid := rw.Header().Get("X-Etcd-Cluster-ID") 151 wcid := cluster.ID().String() 152 if gcid != wcid { 153 t.Errorf("#%d: cid = %s, want %s", i, gcid, wcid) 154 } 155 } 156 }