View Javadoc

1   // Copyright (C) 2003 - 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.communication;
23  
24  import static org.junit.Assert.assertEquals;
25  import static org.junit.Assert.assertNull;
26  import static org.junit.Assert.assertSame;
27  import static org.junit.Assert.assertTrue;
28  import static org.mockito.Mockito.mock;
29  import static org.mockito.Mockito.verify;
30  import static org.mockito.Mockito.verifyNoMoreInteractions;
31  
32  import java.util.List;
33  import java.util.concurrent.CyclicBarrier;
34  
35  import net.grinder.common.UncheckedInterruptedException;
36  import net.grinder.communication.ResourcePool.Listener;
37  
38  import org.junit.Test;
39  
40  
41  /**
42   *  Unit test case for {@code ResourcePool}.
43   *
44   * @author Philip Aston
45   */
46  public class TestResourcePool {
47  
48    @Test public void testConstructorAndSentinel() throws Exception {
49  
50      final ResourcePool resourcePool = new ResourcePoolImplementation();
51  
52      final ResourcePool.Reservation reservation = resourcePool.reserveNext();
53      assertTrue(reservation.isSentinel());
54  
55      // Reserving the Sentinel is a no-op, so we can reserve it as
56      // often as we like.
57      final ResourcePool.Reservation reservation2 = resourcePool.reserveNext();
58      assertTrue(reservation2.isSentinel());
59  
60      // free() and close() are also no-ops.
61      reservation2.free();
62      reservation2.close();
63  
64      assertTrue(!reservation2.isClosed());
65  
66      final ResourcePool.Reservation reservation3 = resourcePool.reserveNext();
67      assertTrue(reservation3.isSentinel());
68  
69      // Sentinel doesn't have a resource.
70      assertNull(reservation3.getResource());
71    }
72  
73    @Test public void testAddAndReserveNext() throws Exception {
74  
75      final ResourcePool resourcePool = new ResourcePoolImplementation();
76  
77      final Listener listener1 = mock(ResourcePool.Listener.class);
78      final Listener listener2 = mock(ResourcePool.Listener.class);
79  
80      resourcePool.addListener(listener1);
81      resourcePool.addListener(listener2);
82  
83      final MyResource resource1 = new MyResource();
84      final MyResource resource2 = new MyResource();
85  
86      resourcePool.add(resource1);
87      resourcePool.add(resource2);
88  
89      verify(listener1).resourceAdded(resource1);
90      verify(listener1).resourceAdded(resource2);
91  
92      verify(listener2).resourceAdded(resource1);
93      verify(listener2).resourceAdded(resource2);
94  
95      final ResourcePool.Reservation reservation1 = resourcePool.reserveNext();
96      final ResourcePool.Reservation reservation2 = resourcePool.reserveNext();
97      final ResourcePool.Reservation sentinel = resourcePool.reserveNext();
98  
99      assertTrue(!reservation1.isSentinel());
100     assertTrue(!reservation2.isSentinel());
101     assertTrue(sentinel.isSentinel());
102     assertTrue(resourcePool.reserveNext().isSentinel());
103 
104     if (resource1.equals(reservation1.getResource())) {
105       assertEquals(resource1, reservation1.getResource());
106       assertEquals(resource2, reservation2.getResource());
107     }
108     else {
109       assertEquals(resource1, reservation2.getResource());
110       assertEquals(resource2, reservation1.getResource());
111     }
112 
113     reservation2.free();
114     assertSame(reservation2, resourcePool.reserveNext());
115 
116     assertSame(sentinel, resourcePool.reserveNext());
117 
118     reservation1.free();
119     assertSame(reservation1, resourcePool.reserveNext());
120 
121     reservation1.free();
122     reservation2.free();
123 
124     // Exercise reserveNext many times to trigger zombie managment -
125     // this time round, nothing should be purged.
126     for (int i = 0; i < 1100; ++i) {
127       resourcePool.reserveNext().free();
128     }
129 
130     assertEquals(2, resourcePool.countActive());
131 
132     reservation2.close();
133     assertTrue(reservation2.isClosed());
134     assertSame(sentinel, resourcePool.reserveNext());
135 
136     verify(listener1).resourceClosed(resource2);
137     verify(listener2).resourceClosed(resource2);
138 
139     assertTrue(!resource1.isClosed());
140     assertTrue(resource2.isClosed());
141 
142     for (int i = 0; i < 1100; ++i) {
143       resourcePool.reserveNext().free();
144     }
145 
146     assertEquals(1, resourcePool.countActive());
147 
148     verifyNoMoreInteractions(listener1, listener2);
149   }
150 
151   @Test public void testReserveAll() throws Exception {
152 
153     final ResourcePool resourcePool = new ResourcePoolImplementation();
154     assertEquals(0, resourcePool.reserveAll().size());
155     assertEquals(0, resourcePool.reserveAll().size());
156 
157     final MyResource resource1 = new MyResource();
158     final MyResource resource2 = new MyResource();
159 
160     resourcePool.add(resource1);
161     resourcePool.add(resource2);
162 
163     final List<?> reservations = resourcePool.reserveAll();
164     assertEquals(2, reservations.size());
165 
166     final ResourcePool.Reservation reservation1 =
167       (ResourcePool.Reservation)reservations.get(0);
168 
169     final ResourcePool.Reservation reservation2 =
170       (ResourcePool.Reservation)reservations.get(1);
171 
172     if (resource1.equals(reservation1.getResource())) {
173       assertEquals(resource1, reservation1.getResource());
174       assertEquals(resource2, reservation2.getResource());
175     }
176     else {
177       assertEquals(resource1, reservation2.getResource());
178       assertEquals(resource2, reservation1.getResource());
179     }
180 
181     assertTrue(!reservation1.isSentinel());
182     reservation1.free();
183 
184     assertTrue(!reservation2.isSentinel());
185     reservation2.free();
186 
187     final List<?> reservations2 = resourcePool.reserveAll();
188     assertEquals(2, reservations2.size());
189 
190     ((ResourcePool.Reservation)reservations2.get(0)).free();
191 
192     assertEquals(
193       UncheckedInterruptedException.class,
194       new BlockingActionThread() {
195         protected void blockingAction() throws InterruptedException {
196           resourcePool.reserveAll();
197         }
198       }.getException().getClass());
199   }
200 
201   @Test public void testReserveAllMultiThreaded() throws Exception {
202     final ResourcePool resourcePool = new ResourcePoolImplementation();
203 
204     resourcePool.add(new MyResource());
205     resourcePool.add(new MyResource());
206     resourcePool.add(new MyResource());
207     resourcePool.add(new MyResource());
208     resourcePool.add(new MyResource());
209 
210     final CyclicBarrier barrier = new CyclicBarrier(20);
211 
212     class ReserveAll implements Runnable {
213       public void run() {
214         try {
215           barrier.await();
216         }
217         catch (Exception e) {
218         }
219 
220         for (int i = 0; i < 50; ++i) {
221           final List<? extends ResourcePool.Reservation> list =
222             resourcePool.reserveAll();
223 
224           assert list.size() == 5;
225 
226           for (ResourcePool.Reservation reservation : list) {
227             reservation.free();
228           }
229         }
230       }
231     }
232 
233     final Thread[] threads = new Thread[barrier.getParties()];
234 
235     for (int i = 0; i<threads.length; ++i) {
236       threads[i] = new Thread(new ReserveAll());
237     }
238 
239     for (int i = 0; i<threads.length; ++i) {
240       threads[i].start();
241     }
242 
243     for (int i=0; i<threads.length; ++i) {
244       threads[i].join();
245     }
246   }
247 
248   @Test public void testClose() throws Exception {
249 
250     final ResourcePool resourcePool = new ResourcePoolImplementation();
251     assertEquals(0, resourcePool.reserveAll().size());
252     assertEquals(0, resourcePool.reserveAll().size());
253 
254     final Listener listener = mock(ResourcePool.Listener.class);
255 
256     final MyResource resource1 = new MyResource();
257     final MyResource resource2 = new MyResource();
258 
259     resourcePool.addListener(listener);
260 
261     resourcePool.add(resource1);
262     resourcePool.add(resource2);
263 
264     verify(listener).resourceAdded(resource1);
265     verify(listener).resourceAdded(resource2);
266 
267     final List<?> reservations = resourcePool.reserveAll();
268     assertEquals(2, reservations.size());
269 
270     ((ResourcePool.Reservation)reservations.get(1)).free();
271 
272     resourcePool.closeCurrentResources();
273 
274     verify(listener).resourceClosed(resource1);
275     verify(listener).resourceClosed(resource2);
276 
277     final List<?> reservations2 = resourcePool.reserveAll();
278     assertEquals(0, reservations2.size());
279 
280     assertTrue(resource1.isClosed());
281     assertTrue(resource2.isClosed());
282 
283     verifyNoMoreInteractions(listener);
284   }
285 
286   @Test public void testCountActive() throws Exception {
287 
288     final ResourcePool resourcePool = new ResourcePoolImplementation();
289     assertEquals(0, resourcePool.countActive());
290 
291     final MyResource resource1 = new MyResource();
292     final MyResource resource2 = new MyResource();
293 
294     resourcePool.add(resource1);
295     assertEquals(1, resourcePool.countActive());
296 
297     resourcePool.add(resource2);
298     assertEquals(2, resourcePool.countActive());
299 
300     final List<?> reservations = resourcePool.reserveAll();
301     assertEquals(2, resourcePool.countActive());
302 
303     ((ResourcePool.Reservation)reservations.get(1)).close();
304     assertEquals(1, resourcePool.countActive());
305 
306     ((ResourcePool.Reservation)reservations.get(0)).close();
307     assertEquals(0, resourcePool.countActive());
308   }
309 
310   private static class MyResource implements ResourcePool.Resource {
311 
312     private boolean m_closed = false;
313 
314     public void close() {
315       m_closed = true;
316     }
317 
318     public boolean isClosed() {
319       return m_closed;
320     }
321   }
322 }