[Gradle] Introduce SourceSetDependenciesResolution dsl for tests

It allows to mock published via gradle libraries to verify
dependency resolution correctness.
This commit is contained in:
Anton Lakotka
2024-02-22 23:56:02 +01:00
committed by Space Team
parent 46abf63796
commit c027ba642f
2 changed files with 156 additions and 0 deletions
@@ -0,0 +1,69 @@
/*
* Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle.dependencyResolutionTests
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
import java.io.File
fun KotlinMultiplatformExtension.publishAsMockedLibrary(repoDir: File, name: String, version: String) {
val moduleRootDir = repoDir.resolve("test/$name/$version")
moduleRootDir.mkdirs()
val moduleFile = moduleRootDir.resolve("$name-$version.module")
moduleFile.writeText(publishedMockedGradleMetadata(name, version))
val pomFile = moduleFile.parentFile.resolve("$name-$version.pom")
pomFile.writeText(
"""
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>test</groupId>
<artifactId>$name</artifactId>
<version>$version</version>
</project>
""".trimIndent()
)
}
private fun KotlinMultiplatformExtension.publishedMockedGradleMetadata(name: String, version: String): String {
val variants = targets.joinToString(",") { it.variantJson() + "\n" }
return """
{
"formatVersion": "1.1",
"component": {
"group": "test",
"module": "$name",
"version": "$version",
"attributes": {
"org.gradle.status": "release"
}
},
"variants": [
$variants
]
}
""".trimIndent()
}
private fun KotlinTarget.variantJson(): String {
val apiElements = project.configurations.getByName(apiElementsConfigurationName)
val attributesString = apiElements
.attributes
.keySet()
.map { it to apiElements.attributes.getAttribute(it) }
.joinToString(",\n") { "\"${it.first.name}\": \"${it.second}\"" }
return """
{
"name": "$name",
"attributes": {
$attributesString
}
}
""".trimIndent()
}
@@ -0,0 +1,87 @@
/*
* Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle.dependencyResolutionTests
import org.gradle.api.Project
import org.gradle.kotlin.dsl.maven
import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
import org.jetbrains.kotlin.gradle.dsl.platformTargets
import org.jetbrains.kotlin.gradle.plugin.mpp.resolvableMetadataConfiguration
import org.jetbrains.kotlin.gradle.plugin.sources.internal
import org.jetbrains.kotlin.gradle.util.*
import org.jetbrains.kotlin.test.KotlinTestUtils
import org.junit.Rule
import org.junit.rules.TemporaryFolder
abstract class SourceSetDependenciesResolution {
@get:Rule
val tempFolder = TemporaryFolder()
class SourceSetDependenciesDsl(
private val project: Project
) {
val declaredDependencies = mutableSetOf<Pair<String, String>>() // list of name + versions
/**
* Declares an API dependency to test:[name]:[version] for [sourceSetName] source set
*/
fun api(sourceSetName: String, name: String, version: String) {
declaredDependencies.add(name to version)
project.kotlinExtension.sourceSets.getByName(sourceSetName).dependencies { api("test:$name:$version") }
}
}
fun assertSourceSetDependenciesResolution(expectedFilePath: String, configure: SourceSetDependenciesDsl.(Project) -> Unit) {
val repoRoot = tempFolder.newFolder()
val project = buildProject {
enableDefaultStdlibDependency(false)
enableDependencyVerification(false)
applyMultiplatformPlugin()
repositories.maven(repoRoot)
}
val dsl = SourceSetDependenciesDsl(project)
dsl.configure(project)
dsl.declaredDependencies.forEach { project.multiplatformExtension.publishAsMockedLibrary(repoRoot, it.first, it.second) }
project.evaluate()
val actualResult = project.resolveAllSourceSetDependencies()
val expectedFile = resourcesRoot.resolve("dependenciesResolution").resolve(expectedFilePath)
KotlinTestUtils.assertEqualsToFile(expectedFile, actualResult)
}
private fun Project.resolveAllSourceSetDependencies(): String {
val allSourceSets = multiplatformExtension.sourceSets.toSet()
val platformSpecificSourceSets = multiplatformExtension
.targets
.platformTargets
.flatMap { it.compilations }
.associate { it.defaultSourceSet to configurations.getByName(it.compileDependencyConfigurationName) }
val commonSourceSetsWithoutMetadataCompilation = allSourceSets
.minus(platformSpecificSourceSets.keys)
.associateWith { it.internal.resolvableMetadataConfiguration }
val actual = (platformSpecificSourceSets + commonSourceSetsWithoutMetadataCompilation).mapValues { (_, configuration) ->
val resolutionResult = configuration.incoming.resolutionResult
val rootComponent = resolutionResult.root
val dependencies = resolutionResult.allComponents
.minus(rootComponent)
.map { it.id.displayName }
.sorted()
dependencies.joinToString("\n") { " $it" }
}.entries.sortedBy { (sourceSet, _) -> sourceSet.name }.joinToString("\n") {
it.key.name + "\n" + it.value
}
return actual
}
}