[Gradle][MPP] MPPBuildReproducibilityIT: Use custom diff implementation
^KT-52740 Verification Pending
This commit is contained in:
committed by
Space
parent
1e118c06af
commit
c93b1d2aab
+73
-20
@@ -10,11 +10,11 @@ import org.gradle.util.GradleVersion
|
|||||||
import org.jetbrains.kotlin.gradle.testbase.*
|
import org.jetbrains.kotlin.gradle.testbase.*
|
||||||
import org.junit.jupiter.api.DisplayName
|
import org.junit.jupiter.api.DisplayName
|
||||||
import org.junit.jupiter.api.condition.OS
|
import org.junit.jupiter.api.condition.OS
|
||||||
|
import java.io.File
|
||||||
import kotlin.io.path.appendText
|
import kotlin.io.path.appendText
|
||||||
import kotlin.test.assertTrue
|
import kotlin.test.assertTrue
|
||||||
|
import kotlin.test.fail
|
||||||
|
|
||||||
/* Only supported on platforms that support the 'diff' util */
|
|
||||||
@OsCondition(supportedOn = [OS.LINUX, OS.MAC])
|
|
||||||
@MppGradlePluginTests
|
@MppGradlePluginTests
|
||||||
@DisplayName("Multiplatform Build Reproducibility")
|
@DisplayName("Multiplatform Build Reproducibility")
|
||||||
class MPPBuildReproducibilityIT : KGPBaseTest() {
|
class MPPBuildReproducibilityIT : KGPBaseTest() {
|
||||||
@@ -38,6 +38,14 @@ class MPPBuildReproducibilityIT : KGPBaseTest() {
|
|||||||
* - Run the 'diff' tool to ensure that the published artifacts are equal in repo1 & repo2
|
* - Run the 'diff' tool to ensure that the published artifacts are equal in repo1 & repo2
|
||||||
*/
|
*/
|
||||||
private fun TestProject.assertConsecutiveBuildsProduceSameBinaries() {
|
private fun TestProject.assertConsecutiveBuildsProduceSameBinaries() {
|
||||||
|
fun File.relativeToProject() = this.relativeTo(projectPath.toFile())
|
||||||
|
|
||||||
|
fun Diff.reportString(): String = when (this) {
|
||||||
|
is Diff.DifferentContent -> "Different File Contents: ${first.relativeToProject()} <-> ${second.relativeToProject()}"
|
||||||
|
is Diff.MissingFile -> "Missing File: ${file.relativeToProject()}"
|
||||||
|
is Diff.TypeMismatch -> "Expected directory, but is file: ${file.relativeToProject()}"
|
||||||
|
}
|
||||||
|
|
||||||
buildGradleKts.appendText(
|
buildGradleKts.appendText(
|
||||||
"""
|
"""
|
||||||
val repo1 = buildDir.resolve("repo1")
|
val repo1 = buildDir.resolve("repo1")
|
||||||
@@ -49,22 +57,6 @@ private fun TestProject.assertConsecutiveBuildsProduceSameBinaries() {
|
|||||||
maven(repo2) { name = "repo2" }
|
maven(repo2) { name = "repo2" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.register<Exec>("checkBuildConsistency") {
|
|
||||||
doFirst {
|
|
||||||
if (!repo1.exists()) {
|
|
||||||
throw IllegalStateException("Missing repo1")
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!repo2.exists()) {
|
|
||||||
throw IllegalStateException("Missing repo2")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
commandLine(
|
|
||||||
"diff", repo1.absolutePath, repo2.absolutePath, "-r", "-x", "maven-metadata**"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -72,11 +64,72 @@ private fun TestProject.assertConsecutiveBuildsProduceSameBinaries() {
|
|||||||
build("publishAllPublicationsToRepo2Repository", "--rerun-tasks") {
|
build("publishAllPublicationsToRepo2Repository", "--rerun-tasks") {
|
||||||
tasks.forEach { task ->
|
tasks.forEach { task ->
|
||||||
assertTrue(
|
assertTrue(
|
||||||
task.outcome in setOf(TaskOutcome.SUCCESS, TaskOutcome.NO_SOURCE),
|
task.outcome in setOf(TaskOutcome.SUCCESS, TaskOutcome.SKIPPED, TaskOutcome.NO_SOURCE),
|
||||||
"Expected all tasks to be re-executed. Task ${task.path} was ${task.outcome}"
|
"Expected all tasks to be re-executed. Task ${task.path} was ${task.outcome}"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
build("checkBuildConsistency", forceOutput = true)
|
val repo1 = projectPath.resolve("build/repo1").toFile()
|
||||||
|
val repo2 = projectPath.resolve("build/repo2").toFile()
|
||||||
|
|
||||||
|
val diffs = diff(repo1, repo2).filter { diff -> "maven-metadata" !in diff.fileName }
|
||||||
|
if (diffs.isNotEmpty()) {
|
||||||
|
fail(
|
||||||
|
buildString {
|
||||||
|
appendLine("${repo1.relativeToProject()} <-> ${repo2.relativeToProject()} are inconsistent!")
|
||||||
|
diffs.forEach { diff ->
|
||||||
|
appendLine(diff.reportString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class Diff {
|
||||||
|
data class MissingFile(val file: File) : Diff()
|
||||||
|
data class DifferentContent(val first: File, val second: File) : Diff()
|
||||||
|
data class TypeMismatch(val directory: File, val file: File) : Diff()
|
||||||
|
|
||||||
|
val fileName: String
|
||||||
|
get() = when (this) {
|
||||||
|
is DifferentContent -> first.name
|
||||||
|
is MissingFile -> file.name
|
||||||
|
is TypeMismatch -> directory.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun diff(firstRoot: File, secondRoot: File): Set<Diff> {
|
||||||
|
return firstRoot.walkTopDown().flatMap { firstFile ->
|
||||||
|
val secondFile = secondRoot.resolve(firstFile.relativeTo(firstRoot))
|
||||||
|
|
||||||
|
if (!secondFile.exists()) {
|
||||||
|
return@flatMap listOf(Diff.MissingFile(secondFile))
|
||||||
|
}
|
||||||
|
|
||||||
|
/* File is directory */
|
||||||
|
if (firstFile.isDirectory) {
|
||||||
|
if (!secondFile.isDirectory) {
|
||||||
|
return@flatMap listOf(Diff.TypeMismatch(directory = firstFile, file = secondFile))
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if all children in the second directory are also present in firstFile */
|
||||||
|
return@flatMap secondFile.listFiles().orEmpty().mapNotNull { secondFileChild ->
|
||||||
|
val firstFileChild = firstRoot.resolve(secondFileChild.relativeTo(secondRoot))
|
||||||
|
if (!firstFileChild.exists()) Diff.MissingFile(firstFileChild)
|
||||||
|
else null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* File is not a directory */
|
||||||
|
if (firstFile.length() != secondFile.length()) {
|
||||||
|
return@flatMap listOf(Diff.DifferentContent(firstFile, secondFile))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!firstFile.readBytes().contentEquals(secondFile.readBytes())) {
|
||||||
|
return@flatMap listOf(Diff.DifferentContent(firstFile, secondFile))
|
||||||
|
}
|
||||||
|
|
||||||
|
emptyList()
|
||||||
|
}.toSet()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user