package org.infinispan.commons.test;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.jboss.logging.Logger;
import org.testng.IConfigurationListener2;
import org.testng.ISuite;
import org.testng.ISuiteListener;
import org.testng.ITestContext;
import org.testng.ITestListener;
import org.testng.ITestResult;
import org.testng.annotations.Test;
/**
* Logs TestNG test progress.
*/
public class TestNGTestListener implements ITestListener, IConfigurationListener2, ISuiteListener {
private static final Logger log = Logger.getLogger(TestNGTestListener.class);
private Set<Long> startupThreads;
private boolean suiteRunning;
@Override
public void onTestStart(ITestResult result) {
TestSuiteProgress.testStarted(testName(result));
}
@Override
public void onTestSuccess(ITestResult result) {
TestSuiteProgress.testFinished(testName(result));
}
@Override
public void onTestFailure(ITestResult result) {
TestSuiteProgress.testFailed(testName(result), result.getThrowable());
}
@Override
public void onTestSkipped(ITestResult result) {
TestSuiteProgress.testIgnored(testName(result));
}
@Override
public void onTestFailedButWithinSuccessPercentage(ITestResult result) {
TestSuiteProgress.testFailed(testName(result), result.getThrowable());
}
@Override
public void onStart(ITestContext context) {
}
@Override
public void onFinish(ITestContext context) {
}
private String testName(ITestResult res) {
StringBuilder result = new StringBuilder();
result.append(res.getTestClass().getRealClass().getName()).append(".").append(res.getMethod().getMethodName());
if (res.getMethod().getConstructorOrMethod().getMethod().isAnnotationPresent(Test.class)) {
String dataProviderName = res.getMethod().getConstructorOrMethod().getMethod().getAnnotation(Test.class)
.dataProvider();
// Add parameters for methods that use a data provider only
if (res.getParameters().length != 0 && (dataProviderName != null && !dataProviderName.isEmpty())) {
result.append("(").append(Arrays.deepToString(res.getParameters())).append(")");
}
}
return result.toString();
}
@Override
public void onStart(ISuite isuite) {
Set<Long> threads = new HashSet<>();
for (Map.Entry<Thread, StackTraceElement[]> s : Thread.getAllStackTraces().entrySet()) {
Thread thread = s.getKey();
if (!thread.getName().startsWith("TestNG")) {
threads.add(thread.getId());
}
}
startupThreads = threads;
suiteRunning = true;
}
@Override
public void onFinish(ISuite isuite) {
// TestNG invokes this method twice, ignore it the second time
boolean firstTime = suiteRunning;
suiteRunning = false;
if (!firstTime)
return;
int count = 0;
for (Map.Entry<Thread, StackTraceElement[]> s : Thread.getAllStackTraces().entrySet()) {
Thread thread = s.getKey();
if (ignoreThread(thread))
continue;
if (count == 0) {
log.warn("Possible leaked threads at the end of the test suite:");
}
count++;
// "management I/O-2" #55 prio=5 os_prio=0 tid=0x00007fe6a8134000 nid=0x7f9d runnable
// [0x00007fe64e4db000]
// java.lang.Thread.State:RUNNABLE
log.warnf("\"%s\" #%d %sprio=%d tid=0x%x nid=NA %s", thread.getName(), count,
thread.isDaemon() ? "daemon " : "", thread.getPriority(), thread.getId(),
thread.getState().toString().toLowerCase());
log.warnf(" java.lang.Thread.State: %s", thread.getState());
for (StackTraceElement ste : s.getValue()) {
log.warnf("\t%s", ste);
}
}
}
private boolean ignoreThread(Thread thread) {
String threadName = thread.getName();
return threadName.startsWith("testng-") || threadName.startsWith("ForkJoinPool.commonPool-worker-") || startupThreads.contains(thread.getId());
}
@Override
public void beforeConfiguration(ITestResult testResult) {
log.debugf("Before setup %s", testResult.getMethod().getMethodName());
}
@Override
public void onConfigurationSuccess(ITestResult testResult) {
log.debugf("After setup %s", testResult.getMethod().getMethodName());
}
@Override
public void onConfigurationFailure(ITestResult testResult) {
if (testResult.getThrowable() != null) {
TestSuiteProgress.setupFailed(testName(testResult), testResult.getThrowable());
}
}
@Override
public void onConfigurationSkip(ITestResult testResult) {
if (testResult.getThrowable() != null) {
TestSuiteProgress.testIgnored(testName(testResult));
}
}
}