View Javadoc

1   // Copyright (C) 2011 Philip Aston
2   // All rights reserved.
3   //
4   // This file is part of The Grinder software distribution. Refer to
5   // the file LICENSE which is part of The Grinder distribution for
6   // licensing details. The Grinder distribution is available on the
7   // Internet at http://grinder.sourceforge.net/
8   //
9   // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
10  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
11  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
12  // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
13  // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
14  // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
15  // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
16  // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
17  // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
18  // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
19  // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
20  // OF THE POSSIBILITY OF SUCH DAMAGE.
21  
22  package net.grinder.synchronisation;
23  
24  import static java.util.Collections.singleton;
25  import static org.junit.Assert.assertEquals;
26  import static org.junit.Assert.assertFalse;
27  import static org.junit.Assert.fail;
28  import static org.mockito.Mockito.doAnswer;
29  import static org.mockito.Mockito.reset;
30  import static org.mockito.Mockito.verify;
31  import static org.mockito.Mockito.verifyNoMoreInteractions;
32  import static org.mockito.Mockito.when;
33  
34  import java.util.concurrent.Callable;
35  import java.util.concurrent.CyclicBarrier;
36  import java.util.concurrent.ExecutorService;
37  import java.util.concurrent.Executors;
38  import java.util.concurrent.Future;
39  import java.util.concurrent.TimeUnit;
40  
41  import net.grinder.common.UncheckedInterruptedException;
42  import net.grinder.script.CancelledBarrierException;
43  import net.grinder.synchronisation.messages.BarrierIdentity;
44  
45  import org.junit.AfterClass;
46  import org.junit.Before;
47  import org.junit.Test;
48  import org.mockito.Mock;
49  import org.mockito.MockitoAnnotations;
50  import org.mockito.invocation.InvocationOnMock;
51  import org.mockito.stubbing.Answer;
52  
53  
54  /**
55   * Unit tests for {@link BarrierImplementation}.
56   *
57   * @author Philip Aston
58   * @version $Revision:$
59   */
60  public class TestBarrierImplementation {
61  
62    private final static ExecutorService m_executor =
63      Executors.newCachedThreadPool();
64  
65    private static final BarrierIdentity ID1 = new BarrierIdentity() {};
66    private static final BarrierIdentity ID2 = new BarrierIdentity() {};
67    private static final BarrierIdentity ID3 = new BarrierIdentity() {};
68  
69    private @Mock BarrierGroup m_barrierGroup;
70    private @Mock BarrierIdentity.Factory m_identityFactory;
71  
72    @Before public void setUp() {
73      MockitoAnnotations.initMocks(this);
74  
75      when(m_identityFactory.next()).thenReturn(ID1, ID2, ID3);
76    }
77  
78    @AfterClass public static void tearDownClass() {
79      m_executor.shutdown();
80    }
81  
82    @Test public void testConstruction() throws Exception {
83      final BarrierImplementation b =
84        new BarrierImplementation(m_barrierGroup, m_identityFactory);
85  
86      verify(m_barrierGroup).addListener(b);
87      verify(m_barrierGroup).addBarrier();
88  
89      verifyNoMoreInteractions(m_barrierGroup);
90    }
91  
92    @Test public void testGetGroupName() throws Exception {
93      final BarrierImplementation b =
94        new BarrierImplementation(m_barrierGroup, m_identityFactory);
95  
96      when(m_barrierGroup.getName()).thenReturn("mygroup");
97  
98      assertEquals("mygroup", b.getName());
99    }
100 
101   @Test public void testAwaitTimeout() throws Exception {
102     final BarrierImplementation b =
103       new BarrierImplementation(m_barrierGroup, m_identityFactory);
104     reset(m_barrierGroup);
105 
106     final boolean result = b.await(1, TimeUnit.MICROSECONDS);
107 
108     verify(m_barrierGroup).addWaiter(ID2);
109     verify(m_barrierGroup).cancelWaiter(ID2);
110     verify(m_barrierGroup).removeBarriers(1);
111     verify(m_barrierGroup).removeListener(b);
112 
113     verifyNoMoreInteractions(m_barrierGroup);
114 
115     assertFalse(result);
116   }
117 
118   @Test public void testAwaitTimeout2() throws Exception {
119     final BarrierImplementation b =
120       new BarrierImplementation(m_barrierGroup, m_identityFactory);
121     reset(m_barrierGroup);
122 
123     final boolean result = b.await(1);
124 
125     verify(m_barrierGroup).addWaiter(ID2);
126 
127     verify(m_barrierGroup).addWaiter(ID2);
128     verify(m_barrierGroup).cancelWaiter(ID2);
129     verify(m_barrierGroup).removeBarriers(1);
130     verify(m_barrierGroup).removeListener(b);
131 
132     verifyNoMoreInteractions(m_barrierGroup);
133 
134     assertFalse(result);
135   }
136 
137   @Test public void testAwaitInterrupted() throws Exception {
138     final BarrierImplementation b =
139       new BarrierImplementation(m_barrierGroup, m_identityFactory);
140 
141     final CyclicBarrier sync = new CyclicBarrier(2);
142     final Thread mainThread = Thread.currentThread();
143 
144     final Future<Void> future = m_executor.submit(
145       new Callable<Void>() {
146         public Void call() throws Exception {
147           sync.await();
148           mainThread.interrupt();
149           return null;
150         }
151       });
152 
153     sync.await();
154 
155     try {
156       b.await();
157       fail("Expected UncheckedInterruptedException");
158     }
159     catch (UncheckedInterruptedException e) {
160     }
161 
162     future.get();
163   }
164 
165   @Test public void testAwaitTimeoutInterrupted() throws Exception {
166     final BarrierImplementation b =
167       new BarrierImplementation(m_barrierGroup, m_identityFactory);
168 
169     reset(m_barrierGroup);
170 
171     Thread.currentThread().interrupt();
172 
173     try {
174       b.await(123456);
175       fail("Expected UncheckedInterruptedException");
176     }
177     catch (UncheckedInterruptedException e) {
178     }
179 
180     verify(m_barrierGroup).addWaiter(ID2);
181     verify(m_barrierGroup).cancelWaiter(ID2);
182     verify(m_barrierGroup).removeBarriers(1);
183     verify(m_barrierGroup).removeListener(b);
184 
185     verifyNoMoreInteractions(m_barrierGroup);
186   }
187 
188   @Test public void testAwaitHappyCase() throws Exception {
189     final BarrierImplementation b =
190       new BarrierImplementation(m_barrierGroup, m_identityFactory);
191     reset(m_barrierGroup);
192 
193     final Future<?>[] futureHolder = { null };
194 
195     doAnswer(new Answer<Void>() {
196       public Void answer(InvocationOnMock invocation) throws Throwable {
197         futureHolder[0] = m_executor.submit(new Callable<Void>() {
198           public Void call() throws Exception {
199             b.awaken(singleton(ID1));
200             b.awaken(singleton(ID2));
201             return null;
202           }});
203 
204         return null;
205       }}).when(m_barrierGroup).addWaiter(ID2);
206 
207     b.await();
208 
209     verify(m_barrierGroup).addWaiter(ID2);
210     verifyNoMoreInteractions(m_barrierGroup);
211 
212     futureHolder[0].get();
213   }
214 
215   @Test public void testConcurrentAwaitDisalllowedThenCancelWaiter()
216     throws Exception {
217 
218     final BarrierImplementation b =
219       new BarrierImplementation(m_barrierGroup, m_identityFactory);
220     reset(m_barrierGroup);
221 
222     final Future<?>[] futureHolder = { null };
223 
224     doAnswer(new Answer<Void>() {
225       public Void answer(InvocationOnMock invocation) throws Throwable {
226         futureHolder[0] = m_executor.submit(new Callable<Void>() {
227           public Void call() throws Exception {
228             try {
229               b.await();
230               fail("Expected IllegalStateException");
231             }
232             catch (IllegalStateException e) {
233             }
234             finally {
235               b.cancel();
236             }
237 
238             return null;
239           }});
240 
241         return null;
242       }}).when(m_barrierGroup).addWaiter(ID2);
243 
244     try {
245       b.await();
246       fail("Expected CancelledBarrierException");
247     }
248     catch (CancelledBarrierException e) {
249     }
250 
251     verify(m_barrierGroup).addWaiter(ID2);
252     verify(m_barrierGroup).cancelWaiter(ID2);
253     verify(m_barrierGroup).removeBarriers(1);
254     verify(m_barrierGroup).removeListener(b);
255     verifyNoMoreInteractions(m_barrierGroup);
256 
257     futureHolder[0].get();
258   }
259 
260   @Test public void testCancelVirginBarrier() throws Exception {
261     final BarrierImplementation b =
262       new BarrierImplementation(m_barrierGroup, m_identityFactory);
263     reset(m_barrierGroup);
264 
265     b.cancel();
266 
267     verify(m_barrierGroup).cancelWaiter(ID1);
268     verify(m_barrierGroup).removeBarriers(1);
269     verify(m_barrierGroup).removeListener(b);
270 
271     verifyNoMoreInteractions(m_barrierGroup);
272 
273     b.cancel();
274     verifyNoMoreInteractions(m_barrierGroup);
275   }
276 
277   @Test public void testUseCancelledBarrier() throws Exception {
278     final BarrierImplementation b =
279       new BarrierImplementation(m_barrierGroup, m_identityFactory);
280     b.cancel();
281     reset(m_barrierGroup);
282 
283     try {
284       b.await();
285       fail("Expected CancelledBarrierException");
286     }
287     catch(CancelledBarrierException e) {
288     }
289   }
290 
291   @Test public void testCancelWaiterThenAwaken() throws Exception {
292 
293     final BarrierImplementation b =
294       new BarrierImplementation(m_barrierGroup, m_identityFactory);
295     reset(m_barrierGroup);
296 
297     final Future<?>[] futureHolder = { null };
298 
299     doAnswer(new Answer<Void>() {
300       public Void answer(InvocationOnMock invocation) throws Throwable {
301         futureHolder[0] = m_executor.submit(new Callable<Void>() {
302           public Void call() throws Exception {
303             b.cancel();
304 
305             b.awaken(singleton(ID2)); // No-op.
306 
307             return null;
308           }});
309 
310         return null;
311       }}).when(m_barrierGroup).addWaiter(ID2);
312 
313     try {
314       b.await();
315       fail("Expected CancelledBarrierException");
316     }
317     catch (CancelledBarrierException e) {
318     }
319 
320     verify(m_barrierGroup).addWaiter(ID2);
321     verify(m_barrierGroup).cancelWaiter(ID2);
322     verify(m_barrierGroup).removeBarriers(1);
323     verify(m_barrierGroup).removeListener(b);
324     verifyNoMoreInteractions(m_barrierGroup);
325 
326     futureHolder[0].get();
327   }
328 
329   @Test public void testCancelTimedWaiter() throws Exception {
330 
331     final BarrierImplementation b =
332       new BarrierImplementation(m_barrierGroup, m_identityFactory);
333     reset(m_barrierGroup);
334 
335     final Future<?>[] futureHolder = { null };
336 
337     doAnswer(new Answer<Void>() {
338       public Void answer(InvocationOnMock invocation) throws Throwable {
339         futureHolder[0] = m_executor.submit(new Callable<Void>() {
340           public Void call() throws Exception {
341             b.cancel();
342             return null;
343           }});
344 
345         return null;
346       }}).when(m_barrierGroup).addWaiter(ID2);
347 
348     try {
349       b.await(2, TimeUnit.DAYS);
350       fail("Expected CancelledBarrierException");
351     }
352     catch (CancelledBarrierException e) {
353     }
354   }
355 }