package com.linkedin.databus2.test; /* * * Copyright 2013 LinkedIn Corp. All rights reserved * * 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. * */ import java.io.File; import java.io.IOException; import java.net.ConnectException; import java.net.Socket; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import org.I0Itec.zkclient.IDefaultNameSpace; import org.I0Itec.zkclient.ZkClient; import org.I0Itec.zkclient.ZkServer; import org.apache.commons.io.FileUtils; import org.apache.log4j.ConsoleAppender; import org.apache.log4j.FileAppender; import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.apache.log4j.PatternLayout; import org.testng.Assert; public class TestUtil { public static final SimpleDateFormat SIMPLE_TIMESTAMP_FORMAT = new SimpleDateFormat("yyyyMMdd-HHmmss"); public static void setupLoggingWithTimestampedFile(boolean logToConsole, String fileNamePrefix, String fileNameSuffix, Level logLevel) { final String fileName = fileNamePrefix + SIMPLE_TIMESTAMP_FORMAT.format(new Date()) + fileNameSuffix; setupLogging(logToConsole, fileName, logLevel); } public static void setupLogging(Level logLevel) { setupLogging(true, "", logLevel); } public static void setupLogging(boolean logToConsole, String fileLogPath, Level logLevel) { PatternLayout defaultLayout = new PatternLayout("%d{ISO8601} [%t] (%p) {%c{1}} %m%n"); Logger.getRootLogger().removeAllAppenders(); if (logToConsole) { ConsoleAppender defaultAppender = new ConsoleAppender(defaultLayout); Logger.getRootLogger().addAppender(defaultAppender); } if (null != fileLogPath && 0 < fileLogPath.length()) { File logFile = new File(fileLogPath); if (null != logFile.getParentFile() && ! logFile.getParentFile().exists()) { if (! logFile.getParentFile().mkdirs()) { Logger.getRootLogger().error("unable to create parent directory for log file: " + logFile); } } FileAppender fileAppender = null; try { fileAppender = new FileAppender(defaultLayout, fileLogPath); } catch (IOException io) { Logger.getRootLogger().error(io); } if (null != fileAppender) Logger.getRootLogger().addAppender(fileAppender); } Logger.getRootLogger().setLevel(logLevel); } /** * Sleep with catch of InterrupedException. If the exception is thrown, the sleep will be * interrupted without reaching the full timeout.*/ public static void sleep(long millis) { try { Thread.sleep(millis); } catch (InterruptedException ie){} } /** * in case we are running in Eclipse - adjust base dir * @return true if running in eclipse */ public static final String ECLIPSE_TEST_BASE_DIR = "ECLIPSE_TEST_BASE_DIR"; public static boolean setupEclipsePath() { String prop = System.getProperty("java.class.path"); if(prop!=null && prop.contains("eclipse")) { System.setProperty(ECLIPSE_TEST_BASE_DIR, "../.."); return true; } else { return false; } } /** * Perform an assert on a condition with exponentially increasing timeouts between checks. Useful * for checking asynchronous conditions. The timeouts start from 1 ms and double on every failure * of the condition check until a maximum threshold is reached. * * @param check implements the condition check * @param message message for logging purposes * @param maxTimeoutMs the maximum timeout in milliseconds. * @param log logger for diagnostic messages (can be null) */ public static void assertWithBackoff(ConditionCheck check, String message, long maxTimeoutMs, Logger log) { boolean done = check.check(); long sleepDuration = 1; while (!done && sleepDuration < maxTimeoutMs) { if (null != log) log.info("sleeping for " + sleepDuration + " ms while waiting for condition: " + message); sleep(sleepDuration); done = check.check(); sleepDuration = (long)(1.3 * sleepDuration + 1); } Assert.assertTrue(check.check(), message); } /** * Checks if a server is running on a given host and port * @param host the server host * @param port the server port * @param log logger for diagnostic messages (can be null) * @return true if successful */ public static boolean checkServerRunning(String host, int port, Logger log) { return checkServerRunning(host, port, log, true); } /** * Checks if a server is running on a given host and port * @param host the server host * @param port the server port * @param log logger for diagnostic messages (can be null) * @return true if successful * @throws IOException */ public static boolean checkServerRunning(String host, int port, Logger log, boolean logError) { boolean success = false; try { Socket socket = new Socket(host, port); log.info( "host=" + host + " port=" + port); log.info("Socket Info:" + socket.toString()); log.info("IsConnected=" + socket.isConnected() + " isClosed=" + socket.isClosed() + " isBound=" + socket.isBound()); success = socket.isConnected(); socket.close(); } catch (ConnectException ce) { if (null != log) log.error("Fail to connect to port:" + port); if (logError && null != log) log.error("Connect error", ce); success = false; } catch (IOException e) { if (logError && null != log) log.error("connect error", e); } catch (RuntimeException e) { if (logError && null != log) log.error("runtime error", e); } return success; } /** * * @author snagaraj (originally by mitch stuart) * */ public static List<ZkServer> startLocalZookeeper( List<Integer> localPortsList, String zkTestDataRootDir, int tickTime) throws IOException { List<ZkServer> localZkServers = new ArrayList<ZkServer>(); int count = 0; for (int port : localPortsList) { ZkServer zkServer = startZkServer(zkTestDataRootDir, count++, port, tickTime); localZkServers.add(zkServer); } return localZkServers; } public static ZkServer startZkServer(String zkTestDataRootDir, int machineId, int port, int tickTime) throws IOException { File zkTestDataRootDirFile = new File(zkTestDataRootDir); zkTestDataRootDirFile.mkdirs(); String dataPath = zkTestDataRootDir + "/" + machineId + "/" + port + "/data"; String logPath = zkTestDataRootDir + "/" + machineId + "/" + port + "/log"; FileUtils.deleteDirectory(new File(dataPath)); FileUtils.deleteDirectory(new File(logPath)); IDefaultNameSpace mockDefaultNameSpace = new IDefaultNameSpace() { @Override public void createDefaultNameSpace(ZkClient zkClient) { } }; ZkServer zkServer = new ZkServer(dataPath, logPath, mockDefaultNameSpace, port, tickTime); zkServer.start(); return zkServer; } static public void stopLocalZookeeper(List<ZkServer> localZkServers) { for (ZkServer zkServer : localZkServers) { zkServer.shutdown(); } } static public String join(String[] name, String delim) { StringBuilder joined = new StringBuilder(); if (name.length > 0) { joined.append(name[0]); for (int i = 1; i < name.length; ++i) { joined.append(delim); joined.append(name[i]); } } return joined.toString(); } }