From 432c6486d558330abd27a335fb71b0b21a69acf3 Mon Sep 17 00:00:00 2001 From: Alexander Likhachev Date: Wed, 27 Jan 2021 10:18:08 +0300 Subject: [PATCH] [Gradle] Make KotlinTest, KotlinTestReport partially cc-compatible --- .../gradle/targets/js/testing/KotlinJsTest.kt | 35 +++++--- .../targets/js/testing/karma/KotlinKarma.kt | 20 +++-- .../targets/js/testing/mocha/KotlinMocha.kt | 11 ++- .../kotlin/gradle/tasks/KotlinTest.kt | 6 +- .../testing/internal/KotlinTestReport.kt | 81 ++++++++++++------- 5 files changed, 96 insertions(+), 57 deletions(-) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/testing/KotlinJsTest.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/testing/KotlinJsTest.kt index a3a349a404b..4502ccf7422 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/testing/KotlinJsTest.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/testing/KotlinJsTest.kt @@ -29,11 +29,14 @@ import javax.inject.Inject open class KotlinJsTest @Inject constructor( - @Internal override var compilation: KotlinJsCompilation + @Transient + @Internal + override var compilation: KotlinJsCompilation ) : KotlinTest(), RequiresNpmDependencies { - private val nodeJs get() = NodeJsRootPlugin.apply(project.rootProject) + private val nodeJs= NodeJsRootPlugin.apply(project.rootProject) + private val npmProject = compilation.npmProject private val projectPath = project.path @@ -69,22 +72,30 @@ constructor( var debug: Boolean = false @Suppress("unused") - val runtimeClasspath: FileCollection - @InputFiles get() = compilation.runtimeDependencyFiles + @get:InputFiles + val runtimeClasspath: FileCollection by lazy { + compilation.runtimeDependencyFiles + } @Suppress("unused") - internal val compilationOutputs: FileCollection - @InputFiles get() = compilation.output.allOutputs + @get:InputFiles + internal val compilationOutputs: FileCollection by lazy { + compilation.output.allOutputs + } @Suppress("unused") - val compilationId: String - @Input get() = compilation.let { + @get:Input + val compilationId: String by lazy { + compilation.let { val target = it.target target.project.path + "@" + target.name + ":" + it.compilationName } + } - val nodeModulesToLoad: List - @Internal get() = listOf("./" + compilation.npmProject.main) + @get:Internal + val nodeModulesToLoad: List by lazy { + listOf("./" + compilation.npmProject.main) + } override val nodeModulesRequired: Boolean @Internal get() = testFramework!!.nodeModulesRequired @@ -115,7 +126,7 @@ constructor( fun useKarma() = useKarma {} fun useKarma(body: KotlinKarma.() -> Unit) = use( - KotlinKarma(compilation, services, path), + KotlinKarma(compilation, { services }, path), body ) fun useKarma(fn: Closure<*>) { @@ -142,7 +153,7 @@ constructor( override fun createTestExecutionSpec(): TCServiceMessagesTestExecutionSpec { val forkOptions = DefaultProcessForkOptions(fileResolver) - forkOptions.workingDir = compilation.npmProject.dir + forkOptions.workingDir = npmProject.dir forkOptions.executable = nodeJs.requireConfigured().nodeExecutable val nodeJsArgs = mutableListOf() diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/testing/karma/KotlinKarma.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/testing/karma/KotlinKarma.kt index de650c15281..1f42f106096 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/testing/karma/KotlinKarma.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/testing/karma/KotlinKarma.kt @@ -36,9 +36,15 @@ import org.jetbrains.kotlin.gradle.utils.property import org.slf4j.Logger import java.io.File -class KotlinKarma(override val compilation: KotlinJsCompilation, private val services: ServiceRegistry, private val basePath: String) : +class KotlinKarma( + @Transient override val compilation: KotlinJsCompilation, + private val services: () -> ServiceRegistry, + private val basePath: String +) : KotlinJsTestFramework { + @Transient private val project: Project = compilation.target.project + private val npmProject = compilation.npmProject private val nodeJs = NodeJsRootPlugin.apply(project.rootProject) private val versions = nodeJs.versions @@ -49,9 +55,11 @@ class KotlinKarma(override val compilation: KotlinJsCompilation, private val ser private val envJsCollector = mutableMapOf() private val confJsWriters = mutableListOf<(Appendable) -> Unit>() private var sourceMaps = false + private val defaultConfigDirectory = project.projectDir.resolve("karma.config.d") private var configDirectory: File by property { - project.projectDir.resolve("karma.config.d") + defaultConfigDirectory } + private val isTeamCity = project.hasProperty(TC_PROJECT_PROPERTY) override val requiredNpmDependencies: Set get() = requiredDependencies + webpackConfig.getRequiredDependencies(versions) @@ -277,8 +285,6 @@ class KotlinKarma(override val compilation: KotlinJsCompilation, private val ser file: String, debug: Boolean ): File { - val npmProject = compilation.npmProject - val adapterJs = npmProject.dir.resolve("adapter-browser.js") adapterJs.printWriter().use { writer -> val karmaRunner = npmProject.require("kotlin-test-js-runner/kotlin-test-karma-runner.js") @@ -301,8 +307,6 @@ class KotlinKarma(override val compilation: KotlinJsCompilation, private val ser nodeJsArgs: MutableList, debug: Boolean ): TCServiceMessagesTestExecutionSpec { - val npmProject = compilation.npmProject - val file = task.nodeModulesToLoad .map { npmProject.require(it) } .single() @@ -341,7 +345,7 @@ class KotlinKarma(override val compilation: KotlinJsCompilation, private val ser prependSuiteName = true, stackTraceParser = ::parseNodeJsStackTraceAsJvm, ignoreOutOfRootNodes = true, - escapeTCMessagesInLog = project.hasProperty(TC_PROJECT_PROPERTY) + escapeTCMessagesInLog = isTeamCity ) config.basePath = npmProject.nodeModulesDir.absolutePath @@ -407,7 +411,7 @@ class KotlinKarma(override val compilation: KotlinJsCompilation, private val ser lateinit var progressLogger: ProgressLogger override fun wrapExecute(body: () -> Unit) { - services.operation("Running and building tests with karma and webpack") { + services().operation("Running and building tests with karma and webpack") { progressLogger = this body() } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/testing/mocha/KotlinMocha.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/testing/mocha/KotlinMocha.kt index a7ce5bc181e..3d53107cb6a 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/testing/mocha/KotlinMocha.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/testing/mocha/KotlinMocha.kt @@ -21,11 +21,14 @@ import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTestFramework import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinTestRunnerCliArgs import java.io.File -class KotlinMocha(override val compilation: KotlinJsCompilation, private val basePath: String) : +class KotlinMocha(@Transient override val compilation: KotlinJsCompilation, private val basePath: String) : KotlinJsTestFramework { + @Transient private val project: Project = compilation.target.project + private val npmProject = compilation.npmProject private val nodeJs = NodeJsRootPlugin.apply(project.rootProject) private val versions = nodeJs.versions + private val isTeamCity = project.hasProperty(TC_PROJECT_PROPERTY) override val settingsState: String get() = "mocha" @@ -54,11 +57,9 @@ class KotlinMocha(override val compilation: KotlinJsCompilation, private val bas prependSuiteName = true, stackTraceParser = ::parseNodeJsStackTraceAsJvm, ignoreOutOfRootNodes = true, - escapeTCMessagesInLog = project.hasProperty(TC_PROJECT_PROPERTY) + escapeTCMessagesInLog = isTeamCity ) - val npmProject = compilation.npmProject - val cliArgs = KotlinTestRunnerCliArgs( include = task.includePatterns, exclude = task.excludePatterns @@ -105,8 +106,6 @@ class KotlinMocha(override val compilation: KotlinJsCompilation, private val bas private fun createAdapterJs( file: String ): File { - val npmProject = compilation.npmProject - val adapterJs = npmProject.dir.resolve(ADAPTER_NODEJS) adapterJs.printWriter().use { writer -> val adapter = npmProject.require("kotlin-test-js-runner/kotlin-test-nodejs-runner.js") diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinTest.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinTest.kt index 6c11c5f9aaa..3416e661a84 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinTest.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinTest.kt @@ -58,11 +58,15 @@ abstract class KotlinTest : AbstractTestTask() { runListeners.add(listener) } + private val ignoreTcsmOverflow by lazy { + PropertiesProvider(project).ignoreTcsmOverflow + } + override fun createTestExecuter() = TCServiceMessagesTestExecutor( execHandleFactory, buildOperationExecutor, runListeners, - PropertiesProvider(project).ignoreTcsmOverflow, + ignoreTcsmOverflow, ignoreRunFailures ) } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/testing/internal/KotlinTestReport.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/testing/internal/KotlinTestReport.kt index aa4473bb25e..72bbccd2ba8 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/testing/internal/KotlinTestReport.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/testing/internal/KotlinTestReport.kt @@ -41,18 +41,24 @@ import java.net.URI * event if child tasks will be executed. */ open class KotlinTestReport : TestReport() { + @Transient @Internal val testTasks = mutableListOf() + @Transient private var parent: KotlinTestReport? = null + // TODO: used in task action when the task is aggregate report, non compatible with configuration cache @Internal val children = mutableListOf>() + @Transient private val projectProperties = PropertiesProvider(project) - val overrideReporting: Boolean - @Input get() = projectProperties.individualTaskReports == null + @get:Input + val overrideReporting: Boolean by lazy { + projectProperties.individualTaskReports == null + } @Input var checkFailedTests: Boolean = false @@ -60,28 +66,14 @@ open class KotlinTestReport : TestReport() { @Input var ignoreFailures: Boolean = false - private var hasOwnFailedTests = false + private val hasOwnFailedTests + get() = failedTestsListener.hasOwnFailedTests ?: false private val hasFailedTests: Boolean get() = hasOwnFailedTests || children.any { it.get().hasFailedTests } - private val ownSuppressedRunningFailures = mutableListOf>() + private val suppressedRunningFailureListeners: MutableSet = mutableSetOf() - private val failedTestsListener = object : TestListener { - override fun beforeTest(testDescriptor: TestDescriptor) { - } - - override fun afterSuite(suite: TestDescriptor, result: TestResult) { - } - - override fun beforeSuite(suite: TestDescriptor) { - } - - override fun afterTest(testDescriptor: TestDescriptor, result: TestResult) { - if (result.failedTestCount > 0) { - hasOwnFailedTests = true - } - } - } + private val failedTestsListener = FailedTestListener() fun addChild(childProvider: TaskProvider) { val child = childProvider.get() @@ -108,11 +100,11 @@ open class KotlinTestReport : TestReport() { testTasks.add(task) task.addTestListener(failedTestsListener) - if (task is KotlinTest) task.addRunListener(object : KotlinTestRunnerListener { - override fun runningFailure(failure: Error) { - ownSuppressedRunningFailures.add(task to failure) - } - }) + if (task is KotlinTest) { + val listener = SuppressedTestRunningFailureListener(task.path) + task.addRunListener(listener) + suppressedRunningFailureListeners.add(listener) + } reportOn(task) addToParents(task) @@ -163,11 +155,11 @@ open class KotlinTestReport : TestReport() { } private fun checkSuppressedRunningFailures() { - val allSuppressedRunningFailures = mutableListOf>() + val allSuppressedRunningFailures = mutableListOf>() fun visitSuppressedRunningFailures(report: KotlinTestReport) { - report.ownSuppressedRunningFailures.forEach { - allSuppressedRunningFailures.add(it) + report.suppressedRunningFailureListeners.filter { it.failure != null }.forEach { + allSuppressedRunningFailures.add(it.taskPath to it.failure!!) } report.children.forEach { @@ -181,8 +173,8 @@ open class KotlinTestReport : TestReport() { val allErrors = mutableListOf() val msg = buildString { appendln("Failed to execute all tests:") - allSuppressedRunningFailures.groupBy { it.first }.forEach { test, errors -> - append(test.path) + allSuppressedRunningFailures.groupBy { it.first }.forEach { path, errors -> + append(path) append(": ") var first = true errors.forEach { (_, error) -> @@ -251,4 +243,33 @@ open class KotlinTestReport : TestReport() { task.reports.junitXml.isEnabled = false } + + private class SuppressedTestRunningFailureListener(val taskPath: String) : KotlinTestRunnerListener { + @Transient + var failure: Error? = null + + override fun runningFailure(failure: Error) { + this.failure = failure + } + } + + private class FailedTestListener : TestListener { + @Transient + var hasOwnFailedTests: Boolean? = false + + override fun beforeTest(testDescriptor: TestDescriptor) { + } + + override fun afterSuite(suite: TestDescriptor, result: TestResult) { + } + + override fun beforeSuite(suite: TestDescriptor) { + } + + override fun afterTest(testDescriptor: TestDescriptor, result: TestResult) { + if (result.failedTestCount > 0) { + hasOwnFailedTests = true + } + } + } }