• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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