Skip to content

Commit 02a73a7

Browse files
authored
Add exception to retry notification; fix assertions (#117)
1 parent 956a385 commit 02a73a7

File tree

6 files changed

+72
-58
lines changed

6 files changed

+72
-58
lines changed

src/main/java/com/nordstrom/automation/junit/JUnitConfig.java

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,29 +25,38 @@ public class JUnitConfig extends SettingsCore<JUnitConfig.JUnitSettings> {
2525
*/
2626
public enum JUnitSettings implements SettingsCore.SettingsAPI {
2727
/**
28-
* Global per-test timeout interval in milliseconds.
28+
* This setting specifies the global per-test timeout interval in milliseconds.
2929
* <p>
3030
* name: <b>junit.timeout.test</b><br>
3131
* default: {@code null}
3232
*/
3333
TEST_TIMEOUT("junit.timeout.test", null),
3434

3535
/**
36-
* Global per-class timeout interval in milliseconds.
36+
* This setting specifies the global per-class timeout interval in milliseconds.
3737
* <p>
3838
* name: <b>junit.timeout.rule</b><br>
3939
* default: {@code null}
4040
*/
4141
TIMEOUT_RULE("junit.timeout.rule", null),
4242

4343
/**
44-
* Maximum retry attempts for failed test methods.
44+
* This setting specifies the maximum retry attempts for failed test methods.
4545
* <p>
4646
* name: <b>junit.max.retry</b><br>
4747
* default: <b>0</b>
4848
*/
49-
MAX_RETRY("junit.max.retry", "0");
49+
MAX_RETRY("junit.max.retry", "0"),
5050

51+
/**
52+
* This setting specifies whether the exception that caused a test to fail will be logged in the notification
53+
* that the test is being retried.
54+
* <p>
55+
* name: <b>junit.retry.more.info</b><br>
56+
* default: {@code false}
57+
*/
58+
RETRY_MORE_INFO("junit.retry.more.info", "false");
59+
5160
private final String propertyName;
5261
private final String defaultValue;
5362

src/main/java/com/nordstrom/automation/junit/MutableTest.java

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -79,21 +79,12 @@ public static MutableTest proxyFor(Method testMethod, long timeout) {
7979
}
8080
if (declared != null) {
8181
try {
82-
Field field = LifecycleHooks.getDeclaredField(testMethod, DECLARED_ANNOTATIONS);
83-
field.setAccessible(true);
84-
try {
85-
@SuppressWarnings("unchecked")
86-
Map<Class<? extends Annotation>, Annotation> map =
87-
(Map<Class<? extends Annotation>, Annotation>) field.get(testMethod);
88-
MutableTest mutable = new MutableTest(declared, timeout);
89-
map.put(Test.class, mutable);
90-
return mutable;
91-
} catch (IllegalArgumentException | IllegalAccessException e) {
92-
throw new UnsupportedOperationException("Failed acquiring annotations map for method: " + testMethod, e);
93-
}
94-
} catch (NoSuchFieldException | SecurityException e) {
95-
throw new UnsupportedOperationException("Failed acquiring [" + DECLARED_ANNOTATIONS
96-
+ "] field of Executable class", e);
82+
Map<Class<? extends Annotation>, Annotation> map = LifecycleHooks.getFieldValue(testMethod, DECLARED_ANNOTATIONS);
83+
MutableTest mutable = new MutableTest(declared, timeout);
84+
map.put(Test.class, mutable);
85+
return mutable;
86+
} catch (IllegalAccessException | NoSuchFieldException | SecurityException e) {
87+
throw new UnsupportedOperationException("Failed acquiring annotations map for method: " + testMethod, e);
9788
}
9889
}
9990
throw new IllegalArgumentException("Specified method is not a JUnit @Test: " + testMethod);

src/main/java/com/nordstrom/automation/junit/RetryHandler.java

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.nordstrom.automation.junit;
22

3+
import static com.nordstrom.automation.junit.LifecycleHooks.getConfig;
34
import static com.nordstrom.automation.junit.LifecycleHooks.invoke;
45
import static com.nordstrom.automation.junit.LifecycleHooks.toMapKey;
56

@@ -119,8 +120,8 @@ public static Throwable runChildWithRetry(final Object runner, final FrameworkMe
119120
static boolean doRetry(FrameworkMethod method, Throwable thrown, AtomicInteger retryCounter) {
120121
boolean doRetry = false;
121122
if ((retryCounter.decrementAndGet() > -1) && isRetriable(method, thrown)) {
122-
LOGGER.warn("### RETRY ### {}", method);
123123
doRetry = true;
124+
LOGGER.warn("### RETRY ### {}", method, getThrowableToLog(thrown));
124125
}
125126
return doRetry;
126127
}
@@ -146,20 +147,31 @@ static int getMaxRetry(Object runner, final FrameworkMethod method) {
146147
// if method isn't ignored or excluded from retry attempts
147148
if (Boolean.FALSE.equals(invoke(runner, "isIgnored", method)) && (noRetryOnMethod == null) && (noRetryOnClass == null)) {
148149
// get configured maximum retry count
149-
maxRetry = JUnitConfig.getConfig().getInteger(JUnitSettings.MAX_RETRY.key(), Integer.valueOf(0));
150+
maxRetry = getConfig().getInteger(JUnitSettings.MAX_RETRY.key(), Integer.valueOf(0));
150151
}
151152

152153
return maxRetry;
153154
}
154155

156+
/**
157+
* Determine if the specified method is being retried.
158+
*
159+
* @param method JUnit framework method
160+
* @return {@code true} if method is being retried; otherwise {@code false}
161+
*/
162+
static boolean doRetryFor(final FrameworkMethod method) {
163+
Boolean doRetry = METHOD_TO_RETRY.get(toMapKey(method));
164+
return (doRetry != null) ? doRetry.booleanValue() : false;
165+
}
166+
155167
/**
156168
* Determine if the specified failed test should be retried.
157169
*
158170
* @param method failed test method
159171
* @param thrown exception for this failed test
160172
* @return {@code true} if test should be retried; otherwise {@code false}
161173
*/
162-
static boolean isRetriable(final FrameworkMethod method, final Throwable thrown) {
174+
private static boolean isRetriable(final FrameworkMethod method, final Throwable thrown) {
163175
synchronized(retryAnalyzerLoader) {
164176
for (JUnitRetryAnalyzer analyzer : retryAnalyzerLoader) {
165177
if (analyzer.retry(method, thrown)) {
@@ -171,14 +183,16 @@ static boolean isRetriable(final FrameworkMethod method, final Throwable thrown)
171183
}
172184

173185
/**
174-
* Determine if the specified method is being retried.
186+
* Get the {@link Throwable} to log with the retry notification.
175187
*
176-
* @param method JUnit framework method
177-
* @return {@code true} if method is being retried; otherwise {@code false}
188+
* @param thrown exception that caused the test to fail
189+
* @return if exception logging is indicated, the specified exception; otherwise {@code null}
178190
*/
179-
static boolean doRetryFor(final FrameworkMethod method) {
180-
Boolean doRetry = METHOD_TO_RETRY.get(toMapKey(method));
181-
return (doRetry != null) ? doRetry.booleanValue() : false;
191+
private static Throwable getThrowableToLog(Throwable thrown) {
192+
if (LOGGER.isDebugEnabled() || getConfig().getBoolean(JUnitSettings.RETRY_MORE_INFO.key())) {
193+
return thrown;
194+
}
195+
return null;
182196
}
183197

184198
}

src/test/java/com/nordstrom/automation/junit/BeforeClassFailureTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ public void verifyBeforeClassExceptionHandling() {
2525
runner.addListener(checker);
2626
Result result = runner.run(BeforeClassThrowsException.class);
2727
assertFalse(result.wasSuccessful());
28-
assertEquals(1, result.getFailureCount(), "Incorrect failed test count");
28+
assertEquals(result.getFailureCount(), 1, "Incorrect failed test count");
2929
Failure failure = result.getFailures().get(0);
30-
assertEquals(RuntimeException.class, failure.getException().getClass(), "Incorrect exception class");
31-
assertEquals("Must be failed", failure.getMessage(), "Incorrect exception message");
30+
assertEquals(failure.getException().getClass(), RuntimeException.class, "Incorrect exception class");
31+
assertEquals(failure.getMessage(), "Must be failed", "Incorrect exception message");
3232
assertTrue(failure.getDescription().isSuite(), "Failure should describe a suite");
3333

3434
Optional<UnitTestWatcher> optWatcher = LifecycleHooks.getAttachedWatcher(UnitTestWatcher.class);

src/test/java/com/nordstrom/automation/junit/ReferenceReleaseTest.java

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ public void verifyHappyPath() {
1818
runner.addListener(checker);
1919
Result result = runner.run(AutomaticRetryPassing.class);
2020
assertTrue(result.wasSuccessful());
21-
assertEquals(result.getRunCount(), 1);
22-
assertEquals(result.getFailureCount(), 0);
21+
assertEquals(result.getRunCount(), 1, "Incorrect test run count");
22+
assertEquals(result.getFailureCount(), 0, "Incorrect failed test count");
2323
checkLeakReports(checker);
2424
}
2525

@@ -31,8 +31,8 @@ public void verifyFailure() {
3131
runner.addListener(checker);
3232
Result result = runner.run(AutomaticRetryFailing.class);
3333
assertFalse(result.wasSuccessful());
34-
assertEquals(result.getRunCount(), 1);
35-
assertEquals(result.getFailureCount(), 1);
34+
assertEquals(result.getRunCount(), 1, "Incorrect test run count");
35+
assertEquals(result.getFailureCount(), 1, "Incorrect failed test count");
3636
checkLeakReports(checker);
3737
}
3838

@@ -44,8 +44,8 @@ public void verifyParameterizedReferenceRelease() {
4444
runner.addListener(checker);
4545
Result result = runner.run(ReferenceReleaseParameterized.class);
4646
assertFalse(result.wasSuccessful());
47-
assertEquals(result.getRunCount(), 2);
48-
assertEquals(result.getFailureCount(), 1);
47+
assertEquals(result.getRunCount(), 2, "Incorrect test run count");
48+
assertEquals(result.getFailureCount(), 1, "Incorrect failed test count");
4949
checkLeakReports(checker);
5050
}
5151

@@ -57,8 +57,8 @@ public void verifyJUnitParamsReferenceRelease() {
5757
runner.addListener(checker);
5858
Result result = runner.run(ReferenceReleaseJUnitParams.class);
5959
assertFalse(result.wasSuccessful());
60-
assertEquals(result.getRunCount(), 2);
61-
assertEquals(result.getFailureCount(), 1);
60+
assertEquals(result.getRunCount(), 2, "Incorrect test run count");
61+
assertEquals(result.getFailureCount(), 1, "Incorrect failed test count");
6262
checkLeakReports(checker);
6363
}
6464

@@ -70,26 +70,26 @@ public void verifyTheoriesReferenceRelease() {
7070
runner.addListener(checker);
7171
Result result = runner.run(ReferenceReleaseTheories.class);
7272
assertFalse(result.wasSuccessful());
73-
assertEquals(result.getRunCount(), 3);
74-
assertEquals(result.getFailureCount(), 2);
73+
assertEquals(result.getRunCount(), 3, "Incorrect test run count");
74+
assertEquals(result.getFailureCount(), 2, "Incorrect failed test count");
7575
checkLeakReports(checker);
7676
}
7777

7878
static void checkLeakReports(ReferenceChecker checker) {
79-
assertEquals(checker.reportNoAtomicTests(), 0);
80-
assertEquals(checker.reportStatementLeaks(), 0);
81-
assertEquals(checker.reportWatcherLeaks(), 0);
82-
assertEquals(checker.reportAtomicTestLeaks(), 0);
83-
assertEquals(checker.reportTargetLeaks(), 0);
84-
assertEquals(checker.reportCallableLeaks(), 0);
85-
assertEquals(checker.reportDescriptionLeaks(), 0);
86-
assertEquals(checker.reportMethodLeaks(), 0);
87-
assertEquals(checker.reportRunnerLeaks(), 0);
88-
assertEquals(checker.reportStartFlagLeaks(), 0);
89-
assertEquals(checker.reportNotifierLeaks(), 0);
90-
assertEquals(checker.reportNotifyFlagLeaks(), 0);
91-
assertEquals(checker.reportParentLeaks(), 0);
92-
assertEquals(checker.reportRunnerStackLeak(), 0);
79+
assertEquals(checker.reportNoAtomicTests(), 0, "Missing atomic tests detected");
80+
assertEquals(checker.reportStatementLeaks(), 0, "Leaked statements detected");
81+
assertEquals(checker.reportWatcherLeaks(), 0, "Leaked watchers detected");
82+
assertEquals(checker.reportAtomicTestLeaks(), 0, "Leaked atomic tests detected");
83+
assertEquals(checker.reportTargetLeaks(), 0, "Leaked target references detected");
84+
assertEquals(checker.reportCallableLeaks(), 0, "Leaked Callable references detected");
85+
assertEquals(checker.reportDescriptionLeaks(), 0, "Leaked Description references detected");
86+
assertEquals(checker.reportMethodLeaks(), 0, "Leaked Method references detected");
87+
assertEquals(checker.reportRunnerLeaks(), 0, "Leaked Runner references detected");
88+
assertEquals(checker.reportStartFlagLeaks(), 0, "Leaked 'start' flags detected");
89+
assertEquals(checker.reportNotifierLeaks(), 0, "Leaked Notifier referenced detected");
90+
assertEquals(checker.reportNotifyFlagLeaks(), 0, "Leaked 'notify' flags detected");
91+
assertEquals(checker.reportParentLeaks(), 0, "Leaked parent runner references detected");
92+
assertEquals(checker.reportRunnerStackLeak(), 0, "Leaked runner stack entries detected");
9393
}
9494

9595
}

src/test/java/com/nordstrom/automation/junit/RuleFailureTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@ public void verifyRuleExceptionHandling() {
1818
runner.addListener(checker);
1919
Result result = runner.run(RuleThrowsException.class);
2020
assertFalse(result.wasSuccessful());
21-
assertEquals(1, result.getFailureCount());
21+
assertEquals(result.getFailureCount(), 1, "Incorrect failed test count");
2222
Failure failure = result.getFailures().get(0);
23-
assertEquals(RuntimeException.class, failure.getException().getClass());
24-
assertEquals("Must be failed", failure.getMessage());
23+
assertEquals(failure.getException().getClass(), RuntimeException.class, "Incorrect failure exception");
24+
assertEquals(failure.getMessage(), "Must be failed", "Incorrect failure message");
2525
ReferenceReleaseTest.checkLeakReports(checker);
2626
}
2727

0 commit comments

Comments
 (0)