org.gradle.integtests.resolve.RepositoryInteractionDependencyResolveIntegrationTest.groovy Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gradle-api Show documentation
Show all versions of gradle-api Show documentation
Gradle 6.9.1 API redistribution.
/*
* Copyright 2017 the original author or authors.
*
* 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 org.gradle.integtests.resolve
import org.gradle.integtests.fixtures.AbstractHttpDependencyResolutionTest
import org.gradle.integtests.fixtures.publish.RemoteRepositorySpec
import org.gradle.integtests.fixtures.resolve.ResolveTestFixture
import org.gradle.test.fixtures.HttpRepository
import org.gradle.test.fixtures.ivy.IvyModule
import spock.lang.Unroll
class RepositoryInteractionDependencyResolveIntegrationTest extends AbstractHttpDependencyResolutionTest {
private static final REPO_TYPES = ['maven', 'ivy', 'maven-gradle', 'ivy-gradle']
private static final TEST_VARIANTS = [
'default': '',
'runtime': 'configurations.conf.attributes.attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage, Usage.JAVA_RUNTIME))',
'api': 'configurations.conf.attributes.attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage, Usage.JAVA_API))',
]
def setup() {
// apply Java ecosystem rules
buildFile << """
org.gradle.api.internal.artifacts.JavaEcosystemSupport.configureSchema(
dependencies.attributesSchema,
project.objects
)
"""
}
private static boolean leaksRuntime(testVariant, repoType, prevRepoType = null) {
if (testVariant == 'runtime' || testVariant == 'default') {
// the runtime variant is supposed to include everything
return true
}
if (testVariant == 'api' && repoType == 'ivy') {
// classic ivy metadata interpretation does not honor api/runtime separation
return true
}
return false
}
private static String expectedConfiguration(repoType, testVariant) {
if (repoType.contains('gradle')) {
if (testVariant.contains('api')) {
return 'api'
}
return 'runtime'
}
if (repoType == 'maven') {
switch (testVariant) {
case 'api':
return 'compile'
default:
return 'runtime'
}
}
return 'default'
}
private ResolveTestFixture resolve
private Map repoSpecs = [:]
private Map repos = [:]
private String configuredRepository(String repoType) {
def isMaven = repoType.contains('maven')
def gradleMetadata = repoType.contains('gradle')
HttpRepository repo = isMaven ?
mavenHttpRepo(repoType, gradleMetadata ? HttpRepository.MetadataType.ONLY_GRADLE : HttpRepository.MetadataType.ONLY_ORIGINAL)
: ivyHttpRepo(repoType, gradleMetadata ? HttpRepository.MetadataType.ONLY_GRADLE : HttpRepository.MetadataType.ONLY_ORIGINAL)
repos += [(repoType): repo]
"""
repositories {
${isMaven ? 'maven' : 'ivy'} {
url "${repo.uri}"
metadataSources { ${gradleMetadata ? 'gradleMetadata()' : isMaven ? 'mavenPom()' : 'ivyDescriptor()'} }
}
}
"""
}
def setupRepositories(repoTypes) {
repoTypes.each { repoType ->
repoSpecs += [(repoType): new RemoteRepositorySpec()]
buildFile << """
${configuredRepository(repoType)}
"""
}
def conf = "conf"
resolve = new ResolveTestFixture(buildFile, conf)
settingsFile << "rootProject.name = 'test'"
resolve.prepare()
buildFile << """
configurations {
$conf
}
"""
resolve.addDefaultVariantDerivationStrategy()
repoTypes.each { repoType ->
repository(repoType) {
"org:$repoType-api-dependency:1.0"()
"org:$repoType-runtime-dependency:1.0"()
"org:$repoType:1.0" {
variant("api") {
dependsOn "org:$repoType-api-dependency:1.0"
}
variant("runtime") {
dependsOn "org:$repoType-api-dependency:1.0"
dependsOn "org:$repoType-runtime-dependency:1.0"
}
}
}
}
}
def setupModuleChain(chain) {
String prevRepoType = null
chain.each { repoType ->
if (prevRepoType) {
repository(prevRepoType) {
"org:$prevRepoType:1.0" {
variant("api") {
dependsOn "org:$repoType:1.0"
}
variant("runtime") {
dependsOn "org:$repoType:1.0"
}
}
}
}
prevRepoType = repoType
}
}
def expectChainInteractions(repoTypes, chain, testVariant = 'api', configuration = null) {
String prevRepoType = null
chain.each { repoType ->
repositoryInteractions(repoType) {
"org:$repoType:1.0" {
expectGetMetadata()
expectGetArtifact()
}
"org:$repoType-api-dependency:1.0" {
expectGetMetadata()
expectGetArtifact()
}
if (leaksRuntime(testVariant, repoType, prevRepoType) || (prevRepoType==null && configuration in ['test', 'runtime'])) {
"org:$repoType-runtime-dependency:1.0" {
expectGetMetadata()
expectGetArtifact()
}
}
repoTypes.subList(repoTypes.indexOf(repoType) + 1, repoTypes.size()).each { other ->
"org:$other:1.0" {
expectGetMetadataMissingThatIsFoundElsewhere()
}
"org:$other-api-dependency:1.0" {
expectGetMetadataMissingThatIsFoundElsewhere()
}
if (leaksRuntime(testVariant, other, chain.indexOf(other) > 0? chain[chain.indexOf(other) - 1] : null)) {
"org:$other-runtime-dependency:1.0" {
expectGetMetadataMissingThatIsFoundElsewhere()
}
}
}
}
prevRepoType = repoType
}
}
void repository(String repoType, @DelegatesTo(RemoteRepositorySpec) Closure spec) {
spec.delegate = repoSpecs[repoType]
spec()
}
void repositoryInteractions(String repoType, @DelegatesTo(RemoteRepositorySpec) Closure spec) {
RemoteRepositorySpec.DEFINES_INTERACTIONS.set(true)
try {
spec.delegate = repoSpecs[repoType]
spec()
repoSpecs[repoType].build(repos[repoType])
} finally {
RemoteRepositorySpec.DEFINES_INTERACTIONS.set(false)
}
}
@Unroll
def "selects #testVariant variant of each dependency in every repo supporting it #chain"() {
given:
setupRepositories(REPO_TYPES)
setupModuleChain(chain)
when:
buildFile << """
${TEST_VARIANTS[testVariant]}
dependencies {
conf 'org:${chain[0]}:1.0'
}
"""
expectChainInteractions(REPO_TYPES, chain, testVariant)
then:
succeeds 'checkDep'
resolve.expectGraph {
root(':', ':test:') {
module("org:${chain[0]}:1.0:${RepositoryInteractionDependencyResolveIntegrationTest.expectedConfiguration(chain[0], testVariant)}") {
module "org:${chain[0]}-api-dependency:1.0"
if (RepositoryInteractionDependencyResolveIntegrationTest.leaksRuntime(testVariant, chain[0])) { module "org:${chain[0]}-runtime-dependency:1.0" }
module("org:${chain[1]}:1.0") {
module "org:${chain[1]}-api-dependency:1.0"
if (RepositoryInteractionDependencyResolveIntegrationTest.leaksRuntime(testVariant, chain[1], chain[0])) { module "org:${chain[1]}-runtime-dependency:1.0" }
module("org:${chain[2]}:1.0") {
module "org:${chain[2]}-api-dependency:1.0"
if (RepositoryInteractionDependencyResolveIntegrationTest.leaksRuntime(testVariant, chain[2], chain[1])) { module "org:${chain[2]}-runtime-dependency:1.0" }
module("org:${chain[3]}:1.0") {
module "org:${chain[3]}-api-dependency:1.0"
if (RepositoryInteractionDependencyResolveIntegrationTest.leaksRuntime(testVariant, chain[3], chain[2])) { module "org:${chain[3]}-runtime-dependency:1.0" }
}
}
}
}
}
}
where:
[chain, testVariant] << [REPO_TYPES.permutations(), TEST_VARIANTS.keySet()].combinations()
}
def "explicit compile configuration selection works for a chain of pure maven dependencies"() {
given:
def modules = ['mavenCompile1', 'mavenCompile2', 'mavenCompile3']
setupRepositories(modules)
setupModuleChain(modules)
when:
buildFile << """
dependencies {
configurations.conf.attributes.attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage, Usage.JAVA_API))
conf group: 'org', name: 'mavenCompile1', version: '1.0', configuration: 'compile'
}
"""
expectChainInteractions(modules, modules)
then:
succeeds 'checkDep'
resolve.expectGraph {
root(':', ':test:') {
module("org:mavenCompile1:1.0:compile") {
module "org:mavenCompile1-api-dependency:1.0"
module("org:mavenCompile2:1.0") {
module "org:mavenCompile2-api-dependency:1.0"
module("org:mavenCompile3:1.0") {
module "org:mavenCompile3-api-dependency:1.0"
}
}
}
}
}
}
def "explicit compile configuration selection with Gradle metadata is propagates to Maven dependencies"() {
given:
def modules = ['mavenCompile1', 'mavenCompile2', 'maven-gradle', 'maven']
setupRepositories(modules)
setupModuleChain(modules)
when:
buildFile << """
dependencies {
configurations.conf.attributes.attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage, Usage.JAVA_API))
conf group: 'org', name: 'mavenCompile1', version: '1.0', configuration: 'compile'
}
"""
expectChainInteractions(modules, modules)
then:
succeeds 'checkDep'
resolve.expectGraph {
root(':', ':test:') {
module("org:mavenCompile1:1.0:compile") {
module "org:mavenCompile1-api-dependency:1.0"
module("org:mavenCompile2:1.0") {
module "org:mavenCompile2-api-dependency:1.0"
module("org:maven-gradle:1.0") { // Attribute matching is used here
module "org:maven-gradle-api-dependency:1.0"
module("org:maven:1.0") {
module "org:maven-api-dependency:1.0"
}
}
}
}
}
}
}
@Unroll
def "explicit #conf configuration selection still works for maven dependencies"() {
given:
def modules = ['maven', 'mavenCompile1', 'maven-gradle', 'mavenCompile2']
setupRepositories(modules)
setupModuleChain(modules)
when:
buildFile << """
dependencies {
configurations.conf.attributes.attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage, Usage.JAVA_API))
conf group: 'org', name: 'maven', version: '1.0', configuration: '$conf'
}
"""
expectChainInteractions(modules, modules, 'api', conf)
then:
succeeds 'checkDep'
resolve.expectGraph {
root(':', ':test:') {
module("org:maven:1.0:$conf") {
module "org:maven-api-dependency:1.0"
module "org:maven-runtime-dependency:1.0"
module("org:mavenCompile1:1.0") {
//form here on, attribute matching is used
module "org:mavenCompile1-api-dependency:1.0"
module("org:maven-gradle:1.0") {
module "org:maven-gradle-api-dependency:1.0"
module("org:mavenCompile2:1.0") {
module "org:mavenCompile2-api-dependency:1.0"
}
}
}
}
}
}
where:
conf << ['runtime', 'test']
}
@Unroll
def "explicit configuration selection in ivy modules is supported=#supported if targeting a #target module"() {
given:
String targetRepoName = supported? "$target-select" : target //use a different name if selection is supported to not follow the default expectations defined in leaksRuntime()
setupRepositories([targetRepoName, 'ivy'])
repository('ivy') {
"org:ivy:1.0" {
withModule(IvyModule) {
dependsOn([organisation: 'org', module: targetRepoName, revision: '1.0', conf: 'runtime->compile'])
}
}
}
when:
buildFile << """
dependencies {
conf 'org:ivy:1.0'
}
"""
expectChainInteractions([targetRepoName, 'ivy'], ['ivy', targetRepoName], supported? 'api' : 'runtime')
then:
succeeds 'checkDep'
resolve.expectGraph {
root(':', ':test:') {
module("org:ivy:1.0") {
module "org:ivy-api-dependency:1.0"
module "org:ivy-runtime-dependency:1.0"
module("org:$targetRepoName:1.0") {
module "org:$targetRepoName-api-dependency:1.0"
if (!supported) {
module "org:$targetRepoName-runtime-dependency:1.0"
}
}
}
}
}
where:
target | supported
'maven' | false
'ivy' | true
'maven-gradle' | false
'ivy-gradle' | false
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy