1 /* 2 * Copyright (C) 2010 The Guava Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.common.util.concurrent; 18 19 import com.google.common.testing.NullPointerTester; 20 import com.google.common.testing.TearDownStack; 21 import java.util.Random; 22 import junit.framework.TestCase; 23 24 /** 25 * Tests for {@link Monitor}, either interruptible or uninterruptible. 26 * 27 * @author Justin T. Sampson 28 */ 29 30 public abstract class MonitorTestCase extends TestCase { 31 32 public class TestGuard extends Monitor.Guard { 33 private volatile boolean satisfied; 34 TestGuard(boolean satisfied)35 public TestGuard(boolean satisfied) { 36 super(MonitorTestCase.this.monitor); 37 this.satisfied = satisfied; 38 } 39 40 @Override isSatisfied()41 public boolean isSatisfied() { 42 return this.satisfied; 43 } 44 setSatisfied(boolean satisfied)45 public void setSatisfied(boolean satisfied) { 46 this.satisfied = satisfied; 47 } 48 } 49 50 private final boolean interruptible; 51 private Monitor monitor; 52 private final TearDownStack tearDownStack = new TearDownStack(true); 53 private TestThread<Monitor> thread1; 54 private TestThread<Monitor> thread2; 55 MonitorTestCase(boolean interruptible)56 protected MonitorTestCase(boolean interruptible) { 57 this.interruptible = interruptible; 58 } 59 60 @Override setUp()61 protected final void setUp() throws Exception { 62 boolean fair = new Random().nextBoolean(); 63 monitor = new Monitor(fair); 64 tearDownStack.addTearDown(thread1 = new TestThread<>(monitor, "TestThread #1")); 65 tearDownStack.addTearDown(thread2 = new TestThread<>(monitor, "TestThread #2")); 66 } 67 68 @Override tearDown()69 protected final void tearDown() { 70 tearDownStack.runTearDown(); 71 } 72 enter()73 private String enter() { 74 return interruptible ? "enterInterruptibly" : "enter"; 75 } 76 tryEnter()77 private String tryEnter() { 78 return "tryEnter"; 79 } 80 enterIf()81 private String enterIf() { 82 return interruptible ? "enterIfInterruptibly" : "enterIf"; 83 } 84 tryEnterIf()85 private String tryEnterIf() { 86 return "tryEnterIf"; 87 } 88 enterWhen()89 private String enterWhen() { 90 return interruptible ? "enterWhen" : "enterWhenUninterruptibly"; 91 } 92 waitFor()93 private String waitFor() { 94 return interruptible ? "waitFor" : "waitForUninterruptibly"; 95 } 96 leave()97 private String leave() { 98 return "leave"; 99 } 100 testMutualExclusion()101 public final void testMutualExclusion() throws Exception { 102 thread1.callAndAssertReturns(enter()); 103 thread2.callAndAssertBlocks(enter()); 104 thread1.callAndAssertReturns(leave()); 105 thread2.assertPriorCallReturns(enter()); 106 } 107 testTryEnter()108 public final void testTryEnter() throws Exception { 109 thread1.callAndAssertReturns(true, tryEnter()); 110 thread2.callAndAssertReturns(false, tryEnter()); 111 thread1.callAndAssertReturns(true, tryEnter()); 112 thread2.callAndAssertReturns(false, tryEnter()); 113 thread1.callAndAssertReturns(leave()); 114 thread2.callAndAssertReturns(false, tryEnter()); 115 thread1.callAndAssertReturns(leave()); 116 thread2.callAndAssertReturns(true, tryEnter()); 117 } 118 testSystemStateMethods()119 public final void testSystemStateMethods() throws Exception { 120 checkSystemStateMethods(0); 121 thread1.callAndAssertReturns(enter()); 122 checkSystemStateMethods(1); 123 thread1.callAndAssertReturns(enter()); 124 checkSystemStateMethods(2); 125 thread1.callAndAssertReturns(leave()); 126 checkSystemStateMethods(1); 127 thread1.callAndAssertReturns(leave()); 128 checkSystemStateMethods(0); 129 } 130 checkSystemStateMethods(int enterCount)131 private void checkSystemStateMethods(int enterCount) throws Exception { 132 thread1.callAndAssertReturns(enterCount != 0, "isOccupied"); 133 thread1.callAndAssertReturns(enterCount != 0, "isOccupiedByCurrentThread"); 134 thread1.callAndAssertReturns(enterCount, "getOccupiedDepth"); 135 136 thread2.callAndAssertReturns(enterCount != 0, "isOccupied"); 137 thread2.callAndAssertReturns(false, "isOccupiedByCurrentThread"); 138 thread2.callAndAssertReturns(0, "getOccupiedDepth"); 139 } 140 testEnterWhen_initiallyTrue()141 public final void testEnterWhen_initiallyTrue() throws Exception { 142 TestGuard guard = new TestGuard(true); 143 thread1.callAndAssertReturns(enterWhen(), guard); 144 // same as above but with the new syntax 145 thread1.callAndAssertReturns(enterWhen(), monitor.newGuard(() -> true)); 146 } 147 testEnterWhen_initiallyFalse()148 public final void testEnterWhen_initiallyFalse() throws Exception { 149 TestGuard guard = new TestGuard(false); 150 thread1.callAndAssertWaits(enterWhen(), guard); 151 monitor.enter(); 152 guard.setSatisfied(true); 153 monitor.leave(); 154 thread1.assertPriorCallReturns(enterWhen()); 155 } 156 testEnterWhen_alreadyOccupied()157 public final void testEnterWhen_alreadyOccupied() throws Exception { 158 TestGuard guard = new TestGuard(true); 159 thread2.callAndAssertReturns(enter()); 160 thread1.callAndAssertBlocks(enterWhen(), guard); 161 thread2.callAndAssertReturns(leave()); 162 thread1.assertPriorCallReturns(enterWhen()); 163 } 164 testEnterIf_initiallyTrue()165 public final void testEnterIf_initiallyTrue() throws Exception { 166 TestGuard guard = new TestGuard(true); 167 thread1.callAndAssertReturns(true, enterIf(), guard); 168 thread2.callAndAssertBlocks(enter()); 169 } 170 testEnterIf_initiallyFalse()171 public final void testEnterIf_initiallyFalse() throws Exception { 172 TestGuard guard = new TestGuard(false); 173 thread1.callAndAssertReturns(false, enterIf(), guard); 174 thread2.callAndAssertReturns(enter()); 175 } 176 testEnterIf_alreadyOccupied()177 public final void testEnterIf_alreadyOccupied() throws Exception { 178 TestGuard guard = new TestGuard(true); 179 thread2.callAndAssertReturns(enter()); 180 thread1.callAndAssertBlocks(enterIf(), guard); 181 thread2.callAndAssertReturns(leave()); 182 thread1.assertPriorCallReturns(true, enterIf()); 183 } 184 testTryEnterIf_initiallyTrue()185 public final void testTryEnterIf_initiallyTrue() throws Exception { 186 TestGuard guard = new TestGuard(true); 187 thread1.callAndAssertReturns(true, tryEnterIf(), guard); 188 thread2.callAndAssertBlocks(enter()); 189 } 190 testTryEnterIf_initiallyFalse()191 public final void testTryEnterIf_initiallyFalse() throws Exception { 192 TestGuard guard = new TestGuard(false); 193 thread1.callAndAssertReturns(false, tryEnterIf(), guard); 194 thread2.callAndAssertReturns(enter()); 195 } 196 testTryEnterIf_alreadyOccupied()197 public final void testTryEnterIf_alreadyOccupied() throws Exception { 198 TestGuard guard = new TestGuard(true); 199 thread2.callAndAssertReturns(enter()); 200 thread1.callAndAssertReturns(false, tryEnterIf(), guard); 201 } 202 testWaitFor_initiallyTrue()203 public final void testWaitFor_initiallyTrue() throws Exception { 204 TestGuard guard = new TestGuard(true); 205 thread1.callAndAssertReturns(enter()); 206 thread1.callAndAssertReturns(waitFor(), guard); 207 } 208 testWaitFor_initiallyFalse()209 public final void testWaitFor_initiallyFalse() throws Exception { 210 TestGuard guard = new TestGuard(false); 211 thread1.callAndAssertReturns(enter()); 212 thread1.callAndAssertWaits(waitFor(), guard); 213 monitor.enter(); 214 guard.setSatisfied(true); 215 monitor.leave(); 216 thread1.assertPriorCallReturns(waitFor()); 217 } 218 testWaitFor_withoutEnter()219 public final void testWaitFor_withoutEnter() throws Exception { 220 TestGuard guard = new TestGuard(true); 221 thread1.callAndAssertThrows(IllegalMonitorStateException.class, waitFor(), guard); 222 } 223 testNulls()224 public void testNulls() { 225 monitor.enter(); // Inhibit IllegalMonitorStateException 226 new NullPointerTester() 227 .setDefault(Monitor.Guard.class, new TestGuard(true)) 228 .testAllPublicInstanceMethods(monitor); 229 } 230 231 // TODO: Test enter(long, TimeUnit). 232 // TODO: Test enterWhen(Guard, long, TimeUnit). 233 // TODO: Test enterIf(Guard, long, TimeUnit). 234 // TODO: Test waitFor(Guard, long, TimeUnit). 235 // TODO: Test getQueueLength(). 236 // TODO: Test hasQueuedThreads(). 237 // TODO: Test getWaitQueueLength(Guard). 238 // TODO: Test automatic signaling before leave, waitFor, and reentrant enterWhen. 239 // TODO: Test blocking to re-enter monitor after being signaled. 240 // TODO: Test interrupts with both interruptible and uninterruptible monitor. 241 // TODO: Test multiple waiters: If guard is still satisfied, signal next waiter. 242 // TODO: Test multiple waiters: If guard is no longer satisfied, do not signal next waiter. 243 244 } 245