org.jboss.as.arquillian.protocol.jmx.ServerKillerExtension Maven / Gradle / Ivy
/*
* Copyright 2015 Red Hat, Inc.
*
* 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.jboss.as.arquillian.protocol.jmx;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import org.jboss.arquillian.container.spi.event.container.BeforeSetup;
import org.jboss.arquillian.core.api.annotation.Observes;
import org.jboss.arquillian.test.spi.event.suite.AfterSuite;
/**
* Massive hack that attempts to improve test suite reliability by killing servers between runs
*
* This means that if a server fails to stop it will not affect later runs
*
* @author Stuart Douglas
*/
public class ServerKillerExtension {
public static final String ORG_WILDFLY_TEST_KILL_SERVERS_BEFORE_TEST = "org.wildfly.test.kill-servers-before-test";
private static volatile String errorProcessTable;
private static boolean runOncePerSuite = true;
private String javaHome;
public ServerKillerExtension() {
javaHome = System.getenv("JAVA_HOME");
if (javaHome == null) {
javaHome = System.getProperty("java.home");
}
}
public void beforeSuite(@Observes BeforeSetup start) {
if (runOncePerSuite) {
killServers();
}
}
public void killServers() {
if (!Boolean.getBoolean(ORG_WILDFLY_TEST_KILL_SERVERS_BEFORE_TEST)) {
return;
}
runOncePerSuite = false;
// server is running and port is open.
Runtime rt = Runtime.getRuntime();
if (System.getProperty("os.name").toLowerCase().indexOf("windows") > -1) {
killWindows(rt);
} else {
killLinux(rt);
}
}
public void throwErrpr(@Observes AfterSuite start) {
runOncePerSuite = true;
String result = errorProcessTable;
errorProcessTable = null;
if (result != null) {
throw new RuntimeException(
"There was a server running at the start of the test run execution. jstack output was \n" + result);
}
}
private String getJStackPath() {
return javaHome + File.separator + "bin" + File.separator + "jstack";
}
private String getJps() {
return javaHome + File.separator + "bin" + File.separator + "jps";
}
private void killLinux(Runtime rt) {
try {
// get a jstack of all the processes
Process process = rt.exec(new String[] { "/bin/sh", "-c", getJps()
+ " | egrep -v \"Jps|AgentMain|Launcher|RemoteMavenServer\" | awk '{ print $1; }' | xargs --no-run-if-empty "
+ getJStackPath() });
InputStream in = process.getInputStream();
String processTable = readString(in);
readString(process.getErrorStream());
if (!processTable.isEmpty()) {
readString(rt.exec(new String[] { "/bin/sh", "-c", getJps()
+ " | egrep -v \"Jps|AgentMain|Launcher|RemoteMavenServer\" | awk '{ print $1; }' | xargs --no-run-if-empty kill -9" })
.getInputStream());
errorProcessTable = processTable;
}
long end = System.currentTimeMillis() + 5000;
while (System.currentTimeMillis() < end) {
String running = readString(rt.exec(new String[] { "/bin/sh", "-c", getJps()
+ " | egrep -v \"Jps|AgentMain|Launcher|RemoteMavenServer\" | awk '{ print $1; }' | xargs --no-run-if-empty "
+ getJStackPath() }).getInputStream());
if (running.isEmpty()) {
break;
} else {
Thread.sleep(100);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void killWindows(Runtime rt) {
final String GET_PROCESSES_COMMAND = "gwmi win32_process -filter \"name='java.exe' and commandLine like '%jboss-modules%' \" | foreach { "
+ getJStackPath() + " $_.ProcessId }";
final String KILL_PROCESSES_COMMAND = "gwmi win32_process -filter \"name='java.exe' and commandLine like '%jboss-modules%' \" | foreach { kill -id $_.ProcessId }";
try {
Path getProcessCommand = createCommandFile(GET_PROCESSES_COMMAND);
Process process = rt.exec(new String[] { "powershell.exe", "-NoProfile", "-NonInteractive", "-ExecutionPolicy",
"ByPass", getProcessCommand.toString() });
InputStream in = process.getInputStream();
String processTable = readString(in);
String errors = readString(process.getErrorStream());
if (errors != null && !errors.isEmpty()) {
System.out.println("Could not get processes:\n" + errors);
}
if (!processTable.isEmpty()) {
Path killProcessesCommand = createCommandFile(KILL_PROCESSES_COMMAND);
readString(rt.exec(new String[] { "powershell.exe", "-NoProfile", "-NonInteractive", "-ExecutionPolicy",
"ByPass", killProcessesCommand.toString() }).getInputStream());
errorProcessTable = processTable;
Files.delete(killProcessesCommand);
}
long end = System.currentTimeMillis() + 5000;
while (System.currentTimeMillis() < end) {
String running = readString(rt.exec(new String[] { "powershell.exe", "-NoProfile", "-NonInteractive",
"-ExecutionPolicy", "ByPass", getProcessCommand.toString() }).getInputStream());
if (running.isEmpty()) {
break;
} else {
Thread.sleep(100);
}
}
Files.delete(getProcessCommand);
} catch (Exception e) {
e.printStackTrace();
}
}
/*
* we save command into powershell script as otherwise there is too much issues with escaping
*/
private static Path createCommandFile(String command) throws IOException {
Path tmp = Files.createTempFile("pskiller", ".ps1");
try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(tmp.toFile()))) {
bos.write(command.getBytes());
}
tmp.toFile().deleteOnExit();
return tmp;
}
public static String readString(InputStream file) {
BufferedInputStream stream = null;
try {
stream = new BufferedInputStream(file);
byte[] buff = new byte[1024];
StringBuilder builder = new StringBuilder();
int read = -1;
while ((read = stream.read(buff)) != -1) {
builder.append(new String(buff, 0, read));
}
return builder.toString();
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
// ignore
}
}
}
}
}