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.scriptengine.java;
23 import static java.util.Collections.singleton;
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.junit.Assert.fail;
29 import static org.mockito.Matchers.any;
30 import static org.mockito.Mockito.doThrow;
31 import static org.mockito.Mockito.mock;
32 import static org.mockito.Mockito.times;
33 import static org.mockito.Mockito.verify;
34 import static org.mockito.Mockito.verifyNoMoreInteractions;
35 import static org.mockito.Mockito.when;
36
37 import grinder.test.MyClass;
38 import grinder.test.MyExtendedClass;
39
40 import java.lang.instrument.Instrumentation;
41 import java.lang.instrument.UnmodifiableClassException;
42 import java.lang.reflect.Method;
43 import java.net.URL;
44 import java.net.URLClassLoader;
45 import java.util.Collections;
46
47 import net.grinder.engine.process.dcr.AnotherClass;
48 import net.grinder.engine.process.dcr.DCRContextImplementation;
49 import net.grinder.engine.process.dcr.RecorderLocatorAccess;
50 import net.grinder.script.NotWrappableTypeException;
51 import net.grinder.script.Test.InstrumentationFilter;
52 import net.grinder.scriptengine.Recorder;
53 import net.grinder.util.BlockingClassLoader;
54 import net.grinder.util.weave.agent.ExposeInstrumentation;
55
56 import org.junit.After;
57 import org.junit.Before;
58 import org.junit.Test;
59 import org.mockito.Mock;
60 import org.mockito.MockitoAnnotations;
61 import org.slf4j.Logger;
62
63
64
65
66
67
68
69
70 public class TestJavaDCRInstrumenter {
71
72 @Mock private Logger m_logger;
73 @Mock private Recorder m_recorder;
74
75 private JavaDCRInstrumenter m_instrumenter;
76 private Instrumentation m_originalInstrumentation;
77
78 @Before public void setUp() throws Exception {
79 MockitoAnnotations.initMocks(this);
80
81 m_instrumenter =
82 new JavaDCRInstrumenter(DCRContextImplementation.create(m_logger));
83 m_originalInstrumentation = ExposeInstrumentation.getInstrumentation();
84 }
85
86 @After public void tearDown() throws Exception {
87 ExposeInstrumentation.premain("", m_originalInstrumentation);
88 RecorderLocatorAccess.clearRecorders();
89 }
90
91 private void assertNotWrappable(Object o) throws Exception {
92 try {
93 m_instrumenter.createInstrumentedProxy(null, null, o);
94 fail("Expected NotWrappableTypeException");
95 }
96 catch (NotWrappableTypeException e) {
97 }
98 }
99
100 @Test public void testGetDescription() throws Exception {
101 assertTrue(m_instrumenter.getDescription().length() > 0);
102 }
103
104 @Test public void testCreateProxyWithNonWrappableParameters() throws Exception {
105
106 assertNotWrappable(Object.class);
107 assertNotWrappable(new Object());
108 assertNotWrappable(new String());
109 assertNotWrappable(java.util.Random.class);
110
111
112 assertNotWrappable(new AnotherClass());
113 }
114
115 @Test public void testInstrumentClass() throws Exception {
116
117 assertEquals(6, MyClass.staticSix());
118
119 final MyClass c1 = new MyClass();
120
121 assertEquals(0, c1.getA());
122
123 final Object result =
124 m_instrumenter.createInstrumentedProxy(null, m_recorder, MyClass.class);
125 assertSame(MyClass.class, result);
126
127 MyClass.staticSix();
128
129 verify(m_recorder).start();
130 verify(m_recorder).end(true);
131
132 assertEquals(0, c1.getA());
133
134 final MyClass c2 = new MyClass();
135 verify(m_recorder, times(3)).start();
136 verify(m_recorder, times(3)).end(true);
137 assertEquals(0, c1.getA());
138 assertEquals(0, c2.getA());
139
140 m_instrumenter.createInstrumentedProxy(null,
141 m_recorder,
142 MyExtendedClass.class);
143
144 MyClass.staticSix();
145
146
147
148 verify(m_recorder, times(4)).start();
149 verify(m_recorder, times(4)).end(true);
150 verifyNoMoreInteractions(m_recorder);
151 }
152
153 @Test public void testInstrumentUnmodifiableCLass() throws Exception {
154
155 final Instrumentation instrumentation = mock(Instrumentation.class);
156 when(instrumentation.isRetransformClassesSupported()).thenReturn(true);
157
158 ExposeInstrumentation.premain("", instrumentation);
159
160 doThrow(new UnmodifiableClassException())
161 .when(instrumentation).retransformClasses((Class<?>[]) any());
162
163 instrumentation.retransformClasses(new Class[0]);
164
165
166 final JavaDCRInstrumenter instrumenter =
167 new JavaDCRInstrumenter(DCRContextImplementation.create(m_logger));
168
169 try {
170 instrumenter.createInstrumentedProxy(null, m_recorder, MyClass.class);
171 fail("Expected NotWrappableTypeException");
172 }
173 catch (NotWrappableTypeException e) {
174 }
175 }
176
177 @Test public void testInstrumentInstance() throws Exception {
178
179 RecorderLocatorAccess.clearRecorders();
180
181 final MyClass c1 = new MyExtendedClass();
182
183 assertEquals(0, c1.getA());
184
185 final Object result =
186 m_instrumenter.createInstrumentedProxy(null, m_recorder, c1);
187 assertSame(c1, result);
188
189 MyClass.staticSix();
190
191 assertEquals(0, c1.getA());
192 verify(m_recorder).start();
193 verify(m_recorder).end(true);
194
195 final MyClass c2 = new MyClass();
196 assertEquals(0, c2.getA());
197
198 verifyNoMoreInteractions(m_recorder);
199 }
200
201 @Test public void testSelectivelyInstrumentInstance() throws Exception {
202
203 RecorderLocatorAccess.clearRecorders();
204
205 final MyClass c1 = new MyExtendedClass();
206
207 assertEquals(0, c1.getA());
208
209 final InstrumentationFilter filter =
210 new InstrumentationFilter() {
211 public boolean matches(Object item) {
212 return ((Method)item).getName().equals("getA");
213 }
214 };
215
216 m_instrumenter.instrument(null, m_recorder, c1, filter);
217
218 MyClass.staticSix();
219
220 assertEquals(0, c1.getA());
221 assertEquals(0, c1.getB());
222
223 verify(m_recorder).start();
224 verify(m_recorder).end(true);
225
226 final MyClass c2 = new MyClass();
227 assertEquals(0, c2.getA());
228
229 verifyNoMoreInteractions(m_recorder);
230 }
231
232
233 @Test public void testWithNull() throws Exception {
234 assertNull(m_instrumenter.createInstrumentedProxy(null, null, null));
235 }
236
237 @Test public void testArrays() throws Exception {
238
239 RecorderLocatorAccess.clearRecorders();
240
241 try {
242 m_instrumenter.createInstrumentedProxy(null, m_recorder, new MyClass[0]);
243 fail("Expected NotWrappableTypeException");
244 }
245 catch (NotWrappableTypeException e) {
246 }
247
248 try {
249 m_instrumenter.createInstrumentedProxy(null, m_recorder, MyClass[].class);
250 fail("Expected NotWrappableTypeException");
251 }
252 catch (NotWrappableTypeException e) {
253 }
254
255 verifyNoMoreInteractions(m_recorder);
256 }
257
258 @Test public void testWithNoPackage() throws Exception {
259
260 RecorderLocatorAccess.clearRecorders();
261
262 final BlockingClassLoader blockingClassLoader =
263 new BlockingClassLoader(singleton(AnotherClass.class.getName()),
264 Collections.<String>emptySet(),
265 Collections.<String>emptySet(),
266 true);
267
268 final NoPackageURLClassLoader cl =
269 new NoPackageURLClassLoader(
270 ((URLClassLoader)getClass().getClassLoader()).getURLs(),
271 blockingClassLoader);
272
273 final Class<?> noPackageClass = cl.loadClass(AnotherClass.class.getName());
274 final Method noPackageMethod = noPackageClass.getMethod("getOne");
275
276 assertEquals(1, noPackageMethod.invoke(null));
277
278 final Object result =
279 m_instrumenter.createInstrumentedProxy(null, m_recorder, noPackageClass);
280 assertSame(noPackageClass, result);
281
282 assertEquals(1, noPackageMethod.invoke(null));
283 verify(m_recorder).start();
284 verify(m_recorder).end(true);
285 verifyNoMoreInteractions(m_recorder);
286 }
287
288 private static class NoPackageURLClassLoader extends URLClassLoader {
289
290 public NoPackageURLClassLoader(URL[] urls, ClassLoader parent) {
291 super(urls, parent);
292 }
293
294 @Override
295 protected Package getPackage(String name) {
296 return null;
297 }
298 }
299 }
300