-
Notifications
You must be signed in to change notification settings - Fork 541
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
[SUREFIRE-2037] Allow for surefire-junit-platform's TestMethodFilter … #487
base: master
Are you sure you want to change the base?
Changes from 1 commit
eee427d
2ed1d7a
b015bef
318467a
8c2dac0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -195,13 +195,13 @@ public boolean shouldRun( Class<?> testClass, String methodName ) | |
/** | ||
* Returns {@code true} if satisfies {@code testClassFile} and {@code methodName} filter. | ||
* | ||
* @param testClassFile format must be e.g. "my/package/MyTest.class" including class extension; or null | ||
* @param methodName real test-method name; or null | ||
* @param containerName format must be e.g. "my/package/MyTest.class" including class extension; or null | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't change this class, it has nothing to do with what you are aiming for. Rather do not make any additional refactoring because it is very hard to separate reasonable and non-reasonable changes. I guess you wanted to make some specific improvement in JUnit5 provider. Do not press CTRL+ALT+L because there is again unnecessary changes. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The parameter names of this method have been changed to reflect their new meaning. The second parameter to this method, for instance, will no longer only ever represent method names. That's the entire purpose of this PR. Would you care to explain why you would expect the parameters to retain their original names? |
||
* @param selectorName real test-method name; or null | ||
*/ | ||
@Override | ||
public boolean shouldRun( String testClassFile, String methodName ) | ||
public boolean shouldRun( String containerName, String selectorName ) | ||
{ | ||
if ( isEmpty() || isBlank( testClassFile ) && isBlank( methodName ) ) | ||
if ( isEmpty() || isBlank( containerName ) && isBlank( selectorName ) ) | ||
{ | ||
return true; | ||
} | ||
|
@@ -217,7 +217,7 @@ public boolean shouldRun( String testClassFile, String methodName ) | |
{ | ||
for ( ResolvedTest filter : getIncludedPatterns() ) | ||
{ | ||
if ( filter.matchAsInclusive( testClassFile, methodName ) ) | ||
if ( filter.matchAsInclusive( containerName, selectorName ) ) | ||
{ | ||
shouldRun = true; | ||
break; | ||
|
@@ -229,7 +229,7 @@ public boolean shouldRun( String testClassFile, String methodName ) | |
{ | ||
for ( ResolvedTest filter : getExcludedPatterns() ) | ||
{ | ||
if ( filter.matchAsExclusive( testClassFile, methodName ) ) | ||
if ( filter.matchAsExclusive( containerName, selectorName ) ) | ||
{ | ||
shouldRun = false; | ||
break; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -136,6 +136,47 @@ | |
</includes> | ||
</configuration> | ||
</plugin> | ||
<plugin> | ||
<groupId>org.apache.maven.plugins</groupId> | ||
<artifactId>maven-jar-plugin</artifactId> | ||
<executions> | ||
<execution> | ||
<id>api-jar</id> | ||
<phase>package</phase> | ||
<goals> | ||
<goal>jar</goal> | ||
</goals> | ||
<configuration> | ||
<classifier>api</classifier> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wasn't sure whether to classify this JAR with In any case, this is simply a slim version of the JAR for service providers who otherwise do not depend on There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This looks like a hack. Why you have introduced Apache SPI and you change the default behavior this way? JUnit5 SPI do not exist with same purpose? The plugin has configuration of class/methods. If somebody changes this in the SPI, then what you be valid? Configuration or SPI? Pls describe very properly what you are aiming for in the JIRA in details. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are other two SPI modules There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Absolutely. Here is my implementation for ArchUnit's
It solves the problem of adding support for applying the same filtering logic Surefire now applies to methods, to other test sources ( In case you're unfamiliar with ArchUnit, here's what an ArchUnit test might look like:
As you can see, test cases are represented by fields, and not methods. This is also why the default Surefire
Yes, of course it exists, and that's exactly what ArchUnit does under the hood. There's no way to influence Surefire filtering logic from inside a JUnit extension, though. I've already verified providing this implementation of the new SPI in ArchUnit solves the linked ArchUnit issue for Surefire. I'm now about to suggest similar extensibility to other build tools. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also, if I understand correctly, here:
You're asking what happens if someone overwrites the service to something else than
Basically, there's no 'changing the SPI'. Thus, for those users who do not extend this SPI in any way, the behavior of Surefire will be consistent with the behavior before this PR.
Yes, and unfortunately, they do not fit my use case. I could implement a custom |
||
<includes> | ||
<include>org/apache/maven/surefire/junitplatform/TestSelectorFactory.class</include> | ||
</includes> | ||
</configuration> | ||
</execution> | ||
</executions> | ||
</plugin> | ||
<plugin> | ||
<groupId>org.codehaus.mojo</groupId> | ||
<artifactId>build-helper-maven-plugin</artifactId> | ||
<version>3.2.0</version> | ||
<executions> | ||
<execution> | ||
<id>api-jar</id> | ||
<goals> | ||
<goal>attach-artifact</goal> | ||
</goals> | ||
<configuration> | ||
<artifacts> | ||
<artifact> | ||
<classifier>api</classifier> | ||
<type>jar</type> | ||
<file>${project.build.directory}/${project.artifactId}-${project.version}-api.jar</file> | ||
</artifact> | ||
</artifacts> | ||
</configuration> | ||
</execution> | ||
</executions> | ||
</plugin> | ||
</plugins> | ||
</build> | ||
</project> |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,37 +19,6 @@ | |
* under the License. | ||
*/ | ||
|
||
import static java.util.Arrays.stream; | ||
import static java.util.Collections.emptyMap; | ||
import static java.util.Optional.empty; | ||
import static java.util.Optional.of; | ||
import static java.util.logging.Level.WARNING; | ||
import static java.util.stream.Collectors.toList; | ||
import static org.apache.maven.surefire.api.booter.ProviderParameterNames.EXCLUDE_JUNIT5_ENGINES_PROP; | ||
import static org.apache.maven.surefire.api.booter.ProviderParameterNames.INCLUDE_JUNIT5_ENGINES_PROP; | ||
import static org.apache.maven.surefire.api.booter.ProviderParameterNames.TESTNG_EXCLUDEDGROUPS_PROP; | ||
import static org.apache.maven.surefire.api.booter.ProviderParameterNames.TESTNG_GROUPS_PROP; | ||
import static org.apache.maven.surefire.api.report.ConsoleOutputCapture.startCapture; | ||
import static org.apache.maven.surefire.api.report.RunMode.NORMAL_RUN; | ||
import static org.apache.maven.surefire.api.report.RunMode.RERUN_TEST_AFTER_FAILURE; | ||
import static org.apache.maven.surefire.api.util.TestsToRun.fromClass; | ||
import static org.apache.maven.surefire.shared.utils.StringUtils.isBlank; | ||
import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; | ||
import static org.junit.platform.engine.discovery.DiscoverySelectors.selectUniqueId; | ||
import static org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder.request; | ||
|
||
import java.io.IOException; | ||
import java.io.StringReader; | ||
import java.io.UncheckedIOException; | ||
import java.util.ArrayList; | ||
import java.util.HashMap; | ||
import java.util.LinkedHashSet; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Optional; | ||
import java.util.Properties; | ||
import java.util.logging.Logger; | ||
|
||
import org.apache.maven.surefire.api.provider.AbstractProvider; | ||
import org.apache.maven.surefire.api.provider.ProviderParameters; | ||
import org.apache.maven.surefire.api.report.ReporterException; | ||
|
@@ -70,13 +39,47 @@ | |
import org.junit.platform.launcher.TestIdentifier; | ||
import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder; | ||
|
||
import java.io.IOException; | ||
import java.io.StringReader; | ||
import java.io.UncheckedIOException; | ||
import java.util.ArrayList; | ||
import java.util.Collection; | ||
import java.util.HashMap; | ||
import java.util.LinkedHashSet; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Optional; | ||
import java.util.Properties; | ||
import java.util.ServiceLoader; | ||
import java.util.logging.Logger; | ||
import java.util.stream.Collectors; | ||
import java.util.stream.StreamSupport; | ||
|
||
import static java.util.Arrays.stream; | ||
import static java.util.Collections.emptyMap; | ||
import static java.util.Optional.empty; | ||
import static java.util.Optional.of; | ||
import static java.util.logging.Level.WARNING; | ||
import static java.util.stream.Collectors.toList; | ||
import static org.apache.maven.surefire.api.booter.ProviderParameterNames.EXCLUDE_JUNIT5_ENGINES_PROP; | ||
import static org.apache.maven.surefire.api.booter.ProviderParameterNames.INCLUDE_JUNIT5_ENGINES_PROP; | ||
import static org.apache.maven.surefire.api.booter.ProviderParameterNames.TESTNG_EXCLUDEDGROUPS_PROP; | ||
import static org.apache.maven.surefire.api.booter.ProviderParameterNames.TESTNG_GROUPS_PROP; | ||
import static org.apache.maven.surefire.api.report.ConsoleOutputCapture.startCapture; | ||
import static org.apache.maven.surefire.api.report.RunMode.NORMAL_RUN; | ||
import static org.apache.maven.surefire.api.report.RunMode.RERUN_TEST_AFTER_FAILURE; | ||
import static org.apache.maven.surefire.api.util.TestsToRun.fromClass; | ||
import static org.apache.maven.surefire.shared.utils.StringUtils.isBlank; | ||
import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; | ||
import static org.junit.platform.engine.discovery.DiscoverySelectors.selectUniqueId; | ||
import static org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder.request; | ||
|
||
/** | ||
* JUnit 5 Platform Provider. | ||
* | ||
* @since 2.22.0 | ||
*/ | ||
public class JUnitPlatformProvider | ||
extends AbstractProvider | ||
public class JUnitPlatformProvider extends AbstractProvider | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is very hard to separate reasonable and non-reasonable changes. I guess you wanted to make some specific improvement in this class. Do not press CTRL+ALT+L because there is again unnecessary changes. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've reformatted this class according to Let me try to revert unrelated changes EDIT Done, see updated code |
||
{ | ||
static final String CONFIGURATION_PARAMETERS = "configurationParameters"; | ||
|
||
|
@@ -105,7 +108,7 @@ public JUnitPlatformProvider( ProviderParameters parameters ) | |
public Iterable<Class<?>> getSuites() | ||
{ | ||
try | ||
{ | ||
{ | ||
return scanClasspath(); | ||
} | ||
finally | ||
|
@@ -115,8 +118,7 @@ public Iterable<Class<?>> getSuites() | |
} | ||
|
||
@Override | ||
public RunResult invoke( Object forkTestSet ) | ||
throws TestSetFailedException, ReporterException | ||
public RunResult invoke( Object forkTestSet ) throws TestSetFailedException, ReporterException | ||
{ | ||
ReporterFactory reporterFactory = parameters.getReporterFactory(); | ||
final RunResult runResult; | ||
|
@@ -132,16 +134,15 @@ public RunResult invoke( Object forkTestSet ) | |
} | ||
else if ( forkTestSet instanceof Class ) | ||
{ | ||
invokeAllTests( fromClass( ( Class<?> ) forkTestSet ), adapter ); | ||
invokeAllTests( fromClass( (Class<?>) forkTestSet ), adapter ); | ||
} | ||
else if ( forkTestSet == null ) | ||
{ | ||
invokeAllTests( scanClasspath(), adapter ); | ||
} | ||
else | ||
{ | ||
throw new IllegalArgumentException( | ||
"Unexpected value of forkTestSet: " + forkTestSet ); | ||
throw new IllegalArgumentException( "Unexpected value of forkTestSet: " + forkTestSet ); | ||
} | ||
} | ||
finally | ||
|
@@ -189,7 +190,7 @@ private void invokeAllTests( TestsToRun testsToRun, RunListenerAdapter adapter ) | |
{ | ||
// Replace the "discoveryRequest" so that it only specifies the failing tests | ||
LauncherDiscoveryRequest discoveryRequest = | ||
buildLauncherDiscoveryRequestForRerunFailures( adapter ); | ||
buildLauncherDiscoveryRequestForRerunFailures( adapter ); | ||
// Reset adapter's recorded failures and invoke the failed tests again | ||
adapter.reset(); | ||
launcher.execute( discoveryRequest, adapter ); | ||
|
@@ -212,37 +213,32 @@ private void execute( TestsToRun testsToRun, RunListenerAdapter adapter ) | |
if ( testsToRun.allowEagerReading() ) | ||
{ | ||
List<DiscoverySelector> selectors = new ArrayList<>(); | ||
testsToRun.iterator() | ||
.forEachRemaining( c -> selectors.add( selectClass( c.getName() ) ) ); | ||
testsToRun.iterator().forEachRemaining( c -> selectors.add( selectClass( c.getName() ) ) ); | ||
|
||
LauncherDiscoveryRequestBuilder builder = request() | ||
.filters( filters ) | ||
.configurationParameters( configurationParameters ) | ||
.selectors( selectors ); | ||
LauncherDiscoveryRequestBuilder builder = | ||
request().filters( filters ).configurationParameters( configurationParameters ).selectors( selectors ); | ||
|
||
launcher.execute( builder.build(), adapter ); | ||
} | ||
else | ||
{ | ||
testsToRun.iterator() | ||
.forEachRemaining( c -> | ||
{ | ||
LauncherDiscoveryRequestBuilder builder = request() | ||
.filters( filters ) | ||
.configurationParameters( configurationParameters ) | ||
testsToRun.iterator().forEachRemaining( c -> | ||
{ | ||
LauncherDiscoveryRequestBuilder builder = | ||
request().filters( filters ).configurationParameters( configurationParameters ) | ||
.selectors( selectClass( c.getName() ) ); | ||
launcher.execute( builder.build(), adapter ); | ||
} ); | ||
launcher.execute( builder.build(), adapter ); | ||
} ); | ||
} | ||
} | ||
|
||
private void closeLauncher() | ||
{ | ||
if ( launcher instanceof AutoCloseable ) | ||
{ | ||
try | ||
{ | ||
( (AutoCloseable) launcher ).close(); | ||
( ( AutoCloseable ) launcher ).close(); | ||
} | ||
catch ( Exception e ) | ||
{ | ||
|
@@ -253,8 +249,8 @@ private void closeLauncher() | |
|
||
private LauncherDiscoveryRequest buildLauncherDiscoveryRequestForRerunFailures( RunListenerAdapter adapter ) | ||
{ | ||
LauncherDiscoveryRequestBuilder builder = request().filters( filters ).configurationParameters( | ||
configurationParameters ); | ||
LauncherDiscoveryRequestBuilder builder = | ||
request().filters( filters ).configurationParameters( configurationParameters ); | ||
// Iterate over recorded failures | ||
for ( TestIdentifier identifier : new LinkedHashSet<>( adapter.getFailures().keySet() ) ) | ||
{ | ||
|
@@ -263,33 +259,31 @@ private LauncherDiscoveryRequest buildLauncherDiscoveryRequestForRerunFailures( | |
return builder.build(); | ||
} | ||
|
||
private Collection<TestSelectorFactory> loadSelectorFactories() | ||
{ | ||
return StreamSupport.stream( ServiceLoader.load( TestSelectorFactory.class ).spliterator(), false ) | ||
.collect( Collectors.toSet() ); | ||
} | ||
|
||
private Filter<?>[] newFilters() | ||
{ | ||
List<Filter<?>> filters = new ArrayList<>(); | ||
|
||
getPropertiesList( TESTNG_GROUPS_PROP ) | ||
.map( TagFilter::includeTags ) | ||
.ifPresent( filters::add ); | ||
getPropertiesList( TESTNG_GROUPS_PROP ).map( TagFilter::includeTags ).ifPresent( filters::add ); | ||
|
||
getPropertiesList( TESTNG_EXCLUDEDGROUPS_PROP ) | ||
.map( TagFilter::excludeTags ) | ||
.ifPresent( filters::add ); | ||
getPropertiesList( TESTNG_EXCLUDEDGROUPS_PROP ).map( TagFilter::excludeTags ).ifPresent( filters::add ); | ||
|
||
TestListResolver testListResolver = parameters.getTestRequest().getTestListResolver(); | ||
if ( !testListResolver.isEmpty() ) | ||
{ | ||
filters.add( new TestMethodFilter( testListResolver ) ); | ||
filters.add( new TestSelectorFilter( testListResolver, loadSelectorFactories() ) ); | ||
} | ||
|
||
getPropertiesList( INCLUDE_JUNIT5_ENGINES_PROP ) | ||
.map( EngineFilter::includeEngines ) | ||
.ifPresent( filters::add ); | ||
getPropertiesList( INCLUDE_JUNIT5_ENGINES_PROP ).map( EngineFilter::includeEngines ).ifPresent( filters::add ); | ||
|
||
getPropertiesList( EXCLUDE_JUNIT5_ENGINES_PROP ) | ||
.map( EngineFilter::excludeEngines ) | ||
.ifPresent( filters::add ); | ||
getPropertiesList( EXCLUDE_JUNIT5_ENGINES_PROP ).map( EngineFilter::excludeEngines ).ifPresent( filters::add ); | ||
|
||
return filters.toArray( new Filter<?>[ filters.size() ] ); | ||
return filters.toArray( new Filter<?>[0] ); | ||
} | ||
|
||
Filter<?>[] getFilters() | ||
|
@@ -309,8 +303,7 @@ private Map<String, String> newConfigurationParameters() | |
Map<String, String> result = new HashMap<>(); | ||
Properties props = new Properties(); | ||
props.load( reader ); | ||
props.stringPropertyNames() | ||
.forEach( key -> result.put( key, props.getProperty( key ) ) ); | ||
props.stringPropertyNames().forEach( key -> result.put( key, props.getProperty( key ) ) ); | ||
return result; | ||
} | ||
catch ( IOException e ) | ||
|
@@ -328,9 +321,8 @@ private Optional<List<String>> getPropertiesList( String key ) | |
{ | ||
String property = parameters.getProviderProperties().get( key ); | ||
return isBlank( property ) ? empty() | ||
: of( stream( property.split( "[,]+" ) ) | ||
.filter( StringUtils::isNotBlank ) | ||
.map( String::trim ) | ||
.collect( toList() ) ); | ||
: of( stream( property.split( "[,]+" ) ) | ||
.filter( StringUtils::isNotBlank ) | ||
.map( String::trim ).collect( toList() ) ); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't change this POM, it has nothing to do with what you are aiming for. Rather do not make any additional refactoring because it is very hard to separate reasonable and non-reasonable changes. I guess you wanted to make some specific improvement in JUnit5 provider. Do not press CTRL+L because there is again unnecessary changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure I follow.
This was an intentional change, otherwise Rat would expect a license inside META-INF/services/org.apache.maven.surefire.junitplatform.TestSelectorFactory
Should I add an entry here for that specific file instead?