From 1c4335ec25d49fa8be7ed6ba682a1da2ff2f5552 Mon Sep 17 00:00:00 2001 From: Nikolay Krasko Date: Sat, 11 Apr 2015 00:38:26 +0300 Subject: [PATCH] Test background threads are stopped --- .../gradle/plugin/FinishBuildListener.kt | 5 +++ .../kotlin/gradle/plugin/ThreadTracker.kt | 42 +++++++++++++++++++ .../jetbrains/kotlin/gradle/BaseGradleIT.kt | 5 ++- .../kotlin/gradle/Kotlin2JsGradlePluginIT.kt | 2 +- 4 files changed, 51 insertions(+), 3 deletions(-) create mode 100644 libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/ThreadTracker.kt diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/FinishBuildListener.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/FinishBuildListener.kt index 287618a3282..d446bcb0cb4 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/FinishBuildListener.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/FinishBuildListener.kt @@ -25,6 +25,8 @@ import java.util.concurrent.ScheduledExecutorService class FinishBuildListener(var pluginClassLoader: ParentLastURLClassLoader?) : BuildAdapter() { val log = Logging.getLogger(this.javaClass) + private var threadTracker: ThreadTracker? = ThreadTracker() + override fun buildFinished(result: BuildResult?) { log.debug("Build finished listener") @@ -38,6 +40,9 @@ class FinishBuildListener(var pluginClassLoader: ParentLastURLClassLoader?) : Bu pluginClassLoader = null result?.getGradle()?.removeListener(this) + + threadTracker?.checkThreadLeak(result?.getGradle()) + threadTracker = null } public fun removeThreadLocals() { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/ThreadTracker.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/ThreadTracker.kt new file mode 100644 index 00000000000..2205c795303 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/ThreadTracker.kt @@ -0,0 +1,42 @@ +package org.jetbrains.kotlin.gradle.plugin + +import org.gradle.api.Project +import org.gradle.api.invocation.Gradle +import org.gradle.api.logging.Logging +import org.junit.Assert +import java.util.HashSet + +public class ThreadTracker { + val log = Logging.getLogger(this.javaClass) + private var before: Collection? = getThreads() + + private fun getThreads(): Collection = Thread.getAllStackTraces().keySet() + + public fun checkThreadLeak(gradle: Gradle?) { + try { + val testThreads = gradle != null && + gradle.getRootProject().hasProperty("kotlin.gradle.test") && + !gradle.getRootProject().hasProperty("kotlin.gradle.noThreadTest") + + Thread.sleep(if (testThreads) 200L else 50L) + + val after = HashSet(getThreads()) + after.removeAll(before!!) + + for (thread in after) { + if (thread == Thread.currentThread()) continue + + val name = thread.getName() + + if (testThreads) { + throw RuntimeException("Thread leaked: $thread: $name\n ${thread.getStackTrace().joinToString(separator = "\n", prefix = " at ")}") + } + else { + log.info("Thread leaked: $thread: $name") + } + } + } finally { + before = null + } + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/BaseGradleIT.kt b/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/BaseGradleIT.kt index 95b3be081db..279aa0069f7 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/BaseGradleIT.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/BaseGradleIT.kt @@ -37,7 +37,7 @@ abstract class BaseGradleIT { copyDirRecursively(File(resourcesRootFile, "GradleWrapper-$wrapperVersion"), projectDir) val cmd = createCommand(tasks) - println("<=== Test build: ${this.projectName} $cmd ====>") + println("<=== Test build: ${this.projectName} $cmd ===>") val process = createProcess(cmd, projectDir) @@ -96,7 +96,8 @@ abstract class BaseGradleIT { private fun Project.createCommand(params: Array): List { val pathToKotlinPlugin = "-PpathToKotlinPlugin=" + File("local-repo").getAbsolutePath() - val tailParameters = params + listOf(pathToKotlinPlugin, "--no-daemon", "--${minLogLevel.name().toLowerCase()}") + val tailParameters = params + + listOf(pathToKotlinPlugin, "--no-daemon", "--${minLogLevel.name().toLowerCase()}", "-Pkotlin.gradle.test=true") return if (isWindows()) listOf("cmd", "/C", "gradlew.bat") + tailParameters diff --git a/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/Kotlin2JsGradlePluginIT.kt b/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/Kotlin2JsGradlePluginIT.kt index 5fb438478ad..60305f441a3 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/Kotlin2JsGradlePluginIT.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/Kotlin2JsGradlePluginIT.kt @@ -8,7 +8,7 @@ class Kotlin2JsGradlePluginIT : BaseGradleIT() { Test fun testBuildAndClean() { val project = Project("kotlin2JsProject", "1.6") - project.build("build") { + project.build("build", "-Pkotlin.gradle.noThreadTest=true") { assertSuccessful() assertReportExists()