From cadc7f68c2b1f3090d6805f5d4015196a6391b0a Mon Sep 17 00:00:00 2001 From: Thomas Tresansky Date: Fri, 13 Jan 2023 12:50:36 -0500 Subject: [PATCH 1/2] Inject services into all external module dependencies created by DefaultJvmComponentDependencies This fixes an issue where you can decorate a dep with platform and get a runtime failure because an AttributesFactory has not been injected into the dep. --- .../artifacts/DefaultDependencyFactory.java | 5 +- .../TestSuitesIntegrationTest.groovy | 76 +++++++++++++++++++ 2 files changed, 80 insertions(+), 1 deletion(-) diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/DefaultDependencyFactory.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/DefaultDependencyFactory.java index a2ed83e65591..fcc18d368f78 100644 --- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/DefaultDependencyFactory.java +++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/DefaultDependencyFactory.java @@ -130,7 +130,9 @@ private void configureModule(ClientModule clientModule, Closure configureClosure @Override public ExternalModuleDependency create(CharSequence dependencyNotation) { - return dependencyNotationParser.getStringNotationParser().parseNotation(dependencyNotation.toString()); + ExternalModuleDependency dependency = dependencyNotationParser.getStringNotationParser().parseNotation(dependencyNotation.toString()); + injectServices(dependency); + return dependency; } @Override @@ -142,6 +144,7 @@ public ExternalModuleDependency create(@Nullable String group, String name, @Nul public ExternalModuleDependency create(@Nullable String group, String name, @Nullable String version, @Nullable String classifier, @Nullable String extension) { DefaultExternalModuleDependency dependency = instantiator.newInstance(DefaultExternalModuleDependency.class, group, name, version); ModuleFactoryHelper.addExplicitArtifactsIfDefined(dependency, extension, classifier); + injectServices(dependency); return dependency; } diff --git a/subprojects/testing-jvm/src/integTest/groovy/org/gradle/testing/testsuites/TestSuitesIntegrationTest.groovy b/subprojects/testing-jvm/src/integTest/groovy/org/gradle/testing/testsuites/TestSuitesIntegrationTest.groovy index 350611a3b3db..ad92fcc1c760 100644 --- a/subprojects/testing-jvm/src/integTest/groovy/org/gradle/testing/testsuites/TestSuitesIntegrationTest.groovy +++ b/subprojects/testing-jvm/src/integTest/groovy/org/gradle/testing/testsuites/TestSuitesIntegrationTest.groovy @@ -782,4 +782,80 @@ class TestSuitesIntegrationTest extends AbstractIntegrationSpec { failure.assertHasErrorOutput("Compilation failed; see the compiler error output for details.") failure.assertHasErrorOutput("error: package org.junit does not exist") } + + @Issue("https://github.com/gradle/gradle/issues/19065") + def "test suites can add platforms using a #platformType with #format"() { + given: "a project defining a platform" + file('platform/build.gradle') << """ + plugins { + id 'java-platform' + } + + group = "org.example.gradle" + + dependencies { + constraints { + api 'org.assertj:assertj-core:3.22.0' + } + } + """ + + and: "an application project with a test suite using the platform" + file('app/build.gradle') << """ + plugins { + id 'java' + } + + ${mavenCentralRepository()} + + testing { + suites { + test { + useJUnitJupiter() + + dependencies { + implementation($expression) + implementation 'org.assertj:assertj-core' + } + } + } + } + """ + file('app/src/test/java/org/example/app/ExampleTest.java') << """ + package org.example.app; + + import org.junit.jupiter.api.Test; + import static org.assertj.core.api.Assertions.assertThat; + + public class ExampleTest { + @Test public void testOK() { + assertThat(1 + 1).isEqualTo(2); + } + } + """ + + settingsFile << """ + dependencyResolutionManagement { + includeBuild("platform") + } + + rootProject.name = 'example-of-platform-in-test-suites' + + include("app") + """ + + expect: "should be able to reference the platform without failing" + succeeds ':app:test' + def unitTestResults = new JUnitXmlTestExecutionResult(testDirectory, 'app/build/test-results/test') + unitTestResults.assertTestClassesExecuted('org.example.app.ExampleTest') + + where: + format | platformType | expression + 'single GAV string' | 'platform' | "platform('org.example.gradle:platform')" + 'module method' | 'platform' | "platform(module('org.example.gradle', 'platform', null))" + 'referencing project.dependencies' | 'platform' | "project.dependencies.platform('org.example.gradle:platform')" + 'single GAV string' | 'enforcedPlatform' | "enforcedPlatform('org.example.gradle:platform')" + 'module method' | 'enforcedPlatform' | "enforcedPlatform(module('org.example.gradle', 'platform', null))" + 'referencing project.dependencies' | 'enforcedPlatform' | "project.dependencies.enforcedPlatform('org.example.gradle:platform')" + } } From e9f1eb327ddc3dcb81abec43f8d3dab209c55621 Mon Sep 17 00:00:00 2001 From: Thomas Tresansky Date: Fri, 13 Jan 2023 14:32:32 -0500 Subject: [PATCH 2/2] ServiceInject project dependencies for consistency - Adds integration tests for test suites using project coordinate dependencies to ensure this remains working --- .../artifacts/DefaultDependencyFactory.java | 4 +- .../TestSuitesIntegrationTest.groovy | 121 +++++++++++++++++- 2 files changed, 123 insertions(+), 2 deletions(-) diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/DefaultDependencyFactory.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/DefaultDependencyFactory.java index fcc18d368f78..2e11a589b3cf 100644 --- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/DefaultDependencyFactory.java +++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/DefaultDependencyFactory.java @@ -155,7 +155,9 @@ public FileCollectionDependency create(FileCollection fileCollection) { @Override public ProjectDependency create(Project project) { - return dependencyNotationParser.getProjectNotationParser().parseNotation(project); + ProjectDependency dependency = dependencyNotationParser.getProjectNotationParser().parseNotation(project); + injectServices(dependency); + return dependency; } // endregion diff --git a/subprojects/testing-jvm/src/integTest/groovy/org/gradle/testing/testsuites/TestSuitesIntegrationTest.groovy b/subprojects/testing-jvm/src/integTest/groovy/org/gradle/testing/testsuites/TestSuitesIntegrationTest.groovy index ad92fcc1c760..cfa3e834fd49 100644 --- a/subprojects/testing-jvm/src/integTest/groovy/org/gradle/testing/testsuites/TestSuitesIntegrationTest.groovy +++ b/subprojects/testing-jvm/src/integTest/groovy/org/gradle/testing/testsuites/TestSuitesIntegrationTest.groovy @@ -784,7 +784,7 @@ class TestSuitesIntegrationTest extends AbstractIntegrationSpec { } @Issue("https://github.com/gradle/gradle/issues/19065") - def "test suites can add platforms using a #platformType with #format"() { + def "test suites can add platforms using a #platformType with #format via coordinates"() { given: "a project defining a platform" file('platform/build.gradle') << """ plugins { @@ -858,4 +858,123 @@ class TestSuitesIntegrationTest extends AbstractIntegrationSpec { 'module method' | 'enforcedPlatform' | "enforcedPlatform(module('org.example.gradle', 'platform', null))" 'referencing project.dependencies' | 'enforcedPlatform' | "project.dependencies.enforcedPlatform('org.example.gradle:platform')" } + + @Issue("https://github.com/gradle/gradle/issues/19065") + def "test suites can add project dependencies via coordinates"() { + given: "a project used as a dependency" + file('dep/build.gradle') << """ + plugins { + id 'java-library' + } + + group = "org.example.gradle" + """ + file('dep/src/main/java/org/example/dep/Dep.java') << """ + package org.example.dep; + public class Dep {} + """ + + and: "an application project with a test suite using a project dependency" + file('app/build.gradle') << """ + plugins { + id 'java' + } + + ${mavenCentralRepository()} + + testing { + suites { + test { + useJUnitJupiter() + + dependencies { + implementation('org.example.gradle:dep') + } + } + } + } + """ + file('app/src/test/java/org/example/app/ExampleTest.java') << """ + package org.example.app; + + import org.junit.jupiter.api.Test; + import org.example.dep.Dep; + + public class ExampleTest { + @Test public void testOK() { + new Dep(); + } + } + """ + + settingsFile << """ + dependencyResolutionManagement { + includeBuild("dep") + } + + rootProject.name = 'example-of-project-reference-in-test-suites' + + include("app") + """ + + expect: "should be able to reference the project without failing" + succeeds ':app:test' + def unitTestResults = new JUnitXmlTestExecutionResult(testDirectory, 'app/build/test-results/test') + unitTestResults.assertTestClassesExecuted('org.example.app.ExampleTest') + } + + @Issue("https://github.com/gradle/gradle/issues/19065") + def "test suites can add self project dependency via coordinates"() { + given: "an application project with a custom test suite with a dependency on the project" + file('app/src/main/java/org/example/dep/Dep.java') << """ + package org.example.dep; + public class Dep {} + """ + file('app/build.gradle') << """ + plugins { + id 'java' + } + + ${mavenCentralRepository()} + + group = "org.example.gradle" + version = "1.0" + + testing { + suites { + integrationTest(JvmTestSuite) { + useJUnitJupiter() + + dependencies { + implementation('org.example.gradle:app:1.0') + } + } + } + } + """ + file('app/src/integrationTest/java/org/example/app/ExampleTest.java') << """ + package org.example.app; + + import org.junit.jupiter.api.Test; + import org.example.dep.Dep; + + public class ExampleTest { + @Test public void testOK() { + new Dep(); + } + } + """ + + settingsFile << """ + rootProject.name = 'example-of-project-reference-in-test-suites' + + include("app") + """ + executer.noDeprecationChecks() + + expect: "should be able to reference the project without failing" + succeeds ':app:assemble', ':app:integrationTest' + def unitTestResults = new JUnitXmlTestExecutionResult(testDirectory, 'app/build/test-results/integrationTest') + unitTestResults.assertTestClassesExecuted('org.example.app.ExampleTest') + } }