1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License.
17  */
18 
19 package org.apache.harmony.jpda.tests.jdwp.EventModifiers;
20 
21 import org.apache.harmony.jpda.tests.framework.Breakpoint;
22 import org.apache.harmony.jpda.tests.framework.jdwp.Event;
23 import org.apache.harmony.jpda.tests.framework.jdwp.EventBuilder;
24 import org.apache.harmony.jpda.tests.framework.jdwp.JDWPConstants;
25 import org.apache.harmony.jpda.tests.framework.jdwp.Location;
26 import org.apache.harmony.jpda.tests.framework.jdwp.ParsedEvent.EventThreadLocation;
27 import org.apache.harmony.jpda.tests.framework.jdwp.ReplyPacket;
28 import org.apache.harmony.jpda.tests.framework.jdwp.Value;
29 import org.apache.harmony.jpda.tests.share.JPDADebuggeeSynchronizer;
30 
31 /**
32  * JDWP Unit test for InstanceOnly event modifier.
33  */
34 public class InstanceOnlyModifierTest extends JDWPEventModifierTestCase {
35 
36     private static final
37             String DEBUGGEE_SIGNATURE = "Lorg/apache/harmony/jpda/tests/jdwp/EventModifiers/InstanceOnlyModifierDebuggee;";
38     private static final
39             String TEST_CLASS_SIGNATURE = "Lorg/apache/harmony/jpda/tests/jdwp/EventModifiers/InstanceOnlyModifierDebuggee$TestClass;";
40     private static final
41             String TEST_CLASS_NAME = "org.apache.harmony.jpda.tests.jdwp.EventModifiers.InstanceOnlyModifierDebuggee$TestClass";
42 
43     // The name of the test method where we set our event requests.
44     private static final String METHOD_NAME = "eventTestMethod";
45 
46     // The name of the test method where we set our event requests.
47     private static final String WATCHED_FIELD_NAME = "watchedField";
48 
49     private static final String INSTANCE_FIELD_NAME = "INSTANCE_ONLY";
50 
51     @Override
getDebuggeeClassName()52     protected String getDebuggeeClassName() {
53         return InstanceOnlyModifierDebuggee.class.getName();
54     }
55 
56     /**
57      * This testcase is for BREAKPOINT event with InstanceOnly modifier.
58      * <BR>It runs InstanceOnlyModifierDebuggee and sets BREAKPOINT to its
59      * {@link InstanceOnlyModifierDebuggee.TestClass#eventTestMethod} method.
60      * <BR>Then calls this method multiple times and verifies that requested
61      * BREAKPOINT event occurs only when 'this' object is the object in field
62      * {@link InstanceOnlyModifierDebuggee#INSTANCE_ONLY}.
63      * <BR>Note: if the VM does not support the canUseInstanceFilters
64      * capability, the test succeeds.
65      */
testBreakpoint()66     public void testBreakpoint() {
67         logWriter.println("testBreakpoint started");
68 
69         synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_READY);
70 
71         if (!checkCanUseInstanceFilterCapability()) {
72             synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
73             return;
74         }
75 
76         byte typeTag = JDWPConstants.TypeTag.CLASS;
77         Breakpoint breakpoint = new Breakpoint(TEST_CLASS_SIGNATURE,
78                 METHOD_NAME, 0);
79         EventBuilder builder = createBreakpointEventBuilder(typeTag,
80                 breakpoint);
81         testEventWithInstanceOnlyModifier(builder);
82         logWriter.println("testBreakpoint done");
83     }
84 
85     /**
86      * This testcase is for METHOD_ENTRY event with InstanceOnly modifier.
87      * <BR>It runs InstanceOnlyModifierDebuggee and sets METHOD_ENTRY to the
88      * {@link InstanceOnlyModifierDebuggee.TestClass} class.
89      * <BR>Then calls
90      * {@link InstanceOnlyModifierDebuggee.TestClass#eventTestMethod} method
91      * multiple times and verifies that requested METHOD_ENTRY event occurs
92      * only when 'this' object is the object in field
93      * {@link InstanceOnlyModifierDebuggee#INSTANCE_ONLY}.
94      * <BR>Note: if the VM does not support the canUseInstanceFilters
95      * capability, the test succeeds.
96      */
testMethodEntry()97     public void testMethodEntry() {
98         logWriter.println("testMethodEntry started");
99 
100         synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_READY);
101 
102         if (!checkCanUseInstanceFilterCapability()) {
103             synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
104             return;
105         }
106 
107         EventBuilder builder = createMethodEntryEventBuilder(TEST_CLASS_NAME);
108         testEventWithInstanceOnlyModifier(builder);
109 
110         logWriter.println("testMethodEntry done");
111     }
112 
113     /**
114      * This testcase is for METHOD_EXIT event with InstanceOnly modifier.
115      * <BR>It runs InstanceOnlyModifierDebuggee and sets METHOD_EXIT to the
116      * {@link InstanceOnlyModifierDebuggee.TestClass} class.
117      * <BR>Then calls
118      * {@link InstanceOnlyModifierDebuggee.TestClass#eventTestMethod} method
119      * multiple times and verifies that requested METHOD_EXIT event occurs
120      * only when 'this' object is the object in field
121      * {@link InstanceOnlyModifierDebuggee#INSTANCE_ONLY}.
122      * <BR>Note: if the VM does not support the canUseInstanceFilters
123      * capability, the test succeeds.
124      */
testMethodExit()125     public void testMethodExit() {
126         logWriter.println("testMethodExit started");
127 
128         synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_READY);
129 
130         if (!checkCanUseInstanceFilterCapability()) {
131             synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
132             return;
133         }
134 
135         EventBuilder builder = createMethodExitEventBuilder(TEST_CLASS_NAME);
136         testEventWithInstanceOnlyModifier(builder);
137 
138         logWriter.println("testMethodExit done");
139     }
140 
141     /**
142      * This testcase is for METHOD_EXIT_WITH_RETURN_VALUE event with
143      * InstanceOnly modifier.
144      * <BR>It runs InstanceOnlyModifierDebuggee and sets
145      * METHOD_EXIT_WITH_RETURN_VALUE to the
146      * {@link InstanceOnlyModifierDebuggee.TestClass} class.
147      * <BR>Then calls
148      * {@link InstanceOnlyModifierDebuggee.TestClass#eventTestMethod} method
149      * multiple times and verifies that requested METHOD_EXIT_WITH_RETURN_VALUE
150      * event occurs only when 'this' object is the object in field
151      * {@link InstanceOnlyModifierDebuggee#INSTANCE_ONLY}.
152      * <BR>Note: if the VM does not support the canUseInstanceFilters
153      * capability, the test succeeds.
154      */
testMethodExitWithReturnValue()155     public void testMethodExitWithReturnValue() {
156         logWriter.println("testMethodExitWithReturnValue started");
157 
158         synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_READY);
159 
160         if (!checkCanUseInstanceFilterCapability()) {
161             synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
162             return;
163         }
164 
165         EventBuilder builder = createMethodExitWithReturnValueEventBuilder(TEST_CLASS_NAME);
166         testEventWithInstanceOnlyModifier(builder);
167 
168         logWriter.println("testMethodExitWithReturnValue done");
169     }
170 
171     /**
172      * This testcase is for EXCEPTION event with ThreadOnly modifier.
173      * <BR>It runs InstanceOnlyModifierDebuggee and sets EXCEPTION to the
174      * {@link InstanceOnlyModifierDebuggee.TestException} class but only for
175      * caught exceptions.
176      * <BR>Then calls
177      * {@link InstanceOnlyModifierDebuggee.TestClass#throwException} method
178      * multiple times and verifies that requested EXCEPTION event occurs only
179      * when 'this' object is the object in field
180      * {@link InstanceOnlyModifierDebuggee#INSTANCE_ONLY}.
181      */
testException()182     public void testException() {
183         logWriter.println("testException started");
184 
185         synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_READY);
186 
187         if (!checkCanUseInstanceFilterCapability()) {
188             synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
189             return;
190         }
191 
192         String exceptionClassSignature =
193                 "Lorg/apache/harmony/jpda/tests/jdwp/EventModifiers/InstanceOnlyModifierDebuggee$TestException;";
194         EventBuilder builder = createExceptionEventBuilder(exceptionClassSignature, true, false);
195         testEventWithInstanceOnlyModifier(builder);
196 
197         logWriter.println("testException done");
198     }
199 
200     /**
201      * This testcase is for FIELD_ACCESS event with InstanceOnly modifier.
202      * <BR>It runs InstanceOnlyModifierDebuggee and requests FIELD_ACCESS event
203      * for {@link InstanceOnlyModifierDebuggee.TestClass#watchedField}.
204      * <BR>Then calls
205      * {@link InstanceOnlyModifierDebuggee.TestClass#readAndWriteField} method
206      * multiple times and verifies that requested FIELD_ACCESS event occurs
207      * only when 'this' object is the object in field
208      * {@link InstanceOnlyModifierDebuggee#INSTANCE_ONLY}.
209      * <BR>Note: if the VM does not support the canUseInstanceFilters and
210      * canWatchFieldAccess capabilities, the test succeeds.
211      */
testFieldAccess()212     public void testFieldAccess() {
213         logWriter.println("testFieldAccess started");
214 
215         synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_READY);
216 
217         if (!checkCanUseInstanceFilterCapability()) {
218             synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
219             return;
220         }
221 
222         if (!canWatchFieldAccessCapability()) {
223             synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
224             return;
225         }
226 
227         EventBuilder builder = createFieldAccessEventBuilder(
228                 JDWPConstants.TypeTag.CLASS, TEST_CLASS_SIGNATURE,
229                 WATCHED_FIELD_NAME);
230         testEventWithInstanceOnlyModifier(builder);
231 
232         logWriter.println("testFieldAccess done");
233     }
234 
235     /**
236      * This testcase is for FIELD_MODIFICATION event with InstanceOnly modifier.
237      * <BR>It runs InstanceOnlyModifierDebuggee and requests FIELD_MODIFICATION
238      * event for {@link InstanceOnlyModifierDebuggee.TestClass#watchedField}.
239      * <BR>Then calls
240      * {@link InstanceOnlyModifierDebuggee.TestClass#readAndWriteField} method
241      * multiple times and verifies that requested FIELD_MODIFICATION event
242      * occurs only when 'this' object is the object in field
243      * {@link InstanceOnlyModifierDebuggee#INSTANCE_ONLY}.
244      * <BR>Note: if the VM does not support the canUseInstanceFilters and
245      * canWatchFieldModification capabilities, the test succeeds.
246      */
testFieldModification()247     public void testFieldModification() {
248         logWriter.println("testFieldModification started");
249 
250         synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_READY);
251 
252         if (!checkCanUseInstanceFilterCapability()) {
253             synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
254             return;
255         }
256 
257         if (!canWatchFieldModificationCapability()) {
258             synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
259             return;
260         }
261 
262         EventBuilder builder = createFieldModificationEventBuilder(
263                 JDWPConstants.TypeTag.CLASS, TEST_CLASS_SIGNATURE,
264                 WATCHED_FIELD_NAME);
265         testEventWithInstanceOnlyModifier(builder);
266 
267         logWriter.println("testFieldModification done");
268     }
269 
checkCanUseInstanceFilterCapability()270     private boolean checkCanUseInstanceFilterCapability() {
271         logWriter.println("Checking canUseInstanceFilters capability");
272         boolean result = debuggeeWrapper.vmMirror.canUseInstanceFilters();
273         if (!result) {
274             logCapabilityWarning("canUseInstanceFilters");
275         }
276         return result;
277     }
278 
getInstanceObjectId()279     private long getInstanceObjectId() {
280         Value fieldValue = getFieldValue(DEBUGGEE_SIGNATURE,
281                 INSTANCE_FIELD_NAME);
282         assertEquals("Invalid field value tag", JDWPConstants.Tag.OBJECT_TAG,
283                 fieldValue.getTag());
284         return fieldValue.getLongValue();
285     }
286 
testEventWithInstanceOnlyModifier(EventBuilder builder)287     private void testEventWithInstanceOnlyModifier(EventBuilder builder) {
288         long objectID = getInstanceObjectId();
289         builder.setInstanceOnly(objectID);
290         Event event = builder.build();
291         int requestID = requestEvent(event);
292 
293         EventThreadLocation eventThread =
294                 (EventThreadLocation) waitForEvent(event.eventKind, requestID);
295 
296         checkThisObject(eventThread, objectID);
297 
298         clearAndResume(event.eventKind, requestID);
299     }
300 
checkThisObject(EventThreadLocation eventThread, long objectID)301     private void checkThisObject(EventThreadLocation eventThread, long objectID) {
302         long threadID = eventThread.getThreadID();
303         assertTrue(threadID != 0);
304 
305         Location location = eventThread.getLocation();
306 
307         logWriter.println("Search the frame ID of the event location in thread " +  threadID);
308         long frameID = -1;
309         int framesCount = debuggeeWrapper.vmMirror.getFrameCount(threadID);
310         ReplyPacket reply = debuggeeWrapper.vmMirror.getThreadFrames(threadID,
311                 0, framesCount);
312         checkReplyPacket(reply, "Failed to get frames for thread " + threadID);
313         int frames = reply.getNextValueAsInt();
314         for (int i = 0; i < frames; ++i) {
315             long currentFrameID = reply.getNextValueAsLong();
316             Location currentFrameLocation = reply.getNextValueAsLocation();
317             if (currentFrameLocation.equals(location)) {
318                 frameID = currentFrameID;
319                 break;
320             }
321         }
322         assertTrue("Failed to find frame for event location", frameID != -1);
323 
324         logWriter.println("Check this object of frame " + frameID);
325         long thisObjectID = debuggeeWrapper.vmMirror.getThisObject(threadID,
326                 frameID);
327         assertEquals("Event is not related to the object we're looking for",
328                 objectID, thisObjectID);
329     }
330 }
331