KT-34862: Clean up tests for incremental compilation after cache hit
Make sure that:
- Compilation with -Pkotlin.incremental.useClasspathSnapshot=true or
-Dkotlin.incremental.classpath.snapshot.enabled=true is incremental
after cache hit.
- Default compilation (using build history files) is non-incremental
after cache hit.
Also unify the related tests into
BuildCacheRelocationIT.testKotlinIncrementalCompilation*. We don't need
corresponding tests in BuildCacheIT because BuildCacheRelocationIT
already covers it.
This commit is contained in:
committed by
nataliya.valtman
parent
33931bf010
commit
39b7c6e326
@@ -16,7 +16,6 @@ enum class BuildAttributeKind : Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum class BuildAttribute(val kind: BuildAttributeKind, val readableString: String) : Serializable {
|
enum class BuildAttribute(val kind: BuildAttributeKind, val readableString: String) : Serializable {
|
||||||
CACHE_DIRECTORY_NOT_POPULATED(BuildAttributeKind.REBUILD_REASON, "Cache directory not populated"),
|
|
||||||
NO_BUILD_HISTORY(BuildAttributeKind.REBUILD_REASON, "Build history file not found"),
|
NO_BUILD_HISTORY(BuildAttributeKind.REBUILD_REASON, "Build history file not found"),
|
||||||
NO_ABI_SNAPSHOT(BuildAttributeKind.REBUILD_REASON, "ABI snapshot not found"),
|
NO_ABI_SNAPSHOT(BuildAttributeKind.REBUILD_REASON, "ABI snapshot not found"),
|
||||||
CLASSPATH_SNAPSHOT_NOT_FOUND(BuildAttributeKind.REBUILD_REASON, "Classpath snapshot not found"),
|
CLASSPATH_SNAPSHOT_NOT_FOUND(BuildAttributeKind.REBUILD_REASON, "Classpath snapshot not found"),
|
||||||
|
|||||||
+4
-8
@@ -37,19 +37,15 @@ data class BuildInfo(val startTS: Long, val dependencyToAbiSnapshot: Map<String,
|
|||||||
private fun ObjectOutputStream.writeBuildInfo(buildInfo: BuildInfo) {
|
private fun ObjectOutputStream.writeBuildInfo(buildInfo: BuildInfo) {
|
||||||
writeLong(buildInfo.startTS)
|
writeLong(buildInfo.startTS)
|
||||||
writeInt(buildInfo.dependencyToAbiSnapshot.size)
|
writeInt(buildInfo.dependencyToAbiSnapshot.size)
|
||||||
for((identifier, abiSnapshot) in buildInfo.dependencyToAbiSnapshot) {
|
for ((identifier, abiSnapshot) in buildInfo.dependencyToAbiSnapshot) {
|
||||||
writeUTF(identifier)
|
writeUTF(identifier)
|
||||||
writeAbiSnapshot(abiSnapshot)
|
writeAbiSnapshot(abiSnapshot)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun read(file: File): BuildInfo? =
|
fun read(file: File): BuildInfo =
|
||||||
try {
|
ObjectInputStream(FileInputStream(file)).use {
|
||||||
ObjectInputStream(FileInputStream(file)).use {
|
it.readBuildInfo()
|
||||||
it.readBuildInfo()
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun write(buildInfo: BuildInfo, file: File) {
|
fun write(buildInfo: BuildInfo, file: File) {
|
||||||
|
|||||||
+3
-10
@@ -46,7 +46,7 @@ abstract class IncrementalCompilerRunner<
|
|||||||
private val workingDir: File,
|
private val workingDir: File,
|
||||||
cacheDirName: String,
|
cacheDirName: String,
|
||||||
protected val reporter: BuildReporter,
|
protected val reporter: BuildReporter,
|
||||||
private val buildHistoryFile: File,
|
protected val buildHistoryFile: File,
|
||||||
// there might be some additional output directories (e.g. for generated java in kapt)
|
// there might be some additional output directories (e.g. for generated java in kapt)
|
||||||
// to remove them correctly on rebuild, we pass them as additional argument
|
// to remove them correctly on rebuild, we pass them as additional argument
|
||||||
private val additionalOutputFiles: Collection<File> = emptyList()
|
private val additionalOutputFiles: Collection<File> = emptyList()
|
||||||
@@ -129,15 +129,8 @@ abstract class IncrementalCompilerRunner<
|
|||||||
else -> providedChangedFiles
|
else -> providedChangedFiles
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check whether the cache directory is populated (note that it may be deleted upon a Gradle build cache hit if the directory is
|
@Suppress("MoveVariableDeclarationIntoWhen")
|
||||||
// marked as @LocalState in the Gradle task).
|
val compilationMode = sourcesToCompile(caches, changedFiles, args, messageCollector, classpathAbiSnapshot)
|
||||||
val cacheDirectoryNotPopulated = cacheDirectory.walk().none { it.isFile }
|
|
||||||
|
|
||||||
val compilationMode = if (cacheDirectoryNotPopulated) {
|
|
||||||
CompilationMode.Rebuild(BuildAttribute.CACHE_DIRECTORY_NOT_POPULATED)
|
|
||||||
} else {
|
|
||||||
sourcesToCompile(caches, changedFiles, args, messageCollector, classpathAbiSnapshot)
|
|
||||||
}
|
|
||||||
|
|
||||||
val exitCode = when (compilationMode) {
|
val exitCode = when (compilationMode) {
|
||||||
is CompilationMode.Incremental -> {
|
is CompilationMode.Incremental -> {
|
||||||
|
|||||||
+3
-1
@@ -118,8 +118,10 @@ class IncrementalJsCompilerRunner(
|
|||||||
messageCollector: MessageCollector,
|
messageCollector: MessageCollector,
|
||||||
classpathAbiSnapshots: Map<String, AbiSnapshot> //Ignore for now
|
classpathAbiSnapshots: Map<String, AbiSnapshot> //Ignore for now
|
||||||
): CompilationMode {
|
): CompilationMode {
|
||||||
|
if (!withSnapshot && !buildHistoryFile.isFile) {
|
||||||
|
return CompilationMode.Rebuild(BuildAttribute.NO_BUILD_HISTORY)
|
||||||
|
}
|
||||||
val lastBuildInfo = BuildInfo.read(lastBuildInfoFile)
|
val lastBuildInfo = BuildInfo.read(lastBuildInfoFile)
|
||||||
?: return CompilationMode.Rebuild(BuildAttribute.NO_BUILD_HISTORY)
|
|
||||||
|
|
||||||
val dirtyFiles = DirtyFilesContainer(caches, reporter, kotlinSourceFilesExtensions)
|
val dirtyFiles = DirtyFilesContainer(caches, reporter, kotlinSourceFilesExtensions)
|
||||||
initDirtyFiles(dirtyFiles, changedFiles)
|
initDirtyFiles(dirtyFiles, changedFiles)
|
||||||
|
|||||||
+8
-1
@@ -256,7 +256,14 @@ class IncrementalJvmCompilerRunner(
|
|||||||
is NotAvailableDueToMissingClasspathSnapshot -> ChangesEither.Unknown(BuildAttribute.CLASSPATH_SNAPSHOT_NOT_FOUND)
|
is NotAvailableDueToMissingClasspathSnapshot -> ChangesEither.Unknown(BuildAttribute.CLASSPATH_SNAPSHOT_NOT_FOUND)
|
||||||
is NotAvailableForNonIncrementalRun -> ChangesEither.Unknown(BuildAttribute.UNKNOWN_CHANGES_IN_GRADLE_INPUTS)
|
is NotAvailableForNonIncrementalRun -> ChangesEither.Unknown(BuildAttribute.UNKNOWN_CHANGES_IN_GRADLE_INPUTS)
|
||||||
is ClasspathSnapshotDisabled -> reporter.measure(BuildTime.IC_ANALYZE_CHANGES_IN_DEPENDENCIES) {
|
is ClasspathSnapshotDisabled -> reporter.measure(BuildTime.IC_ANALYZE_CHANGES_IN_DEPENDENCIES) {
|
||||||
val lastBuildInfo = BuildInfo.read(lastBuildInfoFile) ?: return CompilationMode.Rebuild(BuildAttribute.NO_BUILD_HISTORY)
|
if (!withSnapshot && !buildHistoryFile.isFile) {
|
||||||
|
// If the previous build was a Gradle cache hit, the build history file must have been deleted as it is marked as
|
||||||
|
// @LocalState in the Gradle task. Therefore, this compilation will need to run non-incrementally.
|
||||||
|
// (Note that buildHistoryFile is outside workingDir. We don't need to perform the same check for files inside
|
||||||
|
// workingDir as workingDir is an @OutputDirectory, so the files must be present in an incremental build.)
|
||||||
|
return CompilationMode.Rebuild(BuildAttribute.NO_BUILD_HISTORY)
|
||||||
|
}
|
||||||
|
val lastBuildInfo = BuildInfo.read(lastBuildInfoFile)
|
||||||
reporter.reportVerbose { "Last Kotlin Build info -- $lastBuildInfo" }
|
reporter.reportVerbose { "Last Kotlin Build info -- $lastBuildInfo" }
|
||||||
val scopes = caches.lookupCache.lookupSymbols.map { it.scope.ifBlank { it.name } }.distinct()
|
val scopes = caches.lookupCache.lookupSymbols.map { it.scope.ifBlank { it.name } }.distinct()
|
||||||
|
|
||||||
|
|||||||
+23
-10
@@ -22,7 +22,6 @@ 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 kotlin.io.path.createDirectory
|
import kotlin.io.path.createDirectory
|
||||||
import kotlin.io.path.pathString
|
|
||||||
|
|
||||||
@DisplayName("Build cache relocation")
|
@DisplayName("Build cache relocation")
|
||||||
@SimpleGradlePluginTests
|
@SimpleGradlePluginTests
|
||||||
@@ -328,12 +327,25 @@ class BuildCacheRelocationIT : KGPBaseTest() {
|
|||||||
|
|
||||||
@DisplayName("Kotlin incremental compilation with `kotlin.incremental.useClasspathSnapshot` feature should work correctly")
|
@DisplayName("Kotlin incremental compilation with `kotlin.incremental.useClasspathSnapshot` feature should work correctly")
|
||||||
@GradleTest
|
@GradleTest
|
||||||
fun testKotlinIncrementalCompilation_withClasspathSnapshot(gradleVersion: GradleVersion) {
|
fun testKotlinIncrementalCompilation_withGradleClasspathSnapshot(gradleVersion: GradleVersion) {
|
||||||
checkKotlinIncrementalCompilation(gradleVersion, useClasspathSnapshot = true)
|
checkKotlinIncrementalCompilation(gradleVersion, useGradleClasspathSnapshot = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkKotlinIncrementalCompilation(gradleVersion: GradleVersion, useClasspathSnapshot: Boolean? = null) {
|
@DisplayName("Kotlin incremental compilation with `kotlin.incremental.classpath.snapshot.enabled` feature should work correctly")
|
||||||
val buildOptions = defaultBuildOptions.copy(useClasspathSnapshot = useClasspathSnapshot)
|
@GradleTest
|
||||||
|
fun testKotlinIncrementalCompilation_withICClasspathSnapshot(gradleVersion: GradleVersion) {
|
||||||
|
checkKotlinIncrementalCompilation(gradleVersion, useICClasspathSnapshot = true)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkKotlinIncrementalCompilation(
|
||||||
|
gradleVersion: GradleVersion,
|
||||||
|
useGradleClasspathSnapshot: Boolean? = null,
|
||||||
|
useICClasspathSnapshot: Boolean? = null
|
||||||
|
) {
|
||||||
|
val buildOptions = defaultBuildOptions.copy(
|
||||||
|
useGradleClasspathSnapshot = useGradleClasspathSnapshot,
|
||||||
|
useICClasspathSnapshot = useICClasspathSnapshot
|
||||||
|
)
|
||||||
val (firstProject, secondProject) = prepareTestProjects("buildCacheSimple", gradleVersion, buildOptions)
|
val (firstProject, secondProject) = prepareTestProjects("buildCacheSimple", gradleVersion, buildOptions)
|
||||||
|
|
||||||
// First build, should be stored into the build cache:
|
// First build, should be stored into the build cache:
|
||||||
@@ -346,14 +358,15 @@ class BuildCacheRelocationIT : KGPBaseTest() {
|
|||||||
assertTasksFromCache(":compileKotlin")
|
assertTasksFromCache(":compileKotlin")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Change the return type of foo() from Int to String in foo.kt, and check that fooUsage.kt is recompiled as well:
|
// Check whether compilation after a cache hit is incremental (KT-34862)
|
||||||
val fooKtSourceFile = secondProject.kotlinSourcesDir().resolve("foo.kt")
|
val fooKtSourceFile = secondProject.kotlinSourcesDir().resolve("foo.kt")
|
||||||
val fooUsageKtSourceFile = secondProject.kotlinSourcesDir().resolve("fooUsage.kt")
|
|
||||||
fooKtSourceFile.modify { it.replace("Int = 1", "String = \"abc\"") }
|
fooKtSourceFile.modify { it.replace("Int = 1", "String = \"abc\"") }
|
||||||
secondProject.build("assemble", buildOptions = buildOptions.copy(logLevel = LogLevel.DEBUG)) {
|
secondProject.build("assemble", buildOptions = buildOptions.copy(logLevel = LogLevel.DEBUG)) {
|
||||||
assertIncrementalCompilation(
|
if (useGradleClasspathSnapshot == true || useICClasspathSnapshot == true) {
|
||||||
listOf(fooKtSourceFile, fooUsageKtSourceFile).relativizeTo(secondProject.projectPath).map { it.pathString }
|
assertIncrementalCompilation(listOf("src/main/kotlin/foo.kt", "src/main/kotlin/fooUsage.kt"))
|
||||||
)
|
} else {
|
||||||
|
assertNonIncrementalCompilation()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Revert the change to the return type of foo(), and check if we get a cache hit
|
// Revert the change to the return type of foo(), and check if we get a cache hit
|
||||||
|
|||||||
+5
-2
@@ -9,6 +9,7 @@ import org.gradle.api.logging.LogLevel
|
|||||||
import org.gradle.api.logging.configuration.WarningMode
|
import org.gradle.api.logging.configuration.WarningMode
|
||||||
import org.gradle.util.GradleVersion
|
import org.gradle.util.GradleVersion
|
||||||
import org.jetbrains.kotlin.cli.common.CompilerSystemProperties.COMPILE_INCREMENTAL_WITH_ARTIFACT_TRANSFORM
|
import org.jetbrains.kotlin.cli.common.CompilerSystemProperties.COMPILE_INCREMENTAL_WITH_ARTIFACT_TRANSFORM
|
||||||
|
import org.jetbrains.kotlin.cli.common.CompilerSystemProperties.COMPILE_INCREMENTAL_WITH_CLASSPATH_SNAPSHOTS
|
||||||
import org.jetbrains.kotlin.gradle.BaseGradleIT
|
import org.jetbrains.kotlin.gradle.BaseGradleIT
|
||||||
import org.jetbrains.kotlin.gradle.plugin.KotlinJsCompilerType
|
import org.jetbrains.kotlin.gradle.plugin.KotlinJsCompilerType
|
||||||
import org.jetbrains.kotlin.gradle.report.BuildReportType
|
import org.jetbrains.kotlin.gradle.report.BuildReportType
|
||||||
@@ -22,7 +23,8 @@ data class BuildOptions(
|
|||||||
val configurationCacheProblems: BaseGradleIT.ConfigurationCacheProblems = BaseGradleIT.ConfigurationCacheProblems.FAIL,
|
val configurationCacheProblems: BaseGradleIT.ConfigurationCacheProblems = BaseGradleIT.ConfigurationCacheProblems.FAIL,
|
||||||
val parallel: Boolean = true,
|
val parallel: Boolean = true,
|
||||||
val incremental: Boolean? = null,
|
val incremental: Boolean? = null,
|
||||||
val useClasspathSnapshot: Boolean? = null,
|
val useGradleClasspathSnapshot: Boolean? = null,
|
||||||
|
val useICClasspathSnapshot: Boolean? = null,
|
||||||
val maxWorkers: Int = (Runtime.getRuntime().availableProcessors() / 4 - 1).coerceAtLeast(2),
|
val maxWorkers: Int = (Runtime.getRuntime().availableProcessors() / 4 - 1).coerceAtLeast(2),
|
||||||
val fileSystemWatchEnabled: Boolean = false,
|
val fileSystemWatchEnabled: Boolean = false,
|
||||||
val buildCacheEnabled: Boolean = false,
|
val buildCacheEnabled: Boolean = false,
|
||||||
@@ -83,7 +85,8 @@ data class BuildOptions(
|
|||||||
arguments.add("-Pkotlin.incremental=$incremental")
|
arguments.add("-Pkotlin.incremental=$incremental")
|
||||||
}
|
}
|
||||||
|
|
||||||
useClasspathSnapshot?.let { arguments.add("-P${COMPILE_INCREMENTAL_WITH_ARTIFACT_TRANSFORM.property}=$it") }
|
useGradleClasspathSnapshot?.let { arguments.add("-P${COMPILE_INCREMENTAL_WITH_ARTIFACT_TRANSFORM.property}=$it") }
|
||||||
|
useICClasspathSnapshot?.let { arguments.add("-D${COMPILE_INCREMENTAL_WITH_CLASSPATH_SNAPSHOTS.property}=$it") }
|
||||||
|
|
||||||
if (gradleVersion >= GradleVersion.version("6.5")) {
|
if (gradleVersion >= GradleVersion.version("6.5")) {
|
||||||
if (fileSystemWatchEnabled) {
|
if (fileSystemWatchEnabled) {
|
||||||
|
|||||||
+10
@@ -84,6 +84,16 @@ fun assertCompiledKotlinSources(
|
|||||||
assertSameFiles(expectedSources, actualSources, "Compiled Kotlin files differ${errorMessageSuffix}:\n")
|
assertSameFiles(expectedSources, actualSources, "Compiled Kotlin files differ${errorMessageSuffix}:\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asserts that compilation was non-incremental.
|
||||||
|
*
|
||||||
|
* Note: Log level of output must be set to [LogLevel.DEBUG].
|
||||||
|
*/
|
||||||
|
@Suppress("unused")
|
||||||
|
fun BuildResult.assertNonIncrementalCompilation() {
|
||||||
|
assertOutputContains("Non-incremental compilation will be performed")
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Asserts that compilation was incremental and the set of compiled .kt files exactly match [expectedCompiledKotlinFiles].
|
* Asserts that compilation was incremental and the set of compiled .kt files exactly match [expectedCompiledKotlinFiles].
|
||||||
*
|
*
|
||||||
|
|||||||
Reference in New Issue
Block a user