Skip to content

Commit faa0e33

Browse files
npathaimarcphilipp
authored andcommitted
Clear thread interrupt status after each test
The thread interrupt status flag is now cleared from `classBlock()` and `methodBlock()`. The flag is cleared after each test case completes and after `AfterClass` methods and `ClassRules` have been executed. Fixes #1365.
1 parent 9a28848 commit faa0e33

File tree

4 files changed

+111
-1
lines changed

4 files changed

+111
-1
lines changed

src/main/java/org/junit/runners/BlockJUnit4ClassRunner.java

+1
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,7 @@ protected Object runReflectiveCall() throws Throwable {
319319
statement = withBefores(method, test, statement);
320320
statement = withAfters(method, test, statement);
321321
statement = withRules(method, test, statement);
322+
statement = withInterruptIsolation(statement);
322323
return statement;
323324
}
324325

src/main/java/org/junit/runners/ParentRunner.java

+17
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@ protected Statement classBlock(final RunNotifier notifier) {
214214
statement = withBeforeClasses(statement);
215215
statement = withAfterClasses(statement);
216216
statement = withClassRules(statement);
217+
statement = withInterruptIsolation(statement);
217218
}
218219
return statement;
219220
}
@@ -293,6 +294,22 @@ public void evaluate() {
293294
};
294295
}
295296

297+
/**
298+
* @return a {@link Statement}: clears interrupt status of current thread after execution of statement
299+
*/
300+
protected final Statement withInterruptIsolation(final Statement statement) {
301+
return new Statement() {
302+
@Override
303+
public void evaluate() throws Throwable {
304+
try {
305+
statement.evaluate();
306+
} finally {
307+
Thread.interrupted(); // clearing thread interrupted status for isolation
308+
}
309+
}
310+
};
311+
}
312+
296313
/**
297314
* Evaluates whether a child is ignored. The default implementation always
298315
* returns <code>false</code>.

src/test/java/org/junit/tests/running/classes/AllClassesTests.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
ParentRunnerClassLoaderTest.class,
1818
RunWithTest.class,
1919
SuiteTest.class,
20-
UseSuiteAsASuperclassTest.class
20+
UseSuiteAsASuperclassTest.class,
21+
ThreadsTest.class
2122
})
2223
public class AllClassesTests {
2324
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package org.junit.tests.running.classes;
2+
3+
import org.junit.AfterClass;
4+
import org.junit.Test;
5+
import org.junit.internal.runners.ErrorReportingRunner;
6+
import org.junit.runner.Description;
7+
import org.junit.runner.JUnitCore;
8+
import org.junit.runner.Request;
9+
import org.junit.runner.Result;
10+
import org.junit.runner.RunWith;
11+
import org.junit.runner.Runner;
12+
import org.junit.runner.notification.RunListener;
13+
import org.junit.runners.BlockJUnit4ClassRunner;
14+
import org.junit.runners.model.InitializationError;
15+
16+
import static org.junit.Assert.assertEquals;
17+
18+
public class ThreadsTest {
19+
private String log = "";
20+
21+
public static class TestWithInterrupt {
22+
23+
@Test
24+
public void interruptCurrentThread() {
25+
Thread.currentThread().interrupt();
26+
}
27+
28+
@Test
29+
public void otherTestCaseInterruptingCurrentThread() {
30+
Thread.currentThread().interrupt();
31+
}
32+
33+
}
34+
35+
@Test
36+
public void currentThreadInterruptedStatusIsClearedAfterEachTestExecution() {
37+
log = "";
38+
JUnitCore jUnitCore = new JUnitCore();
39+
jUnitCore.addListener(new RunListener() {
40+
@Override
41+
public void testFinished(Description description) {
42+
log += Thread.currentThread().isInterrupted() + " ";
43+
}
44+
});
45+
46+
Result result = jUnitCore.run(TestWithInterrupt.class);
47+
assertEquals(0, result.getFailureCount());
48+
assertEquals("false false ", log);
49+
}
50+
51+
@RunWith(BlockJUnit4ClassRunner.class)
52+
public static class TestWithInterruptFromAfterClass {
53+
@AfterClass
54+
public static void interruptCurrentThread() {
55+
Thread.currentThread().interrupt();
56+
}
57+
58+
@Test
59+
public void test() {
60+
// no-op
61+
}
62+
}
63+
64+
@Test
65+
public void currentThreadInterruptStatusIsClearedAfterSuiteExecution() {
66+
log = "";
67+
JUnitCore jUnitCore = new JUnitCore();
68+
jUnitCore.addListener(new RunListener() {
69+
@Override
70+
public void testSuiteFinished(Description description) throws Exception {
71+
log += Thread.currentThread().isInterrupted();
72+
}
73+
});
74+
75+
Request request = new Request() {
76+
@Override
77+
public Runner getRunner() {
78+
try {
79+
return new BlockJUnit4ClassRunner(TestWithInterruptFromAfterClass.class) {
80+
};
81+
} catch (InitializationError e) {
82+
return new ErrorReportingRunner(TestWithInterruptFromAfterClass.class, e);
83+
}
84+
}
85+
};
86+
87+
Result result = jUnitCore.run(request);
88+
assertEquals(0, result.getFailureCount());
89+
assertEquals("false", log);
90+
}
91+
}

0 commit comments

Comments
 (0)