You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@zookeeper.apache.org by mi...@apache.org on 2014/01/21 21:29:52 UTC
svn commit: r1560172 -
/zookeeper/trunk/src/java/test/org/apache/zookeeper/server/quorum/StandaloneDisabledTest.java
Author: michim
Date: Tue Jan 21 20:29:52 2014
New Revision: 1560172
URL: http://svn.apache.org/r1560172
Log:
ZOOKEEPER-1691. Add StandaloneDisabledTest.java (Helen Hastings via michim)
Added:
zookeeper/trunk/src/java/test/org/apache/zookeeper/server/quorum/StandaloneDisabledTest.java
Added: zookeeper/trunk/src/java/test/org/apache/zookeeper/server/quorum/StandaloneDisabledTest.java
URL: http://svn.apache.org/viewvc/zookeeper/trunk/src/java/test/org/apache/zookeeper/server/quorum/StandaloneDisabledTest.java?rev=1560172&view=auto
==============================================================================
--- zookeeper/trunk/src/java/test/org/apache/zookeeper/server/quorum/StandaloneDisabledTest.java (added)
+++ zookeeper/trunk/src/java/test/org/apache/zookeeper/server/quorum/StandaloneDisabledTest.java Tue Jan 21 20:29:52 2014
@@ -0,0 +1,243 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zookeeper.server.quorum;
+
+import static org.apache.zookeeper.test.ClientBase.CONNECTION_TIMEOUT;
+
+import java.util.ArrayList;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.data.Stat;
+import org.apache.zookeeper.PortAssignment;
+import org.apache.zookeeper.ZooKeeper;
+import org.apache.zookeeper.Watcher;
+import org.apache.zookeeper.TestableZooKeeper;
+import org.apache.zookeeper.test.ClientBase;
+import org.apache.zookeeper.test.ReconfigTest;
+import org.apache.zookeeper.AsyncCallback.StatCallback;
+import org.apache.zookeeper.server.quorum.QuorumPeerConfig;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class StandaloneDisabledTest extends QuorumPeerTestBase {
+
+ private final int NUM_SERVERS = 5;
+ private MainThread peers[];
+ private ZooKeeper zkHandles[];
+ private int clientPorts[];
+ private final int leaderId = 0;
+ private final int follower1 = 1;
+ private final int follower2 = 2;
+ private final int observer1 = 3;
+ private final int observer2 = 4;
+ private ArrayList<String> serverStrings;
+ private ArrayList<String> reconfigServers;
+
+ /**
+ * Test normal quorum operations work cleanly
+ * with just a single server.
+ */
+ @Test
+ public void startSingleServerTest() throws Exception {
+ setUpData();
+
+ //start one server
+ startServer(leaderId, serverStrings.get(leaderId) + "\n");
+ ReconfigTest.testServerHasConfig(zkHandles[leaderId], null, null);
+ LOG.info("Initial Configuration:\n"
+ + new String(zkHandles[leaderId].getConfig(this, new Stat())));
+
+ //start and add 2 followers
+ startFollowers();
+ testReconfig(leaderId, true, reconfigServers);
+ LOG.info("Configuration after adding 2 followers:\n"
+ + new String(zkHandles[leaderId].getConfig(this, new Stat())));
+
+ //shutdown leader- quorum should still exist
+ shutDownServer(leaderId);
+ ReconfigTest.testNormalOperation(zkHandles[follower1], zkHandles[follower2]);
+
+ //should not be able to remove follower 2
+ //No quorum in new config (1/2)
+ reconfigServers.clear();
+ reconfigServers.add(Integer.toString(follower2));
+ try {
+ ReconfigTest.reconfig(zkHandles[follower1], null, reconfigServers, null, -1);
+ Assert.fail("reconfig completed successfully even though there is no quorum up in new config!");
+ } catch (KeeperException.NewConfigNoQuorum e) { }
+
+ //reconfigure out leader and follower 1. Remaining follower
+ //2 should elect itself as leader and run by itself
+ reconfigServers.clear();
+ reconfigServers.add(Integer.toString(leaderId));
+ reconfigServers.add(Integer.toString(follower1));
+ testReconfig(follower2, false, reconfigServers);
+ LOG.info("Configuration after removing leader and follower 1:\n"
+ + new String(zkHandles[follower2].getConfig(this, new Stat())));
+
+ //Add two participants and change them to observers to check
+ //that we can reconfigure down to one participant with observers.
+ ArrayList<String> observerStrings = new ArrayList<String>();
+ startObservers(observerStrings);
+ testReconfig(follower2, true, reconfigServers); //add partcipants
+ testReconfig(follower2, true, observerStrings); //change to observers
+ LOG.info("Configuration after adding two observers:\n"
+ + new String(zkHandles[follower2].getConfig(this, new Stat())));
+
+ shutDownData();
+ }
+
+ /**
+ * Initialize private data for test.
+ */
+ private void setUpData() throws Exception {
+ ClientBase.setupTestEnv();
+ QuorumPeerConfig.setStandaloneEnabled(false);
+ peers = new MainThread[NUM_SERVERS];
+ zkHandles = new ZooKeeper[NUM_SERVERS];
+ clientPorts = new int[NUM_SERVERS];
+ serverStrings = buildServerStrings();
+ reconfigServers = new ArrayList<String>();
+ }
+
+ /**
+ * Stop server threads.
+ */
+ private void shutDownData() throws Exception {
+ for (int i = 0; i < NUM_SERVERS; i++) {
+ zkHandles[i].close();
+ }
+ for (int i = 1; i < NUM_SERVERS; i++) {
+ peers[i].shutdown();
+ }
+ }
+
+ /**
+ * Create config strings that will be used for
+ * the test servers.
+ */
+ private ArrayList<String> buildServerStrings() {
+ ArrayList<String> serverStrings = new ArrayList<String>();
+
+ for(int i = 0; i < NUM_SERVERS; i++) {
+ clientPorts[i] = PortAssignment.unique();
+ String server = "server." + i + "=localhost:" + PortAssignment.unique()
+ +":"+PortAssignment.unique() + ":participant;"
+ + "localhost:" + clientPorts[i];
+ serverStrings.add(server);
+ }
+ return serverStrings;
+ }
+
+ /**
+ * Starts a single server in replicated mode,
+ * initializes its client, and waits for it
+ * to be connected.
+ */
+ private void startServer(int id, String config) throws Exception {
+ peers[id] = new MainThread(id, clientPorts[id], config);
+ zkHandles[id] = new ZooKeeper("127.0.0.1:" + clientPorts[id],
+ CONNECTION_TIMEOUT, this);
+ peers[id].start();
+ Assert.assertTrue("Server " + id + " is not up",
+ ClientBase.waitForServerUp("127.0.0.1:" + clientPorts[id], CONNECTION_TIMEOUT));
+ Assert.assertTrue("Error- Server started in Standalone Mode!",
+ peers[id].isQuorumPeerRunning());
+ }
+
+ /**
+ * Shuts down a server, waits for it to disconnect,
+ * and gives enough time for the learner handler
+ * in its ensemble to realize it's been shut down.
+ */
+ private void shutDownServer(int id) throws Exception {
+ peers[id].shutdown();
+ ClientBase.waitForServerDown("127.0.0.1:" + clientPorts[id], CONNECTION_TIMEOUT);
+ TimeUnit.SECONDS.sleep(25);
+ }
+
+ /**
+ * Starts servers 1 & 2 as participants and
+ * adds them to the list to be reconfigured
+ * into the ensemble.
+ */
+ private void startFollowers() throws Exception {
+ reconfigServers.clear();
+ for(int i = 1; i <= 2; i++) {
+ String config = serverStrings.get(leaderId) + "\n"
+ + serverStrings.get(i) + "\n"
+ + serverStrings.get(i % 2 + 1) + "\n";
+ startServer(i, config);
+ reconfigServers.add(serverStrings.get(i));
+ }
+ }
+ /**
+ * Starts servers 1 & 2 as participants,
+ * adds them to the list to be reconfigured
+ * into the ensemble, and adds an observer
+ * version of their information to a list
+ * so they will be turned into observers later.
+ */
+ private void startObservers(ArrayList<String> observerStrings) throws Exception {
+ reconfigServers.clear();
+ for(int i = observer1; i <= observer2; i++) {
+ String config = serverStrings.get(follower2) + "\n"
+ + serverStrings.get(i) + "\n";
+ startServer(i, config);
+ reconfigServers.add(serverStrings.get(i));
+ observerStrings.add(serverStrings.get(i).replace("participant", "observer"));
+ }
+ }
+
+ /**
+ * Calls reconfig on the client corresponding to id to add or remove
+ * the given servers. Tests appropriately to make sure the
+ * reconfig succeeded.
+ */
+ private void testReconfig(int id, boolean adding,
+ ArrayList<String> servers) throws Exception {
+ if (adding) {
+ ReconfigTest.reconfig(zkHandles[id], servers, null, null, -1);
+ for (String server : servers) {
+ int id2 = Integer.parseInt(server.substring(7, 8)); //server.#
+ ReconfigTest.testNormalOperation(zkHandles[id], zkHandles[id2]);
+ }
+ } else {
+ ReconfigTest.reconfig(zkHandles[id], null, servers, null, -1);
+ }
+
+ ReconfigTest.testServerHasConfig(zkHandles[id], servers, null);
+ }
+
+ /**
+ * Ensure observer cannot start by itself
+ **/
+ @Test
+ public void startObserver() throws Exception {
+ int clientPort = PortAssignment.unique();
+ String config = "server." + observer1 + "=localhost:"+ PortAssignment.unique()
+ + ":" + clientPort + ":observer;"
+ + "localhost:" + PortAssignment.unique();
+ MainThread observer = new MainThread(observer1, clientPort, config);
+ observer.start();
+ Assert.assertFalse("Observer was able to start by itself!",
+ ClientBase.waitForServerUp("127.0.0.1:" + clientPort, CONNECTION_TIMEOUT));
+ }
+}
\ No newline at end of file