Skip to content

Commit 2873269

Browse files
committed
Replace Concurrent annotation with RunNotifier.ThreadSafe
Update Javadoc Delete AddRemoveListenerTest (functionality covered by RunNotifierTest)
1 parent 58a5a92 commit 2873269

File tree

8 files changed

+65
-228
lines changed

8 files changed

+65
-228
lines changed

Diff for: src/main/java/org/junit/runner/Result.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import java.util.concurrent.atomic.AtomicInteger;
77
import java.util.concurrent.atomic.AtomicLong;
88

9-
import org.junit.runner.notification.Concurrent;
109
import org.junit.runner.notification.Failure;
1110
import org.junit.runner.notification.RunListener;
1211

@@ -66,7 +65,7 @@ public boolean wasSuccessful() {
6665
return getFailureCount() == 0;
6766
}
6867

69-
@Concurrent
68+
@RunListener.ThreadSafe
7069
private class Listener extends RunListener {
7170
@Override
7271
public void testRunStarted(Description description) throws Exception {

Diff for: src/main/java/org/junit/runner/notification/Concurrent.java

-21
This file was deleted.

Diff for: src/main/java/org/junit/runner/notification/RunListener.java

+52-9
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,20 @@
11
package org.junit.runner.notification;
22

3+
import java.lang.annotation.Documented;
4+
import java.lang.annotation.ElementType;
5+
import java.lang.annotation.Retention;
6+
import java.lang.annotation.RetentionPolicy;
7+
import java.lang.annotation.Target;
8+
39
import org.junit.internal.AssumptionViolatedException;
410
import org.junit.runner.Description;
511
import org.junit.runner.Result;
612

713
/**
8-
* <p>If you need to respond to the events during a test run, extend <code>RunListener</code>
9-
* and override the appropriate methods. If a listener throws an exception while processing a
10-
* test event, it will be removed for the remainder of the test run.</p>
14+
* Register an instance of this class with {@link RunNotifier} to be notified
15+
* of events that occur during a test run. All of the methods in this class
16+
* are abstract and have no implementation; override one or more methods to
17+
* receive events.
1118
*
1219
* <p>For example, suppose you have a <code>Cowbell</code>
1320
* class that you want to make a noise whenever a test fails. You could write:
@@ -18,7 +25,6 @@
1825
* }
1926
* }
2027
* </pre>
21-
* </p>
2228
*
2329
* <p>To invoke your listener, you need to run your tests through <code>JUnitCore</code>.
2430
* <pre>
@@ -28,23 +34,36 @@
2834
* core.run(MyTestClass.class);
2935
* }
3036
* </pre>
31-
* </p>
37+
*
38+
* <p>If a listener throws an exception for a test event, the other listeners will
39+
* have their {@link RunListener#testFailure(Failure)} called with a {@code Description}
40+
* of {@link Description#TEST_MECHANISM} to indicate the failure.
41+
*
42+
* <p>By default, JUnit will synchronize calls to your listener. If your listener
43+
* is thread-safe and you want to allow JUnit to call your listener from
44+
* multiple threads when tests are run in parallel, you can annotate your
45+
* test class with {@link RunListener.ThreadSafe}.
46+
*
47+
* <p>Listener methods will be called from the same thread as is running
48+
* the test, unless otherwise indicated by the method Javadoc
3249
*
3350
* @see org.junit.runner.JUnitCore
3451
* @since 4.0
3552
*/
3653
public class RunListener {
3754

3855
/**
39-
* Called before any tests have been run.
56+
* Called before any tests have been run. This may not necessarily
57+
* be called by the same thread as started the test run.
4058
*
4159
* @param description describes the tests to be run
4260
*/
4361
public void testRunStarted(Description description) throws Exception {
4462
}
4563

4664
/**
47-
* Called when all tests have finished
65+
* Called when all tests have finished. This may not necessarily
66+
* be called by the same thread as started the test run.
4867
*
4968
* @param result the summary of the test run, including all the tests that failed
5069
*/
@@ -69,7 +88,17 @@ public void testFinished(Description description) throws Exception {
6988
}
7089

7190
/**
72-
* Called when an atomic test fails.
91+
* Called when an atomic test fails, or when a listener throws an exception.
92+
*
93+
* <p>In the case of a failure of an atomic test, this method will be called
94+
* with the same {@code Description} passed to
95+
* {@link #testStarted(Description)}, from the same thread that called
96+
* {@link #testStarted(Description)}.
97+
*
98+
* <p>In the case of a listener throwing an exception, this will be called with
99+
* a {@code Description} of {@link Description#TEST_MECHANISM}. This call
100+
* may or may not be called in the same thread as the failing listener was
101+
* called
73102
*
74103
* @param failure describes the test that failed and the exception that was thrown
75104
*/
@@ -94,6 +123,20 @@ public void testAssumptionFailure(Failure failure) {
94123
*/
95124
public void testIgnored(Description description) throws Exception {
96125
}
97-
}
98126

99127

128+
/**
129+
* Indicates a {@code RunListener} that can have its methods called
130+
* concurrently. This implies that the class is thread-safe (i.e. no set of
131+
* listener calls can put the listener into an invalid state, even if those
132+
* listener calls are being made by multiple threads without
133+
* synchronization).
134+
*
135+
* @since 4.12
136+
*/
137+
@Documented
138+
@Target(ElementType.TYPE)
139+
@Retention(RetentionPolicy.RUNTIME)
140+
public @interface ThreadSafe {
141+
}
142+
}

Diff for: src/main/java/org/junit/runner/notification/SynchronizedRunListener.java

+10-5
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,29 @@
66
/**
77
* SynchronizedRunListener decorates {@link RunListener}, has all methods
88
* synchronized and is <em>not</em> public.
9-
* <p>
10-
* Due to backward compatibility, this synchronized listener behaves thread
9+
*
10+
* <p>Due to backward compatibility, this synchronized listener behaves thread
1111
* safe as {@link RunListener} in the old synchronized {@link RunNotifier}.
1212
*
1313
* @author Tibor Digana (tibor17)
14+
* @author Kevin Cooney (kcooney)
1415
* @version 4.12
1516
* @since 4.12
1617
*
1718
* @see RunNotifier
1819
*/
19-
@Concurrent
20+
@RunListener.ThreadSafe
2021
final class SynchronizedRunListener extends RunListener {
2122
private static final Object sMonitor = new Object();
2223
private final RunListener fListener;
2324

25+
/**
26+
* Wraps the given listener with {@link SynchronizedRunListener} if
27+
* it is not annotated with {@link RunListener.ThreadSafe}.
28+
*/
2429
public static RunListener wrapIfNotThreadSafe(RunListener listener) {
25-
boolean isThreadSafe = listener.getClass().isAnnotationPresent(Concurrent.class);
26-
return isThreadSafe ? listener : new SynchronizedRunListener(listener);
30+
return listener.getClass().isAnnotationPresent(RunListener.ThreadSafe.class) ?
31+
listener : new SynchronizedRunListener(listener);
2732
}
2833

2934
SynchronizedRunListener(RunListener listener) {

Diff for: src/test/java/org/junit/runner/notification/AddRemoveListenerTest.java

-187
This file was deleted.

Diff for: src/test/java/org/junit/runner/notification/RunNotifierTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ public void testStarted(Description description) throws Exception {
113113
}
114114
}
115115

116-
@Concurrent
116+
@RunListener.ThreadSafe
117117
private static class ThreadSafeListener extends CountingListener {
118118
}
119119

Diff for: src/test/java/org/junit/runner/notification/SynchronizedRunListenerTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ public boolean equals(Object obj) {
9999
}
100100
}
101101

102-
@Concurrent
102+
@RunListener.ThreadSafe
103103
private static class ThreadSafeRunListener extends RunListener {
104104
}
105105

0 commit comments

Comments
 (0)