Revise incremental compilation failure handling tests
Revise BaseIncrementalCompilationMultiProjectIT's failure handling tests to make it clear we have covered 2 important scenarios: - Failures caused by user errors: testFailureHandling_UserError - Failures caused by tool errors: testFailureHandling_ToolError ^KT-53231 In progress
This commit is contained in:
+2
-2
@@ -335,7 +335,7 @@ class BuildCacheRelocationIT : KGPBaseTest() {
|
|||||||
@GradleTest
|
@GradleTest
|
||||||
fun testKotlinIncrementalCompilation_withGradleClasspathSnapshot(gradleVersion: GradleVersion) {
|
fun testKotlinIncrementalCompilation_withGradleClasspathSnapshot(gradleVersion: GradleVersion) {
|
||||||
checkKotlinIncrementalCompilationAfterCacheHit(gradleVersion, defaultBuildOptions.copy(useGradleClasspathSnapshot = true)) {
|
checkKotlinIncrementalCompilationAfterCacheHit(gradleVersion, defaultBuildOptions.copy(useGradleClasspathSnapshot = true)) {
|
||||||
assertIncrementalCompilation(listOf("src/main/kotlin/foo.kt", "src/main/kotlin/fooUsage.kt"))
|
assertIncrementalCompilation(listOf("src/main/kotlin/foo.kt", "src/main/kotlin/fooUsage.kt").toPaths())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -343,7 +343,7 @@ class BuildCacheRelocationIT : KGPBaseTest() {
|
|||||||
@GradleTest
|
@GradleTest
|
||||||
fun testKotlinIncrementalCompilation_withICClasspathSnapshot(gradleVersion: GradleVersion) {
|
fun testKotlinIncrementalCompilation_withICClasspathSnapshot(gradleVersion: GradleVersion) {
|
||||||
checkKotlinIncrementalCompilationAfterCacheHit(gradleVersion, defaultBuildOptions.copy(useICClasspathSnapshot = true)) {
|
checkKotlinIncrementalCompilationAfterCacheHit(gradleVersion, defaultBuildOptions.copy(useICClasspathSnapshot = true)) {
|
||||||
assertIncrementalCompilation(listOf("src/main/kotlin/foo.kt", "src/main/kotlin/fooUsage.kt"))
|
assertIncrementalCompilation(listOf("src/main/kotlin/foo.kt", "src/main/kotlin/fooUsage.kt").toPaths())
|
||||||
assertOutputContains("Incremental compilation with ABI snapshot enabled")
|
assertOutputContains("Incremental compilation with ABI snapshot enabled")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+62
-84
@@ -2,9 +2,9 @@ package org.jetbrains.kotlin.gradle
|
|||||||
|
|
||||||
import org.gradle.testkit.runner.BuildResult
|
import org.gradle.testkit.runner.BuildResult
|
||||||
import org.gradle.util.GradleVersion
|
import org.gradle.util.GradleVersion
|
||||||
|
import org.jetbrains.kotlin.build.report.metrics.BuildAttribute
|
||||||
import org.jetbrains.kotlin.gradle.testbase.*
|
import org.jetbrains.kotlin.gradle.testbase.*
|
||||||
import org.jetbrains.kotlin.gradle.util.checkedReplace
|
import org.jetbrains.kotlin.gradle.util.checkedReplace
|
||||||
import org.jetbrains.kotlin.test.KtAssert.assertTrue
|
|
||||||
import org.junit.jupiter.api.DisplayName
|
import org.junit.jupiter.api.DisplayName
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import kotlin.io.path.*
|
import kotlin.io.path.*
|
||||||
@@ -38,8 +38,7 @@ class IncrementalCompilationJsMultiProjectIT : BaseIncrementalCompilationMultiPr
|
|||||||
get() = "caches-js"
|
get() = "caches-js"
|
||||||
|
|
||||||
//compileKotlin2Js's modification doe not work
|
//compileKotlin2Js's modification doe not work
|
||||||
override fun testIncrementalBuildWithCompilationError(gradleVersion: GradleVersion) {}
|
override fun testFailureHandling_ToolError(gradleVersion: GradleVersion) {}
|
||||||
override fun testValidOutputsWithCacheCorrupted(gradleVersion: GradleVersion) {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmGradlePluginTests
|
@JvmGradlePluginTests
|
||||||
@@ -502,44 +501,6 @@ abstract class BaseIncrementalCompilationMultiProjectIT : IncrementalCompilation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@DisplayName("compile error in lib project")
|
|
||||||
@GradleTest
|
|
||||||
fun testCompileErrorInLib(gradleVersion: GradleVersion) {
|
|
||||||
defaultProject(gradleVersion) {
|
|
||||||
build("assemble")
|
|
||||||
|
|
||||||
val bKt = subProject("lib").kotlinSourcesDir().resolve("bar/B.kt")
|
|
||||||
val bKtContent = bKt.readText()
|
|
||||||
bKt.deleteExisting()
|
|
||||||
|
|
||||||
fun runFailingBuild() {
|
|
||||||
buildAndFail("assemble") {
|
|
||||||
assertOutputContains("B.kt has been removed")
|
|
||||||
assertTasksFailed(":lib:$compileKotlinTaskName")
|
|
||||||
assertCompiledKotlinSources(
|
|
||||||
getExpectedKotlinSourcesForDefaultProject(
|
|
||||||
libSources = listOf("bar/barUseAB.kt", "bar/barUseB.kt")
|
|
||||||
),
|
|
||||||
output
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
runFailingBuild()
|
|
||||||
runFailingBuild()
|
|
||||||
|
|
||||||
bKt.writeText(bKtContent.replace("fun b", "open fun b"))
|
|
||||||
|
|
||||||
build("assemble") {
|
|
||||||
val expectedSources = getExpectedKotlinSourcesForDefaultProject(
|
|
||||||
libSources = listOf("bar/B.kt", "bar/barUseAB.kt", "bar/barUseB.kt"),
|
|
||||||
appSources = listOf("foo/BB.kt", "foo/fooUseB.kt")
|
|
||||||
)
|
|
||||||
assertCompiledKotlinSources(expectedSources, output)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@DisplayName("Remove library from classpath")
|
@DisplayName("Remove library from classpath")
|
||||||
@GradleTest
|
@GradleTest
|
||||||
fun testRemoveLibFromClasspath(gradleVersion: GradleVersion) {
|
fun testRemoveLibFromClasspath(gradleVersion: GradleVersion) {
|
||||||
@@ -687,63 +648,80 @@ abstract class BaseIncrementalCompilationMultiProjectIT : IncrementalCompilation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@DisplayName("KT-49780: Valid outputs after cache corruption exception")
|
@DisplayName("Test handling of failures caused by user errors")
|
||||||
@GradleTest
|
@GradleTest
|
||||||
open fun testValidOutputsWithCacheCorrupted(gradleVersion: GradleVersion) {
|
fun testFailureHandling_UserError(gradleVersion: GradleVersion) {
|
||||||
defaultProject(gradleVersion) {
|
defaultProject(gradleVersion) {
|
||||||
breakCachesAfterCompileKotlinExecution(this)
|
// Perform the first non-incremental build
|
||||||
|
build(":lib:compileKotlin")
|
||||||
|
|
||||||
build("assemble")
|
// Make a compile error in the source code
|
||||||
|
var classAKtContents: String? = null
|
||||||
subProject("lib").kotlinSourcesDir().resolve("bar/B.kt").modify {
|
subProject("lib").kotlinSourcesDir().resolve("bar/A.kt").modify {
|
||||||
it.replace("fun b() {}", "fun b() = 123")
|
classAKtContents = it
|
||||||
|
it.replace("fun a() {}", "fun a() { // Compile error: Missing closing bracket")
|
||||||
}
|
}
|
||||||
|
|
||||||
build("assemble") {
|
// In the next build, compilation should be incremental and fail, and not fall back to non-incremental compilation
|
||||||
assertOutputContains("Non-incremental compilation will be performed: INCREMENTAL_COMPILATION_FAILED")
|
buildAndFail(":lib:compileKotlin") {
|
||||||
|
assertTasksFailed(":lib:$compileKotlinTaskName")
|
||||||
|
assertOutputContains("Compilation error. See log for more details")
|
||||||
|
assertOutputDoesNotContain("Non-incremental compilation will be performed: ${BuildAttribute.INCREMENTAL_COMPILATION_FAILED.name}")
|
||||||
}
|
}
|
||||||
|
|
||||||
val lookupFile = projectPath.resolve("lib/build/kotlin/${compileKotlinTaskName}/cacheable/${compileCacheFolderName}/lookups/file-to-id.tab")
|
// Fix the compile error in the source code
|
||||||
assertTrue("Output is empty", lookupFile.exists())
|
subProject("lib").kotlinSourcesDir().resolve("bar/A.kt").writeText(classAKtContents!!)
|
||||||
|
changeMethodSignatureInLib()
|
||||||
|
|
||||||
}
|
// In the next build, compilation should be incremental and succeed
|
||||||
}
|
build(":lib:compileKotlin") {
|
||||||
|
assertIncrementalCompilation(
|
||||||
@DisplayName("KT-49780: No need to rebuild invalid code due to cache corruption")
|
expectedCompiledKotlinFiles = getExpectedKotlinSourcesForDefaultProject(
|
||||||
@GradleTest
|
libSources = listOf("bar/A.kt", "bar/B.kt", "bar/barUseA.kt")
|
||||||
open fun testIncrementalBuildWithCompilationError(gradleVersion: GradleVersion) {
|
)
|
||||||
defaultProject(gradleVersion) {
|
)
|
||||||
breakCachesAfterCompileKotlinExecution(this)
|
|
||||||
|
|
||||||
build("assemble")
|
|
||||||
|
|
||||||
subProject("lib").kotlinSourcesDir().resolve("bar/B.kt").modify {
|
|
||||||
it.replace("fun b() {}", "fun a() = 123")
|
|
||||||
}
|
|
||||||
|
|
||||||
buildAndFail("assemble") {
|
|
||||||
printBuildOutput()
|
|
||||||
assertOutputDoesNotContain("Possible caches corruption:")
|
|
||||||
assertOutputDoesNotContain("Non-incremental compilation will be performed:")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun breakCachesAfterCompileKotlinExecution(testProject: TestProject) {
|
@DisplayName("Test handling of failures caused by tool errors")
|
||||||
listOf("app", "lib").forEach {
|
@GradleTest
|
||||||
testProject.subProject(it).buildGradle.appendText(
|
open fun testFailureHandling_ToolError(gradleVersion: GradleVersion) {
|
||||||
"""
|
defaultProject(gradleVersion) {
|
||||||
$compileKotlinTaskName {
|
// Simulate a tool error by registering a doLast that breaks caches in the KotlinCompile task
|
||||||
doLast {
|
val lookupFile =
|
||||||
def file = new File(projectDir.path, "/build/kotlin/${compileKotlinTaskName}/cacheable/${compileCacheFolderName}/lookups/file-to-id.tab")
|
projectPath.resolve("lib/build/kotlin/${compileKotlinTaskName}/cacheable/${compileCacheFolderName}/lookups/file-to-id.tab")
|
||||||
println("Update lookup file " + file.path)
|
breakCachesAfterKotlinCompile(subProject("lib"), lookupFile)
|
||||||
file.write("la-la")
|
|
||||||
}
|
// Perform the first non-incremental build
|
||||||
}
|
build(":lib:compileKotlin") {
|
||||||
""".trimIndent()
|
// Caches should be in a corrupted state, which will ensure the next build will fail
|
||||||
)
|
assertFileContains(lookupFile, "Invalid contents")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make a change in the source code
|
||||||
|
changeMethodSignatureInLib()
|
||||||
|
|
||||||
|
// In the next build, compilation should be incremental and fail, then fall back to non-incremental compilation and succeed
|
||||||
|
build(":lib:compileKotlin") {
|
||||||
|
assertOutputContains("Non-incremental compilation will be performed: ${BuildAttribute.INCREMENTAL_COMPILATION_FAILED.name}")
|
||||||
|
// Also check that the output is not deleted (regression test for KT-49780)
|
||||||
|
assertFileExists(lookupFile)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun breakCachesAfterKotlinCompile(gradleProject: GradleProject, lookupFile: Path) {
|
||||||
|
gradleProject.buildGradle.appendText(
|
||||||
|
"""
|
||||||
|
$compileKotlinTaskName {
|
||||||
|
doLast {
|
||||||
|
new File("$lookupFile").write("Invalid contents")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -101,9 +101,9 @@ fun BuildResult.assertNonIncrementalCompilation() {
|
|||||||
*
|
*
|
||||||
* Note: Log level of output must be set to [LogLevel.DEBUG].
|
* Note: Log level of output must be set to [LogLevel.DEBUG].
|
||||||
*/
|
*/
|
||||||
fun BuildResult.assertIncrementalCompilation(expectedCompiledKotlinFiles: Iterable<String>) {
|
fun BuildResult.assertIncrementalCompilation(expectedCompiledKotlinFiles: Iterable<Path>) {
|
||||||
assertOutputDoesNotContain("Non-incremental compilation will be performed")
|
assertOutputDoesNotContain("Non-incremental compilation will be performed")
|
||||||
|
|
||||||
val actualCompiledKotlinFiles = extractCompiledKotlinFiles(output)
|
val actualCompiledKotlinFiles = extractCompiledKotlinFiles(output)
|
||||||
assertSameFiles(expectedCompiledKotlinFiles.toPaths(), actualCompiledKotlinFiles, "Compiled Kotlin files differ:\n")
|
assertSameFiles(expectedCompiledKotlinFiles, actualCompiledKotlinFiles, "Compiled Kotlin files differ:\n")
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user