• 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 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