/* * Copyright 2014 NAVER Corp. * * 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.navercorp.pinpoint.web.cluster; import com.navercorp.pinpoint.common.util.NetUtils; import com.navercorp.pinpoint.rpc.client.DefaultPinpointClientFactory; import com.navercorp.pinpoint.rpc.client.PinpointClient; import com.navercorp.pinpoint.rpc.client.PinpointClientFactory; import com.navercorp.pinpoint.rpc.client.SimpleMessageListener; import com.navercorp.pinpoint.web.cluster.connection.ClusterConnectionManager; import com.navercorp.pinpoint.web.cluster.zookeeper.ZookeeperClusterDataManager; import com.navercorp.pinpoint.web.config.WebConfig; import com.navercorp.pinpoint.web.TestAwaitTaskUtils; import com.navercorp.pinpoint.web.TestAwaitUtils; import com.navercorp.pinpoint.web.util.PinpointWebTestUtils; import org.apache.curator.test.TestingServer; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.ZooKeeper; import org.junit.After; import org.junit.AfterClass; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.util.SocketUtils; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.Iterator; import java.util.List; /** * @author Taejin Koo */ public class ClusterTest { private static final Logger LOGGER = LoggerFactory.getLogger(ClusterTest.class); private static final Charset UTF_8_CHARSET = StandardCharsets.UTF_8; // some tests may fail when executed in local environment // when failures happen, you have to copy pinpoint-web.properties of resource-test to resource-local. Tests will succeed. private static TestAwaitUtils awaitUtils = new TestAwaitUtils(100, 10000); private static final String DEFAULT_IP = PinpointWebTestUtils.getRepresentationLocalV4Ip(); static ClusterConnectionManager clusterConnectionManager; static ZookeeperClusterDataManager clusterDataManager; private static String CLUSTER_NODE_PATH; private static int acceptorPort; private static int zookeeperPort; private static String acceptorAddress; private static String zookeeperAddress; private static TestingServer ts = null; @BeforeClass public static void setUp() throws Exception { acceptorPort = SocketUtils.findAvailableTcpPort(28000); acceptorAddress = DEFAULT_IP + ":" + acceptorPort; zookeeperPort = SocketUtils.findAvailableTcpPort(acceptorPort + 1); zookeeperAddress = DEFAULT_IP + ":" + zookeeperPort; ts = createZookeeperServer(zookeeperPort); CLUSTER_NODE_PATH = "/pinpoint-cluster/web/" + acceptorAddress; LOGGER.debug("CLUSTER_NODE_PATH:{}", CLUSTER_NODE_PATH); WebConfig config = mock(WebConfig.class); when(config.isClusterEnable()).thenReturn(true); when(config.getClusterTcpPort()).thenReturn(acceptorPort); when(config.getClusterZookeeperAddress()).thenReturn(zookeeperAddress); when(config.getClusterZookeeperRetryInterval()).thenReturn(60000); when(config.getClusterZookeeperSessionTimeout()).thenReturn(3000); clusterConnectionManager = new ClusterConnectionManager(config); clusterConnectionManager.start(); clusterDataManager = new ZookeeperClusterDataManager(config); clusterDataManager.start(); List<String> localV4IpList = NetUtils.getLocalV4IpList(); clusterDataManager.registerWebCluster(acceptorAddress, convertIpListToBytes(localV4IpList, "\r\n")); } @AfterClass public static void tearDown() throws Exception { closeZookeeperServer(ts); try { clusterDataManager.stop(); } catch (Exception ignore) { } try { clusterConnectionManager.stop(); } catch (Exception ignore) { } } private static TestingServer createZookeeperServer(int port) throws Exception { TestingServer mockZookeeperServer = new TestingServer(port); mockZookeeperServer.start(); return mockZookeeperServer; } private static void closeZookeeperServer(TestingServer mockZookeeperServer) throws Exception { try { if (mockZookeeperServer != null) { mockZookeeperServer.close(); } } catch (Exception e) { e.printStackTrace(); } } private static byte[] convertIpListToBytes(List<String> ipList, String delimiter) { StringBuilder stringBuilder = new StringBuilder(); Iterator<String> ipIterator = ipList.iterator(); while (ipIterator.hasNext()) { String eachIp = ipIterator.next(); stringBuilder.append(eachIp); if (ipIterator.hasNext()) { stringBuilder.append(delimiter); } } return stringBuilder.toString().getBytes(UTF_8_CHARSET); } @After public void after() throws Exception { ts.restart(); } @Test public void clusterTest1() throws Exception { ZooKeeper zookeeper = new ZooKeeper(zookeeperAddress, 5000, null); awaitZookeeperConnected(zookeeper); if (zookeeper != null) { zookeeper.close(); } } @Test public void clusterTest2() throws Exception { ZooKeeper zookeeper = new ZooKeeper(zookeeperAddress, 5000, null); awaitZookeeperConnected(zookeeper); ts.stop(); awaitZookeeperDisconnected(zookeeper); try { zookeeper.getData(CLUSTER_NODE_PATH, null, null); Assert.fail(); } catch (KeeperException e) { Assert.assertEquals(KeeperException.Code.CONNECTIONLOSS, e.code()); // TODO Auto-generated catch block e.printStackTrace(); } ts.restart(); getNodeAndCompareContents(zookeeper); if (zookeeper != null) { zookeeper.close(); } } @Test public void clusterTest3() throws Exception { PinpointClientFactory clientFactory = null; PinpointClient client = null; ZooKeeper zookeeper = null; try { zookeeper = new ZooKeeper(zookeeperAddress, 5000, null); awaitZookeeperConnected(zookeeper); Assert.assertEquals(0, clusterConnectionManager.getClusterList().size()); clientFactory = new DefaultPinpointClientFactory(); clientFactory.setMessageListener(SimpleMessageListener.INSTANCE); client = clientFactory.connect(DEFAULT_IP, acceptorPort); awaitPinpointClientConnected(clusterConnectionManager); Assert.assertEquals(1, clusterConnectionManager.getClusterList().size()); } finally { closePinpointSocket(clientFactory, client); if (zookeeper != null) { zookeeper.close(); } } } private void awaitZookeeperConnected(final ZooKeeper zookeeper) { boolean pass = awaitUtils.await(new TestAwaitTaskUtils() { @Override public boolean checkCompleted() { return getNodeAndCompareContents0(zookeeper); } }); Assert.assertTrue(pass); } private void awaitZookeeperDisconnected(final ZooKeeper zookeeper) { boolean pass = awaitUtils.await(new TestAwaitTaskUtils() { @Override public boolean checkCompleted() { return !getNodeAndCompareContents0(zookeeper); } }); Assert.assertTrue(pass); } private void awaitPinpointClientConnected(final ClusterConnectionManager connectionManager) { boolean pass = awaitUtils.await(new TestAwaitTaskUtils() { @Override public boolean checkCompleted() { return !connectionManager.getClusterList().isEmpty(); } }); Assert.assertTrue(pass); } private void getNodeAndCompareContents(ZooKeeper zookeeper) throws KeeperException, InterruptedException { LOGGER.debug("getNodeAndCompareContents() {}", CLUSTER_NODE_PATH); byte[] contents = zookeeper.getData(CLUSTER_NODE_PATH, null, null); String[] registeredIplist = new String(contents).split("\r\n"); List<String> ipList = NetUtils.getLocalV4IpList(); Assert.assertEquals(registeredIplist.length, ipList.size()); for (String ip : registeredIplist) { Assert.assertTrue(ipList.contains(ip)); } } private boolean getNodeAndCompareContents0(ZooKeeper zookeeper) { try { LOGGER.debug("getNodeAndCompareContents() {}", CLUSTER_NODE_PATH); byte[] contents = zookeeper.getData(CLUSTER_NODE_PATH, null, null); if (contents == null) { contents = new byte[0]; } String[] registeredIplist = new String(contents).split("\r\n"); List<String> ipList = NetUtils.getLocalV4IpList(); if (registeredIplist.length != ipList.size()) { return false; } for (String ip : registeredIplist) { if (!ipList.contains(ip)) { return false; } } return true; } catch (Exception e) { LOGGER.warn(e.getMessage(), e); } return false; } private void closePinpointSocket(PinpointClientFactory clientFactory, PinpointClient client) { if (client != null) { client.close(); } if (clientFactory != null) { clientFactory.release(); } } }