/** * Copyright 2011 LiveRamp * * 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 com.liveramp.hank.coordinator.zk; import com.liveramp.hank.coordinator.Coordinator; import com.liveramp.hank.coordinator.Domain; import com.liveramp.hank.coordinator.HostCommand; import com.liveramp.hank.coordinator.HostDomain; import com.liveramp.hank.coordinator.HostState; import com.liveramp.hank.coordinator.Hosts; import com.liveramp.hank.coordinator.PartitionServerAddress; import com.liveramp.hank.coordinator.mock.MockCoordinator; import com.liveramp.hank.coordinator.mock.MockDomain; import com.liveramp.hank.test.ZkTestCase; import com.liveramp.hank.util.Condition; import com.liveramp.hank.util.WaitUntil; import org.junit.Before; import org.junit.Test; import java.io.IOException; import java.util.Arrays; import java.util.Collections; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; public class TestZkHost extends ZkTestCase { private static final PartitionServerAddress ADDRESS = new PartitionServerAddress("my.super.host", 32267); private static final PartitionServerAddress OTHER_ADDRESS = new PartitionServerAddress("my.other.host", 32267); private Coordinator coordinator; private Domain d0 = new MockDomain("d0"); @Before public void setUp() throws Exception { coordinator = new MockCoordinator() { @Override public Domain getDomainById(int domainId) { if (domainId == 0) { return d0; } else { throw new IllegalStateException(); } } }; } @Test public void testCreateAndLoad() throws Exception { final ZkHost host = ZkHost.create(getZk(), coordinator, getRoot(), ADDRESS, null, Collections.<String>emptyList()); assertEquals(ADDRESS, host.getAddress()); assertEquals(0, host.getCommandQueue().size()); assertNull(host.getCurrentCommand()); assertEquals(HostState.OFFLINE, host.getState()); assertFalse(Hosts.isOnline(host)); host.setEphemeralStatistic("a", "A"); host.setEphemeralStatistic("b", "B"); WaitUntil.orDie(new Condition() { @Override public boolean test() { try { return "A".equals(host.getStatistic("a")) && "B".equals(host.getStatistic("b")); } catch (IOException e) { throw new RuntimeException(e); } } }); assertEquals("A", host.getStatistic("a")); assertEquals("B", host.getStatistic("b")); assertNull(host.getStatistic("c")); host.setAddress(OTHER_ADDRESS); WaitUntil.orDie(new Condition() { @Override public boolean test() { return host.getAddress().equals(OTHER_ADDRESS); } }); assertEquals(OTHER_ADDRESS, host.getAddress()); } @Test public void testStateChangeListener() throws Exception { ZkHost host = ZkHost.create(getZk(), coordinator, getRoot(), ADDRESS, null, Collections.<String>emptyList()); MockHostStateChangeListener mockListener = new MockHostStateChangeListener(); host.setStateChangeListener(mockListener); synchronized (mockListener) { mockListener.wait(100); } assertNull("should not receive a callback until something is changed...", mockListener.calledWith); host.setState(HostState.SERVING); synchronized (mockListener) { mockListener.wait(1000); } assertNotNull("mock listener should have received a call!", mockListener.calledWith); assertEquals(HostState.SERVING, mockListener.calledWith); host.close(); } @Test public void testSetState() throws Exception { ZkHost host = ZkHost.create(getZk(), coordinator, getRoot(), ADDRESS, null, Collections.<String>emptyList()); assertEquals(HostState.OFFLINE, host.getState()); assertFalse(Hosts.isOnline(host)); host.setState(HostState.IDLE); waitUntilHost(HostState.IDLE, host); assertEquals(HostState.IDLE, host.getState()); assertTrue(Hosts.isOnline(host)); host.setState(HostState.OFFLINE); waitUntilHost(HostState.OFFLINE, host); assertEquals(HostState.OFFLINE, host.getState()); assertFalse(Hosts.isOnline(host)); host.close(); } @Test public void testCommandQueue() throws Exception { ZkHost host = ZkHost.create(getZk(), coordinator, getRoot(), ADDRESS, null, Collections.<String>emptyList()); assertEquals(Collections.EMPTY_LIST, host.getCommandQueue()); assertNull(host.getCurrentCommand()); host.enqueueCommand(HostCommand.GO_TO_IDLE); assertEquals(Arrays.asList(HostCommand.GO_TO_IDLE), host.getCommandQueue()); assertNull(host.getCurrentCommand()); host.enqueueCommand(HostCommand.SERVE_DATA); assertEquals(Arrays.asList(HostCommand.GO_TO_IDLE, HostCommand.SERVE_DATA), host.getCommandQueue()); assertNull(host.getCurrentCommand()); assertEquals(HostCommand.GO_TO_IDLE, host.nextCommand()); waitUntilCommand(HostCommand.GO_TO_IDLE, host); assertEquals(HostCommand.GO_TO_IDLE, host.getCurrentCommand()); assertEquals(Arrays.asList(HostCommand.SERVE_DATA), host.getCommandQueue()); assertEquals(Arrays.asList(HostCommand.SERVE_DATA), host.getCommandQueue()); host.clearCommandQueue(); assertEquals(Collections.EMPTY_LIST, host.getCommandQueue()); host.close(); } @Test public void testCommandQueueListener() throws Exception { ZkHost host = ZkHost.create(getZk(), coordinator, getRoot(), ADDRESS, null, Collections.<String>emptyList()); MockHostCommandQueueChangeListener l2 = new MockHostCommandQueueChangeListener(); host.setCommandQueueChangeListener(l2); MockHostStateChangeListener l1 = new MockHostStateChangeListener(); host.setStateChangeListener(l1); assertNull(l1.calledWith); assertNull(l2.calledWith); host.enqueueCommand(HostCommand.EXECUTE_UPDATE); l2.waitForNotification(); assertNull(l1.calledWith); assertEquals(host, l2.calledWith); l2.calledWith = null; host.enqueueCommand(HostCommand.SERVE_DATA); l2.waitForNotification(); assertNull(l1.calledWith); assertEquals(host, l2.calledWith); l2.calledWith = null; host.enqueueCommand(HostCommand.GO_TO_IDLE); l2.waitForNotification(); assertNull(l1.calledWith); assertEquals(host, l2.calledWith); l2.calledWith = null; host.nextCommand(); l2.waitForNotification(); assertNull(l1.calledWith); assertEquals(host, l2.calledWith); l2.calledWith = null; host.nextCommand(); l2.waitForNotification(); assertNull(l1.calledWith); assertEquals(host, l2.calledWith); l2.calledWith = null; host.nextCommand(); l2.waitForNotification(); assertNull(l1.calledWith); assertEquals(host, l2.calledWith); l2.calledWith = null; host.nextCommand(); l2.waitForNotification(true); assertNull(l1.calledWith); assertNull(l2.calledWith); } @Test public void testDomains() throws Exception { final ZkHost host = ZkHost.create(getZk(), coordinator, getRoot(), ADDRESS, null, Collections.<String>emptyList()); assertEquals(0, host.getAssignedDomains().size()); host.addDomain(d0); WaitUntil.orDie(new Condition() { @Override public boolean test() { try { return !host.getAssignedDomains().isEmpty(); } catch (IOException e) { throw new RuntimeException(e); } } }); HostDomain hostDomain = (HostDomain) host.getAssignedDomains().toArray()[0]; assertEquals(0, hostDomain.getDomain().getId()); assertEquals(0, host.getHostDomain(d0).getDomain().getId()); } @Test public void testUptime() throws Exception { ZkHost host = ZkHost.create(getZk(), coordinator, getRoot(), ADDRESS, null, Collections.<String>emptyList()); assertNull(host.getUpSince()); final long currentTimeMillis = System.currentTimeMillis(); host.setState(HostState.IDLE); dumpZk(); Thread.sleep(2000); assertNotNull(host.getUpSince()); assertTrue(host.getUpSince() >= currentTimeMillis); } }