View Javadoc

1   // Copyright (C) 2008 - 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.engine.process;
23  
24  import static org.junit.Assert.assertEquals;
25  import static org.junit.Assert.assertFalse;
26  import static org.junit.Assert.assertNotNull;
27  import static org.junit.Assert.assertNotSame;
28  import static org.junit.Assert.assertNull;
29  import static org.junit.Assert.assertSame;
30  import static org.junit.Assert.assertTrue;
31  import static org.junit.Assert.fail;
32  import static org.mockito.Mockito.mock;
33  import static org.mockito.Mockito.times;
34  import static org.mockito.Mockito.verify;
35  import static org.mockito.Mockito.when;
36  
37  import java.util.concurrent.Callable;
38  import java.util.concurrent.ExecutorService;
39  import java.util.concurrent.Executors;
40  import java.util.concurrent.Future;
41  
42  import net.grinder.common.ThreadLifeCycleListener;
43  import net.grinder.communication.QueuedSender;
44  import net.grinder.engine.process.GrinderProcess.ThreadContexts;
45  import net.grinder.engine.process.GrinderProcess.ThreadSynchronisation;
46  import net.grinder.engine.process.GrinderProcess.Times;
47  import net.grinder.script.InvalidContextException;
48  import net.grinder.util.thread.Condition;
49  
50  import org.junit.AfterClass;
51  import org.junit.Test;
52  import org.mockito.ArgumentCaptor;
53  
54  
55  /**
56   * Unit tests for {@link GrinderProcess}
57   *
58   * @author Philip Aston
59   */
60  public class TestGrinderProcess {
61    private static final ExecutorService s_executor =
62      Executors.newCachedThreadPool();
63  
64    @AfterClass public static void shutdown() {
65      s_executor.shutdown();
66    }
67  
68    @Test public void testThreadSynchronisationZeroThreads() throws Exception {
69      final Condition c = new Condition();
70  
71      final ThreadSynchronisation ts =
72        new GrinderProcess.ThreadSynchronisation(c);
73  
74      assertEquals(0, ts.getTotalNumberOfThreads());
75      assertEquals(0, ts.getNumberOfRunningThreads());
76      assertTrue(ts.isReadyToStart());
77      assertTrue(ts.isFinished());
78  
79      ts.startThreads();
80      ts.awaitStart();
81    }
82  
83    @Test public void testThreadSynchronisationNThreads() throws Exception {
84      final Condition c = new Condition();
85      final Thread[] threads = new Thread[100];
86  
87      final ThreadSynchronisation ts =
88        new GrinderProcess.ThreadSynchronisation(c);
89  
90      for (int i = 0; i < threads.length; ++i) {
91        threads[i] = new Thread(new MyRunnable(ts, i % 3 == 0));
92      }
93  
94      assertEquals(100, ts.getTotalNumberOfThreads());
95      assertEquals(100, ts.getNumberOfRunningThreads());
96      assertFalse(ts.isReadyToStart());
97      assertFalse(ts.isFinished());
98  
99      for (int i = 0; i < threads.length; ++i) {
100       threads[i].start();
101     }
102 
103     ts.startThreads();
104 
105     synchronized (c) {
106       while (!ts.isFinished()) {
107         c.waitNoInterrruptException();
108       }
109     }
110 
111     assertTrue(ts.isFinished());
112     assertEquals(0, ts.getNumberOfRunningThreads());
113     assertEquals(100, ts.getTotalNumberOfThreads());
114   }
115 
116   private static class MyRunnable implements Runnable {
117     private final ThreadSynchronisation m_ts;
118     private final boolean m_failBeforeStart;
119 
120     public MyRunnable(ThreadSynchronisation ts, boolean failBeforeStart) {
121       m_ts = ts;
122       m_failBeforeStart = failBeforeStart;
123       ts.threadCreated();
124     }
125 
126     public void run() {
127       shortSleep();
128 
129       if (m_failBeforeStart) {
130         m_ts.threadFinished();
131       }
132       else {
133         m_ts.awaitStart();
134 
135         shortSleep();
136 
137         m_ts.threadFinished();
138       }
139     }
140 
141     private void shortSleep() {
142       try {
143         Thread.sleep(10);
144       }
145       catch (InterruptedException e) {
146       }
147     }
148   }
149 
150   @Test public void testTimes() {
151     final Times times = new Times();
152     assertNotNull(times.getTimeAuthority());
153 
154     assertEquals(0, times.getExecutionStartTime());
155     final long t1 = System.currentTimeMillis();
156     times.setExecutionStartTime();
157     final long t2 = System.currentTimeMillis();
158 
159     // Fudge required since nanoTime() is more precise that currentTimeMillis().
160     final long FUDGE = 10;
161 
162     assertTrue(t1 - FUDGE <= times.getExecutionStartTime());
163     assertTrue(times.getExecutionStartTime() <= t2 + FUDGE);
164     final long elapsedTime = times.getElapsedTime();
165     assertTrue(elapsedTime <= (System.currentTimeMillis() - t1));
166     assertTrue(elapsedTime >= 0);
167   }
168 
169   @Test public void testThreadContextsThreadContextLocator() throws Exception {
170     final ThreadContexts threadContexts = new ThreadContexts();
171     assertNull(threadContexts.get());
172 
173     final ThreadContext threadContext1 = mock(ThreadContext.class);
174 
175     threadContexts.threadStarted(threadContext1);
176     assertSame(threadContext1, threadContexts.get());
177 
178     final Future<ThreadContext> future =
179       s_executor.submit(new Callable<ThreadContext>() {
180 
181       public ThreadContext call() throws Exception {
182         return threadContexts.get();
183       }});
184 
185     final ThreadContext otherContext = future.get();
186 
187     assertNotSame(otherContext, threadContexts.get());
188     assertSame(threadContext1, threadContexts.get());
189   }
190 
191   @Test public void testThreadContextsThreadCreated() throws Exception {
192     final ThreadContexts threadContexts = new ThreadContexts();
193 
194     final ThreadContext threadContext = mock(ThreadContext.class);
195     when(threadContext.getThreadNumber()).thenReturn(99);
196 
197     threadContexts.threadCreated(threadContext);
198 
199     final ArgumentCaptor<ThreadLifeCycleListener> listenerCaptor=
200       ArgumentCaptor.forClass(ThreadLifeCycleListener.class);
201 
202     verify(threadContext)
203       .registerThreadLifeCycleListener(listenerCaptor.capture());
204 
205     listenerCaptor.getValue().endThread();
206 
207     // Thread context discarded because thread has ended.
208     assertFalse(threadContexts.shutdown(99));
209   }
210 
211   @Test public void testThreadContextsShutdown() throws Exception {
212     final ThreadContexts threadContexts = new ThreadContexts();
213     assertFalse(threadContexts.shutdown(2));
214 
215     final ThreadContext threadContext = mock(ThreadContext.class);
216     when(threadContext.getThreadNumber()).thenReturn(2);
217 
218     threadContexts.threadCreated(threadContext);
219 
220     assertTrue(threadContexts.shutdown(2));
221     assertTrue(threadContexts.shutdown(2));
222 
223     verify(threadContext, times(2)).shutdown();
224   }
225 
226   @Test public void testThreadContextsShutdownAll() throws Exception {
227     final ThreadContexts threadContexts = new ThreadContexts();
228 
229     final ThreadContext threadContext1 = mock(ThreadContext.class);
230     when(threadContext1.getThreadNumber()).thenReturn(1);
231     threadContexts.threadCreated(threadContext1);
232 
233     final ThreadContext threadContext2 = mock(ThreadContext.class);
234     when(threadContext2.getThreadNumber()).thenReturn(2);
235     threadContexts.threadCreated(threadContext2);
236 
237     threadContexts.shutdownAll();
238 
239     verify(threadContext1).shutdown();
240     verify(threadContext2).shutdown();
241 
242     final ThreadContext threadContext3 = mock(ThreadContext.class);
243     when(threadContext3.getThreadNumber()).thenReturn(2);
244     threadContexts.threadCreated(threadContext3);
245 
246     verify(threadContext3).shutdown();
247   }
248 
249   @Test public void testInvalidThreadStarter() throws Exception {
250     final ThreadStarter starter = new GrinderProcess.InvalidThreadStarter();
251 
252     try {
253       starter.startThread(null);
254       fail("Expected InvalidContextException");
255     }
256     catch (InvalidContextException e) {
257     }
258   }
259 
260   @Test public void testCoverNullQueuedSender() throws Exception {
261     final QueuedSender sender = new GrinderProcess.NullQueuedSender();
262 
263     sender.send(null);
264     sender.send(null);
265     sender.flush();
266     sender.shutdown();
267 
268     sender.send(null);
269     sender.send(null);
270     sender.flush();
271     sender.shutdown();
272   }
273 }