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.util.weave.j2se6;
23  
24  import static org.junit.Assert.assertEquals;
25  import static org.junit.Assert.assertNotNull;
26  import static org.junit.Assert.assertNull;
27  import static org.junit.Assert.assertSame;
28  import static org.junit.Assert.fail;
29  import static org.mockito.Matchers.isA;
30  import static org.mockito.Mockito.doThrow;
31  import static org.mockito.Mockito.times;
32  import static org.mockito.Mockito.verify;
33  import static org.mockito.Mockito.verifyNoMoreInteractions;
34  import static org.mockito.Mockito.when;
35  
36  import java.lang.instrument.ClassFileTransformer;
37  import java.lang.instrument.Instrumentation;
38  import java.lang.instrument.UnmodifiableClassException;
39  import java.lang.reflect.Constructor;
40  import java.lang.reflect.Method;
41  import java.util.List;
42  import java.util.Map;
43  
44  import net.grinder.util.weave.Weaver;
45  import net.grinder.util.weave.WeavingException;
46  import net.grinder.util.weave.Weaver.TargetSource;
47  import net.grinder.util.weave.j2se6.DCRWeaver.ClassFileTransformerFactory;
48  
49  import org.junit.Before;
50  import org.junit.Test;
51  import org.mockito.ArgumentCaptor;
52  import org.mockito.Captor;
53  import org.mockito.Mock;
54  import org.mockito.MockitoAnnotations;
55  
56  
57  /**
58   * Unit test for {@link DCRWeaver}.
59   * TestDCRWeaver.
60   *
61   * @author Philip Aston
62   */
63  public class TestDCRWeaver {
64  
65    @Mock private ClassFileTransformerFactory m_classFileTransformerFactory;
66    @Mock private ClassFileTransformer m_transformer;
67    @Mock private Instrumentation m_instrumentation;
68    @Captor private ArgumentCaptor<PointCutRegistry> m_pointCutRegistryCaptor;
69  
70    @SuppressWarnings("unused")
71    private void myMethod() {
72    }
73  
74    @SuppressWarnings("unused")
75    private void myOtherMethod() {
76    }
77  
78    @Before public void setUp() {
79      MockitoAnnotations.initMocks(this);
80  
81      when(m_classFileTransformerFactory.create(isA(PointCutRegistry.class)))
82        .thenReturn(m_transformer);
83    }
84  
85    @Test public void testMethodRegistration() throws Exception {
86      final Weaver weaver = new DCRWeaver(m_classFileTransformerFactory,
87                                          m_instrumentation);
88  
89      verify(m_classFileTransformerFactory)
90        .create(m_pointCutRegistryCaptor.capture());
91      verify(m_instrumentation).addTransformer(m_transformer, true);
92  
93      final Method method = getClass().getDeclaredMethod("myMethod");
94  
95      final String l1 = weaver.weave(method, TargetSource.FIRST_PARAMETER);
96      final String l2 = weaver.weave(method, TargetSource.FIRST_PARAMETER);
97      assertEquals(l1, l2);
98  
99      weaver.weave(method, TargetSource.FIRST_PARAMETER);
100 
101     final PointCutRegistry pointCutRegistry =
102       m_pointCutRegistryCaptor.getValue();
103 
104     final String internalClassName = getClass().getName().replace('.', '/');
105 
106     final Map<Constructor<?>, List<WeavingDetails>> constructorPointCuts =
107       pointCutRegistry.getConstructorPointCutsForClass(internalClassName);
108 
109     assertNull(constructorPointCuts);
110 
111     final Map<Method, List<WeavingDetails>> methodPointCuts =
112       pointCutRegistry.getMethodPointCutsForClass(internalClassName);
113 
114     assertEquals(1, methodPointCuts.size());
115 
116     final List<WeavingDetails> locations1 = methodPointCuts.get(method);
117     assertEquals(1, locations1.size());
118     final String location1 = locations1.get(0).getLocation();
119     assertNotNull(location1);
120 
121     final Method method2 = getClass().getDeclaredMethod("myOtherMethod");
122 
123     weaver.weave(method, TargetSource.FIRST_PARAMETER);
124     weaver.weave(method2, TargetSource.FIRST_PARAMETER);
125 
126     final Map<Method, List<WeavingDetails>> pointCuts2 =
127       pointCutRegistry.getMethodPointCutsForClass(internalClassName);
128 
129     assertEquals(2, pointCuts2.size());
130 
131     final List<WeavingDetails> locations2 = pointCuts2.get(method);
132     assertEquals(1, locations2.size());
133 
134     assertEquals(new WeavingDetails(location1, TargetSource.FIRST_PARAMETER),
135                  locations2.get(0));
136     assertNotNull(pointCuts2.get(method2));
137 
138     verifyNoMoreInteractions(m_classFileTransformerFactory, m_instrumentation);
139   }
140 
141   @Test public void testConstructorRegistration() throws Exception {
142     final Weaver weaver = new DCRWeaver(m_classFileTransformerFactory,
143                                         m_instrumentation);
144 
145 
146     verify(m_classFileTransformerFactory)
147       .create(m_pointCutRegistryCaptor.capture());
148 
149     final Constructor<?> constructor = getClass().getDeclaredConstructor();
150 
151     final String l1 = weaver.weave(constructor);
152     final String l2 = weaver.weave(constructor);
153     assertEquals(l1, l2);
154 
155     weaver.weave(constructor);
156 
157     final PointCutRegistry pointCutRegistry =
158       m_pointCutRegistryCaptor.getValue();
159 
160     final String internalClassName = getClass().getName().replace('.', '/');
161 
162     final Map<Constructor<?>, List<WeavingDetails>> constructorPointCuts =
163       pointCutRegistry.getConstructorPointCutsForClass(internalClassName);
164 
165     assertEquals(1, constructorPointCuts.size());
166 
167     final Map<Method, List<WeavingDetails>> methodPointCuts =
168       pointCutRegistry.getMethodPointCutsForClass(internalClassName);
169 
170     assertNull(methodPointCuts);
171 
172     final List<WeavingDetails> locations1 =
173       constructorPointCuts.get(constructor);
174 
175     assertEquals(1, locations1.size());
176 
177     final String location1 = locations1.get(0).getLocation();
178     assertNotNull(location1);
179   }
180 
181   @Test public void testWeavingWithInstrumentation() throws Exception {
182     final Weaver weaver = new DCRWeaver(m_classFileTransformerFactory,
183                                         m_instrumentation);
184 
185     verify(m_classFileTransformerFactory)
186       .create(m_pointCutRegistryCaptor.capture());
187     verify(m_instrumentation).addTransformer(m_transformer, true);
188 
189     final Method method = getClass().getDeclaredMethod("myMethod");
190     weaver.weave(method, TargetSource.FIRST_PARAMETER);
191 
192     weaver.applyChanges();
193 
194     verify(m_instrumentation).retransformClasses(new Class[] { getClass(),});
195 
196     weaver.weave(method, TargetSource.FIRST_PARAMETER);
197     weaver.applyChanges();
198 
199     verifyNoMoreInteractions(m_classFileTransformerFactory,
200                              m_instrumentation);
201   }
202 
203   // Cover case where location key is different.
204   @Test public void testWeavingWithInstrumentation2() throws Exception {
205     final Weaver weaver = new DCRWeaver(m_classFileTransformerFactory,
206                                         m_instrumentation);
207 
208     verify(m_classFileTransformerFactory)
209       .create(m_pointCutRegistryCaptor.capture());
210     verify(m_instrumentation).addTransformer(m_transformer, true);
211 
212     final Method method = getClass().getDeclaredMethod("myMethod");
213 
214     weaver.weave(method, TargetSource.FIRST_PARAMETER);
215     weaver.applyChanges();
216     weaver.weave(method, TargetSource.CLASS);
217     weaver.applyChanges();
218 
219     verify(m_instrumentation, times(2))
220       .retransformClasses(new Class[] { getClass(),});
221 
222     verifyNoMoreInteractions(m_classFileTransformerFactory,
223                              m_instrumentation);
224   }
225 
226   @Test public void testWeavingWithBadInstrumentation() throws Exception {
227     final Weaver weaver = new DCRWeaver(m_classFileTransformerFactory,
228                                         m_instrumentation);
229 
230     final Method method = getClass().getDeclaredMethod("myMethod");
231 
232     weaver.weave(method, TargetSource.FIRST_PARAMETER);
233     weaver.weave(method, TargetSource.FIRST_PARAMETER);
234 
235     final Exception uce = new UnmodifiableClassException();
236 
237     doThrow(uce)
238       .when(m_instrumentation).retransformClasses(isA(Class.class));
239 
240     try {
241       weaver.applyChanges();
242       verifyNoMoreInteractions(m_instrumentation);
243       fail("Expected WeavingException");
244     }
245     catch (WeavingException e) {
246       assertSame(e.getCause(), uce);
247     }
248   }
249 
250   @Test(expected=WeavingException.class)
251   public void testInsufficientParameters() throws Exception {
252     final Weaver weaver = new DCRWeaver(m_classFileTransformerFactory,
253                                         m_instrumentation);
254 
255     final Method method = getClass().getDeclaredMethod("myMethod");
256 
257     weaver.weave(method, TargetSource.SECOND_PARAMETER);
258   }
259 }