Remove use of PlatformDependent.throwsException in SingleThreadEventExecutor (#10827)
Motivation: We should avoid lying with throws declarations whenever possible. Modification: Changed the code to instead directly throw Error, which seems to have been the intent. Also, while we're here, convert its associated test to JUnit 5 and clean it up a bit. Result: Cleaner code.
This commit is contained in:
parent
2dae6665f4
commit
db4f85a479
@ -831,9 +831,9 @@ public class SingleThreadEventExecutor extends AbstractScheduledEventExecutor im
|
|||||||
STATE_UPDATER.set(this, ST_TERMINATED);
|
STATE_UPDATER.set(this, ST_TERMINATED);
|
||||||
terminationFuture.tryFailure(cause);
|
terminationFuture.tryFailure(cause);
|
||||||
|
|
||||||
if (!(cause instanceof Exception)) {
|
if (cause instanceof Error) {
|
||||||
// Also rethrow as it may be an OOME for example
|
// Rethrow errors so they can't be ignored.
|
||||||
PlatformDependent.throwException(cause);
|
throw cause;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -15,9 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package io.netty.util.concurrent;
|
package io.netty.util.concurrent;
|
||||||
|
|
||||||
import org.hamcrest.CoreMatchers;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
@ -34,11 +32,16 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.*;
|
import static java.time.Duration.ofSeconds;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
public class SingleThreadEventExecutorTest {
|
public class SingleThreadEventExecutorTest {
|
||||||
|
public static final Runnable DUMMY_TASK = () -> {
|
||||||
|
};
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testWrappedExecutorIsShutdown() {
|
public void testWrappedExecutorIsShutdown() {
|
||||||
@ -59,25 +62,14 @@ public class SingleThreadEventExecutorTest {
|
|||||||
executorService.shutdownNow();
|
executorService.shutdownNow();
|
||||||
executeShouldFail(executor);
|
executeShouldFail(executor);
|
||||||
executeShouldFail(executor);
|
executeShouldFail(executor);
|
||||||
try {
|
var exception = assertThrows(
|
||||||
executor.shutdownGracefully().syncUninterruptibly();
|
CompletionException.class, () -> executor.shutdownGracefully().syncUninterruptibly());
|
||||||
Assert.fail();
|
assertThat(exception).hasCauseInstanceOf(RejectedExecutionException.class);
|
||||||
} catch (CompletionException expected) {
|
assertTrue(executor.isShutdown());
|
||||||
// expected
|
|
||||||
Assert.assertThat(expected.getCause(), CoreMatchers.instanceOf(RejectedExecutionException.class));
|
|
||||||
}
|
|
||||||
Assert.assertTrue(executor.isShutdown());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void executeShouldFail(Executor executor) {
|
private static void executeShouldFail(Executor executor) {
|
||||||
try {
|
assertThrows(RejectedExecutionException.class, () -> executor.execute(DUMMY_TASK));
|
||||||
executor.execute(() -> {
|
|
||||||
// Noop.
|
|
||||||
});
|
|
||||||
Assert.fail();
|
|
||||||
} catch (RejectedExecutionException expected) {
|
|
||||||
// expected
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -98,49 +90,45 @@ public class SingleThreadEventExecutorTest {
|
|||||||
ThreadProperties threadProperties = executor.threadProperties();
|
ThreadProperties threadProperties = executor.threadProperties();
|
||||||
|
|
||||||
Thread thread = threadRef.get();
|
Thread thread = threadRef.get();
|
||||||
Assert.assertEquals(thread.getId(), threadProperties.id());
|
assertEquals(thread.getId(), threadProperties.id());
|
||||||
Assert.assertEquals(thread.getName(), threadProperties.name());
|
assertEquals(thread.getName(), threadProperties.name());
|
||||||
Assert.assertEquals(thread.getPriority(), threadProperties.priority());
|
assertEquals(thread.getPriority(), threadProperties.priority());
|
||||||
Assert.assertEquals(thread.isAlive(), threadProperties.isAlive());
|
assertEquals(thread.isAlive(), threadProperties.isAlive());
|
||||||
Assert.assertEquals(thread.isDaemon(), threadProperties.isDaemon());
|
assertEquals(thread.isDaemon(), threadProperties.isDaemon());
|
||||||
Assert.assertTrue(threadProperties.stackTrace().length > 0);
|
assertTrue(threadProperties.stackTrace().length > 0);
|
||||||
executor.shutdownGracefully();
|
executor.shutdownGracefully();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = RejectedExecutionException.class, timeout = 3000)
|
@Test
|
||||||
public void testInvokeAnyInEventLoop() throws Throwable {
|
public void testInvokeAnyInEventLoop() throws Throwable {
|
||||||
try {
|
assertTimeoutPreemptively(ofSeconds(3), () -> {
|
||||||
testInvokeInEventLoop(true, false);
|
var exception = assertThrows(CompletionException.class, () -> testInvokeInEventLoop(true, false));
|
||||||
} catch (CompletionException e) {
|
assertThat(exception).hasCauseInstanceOf(RejectedExecutionException.class);
|
||||||
throw e.getCause();
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = RejectedExecutionException.class, timeout = 3000)
|
@Test
|
||||||
public void testInvokeAnyInEventLoopWithTimeout() throws Throwable {
|
public void testInvokeAnyInEventLoopWithTimeout() throws Throwable {
|
||||||
try {
|
assertTimeoutPreemptively(ofSeconds(3), () -> {
|
||||||
testInvokeInEventLoop(true, true);
|
var exception = assertThrows(CompletionException.class, () -> testInvokeInEventLoop(true, true));
|
||||||
} catch (CompletionException e) {
|
assertThat(exception).hasCauseInstanceOf(RejectedExecutionException.class);
|
||||||
throw e.getCause();
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = RejectedExecutionException.class, timeout = 3000)
|
@Test
|
||||||
public void testInvokeAllInEventLoop() throws Throwable {
|
public void testInvokeAllInEventLoop() throws Throwable {
|
||||||
try {
|
assertTimeoutPreemptively(ofSeconds(3), () -> {
|
||||||
testInvokeInEventLoop(false, false);
|
var exception = assertThrows(CompletionException.class, () -> testInvokeInEventLoop(false, false));
|
||||||
} catch (CompletionException e) {
|
assertThat(exception).hasCauseInstanceOf(RejectedExecutionException.class);
|
||||||
throw e.getCause();
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = RejectedExecutionException.class, timeout = 3000)
|
@Test
|
||||||
public void testInvokeAllInEventLoopWithTimeout() throws Throwable {
|
public void testInvokeAllInEventLoopWithTimeout() throws Throwable {
|
||||||
try {
|
assertTimeoutPreemptively(ofSeconds(3), () -> {
|
||||||
testInvokeInEventLoop(false, true);
|
var exception = assertThrows(CompletionException.class, () -> testInvokeInEventLoop(false, true));
|
||||||
} catch (CompletionException e) {
|
assertThat(exception).hasCauseInstanceOf(RejectedExecutionException.class);
|
||||||
throw e.getCause();
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void testInvokeInEventLoop(final boolean any, final boolean timeout) {
|
private static void testInvokeInEventLoop(final boolean any, final boolean timeout) {
|
||||||
@ -198,9 +186,6 @@ public class SingleThreadEventExecutorTest {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
final Runnable dummyTask = () -> {
|
|
||||||
};
|
|
||||||
|
|
||||||
final LinkedBlockingQueue<Future<?>> submittedTasks = new LinkedBlockingQueue<Future<?>>();
|
final LinkedBlockingQueue<Future<?>> submittedTasks = new LinkedBlockingQueue<Future<?>>();
|
||||||
final AtomicInteger attempts = new AtomicInteger();
|
final AtomicInteger attempts = new AtomicInteger();
|
||||||
final AtomicInteger rejects = new AtomicInteger();
|
final AtomicInteger rejects = new AtomicInteger();
|
||||||
@ -231,7 +216,7 @@ public class SingleThreadEventExecutorTest {
|
|||||||
if (result) {
|
if (result) {
|
||||||
attempts.incrementAndGet();
|
attempts.incrementAndGet();
|
||||||
try {
|
try {
|
||||||
submittedTasks.add(submit(dummyTask));
|
submittedTasks.add(submit(DUMMY_TASK));
|
||||||
} catch (RejectedExecutionException e) {
|
} catch (RejectedExecutionException e) {
|
||||||
// ignore, tasks are either accepted or rejected
|
// ignore, tasks are either accepted or rejected
|
||||||
rejects.incrementAndGet();
|
rejects.incrementAndGet();
|
||||||
@ -242,24 +227,24 @@ public class SingleThreadEventExecutorTest {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Start the loop
|
// Start the loop
|
||||||
executor.submit(dummyTask).sync();
|
executor.submit(DUMMY_TASK).sync();
|
||||||
|
|
||||||
// Shutdown without any quiet period
|
// Shutdown without any quiet period
|
||||||
executor.shutdownGracefully(0, 100, TimeUnit.MILLISECONDS).sync();
|
executor.shutdownGracefully(0, 100, TimeUnit.MILLISECONDS).sync();
|
||||||
|
|
||||||
// Ensure there are no user-tasks left.
|
// Ensure there are no user-tasks left.
|
||||||
Assert.assertEquals(0, executor.drainTasks());
|
assertEquals(0, executor.drainTasks());
|
||||||
|
|
||||||
// Verify that queue is empty and all attempts either succeeded or were rejected
|
// Verify that queue is empty and all attempts either succeeded or were rejected
|
||||||
Assert.assertTrue(taskQueue.isEmpty());
|
assertTrue(taskQueue.isEmpty());
|
||||||
Assert.assertTrue(attempts.get() > 0);
|
assertTrue(attempts.get() > 0);
|
||||||
Assert.assertEquals(attempts.get(), submittedTasks.size() + rejects.get());
|
assertEquals(attempts.get(), submittedTasks.size() + rejects.get());
|
||||||
for (Future<?> f : submittedTasks) {
|
for (Future<?> f : submittedTasks) {
|
||||||
Assert.assertTrue(f.isSuccess());
|
assertTrue(f.isSuccess());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout = 5000)
|
@Test
|
||||||
public void testTakeTask() throws Exception {
|
public void testTakeTask() throws Exception {
|
||||||
final SingleThreadEventExecutor executor =
|
final SingleThreadEventExecutor executor =
|
||||||
new SingleThreadEventExecutor(Executors.defaultThreadFactory()) {
|
new SingleThreadEventExecutor(Executors.defaultThreadFactory()) {
|
||||||
@ -274,6 +259,7 @@ public class SingleThreadEventExecutorTest {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
assertTimeoutPreemptively(ofSeconds(5), () -> {
|
||||||
//add task
|
//add task
|
||||||
TestRunnable beforeTask = new TestRunnable();
|
TestRunnable beforeTask = new TestRunnable();
|
||||||
executor.execute(beforeTask);
|
executor.execute(beforeTask);
|
||||||
@ -288,12 +274,13 @@ public class SingleThreadEventExecutorTest {
|
|||||||
|
|
||||||
f.sync();
|
f.sync();
|
||||||
|
|
||||||
assertThat(beforeTask.ran.get(), is(true));
|
assertThat(beforeTask.ran.get()).isTrue();
|
||||||
assertThat(scheduledTask.ran.get(), is(true));
|
assertThat(scheduledTask.ran.get()).isTrue();
|
||||||
assertThat(afterTask.ran.get(), is(true));
|
assertThat(afterTask.ran.get()).isTrue();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout = 5000)
|
@Test
|
||||||
public void testTakeTaskAlwaysHasTask() throws Exception {
|
public void testTakeTaskAlwaysHasTask() throws Exception {
|
||||||
//for https://github.com/netty/netty/issues/1614
|
//for https://github.com/netty/netty/issues/1614
|
||||||
|
|
||||||
@ -310,6 +297,7 @@ public class SingleThreadEventExecutorTest {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
assertTimeoutPreemptively(ofSeconds(5), () -> {
|
||||||
//add scheduled task
|
//add scheduled task
|
||||||
TestRunnable t = new TestRunnable();
|
TestRunnable t = new TestRunnable();
|
||||||
final ScheduledFuture<?> f = executor.schedule(t, 1500, TimeUnit.MILLISECONDS);
|
final ScheduledFuture<?> f = executor.schedule(t, 1500, TimeUnit.MILLISECONDS);
|
||||||
@ -327,7 +315,8 @@ public class SingleThreadEventExecutorTest {
|
|||||||
|
|
||||||
f.sync();
|
f.sync();
|
||||||
|
|
||||||
assertThat(t.ran.get(), is(true));
|
assertThat(t.ran.get()).isTrue();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class TestRunnable implements Runnable {
|
private static final class TestRunnable implements Runnable {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user