From f2fb70694801531c1752067d1055655df00d9478 Mon Sep 17 00:00:00 2001 From: Michael Stack Date: Mon, 12 Feb 2018 14:00:35 -0800 Subject: [PATCH] HBASE-19986 If HBaseTestClassRule timesout a test, thread dump --- .../apache/hadoop/hbase/HBaseClassTestRule.java | 34 +++++++++++++++++++++- .../hadoop/hbase/ResourceCheckerJUnitListener.java | 2 +- .../java/org/apache/hadoop/hbase/TestTimeout.java | 15 +++++++++- .../apache/hadoop/hbase/TimedOutTestsListener.java | 0 4 files changed, 48 insertions(+), 3 deletions(-) rename {hbase-server => hbase-common}/src/test/java/org/apache/hadoop/hbase/TimedOutTestsListener.java (100%) diff --git a/hbase-common/src/test/java/org/apache/hadoop/hbase/HBaseClassTestRule.java b/hbase-common/src/test/java/org/apache/hadoop/hbase/HBaseClassTestRule.java index bcde826020..87a55935bd 100644 --- a/hbase-common/src/test/java/org/apache/hadoop/hbase/HBaseClassTestRule.java +++ b/hbase-common/src/test/java/org/apache/hadoop/hbase/HBaseClassTestRule.java @@ -17,16 +17,26 @@ */ package org.apache.hadoop.hbase; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import java.util.concurrent.TimeUnit; + +import org.apache.hadoop.hbase.io.ByteArrayOutputStream; import org.apache.hadoop.hbase.testclassification.LargeTests; import org.apache.hadoop.hbase.testclassification.MediumTests; import org.apache.hadoop.hbase.testclassification.SmallTests; +import org.apache.hadoop.hbase.util.Bytes; +import org.apache.hadoop.hbase.util.Threads; import org.apache.yetus.audience.InterfaceAudience; import org.junit.experimental.categories.Category; import org.junit.rules.TestRule; import org.junit.rules.Timeout; import org.junit.runner.Description; +import org.junit.runners.model.MultipleFailureException; import org.junit.runners.model.Statement; +import org.junit.runners.model.TestTimedOutException; /** * The class level TestRule for all the tests. Every test class should have a {@code ClassRule} with @@ -74,6 +84,28 @@ public final class HBaseClassTestRule implements TestRule { @Override public Statement apply(Statement base, Description description) { - return timeout.apply(base, description); + final Statement s = timeout.apply(base, description); + return new Statement() { + Statement delegate = s; + + @Override + public void evaluate() throws Throwable { + try { + this.delegate.evaluate(); + } catch (TestTimedOutException|MultipleFailureException e) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PrintStream ps = new PrintStream(baos); + Threads.printThreadInfo(ps, "Timeout Timeout"); + ps.close(); + baos.close(); + String threadDump = Bytes.toString(baos.toByteArray()); + List failures = e instanceof MultipleFailureException? + new ArrayList<>(((MultipleFailureException) e).getFailures()): + new ArrayList<>(Arrays.asList(e)); + failures.add(new Throwable(threadDump)); + throw new MultipleFailureException(failures); + } + } + }; } } diff --git a/hbase-common/src/test/java/org/apache/hadoop/hbase/ResourceCheckerJUnitListener.java b/hbase-common/src/test/java/org/apache/hadoop/hbase/ResourceCheckerJUnitListener.java index 225d94f42b..d5c2d10230 100644 --- a/hbase-common/src/test/java/org/apache/hadoop/hbase/ResourceCheckerJUnitListener.java +++ b/hbase-common/src/test/java/org/apache/hadoop/hbase/ResourceCheckerJUnitListener.java @@ -38,7 +38,7 @@ import org.junit.runner.notification.RunListener; *

* When surefire forkMode=once/always/perthread, this code is executed on the forked process. */ -public class ResourceCheckerJUnitListener extends RunListener { +public class ResourceCheckerJUnitListener extends TimedOutTestsListener { private Map rcs = new ConcurrentHashMap<>(); static class ThreadResourceAnalyzer extends ResourceChecker.ResourceAnalyzer { diff --git a/hbase-common/src/test/java/org/apache/hadoop/hbase/TestTimeout.java b/hbase-common/src/test/java/org/apache/hadoop/hbase/TestTimeout.java index 343108e08b..495667c802 100644 --- a/hbase-common/src/test/java/org/apache/hadoop/hbase/TestTimeout.java +++ b/hbase-common/src/test/java/org/apache/hadoop/hbase/TestTimeout.java @@ -18,6 +18,7 @@ package org.apache.hadoop.hbase; import org.apache.hadoop.hbase.testclassification.SmallTests; +import org.apache.hadoop.hbase.util.Threads; import org.junit.ClassRule; import org.junit.Ignore; import org.junit.Test; @@ -41,6 +42,18 @@ public class TestTimeout { */ @Ignore @Test public void infiniteLoop() { - while (true) {} + // Launch a background non-daemon thread. + Thread t = new Thread("HangingThread") { + public void run() { + synchronized(this) { + while(true) { + } + } + } + }; + t.start(); + while (true) { + // Just hang out too. + } } } diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/TimedOutTestsListener.java b/hbase-common/src/test/java/org/apache/hadoop/hbase/TimedOutTestsListener.java similarity index 100% rename from hbase-server/src/test/java/org/apache/hadoop/hbase/TimedOutTestsListener.java rename to hbase-common/src/test/java/org/apache/hadoop/hbase/TimedOutTestsListener.java -- 2.11.0 (Apple Git-81)