You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by sd...@apache.org on 2022/10/10 08:28:40 UTC

[ignite] branch master updated: IGNITE-17847 Dump threads if afterTest() times out (#10295)

This is an automated email from the ASF dual-hosted git repository.

sdanilov pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite.git


The following commit(s) were added to refs/heads/master by this push:
     new 607839cef8f IGNITE-17847 Dump threads if afterTest() times out (#10295)
607839cef8f is described below

commit 607839cef8fa2cdafcdb311dd5c1369676021a21
Author: Roman Puchkovskiy <ro...@gmail.com>
AuthorDate: Mon Oct 10 12:28:33 2022 +0400

    IGNITE-17847 Dump threads if afterTest() times out (#10295)
---
 .../testframework/junits/GridAbstractTest.java     | 75 +++++++++++++++++++---
 1 file changed, 67 insertions(+), 8 deletions(-)

diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/junits/GridAbstractTest.java b/modules/core/src/test/java/org/apache/ignite/testframework/junits/GridAbstractTest.java
index e83ff92d63c..cd4ca5c508c 100755
--- a/modules/core/src/test/java/org/apache/ignite/testframework/junits/GridAbstractTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/testframework/junits/GridAbstractTest.java
@@ -42,7 +42,11 @@ import java.util.UUID;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.function.Consumer;
@@ -734,7 +738,7 @@ public abstract class GridAbstractTest extends JUnitAssertAware {
         printJvmMemoryStatistic();
 
         try {
-            afterTest();
+            runAfterTest();
         }
         finally {
             if (!keepSerializedObjects())
@@ -748,6 +752,54 @@ public abstract class GridAbstractTest extends JUnitAssertAware {
         }
     }
 
+    /**
+     * Runs afterTest() callback method with necessary scaffolding.
+     */
+    private void runAfterTest() throws Exception {
+        AtomicBoolean afterTestFinished = new AtomicBoolean(false);
+
+        ScheduledExecutorService scheduler = scheduleThreadDumpOnAfterTestTimeOut(afterTestFinished);
+
+        try {
+            afterTest();
+        }
+        finally {
+            afterTestFinished.set(true);
+
+            scheduler.shutdownNow();
+        }
+    }
+
+    /**
+     * Schedules a task that will print a thread dump if {@code afterTest()} times out.
+     *
+     * @param afterTestFinished Boolean flag used to tell whether {@code afterTest()} finished execution.
+     * @return Scheduled executor used when scheduling.
+     */
+    private ScheduledExecutorService scheduleThreadDumpOnAfterTestTimeOut(AtomicBoolean afterTestFinished) {
+        // Compute class name as string to avoid holding reference to the test class instance in task.
+        String testClassName = getClass().getName();
+
+        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1, task -> {
+            Thread thread = new Thread(task, "after-test-timeout-" + testClassName);
+            thread.setDaemon(true);
+            return thread;
+        });
+
+        scheduler.schedule(() -> {
+            scheduler.shutdownNow();
+
+            if (!afterTestFinished.get()) {
+                log.info(testClassName +
+                    ".afterTest() timed out, dumping threads (afterTest() still keeps running)");
+
+                dumpThreadsReliably();
+            }
+        }, getTestTimeout(), TimeUnit.MILLISECONDS);
+
+        return scheduler;
+    }
+
     /** Prints JVM memory statistic. */
     private void printJvmMemoryStatistic() {
         U.quietAndInfo(log(),
@@ -2475,11 +2527,7 @@ public abstract class GridAbstractTest extends JUnitAssertAware {
                 for (Ignite node : nodes)
                     ((IgniteKernal)node).dumpDebugInfo();
 
-                // We dump threads to stdout, because we can loose logs in case
-                // the build is cancelled on TeamCity.
-                U.dumpThreads(null);
-
-                U.dumpThreads(log);
+                dumpThreadsReliably();
 
                 U.interrupt(runner);
 
@@ -2514,6 +2562,17 @@ public abstract class GridAbstractTest extends JUnitAssertAware {
         }
     }
 
+    /**
+     * Dumps threads both to the console and log.
+     */
+    private static void dumpThreadsReliably() {
+        // We dump threads to stdout, because we can lose logs in case
+        // the build is cancelled on TeamCity.
+        U.dumpThreads(null);
+
+        U.dumpThreads(log);
+    }
+
     /**
      * Runs before each test. Is responsible for prepare test enviroment in accordance with {@link #beforeTest()}
      * method overriding.
@@ -2569,14 +2628,14 @@ public abstract class GridAbstractTest extends JUnitAssertAware {
     }
 
     /**
-     * @return Test case timeout.
+     * @return Test case timeout (in millis).
      */
     protected long getTestTimeout() {
         return getDefaultTestTimeout();
     }
 
     /**
-     * @return Default test case timeout.
+     * @return Default test case timeout (in millis).
      */
     private long getDefaultTestTimeout() {
         String timeout = GridTestProperties.getProperty("test.timeout");