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 22 import junit.framework.TestCase; 23 24 import java.util.Random; 25 import java.util.concurrent.TimeUnit; 26 27 /** 28 * Tests for {@link Monitor}, either interruptible or uninterruptible. 29 * 30 * @author Justin T. Sampson 31 */ 32 33 public abstract class MonitorTestCase extends TestCase { 34 35 public class TestGuard extends Monitor.Guard { 36 private volatile boolean satisfied; 37 TestGuard(boolean satisfied)38 public TestGuard(boolean satisfied) { 39 super(MonitorTestCase.this.monitor); 40 this.satisfied = satisfied; 41 } 42 isSatisfied()43 @Override public boolean isSatisfied() { 44 return this.satisfied; 45 } 46 setSatisfied(boolean satisfied)47 public void setSatisfied(boolean satisfied) { 48 this.satisfied = satisfied; 49 } 50 } 51 52 private final boolean interruptible; 53 private Monitor monitor; 54 private final TearDownStack tearDownStack = new TearDownStack(true); 55 private TestThread<Monitor> thread1; 56 private TestThread<Monitor> thread2; 57 MonitorTestCase(boolean interruptible)58 protected MonitorTestCase(boolean interruptible) { 59 this.interruptible = interruptible; 60 } 61 setUp()62 @Override protected final void setUp() throws Exception { 63 boolean fair = new Random().nextBoolean(); 64 monitor = new Monitor(fair); 65 tearDownStack.addTearDown(thread1 = new TestThread<Monitor>(monitor, "TestThread #1")); 66 tearDownStack.addTearDown(thread2 = new TestThread<Monitor>(monitor, "TestThread #2")); 67 } 68 tearDown()69 @Override 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 } 145 testEnterWhen_initiallyFalse()146 public final void testEnterWhen_initiallyFalse() throws Exception { 147 TestGuard guard = new TestGuard(false); 148 thread1.callAndAssertWaits(enterWhen(), guard); 149 monitor.enter(); 150 guard.setSatisfied(true); 151 monitor.leave(); 152 thread1.assertPriorCallReturns(enterWhen()); 153 } 154 testEnterWhen_alreadyOccupied()155 public final void testEnterWhen_alreadyOccupied() throws Exception { 156 TestGuard guard = new TestGuard(true); 157 thread2.callAndAssertReturns(enter()); 158 thread1.callAndAssertBlocks(enterWhen(), guard); 159 thread2.callAndAssertReturns(leave()); 160 thread1.assertPriorCallReturns(enterWhen()); 161 } 162 testEnterIf_initiallyTrue()163 public final void testEnterIf_initiallyTrue() throws Exception { 164 TestGuard guard = new TestGuard(true); 165 thread1.callAndAssertReturns(true, enterIf(), guard); 166 thread2.callAndAssertBlocks(enter()); 167 } 168 testEnterIf_initiallyFalse()169 public final void testEnterIf_initiallyFalse() throws Exception { 170 TestGuard guard = new TestGuard(false); 171 thread1.callAndAssertReturns(false, enterIf(), guard); 172 thread2.callAndAssertReturns(enter()); 173 } 174 testEnterIf_alreadyOccupied()175 public final void testEnterIf_alreadyOccupied() throws Exception { 176 TestGuard guard = new TestGuard(true); 177 thread2.callAndAssertReturns(enter()); 178 thread1.callAndAssertBlocks(enterIf(), guard); 179 thread2.callAndAssertReturns(leave()); 180 thread1.assertPriorCallReturns(true, enterIf()); 181 } 182 testTryEnterIf_initiallyTrue()183 public final void testTryEnterIf_initiallyTrue() throws Exception { 184 TestGuard guard = new TestGuard(true); 185 thread1.callAndAssertReturns(true, tryEnterIf(), guard); 186 thread2.callAndAssertBlocks(enter()); 187 } 188 testTryEnterIf_initiallyFalse()189 public final void testTryEnterIf_initiallyFalse() throws Exception { 190 TestGuard guard = new TestGuard(false); 191 thread1.callAndAssertReturns(false, tryEnterIf(), guard); 192 thread2.callAndAssertReturns(enter()); 193 } 194 testTryEnterIf_alreadyOccupied()195 public final void testTryEnterIf_alreadyOccupied() throws Exception { 196 TestGuard guard = new TestGuard(true); 197 thread2.callAndAssertReturns(enter()); 198 thread1.callAndAssertReturns(false, tryEnterIf(), guard); 199 } 200 testWaitFor_initiallyTrue()201 public final void testWaitFor_initiallyTrue() throws Exception { 202 TestGuard guard = new TestGuard(true); 203 thread1.callAndAssertReturns(enter()); 204 thread1.callAndAssertReturns(waitFor(), guard); 205 } 206 testWaitFor_initiallyFalse()207 public final void testWaitFor_initiallyFalse() throws Exception { 208 TestGuard guard = new TestGuard(false); 209 thread1.callAndAssertReturns(enter()); 210 thread1.callAndAssertWaits(waitFor(), guard); 211 monitor.enter(); 212 guard.setSatisfied(true); 213 monitor.leave(); 214 thread1.assertPriorCallReturns(waitFor()); 215 } 216 testWaitFor_withoutEnter()217 public final void testWaitFor_withoutEnter() throws Exception { 218 TestGuard guard = new TestGuard(true); 219 thread1.callAndAssertThrows(IllegalMonitorStateException.class, waitFor(), guard); 220 } 221 testNulls()222 public void testNulls() { 223 monitor.enter(); // Inhibit IllegalMonitorStateException 224 new NullPointerTester() 225 .setDefault(TimeUnit.class, TimeUnit.SECONDS) 226 .setDefault(Monitor.Guard.class, new TestGuard(true)) 227 .testAllPublicInstanceMethods(monitor); 228 } 229 230 // TODO: Test enter(long, TimeUnit). 231 // TODO: Test enterWhen(Guard, long, TimeUnit). 232 // TODO: Test enterIf(Guard, long, TimeUnit). 233 // TODO: Test waitFor(Guard, long, TimeUnit). 234 // TODO: Test getQueueLength(). 235 // TODO: Test hasQueuedThreads(). 236 // TODO: Test getWaitQueueLength(Guard). 237 // TODO: Test automatic signaling before leave, waitFor, and reentrant enterWhen. 238 // TODO: Test blocking to re-enter monitor after being signaled. 239 // TODO: Test interrupts with both interruptible and uninterruptible monitor. 240 // TODO: Test multiple waiters: If guard is still satisfied, signal next waiter. 241 // TODO: Test multiple waiters: If guard is no longer satisfied, do not signal next waiter. 242 243 } 244