|
17 | 17 | package com.google.common.util.concurrent; |
18 | 18 |
|
19 | 19 | import static com.google.common.util.concurrent.InterruptionUtil.repeatedlyInterruptTestThread; |
| 20 | +import static com.google.common.util.concurrent.Uninterruptibles.awaitUninterruptibly; |
20 | 21 | import static com.google.common.util.concurrent.Uninterruptibles.joinUninterruptibly; |
21 | 22 | import static com.google.common.util.concurrent.Uninterruptibles.putUninterruptibly; |
22 | 23 | import static com.google.common.util.concurrent.Uninterruptibles.takeUninterruptibly; |
|
28 | 29 | import com.google.common.testing.NullPointerTester; |
29 | 30 | import com.google.common.testing.TearDown; |
30 | 31 | import com.google.common.testing.TearDownStack; |
| 32 | +import java.util.Date; |
31 | 33 | import java.util.concurrent.ArrayBlockingQueue; |
32 | 34 | import java.util.concurrent.BlockingQueue; |
33 | 35 | import java.util.concurrent.CountDownLatch; |
| 36 | +import java.util.concurrent.Executors; |
| 37 | +import java.util.concurrent.Future; |
| 38 | +import java.util.concurrent.ScheduledExecutorService; |
34 | 39 | import java.util.concurrent.Semaphore; |
| 40 | +import java.util.concurrent.TimeUnit; |
| 41 | +import java.util.concurrent.locks.Condition; |
| 42 | +import java.util.concurrent.locks.Lock; |
| 43 | +import java.util.concurrent.locks.ReentrantLock; |
35 | 44 | import junit.framework.TestCase; |
36 | 45 |
|
37 | 46 | /** |
@@ -85,6 +94,53 @@ public void testNull() throws Exception { |
85 | 94 |
|
86 | 95 | // CountDownLatch.await() tests |
87 | 96 |
|
| 97 | + // Condition.await() tests |
| 98 | + public void testConditionAwaitTimeoutExceeded() { |
| 99 | + Stopwatch stopwatch = Stopwatch.createStarted(); |
| 100 | + Condition condition = TestCondition.create(); |
| 101 | + |
| 102 | + boolean signaledBeforeTimeout = awaitUninterruptibly(condition, 500, MILLISECONDS); |
| 103 | + |
| 104 | + assertFalse(signaledBeforeTimeout); |
| 105 | + assertAtLeastTimePassed(stopwatch, 500); |
| 106 | + assertNotInterrupted(); |
| 107 | + } |
| 108 | + |
| 109 | + public void testConditionAwaitTimeoutNotExceeded() { |
| 110 | + Stopwatch stopwatch = Stopwatch.createStarted(); |
| 111 | + Condition condition = TestCondition.createAndSignalAfter(500, MILLISECONDS); |
| 112 | + |
| 113 | + boolean signaledBeforeTimeout = awaitUninterruptibly(condition, 1500, MILLISECONDS); |
| 114 | + |
| 115 | + assertTrue(signaledBeforeTimeout); |
| 116 | + assertTimeNotPassed(stopwatch, LONG_DELAY_MS); |
| 117 | + assertNotInterrupted(); |
| 118 | + } |
| 119 | + |
| 120 | + public void testConditionAwaitInterruptedTimeoutExceeded() { |
| 121 | + Stopwatch stopwatch = Stopwatch.createStarted(); |
| 122 | + Condition condition = TestCondition.create(); |
| 123 | + requestInterruptIn(500); |
| 124 | + |
| 125 | + boolean signaledBeforeTimeout = awaitUninterruptibly(condition, 1000, MILLISECONDS); |
| 126 | + |
| 127 | + assertFalse(signaledBeforeTimeout); |
| 128 | + assertAtLeastTimePassed(stopwatch, 1000); |
| 129 | + assertInterrupted(); |
| 130 | + } |
| 131 | + |
| 132 | + public void testConditionAwaitInterruptedTimeoutNotExceeded() { |
| 133 | + Stopwatch stopwatch = Stopwatch.createStarted(); |
| 134 | + Condition condition = TestCondition.createAndSignalAfter(1000, MILLISECONDS); |
| 135 | + requestInterruptIn(500); |
| 136 | + |
| 137 | + boolean signaledBeforeTimeout = awaitUninterruptibly(condition, 1500, MILLISECONDS); |
| 138 | + |
| 139 | + assertTrue(signaledBeforeTimeout); |
| 140 | + assertTimeNotPassed(stopwatch, LONG_DELAY_MS); |
| 141 | + assertInterrupted(); |
| 142 | + } |
| 143 | + |
88 | 144 | // BlockingQueue.put() tests |
89 | 145 | public void testPutWithNoWait() { |
90 | 146 | Stopwatch stopwatch = Stopwatch.createStarted(); |
@@ -378,18 +434,18 @@ void assertCompletionNotExpected(long timeout) { |
378 | 434 | assertAtLeastTimePassed(stopwatch, timeout); |
379 | 435 | assertTimeNotPassed(stopwatch, expectedCompletionWaitMillis); |
380 | 436 | } |
| 437 | + } |
381 | 438 |
|
382 | | - private static void assertAtLeastTimePassed(Stopwatch stopwatch, long expectedMillis) { |
383 | | - long elapsedMillis = stopwatch.elapsed(MILLISECONDS); |
384 | | - /* |
385 | | - * The "+ 5" below is to permit, say, sleep(10) to sleep only 9 milliseconds. We see such |
386 | | - * behavior sometimes when running these tests publicly as part of Guava. "+ 5" is probably |
387 | | - * more generous than it needs to be. |
388 | | - */ |
389 | | - assertTrue( |
390 | | - "Expected elapsed millis to be >= " + expectedMillis + " but was " + elapsedMillis, |
391 | | - elapsedMillis + 5 >= expectedMillis); |
392 | | - } |
| 439 | + private static void assertAtLeastTimePassed(Stopwatch stopwatch, long expectedMillis) { |
| 440 | + long elapsedMillis = stopwatch.elapsed(MILLISECONDS); |
| 441 | + /* |
| 442 | + * The "+ 5" below is to permit, say, sleep(10) to sleep only 9 milliseconds. We see such |
| 443 | + * behavior sometimes when running these tests publicly as part of Guava. "+ 5" is probably more |
| 444 | + * generous than it needs to be. |
| 445 | + */ |
| 446 | + assertTrue( |
| 447 | + "Expected elapsed millis to be >= " + expectedMillis + " but was " + elapsedMillis, |
| 448 | + elapsedMillis + 5 >= expectedMillis); |
393 | 449 | } |
394 | 450 |
|
395 | 451 | // TODO(cpovirk): Split this into separate CountDownLatch and IncrementableCountDownLatch classes. |
@@ -672,4 +728,109 @@ private static void assertNotInterrupted() { |
672 | 728 | private static void requestInterruptIn(long millis) { |
673 | 729 | InterruptionUtil.requestInterruptIn(millis, MILLISECONDS); |
674 | 730 | } |
| 731 | + |
| 732 | + private static class TestCondition implements Condition { |
| 733 | + private final Lock lock; |
| 734 | + private final Condition condition; |
| 735 | + |
| 736 | + private TestCondition(Lock lock, Condition condition) { |
| 737 | + this.lock = lock; |
| 738 | + this.condition = condition; |
| 739 | + } |
| 740 | + |
| 741 | + static TestCondition createAndSignalAfter(long delay, TimeUnit unit) { |
| 742 | + final TestCondition testCondition = create(); |
| 743 | + |
| 744 | + ScheduledExecutorService scheduledPool = Executors.newScheduledThreadPool(1); |
| 745 | + // If signal() fails somehow, we should see a failed test, even without looking at the Future. |
| 746 | + Future<?> unused = |
| 747 | + scheduledPool.schedule( |
| 748 | + new Runnable() { |
| 749 | + @Override |
| 750 | + public void run() { |
| 751 | + testCondition.signal(); |
| 752 | + } |
| 753 | + }, |
| 754 | + delay, |
| 755 | + unit); |
| 756 | + |
| 757 | + return testCondition; |
| 758 | + } |
| 759 | + |
| 760 | + static TestCondition create() { |
| 761 | + Lock lock = new ReentrantLock(); |
| 762 | + Condition condition = lock.newCondition(); |
| 763 | + return new TestCondition(lock, condition); |
| 764 | + } |
| 765 | + |
| 766 | + @Override |
| 767 | + public void await() throws InterruptedException { |
| 768 | + lock.lock(); |
| 769 | + try { |
| 770 | + condition.await(); |
| 771 | + } finally { |
| 772 | + lock.unlock(); |
| 773 | + } |
| 774 | + } |
| 775 | + |
| 776 | + @Override |
| 777 | + public void awaitUninterruptibly() { |
| 778 | + lock.lock(); |
| 779 | + try { |
| 780 | + condition.awaitUninterruptibly(); |
| 781 | + } finally { |
| 782 | + lock.unlock(); |
| 783 | + } |
| 784 | + } |
| 785 | + |
| 786 | + @Override |
| 787 | + public long awaitNanos(long nanosTimeout) throws InterruptedException { |
| 788 | + lock.lock(); |
| 789 | + try { |
| 790 | + return condition.awaitNanos(nanosTimeout); |
| 791 | + } finally { |
| 792 | + lock.unlock(); |
| 793 | + } |
| 794 | + } |
| 795 | + |
| 796 | + @Override |
| 797 | + public boolean await(long time, TimeUnit unit) throws InterruptedException { |
| 798 | + lock.lock(); |
| 799 | + try { |
| 800 | + return condition.await(time, unit); |
| 801 | + } finally { |
| 802 | + lock.unlock(); |
| 803 | + } |
| 804 | + } |
| 805 | + |
| 806 | + @Override |
| 807 | + public boolean awaitUntil(Date deadline) throws InterruptedException { |
| 808 | + lock.lock(); |
| 809 | + try { |
| 810 | + return condition.awaitUntil(deadline); |
| 811 | + } finally { |
| 812 | + lock.unlock(); |
| 813 | + } |
| 814 | + } |
| 815 | + |
| 816 | + @Override |
| 817 | + public void signal() { |
| 818 | + lock.lock(); |
| 819 | + try { |
| 820 | + condition.signal(); |
| 821 | + } finally { |
| 822 | + lock.unlock(); |
| 823 | + } |
| 824 | + } |
| 825 | + |
| 826 | + @Override |
| 827 | + public void signalAll() { |
| 828 | + lock.lock(); |
| 829 | + try { |
| 830 | + condition.signalAll(); |
| 831 | + } finally { |
| 832 | + lock.unlock(); |
| 833 | + } |
| 834 | + } |
| 835 | + } |
675 | 836 | } |
0 commit comments