1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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
56
57
58
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));
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 }