From 754f4830b900695563773456a336c117251f00c8 Mon Sep 17 00:00:00 2001 From: "Alexander.Likhachev" Date: Mon, 26 Jun 2023 19:29:20 +0200 Subject: [PATCH] [Gradle] Add integration tests for JVM compilation via the Build Tools API --- .../gradle/BuildToolsApiJvmCompilationIT.kt | 85 +++++++++++++++++++ .../kotlin/gradle/ExecutionStrategyIT.kt | 37 ++++---- .../IncrementalCompilationMultiProjectIT.kt | 4 +- .../kotlin/gradle/testbase/BuildOptions.kt | 11 +++ .../kotlin/compilerRunner/reportUtils.kt | 5 +- .../internals/ExposedForIntegrationTests.kt | 5 ++ 6 files changed, 129 insertions(+), 18 deletions(-) create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/BuildToolsApiJvmCompilationIT.kt diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/BuildToolsApiJvmCompilationIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/BuildToolsApiJvmCompilationIT.kt new file mode 100644 index 00000000000..581fc80b2ad --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/BuildToolsApiJvmCompilationIT.kt @@ -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() + } + } + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/ExecutionStrategyIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/ExecutionStrategyIT.kt index 9fdf585fbee..d736fb02e28 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/ExecutionStrategyIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/ExecutionStrategyIT.kt @@ -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() diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/IncrementalCompilationMultiProjectIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/IncrementalCompilationMultiProjectIT.kt index 4ec8dae6ae8..a260844448d 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/IncrementalCompilationMultiProjectIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/IncrementalCompilationMultiProjectIT.kt @@ -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()) diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/testbase/BuildOptions.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/testbase/BuildOptions.kt index f124ade0322..f4816b16494 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/testbase/BuildOptions.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/testbase/BuildOptions.kt @@ -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() diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/compilerRunner/reportUtils.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/compilerRunner/reportUtils.kt index 8d3509bb762..0cdc0f167e7 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/compilerRunner/reportUtils.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/compilerRunner/reportUtils.kt @@ -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 { diff --git a/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/internals/ExposedForIntegrationTests.kt b/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/internals/ExposedForIntegrationTests.kt index 3768a902baf..ed32d2dbd32 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/internals/ExposedForIntegrationTests.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/internals/ExposedForIntegrationTests.kt @@ -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 \ No newline at end of file