Updated Branches: refs/heads/master 6a013649e -> 9b3beb4f6
[SUREFIRE-800] redirectTestOutputToFile is not taken into account in all cases with JUnit47 provider Made serial runs use a serial run listener. Patch by N Keywal, extensively modified by me. Project: http://git-wip-us.apache.org/repos/asf/maven-surefire/repo Commit: http://git-wip-us.apache.org/repos/asf/maven-surefire/commit/9b3beb4f Tree: http://git-wip-us.apache.org/repos/asf/maven-surefire/tree/9b3beb4f Diff: http://git-wip-us.apache.org/repos/asf/maven-surefire/diff/9b3beb4f Branch: refs/heads/master Commit: 9b3beb4f6a1890d7a8ee916219ac2f0bedef8fcd Parents: 6a01364 Author: Kristian Rosenvold <krosenv...@apache.org> Authored: Thu Dec 13 15:56:21 2012 +0100 Committer: Kristian Rosenvold <krosenv...@apache.org> Committed: Thu Dec 13 15:56:21 2012 +0100 ---------------------------------------------------------------------- .../maven/surefire/its/fixture/MavenLauncher.java | 2 +- .../src/test/java/junit47ConsoleOutput/Test0.java | 63 +++++++ .../surefire/common/junit4/JUnit4RunListener.java | 12 +- .../surefire/junitcore/JUnitCoreProvider.java | 35 +++-- .../junitcore/NonConcurrentRunListener.java | 137 +++++++++++++++ 5 files changed, 233 insertions(+), 16 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/9b3beb4f/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/fixture/MavenLauncher.java ---------------------------------------------------------------------- diff --git a/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/fixture/MavenLauncher.java b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/fixture/MavenLauncher.java index f31fb85..bbf910c 100755 --- a/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/fixture/MavenLauncher.java +++ b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/fixture/MavenLauncher.java @@ -219,7 +219,7 @@ public class MavenLauncher return conditionalExec( "install" ); } - public OutputValidator conditionalExec(String goal) + private OutputValidator conditionalExec(String goal) { OutputValidator verify; try http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/9b3beb4f/surefire-integration-tests/src/test/resources/junit47-redirect-output/src/test/java/junit47ConsoleOutput/Test0.java ---------------------------------------------------------------------- diff --git a/surefire-integration-tests/src/test/resources/junit47-redirect-output/src/test/java/junit47ConsoleOutput/Test0.java b/surefire-integration-tests/src/test/resources/junit47-redirect-output/src/test/java/junit47ConsoleOutput/Test0.java new file mode 100644 index 0000000..102faaa --- /dev/null +++ b/surefire-integration-tests/src/test/resources/junit47-redirect-output/src/test/java/junit47ConsoleOutput/Test0.java @@ -0,0 +1,63 @@ +package junit47ConsoleOutput; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +public class Test0 { + + public Test0(){ + System.out.println("Constructor"); + } + + @Test + public void testT0() throws Exception { + System.out.println("testT0"); + } + + @Test + public void testT1() throws Exception { + System.out.println("testT1"); + } + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + System.out.println("setUpBeforeClass"); + } + + @AfterClass + public static void tearDownAfterClass() throws Exception { + System.out.println("tearDownAfterClass"); + } + + @Before + public void setUp() throws Exception { + System.out.println("setUp"); + } + + @After + public void tearDown() throws Exception { + System.out.println("tearDown"); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/9b3beb4f/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/common/junit4/JUnit4RunListener.java ---------------------------------------------------------------------- diff --git a/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/common/junit4/JUnit4RunListener.java b/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/common/junit4/JUnit4RunListener.java index 1bd2c3a..50c7498 100644 --- a/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/common/junit4/JUnit4RunListener.java +++ b/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/common/junit4/JUnit4RunListener.java @@ -73,7 +73,7 @@ public class JUnit4RunListener { final String reason = jUnit4Reflector.getAnnotatedIgnoreValue( description ); final SimpleReportEntry report = - SimpleReportEntry.ignored( extractClassName( description ), description.getDisplayName(), reason ); + SimpleReportEntry.ignored( getClassName( description ), description.getDisplayName(), reason ); reporter.testSkipped( report ); } @@ -99,7 +99,7 @@ public class JUnit4RunListener throws Exception { ReportEntry report = - SimpleReportEntry.withException( extractClassName( failure.getDescription() ), failure.getTestHeader(), + SimpleReportEntry.withException( getClassName( failure.getDescription() ), failure.getTestHeader(), createStackTraceWriter( failure ) ); if ( failure.getException() instanceof AssertionError ) @@ -141,11 +141,15 @@ public class JUnit4RunListener } } - private SimpleReportEntry createReportEntry( Description description ) + protected SimpleReportEntry createReportEntry( Description description ) { - return new SimpleReportEntry( extractClassName( description ), description.getDisplayName() ); + return new SimpleReportEntry( getClassName( description ), description.getDisplayName() ); } + public String getClassName( Description description ) + { + return extractClassName( description ); + } public static String extractClassName( Description description ) { http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/9b3beb4f/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCoreProvider.java ---------------------------------------------------------------------- diff --git a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCoreProvider.java b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCoreProvider.java index d857aff..73cdca7 100644 --- a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCoreProvider.java +++ b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCoreProvider.java @@ -23,6 +23,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; + import org.apache.maven.surefire.common.junit4.JUnit4RunListenerFactory; import org.apache.maven.surefire.common.junit4.JUnit4TestChecker; import org.apache.maven.surefire.common.junit48.FilterFactory; @@ -100,14 +101,18 @@ public class JUnitCoreProvider return testsToRun.iterator(); } + private boolean isSingleThreaded() + { + return !jUnitCoreParameters.isAnyParallelitySelected() || + ( testsToRun.containsExactly( 1 ) && !jUnitCoreParameters.isParallelMethod() ); + } + public RunResult invoke( Object forkTestSet ) throws TestSetFailedException, ReporterException { - final String message = "Concurrency config is " + jUnitCoreParameters.toString() + "\n"; final ReporterFactory reporterFactory = providerParameters.getReporterFactory(); final ConsoleLogger consoleLogger = providerParameters.getConsoleLogger(); - consoleLogger.info( message ); Filter filter = jUnit48Reflector.isJUnit48Available() ? createJUnit48Filter() : null; @@ -128,18 +133,26 @@ public class JUnitCoreProvider } } - final Map<String, TestSet> testSetMap = new ConcurrentHashMap<String, TestSet>(); - - RunListener listener = ConcurrentReporterManager.createInstance( testSetMap, reporterFactory, - jUnitCoreParameters.isParallelClasses(), - jUnitCoreParameters.isParallelBoth(), - consoleLogger ); + org.junit.runner.notification.RunListener jUnit4RunListener; + if ( isSingleThreaded() ) + { + NonConcurrentRunListener rm = new NonConcurrentRunListener( reporterFactory.createReporter() ); + ConsoleOutputCapture.startCapture( rm ); + jUnit4RunListener = rm; + } + else + { + final Map<String, TestSet> testSetMap = new ConcurrentHashMap<String, TestSet>(); - ConsoleOutputCapture.startCapture( (ConsoleOutputReceiver) listener ); + RunListener listener = ConcurrentReporterManager.createInstance( testSetMap, reporterFactory, + jUnitCoreParameters.isParallelClasses(), + jUnitCoreParameters.isParallelBoth(), + consoleLogger ); + ConsoleOutputCapture.startCapture( (ConsoleOutputReceiver) listener ); - org.junit.runner.notification.RunListener jUnit4RunListener = new JUnitCoreRunListener( listener, testSetMap ); + jUnit4RunListener = new JUnitCoreRunListener( listener, testSetMap ); + } customRunListeners.add( 0, jUnit4RunListener ); - JUnitCoreWrapper.execute( testsToRun, jUnitCoreParameters, customRunListeners, filter ); return reporterFactory.close(); } http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/9b3beb4f/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/NonConcurrentRunListener.java ---------------------------------------------------------------------- diff --git a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/NonConcurrentRunListener.java b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/NonConcurrentRunListener.java new file mode 100644 index 0000000..835f46c --- /dev/null +++ b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/NonConcurrentRunListener.java @@ -0,0 +1,137 @@ +package org.apache.maven.surefire.junitcore; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.maven.surefire.common.junit4.JUnit4RunListener; +import org.apache.maven.surefire.report.ConsoleOutputReceiver; +import org.apache.maven.surefire.report.RunListener; +import org.apache.maven.surefire.report.SimpleReportEntry; +import org.apache.maven.surefire.testset.TestSetFailedException; +import org.junit.runner.Description; +import org.junit.runner.Result; +import org.junit.runner.notification.Failure; + +/** + * A class to be used when there is no JUnit parallelism (methods or/and class). This + * allow to workaround JUnit limitation a la Junit4 provider. Specifically, we can redirect + * properly the output even if we don't have class demarcation in JUnit. It works when + * if there is a JVM instance per test run, i.e. with forkMode=always or perthread. + */ +public class NonConcurrentRunListener + extends JUnit4RunListener + implements ConsoleOutputReceiver +{ + + private long startTime = System.currentTimeMillis(); + + private java.lang.Class<?> currentTestClass; + + private Description lastFinishedDescription; + + public NonConcurrentRunListener( RunListener reporter ) + throws TestSetFailedException + { + super( reporter ); + } + + public synchronized void writeTestOutput( byte[] buf, int off, int len, boolean stdout ) + { + // We can write immediately: no parallelism and a single class. + ( (ConsoleOutputReceiver) reporter ).writeTestOutput( buf, off, len, stdout ); + } + + protected SimpleReportEntry createReportEntry( Description description ) + { + return new SimpleReportEntry( description.getClassName(), description.getClassName(), + (int) ( System.currentTimeMillis() - startTime ) ); + } + + + public String getClassName( Description description ) + { + return description.getClass().getSimpleName(); + } + + @Override + public void testStarted( Description description ) + throws Exception + { + if ( !description.getTestClass().equals( currentTestClass ) ) + { + currentTestClass = description.getTestClass(); + if ( lastFinishedDescription != null ) + { + reporter.testSetCompleted( createReportEntry( lastFinishedDescription ) ); + lastFinishedDescription = null; + } + startTime = System.currentTimeMillis(); + reporter.testSetStarting( createReportEntry( description ) ); + } + super.testStarted( description ); + } + + @Override + public void testFinished( Description description ) + throws Exception + { + super.testFinished( description ); + this.lastFinishedDescription = description; + } + + @Override + public void testIgnored( Description description ) + throws Exception + { + super.testIgnored( description ); + this.lastFinishedDescription = description; + } + + @Override + public void testFailure( Failure failure ) + throws Exception + { + super.testFailure( failure ); + this.lastFinishedDescription = failure.getDescription(); + } + + @Override + public void testAssumptionFailure( Failure failure ) + { + super.testAssumptionFailure( failure ); + this.lastFinishedDescription = failure.getDescription(); + } + + @Override + public void testRunStarted( Description description ) + throws Exception + { + } + + @Override + public void testRunFinished( Result result ) + throws Exception + { + if ( lastFinishedDescription != null ) + { + reporter.testSetCompleted( createReportEntry( lastFinishedDescription ) ); + lastFinishedDescription = null; + } + } +}