package com.arjuna.qa.extension; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.logging.Logger; import org.jboss.arquillian.container.spi.Container; import org.jboss.arquillian.container.spi.ServerKillProcessor; /** * JBoss Server kill processor base class. * @author <a href="mailto:hhovsepy@redhat.com">Hayk Hovsepyan</a> */ public abstract class BaseServerKillProcessor implements ServerKillProcessor { protected final int checkPeriodMillis = 10 * 1000; protected final int numChecks = 60; protected static int processLogId = 0; protected abstract String runShellCommand(String cmd) throws Exception; protected abstract Logger getLogger(); protected abstract String getJBossAliveCmd(); protected abstract String getDefunctJavaCmd(); protected abstract String getShutdownJBossCmd(); protected abstract String getProcessesCmd(); @Override public void kill(Container container) throws Exception { getLogger().info("waiting for byteman to kill the server"); for (int i = 0; i < numChecks; i++) { if (jbossIsAlive()) { Thread.sleep(checkPeriodMillis); getLogger().info("jboss-as is still alive, sleeping for a further " + checkPeriodMillis + "ms"); } else if (isDefunctJavaProcess()) { getLogger().info("Found a defunct java process, sleeping for a further " + checkPeriodMillis + "ms"); dumpProcesses(container); } else { getLogger().info("jboss-as killed by byteman scirpt"); dumpProcesses(container); return; } } //We've waited long enough for Byteman to kill the server and it has not yet done it. // Kill the server manually and fail the test shutdownJBoss(); throw new RuntimeException("jboss-as was not killed by Byteman, this indicates a test failure"); } protected boolean jbossIsAlive() throws Exception { //Command will 'res != null' if jboss is not running and 'res == null' if it is return !isEmpty(runShellCommand(getJBossAliveCmd())); } protected boolean isDefunctJavaProcess() throws Exception { //Command will 'res != null' if a defunct java process is not running and 'res == null' if there is return !isEmpty(runShellCommand(getDefunctJavaCmd())); } protected void shutdownJBoss() throws Exception { String res = runShellCommand(getJBossAliveCmd()); if (res != null && !res.isEmpty()) { String[] splitLine = res.split("\\s+"); if (splitLine.length != 1) { String pid = splitLine[(splitLine.length) - 1]; runShellCommand(String.format(getShutdownJBossCmd(), pid)); } } // wait 5 * 60 second for jboss-as shutdown complete for (int i = 0; i < numChecks; i++) { if (jbossIsAlive()) { Thread.sleep(5000); } else { getLogger().info("jboss-as shutdown after sending shutdown command"); return; } } } protected String dumpStream(String msg, InputStream is) { try { BufferedReader ein = new BufferedReader(new InputStreamReader(is)); List<String> lines = new LinkedList<String>(); String line; while ( (line = ein.readLine()) != null) { lines.add(line); } is.close(); if (!lines.isEmpty()) { String res = lines.get(0); System.out.printf("%s %s\n", msg, res); getLogger().info("Execution result: '" + res + "'"); return res; } } catch (IOException e) { getLogger().info("Exception dumping stream: " + e.getMessage()); } return null; } protected void dumpProcesses(Container container) throws Exception { Map<String, String> config = container.getContainerConfiguration().getContainerProperties(); String testClass = config.get("testClass"); String scriptName = config.get("scriptName"); String dir = "target" + File.separator + "surefire-reports" + File.separator + "processes"; if(!new File(dir).exists()) { runShellCommand("mkdir " + dir); } String logFile = dir + File.separator + scriptName + ":" + testClass + "_" + processLogId++ + ".txt"; runShellCommand(getProcessesCmd() + " > " + logFile); getLogger().info("Logged current running processes to: " + logFile); } public boolean isEmpty(String res) { return res == null || res.isEmpty(); } }