diff --git a/idea/idea-test-framework/src/org/jetbrains/kotlin/idea/test/testUtils.kt b/idea/idea-test-framework/src/org/jetbrains/kotlin/idea/test/testUtils.kt index d75cc74f939..e6db7f205eb 100644 --- a/idea/idea-test-framework/src/org/jetbrains/kotlin/idea/test/testUtils.kt +++ b/idea/idea-test-framework/src/org/jetbrains/kotlin/idea/test/testUtils.kt @@ -95,9 +95,7 @@ fun doKotlinTearDown(project: Project, runnable: RunnableWithException) { fun doKotlinTearDown(project: Project, runnable: () -> Unit) { unInvalidateBuiltinsAndStdLib(project) { - patchThreadTracker { - runnable() - } + runnable() } } @@ -148,55 +146,4 @@ fun Document.extractMarkerOffset(project: Project, caretMarker: String = " Unit) { - fun patch() { - if (patched.get()) return - - patched.compareAndSet(false, true) - - IdeaForkJoinWorkerThreadFactory.setupForkJoinCommonPool() - - // Check setup was successful - val commonPoolFactoryName = ForkJoinPool.commonPool().factory.javaClass.name - if (commonPoolFactoryName == IdeaForkJoinWorkerThreadFactory::class.java.name) { - return - } - - println("Patching!") - - try { - val wellKnownOffendersField = try { - ThreadTracker::class.java.getDeclaredField("wellKnownOffenders") - } - catch (communityPropertyNotFoundEx: NoSuchFieldException) { - ThreadTracker::class.java.getDeclaredField("a") - } - - wellKnownOffendersField.isAccessible = true - - @Suppress("UNCHECKED_CAST") - val wellKnownOffenders = wellKnownOffendersField.get(null) as MutableSet - - wellKnownOffenders.add("ForkJoinPool.commonPool-worker-") - } - catch (e: NoSuchFieldException) { - println("Patching failed: " + e) - } - catch (e: IllegalAccessException) { - println("Patching failed: " + e) - } - } - - patch() - runnable() } \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/ForkJoinPoolPatcherForTeamCityTesting.kt b/idea/src/org/jetbrains/kotlin/idea/ForkJoinPoolPatcherForTeamCityTesting.kt new file mode 100644 index 00000000000..24168b679b7 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/ForkJoinPoolPatcherForTeamCityTesting.kt @@ -0,0 +1,74 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.idea + +import com.intellij.concurrency.IdeaForkJoinWorkerThreadFactory +import com.intellij.testFramework.ThreadTracker +import java.util.concurrent.ForkJoinPool +import java.util.concurrent.atomic.AtomicBoolean + +/* +Workaround for ThreadTracker.checkLeak() failures on TeamCity. + +Currently TeamCity runs tests in classloader without boot.jar where IdeaForkJoinWorkerThreadFactory is defined. That +makes ForkJoinPool.commonPool() silently ignores java.util.concurrent.ForkJoinPool.common.threadFactory +(because of java.lang.ClassNotFoundException) option during factory initialization. + +Standard names for ForkJoinPool threads doesn't pass ThreadTracker.checkLeak() check and that ruins tests constantly. +As it's allowed to reorder tests on TeamCity and any test can be first at some point, this patch should be applied at +some common place. + */ +object ForkJoinPoolPatcherForTeamCityTesting { + private val patched = AtomicBoolean(false) + + fun patchThreadTracker() { + if (patched.get()) return + + patched.compareAndSet(false, true) + + IdeaForkJoinWorkerThreadFactory.setupForkJoinCommonPool() + + // Check setup was successful and patching isn't needed + val commonPoolFactoryName = ForkJoinPool.commonPool().factory.javaClass.name + if (commonPoolFactoryName == IdeaForkJoinWorkerThreadFactory::class.java.name) { + return + } + + try { + val wellKnownOffendersField = try { + ThreadTracker::class.java.getDeclaredField("wellKnownOffenders") + } + catch (communityPropertyNotFoundEx: NoSuchFieldException) { + ThreadTracker::class.java.getDeclaredField("a") + } + + wellKnownOffendersField.isAccessible = true + + @Suppress("UNCHECKED_CAST") + val wellKnownOffenders = wellKnownOffendersField.get(null) as MutableSet + + wellKnownOffenders.add("ForkJoinPool.commonPool-worker-") + println("Patching ThreadTracker was successful") + } + catch (e: NoSuchFieldException) { + println("Patching ThreadTracker failed: " + e) + } + catch (e: IllegalAccessException) { + println("Patching ThreadTracker failed: " + e) + } + } +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/PluginStartupComponent.java b/idea/src/org/jetbrains/kotlin/idea/PluginStartupComponent.java index b84fa77bae8..b1791a517ac 100644 --- a/idea/src/org/jetbrains/kotlin/idea/PluginStartupComponent.java +++ b/idea/src/org/jetbrains/kotlin/idea/PluginStartupComponent.java @@ -54,6 +54,10 @@ public class PluginStartupComponent implements ApplicationComponent { public void initComponent() { registerPathVariable(); + if (ApplicationManager.getApplication().isUnitTestMode()) { + ForkJoinPoolPatcherForTeamCityTesting.INSTANCE.patchThreadTracker(); + } + JarUserDataManager.INSTANCE.register(KotlinJavaScriptLibraryDetectionUtil.HasKotlinJSMetadataInJar.INSTANCE); DebuggerFiltersUtilKt.addKotlinStdlibDebugFilterIfNeeded(); diff --git a/idea/tests/org/jetbrains/kotlin/idea/KotlinDaemonAnalyzerTestCase.java b/idea/tests/org/jetbrains/kotlin/idea/KotlinDaemonAnalyzerTestCase.java index 573b164a8ca..cf9f089406c 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/KotlinDaemonAnalyzerTestCase.java +++ b/idea/tests/org/jetbrains/kotlin/idea/KotlinDaemonAnalyzerTestCase.java @@ -18,8 +18,6 @@ package org.jetbrains.kotlin.idea; import com.intellij.codeInsight.daemon.DaemonAnalyzerTestCase; import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess; -import org.jetbrains.kotlin.idea.test.RunnableWithException; -import org.jetbrains.kotlin.idea.test.TestUtilsKt; import org.jetbrains.kotlin.test.KotlinTestUtils; abstract public class KotlinDaemonAnalyzerTestCase extends DaemonAnalyzerTestCase { @@ -31,12 +29,7 @@ abstract public class KotlinDaemonAnalyzerTestCase extends DaemonAnalyzerTestCas @Override protected void tearDown() throws Exception { - TestUtilsKt.patchThreadTracker(new RunnableWithException() { - @Override - public void run() throws Exception { - KotlinDaemonAnalyzerTestCase.super.tearDown(); - } - }); + super.tearDown(); VfsRootAccess.disallowRootAccess(KotlinTestUtils.getHomeDirectory()); } } diff --git a/idea/tests/org/jetbrains/kotlin/idea/debugger/KotlinDebuggerTestCase.java b/idea/tests/org/jetbrains/kotlin/idea/debugger/KotlinDebuggerTestCase.java index a4b97e81412..0aaad0d0ea5 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/debugger/KotlinDebuggerTestCase.java +++ b/idea/tests/org/jetbrains/kotlin/idea/debugger/KotlinDebuggerTestCase.java @@ -45,8 +45,6 @@ import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade; import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime; import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil; import org.jetbrains.kotlin.idea.test.PluginTestCaseBase; -import org.jetbrains.kotlin.idea.test.RunnableWithException; -import org.jetbrains.kotlin.idea.test.TestUtilsKt; import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils; import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.psi.KtFile; @@ -101,7 +99,6 @@ public abstract class KotlinDebuggerTestCase extends DescriptorTestCase { ConfigLibraryUtil.addLibrary(customLibEditor, model); } - @SuppressWarnings("MethodDoesntCallSuperMethod") @Override protected void tearDown() throws Exception { if (getTestName(true).startsWith("dex")) { @@ -116,12 +113,7 @@ public abstract class KotlinDebuggerTestCase extends DescriptorTestCase { } }); - TestUtilsKt.patchThreadTracker(new RunnableWithException() { - @Override - public void run() throws Exception { - KotlinDebuggerTestCase.super.tearDown(); - } - }); + super.tearDown(); VfsRootAccess.allowRootAccess(KotlinTestUtils.getHomeDirectory()); } diff --git a/ultimate/tests/org/jetbrains/kotlin/idea/rename/AbstractUltimateRenameTest.kt b/ultimate/tests/org/jetbrains/kotlin/idea/rename/AbstractUltimateRenameTest.kt index 450cb045b07..46bdab465de 100644 --- a/ultimate/tests/org/jetbrains/kotlin/idea/rename/AbstractUltimateRenameTest.kt +++ b/ultimate/tests/org/jetbrains/kotlin/idea/rename/AbstractUltimateRenameTest.kt @@ -17,15 +17,8 @@ package org.jetbrains.kotlin.idea.rename import org.jetbrains.kotlin.idea.refactoring.rename.AbstractRenameTest -import org.jetbrains.kotlin.idea.test.patchThreadTracker import org.jetbrains.kotlin.tests.ULTIMATE_TEST_DATA_DIR abstract class AbstractUltimateRenameTest : AbstractRenameTest() { override fun getTestDataPath() = ULTIMATE_TEST_DATA_DIR - - override fun tearDown() { - patchThreadTracker { - super.tearDown() - } - } } \ No newline at end of file