View Javadoc
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  
38      public TestGuard(boolean satisfied) {
39        super(MonitorTestCase.this.monitor);
40        this.satisfied = satisfied;
41      }
42  
43      @Override public boolean isSatisfied() {
44        return this.satisfied;
45      }
46  
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  
58    protected MonitorTestCase(boolean interruptible) {
59      this.interruptible = interruptible;
60    }
61  
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  
69    @Override protected final void tearDown() {
70      tearDownStack.runTearDown();
71    }
72  
73    private String enter() {
74      return interruptible ? "enterInterruptibly" : "enter";
75    }
76  
77    private String tryEnter() {
78      return "tryEnter";
79    }
80  
81    private String enterIf() {
82      return interruptible ? "enterIfInterruptibly" : "enterIf";
83    }
84  
85    private String tryEnterIf() {
86      return "tryEnterIf";
87    }
88  
89    private String enterWhen() {
90      return interruptible ? "enterWhen" : "enterWhenUninterruptibly";
91    }
92  
93    private String waitFor() {
94      return interruptible ? "waitFor" : "waitForUninterruptibly";
95    }
96  
97    private String leave() {
98      return "leave";
99    }
100 
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 
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 
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 
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 
141   public final void testEnterWhen_initiallyTrue() throws Exception {
142     TestGuard guard = new TestGuard(true);
143     thread1.callAndAssertReturns(enterWhen(), guard);
144   }
145 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
217   public final void testWaitFor_withoutEnter() throws Exception {
218     TestGuard guard = new TestGuard(true);
219     thread1.callAndAssertThrows(IllegalMonitorStateException.class, waitFor(), guard);
220   }
221 
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 }