Skip to content

Commit 345ba45

Browse files
author
David Saff
committed
Merge pull request #549 from Tibor17/junit.reopen
fixes for #544 and #545
2 parents 67eaa9f + f851c3e commit 345ba45

File tree

2 files changed

+67
-7
lines changed

2 files changed

+67
-7
lines changed

src/main/java/org/junit/internal/runners/statements/FailOnTimeout.java

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
import org.junit.runners.model.Statement;
44

5+
import java.io.InterruptedIOException;
6+
import java.nio.channels.ClosedByInterruptException;
57
import java.util.concurrent.TimeUnit;
68

79
public class FailOnTimeout extends Statement {
@@ -29,6 +31,8 @@ public void evaluate() throws Throwable {
2931

3032
private StatementThread evaluateStatement() throws InterruptedException {
3133
StatementThread thread = new StatementThread(fOriginalStatement);
34+
// Let the process/application complete after timeout expired.
35+
thread.setDaemon(true);
3236
thread.start();
3337
fTimeUnit.timedJoin(thread, fTimeout);
3438
if (!thread.fFinished) {
@@ -55,15 +59,27 @@ private void throwTimeoutException(StatementThread thread) throws Exception {
5559
}
5660

5761
private static class StatementThread extends Thread {
62+
/**
63+
* This is final variable because the statement is set once.
64+
* Final makes sure that the statement is immediately visible in
65+
* #run() (other than current thread) after constructor finished.
66+
*/
5867
private final Statement fStatement;
5968

60-
private boolean fFinished = false;
69+
/**
70+
* These two variables are volatile to make sure that the Thread calling #evaluate()
71+
* can immediately read their values set by this thread.
72+
* */
73+
private volatile boolean fFinished;
74+
private volatile Throwable fExceptionThrownByOriginalStatement;
6175

62-
private Throwable fExceptionThrownByOriginalStatement = null;
63-
64-
private StackTraceElement[] fRecordedStackTrace = null;
76+
// No need for volatile, because written and read by one thread.
77+
private StackTraceElement[] fRecordedStackTrace;
6578

6679
public StatementThread(Statement statement) {
80+
fFinished = false;
81+
fExceptionThrownByOriginalStatement = null;
82+
fRecordedStackTrace = null;
6783
fStatement = statement;
6884
}
6985

@@ -82,6 +98,10 @@ public void run() {
8298
fFinished = true;
8399
} catch (InterruptedException e) {
84100
// don't log the InterruptedException
101+
} catch (InterruptedIOException e) {
102+
// don't log the InterruptedIOException
103+
} catch (ClosedByInterruptException e) {
104+
// don't log the ClosedByInterruptException
85105
} catch (Throwable e) {
86106
fExceptionThrownByOriginalStatement = e;
87107
}

src/test/java/org/junit/tests/experimental/rules/TimeoutRuleTest.java

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,19 @@
44
import org.junit.Before;
55
import org.junit.Rule;
66
import org.junit.Test;
7+
import org.junit.rules.TemporaryFolder;
78
import org.junit.rules.TestRule;
89
import org.junit.rules.Timeout;
910
import org.junit.runner.JUnitCore;
1011
import org.junit.runner.Result;
1112

13+
import java.io.File;
14+
import java.io.IOException;
15+
import java.io.InterruptedIOException;
16+
import java.io.RandomAccessFile;
17+
import java.nio.ByteBuffer;
18+
import java.nio.channels.FileChannel;
19+
import java.util.Random;
1220
import java.util.concurrent.TimeUnit;
1321
import java.util.concurrent.locks.ReentrantLock;
1422

@@ -24,6 +32,9 @@ public class TimeoutRuleTest {
2432
public abstract static class AbstractTimeoutTest {
2533
public static final StringBuffer logger = new StringBuffer();
2634

35+
@Rule
36+
public final TemporaryFolder tmpFile = new TemporaryFolder();
37+
2738
@Test
2839
public void run1() throws InterruptedException {
2940
logger.append("run1");
@@ -49,6 +60,30 @@ public void run4() {
4960
while (!run4done) {
5061
}
5162
}
63+
64+
@Test
65+
public void run5() throws IOException {
66+
logger.append("run5");
67+
Random rnd = new Random();
68+
byte[] data = new byte[1024];
69+
File tmp = tmpFile.newFile();
70+
while (true) {
71+
FileChannel channel = new RandomAccessFile(tmp, "rw").getChannel();
72+
rnd.nextBytes(data);
73+
ByteBuffer buffer = ByteBuffer.wrap(data);
74+
// Interrupted thread closes channel and throws ClosedByInterruptException.
75+
channel.write(buffer);
76+
channel.close();
77+
tmp.delete();
78+
}
79+
}
80+
81+
@Test
82+
public void run6() throws InterruptedIOException {
83+
logger.append("run6");
84+
// Java IO throws InterruptedIOException only on SUN machines.
85+
throw new InterruptedIOException();
86+
}
5287
}
5388

5489
public static class HasGlobalLongTimeout extends AbstractTimeoutTest {
@@ -71,29 +106,34 @@ public void before() {
71106

72107
@After
73108
public void after() {
74-
run4done = true;//to make sure that the thread won't continue at run4()
109+
// set run4done to make sure that the thread won't continue at run4()
110+
run4done = true;
75111
run1Lock.unlock();
76112
}
77113

78114
@Test
79115
public void timeUnitTimeout() throws InterruptedException {
80116
HasGlobalTimeUnitTimeout.logger.setLength(0);
81117
Result result = JUnitCore.runClasses(HasGlobalTimeUnitTimeout.class);
82-
assertEquals(4, result.getFailureCount());
118+
assertEquals(6, result.getFailureCount());
83119
assertThat(HasGlobalTimeUnitTimeout.logger.toString(), containsString("run1"));
84120
assertThat(HasGlobalTimeUnitTimeout.logger.toString(), containsString("run2"));
85121
assertThat(HasGlobalTimeUnitTimeout.logger.toString(), containsString("run3"));
86122
assertThat(HasGlobalTimeUnitTimeout.logger.toString(), containsString("run4"));
123+
assertThat(HasGlobalTimeUnitTimeout.logger.toString(), containsString("run5"));
124+
assertThat(HasGlobalTimeUnitTimeout.logger.toString(), containsString("run6"));
87125
}
88126

89127
@Test
90128
public void longTimeout() throws InterruptedException {
91129
HasGlobalLongTimeout.logger.setLength(0);
92130
Result result = JUnitCore.runClasses(HasGlobalLongTimeout.class);
93-
assertEquals(4, result.getFailureCount());
131+
assertEquals(6, result.getFailureCount());
94132
assertThat(HasGlobalLongTimeout.logger.toString(), containsString("run1"));
95133
assertThat(HasGlobalLongTimeout.logger.toString(), containsString("run2"));
96134
assertThat(HasGlobalLongTimeout.logger.toString(), containsString("run3"));
97135
assertThat(HasGlobalLongTimeout.logger.toString(), containsString("run4"));
136+
assertThat(HasGlobalLongTimeout.logger.toString(), containsString("run5"));
137+
assertThat(HasGlobalLongTimeout.logger.toString(), containsString("run6"));
98138
}
99139
}

0 commit comments

Comments
 (0)