diff --git a/python/testSrc/com/jetbrains/env/python/console/PyConsoleTask.java b/python/testSrc/com/jetbrains/env/python/console/PyConsoleTask.java index e603fd927239..8de5249e3f7a 100644 --- a/python/testSrc/com/jetbrains/env/python/console/PyConsoleTask.java +++ b/python/testSrc/com/jetbrains/env/python/console/PyConsoleTask.java @@ -41,6 +41,7 @@ import org.jetbrains.annotations.Nullable; import org.junit.Assert; import java.util.List; +import java.util.Optional; import java.util.Set; import java.util.concurrent.*; @@ -91,6 +92,9 @@ public class PyConsoleTask extends PyExecutionFixtureTestTask { @Override public void tearDown() throws Exception { + // Prevents thread leak, see its doc + killRpcThread(); + UIUtil.invokeAndWaitIfNeeded((Runnable)() -> { try { if (myConsoleView != null) { @@ -104,12 +108,29 @@ public class PyConsoleTask extends PyExecutionFixtureTestTask { super.tearDown(); } + /** + * Kill XML-Rpc thread + * Due to stupid bug in {@link LiteXmlRpcTransport#initConnection()} which has infinite loop that + * tries to connect to already dead process (already closed socket): See "tries" var. + */ + private static void killRpcThread() throws InterruptedException { + final Optional rpc = Thread.getAllStackTraces().keySet().stream() + .filter(o -> o.getClass().getName().contains("XmlRpc")) + .findFirst(); + if (rpc.isPresent()) { + final Thread thread = rpc.get(); + // There is no way to interrupt this thread with "interrupt": it has infinite loop (bug) which does not check ".isInterrupted()" + thread.stop(); + thread.join(); + } + } + /** * Disposes Python console and waits for Python console server thread to die. */ - private void disposeConsole() throws InterruptedException, ExecutionException, TimeoutException { + private void disposeConsole() throws InterruptedException, ExecutionException { try { - disposeConsoleAsync().get(30L, TimeUnit.SECONDS); + disposeConsoleAsync().get(); } finally { // Even if console failed in its side we need