[Gradle] Add integration tests for JVM compilation via the Build Tools API

This commit is contained in:
Alexander.Likhachev
2023-06-26 19:29:20 +02:00
committed by Space Team
parent 419381af7f
commit 754f4830b9
6 changed files with 129 additions and 18 deletions
@@ -0,0 +1,85 @@
/*
* Copyright 2010-2023 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
import org.gradle.testkit.runner.BuildResult
import org.gradle.util.GradleVersion
import org.jetbrains.kotlin.gradle.internals.asFinishLogMessage
import org.jetbrains.kotlin.gradle.testbase.*
import org.jetbrains.kotlin.gradle.tasks.KotlinCompilerExecutionStrategy
import org.jetbrains.kotlin.gradle.tasks.USING_JVM_INCREMENTAL_COMPILATION_MESSAGE
import org.junit.jupiter.api.Disabled
import org.junit.jupiter.api.DisplayName
@DisplayName("JVM compilation via the Build Tools API")
@JvmGradlePluginTests
class BuildToolsApiJvmCompilationIT : KGPBaseTest() {
override val defaultBuildOptions = super.defaultBuildOptions.copy(runViaBuildToolsApi = true)
@GradleTest
@Disabled
@DisplayName("Simple project non-incremental in-process compilation")
fun compileJvmInProcessNonIncremental(gradleVersion: GradleVersion) = testSimpleProject(
gradleVersion, defaultBuildOptions.copy(
compilerExecutionStrategy = KotlinCompilerExecutionStrategy.IN_PROCESS,
incremental = false,
)
) {
assertOutputContains(KotlinCompilerExecutionStrategy.IN_PROCESS.asFinishLogMessage)
assertOutputDoesNotContain(USING_JVM_INCREMENTAL_COMPILATION_MESSAGE)
}
@GradleTest
@Disabled
@DisplayName("Simple project incremental in-process compilation")
fun compileJvmInProcessIncremental(gradleVersion: GradleVersion) = testSimpleProject(
gradleVersion, defaultBuildOptions.copy(
compilerExecutionStrategy = KotlinCompilerExecutionStrategy.IN_PROCESS,
incremental = false,
)
) {
assertOutputContains(KotlinCompilerExecutionStrategy.IN_PROCESS.asFinishLogMessage)
assertOutputContains(USING_JVM_INCREMENTAL_COMPILATION_MESSAGE)
}
@GradleTest
@Disabled
@DisplayName("Simple project non-incremental compilation within the daemon")
fun compileJvmNonIncrementalWithinDaemon(gradleVersion: GradleVersion) = testSimpleProject(
gradleVersion, defaultBuildOptions.copy(
compilerExecutionStrategy = KotlinCompilerExecutionStrategy.DAEMON,
incremental = false,
)
) {
assertOutputContains(KotlinCompilerExecutionStrategy.DAEMON.asFinishLogMessage)
assertOutputDoesNotContain(USING_JVM_INCREMENTAL_COMPILATION_MESSAGE)
}
@GradleTest
@Disabled
@DisplayName("Simple project incremental compilation within the daemon")
fun compileJvmIncrementalWithinDaemon(gradleVersion: GradleVersion) = testSimpleProject(
gradleVersion, defaultBuildOptions.copy(
compilerExecutionStrategy = KotlinCompilerExecutionStrategy.DAEMON,
incremental = true,
)
) {
assertOutputContains(KotlinCompilerExecutionStrategy.DAEMON.asFinishLogMessage)
assertOutputContains(USING_JVM_INCREMENTAL_COMPILATION_MESSAGE)
}
private fun testSimpleProject(gradleVersion: GradleVersion, buildOptions: BuildOptions, assertions: BuildResult.() -> Unit) {
project("simpleProject", gradleVersion, buildOptions = buildOptions) {
build("assemble", "compileDeployKotlin") {
assertFileExists(kotlinClassesDir("main").resolve("demo/KotlinGreetingJoiner.class"))
assertFileExists(javaClassesDir("main").resolve("demo/Greeter.class"))
assertFileExists(javaClassesDir("main").resolve("demo/HelloWorld.class"))
assertFileExists(kotlinClassesDir("deploy").resolve("demo/ExampleSource.class"))
assertions()
}
}
}
}
@@ -3,6 +3,7 @@ package org.jetbrains.kotlin.gradle
import org.gradle.api.logging.LogLevel
import org.gradle.testkit.runner.BuildResult
import org.gradle.util.GradleVersion
import org.jetbrains.kotlin.gradle.internals.asFinishLogMessage
import org.jetbrains.kotlin.gradle.tasks.KotlinCompilerExecutionStrategy
import org.jetbrains.kotlin.gradle.testbase.*
import org.jetbrains.kotlin.gradle.util.checkedReplace
@@ -99,15 +100,17 @@ abstract class ExecutionStrategyIT : KGPDaemonsBaseTest() {
project(
projectName = "kotlinBuiltins",
gradleVersion = gradleVersion,
addHeapDumpOptions = false
addHeapDumpOptions = false,
buildOptions = defaultBuildOptions.copy(
useDaemonFallbackStrategy = false,
compilerExecutionStrategy = KotlinCompilerExecutionStrategy.DAEMON,
)
) {
setupProject(this)
buildAndFail(
"build",
"-Pkotlin.compiler.execution.strategy=${KotlinCompilerExecutionStrategy.DAEMON}",
"-Pkotlin.daemon.jvmargs=-Xmxqwerty",
"-Pkotlin.daemon.useFallbackStrategy=false"
) {
assertOutputContains("Failed to compile with Kotlin daemon. Fallback strategy (compiling without Kotlin daemon) is turned off.")
}
@@ -200,26 +203,28 @@ abstract class ExecutionStrategyIT : KGPDaemonsBaseTest() {
projectName = "kotlinBuiltins",
gradleVersion = gradleVersion,
addHeapDumpOptions = addHeapDumpOptions,
buildOptions = defaultBuildOptions.copy(useDaemonFallbackStrategy = testFallbackStrategy)
buildOptions = defaultBuildOptions.copy(
useDaemonFallbackStrategy = testFallbackStrategy,
compilerExecutionStrategy = if (shouldConfigureStrategyViaGradleProperty) {
executionStrategy
} else {
null
}
)
) {
setupProject(this)
additionalProjectConfiguration()
@OptIn(ExperimentalStdlibApi::class)
val args = buildList {
if (shouldConfigureStrategyViaGradleProperty) {
add("-Pkotlin.compiler.execution.strategy=${executionStrategy.propertyValue}")
}
if (testFallbackStrategy) {
// add jvm option that JVM fails to parse
add("-Pkotlin.daemon.jvmargs=-Xmxqwerty")
}
}.toTypedArray()
val args = if (testFallbackStrategy) {
arrayOf("-Pkotlin.daemon.jvmargs=-Xmxqwerty")
} else {
emptyArray()
}
val expectedFinishStrategy = if (testFallbackStrategy) KotlinCompilerExecutionStrategy.OUT_OF_PROCESS else executionStrategy
val finishMessage = "Finished executing kotlin compiler using $expectedFinishStrategy strategy"
val finishMessage = expectedFinishStrategy.asFinishLogMessage
build("build", *args) {
assertOutputContains(finishMessage)
assertOutputContains(expectedFinishStrategy.asFinishLogMessage)
checkOutput(this@project)
assertNoBuildWarnings()
@@ -880,7 +880,9 @@ abstract class BaseIncrementalCompilationMultiProjectIT : IncrementalCompilation
// Perform the first non-incremental build without using Kotlin daemon so that incremental state is not produced
build(
":lib:compileKotlin",
"-Pkotlin.compiler.execution.strategy=${KotlinCompilerExecutionStrategy.IN_PROCESS.propertyValue}"
buildOptions = defaultBuildOptions.copy(
compilerExecutionStrategy = KotlinCompilerExecutionStrategy.IN_PROCESS,
),
) {
projectPath.resolve("lib/build/kotlin/${compileKotlinTaskName}/classpath-snapshot").let {
assert(!it.exists() || it.listDirectoryEntries().isEmpty())
@@ -11,6 +11,7 @@ import org.gradle.util.GradleVersion
import org.jetbrains.kotlin.cli.common.CompilerSystemProperties.COMPILE_INCREMENTAL_WITH_ARTIFACT_TRANSFORM
import org.jetbrains.kotlin.gradle.BaseGradleIT
import org.jetbrains.kotlin.gradle.dsl.NativeCacheKind
import org.jetbrains.kotlin.gradle.tasks.KotlinCompilerExecutionStrategy
import org.jetbrains.kotlin.gradle.report.BuildReportType
import org.junit.jupiter.api.condition.OS
import java.util.*
@@ -44,6 +45,8 @@ data class BuildOptions(
val useDaemonFallbackStrategy: Boolean = false,
val verboseDiagnostics: Boolean = true,
val nativeOptions: NativeOptions = NativeOptions(),
val compilerExecutionStrategy: KotlinCompilerExecutionStrategy? = null,
val runViaBuildToolsApi: Boolean? = null,
) {
val safeAndroidVersion: String
get() = androidVersion ?: error("AGP version is expected to be set")
@@ -176,6 +179,14 @@ data class BuildOptions(
arguments.add("-Pkotlin.internal.verboseDiagnostics=$verboseDiagnostics")
}
if (compilerExecutionStrategy != null) {
arguments.add("-Pkotlin.compiler.execution.strategy=${compilerExecutionStrategy.propertyValue}")
}
if (runViaBuildToolsApi != null) {
arguments.add("-Pkotlin.compiler.runViaBuildToolsApi=$runViaBuildToolsApi")
}
arguments.addAll(freeArgs)
return arguments.toList()
@@ -227,8 +227,11 @@ private fun createLoggingMessageCollector(log: KotlinLogger): MessageCollector =
}
}
internal val KotlinCompilerExecutionStrategy.asFinishLogMessage: String
get() = "Finished executing kotlin compiler using $this strategy"
internal fun KotlinLogger.logFinish(strategy: KotlinCompilerExecutionStrategy) {
debug("Finished executing kotlin compiler using $strategy strategy")
debug(strategy.asFinishLogMessage)
}
internal fun exitCodeFromProcessExitCode(log: KotlinLogger, code: Int): ExitCode {
@@ -5,11 +5,13 @@
package org.jetbrains.kotlin.gradle.internals
import org.jetbrains.kotlin.compilerRunner.asFinishLogMessage
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_NATIVE_IGNORE_DISABLED_TARGETS
import org.jetbrains.kotlin.gradle.plugin.diagnostics.DIAGNOSTIC_SEPARATOR
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinProjectStructureMetadata
import org.jetbrains.kotlin.gradle.plugin.mpp.MULTIPLATFORM_PROJECT_METADATA_JSON_FILE_NAME
import org.jetbrains.kotlin.gradle.plugin.mpp.parseKotlinSourceSetMetadataFromJson
import org.jetbrains.kotlin.gradle.tasks.KotlinCompilerExecutionStrategy
fun parseKotlinSourceSetMetadataFromJson(json: String): KotlinProjectStructureMetadata = parseKotlinSourceSetMetadataFromJson(json)
@@ -18,3 +20,6 @@ const val MULTIPLATFORM_PROJECT_METADATA_JSON_FILE_NAME = MULTIPLATFORM_PROJECT_
const val KOTLIN_NATIVE_IGNORE_DISABLED_TARGETS_PROPERTY = KOTLIN_NATIVE_IGNORE_DISABLED_TARGETS
const val VERBOSE_DIAGNOSTIC_SEPARATOR = DIAGNOSTIC_SEPARATOR
val KotlinCompilerExecutionStrategy.asFinishLogMessage: String
get() = this.asFinishLogMessage