diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/MavenSessionBuilderSupplier.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/MavenSessionBuilderSupplier.java index f18d9f09a515..0483d9ff34c6 100644 --- a/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/MavenSessionBuilderSupplier.java +++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/MavenSessionBuilderSupplier.java @@ -100,11 +100,13 @@ public DependencyManager getDependencyManager(boolean transitive) { } public DependencySelector getDependencySelector() { + DependencySelector scopeSelector = ScopeDependencySelector.legacy( + null, Arrays.asList(DependencyScope.TEST.id(), DependencyScope.PROVIDED.id())); + if (!mavenMaven3Personality) { + scopeSelector = new TestJarDependencySelector(scopeSelector); + } return new AndDependencySelector( - ScopeDependencySelector.legacy( - null, Arrays.asList(DependencyScope.TEST.id(), DependencyScope.PROVIDED.id())), - OptionalDependencySelector.fromDirect(), - new ExclusionDependencySelector()); + scopeSelector, OptionalDependencySelector.fromDirect(), new ExclusionDependencySelector()); } public DependencyGraphTransformer getDependencyGraphTransformer() { diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/TestJarDependencySelector.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/TestJarDependencySelector.java new file mode 100644 index 000000000000..fa038992793d --- /dev/null +++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/TestJarDependencySelector.java @@ -0,0 +1,94 @@ +/* + * 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. + */ +package org.apache.maven.impl.resolver; + +import java.util.Objects; + +import org.apache.maven.api.DependencyScope; +import org.apache.maven.api.Type; +import org.eclipse.aether.artifact.ArtifactProperties; +import org.eclipse.aether.collection.DependencyCollectionContext; +import org.eclipse.aether.collection.DependencySelector; +import org.eclipse.aether.graph.Dependency; + +import static java.util.Objects.requireNonNull; + +/** + * Preserves Maven's normal non-transitive test-scope semantics while allowing the direct test-scoped dependencies of + * a test JAR to participate in dependency collection. Those dependencies are part of the test artifact's classpath + * contract, not the producer's main artifact contract. + */ +final class TestJarDependencySelector implements DependencySelector { + private final DependencySelector delegate; + private final boolean testJarParent; + + TestJarDependencySelector(DependencySelector delegate) { + this(delegate, false); + } + + private TestJarDependencySelector(DependencySelector delegate, boolean testJarParent) { + this.delegate = requireNonNull(delegate, "delegate cannot be null"); + this.testJarParent = testJarParent; + } + + @Override + public boolean selectDependency(Dependency dependency) { + requireNonNull(dependency, "dependency cannot be null"); + if (testJarParent && DependencyScope.TEST.id().equals(dependency.getScope())) { + return true; + } + return delegate.selectDependency(dependency); + } + + @Override + public DependencySelector deriveChildSelector(DependencyCollectionContext context) { + requireNonNull(context, "context cannot be null"); + + DependencySelector childDelegate = delegate.deriveChildSelector(context); + Dependency parent = context.getDependency(); + boolean childOfTestJar = parent != null + && Type.TEST_JAR.equals(parent.getArtifact().getProperty(ArtifactProperties.TYPE, "")); + + if (childDelegate == delegate && childOfTestJar == testJarParent) { + return this; + } + return new TestJarDependencySelector(childDelegate, childOfTestJar); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof TestJarDependencySelector that)) { + return false; + } + return testJarParent == that.testJarParent && delegate.equals(that.delegate); + } + + @Override + public int hashCode() { + return Objects.hash(delegate, testJarParent); + } + + @Override + public String toString() { + return getClass().getSimpleName() + "[delegate=" + delegate + ", testJarParent=" + testJarParent + ']'; + } +} diff --git a/its/core-it-suite/src/test/java/org/apache/maven/it/MavenITmng1378TestJarTransitiveDependenciesTest.java b/its/core-it-suite/src/test/java/org/apache/maven/it/MavenITmng1378TestJarTransitiveDependenciesTest.java new file mode 100644 index 000000000000..f30ba775a978 --- /dev/null +++ b/its/core-it-suite/src/test/java/org/apache/maven/it/MavenITmng1378TestJarTransitiveDependenciesTest.java @@ -0,0 +1,67 @@ +/* + * 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. + */ +package org.apache.maven.it; + +import java.nio.file.Path; +import java.util.List; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Integration test for MNG-1378. + */ +public class MavenITmng1378TestJarTransitiveDependenciesTest extends AbstractMavenIntegrationTestCase { + + @Test + public void testTestJarCarriesProducerTestDependencies() throws Exception { + Path testDir = extractResources("mng-1378"); + + Verifier producer = newVerifier(testDir); + producer.setAutoclean(false); + producer.deleteArtifacts("org.apache.maven.its.mng1378"); + producer.addCliArgument("-pl"); + producer.addCliArgument("support,test-jar"); + producer.addCliArgument("validate"); + producer.execute(); + producer.verifyErrorFreeLog(); + + Verifier consumer = newVerifier(testDir.resolve("consumer")); + consumer.setAutoclean(false); + consumer.addCliArgument("validate"); + consumer.execute(); + consumer.verifyErrorFreeLog(); + + List testClasspath = consumer.loadLines("target/test.txt"); + assertTrue(testClasspath.contains("test-jar-1.0-tests.jar"), testClasspath.toString()); + assertTrue(testClasspath.contains("support-1.0.jar"), testClasspath.toString()); + + Verifier regularConsumer = newVerifier(testDir.resolve("regular-consumer")); + regularConsumer.setAutoclean(false); + regularConsumer.addCliArgument("validate"); + regularConsumer.execute(); + regularConsumer.verifyErrorFreeLog(); + + List regularTestClasspath = regularConsumer.loadLines("target/test.txt"); + assertTrue(regularTestClasspath.contains("test-jar-1.0.jar"), regularTestClasspath.toString()); + assertFalse(regularTestClasspath.contains("support-1.0.jar"), regularTestClasspath.toString()); + } +} diff --git a/its/core-it-suite/src/test/resources/mng-1378/consumer/pom.xml b/its/core-it-suite/src/test/resources/mng-1378/consumer/pom.xml new file mode 100644 index 000000000000..2e9b1c66dbcc --- /dev/null +++ b/its/core-it-suite/src/test/resources/mng-1378/consumer/pom.xml @@ -0,0 +1,61 @@ + + + + 4.0.0 + + org.apache.maven.its.mng1378 + consumer + 1.0 + + Maven Integration Test :: MNG-1378 :: Test JAR Consumer + + + + org.apache.maven.its.mng1378 + test-jar + 1.0 + test-jar + test + + + + + + + org.apache.maven.its.plugins + maven-it-plugin-dependency-resolution + 2.1-SNAPSHOT + + + test + + test + + validate + + target/test.txt + 1 + + + + + + + diff --git a/its/core-it-suite/src/test/resources/mng-1378/pom.xml b/its/core-it-suite/src/test/resources/mng-1378/pom.xml new file mode 100644 index 000000000000..f73f76e221a2 --- /dev/null +++ b/its/core-it-suite/src/test/resources/mng-1378/pom.xml @@ -0,0 +1,37 @@ + + + + 4.0.0 + + org.apache.maven.its.mng1378 + parent + 1.0 + pom + + Maven Integration Test :: MNG-1378 + Verify that dependencies required by a producer's test JAR are transitively available to test-JAR consumers. + + + support + test-jar + consumer + regular-consumer + + diff --git a/its/core-it-suite/src/test/resources/mng-1378/regular-consumer/pom.xml b/its/core-it-suite/src/test/resources/mng-1378/regular-consumer/pom.xml new file mode 100644 index 000000000000..17bd00050f25 --- /dev/null +++ b/its/core-it-suite/src/test/resources/mng-1378/regular-consumer/pom.xml @@ -0,0 +1,60 @@ + + + + 4.0.0 + + org.apache.maven.its.mng1378 + regular-consumer + 1.0 + + Maven Integration Test :: MNG-1378 :: Regular JAR Consumer + + + + org.apache.maven.its.mng1378 + test-jar + 1.0 + test + + + + + + + org.apache.maven.its.plugins + maven-it-plugin-dependency-resolution + 2.1-SNAPSHOT + + + test + + test + + validate + + target/test.txt + 1 + + + + + + + diff --git a/its/core-it-suite/src/test/resources/mng-1378/support/pom.xml b/its/core-it-suite/src/test/resources/mng-1378/support/pom.xml new file mode 100644 index 000000000000..c0d7f5ba0117 --- /dev/null +++ b/its/core-it-suite/src/test/resources/mng-1378/support/pom.xml @@ -0,0 +1,51 @@ + + + + 4.0.0 + + org.apache.maven.its.mng1378 + support + 1.0 + + Maven Integration Test :: MNG-1378 :: Test Support + + + + + org.apache.maven.its.plugins + maven-it-plugin-artifact + 2.1-SNAPSHOT + + pom.xml + + + + install + + set + install + + validate + + + + + + diff --git a/its/core-it-suite/src/test/resources/mng-1378/test-jar/pom.xml b/its/core-it-suite/src/test/resources/mng-1378/test-jar/pom.xml new file mode 100644 index 000000000000..0294fd3bf9d2 --- /dev/null +++ b/its/core-it-suite/src/test/resources/mng-1378/test-jar/pom.xml @@ -0,0 +1,65 @@ + + + + 4.0.0 + + org.apache.maven.its.mng1378 + test-jar + 1.0 + + Maven Integration Test :: MNG-1378 :: Test JAR Producer + + + + org.apache.maven.its.mng1378 + support + 1.0 + test + + + + + + + org.apache.maven.its.plugins + maven-it-plugin-artifact + 2.1-SNAPSHOT + + + install + + set + attach-pom + attach + install + + validate + + pom.xml + pom.xml + test-jar + tests + + + + + + +