/** * Copyright 2010 the original author or authors. * * Licensed 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.I0Itec.zkclient; import static org.junit.Assert.assertEquals; import java.util.List; import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher; import org.apache.zookeeper.Watcher.Event.KeeperState; import org.apache.zookeeper.ZooKeeper.States; import org.apache.zookeeper.data.ACL; import org.apache.zookeeper.data.Stat; import org.apache.zookeeper.Op; import org.apache.zookeeper.OpResult; import org.junit.After; import org.junit.Before; import org.junit.Test; public class ZkStateChangeTest { private StateOnlyConnection zkConn; private ZkClient client; private TestStateListener listener; @Before public void setUp() { zkConn = new StateOnlyConnection(); client = new ZkClient(zkConn); listener = new TestStateListener(); client.subscribeStateChanges(listener); } @After public void tearDown() { client.close(); } @Test public void testNewSessionEvent() throws Exception { zkConn.expireSession(); assertTimed(1, new Callable<Integer>() { @Override public Integer call() throws Exception { return listener.expiredEvents; } }); assertTimed(0, new Callable<Integer>() { @Override public Integer call() throws Exception { return listener.sessionEstablishErrors; } }); assertTimed(1, new Callable<Integer>() { @Override public Integer call() throws Exception { return listener.newSessionEvent; } }); } @Test public void testFailConnectEvent() throws Exception { zkConn.setFailOnConnect(true); zkConn.expireSession(); assertTimed(1, new Callable<Integer>() { @Override public Integer call() throws Exception { return listener.expiredEvents; } }); assertTimed(1, new Callable<Integer>() { @Override public Integer call() throws Exception { return listener.sessionEstablishErrors; } }); assertTimed(0, new Callable<Integer>() { @Override public Integer call() throws Exception { return listener.newSessionEvent; } }); client.close(); } private <T> void assertTimed(T expectedVal, Callable<T> condition) throws Exception { assertEquals(expectedVal, TestUtil.waitUntil(expectedVal, condition, TimeUnit.SECONDS, 5)); } private static class StateOnlyConnection implements IZkConnection { private Watcher _watcher; private boolean failOnConnect = false; @Override public void connect(Watcher w) { _watcher = w; if (failOnConnect) { // As as example: throw new RuntimeException("Testing connection failure"); } new Thread() { @Override public void run() { _watcher.process(new WatchedEvent(null, KeeperState.SyncConnected, null)); } }.start(); } public void expireSession() { _watcher.process(new WatchedEvent(null, KeeperState.Expired, null)); } public void setFailOnConnect(boolean failFlag) { this.failOnConnect = failFlag; } @Override public void close() throws InterruptedException { } @Override public String create(String path, byte[] data, CreateMode mode) throws KeeperException, InterruptedException { throw new RuntimeException("not implemented"); } @Override public String create(String path, byte[] data, List<ACL> acl, CreateMode mode) throws KeeperException, InterruptedException { throw new RuntimeException("not implemented"); } @Override public void delete(String path) throws InterruptedException, KeeperException { throw new RuntimeException("not implemented"); } @Override public void delete(String path, int version) throws InterruptedException, KeeperException { throw new RuntimeException("not implemented"); } @Override public boolean exists(final String path, final boolean watch) throws KeeperException, InterruptedException { throw new RuntimeException("not implemented"); } public List<String> getChildren(final String path, final boolean watch) throws KeeperException, InterruptedException { throw new RuntimeException("not implemented"); } @Override public byte[] readData(String path, Stat stat, boolean watch) throws KeeperException, InterruptedException { throw new RuntimeException("not implemented"); } @Override public void writeData(String path, byte[] data, int expectedVersion) throws KeeperException, InterruptedException { throw new RuntimeException("not implemented"); } @Override public Stat writeDataReturnStat(String path, byte[] data, int expectedVersion) throws KeeperException, InterruptedException { throw new RuntimeException("not implemented"); } @Override public States getZookeeperState() { throw new RuntimeException("not implemented"); } @Override public long getCreateTime(String path) throws KeeperException, InterruptedException { throw new RuntimeException("not implemented"); } @Override public String getServers() { return "test"; } @Override public List<OpResult> multi(Iterable<Op> ops) throws KeeperException, InterruptedException { throw new UnsupportedOperationException(); } @Override public void addAuthInfo(String scheme, byte[] auth) { throw new RuntimeException("not implemented"); } @Override public void setAcl(String path, List<ACL> acl, int version) throws KeeperException, InterruptedException { throw new UnsupportedOperationException(); } @Override public Map.Entry<List<ACL>, Stat> getAcl(String path) throws KeeperException, InterruptedException { throw new UnsupportedOperationException(); } } private static class TestStateListener implements IZkStateListener { public int expiredEvents = 0; public int newSessionEvent = 0; public int sessionEstablishErrors = 0; @Override public void handleStateChanged(KeeperState state) throws Exception { if (state == KeeperState.Expired) { expiredEvents++; } } @Override public void handleNewSession() throws Exception { newSessionEvent++; } @Override public void handleSessionEstablishmentError(final Throwable error) throws Exception { sessionEstablishErrors++; } } }