View Javadoc

1   // Copyright (C) 2009 - 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.dcr;
23  
24  import java.util.ArrayList;
25  import java.util.List;
26  import java.util.Random;
27  import java.util.concurrent.ExecutorService;
28  import java.util.concurrent.Executors;
29  import java.util.concurrent.RejectedExecutionException;
30  import java.util.concurrent.TimeUnit;
31  import java.util.concurrent.atomic.AtomicInteger;
32  
33  import junit.framework.TestCase;
34  import net.grinder.common.UncheckedGrinderException;
35  import net.grinder.engine.common.EngineException;
36  import net.grinder.engine.process.dcr.RecorderLocator;
37  import net.grinder.engine.process.dcr.RecorderRegistry;
38  import net.grinder.scriptengine.Recorder;
39  import net.grinder.testutility.RandomStubFactory;
40  
41  
42  /**
43   * Unit tests for {@link RecorderLocator}.
44   *
45   * @author Philip Aston
46   * @version $Revision:$
47   */
48  public class TestRecorderLocator extends TestCase {
49  
50    private final RandomStubFactory<Recorder> m_recorderStubFactory =
51      RandomStubFactory.create(Recorder.class);
52    private final Recorder m_recorder = m_recorderStubFactory.getStub();
53  
54    private final RandomStubFactory<Recorder> m_recorderStubFactory2 =
55        RandomStubFactory.create(Recorder.class);
56    private final Recorder m_recorder2 = m_recorderStubFactory2.getStub();
57  
58    private final RecorderRegistry m_recorderRegistry =
59      RecorderLocator.getRecorderRegistry();
60  
61    @Override protected void tearDown() throws Exception {
62      super.tearDown();
63      RecorderLocator.clearRecorders();
64    }
65  
66    public void testNullBehaviour() throws Exception {
67      RecorderLocator.enter(this, "foo");
68      RecorderLocator.exit(this, "foo", false);
69    }
70  
71    public void testSingleRegistration() throws Exception {
72      final Object target = new Object();
73  
74      m_recorderRegistry.register(target, "location", m_recorder);
75      m_recorderStubFactory.assertNoMoreCalls();
76  
77      RecorderLocator.enter(target, "location");
78      m_recorderStubFactory.assertSuccess("start");
79      m_recorderStubFactory.assertNoMoreCalls();
80  
81      RecorderLocator.exit(target, "location", true);
82      m_recorderStubFactory.assertSuccess("end", true);
83      m_recorderStubFactory.assertNoMoreCalls();
84  
85      RecorderLocator.enter(this, "location");
86      RecorderLocator.exit(this, "location", true);
87      m_recorderStubFactory.assertNoMoreCalls();
88  
89      RecorderLocator.enter(target, "location2");
90      RecorderLocator.exit(target, "location2", true);
91      m_recorderStubFactory.assertNoMoreCalls();
92  
93      RecorderLocator.enter(target, "location");
94      m_recorderStubFactory.assertSuccess("start");
95      m_recorderStubFactory.assertNoMoreCalls();
96  
97      RecorderLocator.exit(target, "location", false);
98      m_recorderStubFactory.assertSuccess("end", false);
99      m_recorderStubFactory.assertNoMoreCalls();
100 
101     // Interned strings shouldn't match.
102     RecorderLocator.enter(target, new String("location"));
103     RecorderLocator.exit(target, new String("location"), true);
104     m_recorderStubFactory.assertNoMoreCalls();
105   }
106 
107   public void testBadRegistration() throws Exception {
108     final Object target = new Object();
109 
110     final EngineException exception = new EngineException("bork");
111 
112     m_recorderStubFactory.setThrows("start", exception);
113     m_recorderStubFactory.setThrows("end", exception);
114 
115     m_recorderRegistry.register(target, "location", m_recorder);
116     m_recorderStubFactory.assertNoMoreCalls();
117 
118     try {
119       RecorderLocator.enter(target, "location");
120       fail("Expected UncheckedGrinderException");
121     }
122     catch (UncheckedGrinderException e) {
123       assertSame(exception, e.getCause());
124     }
125     m_recorderStubFactory.assertException("start", exception);
126     m_recorderStubFactory.assertNoMoreCalls();
127 
128     try {
129       RecorderLocator.exit(target, "location", false);
130       fail("Expected UncheckedGrinderException");
131     }
132     catch (UncheckedGrinderException e) {
133       assertSame(exception, e.getCause());
134     }
135     m_recorderStubFactory.assertException("end", exception, false);
136     m_recorderStubFactory.assertNoMoreCalls();
137   }
138 
139   public void testMultipleRegistrations() throws Exception {
140     final Object target = new Object();
141     final Object target2 = new Object();
142 
143     m_recorderRegistry.register(target, "location", m_recorder);
144 
145     RecorderLocator.enter(target2, "location");
146     RecorderLocator.exit(target2, "location", false);
147     m_recorderStubFactory.assertNoMoreCalls();
148 
149     RecorderLocator.enter(target, "location");
150     m_recorderStubFactory.assertSuccess("start");
151     m_recorderStubFactory.assertNoMoreCalls();
152 
153     RecorderLocator.exit(target, "location", true);
154     m_recorderStubFactory.assertSuccess("end", true);
155     m_recorderStubFactory.assertNoMoreCalls();
156 
157     m_recorderRegistry.register(target2, "location", m_recorder2);
158     m_recorderRegistry.register(target2, "location2", m_recorder);
159 
160     RecorderLocator.enter(target, "location");
161     m_recorderStubFactory.assertSuccess("start");
162     m_recorderStubFactory.assertNoMoreCalls();
163 
164     RecorderLocator.enter(target2, "location");
165     m_recorderStubFactory2.assertSuccess("start");
166     m_recorderStubFactory2.assertNoMoreCalls();
167 
168     RecorderLocator.exit(target, "location", true);
169     m_recorderStubFactory.assertSuccess("end", true);
170     m_recorderStubFactory.assertNoMoreCalls();
171 
172     RecorderLocator.exit(target2, "location", false);
173     m_recorderStubFactory2.assertSuccess("end", false);
174     m_recorderStubFactory2.assertNoMoreCalls();
175     m_recorderStubFactory.assertNoMoreCalls();
176 
177     RecorderLocator.enter(target2, "location2");
178     m_recorderStubFactory.assertSuccess("start");
179     m_recorderStubFactory.assertNoMoreCalls();
180 
181     RecorderLocator.exit(target2, "location2", true);
182     m_recorderStubFactory.assertSuccess("end", true);
183     m_recorderStubFactory.assertNoMoreCalls();
184   }
185 
186   public void testNestedRegistrations() throws Exception {
187     final Object target = new Object();
188 
189     m_recorderRegistry.register(target, "location", m_recorder);
190 
191     // Same target, location, recorder => noop.
192     m_recorderRegistry.register(target, "location", m_recorder);
193 
194     m_recorderRegistry.register(target, "location", m_recorder2);
195 
196     RecorderLocator.enter(target, "location");
197     m_recorderStubFactory.assertSuccess("start");
198     m_recorderStubFactory2.assertSuccess("start");
199     m_recorderStubFactory.assertNoMoreCalls();
200     m_recorderStubFactory2.assertNoMoreCalls();
201 
202     RecorderLocator.exit(target, "location", false);
203     m_recorderStubFactory2.assertSuccess("end", false);
204     m_recorderStubFactory.assertSuccess("end", false);
205     m_recorderStubFactory.assertNoMoreCalls();
206     m_recorderStubFactory2.assertNoMoreCalls();
207   }
208 
209   public void testWithNull() throws Exception {
210     final Object target = new Object();
211 
212     m_recorderRegistry.register(target, "location", m_recorder);
213     m_recorderStubFactory.assertNoMoreCalls();
214 
215     RecorderLocator.enter(null, "location");
216     m_recorderStubFactory.assertNoMoreCalls();
217 
218     RecorderLocator.exit(null, "location", true);
219     m_recorderStubFactory.assertNoMoreCalls();
220   }
221 
222   public void testConcurrency() throws Exception {
223     final ExecutorService executor = Executors.newCachedThreadPool();
224 
225     final AtomicInteger runs = new AtomicInteger(0);
226     final AtomicInteger n = new AtomicInteger(0);
227 
228     final Recorder instrumentation = new Recorder() {
229       public void start() throws EngineException {
230         n.incrementAndGet();
231       }
232 
233       public void end(boolean success) throws EngineException {
234         n.decrementAndGet();
235       }
236     };
237 
238     final Random random = new Random();
239 
240     final String[] locations = { "L1", "L2", "L3" };
241 
242     class RegisterInstrumentation implements Runnable {
243       public void run() {
244         runs.incrementAndGet();
245 
246         final String location = locations[random.nextInt(locations.length)];
247 
248         if (random.nextInt(10) == 0) {
249           m_recorderRegistry.register(this, location, instrumentation);
250         }
251 
252         RecorderLocator.enter(this, location);
253         RecorderLocator.exit(this, location, true);
254 
255         try {
256           executor.execute(this);
257         }
258         catch (RejectedExecutionException e) {
259         }
260       }}
261 
262     final List<Runnable> runnables = new ArrayList<Runnable>();
263 
264     for (int i = 0; i < 10; ++i) {
265       runnables.add(new RegisterInstrumentation());
266     }
267 
268     for (Runnable r : runnables) {
269       executor.execute(r);
270     }
271 
272     while (runs.get() < 10000) {
273       Thread.sleep(10);
274     }
275     executor.shutdown();
276     assertTrue(executor.awaitTermination(1, TimeUnit.SECONDS));
277 
278     assertEquals(0, n.get());
279   }
280 }