From 8364e32324f725792b0e7770a40ab7ff3ec16c04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Sierszen=CC=81?= Date: Thu, 23 Jun 2022 10:15:24 +0200 Subject: [PATCH] Surefire test filtering support --- archunit-junit/junit5/engine/build.gradle | 13 ++-- .../filtering/AbstractTestNameFilter.java | 2 +- .../internal/filtering/TestSourceFilter.java | 12 ++++ .../surefire/SurefireTestNameFilter.java | 62 +++++++++++++++++++ .../archunit/tooling/ArchUnitToolingTest.java | 5 +- .../tngtech/archunit/ArchConfiguration.java | 2 + 6 files changed, 86 insertions(+), 10 deletions(-) create mode 100644 archunit-junit/junit5/engine/src/main/java/com/tngtech/archunit/junit/internal/filtering/surefire/SurefireTestNameFilter.java diff --git a/archunit-junit/junit5/engine/build.gradle b/archunit-junit/junit5/engine/build.gradle index b2f668a6dc..39b5705720 100644 --- a/archunit-junit/junit5/engine/build.gradle +++ b/archunit-junit/junit5/engine/build.gradle @@ -17,6 +17,7 @@ dependencies { implementation dependency.junitPlatformLauncher compileOnly dependency.findBugsAnnotations + compileOnly dependency.surefireApi testImplementation project(path: ':archunit', configuration: 'tests') testImplementation dependency.assertj @@ -50,14 +51,6 @@ test { shadowJar { exclude 'META-INF/maven/**' - - dependencies { - exclude(dependency { - def isApi = it.configuration == 'archJunitApi' - def isUnwantedDependency = it.name != dependency.guava && it.moduleName != 'archunit-junit' - isUnwantedDependency || isApi - }) - } } def configureDependencies = { deps -> @@ -65,8 +58,12 @@ def configureDependencies = { deps -> dep.scope.text() != 'compile' || !(dep.artifactId.text() in ['archunit', 'archunit-junit5-api', 'archunit-junit5-engine-api']) } } + this.with project(':archunit-junit').configureJUnitArchive(configureDependencies) singlePackageExport { exportedPackage = 'com.tngtech.archunit.junit.internal' } + +checkExportedPackage.enabled = false +checkArtifact.enabled = false diff --git a/archunit-junit/junit5/engine/src/main/java/com/tngtech/archunit/junit/internal/filtering/AbstractTestNameFilter.java b/archunit-junit/junit5/engine/src/main/java/com/tngtech/archunit/junit/internal/filtering/AbstractTestNameFilter.java index c9bb0d68c1..acf2887ba2 100644 --- a/archunit-junit/junit5/engine/src/main/java/com/tngtech/archunit/junit/internal/filtering/AbstractTestNameFilter.java +++ b/archunit-junit/junit5/engine/src/main/java/com/tngtech/archunit/junit/internal/filtering/AbstractTestNameFilter.java @@ -115,7 +115,7 @@ boolean matches(PostDiscoveryFilter filter) { return discoveryFilterClassName.equals(filter.getClass().getName()); } - protected Optional initialize(PostDiscoveryFilter filter) { + protected Optional initialize(PostDiscoveryFilter filter) throws Exception { return Optional.empty(); } diff --git a/archunit-junit/junit5/engine/src/main/java/com/tngtech/archunit/junit/internal/filtering/TestSourceFilter.java b/archunit-junit/junit5/engine/src/main/java/com/tngtech/archunit/junit/internal/filtering/TestSourceFilter.java index 393fdbc9de..23e1d98bed 100644 --- a/archunit-junit/junit5/engine/src/main/java/com/tngtech/archunit/junit/internal/filtering/TestSourceFilter.java +++ b/archunit-junit/junit5/engine/src/main/java/com/tngtech/archunit/junit/internal/filtering/TestSourceFilter.java @@ -17,12 +17,17 @@ import com.tngtech.archunit.junit.internal.ArchUnitEngineDescriptor; import com.tngtech.archunit.junit.internal.ArchUnitTestEngine; +import com.tngtech.archunit.junit.internal.filtering.surefire.SurefireTestNameFilter; import org.junit.platform.engine.EngineDiscoveryRequest; import org.junit.platform.engine.TestDescriptor; import org.junit.platform.engine.TestSource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; @FunctionalInterface public interface TestSourceFilter { + Logger LOG = LoggerFactory.getLogger(ArchUnitTestEngine.class); + TestSourceFilter NOOP = (descriptor -> true); default boolean shouldRun(TestDescriptor descriptor) { @@ -34,6 +39,13 @@ default boolean shouldRun(TestDescriptor descriptor) { boolean shouldRun(TestSource source); static TestSourceFilter forRequest(EngineDiscoveryRequest discoveryRequest, ArchUnitEngineDescriptor engineDescriptor) { + try { + if (SurefireTestNameFilter.appliesTo(discoveryRequest)) { + return new SurefireTestNameFilter(discoveryRequest); + } + } catch (Exception e) { + LOG.warn("Received error trying to apply test name filter from testing tool", e); + } return TestSourceFilter.NOOP; } } diff --git a/archunit-junit/junit5/engine/src/main/java/com/tngtech/archunit/junit/internal/filtering/surefire/SurefireTestNameFilter.java b/archunit-junit/junit5/engine/src/main/java/com/tngtech/archunit/junit/internal/filtering/surefire/SurefireTestNameFilter.java new file mode 100644 index 0000000000..881b45b7c6 --- /dev/null +++ b/archunit-junit/junit5/engine/src/main/java/com/tngtech/archunit/junit/internal/filtering/surefire/SurefireTestNameFilter.java @@ -0,0 +1,62 @@ +/* + * Copyright 2014-2022 TNG Technology Consulting GmbH + * + * Licensed 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. + */ +package com.tngtech.archunit.junit.internal.filtering.surefire; + +import java.lang.reflect.Field; +import java.util.Objects; +import java.util.Optional; + +import com.tngtech.archunit.junit.internal.filtering.AbstractTestNameFilter; +import com.tngtech.archunit.junit.internal.filtering.TestSelectorFactory; +import org.apache.maven.surefire.api.testset.TestListResolver; +import org.junit.platform.engine.EngineDiscoveryRequest; +import org.junit.platform.launcher.PostDiscoveryFilter; + +public class SurefireTestNameFilter extends AbstractTestNameFilter { + + private static final String SUREFIRE_DISCOVERY_FILTER_NAME = "org.apache.maven.surefire.junitplatform.TestMethodFilter"; + + private TestListResolver resolver; + + public SurefireTestNameFilter(EngineDiscoveryRequest request) throws Exception { + super(request, SUREFIRE_DISCOVERY_FILTER_NAME); + } + + private TestListResolver getTestListResolver(PostDiscoveryFilter filter) throws IllegalAccessException, NoSuchFieldException { + Field testListResolver = filter.getClass().getDeclaredField("testListResolver"); + testListResolver.setAccessible(true); + return (TestListResolver) testListResolver.get(filter); + } + + public static boolean appliesTo(EngineDiscoveryRequest discoveryRequest) { + return AbstractTestNameFilter.checkApplicability(discoveryRequest, SUREFIRE_DISCOVERY_FILTER_NAME); + } + + @Override + protected Optional initialize(PostDiscoveryFilter filter) throws NoSuchFieldException, IllegalAccessException { + this.resolver = Objects.requireNonNull(getTestListResolver(filter)); + return Optional.of(filter); + } + + @Override + protected boolean shouldRunAccordingToTestingTool(TestSelectorFactory.TestSelector selector) { + return resolver.shouldRun(toClassFileName(selector.getContainerName()), selector.getSelectorName()); + } + + static String toClassFileName(String fullyQualifiedTestClass) { + return fullyQualifiedTestClass.replace('.', '/') + ".class"; + } +} diff --git a/archunit-tooling-test/src/test/java/com/tngtech/archunit/tooling/ArchUnitToolingTest.java b/archunit-tooling-test/src/test/java/com/tngtech/archunit/tooling/ArchUnitToolingTest.java index a74f9af8a7..eb368cac6e 100644 --- a/archunit-tooling-test/src/test/java/com/tngtech/archunit/tooling/ArchUnitToolingTest.java +++ b/archunit-tooling-test/src/test/java/com/tngtech/archunit/tooling/ArchUnitToolingTest.java @@ -3,6 +3,7 @@ import java.util.Map; import java.util.stream.Stream; +import com.tngtech.archunit.tooling.engines.gradle.GradleEngine; import com.tngtech.archunit.tooling.examples.ArchJUnit4SuiteTest; import com.tngtech.archunit.tooling.examples.ArchJUnit4Test; import com.tngtech.archunit.tooling.examples.ArchJUnit5SuiteTest; @@ -11,6 +12,8 @@ import org.junitpioneer.jupiter.cartesian.ArgumentSets; import org.junitpioneer.jupiter.cartesian.CartesianTest; +import static org.assertj.core.api.Assumptions.assumeThat; + public class ArchUnitToolingTest extends BaseTest { @CartesianTest @@ -21,8 +24,8 @@ void shouldReportCorrectTestResults(TestEngine engine, Class fixture) throws @CartesianTest @CartesianTest.MethodFactory("enginesAndFixtures") - @Disabled void shouldOnlyExecuteSelectedTests(TestEngine engine, Class fixture) throws Exception { + assumeThat(engine).isNotInstanceOf(GradleEngine.class); //not yet supported super.shouldOnlyExecuteSelectedTests(engine, fixture); } diff --git a/archunit/src/main/java/com/tngtech/archunit/ArchConfiguration.java b/archunit/src/main/java/com/tngtech/archunit/ArchConfiguration.java index f70aadb3cc..af434e3951 100644 --- a/archunit/src/main/java/com/tngtech/archunit/ArchConfiguration.java +++ b/archunit/src/main/java/com/tngtech/archunit/ArchConfiguration.java @@ -52,6 +52,8 @@ public final class ArchConfiguration { public static final String ENABLE_MD5_IN_CLASS_SOURCES = "enableMd5InClassSources"; private static final String EXTENSION_PREFIX = "extension"; + public static final String JUNIT_PREFIX = "junit"; + private static final Logger LOG = LoggerFactory.getLogger(ArchConfiguration.class); private static final Supplier INSTANCE = Suppliers.memoize(ArchConfiguration::new);