Skip to content

Commit 831f511

Browse files
cpovirkGoogle Java Core Libraries
authored andcommitted
Test that the interrupted InterruptibleTask does in fact produce InterruptedException.
I added this as part of debugging an inexplicable flaky failure under Android Lollipop. The failure remains inexplicable, but I figured I might as well submit the new assertion. This assertion, by blocking on some `InterruptibleTask` output, conveniently makes the existing blocking in `join` obsolete. RELNOTES=n/a PiperOrigin-RevId: 752845298
1 parent bdf2a9d commit 831f511

File tree

2 files changed

+42
-18
lines changed

2 files changed

+42
-18
lines changed

android/guava-tests/test/com/google/common/util/concurrent/InterruptibleTaskTest.java

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import com.google.common.util.concurrent.InterruptibleTask.Blocker;
2323
import java.nio.channels.spi.AbstractInterruptibleChannel;
2424
import java.util.concurrent.CountDownLatch;
25+
import java.util.concurrent.ExecutionException;
2526
import java.util.concurrent.locks.LockSupport;
2627
import junit.framework.TestCase;
2728
import org.jspecify.annotations.NullUnmarked;
@@ -34,15 +35,16 @@ public final class InterruptibleTaskTest extends TestCase {
3435
// transition to DONE
3536
public void testInterruptThrows() throws Exception {
3637
final CountDownLatch isInterruptibleRegistered = new CountDownLatch(1);
37-
InterruptibleTask<@Nullable Void> task =
38-
new InterruptibleTask<@Nullable Void>() {
38+
SettableFuture<String> taskResult = SettableFuture.create();
39+
InterruptibleTask<String> task =
40+
new InterruptibleTask<String>() {
3941
@Override
40-
@Nullable Void runInterruptibly() throws Exception {
42+
String runInterruptibly() throws Exception {
4143
BrokenChannel bc = new BrokenChannel();
4244
bc.doBegin();
4345
isInterruptibleRegistered.countDown();
4446
new CountDownLatch(1).await(); // the interrupt will wake us up
45-
return null;
47+
return "impossible!";
4648
}
4749

4850
@Override
@@ -56,10 +58,14 @@ String toPendingString() {
5658
}
5759

5860
@Override
59-
void afterRanInterruptiblySuccess(@Nullable Void result) {}
61+
void afterRanInterruptiblySuccess(String result) {
62+
taskResult.set(result);
63+
}
6064

6165
@Override
62-
void afterRanInterruptiblyFailure(Throwable error) {}
66+
void afterRanInterruptiblyFailure(Throwable error) {
67+
taskResult.setException(error);
68+
}
6369
};
6470
Thread runner = new Thread(task);
6571
runner.start();
@@ -68,9 +74,15 @@ void afterRanInterruptiblyFailure(Throwable error) {}
6874
assertThat(expected)
6975
.hasMessageThat()
7076
.isEqualTo("I bet you didn't think Thread.interrupt could throw");
71-
// We need to wait for the runner to exit. It used to be that the runner would get stuck in the
72-
// busy loop when interrupt threw.
73-
runner.join(SECONDS.toMillis(10));
77+
/*
78+
* We need to wait for the runner to exit. It used to be that the runner would get stuck in the
79+
* busy loop when interrupt threw.
80+
*
81+
* While we're at it, we confirm that the interrupt happened as expected.
82+
*/
83+
ExecutionException fromRunInterruptibly =
84+
assertThrows(ExecutionException.class, () -> taskResult.get(10, SECONDS));
85+
assertThat(fromRunInterruptibly).hasCauseThat().isInstanceOf(InterruptedException.class);
7486
}
7587

7688
static final class BrokenChannel extends AbstractInterruptibleChannel {

guava-tests/test/com/google/common/util/concurrent/InterruptibleTaskTest.java

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import com.google.common.util.concurrent.InterruptibleTask.Blocker;
2323
import java.nio.channels.spi.AbstractInterruptibleChannel;
2424
import java.util.concurrent.CountDownLatch;
25+
import java.util.concurrent.ExecutionException;
2526
import java.util.concurrent.locks.LockSupport;
2627
import junit.framework.TestCase;
2728
import org.jspecify.annotations.NullUnmarked;
@@ -34,15 +35,16 @@ public final class InterruptibleTaskTest extends TestCase {
3435
// transition to DONE
3536
public void testInterruptThrows() throws Exception {
3637
final CountDownLatch isInterruptibleRegistered = new CountDownLatch(1);
37-
InterruptibleTask<@Nullable Void> task =
38-
new InterruptibleTask<@Nullable Void>() {
38+
SettableFuture<String> taskResult = SettableFuture.create();
39+
InterruptibleTask<String> task =
40+
new InterruptibleTask<String>() {
3941
@Override
40-
@Nullable Void runInterruptibly() throws Exception {
42+
String runInterruptibly() throws Exception {
4143
BrokenChannel bc = new BrokenChannel();
4244
bc.doBegin();
4345
isInterruptibleRegistered.countDown();
4446
new CountDownLatch(1).await(); // the interrupt will wake us up
45-
return null;
47+
return "impossible!";
4648
}
4749

4850
@Override
@@ -56,10 +58,14 @@ String toPendingString() {
5658
}
5759

5860
@Override
59-
void afterRanInterruptiblySuccess(@Nullable Void result) {}
61+
void afterRanInterruptiblySuccess(String result) {
62+
taskResult.set(result);
63+
}
6064

6165
@Override
62-
void afterRanInterruptiblyFailure(Throwable error) {}
66+
void afterRanInterruptiblyFailure(Throwable error) {
67+
taskResult.setException(error);
68+
}
6369
};
6470
Thread runner = new Thread(task);
6571
runner.start();
@@ -68,9 +74,15 @@ void afterRanInterruptiblyFailure(Throwable error) {}
6874
assertThat(expected)
6975
.hasMessageThat()
7076
.isEqualTo("I bet you didn't think Thread.interrupt could throw");
71-
// We need to wait for the runner to exit. It used to be that the runner would get stuck in the
72-
// busy loop when interrupt threw.
73-
runner.join(SECONDS.toMillis(10));
77+
/*
78+
* We need to wait for the runner to exit. It used to be that the runner would get stuck in the
79+
* busy loop when interrupt threw.
80+
*
81+
* While we're at it, we confirm that the interrupt happened as expected.
82+
*/
83+
ExecutionException fromRunInterruptibly =
84+
assertThrows(ExecutionException.class, () -> taskResult.get(10, SECONDS));
85+
assertThat(fromRunInterruptibly).hasCauseThat().isInstanceOf(InterruptedException.class);
7486
}
7587

7688
static final class BrokenChannel extends AbstractInterruptibleChannel {

0 commit comments

Comments
 (0)