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 public abstract class MonitorTestCase extends TestCase { 30 31 public class TestGuard extends Monitor.Guard { 32 private volatile boolean satisfied; 33 TestGuard(boolean satisfied)34 public TestGuard(boolean satisfied) { 35 super(MonitorTestCase.this.monitor); 36 this.satisfied = satisfied; 37 } 38 39 @Override isSatisfied()40 public boolean isSatisfied() { 41 return this.satisfied; 42 } 43 setSatisfied(boolean satisfied)44 public void setSatisfied(boolean satisfied) { 45 this.satisfied = satisfied; 46 } 47 } 48 49 private final boolean interruptible; 50 private Monitor monitor; 51 private final TearDownStack tearDownStack = new TearDownStack(true); 52 private TestThread<Monitor> thread1; 53 private TestThread<Monitor> thread2; 54 MonitorTestCase(boolean interruptible)55 protected MonitorTestCase(boolean interruptible) { 56 this.interruptible = interruptible; 57 } 58 59 @Override setUp()60 protected final void setUp() throws Exception { 61 boolean fair = new Random().nextBoolean(); 62 monitor = new Monitor(fair); 63 tearDownStack.addTearDown(thread1 = new TestThread<>(monitor, "TestThread #1")); 64 tearDownStack.addTearDown(thread2 = new TestThread<>(monitor, "TestThread #2")); 65 } 66 67 @Override tearDown()68 protected final void tearDown() { 69 tearDownStack.runTearDown(); 70 } 71 enter()72 private String enter() { 73 return interruptible ? "enterInterruptibly" : "enter"; 74 } 75 tryEnter()76 private String tryEnter() { 77 return "tryEnter"; 78 } 79 enterIf()80 private String enterIf() { 81 return interruptible ? "enterIfInterruptibly" : "enterIf"; 82 } 83 tryEnterIf()84 private String tryEnterIf() { 85 return "tryEnterIf"; 86 } 87 enterWhen()88 private String enterWhen() { 89 return interruptible ? "enterWhen" : "enterWhenUninterruptibly"; 90 } 91 waitFor()92 private String waitFor() { 93 return interruptible ? "waitFor" : "waitForUninterruptibly"; 94 } 95 leave()96 private String leave() { 97 return "leave"; 98 } 99 testMutualExclusion()100 public final void testMutualExclusion() throws Exception { 101 thread1.callAndAssertReturns(enter()); 102 thread2.callAndAssertBlocks(enter()); 103 thread1.callAndAssertReturns(leave()); 104 thread2.assertPriorCallReturns(enter()); 105 } 106 testTryEnter()107 public final void testTryEnter() throws Exception { 108 thread1.callAndAssertReturns(true, tryEnter()); 109 thread2.callAndAssertReturns(false, tryEnter()); 110 thread1.callAndAssertReturns(true, tryEnter()); 111 thread2.callAndAssertReturns(false, tryEnter()); 112 thread1.callAndAssertReturns(leave()); 113 thread2.callAndAssertReturns(false, tryEnter()); 114 thread1.callAndAssertReturns(leave()); 115 thread2.callAndAssertReturns(true, tryEnter()); 116 } 117 testSystemStateMethods()118 public final void testSystemStateMethods() throws Exception { 119 checkSystemStateMethods(0); 120 thread1.callAndAssertReturns(enter()); 121 checkSystemStateMethods(1); 122 thread1.callAndAssertReturns(enter()); 123 checkSystemStateMethods(2); 124 thread1.callAndAssertReturns(leave()); 125 checkSystemStateMethods(1); 126 thread1.callAndAssertReturns(leave()); 127 checkSystemStateMethods(0); 128 } 129 checkSystemStateMethods(int enterCount)130 private void checkSystemStateMethods(int enterCount) throws Exception { 131 thread1.callAndAssertReturns(enterCount != 0, "isOccupied"); 132 thread1.callAndAssertReturns(enterCount != 0, "isOccupiedByCurrentThread"); 133 thread1.callAndAssertReturns(enterCount, "getOccupiedDepth"); 134 135 thread2.callAndAssertReturns(enterCount != 0, "isOccupied"); 136 thread2.callAndAssertReturns(false, "isOccupiedByCurrentThread"); 137 thread2.callAndAssertReturns(0, "getOccupiedDepth"); 138 } 139 testEnterWhen_initiallyTrue()140 public final void testEnterWhen_initiallyTrue() throws Exception { 141 TestGuard guard = new TestGuard(true); 142 thread1.callAndAssertReturns(enterWhen(), guard); 143 // same as above but with the new syntax 144 thread1.callAndAssertReturns(enterWhen(), monitor.newGuard(() -> true)); 145 } 146 testEnterWhen_initiallyFalse()147 public final void testEnterWhen_initiallyFalse() throws Exception { 148 TestGuard guard = new TestGuard(false); 149 thread1.callAndAssertWaits(enterWhen(), guard); 150 monitor.enter(); 151 guard.setSatisfied(true); 152 monitor.leave(); 153 thread1.assertPriorCallReturns(enterWhen()); 154 } 155 testEnterWhen_alreadyOccupied()156 public final void testEnterWhen_alreadyOccupied() throws Exception { 157 TestGuard guard = new TestGuard(true); 158 thread2.callAndAssertReturns(enter()); 159 thread1.callAndAssertBlocks(enterWhen(), guard); 160 thread2.callAndAssertReturns(leave()); 161 thread1.assertPriorCallReturns(enterWhen()); 162 } 163 testEnterIf_initiallyTrue()164 public final void testEnterIf_initiallyTrue() throws Exception { 165 TestGuard guard = new TestGuard(true); 166 thread1.callAndAssertReturns(true, enterIf(), guard); 167 thread2.callAndAssertBlocks(enter()); 168 } 169 testEnterIf_initiallyFalse()170 public final void testEnterIf_initiallyFalse() throws Exception { 171 TestGuard guard = new TestGuard(false); 172 thread1.callAndAssertReturns(false, enterIf(), guard); 173 thread2.callAndAssertReturns(enter()); 174 } 175 testEnterIf_alreadyOccupied()176 public final void testEnterIf_alreadyOccupied() throws Exception { 177 TestGuard guard = new TestGuard(true); 178 thread2.callAndAssertReturns(enter()); 179 thread1.callAndAssertBlocks(enterIf(), guard); 180 thread2.callAndAssertReturns(leave()); 181 thread1.assertPriorCallReturns(true, enterIf()); 182 } 183 testTryEnterIf_initiallyTrue()184 public final void testTryEnterIf_initiallyTrue() throws Exception { 185 TestGuard guard = new TestGuard(true); 186 thread1.callAndAssertReturns(true, tryEnterIf(), guard); 187 thread2.callAndAssertBlocks(enter()); 188 } 189 testTryEnterIf_initiallyFalse()190 public final void testTryEnterIf_initiallyFalse() throws Exception { 191 TestGuard guard = new TestGuard(false); 192 thread1.callAndAssertReturns(false, tryEnterIf(), guard); 193 thread2.callAndAssertReturns(enter()); 194 } 195 testTryEnterIf_alreadyOccupied()196 public final void testTryEnterIf_alreadyOccupied() throws Exception { 197 TestGuard guard = new TestGuard(true); 198 thread2.callAndAssertReturns(enter()); 199 thread1.callAndAssertReturns(false, tryEnterIf(), guard); 200 } 201 testWaitFor_initiallyTrue()202 public final void testWaitFor_initiallyTrue() throws Exception { 203 TestGuard guard = new TestGuard(true); 204 thread1.callAndAssertReturns(enter()); 205 thread1.callAndAssertReturns(waitFor(), guard); 206 } 207 testWaitFor_initiallyFalse()208 public final void testWaitFor_initiallyFalse() throws Exception { 209 TestGuard guard = new TestGuard(false); 210 thread1.callAndAssertReturns(enter()); 211 thread1.callAndAssertWaits(waitFor(), guard); 212 monitor.enter(); 213 guard.setSatisfied(true); 214 monitor.leave(); 215 thread1.assertPriorCallReturns(waitFor()); 216 } 217 testWaitFor_withoutEnter()218 public final void testWaitFor_withoutEnter() throws Exception { 219 TestGuard guard = new TestGuard(true); 220 thread1.callAndAssertThrows(IllegalMonitorStateException.class, waitFor(), guard); 221 } 222 testNulls()223 public void testNulls() { 224 monitor.enter(); // Inhibit IllegalMonitorStateException 225 new NullPointerTester() 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