diff --git a/pom.xml b/pom.xml index 40c562c890..7730b3a896 100644 --- a/pom.xml +++ b/pom.xml @@ -14,7 +14,7 @@ ~ "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. + ~ under the License. --> @@ -532,8 +532,7 @@ src/test/resources/**/* src/test/resources/**/*.css **/*.jj - src/main/resources/META-INF/services/org.apache.maven.surefire.api.provider.SurefireProvider - + src/main/resources/META-INF/services/** DEPENDENCIES .m2/** .m2 diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/api/testset/TestListResolver.java b/surefire-api/src/main/java/org/apache/maven/surefire/api/testset/TestListResolver.java index f8ebb1bdbc..5135f8bf69 100644 --- a/surefire-api/src/main/java/org/apache/maven/surefire/api/testset/TestListResolver.java +++ b/surefire-api/src/main/java/org/apache/maven/surefire/api/testset/TestListResolver.java @@ -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 + * @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; diff --git a/surefire-providers/surefire-junit-platform/pom.xml b/surefire-providers/surefire-junit-platform/pom.xml index 264e9a3417..c785b5f1c7 100644 --- a/surefire-providers/surefire-junit-platform/pom.xml +++ b/surefire-providers/surefire-junit-platform/pom.xml @@ -136,6 +136,47 @@ + + org.apache.maven.plugins + maven-jar-plugin + + + api-jar + package + + jar + + + api + + org/apache/maven/surefire/junitplatform/TestSelectorFactory.class + + + + + + + org.codehaus.mojo + build-helper-maven-plugin + 3.2.0 + + + api-jar + + attach-artifact + + + + + api + jar + ${project.build.directory}/${project.artifactId}-${project.version}-api.jar + + + + + + diff --git a/surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/JUnitPlatformProvider.java b/surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/JUnitPlatformProvider.java index 92385e5fcd..e27c0fd1d2 100644 --- a/surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/JUnitPlatformProvider.java +++ b/surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/JUnitPlatformProvider.java @@ -42,13 +42,17 @@ 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 org.apache.maven.surefire.api.provider.AbstractProvider; import org.apache.maven.surefire.api.provider.ProviderParameters; @@ -105,7 +109,7 @@ public JUnitPlatformProvider( ProviderParameters parameters ) public Iterable> getSuites() { try - { + { return scanClasspath(); } finally @@ -235,7 +239,7 @@ private void execute( TestsToRun testsToRun, RunListenerAdapter adapter ) } ); } } - + private void closeLauncher() { if ( launcher instanceof AutoCloseable ) @@ -263,6 +267,12 @@ private LauncherDiscoveryRequest buildLauncherDiscoveryRequestForRerunFailures( return builder.build(); } + private Collection loadSelectorFactories() + { + return StreamSupport.stream( ServiceLoader.load( TestSelectorFactory.class ).spliterator(), false ) + .collect( Collectors.toSet() ); + } + private Filter[] newFilters() { List> filters = new ArrayList<>(); @@ -278,7 +288,7 @@ private Filter[] newFilters() TestListResolver testListResolver = parameters.getTestRequest().getTestListResolver(); if ( !testListResolver.isEmpty() ) { - filters.add( new TestMethodFilter( testListResolver ) ); + filters.add( new TestSelectorFilter( testListResolver, loadSelectorFactories() ) ); } getPropertiesList( INCLUDE_JUNIT5_ENGINES_PROP ) @@ -289,7 +299,7 @@ private Filter[] newFilters() .map( EngineFilter::excludeEngines ) .ifPresent( filters::add ); - return filters.toArray( new Filter[ filters.size() ] ); + return filters.toArray( new Filter[ 0 ] ); } Filter[] getFilters() diff --git a/surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/MethodSelectorFactory.java b/surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/MethodSelectorFactory.java new file mode 100644 index 0000000000..6754d6e4d0 --- /dev/null +++ b/surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/MethodSelectorFactory.java @@ -0,0 +1,47 @@ +package org.apache.maven.surefire.junitplatform; + +/* + * 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.platform.engine.TestSource; +import org.junit.platform.engine.support.descriptor.MethodSource; + +/** + * The default implementation for {@link TestSelectorFactory}, recognizing instances of {@link MethodSource} + */ +public class MethodSelectorFactory implements TestSelectorFactory +{ + @Override + public boolean supports( TestSource source ) + { + return source instanceof MethodSource; + } + + @Override + public String getContainerName( TestSource source ) + { + return ( ( MethodSource ) source ).getClassName(); + } + + @Override + public String getSelectorName( TestSource source ) + { + return ( ( MethodSource ) source ).getMethodName(); + } +} diff --git a/surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/TestSelectorFactory.java b/surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/TestSelectorFactory.java new file mode 100644 index 0000000000..01261970c9 --- /dev/null +++ b/surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/TestSelectorFactory.java @@ -0,0 +1,102 @@ +package org.apache.maven.surefire.junitplatform; + +/* + * 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.api.testset.TestListResolver; +import org.junit.platform.engine.TestSource; + +import java.util.Objects; + +/** + * A test selector factory used in combination with a {@link org.apache.maven.surefire.api.testset.TestListResolver} + * to determine whether a given {@link org.junit.platform.engine.TestSource} should be considered for running. + * + *

