Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Concurrency fixes for junit-interface #401

Merged
merged 2 commits into from
Aug 20, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@
import java.util.Collections;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.io.IOException;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.stream.Collectors;
import java.util.concurrent.atomic.AtomicBoolean;

import org.junit.runner.Description;
import org.junit.runner.Result;
Expand All @@ -23,16 +21,13 @@ final class EventDispatcher extends RunListener
{
private final RichLogger logger;
private final Set<Description> reported = Collections.newSetFromMap(new ConcurrentHashMap<Description, Boolean>());
private final Set<String> reportedSuites = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>());
private final AtomicBoolean suiteStartReported = new AtomicBoolean(false);
private final ConcurrentHashMap<String, Long> startTimes = new ConcurrentHashMap<String, Long>();
private final EventHandler handler;
private final RunSettings settings;
private final Fingerprint fingerprint;
private final String taskInfo;
private final RunStatistics runStatistics;
private OutputCapture capture;

private final static Description TEST_RUN = Description.createTestDescription("Test", "run");

EventDispatcher(RichLogger logger, EventHandler handler, RunSettings settings, Fingerprint fingerprint,
Description taskDescription, RunStatistics runStatistics)
Expand Down Expand Up @@ -71,11 +66,10 @@ private abstract class InfoEvent extends Event {
@Override
public void testAssumptionFailure(final Failure failure)
{
uncapture(true);
postIfFirst(failure.getDescription(), new ErrorEvent(failure, Status.Skipped) {
void logTo(RichLogger logger) {
if (settings.verbose) {
logger.info(failure.getDescription(), Ansi.c("==> i " + failure.getDescription().getMethodName(), WARNMSG));
logger.info(Ansi.c("==> i " + failure.getDescription().getMethodName(), WARNMSG));
}
}
});
Expand All @@ -96,10 +90,9 @@ public void testFailure(final Failure failure)
// Ignore error.
}
}
uncapture(true);
postIfFirst(failure.getDescription(), new ErrorEvent(failure, Status.Failure) {
void logTo(RichLogger logger) {
logger.error( failure.getDescription(), settings.buildTestResult(Status.Failure) +ansiName+" "+ durationSuffix() + " " + ansiMsg, error);
logger.error(settings.buildTestResult(Status.Failure) +ansiName+" "+ durationSuffix() + " " + ansiMsg, error);
}
});
}
Expand All @@ -108,21 +101,19 @@ void logTo(RichLogger logger) {
@Override
public void testFinished(Description desc)
{
uncapture(false);
postIfFirst(desc, new InfoEvent(desc, Status.Success) {
void logTo(RichLogger logger) {
logger.info(desc, settings.buildTestResult(Status.Success) + Ansi.c(desc.getMethodName(), SUCCESS1) + durationSuffix());
logger.info(settings.buildTestResult(Status.Success) + Ansi.c(desc.getMethodName(), SUCCESS1) + durationSuffix());
}
});
logger.popCurrentTestClassName();
}

@Override
public void testIgnored(Description desc)
{
postIfFirst(desc, new InfoEvent(desc, Status.Skipped) {
void logTo(RichLogger logger) {
logger.warn(desc, settings.buildTestResult(Status.Ignored) + ansiName+" ignored" + durationSuffix());
logger.warn(settings.buildTestResult(Status.Ignored) + ansiName+" ignored" + durationSuffix());
}
});
}
Expand All @@ -132,31 +123,26 @@ void logTo(RichLogger logger) {
public void testSuiteStarted(Description desc)
{
if (desc == null || desc.getClassName() == null || desc.getClassName().equals("null")) return;
reportedSuites.add(desc.getClassName());
logger.info(desc, c(desc.getClassName() + ":", SUCCESS1));
if (suiteStartReported.compareAndSet(false, true)) logger.info(c(desc.getClassName() + ":", SUCCESS1));
}


@Override
public void testStarted(Description desc)
{
recordStartTime(desc);
if (reportedSuites.add(desc.getClassName())) {
testSuiteStarted(desc);
}
logger.pushCurrentTestClassName(desc.getClassName());
testSuiteStarted(desc);
if (settings.verbose) {
logger.info(desc, settings.buildPlainName(desc) + " started");
logger.info(settings.buildPlainName(desc) + " started");
}
capture();
}

private void recordStartTime(Description description) {
startTimes.putIfAbsent(settings.buildPlainName(description), System.currentTimeMillis());
startTimes.putIfAbsent(description.getMethodName(), System.currentTimeMillis());
}

private Long elapsedTime(Description description) {
Long startTime = startTimes.get(settings.buildPlainName(description));
Long startTime = startTimes.get(description.getMethodName());
if( startTime == null ) {
return 0l;
} else {
Expand All @@ -168,34 +154,36 @@ private Long elapsedTime(Description description) {
public void testRunFinished(Result result)
{
if (settings.verbose) {
logger.info(TEST_RUN, "Test run " +taskInfo+" finished: "+
logger.info("Test run " +taskInfo+" finished: "+
result.getFailureCount()+" failed" +
", " +
result.getIgnoreCount()+" ignored" +
", "+result.getRunCount()+" total, "+(result.getRunTime()/1000.0)+"s") ;
logger.flush();
}
runStatistics.addTime(result.getRunTime());
logger.flush(TEST_RUN);
}

@Override
public void testSuiteFinished(Description description) throws Exception {
logger.flush(description);
public void testSuiteFinished(Description desc) throws Exception {
logger.flush();
}

@Override
public void testRunStarted(Description desc)
{
if (settings.verbose) {
logger.info(desc, taskInfo + " started");
logger.info(taskInfo + " started");
logger.flush();
}
}

void testExecutionFailed(String testName, Throwable err)
{
post(new Event(Ansi.c(testName, Ansi.ERRMSG), settings.buildErrorMessage(err), Status.Error, 0L, err) {
void logTo(RichLogger logger) {
logger.error(TEST_RUN, ansiName+" failed: "+ansiMsg, error);
logger.error(ansiName+" failed: "+ansiMsg, error);
logger.flush();
}
});
}
Expand All @@ -217,26 +205,6 @@ void post(AbstractEvent e)
handler.handle(e);
}

private void capture()
{
if(settings.quiet && capture == null)
capture = OutputCapture.start();
}

void uncapture(boolean replay)
{
if(settings.quiet && capture != null)
{
capture.stop();
if(replay)
{
try { capture.replay(); }
catch(IOException ex) { logger.error(TEST_RUN, "Error replaying captured stdio", ex); }
}
capture = null;
}
}


// Removes stack trace elements that reference the reflective invocation in TestLauncher.
private static void trimStackTrace(Throwable ex, String fromClassName, String toClassName, Settings settings) {
Expand All @@ -248,7 +216,7 @@ private static void trimStackTrace(Throwable ex, String fromClassName, String to
int end = stackTrace.length - 1;
StackTraceElement last = stackTrace[end];
if (last.getClassName() != null && last.getClassName().equals(fromClassName)) {
for (int i = 0; end >= 0; end--) {
for (; end >= 0; end--) {
StackTraceElement e = stackTrace[end];
if (e.getClassName().equals(toClassName)) {
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,9 @@ final class JUnitRunner implements Runner {
this.customRunners = customRunners;
Settings defaults = Settings.defaults();

boolean quiet = false, nocolor = false, decodeScalaNames = false,
boolean nocolor = false, decodeScalaNames = false,
logAssert = true, logExceptionClass = true, useSbtLoggers = false, useBufferedLoggers = true;
boolean verbose = false;
boolean suppressSystemError = false;
boolean trimStackTraces = defaults.trimStackTraces();
RunSettings.Summary summary = RunSettings.Summary.SBT;
HashMap<String, String> sysprops = new HashMap<String, String>();
Expand All @@ -51,8 +50,7 @@ final class JUnitRunner implements Runner {
String ignoreRunners = "org.junit.runners.Suite";
String runListener = null;
for(String s : args) {
if("-q".equals(s)) quiet = true;
else if("-v".equals(s) || "--verbose".equals(s)) verbose = true;
if("-v".equals(s) || "--verbose".equals(s)) verbose = true;
else if(s.startsWith("--summary=")) summary = RunSettings.Summary.values()[Integer.parseInt(s.substring(10))];
else if("-n".equals(s)) nocolor = true;
else if("-s".equals(s)) decodeScalaNames = true;
Expand Down Expand Up @@ -80,18 +78,15 @@ else if(s.startsWith("-D") && s.contains("=")) {
else if(!s.startsWith("-") && !s.startsWith("+")) globPatterns.add(s);
}
for(String s : args) {
if("+q".equals(s)) quiet = false;
else if("+n".equals(s)) nocolor = false;
if("+n".equals(s)) nocolor = false;
else if("+s".equals(s)) decodeScalaNames = false;
else if("+a".equals(s)) logAssert = false;
else if("+c".equals(s)) logExceptionClass = true;
else if("+l".equals(s)) useSbtLoggers = true;
else if("--no-stderr".equals(s)) suppressSystemError = true;
else if("--stderr".equals(s)) suppressSystemError = false;
}
this.settings =
new RunSettings(!nocolor, decodeScalaNames, quiet, verbose, useSbtLoggers, useBufferedLoggers, trimStackTraces, summary, logAssert, ignoreRunners, logExceptionClass,
suppressSystemError, sysprops, globPatterns, includeCategories, excludeCategories, includeTags, excludeTags,
new RunSettings(!nocolor, decodeScalaNames, verbose, useSbtLoggers, useBufferedLoggers, trimStackTraces, summary, logAssert, ignoreRunners, logExceptionClass,
sysprops, globPatterns, includeCategories, excludeCategories, includeTags, excludeTags,
testFilter);
this.runListener = createRunListener(runListener);
this.runStatistics = new RunStatistics(settings);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package munit.internal.junitinterface;

import java.io.OutputStream;
import java.io.PrintStream;
import java.lang.annotation.Annotation;
import java.util.HashSet;
import java.util.Map;
Expand Down Expand Up @@ -55,9 +53,7 @@ public Task[] execute(EventHandler eventHandler, Logger[] loggers) {
if (runner.runListener != null) ju.addListener(runner.runListener);

Map<String, Object> oldprops = settings.overrideSystemProperties();
PrintStream oldSystemError = System.err;
try {
suppressSystemError();
try {
Class<?> cl = runner.testClassLoader.loadClass(testClassName);
boolean isRun = shouldRun(fingerprint, cl, settings);
Expand All @@ -84,23 +80,11 @@ public Task[] execute(EventHandler eventHandler, Logger[] loggers) {
}
} finally {
settings.restoreSystemProperties(oldprops);
System.setErr(oldSystemError);
}
return new Task[0]; // junit tests do not nest
}


private static final PrintStream EMPTY_PRINTSTREAM = new PrintStream(new OutputStream() {
@Override
public void write(int b) {}
});
private void suppressSystemError() {
if (settings.suppressSystemError) {
System.setErr(EMPTY_PRINTSTREAM);
}
}


private boolean shouldRun(Fingerprint fingerprint, Class<?> clazz, RunSettings settings) {
if(JUNIT_FP.equals(fingerprint)) {
// Ignore classes which are matched by the other fingerprints
Expand Down

This file was deleted.

Loading