This is an automated email from the ASF dual-hosted git repository.
zhangduo pushed a commit to branch branch-3
in repository https://gitbox.apache.org/repos/asf/hbase.git
The following commit(s) were added to refs/heads/branch-3 by this push:
new 8818f4d17b3 HBASE-29637 Implement ResourceCheckerJUnitListener for
junit 5 (#7366)
8818f4d17b3 is described below
commit 8818f4d17b3208dbdce280e806cb4e4aed3f4c14
Author: Duo Zhang <[email protected]>
AuthorDate: Thu Oct 9 16:46:18 2025 +0800
HBASE-29637 Implement ResourceCheckerJUnitListener for junit 5 (#7366)
Co-authored-by: Copilot <[email protected]>
Signed-off-by: Istvan Toth <[email protected]>
(cherry picked from commit d8b1912361218ce9de3c3f7d4c5194c23519fa69)
---
.../apache/hadoop/hbase/HBaseJupiterExtension.java | 63 +++++++++---
...nitListener.java => JUnitResourceCheckers.java} | 74 +++----------
.../hadoop/hbase/ResourceCheckerJUnitListener.java | 114 +--------------------
3 files changed, 62 insertions(+), 189 deletions(-)
diff --git
a/hbase-common/src/test/java/org/apache/hadoop/hbase/HBaseJupiterExtension.java
b/hbase-common/src/test/java/org/apache/hadoop/hbase/HBaseJupiterExtension.java
index 997e3dfa357..9d4ea87e0ec 100644
---
a/hbase-common/src/test/java/org/apache/hadoop/hbase/HBaseJupiterExtension.java
+++
b/hbase-common/src/test/java/org/apache/hadoop/hbase/HBaseJupiterExtension.java
@@ -37,7 +37,9 @@ import org.apache.hadoop.hbase.testclassification.MediumTests;
import org.apache.hadoop.hbase.testclassification.SmallTests;
import org.apache.yetus.audience.InterfaceAudience;
import org.junit.jupiter.api.extension.AfterAllCallback;
+import org.junit.jupiter.api.extension.AfterEachCallback;
import org.junit.jupiter.api.extension.BeforeAllCallback;
+import org.junit.jupiter.api.extension.BeforeEachCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.ExtensionContext.Store;
import org.junit.jupiter.api.extension.InvocationInterceptor;
@@ -60,14 +62,18 @@ import
org.apache.hbase.thirdparty.com.google.common.util.concurrent.ThreadFacto
* the tag.
* <p>
* It also controls the timeout for the whole test class running, while the
timeout annotation in
- * JUnit5 can only enforce the timeout for each test method.
+ * JUnit5 can only enforce the timeout for each test method. When a test is
timed out, a thread dump
+ * will be printed to log output.
* <p>
- * Finally, it also forbid System.exit call in tests. TODO: need to find a new
way as
- * SecurityManager has been removed since Java 21.
+ * It also implements resource check for each test method, using the {@link
ResourceChecker} class.
+ * <p>
+ * Finally, it also forbid System.exit call in tests. <br>
+ * TODO: need to find a new way as SecurityManager was deprecated in Java 17
and permanently
+ * disabled since Java 24.
*/
@InterfaceAudience.Private
-public class HBaseJupiterExtension
- implements InvocationInterceptor, BeforeAllCallback, AfterAllCallback {
+public class HBaseJupiterExtension implements InvocationInterceptor,
BeforeAllCallback,
+ AfterAllCallback, BeforeEachCallback, AfterEachCallback {
private static final Logger LOG =
LoggerFactory.getLogger(HBaseJupiterExtension.class);
@@ -84,6 +90,8 @@ public class HBaseJupiterExtension
private static final String DEADLINE = "deadline";
+ private static final String RESOURCE_CHECK = "rc";
+
private Duration pickTimeout(ExtensionContext ctx) {
Set<String> timeoutTags = TAG_TO_TIMEOUT.keySet();
Set<String> timeoutTag = Sets.intersection(timeoutTags, ctx.getTags());
@@ -130,7 +138,8 @@ public class HBaseJupiterExtension
System.setSecurityManager(null);
}
- private <T> T runWithTimeout(Invocation<T> invocation, ExtensionContext ctx)
throws Throwable {
+ private <T> T runWithTimeout(Invocation<T> invocation, ExtensionContext ctx,
String name)
+ throws Throwable {
Store store = ctx.getStore(NAMESPACE);
ExecutorService executor = store.get(EXECUTOR, ExecutorService.class);
if (executor == null) {
@@ -139,12 +148,12 @@ public class HBaseJupiterExtension
Instant deadline = store.get(DEADLINE, Instant.class);
Instant now = Instant.now();
if (!now.isBefore(deadline)) {
- fail("Test " + ctx.getDisplayName() + " timed out, deadline is " +
deadline);
+ fail("Test " + name + " timed out, deadline is " + deadline);
return null;
}
Duration remaining = Duration.between(now, deadline);
- LOG.info("remaining timeout for {} is {}", ctx.getDisplayName(),
remaining);
+ LOG.info("remaining timeout for {} is {}", name, remaining);
Future<T> future = executor.submit(() -> {
try {
return invocation.proceed();
@@ -157,14 +166,13 @@ public class HBaseJupiterExtension
return future.get(remaining.toNanos(), TimeUnit.NANOSECONDS);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
- fail("Test " + ctx.getDisplayName() + " interrupted");
+ fail("Test " + name + " interrupted");
return null;
} catch (ExecutionException e) {
throw ExceptionUtils.throwAsUncheckedException(e.getCause());
} catch (TimeoutException e) {
printThreadDump();
- throw new JUnitException(
- "Test " + ctx.getDisplayName() + " timed out, deadline is " +
deadline, e);
+ throw new JUnitException("Test " + name + " timed out, deadline is " +
deadline, e);
}
}
@@ -177,41 +185,62 @@ public class HBaseJupiterExtension
public void interceptBeforeAllMethod(Invocation<Void> invocation,
ReflectiveInvocationContext<Method> invocationContext, ExtensionContext
extensionContext)
throws Throwable {
- runWithTimeout(invocation, extensionContext);
+ runWithTimeout(invocation, extensionContext,
extensionContext.getDisplayName() + ".beforeAll");
}
@Override
public void interceptBeforeEachMethod(Invocation<Void> invocation,
ReflectiveInvocationContext<Method> invocationContext, ExtensionContext
extensionContext)
throws Throwable {
- runWithTimeout(invocation, extensionContext);
+ runWithTimeout(invocation, extensionContext,
extensionContext.getDisplayName() + ".beforeEach");
}
@Override
public void interceptTestMethod(Invocation<Void> invocation,
ReflectiveInvocationContext<Method> invocationContext, ExtensionContext
extensionContext)
throws Throwable {
- runWithTimeout(invocation, extensionContext);
+ runWithTimeout(invocation, extensionContext,
extensionContext.getDisplayName());
}
@Override
public void interceptAfterEachMethod(Invocation<Void> invocation,
ReflectiveInvocationContext<Method> invocationContext, ExtensionContext
extensionContext)
throws Throwable {
- runWithTimeout(invocation, extensionContext);
+ runWithTimeout(invocation, extensionContext,
extensionContext.getDisplayName() + ".afterEach");
}
@Override
public void interceptAfterAllMethod(Invocation<Void> invocation,
ReflectiveInvocationContext<Method> invocationContext, ExtensionContext
extensionContext)
throws Throwable {
- runWithTimeout(invocation, extensionContext);
+ runWithTimeout(invocation, extensionContext,
extensionContext.getDisplayName() + ".afterAll");
}
@Override
public <T> T interceptTestClassConstructor(Invocation<T> invocation,
ReflectiveInvocationContext<Constructor<T>> invocationContext,
ExtensionContext extensionContext) throws Throwable {
- return runWithTimeout(invocation, extensionContext);
+ return runWithTimeout(invocation, extensionContext,
+ extensionContext.getDisplayName() + ".constructor");
+ }
+
+ // below are for implementing resource checker around test method
+
+ @Override
+ public void beforeEach(ExtensionContext ctx) throws Exception {
+ ResourceChecker rc = new ResourceChecker(ctx.getDisplayName());
+ JUnitResourceCheckers.addResourceAnalyzer(rc);
+ Store store = ctx.getStore(NAMESPACE);
+ store.put(RESOURCE_CHECK, rc);
+ rc.start();
+ }
+
+ @Override
+ public void afterEach(ExtensionContext ctx) throws Exception {
+ Store store = ctx.getStore(NAMESPACE);
+ ResourceChecker rc = store.remove(RESOURCE_CHECK, ResourceChecker.class);
+ if (rc != null) {
+ rc.end();
+ }
}
}
diff --git
a/hbase-common/src/test/java/org/apache/hadoop/hbase/ResourceCheckerJUnitListener.java
b/hbase-common/src/test/java/org/apache/hadoop/hbase/JUnitResourceCheckers.java
similarity index 60%
copy from
hbase-common/src/test/java/org/apache/hadoop/hbase/ResourceCheckerJUnitListener.java
copy to
hbase-common/src/test/java/org/apache/hadoop/hbase/JUnitResourceCheckers.java
index 4dfce7f536b..aee49dc2c60 100644
---
a/hbase-common/src/test/java/org/apache/hadoop/hbase/ResourceCheckerJUnitListener.java
+++
b/hbase-common/src/test/java/org/apache/hadoop/hbase/JUnitResourceCheckers.java
@@ -22,27 +22,20 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
import org.apache.hadoop.hbase.ResourceChecker.Phase;
import org.apache.hadoop.hbase.util.JVM;
-import org.junit.runner.notification.RunListener;
/**
- * Listen to the test progress and check the usage of:
- * <ul>
- * <li>threads</li>
- * <li>open file descriptor</li>
- * <li>max open file descriptor</li>
- * </ul>
- * <p>
- * When surefire forkMode=once/always/perthread, this code is executed on the
forked process.
+ * ResourceCheckers when running JUnit tests.
*/
-public class ResourceCheckerJUnitListener extends RunListener {
- private Map<String, ResourceChecker> rcs = new ConcurrentHashMap<>();
+public final class JUnitResourceCheckers {
- static class ThreadResourceAnalyzer extends ResourceChecker.ResourceAnalyzer
{
- private static Set<String> initialThreadNames = new HashSet<>();
- private static List<String> stringsToLog = null;
+ private JUnitResourceCheckers() {
+ }
+
+ private static class ThreadResourceAnalyzer extends
ResourceChecker.ResourceAnalyzer {
+ private Set<String> initialThreadNames = new HashSet<>();
+ private List<String> stringsToLog = null;
@Override
public int getVal(Phase phase) {
@@ -80,7 +73,7 @@ public class ResourceCheckerJUnitListener extends RunListener
{
}
}
- static class OpenFileDescriptorResourceAnalyzer extends
ResourceChecker.ResourceAnalyzer {
+ private static class OpenFileDescriptorResourceAnalyzer extends
ResourceChecker.ResourceAnalyzer {
@Override
public int getVal(Phase phase) {
if (!JVM.isUnix()) {
@@ -96,7 +89,7 @@ public class ResourceCheckerJUnitListener extends RunListener
{
}
}
- static class MaxFileDescriptorResourceAnalyzer extends
ResourceChecker.ResourceAnalyzer {
+ private static class MaxFileDescriptorResourceAnalyzer extends
ResourceChecker.ResourceAnalyzer {
@Override
public int getVal(Phase phase) {
if (!JVM.isUnix()) {
@@ -107,7 +100,7 @@ public class ResourceCheckerJUnitListener extends
RunListener {
}
}
- static class SystemLoadAverageResourceAnalyzer extends
ResourceChecker.ResourceAnalyzer {
+ private static class SystemLoadAverageResourceAnalyzer extends
ResourceChecker.ResourceAnalyzer {
@Override
public int getVal(Phase phase) {
if (!JVM.isUnix()) {
@@ -117,7 +110,7 @@ public class ResourceCheckerJUnitListener extends
RunListener {
}
}
- static class ProcessCountResourceAnalyzer extends
ResourceChecker.ResourceAnalyzer {
+ private static class ProcessCountResourceAnalyzer extends
ResourceChecker.ResourceAnalyzer {
@Override
public int getVal(Phase phase) {
if (!JVM.isUnix()) {
@@ -127,7 +120,7 @@ public class ResourceCheckerJUnitListener extends
RunListener {
}
}
- static class AvailableMemoryMBResourceAnalyzer extends
ResourceChecker.ResourceAnalyzer {
+ private static class AvailableMemoryMBResourceAnalyzer extends
ResourceChecker.ResourceAnalyzer {
@Override
public int getVal(Phase phase) {
if (!JVM.isUnix()) {
@@ -137,51 +130,12 @@ public class ResourceCheckerJUnitListener extends
RunListener {
}
}
- /**
- * To be implemented by sub classes if they want to add specific
ResourceAnalyzer.
- */
- protected void addResourceAnalyzer(ResourceChecker rc) {
- }
-
- private void start(String testName) {
- ResourceChecker rc = new ResourceChecker(testName);
+ public static void addResourceAnalyzer(ResourceChecker rc) {
rc.addResourceAnalyzer(new ThreadResourceAnalyzer());
rc.addResourceAnalyzer(new OpenFileDescriptorResourceAnalyzer());
rc.addResourceAnalyzer(new MaxFileDescriptorResourceAnalyzer());
rc.addResourceAnalyzer(new SystemLoadAverageResourceAnalyzer());
rc.addResourceAnalyzer(new ProcessCountResourceAnalyzer());
rc.addResourceAnalyzer(new AvailableMemoryMBResourceAnalyzer());
-
- addResourceAnalyzer(rc);
-
- rcs.put(testName, rc);
-
- rc.start();
- }
-
- private void end(String testName) {
- ResourceChecker rc = rcs.remove(testName);
- assert rc != null;
- rc.end();
- }
-
- /**
- * Get the test name from the JUnit Description
- * @return the string for the short test name
- */
- private String descriptionToShortTestName(org.junit.runner.Description
description) {
- final int toRemove = "org.apache.hadoop.hbase.".length();
- return description.getTestClass().getName().substring(toRemove) + "#"
- + description.getMethodName();
- }
-
- @Override
- public void testStarted(org.junit.runner.Description description) throws
java.lang.Exception {
- start(descriptionToShortTestName(description));
- }
-
- @Override
- public void testFinished(org.junit.runner.Description description) throws
java.lang.Exception {
- end(descriptionToShortTestName(description));
}
}
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 4dfce7f536b..2a796cc4077 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
@@ -17,14 +17,8 @@
*/
package org.apache.hadoop.hbase;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
import java.util.Map;
-import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
-import org.apache.hadoop.hbase.ResourceChecker.Phase;
-import org.apache.hadoop.hbase.util.JVM;
import org.junit.runner.notification.RunListener;
/**
@@ -38,104 +32,8 @@ 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 {
- private Map<String, ResourceChecker> rcs = new ConcurrentHashMap<>();
- static class ThreadResourceAnalyzer extends ResourceChecker.ResourceAnalyzer
{
- private static Set<String> initialThreadNames = new HashSet<>();
- private static List<String> stringsToLog = null;
-
- @Override
- public int getVal(Phase phase) {
- Map<Thread, StackTraceElement[]> stackTraces =
Thread.getAllStackTraces();
- if (phase == Phase.INITIAL) {
- stringsToLog = null;
- for (Thread t : stackTraces.keySet()) {
- initialThreadNames.add(t.getName());
- }
- } else if (phase == Phase.END) {
- if (stackTraces.size() > initialThreadNames.size()) {
- stringsToLog = new ArrayList<>();
- for (Thread t : stackTraces.keySet()) {
- if (!initialThreadNames.contains(t.getName())) {
- stringsToLog.add("\nPotentially hanging thread: " + t.getName()
+ "\n");
- StackTraceElement[] stackElements = stackTraces.get(t);
- for (StackTraceElement ele : stackElements) {
- stringsToLog.add("\t" + ele + "\n");
- }
- }
- }
- }
- }
- return stackTraces.size();
- }
-
- @Override
- public int getMax() {
- return 500;
- }
-
- @Override
- public List<String> getStringsToLog() {
- return stringsToLog;
- }
- }
-
- static class OpenFileDescriptorResourceAnalyzer extends
ResourceChecker.ResourceAnalyzer {
- @Override
- public int getVal(Phase phase) {
- if (!JVM.isUnix()) {
- return 0;
- }
- JVM jvm = new JVM();
- return (int) jvm.getOpenFileDescriptorCount();
- }
-
- @Override
- public int getMax() {
- return 1024;
- }
- }
-
- static class MaxFileDescriptorResourceAnalyzer extends
ResourceChecker.ResourceAnalyzer {
- @Override
- public int getVal(Phase phase) {
- if (!JVM.isUnix()) {
- return 0;
- }
- JVM jvm = new JVM();
- return (int) jvm.getMaxFileDescriptorCount();
- }
- }
-
- static class SystemLoadAverageResourceAnalyzer extends
ResourceChecker.ResourceAnalyzer {
- @Override
- public int getVal(Phase phase) {
- if (!JVM.isUnix()) {
- return 0;
- }
- return (int) (new JVM().getSystemLoadAverage() * 100);
- }
- }
-
- static class ProcessCountResourceAnalyzer extends
ResourceChecker.ResourceAnalyzer {
- @Override
- public int getVal(Phase phase) {
- if (!JVM.isUnix()) {
- return 0;
- }
- return new JVM().getNumberOfRunningProcess();
- }
- }
-
- static class AvailableMemoryMBResourceAnalyzer extends
ResourceChecker.ResourceAnalyzer {
- @Override
- public int getVal(Phase phase) {
- if (!JVM.isUnix()) {
- return 0;
- }
- return (int) (new JVM().getFreeMemory() / (1024L * 1024L));
- }
- }
+ private final Map<String, ResourceChecker> rcs = new ConcurrentHashMap<>();
/**
* To be implemented by sub classes if they want to add specific
ResourceAnalyzer.
@@ -145,17 +43,9 @@ public class ResourceCheckerJUnitListener extends
RunListener {
private void start(String testName) {
ResourceChecker rc = new ResourceChecker(testName);
- rc.addResourceAnalyzer(new ThreadResourceAnalyzer());
- rc.addResourceAnalyzer(new OpenFileDescriptorResourceAnalyzer());
- rc.addResourceAnalyzer(new MaxFileDescriptorResourceAnalyzer());
- rc.addResourceAnalyzer(new SystemLoadAverageResourceAnalyzer());
- rc.addResourceAnalyzer(new ProcessCountResourceAnalyzer());
- rc.addResourceAnalyzer(new AvailableMemoryMBResourceAnalyzer());
-
+ JUnitResourceCheckers.addResourceAnalyzer(rc);
addResourceAnalyzer(rc);
-
rcs.put(testName, rc);
-
rc.start();
}