This is a service provider interface; clients may provide their own implementations + * that will be applied along the default {@link MethodSelectorFactory}

+ */ +public interface TestSelectorFactory +{ + + boolean supports( TestSource source ); + + String getContainerName( TestSource source ); + + String getSelectorName( TestSource source ); + + default boolean isClassContainer() + { + return true; + } + + default TestSelector createSelector( TestSource source ) + { + String containerName = getContainerName( source ); + return new TestSelector( + isClassContainer() ? TestListResolver.toClassFileName( containerName ) : containerName, + getSelectorName( source ) ); + } + + /** + * Represents a single test case selector + * (e.g. a fully-qualified class name + test-annotated method name) + */ + class TestSelector + { + private final String containerName; + private final String selectorName; + + public TestSelector( String containerName, String selectorName ) + { + this.containerName = containerName; + this.selectorName = selectorName; + } + + public String getContainerName() + { + return containerName; + } + + public String getSelectorName() + { + return selectorName; + } + + @Override + public boolean equals( Object o ) + { + if ( this == o ) + { + return true; + } + if ( o == null || getClass() != o.getClass() ) + { + return false; + } + TestSelector that = ( TestSelector ) o; + return containerName.equals( that.containerName ) && Objects.equals( selectorName, that.selectorName ); + } + + @Override + public int hashCode() + { + return Objects.hash( containerName, selectorName ); + } + } +} diff --git a/surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/TestMethodFilter.java b/surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/TestSelectorFilter.java similarity index 60% rename from surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/TestMethodFilter.java rename to surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/TestSelectorFilter.java index d766ffdd27..4513008619 100644 --- a/surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/TestMethodFilter.java +++ b/surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/TestSelectorFilter.java @@ -22,39 +22,48 @@ import org.apache.maven.surefire.api.testset.TestListResolver; import org.junit.platform.engine.FilterResult; import org.junit.platform.engine.TestDescriptor; -import org.junit.platform.engine.support.descriptor.MethodSource; +import org.junit.platform.engine.TestSource; import org.junit.platform.launcher.PostDiscoveryFilter; +import java.util.Collection; +import java.util.Optional; + /** * @since 2.22.0 */ -class TestMethodFilter +class TestSelectorFilter implements PostDiscoveryFilter { private final TestListResolver testListResolver; + private final Collection selectorFactories; - TestMethodFilter( TestListResolver testListResolver ) + TestSelectorFilter( TestListResolver testListResolver, Collection selectorFactories ) { this.testListResolver = testListResolver; + this.selectorFactories = selectorFactories; } @Override public FilterResult apply( TestDescriptor descriptor ) { boolean shouldRun = descriptor.getSource() - .filter( MethodSource.class::isInstance ) - .map( MethodSource.class::cast ) - .map( this::shouldRun ) - .orElse( true ); - + .flatMap( source -> resolveFactory( source ) + .map( factory -> factory.createSelector( source ) ) ) + .map( this::shouldRun ) + .orElse( true ); return FilterResult.includedIf( shouldRun ); } - private boolean shouldRun( MethodSource source ) + private boolean shouldRun( TestSelectorFactory.TestSelector selector ) + { + return this.testListResolver.shouldRun( selector.getContainerName(), selector.getSelectorName() ); + } + + private Optional resolveFactory( TestSource source ) { - String testClass = TestListResolver.toClassFileName( source.getClassName() ); - String testMethod = source.getMethodName(); - return this.testListResolver.shouldRun( testClass, testMethod ); + return selectorFactories.stream() + .filter( factory -> factory.supports( source ) ) + .findAny(); } } diff --git a/surefire-providers/surefire-junit-platform/src/main/resources/META-INF/services/org.apache.maven.surefire.junitplatform.TestSelectorFactory b/surefire-providers/surefire-junit-platform/src/main/resources/META-INF/services/org.apache.maven.surefire.junitplatform.TestSelectorFactory new file mode 100644 index 0000000000..f02d320f19 --- /dev/null +++ b/surefire-providers/surefire-junit-platform/src/main/resources/META-INF/services/org.apache.maven.surefire.junitplatform.TestSelectorFactory @@ -0,0 +1 @@ +org.apache.maven.surefire.junitplatform.MethodSelectorFactory diff --git a/surefire-providers/surefire-junit-platform/src/test/java/org/apache/maven/surefire/junitplatform/JUnit47SuiteTest.java b/surefire-providers/surefire-junit-platform/src/test/java/org/apache/maven/surefire/junitplatform/JUnit47SuiteTest.java index 7db25c9b20..1b4c8f3c13 100644 --- a/surefire-providers/surefire-junit-platform/src/test/java/org/apache/maven/surefire/junitplatform/JUnit47SuiteTest.java +++ b/surefire-providers/surefire-junit-platform/src/test/java/org/apache/maven/surefire/junitplatform/JUnit47SuiteTest.java @@ -36,7 +36,7 @@ public static Test suite() TestSuite suite = new TestSuite(); suite.addTest( new JUnit4TestAdapter( JUnitPlatformProviderTest.class ) ); suite.addTest( new JUnit4TestAdapter( RunListenerAdapterTest.class ) ); - suite.addTest( new JUnit4TestAdapter( TestMethodFilterTest.class ) ); + suite.addTest( new JUnit4TestAdapter( TestSelectorFilterTest.class ) ); suite.addTest( new JUnit4TestAdapter( TestPlanScannerFilterTest.class ) ); return suite; } diff --git a/surefire-providers/surefire-junit-platform/src/test/java/org/apache/maven/surefire/junitplatform/TestMethodFilterTest.java b/surefire-providers/surefire-junit-platform/src/test/java/org/apache/maven/surefire/junitplatform/TestSelectorFilterTest.java similarity index 92% rename from surefire-providers/surefire-junit-platform/src/test/java/org/apache/maven/surefire/junitplatform/TestMethodFilterTest.java rename to surefire-providers/surefire-junit-platform/src/test/java/org/apache/maven/surefire/junitplatform/TestSelectorFilterTest.java index 33f14e9afd..32cbf07731 100644 --- a/surefire-providers/surefire-junit-platform/src/test/java/org/apache/maven/surefire/junitplatform/TestMethodFilterTest.java +++ b/surefire-providers/surefire-junit-platform/src/test/java/org/apache/maven/surefire/junitplatform/TestSelectorFilterTest.java @@ -19,14 +19,6 @@ * under the License. */ -import static org.apache.maven.surefire.api.testset.TestListResolver.toClassFileName; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.lang.reflect.Method; - import org.apache.maven.surefire.api.testset.TestListResolver; import org.junit.Test; import org.junit.jupiter.engine.descriptor.ClassTestDescriptor; @@ -35,18 +27,28 @@ import org.junit.platform.engine.FilterResult; import org.junit.platform.engine.UniqueId; +import java.lang.reflect.Method; + +import static java.util.Collections.singletonList; +import static org.apache.maven.surefire.api.testset.TestListResolver.toClassFileName; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + /** - * Unit tests for {@link TestMethodFilter}. + * Unit tests for {@link TestSelectorFilter}. * * @since 2.22.0 */ -public class TestMethodFilterTest +public class TestSelectorFilterTest { private static final ConfigurationParameters CONFIG_PARAMS = mock( ConfigurationParameters.class ); private final TestListResolver resolver = mock( TestListResolver.class ); - private final TestMethodFilter filter = new TestMethodFilter( this.resolver ); + private final TestSelectorFilter filter + = new TestSelectorFilter( this.resolver, singletonList( new MethodSelectorFactory() ) ); @Test public void includesBasedOnTestListResolver()