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.engine.agent;
23
24 import static net.grinder.testutility.AssertUtilities.assertContains;
25 import static org.junit.Assert.assertEquals;
26 import static org.junit.Assert.fail;
27 import static org.mockito.Mockito.mock;
28
29 import java.io.File;
30 import java.io.InputStream;
31 import java.lang.instrument.Instrumentation;
32
33 import net.grinder.common.GrinderProperties;
34 import net.grinder.communication.CommunicationException;
35 import net.grinder.communication.FanOutStreamSender;
36 import net.grinder.communication.StreamReceiver;
37 import net.grinder.engine.agent.DebugThreadWorker.IsolateGrinderProcessRunner;
38 import net.grinder.engine.common.EngineException;
39 import net.grinder.engine.common.ScriptLocation;
40 import net.grinder.engine.messages.InitialiseGrinderMessage;
41 import net.grinder.testutility.AbstractJUnit4FileTestCase;
42 import net.grinder.testutility.AssertUtilities;
43 import net.grinder.testutility.RedirectStandardStreams;
44 import net.grinder.util.weave.agent.ExposeInstrumentation;
45
46 import org.junit.After;
47 import org.junit.Test;
48
49
50
51
52
53
54
55 public class TestDebugThreadWorkerFactory extends AbstractJUnit4FileTestCase {
56
57 private AgentIdentityImplementation m_agentIdentity =
58 new AgentIdentityImplementation(getClass().getName());
59
60 private FanOutStreamSender m_fanOutStreamSender = new FanOutStreamSender(1);
61 private GrinderProperties m_properties = new GrinderProperties();
62
63 @After public void shutdownStreamSender() throws Exception {
64 m_fanOutStreamSender.shutdown();
65 }
66
67 @Test public void testFactory() throws Exception {
68 m_properties.setProperty("grinder.logDirectory",
69 getDirectory().getAbsolutePath());
70
71 final DebugThreadWorkerFactory factory =
72 new DebugThreadWorkerFactory(m_agentIdentity,
73 m_fanOutStreamSender,
74 false,
75 new ScriptLocation(new File("missing.py")),
76 m_properties);
77
78 final RedirectStandardStreams streams = new RedirectStandardStreams() {
79 protected void runWithRedirectedStreams() throws Exception {
80 final Worker worker = factory.create(null, null);
81 worker.waitFor();
82 }
83 }.run();
84
85 streams.assertNoStdout();
86
87 assertContains(new String(streams.getStderrBytes()), "File not found");
88
89
90 final File[] files = getDirectory().listFiles();
91
92 assertEquals(2, files.length);
93 }
94
95 @Test public void testWithBadIsolatedRunner() throws Exception {
96 try {
97 DebugThreadWorkerFactory.setIsolatedRunnerClass(
98 BadClassInaccesible.class.getName());
99
100 final DebugThreadWorkerFactory factory =
101 new DebugThreadWorkerFactory(m_agentIdentity,
102 m_fanOutStreamSender,
103 false,
104 new ScriptLocation(new File(".")),
105 m_properties);
106
107 try {
108 factory.create(null, null);
109 fail("Expected EngineException");
110 }
111 catch (EngineException e) {
112 }
113 }
114 finally {
115 DebugThreadWorkerFactory.setIsolatedRunnerClass(null);
116 }
117 }
118
119 @Test public void testWithBadIsolatedRunner2() throws Exception {
120 try {
121 DebugThreadWorkerFactory.setIsolatedRunnerClass(
122 BadClassCantInstantiate.class.getName());
123
124 final DebugThreadWorkerFactory factory2 =
125 new DebugThreadWorkerFactory(m_agentIdentity,
126 m_fanOutStreamSender,
127 false,
128 new ScriptLocation(new File(".")),
129 m_properties);
130
131 try {
132 factory2.create(null, null);
133 fail("Expected EngineException");
134 }
135 catch (EngineException e) {
136 }
137 }
138 finally {
139 DebugThreadWorkerFactory.setIsolatedRunnerClass(null);
140 }
141 }
142
143 @Test public void testWithBadIsolatedRunner3() throws Exception {
144 try {
145 DebugThreadWorkerFactory.setIsolatedRunnerClass(
146 BadClassNotAnIsolateGrinderProcessRunner.class.getName());
147
148 final DebugThreadWorkerFactory factory3 =
149 new DebugThreadWorkerFactory(m_agentIdentity,
150 m_fanOutStreamSender,
151 false,
152 new ScriptLocation(new File(".")),
153 m_properties);
154
155 try {
156 factory3.create(null, null);
157 fail("Expected ClassCastException");
158 }
159 catch (ClassCastException e) {
160 }
161 }
162 finally {
163 DebugThreadWorkerFactory.setIsolatedRunnerClass(null);
164 }
165 }
166
167 @Test public void testWithBadIsolatedRunner4() throws Exception {
168 try {
169 DebugThreadWorkerFactory.setIsolatedRunnerClass("Not a class");
170
171 final DebugThreadWorkerFactory factory3 =
172 new DebugThreadWorkerFactory(m_agentIdentity,
173 m_fanOutStreamSender,
174 false,
175 new ScriptLocation(new File(".")),
176 m_properties);
177
178 try {
179 factory3.create(null, null);
180 fail("Expected AssertionError");
181 }
182 catch (AssertionError e) {
183 }
184 }
185 finally {
186 DebugThreadWorkerFactory.setIsolatedRunnerClass(null);
187 }
188 }
189
190 @Test public void testIsolation() throws Exception {
191 try {
192 DebugThreadWorkerFactory
193 .setIsolatedRunnerClass(GoodRunner.class.getName());
194
195 final DebugThreadWorkerFactory factory =
196 new DebugThreadWorkerFactory(m_agentIdentity,
197 m_fanOutStreamSender,
198 false,
199 new ScriptLocation(new File(".")),
200 m_properties);
201
202 final RedirectStandardStreams rss0 = new RedirectStandardStreams() {
203 protected void runWithRedirectedStreams() throws Exception {
204 final Worker worker = factory.create(null, null);
205 worker.waitFor();
206 }
207 };
208
209 rss0.run();
210
211 final RedirectStandardStreams rss1 = new RedirectStandardStreams() {
212 protected void runWithRedirectedStreams() throws Exception {
213 final Worker worker = factory.create(null, null);
214 worker.waitFor();
215 }
216 };
217
218 rss1.run();
219
220 final String worker0Result = new String(rss0.getStdoutBytes());
221 final String worker1Result = new String(rss1.getStdoutBytes());
222
223 AssertUtilities.assertContains(worker0Result, "Hello from 0 count is 1");
224 AssertUtilities.assertContains(worker1Result, "Hello from 1 count is 1");
225 }
226 finally {
227 DebugThreadWorkerFactory.setIsolatedRunnerClass(null);
228 }
229 }
230
231 @Test public void testIsolationWithSharedClasses() throws Exception {
232 try {
233 m_properties.setProperty("grinder.debug.singleprocess.sharedclasses",
234 MyStaticHolder.class.getName());
235
236 DebugThreadWorkerFactory
237 .setIsolatedRunnerClass(GoodRunner.class.getName());
238
239 final DebugThreadWorkerFactory factory =
240 new DebugThreadWorkerFactory(m_agentIdentity,
241 m_fanOutStreamSender,
242 false,
243 new ScriptLocation(new File(".")),
244 m_properties);
245
246 final RedirectStandardStreams rss0 = new RedirectStandardStreams() {
247 protected void runWithRedirectedStreams() throws Exception {
248 final Worker worker = factory.create(null, null);
249 worker.waitFor();
250 }
251 };
252
253 rss0.run();
254
255 final RedirectStandardStreams rss1 = new RedirectStandardStreams() {
256 protected void runWithRedirectedStreams() throws Exception {
257 final Worker worker = factory.create(null, null);
258 worker.waitFor();
259 }
260 };
261
262 rss1.run();
263
264 final String worker0Result = new String(rss0.getStdoutBytes());
265 final String worker1Result = new String(rss1.getStdoutBytes());
266
267 AssertUtilities.assertContains(worker0Result, "Hello from 0 count is 1");
268 AssertUtilities.assertContains(worker1Result, "Hello from 1 count is 2");
269 }
270 finally {
271 DebugThreadWorkerFactory.setIsolatedRunnerClass(null);
272 }
273 }
274
275
276 @Test public void testExposeInstrumentationNotIsolated() throws Exception {
277
278 final Instrumentation originalInstrumentation =
279 ExposeInstrumentation.getInstrumentation();
280
281 final Instrumentation instrumentation = mock(Instrumentation.class);
282
283 DebugThreadWorkerFactory.setIsolatedRunnerClass(
284 AccessInstrumentationRunner.class.getName());
285
286 try {
287 ExposeInstrumentation.premain("", instrumentation);
288
289 final DebugThreadWorkerFactory factory =
290 new DebugThreadWorkerFactory(m_agentIdentity,
291 m_fanOutStreamSender,
292 false,
293 new ScriptLocation(new File(".")),
294 m_properties);
295
296 final RedirectStandardStreams rss0 = new RedirectStandardStreams() {
297 protected void runWithRedirectedStreams() throws Exception {
298 final Worker worker = factory.create(null, null);
299 worker.waitFor();
300 }
301 };
302
303 rss0.run();
304
305 final String worker0Result = new String(rss0.getStdoutBytes());
306
307 AssertUtilities.assertContains(
308 worker0Result,
309 Integer.toString(instrumentation.hashCode()));
310 }
311 finally {
312 DebugThreadWorkerFactory.setIsolatedRunnerClass(null);
313 ExposeInstrumentation.premain("", originalInstrumentation);
314 }
315 }
316
317
318 public static class BadClassInaccesible {
319 BadClassInaccesible() { }
320 }
321
322 public static abstract class BadClassCantInstantiate {
323 public BadClassCantInstantiate() { }
324 }
325
326 public static class BadClassNotAnIsolateGrinderProcessRunner { }
327
328 public static class MyStaticHolder {
329 private static int s_number = 0;
330
331 public static void incrementNumber() {
332 ++s_number;
333 }
334
335 public static int getNumber() {
336 return s_number;
337 }
338 }
339
340 public abstract static class AbstractGoodRunner
341 implements IsolateGrinderProcessRunner {
342 protected InitialiseGrinderMessage initialise(InputStream inputStream) {
343
344 final StreamReceiver streamReceiver = new StreamReceiver(inputStream);
345
346 try {
347 return (InitialiseGrinderMessage)streamReceiver.waitForMessage();
348 }
349 catch (CommunicationException e) {
350 throw new AssertionError(e);
351 }
352 }
353 }
354
355 public static class GoodRunner extends AbstractGoodRunner{
356 public int run(InputStream agentInputStream) {
357 final InitialiseGrinderMessage message = initialise(agentInputStream);
358
359 MyStaticHolder.incrementNumber();
360
361 System.out.println(
362 "Hello from " + message.getWorkerIdentity().getNumber() +
363 " count is " + MyStaticHolder.getNumber());
364
365 return 0;
366 }
367 }
368
369 public static class AccessInstrumentationRunner
370 extends AbstractGoodRunner {
371
372 public int run(InputStream agentInputStream) {
373 initialise(agentInputStream);
374
375 System.out.println(ExposeInstrumentation.getInstrumentation().hashCode());
376
377 return 0;
378 }
379 }
380 }