This is an automated email from the ASF dual-hosted git repository.
shuber pushed a commit to branch opensearch-persistence
in repository https://gitbox.apache.org/repos/asf/unomi.git
The following commit(s) were added to refs/heads/opensearch-persistence by this
push:
new 9f4e1b9b4 Enhance ProgressListener with detailed JUnit test run
reporting features. Added visual elements, timing information, motivational
quotes, and CSV output for performance data. Improved ANSI color support and
structured documentation for better usability.
9f4e1b9b4 is described below
commit 9f4e1b9b4082aeb4ac3926ad77cf4067b56d2f5d
Author: Serge Huber <[email protected]>
AuthorDate: Mon Oct 13 19:46:15 2025 +0200
Enhance ProgressListener with detailed JUnit test run reporting features.
Added visual elements, timing information, motivational quotes, and CSV output
for performance data. Improved ANSI color support and structured documentation
for better usability.
---
.../org/apache/unomi/itests/ProgressListener.java | 132 ++++++++++++++++++++-
1 file changed, 131 insertions(+), 1 deletion(-)
diff --git a/itests/src/test/java/org/apache/unomi/itests/ProgressListener.java
b/itests/src/test/java/org/apache/unomi/itests/ProgressListener.java
index ca764ba06..b39355a43 100644
--- a/itests/src/test/java/org/apache/unomi/itests/ProgressListener.java
+++ b/itests/src/test/java/org/apache/unomi/itests/ProgressListener.java
@@ -24,42 +24,115 @@ import org.junit.runner.notification.RunListener;
import java.util.PriorityQueue;
import java.util.concurrent.atomic.AtomicInteger;
+/**
+ * A comprehensive JUnit test run listener that provides enhanced progress
reporting
+ * with visual elements, timing information, and motivational quotes during
test execution.
+ *
+ * <p>This listener extends JUnit's {@link RunListener} to provide real-time
feedback
+ * about test execution progress. It features:</p>
+ * <ul>
+ * <li>ASCII art logo display at test suite startup</li>
+ * <li>Real-time progress bar with percentage completion</li>
+ * <li>Colorized output (when ANSI is supported)</li>
+ * <li>Estimated time remaining calculations</li>
+ * <li>Test success/failure counters</li>
+ * <li>Top 10 slowest tests tracking and reporting</li>
+ * <li>Motivational quotes displayed at progress milestones</li>
+ * <li>CSV-formatted performance data output</li>
+ * </ul>
+ *
+ * <p>The listener automatically detects ANSI color support based on the
terminal
+ * environment and adjusts output accordingly. When ANSI is not supported,
+ * plain text output is used instead.</p>
+ *
+ * <p>Example usage in test configuration:</p>
+ * <pre>{@code
+ * JUnitCore core = new JUnitCore();
+ * ProgressListener listener = new ProgressListener(totalTestCount,
completedCounter);
+ * core.addListener(listener);
+ * core.run(testClasses);
+ * }</pre>
+ *
+ * <p>The listener tracks test execution times and maintains a priority queue
+ * of the slowest tests, which is reported at the end of the test run along
+ * with CSV-formatted data for further analysis.</p>
+ *
+ * @author Apache Unomi
+ * @since 3.0.0
+ * @see org.junit.runner.notification.RunListener
+ * @see org.junit.runner.Description
+ * @see org.junit.runner.Result
+ */
public class ProgressListener extends RunListener {
+ /** ANSI escape code to reset text formatting */
private static final String RESET = "\u001B[0m";
+ /** ANSI escape code for green text color */
private static final String GREEN = "\u001B[32m";
+ /** ANSI escape code for yellow text color */
private static final String YELLOW = "\u001B[33m";
+ /** ANSI escape code for red text color */
private static final String RED = "\u001B[31m";
+ /** ANSI escape code for cyan text color */
private static final String CYAN = "\u001B[36m";
+ /** ANSI escape code for blue text color */
private static final String BLUE = "\u001B[34m";
+ /** Array of motivational quotes displayed at progress milestones */
private static final String[] QUOTES = {
"Success is not final, failure is not fatal: It is the courage to
continue that counts. - Winston Churchill",
"Believe you can and you're halfway there. - Theodore Roosevelt",
- "Don’t watch the clock; do what it does. Keep going. - Sam
Levenson",
+ "Don't watch the clock; do what it does. Keep going. - Sam
Levenson",
"It does not matter how slowly you go as long as you do not stop.
- Confucius",
"Hardships often prepare ordinary people for an extraordinary
destiny. - C.S. Lewis"
};
+ /**
+ * Inner class representing a test execution time record.
+ * Used to track individual test performance for reporting the slowest
tests.
+ */
private static class TestTime {
+ /** The display name of the test */
String name;
+ /** The execution time in milliseconds */
long time;
+ /**
+ * Creates a new test time record.
+ *
+ * @param name the display name of the test
+ * @param time the execution time in milliseconds
+ */
TestTime(String name, long time) {
this.name = name;
this.time = time;
}
}
+ /** Total number of tests to be executed */
private final int totalTests;
+ /** Thread-safe counter for completed tests */
private final AtomicInteger completedTests;
+ /** Thread-safe counter for successful tests */
private final AtomicInteger successfulTests = new AtomicInteger(0);
+ /** Thread-safe counter for failed tests */
private final AtomicInteger failedTests = new AtomicInteger(0);
+ /** Priority queue to track the slowest tests (limited to top 10) */
private final PriorityQueue<TestTime> slowTests;
+ /** Flag indicating whether ANSI color codes are supported in the terminal
*/
private final boolean ansiSupported;
+ /** Timestamp when the test suite started */
private long startTime = System.currentTimeMillis();
+ /** Timestamp when the current individual test started */
private long startTestTime = System.currentTimeMillis();
+ /**
+ * Creates a new ProgressListener instance.
+ *
+ * @param totalTests the total number of tests that will be executed
+ * @param completedTests a thread-safe counter that tracks the number of
completed tests
+ * (this should be shared with the test runner for
accurate progress tracking)
+ */
public ProgressListener(int totalTests, AtomicInteger completedTests) {
this.totalTests = totalTests;
this.completedTests = completedTests;
@@ -67,11 +140,23 @@ public class ProgressListener extends RunListener {
this.ansiSupported = isAnsiSupported();
}
+ /**
+ * Determines if the current terminal supports ANSI color codes.
+ *
+ * @return true if ANSI colors are supported, false otherwise
+ */
private boolean isAnsiSupported() {
String term = System.getenv("TERM");
return System.console() != null && term != null &&
term.contains("xterm");
}
+ /**
+ * Applies ANSI color codes to text if the terminal supports them.
+ *
+ * @param text the text to colorize
+ * @param color the ANSI color code to apply
+ * @return the colorized text if ANSI is supported, otherwise the original
text
+ */
private String colorize(String text, String color) {
if (ansiSupported) {
return color + text + RESET;
@@ -79,6 +164,11 @@ public class ProgressListener extends RunListener {
return text;
}
+ /**
+ * Called when the test run starts. Displays an ASCII art logo and welcome
message.
+ *
+ * @param description the description of the test run
+ */
@Override
public void testRunStarted(Description description) {
startTime = System.currentTimeMillis();
@@ -121,11 +211,21 @@ public class ProgressListener extends RunListener {
System.out.println(colorize(bottomBorder, CYAN));
}
+ /**
+ * Called when an individual test starts. Records the start time for
timing calculations.
+ *
+ * @param description the description of the test that started
+ */
@Override
public void testStarted(Description description) {
startTestTime = System.currentTimeMillis();
}
+ /**
+ * Called when an individual test finishes successfully. Updates counters
and displays progress.
+ *
+ * @param description the description of the test that finished
+ */
@Override
public void testFinished(Description description) {
long testDuration = System.currentTimeMillis() - startTestTime;
@@ -139,6 +239,11 @@ public class ProgressListener extends RunListener {
displayProgress();
}
+ /**
+ * Called when a test fails. Updates failure counters and displays the
failure message.
+ *
+ * @param failure the failure information
+ */
@Override
public void testFailure(Failure failure) {
successfulTests.decrementAndGet(); // Remove the previous success
count for this test.
@@ -147,6 +252,11 @@ public class ProgressListener extends RunListener {
displayProgress();
}
+ /**
+ * Called when the entire test run finishes. Displays final statistics and
performance data.
+ *
+ * @param result the final result of the test run
+ */
@Override
public void testRunFinished(Result result) {
long elapsedTime = System.currentTimeMillis() - startTime;
@@ -190,6 +300,9 @@ public class ProgressListener extends RunListener {
/**
* Escapes special characters for CSV compatibility.
+ *
+ * @param value the string value to escape
+ * @return the escaped string suitable for CSV output
*/
private String escapeCsv(String value) {
if (value.contains(",") || value.contains("\"") ||
value.contains("\n")) {
@@ -198,6 +311,11 @@ public class ProgressListener extends RunListener {
return value;
}
+ /**
+ * Displays the current progress of the test run including progress bar,
+ * percentage completion, estimated time remaining, and success/failure
counts.
+ * Also displays motivational quotes at progress milestones.
+ */
private void displayProgress() {
int completed = completedTests.get();
long elapsedTime = System.currentTimeMillis() - startTime;
@@ -236,6 +354,12 @@ public class ProgressListener extends RunListener {
}
}
+ /**
+ * Formats a time duration in milliseconds into a human-readable string.
+ *
+ * @param timeInMillis the time duration in milliseconds
+ * @return a formatted time string (e.g., "1h 23m 45s" or "2m 30s")
+ */
private String formatTime(long timeInMillis) {
long seconds = timeInMillis / 1000;
long hours = seconds / 3600;
@@ -259,6 +383,12 @@ public class ProgressListener extends RunListener {
return timeBuilder.toString().trim(); // Trim any trailing spaces
}
+ /**
+ * Generates a visual progress bar based on the completion percentage.
+ *
+ * @param progressPercentage the completion percentage (0.0 to 100.0)
+ * @return a string representation of the progress bar with appropriate
colors
+ */
private String generateProgressBar(double progressPercentage) {
int totalBars = 30;
int completedBars = (int) (progressPercentage / (100.0 / totalBars));