SingleThreadEventLoopTest failures

Motivation:
Some unit tests in SingleThreadEventLoopTest rely upon Thread.sleep for sequencing events between threads. This can be unreliable and result in spurious test failures if thread scheduling does not occur in a fair predictable manner.

Modifications:
- Reduce the reliance on Thread.sleep in SingleThreadEventLoopTest

Result:
Fixes https://github.com/netty/netty/issues/5851
This commit is contained in:
Scott Mitchell 2016-09-21 23:08:25 -07:00 committed by Norman Maurer
parent 32a560e42c
commit eb1dfb8f5e

View File

@ -169,18 +169,20 @@ public class SingleThreadEventLoopTest {
is(greaterThanOrEqualTo(TimeUnit.MILLISECONDS.toNanos(500)))); is(greaterThanOrEqualTo(TimeUnit.MILLISECONDS.toNanos(500))));
} }
@Test @Test(timeout = 5000)
public void scheduleTaskAtFixedRateA() throws Exception { public void scheduleTaskAtFixedRateA() throws Exception {
testScheduleTaskAtFixedRate(loopA); testScheduleTaskAtFixedRate(loopA);
} }
@Test @Test(timeout = 5000)
public void scheduleTaskAtFixedRateB() throws Exception { public void scheduleTaskAtFixedRateB() throws Exception {
testScheduleTaskAtFixedRate(loopB); testScheduleTaskAtFixedRate(loopB);
} }
private static void testScheduleTaskAtFixedRate(EventLoop loopA) throws InterruptedException { private static void testScheduleTaskAtFixedRate(EventLoop loopA) throws InterruptedException {
final Queue<Long> timestamps = new LinkedBlockingQueue<Long>(); final Queue<Long> timestamps = new LinkedBlockingQueue<Long>();
final int expectedTimeStamps = 5;
final CountDownLatch allTimeStampsLatch = new CountDownLatch(expectedTimeStamps);
ScheduledFuture<?> f = loopA.scheduleAtFixedRate(new Runnable() { ScheduledFuture<?> f = loopA.scheduleAtFixedRate(new Runnable() {
@Override @Override
public void run() { public void run() {
@ -190,11 +192,13 @@ public class SingleThreadEventLoopTest {
} catch (InterruptedException e) { } catch (InterruptedException e) {
// Ignore // Ignore
} }
allTimeStampsLatch.countDown();
} }
}, 100, 100, TimeUnit.MILLISECONDS); }, 100, 100, TimeUnit.MILLISECONDS);
Thread.sleep(550); allTimeStampsLatch.await();
assertTrue(f.cancel(true)); assertTrue(f.cancel(true));
assertEquals(5, timestamps.size()); Thread.sleep(300);
assertEquals(expectedTimeStamps, timestamps.size());
// Check if the task was run without a lag. // Check if the task was run without a lag.
Long firstTimestamp = null; Long firstTimestamp = null;
@ -213,18 +217,20 @@ public class SingleThreadEventLoopTest {
} }
} }
@Test @Test(timeout = 5000)
public void scheduleLaggyTaskAtFixedRateA() throws Exception { public void scheduleLaggyTaskAtFixedRateA() throws Exception {
testScheduleLaggyTaskAtFixedRate(loopA); testScheduleLaggyTaskAtFixedRate(loopA);
} }
@Test @Test(timeout = 5000)
public void scheduleLaggyTaskAtFixedRateB() throws Exception { public void scheduleLaggyTaskAtFixedRateB() throws Exception {
testScheduleLaggyTaskAtFixedRate(loopB); testScheduleLaggyTaskAtFixedRate(loopB);
} }
private static void testScheduleLaggyTaskAtFixedRate(EventLoop loopA) throws InterruptedException { private static void testScheduleLaggyTaskAtFixedRate(EventLoop loopA) throws InterruptedException {
final Queue<Long> timestamps = new LinkedBlockingQueue<Long>(); final Queue<Long> timestamps = new LinkedBlockingQueue<Long>();
final int expectedTimeStamps = 5;
final CountDownLatch allTimeStampsLatch = new CountDownLatch(expectedTimeStamps);
ScheduledFuture<?> f = loopA.scheduleAtFixedRate(new Runnable() { ScheduledFuture<?> f = loopA.scheduleAtFixedRate(new Runnable() {
@Override @Override
public void run() { public void run() {
@ -237,11 +243,13 @@ public class SingleThreadEventLoopTest {
// Ignore // Ignore
} }
} }
allTimeStampsLatch.countDown();
} }
}, 100, 100, TimeUnit.MILLISECONDS); }, 100, 100, TimeUnit.MILLISECONDS);
Thread.sleep(550); allTimeStampsLatch.await();
assertTrue(f.cancel(true)); assertTrue(f.cancel(true));
assertEquals(5, timestamps.size()); Thread.sleep(300);
assertEquals(expectedTimeStamps, timestamps.size());
// Check if the task was run with lag. // Check if the task was run with lag.
int i = 0; int i = 0;
@ -263,18 +271,20 @@ public class SingleThreadEventLoopTest {
} }
} }
@Test @Test(timeout = 5000)
public void scheduleTaskWithFixedDelayA() throws Exception { public void scheduleTaskWithFixedDelayA() throws Exception {
testScheduleTaskWithFixedDelay(loopA); testScheduleTaskWithFixedDelay(loopA);
} }
@Test @Test(timeout = 5000)
public void scheduleTaskWithFixedDelayB() throws Exception { public void scheduleTaskWithFixedDelayB() throws Exception {
testScheduleTaskWithFixedDelay(loopB); testScheduleTaskWithFixedDelay(loopB);
} }
private static void testScheduleTaskWithFixedDelay(EventLoop loopA) throws InterruptedException { private static void testScheduleTaskWithFixedDelay(EventLoop loopA) throws InterruptedException {
final Queue<Long> timestamps = new LinkedBlockingQueue<Long>(); final Queue<Long> timestamps = new LinkedBlockingQueue<Long>();
final int expectedTimeStamps = 3;
final CountDownLatch allTimeStampsLatch = new CountDownLatch(expectedTimeStamps);
ScheduledFuture<?> f = loopA.scheduleWithFixedDelay(new Runnable() { ScheduledFuture<?> f = loopA.scheduleWithFixedDelay(new Runnable() {
@Override @Override
public void run() { public void run() {
@ -284,11 +294,13 @@ public class SingleThreadEventLoopTest {
} catch (InterruptedException e) { } catch (InterruptedException e) {
// Ignore // Ignore
} }
allTimeStampsLatch.countDown();
} }
}, 100, 100, TimeUnit.MILLISECONDS); }, 100, 100, TimeUnit.MILLISECONDS);
Thread.sleep(500); allTimeStampsLatch.await();
assertTrue(f.cancel(true)); assertTrue(f.cancel(true));
assertEquals(3, timestamps.size()); Thread.sleep(300);
assertEquals(expectedTimeStamps, timestamps.size());
// Check if the task was run without a lag. // Check if the task was run without a lag.
Long previousTimestamp = null; Long previousTimestamp = null;