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  }