From 800747e1cf257ade3092044bb278363f4503c88d Mon Sep 17 00:00:00 2001 From: Xiang Li Date: Mon, 17 Nov 2014 11:21:16 -0800 Subject: [PATCH] integration: add test for member restart --- integration/cluster_test.go | 56 ++++++++++++++++++++++++------------- integration/member_test.go | 40 ++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 20 deletions(-) create mode 100644 integration/member_test.go diff --git a/integration/cluster_test.go b/integration/cluster_test.go index 3b5789eb0..f304005e2 100644 --- a/integration/cluster_test.go +++ b/integration/cluster_test.go @@ -99,23 +99,6 @@ func testDoubleClusterSize(t *testing.T, size int) { clusterMustProgress(t, c) } -func TestLaunchDuplicateMemberShouldFail(t *testing.T) { - size := 3 - c := NewCluster(t, size) - m := c.Members[0].Clone() - var err error - m.DataDir, err = ioutil.TempDir(os.TempDir(), "etcd") - if err != nil { - t.Fatal(err) - } - c.Launch(t) - defer c.Terminate(t) - - if err := m.Launch(); err == nil { - t.Errorf("unexpect successful launch") - } -} - // clusterMustProgress ensures that cluster can make progress. It creates // a key first, and check the new key could be got from all client urls of // the cluster. @@ -314,6 +297,24 @@ func newLocalListener(t *testing.T) net.Listener { return l } +func newListenerWithAddr(t *testing.T, addr string) net.Listener { + var err error + var l net.Listener + // TODO: we want to reuse a previous closed port immediately. + // a better way is to set SO_REUSExx instead of doing retry. + for i := 0; i < 3; i++ { + l, err = net.Listen("tcp", addr) + if err == nil { + break + } + time.Sleep(500 * time.Millisecond) + } + if err != nil { + t.Fatal(err) + } + return l +} + type member struct { etcdserver.ServerConfig PeerListeners, ClientListeners []net.Listener @@ -417,12 +418,27 @@ func (m *member) Launch() error { // Stop stops the member, but the data dir of the member is preserved. func (m *member) Stop(t *testing.T) { - panic("unimplemented") + m.s.Stop() + for _, hs := range m.hss { + hs.CloseClientConnections() + hs.Close() + } + m.hss = nil } // Start starts the member using the preserved data dir. -func (m *member) Start(t *testing.T) { - panic("unimplemented") +func (m *member) Restart(t *testing.T) error { + newPeerListeners := make([]net.Listener, 0) + for _, ln := range m.PeerListeners { + newPeerListeners = append(newPeerListeners, newListenerWithAddr(t, ln.Addr().String())) + } + m.PeerListeners = newPeerListeners + newClientListeners := make([]net.Listener, 0) + for _, ln := range m.ClientListeners { + newClientListeners = append(newClientListeners, newListenerWithAddr(t, ln.Addr().String())) + } + m.ClientListeners = newClientListeners + return m.Launch() } // Terminate stops the member and removes the data dir. diff --git a/integration/member_test.go b/integration/member_test.go new file mode 100644 index 000000000..7a8457fe7 --- /dev/null +++ b/integration/member_test.go @@ -0,0 +1,40 @@ +package integration + +import ( + "io/ioutil" + "os" + "testing" +) + +func TestRestartMember(t *testing.T) { + defer afterTest(t) + c := NewCluster(t, 3) + c.Launch(t) + defer c.Terminate(t) + + for i := 0; i < 3; i++ { + c.Members[i].Stop(t) + err := c.Members[i].Restart(t) + if err != nil { + t.Fatal(err) + } + } + clusterMustProgress(t, c) +} + +func TestLaunchDuplicateMemberShouldFail(t *testing.T) { + size := 3 + c := NewCluster(t, size) + m := c.Members[0].Clone() + var err error + m.DataDir, err = ioutil.TempDir(os.TempDir(), "etcd") + if err != nil { + t.Fatal(err) + } + c.Launch(t) + defer c.Terminate(t) + + if err := m.Launch(); err == nil { + t.Errorf("unexpect successful launch") + } +}