1// Copyright 2016 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 15package e2e 16 17import ( 18 "encoding/json" 19 "fmt" 20 "io" 21 "strings" 22 "testing" 23 24 "github.com/coreos/etcd/etcdserver/etcdserverpb" 25) 26 27func TestCtlV3MemberList(t *testing.T) { testCtl(t, memberListTest) } 28func TestCtlV3MemberRemove(t *testing.T) { 29 testCtl(t, memberRemoveTest, withQuorum(), withNoStrictReconfig()) 30} 31func TestCtlV3MemberAdd(t *testing.T) { testCtl(t, memberAddTest) } 32func TestCtlV3MemberUpdate(t *testing.T) { testCtl(t, memberUpdateTest) } 33 34func memberListTest(cx ctlCtx) { 35 if err := ctlV3MemberList(cx); err != nil { 36 cx.t.Fatalf("memberListTest ctlV3MemberList error (%v)", err) 37 } 38} 39 40func ctlV3MemberList(cx ctlCtx) error { 41 cmdArgs := append(cx.PrefixArgs(), "member", "list") 42 lines := make([]string, cx.cfg.clusterSize) 43 for i := range lines { 44 lines[i] = "started" 45 } 46 return spawnWithExpects(cmdArgs, lines...) 47} 48 49func getMemberList(cx ctlCtx) (etcdserverpb.MemberListResponse, error) { 50 cmdArgs := append(cx.PrefixArgs(), "--write-out", "json", "member", "list") 51 52 proc, err := spawnCmd(cmdArgs) 53 if err != nil { 54 return etcdserverpb.MemberListResponse{}, err 55 } 56 var txt string 57 txt, err = proc.Expect("members") 58 if err != nil { 59 return etcdserverpb.MemberListResponse{}, err 60 } 61 if err = proc.Close(); err != nil { 62 return etcdserverpb.MemberListResponse{}, err 63 } 64 65 resp := etcdserverpb.MemberListResponse{} 66 dec := json.NewDecoder(strings.NewReader(txt)) 67 if err := dec.Decode(&resp); err == io.EOF { 68 return etcdserverpb.MemberListResponse{}, err 69 } 70 return resp, nil 71} 72 73func memberRemoveTest(cx ctlCtx) { 74 ep, memIDToRemove, clusterID := cx.memberToRemove() 75 if err := ctlV3MemberRemove(cx, ep, memIDToRemove, clusterID); err != nil { 76 cx.t.Fatal(err) 77 } 78} 79 80func ctlV3MemberRemove(cx ctlCtx, ep, memberID, clusterID string) error { 81 cmdArgs := append(cx.prefixArgs([]string{ep}), "member", "remove", memberID) 82 return spawnWithExpect(cmdArgs, fmt.Sprintf("%s removed from cluster %s", memberID, clusterID)) 83} 84 85func memberAddTest(cx ctlCtx) { 86 if err := ctlV3MemberAdd(cx, fmt.Sprintf("http://localhost:%d", etcdProcessBasePort+11)); err != nil { 87 cx.t.Fatal(err) 88 } 89} 90 91func ctlV3MemberAdd(cx ctlCtx, peerURL string) error { 92 cmdArgs := append(cx.PrefixArgs(), "member", "add", "newmember", fmt.Sprintf("--peer-urls=%s", peerURL)) 93 return spawnWithExpect(cmdArgs, " added to cluster ") 94} 95 96func memberUpdateTest(cx ctlCtx) { 97 mr, err := getMemberList(cx) 98 if err != nil { 99 cx.t.Fatal(err) 100 } 101 102 peerURL := fmt.Sprintf("http://localhost:%d", etcdProcessBasePort+11) 103 memberID := fmt.Sprintf("%x", mr.Members[0].ID) 104 if err = ctlV3MemberUpdate(cx, memberID, peerURL); err != nil { 105 cx.t.Fatal(err) 106 } 107} 108 109func ctlV3MemberUpdate(cx ctlCtx, memberID, peerURL string) error { 110 cmdArgs := append(cx.PrefixArgs(), "member", "update", memberID, fmt.Sprintf("--peer-urls=%s", peerURL)) 111 return spawnWithExpect(cmdArgs, " updated in cluster ") 112} 113