/**
* Licensed to Ravel, Inc. under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. Ravel, Inc. 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.goldenorb.zookeeper;
import static org.junit.Assert.assertTrue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.apache.zookeeper.ZooKeeper;
import org.goldenorb.conf.OrbConfiguration;
import org.junit.Test;
/**
* Tests OrbBarrier by using Threads to simulate multiple members joining under a barrier in ZooKeeper.
*
* @author long
*
*/
public class OrbBarrierTest {
OrbConfiguration orbConf = new OrbConfiguration(true);
String barrierName = "/TestBarrierName";
CountDownLatch startLatch = new CountDownLatch(1);
int numOfMembers;
/**
* Tests the behavior of the barrier if all expected member nodes join in a timely manner.
*
* @throws Exception
*/
@Test
public void allMembersJoin() throws Exception {
numOfMembers = 3;
CountDownLatch everyoneDoneLatch = new CountDownLatch(numOfMembers);
orbConf.setOrbZooKeeperQuorum("localhost:21810");
ZooKeeper zk = ZookeeperUtils.connect(orbConf.getOrbZooKeeperQuorum());
OrbBarrier testBarrier1 = new OrbBarrier(orbConf, barrierName, numOfMembers, "member1", zk);
OrbBarrier testBarrier2 = new OrbBarrier(orbConf, barrierName, numOfMembers, "member2", zk);
OrbBarrier testBarrier3 = new OrbBarrier(orbConf, barrierName, numOfMembers, "member3", zk);
BarrierThread bThread1 = new BarrierThread(testBarrier1, startLatch, everyoneDoneLatch);
BarrierThread bThread2 = new BarrierThread(testBarrier2, startLatch, everyoneDoneLatch);
BarrierThread bThread3 = new BarrierThread(testBarrier3, startLatch, everyoneDoneLatch);
bThread1.start();
bThread2.start();
bThread3.start();
startLatch.countDown(); // start all threads
everyoneDoneLatch.await(); // wait until all threads are done
assertTrue(zk.exists(barrierName + "/member1", false) != null);
assertTrue(zk.exists(barrierName + "/member2", false) != null);
assertTrue(zk.exists(barrierName + "/member3", false) != null);
ZookeeperUtils.deleteNodeIfEmpty(zk, barrierName + "/member1");
ZookeeperUtils.deleteNodeIfEmpty(zk, barrierName + "/member2");
ZookeeperUtils.deleteNodeIfEmpty(zk, barrierName + "/member3");
ZookeeperUtils.deleteNodeIfEmpty(zk, barrierName);
zk.close();
}
/**
* Tests the behavior of the barrier if only some of the member nodes join.
*
* @throws Exception
*/
@Test
public void someMembersJoin() throws Exception {
numOfMembers = 3;
CountDownLatch everyoneDoneLatch = new CountDownLatch(numOfMembers);
CountDownLatch lastMemberLatch = new CountDownLatch(1);
orbConf.setOrbZooKeeperQuorum("localhost:21810");
ZooKeeper zk = ZookeeperUtils.connect(orbConf.getOrbZooKeeperQuorum());
OrbBarrier testBarrier1 = new OrbBarrier(orbConf, barrierName, numOfMembers, "member1", zk);
OrbBarrier testBarrier2 = new OrbBarrier(orbConf, barrierName, numOfMembers, "member2", zk);
OrbBarrier testBarrier3 = new OrbBarrier(orbConf, barrierName, numOfMembers, "member3", zk);
BarrierThread bThread1 = new BarrierThread(testBarrier1, startLatch, everyoneDoneLatch);
BarrierThread bThread2 = new BarrierThread(testBarrier2, startLatch, everyoneDoneLatch);
BarrierThread bThread3 = new BarrierThread(testBarrier3, lastMemberLatch, everyoneDoneLatch);
bThread1.start();
bThread2.start();
bThread3.start();
startLatch.countDown(); // start first 2 threads
everyoneDoneLatch.await(500, TimeUnit.MILLISECONDS); // wait on the threads with 500ms timeout, expect to
// timeout
lastMemberLatch.countDown(); // start the last member
everyoneDoneLatch.await();
assertTrue(zk.exists(barrierName + "/member1", false) != null);
assertTrue(zk.exists(barrierName + "/member2", false) != null);
assertTrue(zk.exists(barrierName + "/member3", false) != null);
ZookeeperUtils.deleteNodeIfEmpty(zk, barrierName + "/member1");
ZookeeperUtils.deleteNodeIfEmpty(zk, barrierName + "/member2");
ZookeeperUtils.deleteNodeIfEmpty(zk, barrierName + "/member3");
ZookeeperUtils.deleteNodeIfEmpty(zk, barrierName);
zk.close();
}
/**
* This class defines a Thread that is used to start a member and have it enter the barrier.
*
* @author long
*
*/
class BarrierThread extends Thread {
private OrbBarrier testBarrier;
private CountDownLatch startLatch;
private CountDownLatch everyoneDoneLatch;
/**
* Constructs the BarrierThread.
*
* @param barrier
* - name of the OrbBarrier
* @param startLatch
* - Used in conjunction with countDown within the calling block of code to start Threads
* @param everyoneDoneLatch
* - Used to wait for all Threads to finish
*/
public BarrierThread(OrbBarrier barrier, CountDownLatch startLatch, CountDownLatch everyoneDoneLatch) {
this.testBarrier = barrier;
this.startLatch = startLatch;
this.everyoneDoneLatch = everyoneDoneLatch;
}
/**
* Runs the Thread to enter the barrier. It first awaits the latch to start, then enters, and finally
* counts down the everyoneDoneLatch once it is finished.
*/
public void run() {
try {
startLatch.await(); // wait for CountDown signal
testBarrier.enter();
everyoneDoneLatch.countDown(); // thread completed
} catch (OrbZKFailure e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}