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 /**
20  * @author Anatoly F. Bondarenko
21  */
22 
23 /**
24  * Created on 06.10.2006
25  */
26 package org.apache.harmony.jpda.tests.jdwp.Events;
27 
28 import org.apache.harmony.jpda.tests.framework.jdwp.CommandPacket;
29 import org.apache.harmony.jpda.tests.framework.jdwp.JDWPConstants;
30 import org.apache.harmony.jpda.tests.framework.jdwp.Location;
31 import org.apache.harmony.jpda.tests.framework.jdwp.ParsedEvent;
32 import org.apache.harmony.jpda.tests.framework.jdwp.ReplyPacket;
33 import org.apache.harmony.jpda.tests.share.JPDADebuggeeSynchronizer;
34 
35 import java.util.ArrayList;
36 import java.util.Arrays;
37 import java.util.HashMap;
38 import java.util.List;
39 import java.util.Map;
40 
41 
42 /**
43  * JDWP Unit test for METHOD_ENTRY, METHOD_EXIT events for empty method.
44  */
45 public class CombinedEvents002Test extends CombinedEventsTestCase {
46     static final String TESTED_CLASS_NAME =
47         CombinedEvents002Debuggee.TESTED_CLASS_NAME;
48     static final String TESTED_CLASS_SIGNATURE =
49         CombinedEvents002Debuggee.TESTED_CLASS_SIGNATURE;
50     static final String TESTED_METHOD_NAME = CombinedEvents002Debuggee.TESTED_METHOD_NAME;
51 
52     private long testedClassID = -1;
53     private long testedMethodID = -1;
54     private long testedMethodStartCodeIndex = -1;
55     private long testedMethodEndCodeIndex = -1;
56     private Map<Byte, Integer> requestsMap = new HashMap<>();
57 
58     @Override
getDebuggeeClassName()59     protected String getDebuggeeClassName() {
60         return CombinedEvents002Debuggee.class.getName();
61     }
62 
63     /**
64      * This testcase is for METHOD_ENTRY, METHOD_EXIT events for empty method.
65      * <BR>It runs CombinedEvents002Debuggee that executed its own empty method
66      * and verify that requested METHOD_ENTRY, METHOD_EXIT events occur
67      * for empty method.
68      */
testCombinedEvents002_01()69     public void testCombinedEvents002_01() {
70         byte[] expectedEventKinds = {
71                 JDWPConstants.EventKind.METHOD_ENTRY,
72                 JDWPConstants.EventKind.METHOD_EXIT
73         };
74         runTest(expectedEventKinds);
75     }
76 
77     /**
78      * This testcase is for METHOD_ENTRY, METHOD_EXIT_WITH_RETURN_VALUE events for empty method.
79      * <BR>It runs CombinedEvents002Debuggee that executed its own empty method
80      * and verify that requested METHOD_ENTRY, METHOD_EXIT_WITH_RETURN_VALUE events occur
81      * for empty method.
82      */
testCombinedEvents002_02()83     public void testCombinedEvents002_02() {
84         byte[] expectedEventKinds = {
85                 JDWPConstants.EventKind.METHOD_ENTRY,
86                 JDWPConstants.EventKind.METHOD_EXIT_WITH_RETURN_VALUE
87         };
88         runTest(expectedEventKinds);
89     }
90 
runTest(byte[] expectedEventKinds)91     private void runTest(byte[] expectedEventKinds) {
92         logWriter.println("==> " + getName() + ": Start...");
93 
94         prepareDebuggee(expectedEventKinds);
95         List<ParsedEvent> receivedEvents = receiveEvents();
96         checkEvents(receivedEvents, expectedEventKinds);
97         clearEvents();
98 
99         logWriter.println("==> Resume debuggee VM...");
100         debuggeeWrapper.vmMirror.resume();
101         logWriter.println("==> " + getName() + ": PASSED! ");
102     }
103 
104     /**
105      * Computes JDWP ids and requests events.
106      */
prepareDebuggee(byte[] expectedEventKinds)107     private void prepareDebuggee(byte[] expectedEventKinds) {
108         logWriter.println("==> Wait for SGNL_READY signal from debuggee...");
109         synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_READY);
110         logWriter.println("==> OK - SGNL_READY signal received!");
111 
112         testedClassID =
113             debuggeeWrapper.vmMirror.getClassID(TESTED_CLASS_SIGNATURE);
114         if ( testedClassID == -1 ) {
115             String failureMessage = "## FAILURE: Can NOT get ClassID for '"
116                 + TESTED_CLASS_SIGNATURE + "'";
117             printErrorAndFail(failureMessage);
118         }
119         logWriter.println("==> Tested Class Name = '" + TESTED_CLASS_NAME + "'");
120         logWriter.println("==> testedClassID = " + testedClassID);
121 
122         logWriter.println("==> ");
123         logWriter.println("==> Info for tested method '" + TESTED_METHOD_NAME + "':");
124         testedMethodID = debuggeeWrapper.vmMirror.getMethodID(testedClassID, TESTED_METHOD_NAME);
125         if (testedMethodID == -1 ) {
126             String failureMessage = "## FAILURE: Can NOT get MethodID for class '"
127                 + TESTED_CLASS_NAME + "'; Method name = " + TESTED_METHOD_NAME;
128             printErrorAndFail(failureMessage);
129         }
130         logWriter.println("==> testedMethodID = " + testedMethodID);
131         printMethodLineTable(testedClassID, null, TESTED_METHOD_NAME);
132         testedMethodStartCodeIndex = getMethodStartCodeIndex(testedClassID, TESTED_METHOD_NAME);
133         if ( testedMethodStartCodeIndex == -1 ) {
134             String failureMessage = "## FAILURE: Can NOT get MethodStartCodeIndex for method '"
135                 + TESTED_METHOD_NAME + "' ";
136             printErrorAndFail(failureMessage);
137         }
138         testedMethodEndCodeIndex = getMethodEndCodeIndex(testedClassID, TESTED_METHOD_NAME);
139         if ( testedMethodEndCodeIndex == -1 ) {
140             String failureMessage = "## FAILURE: Can NOT get MethodEndCodeIndex for method '"
141                 + TESTED_METHOD_NAME + "' ";
142             printErrorAndFail(failureMessage);
143         }
144 
145         // Request events.
146         for (byte eventKind : expectedEventKinds) {
147             String eventKindName = JDWPConstants.EventKind.getName(eventKind);
148             logWriter.println("==> ");
149             logWriter.println("==> Set request for " + eventKindName +
150                     " event for '" + TESTED_CLASS_NAME + "'... ");
151             ReplyPacket reply = null;
152             switch (eventKind) {
153             case JDWPConstants.EventKind.METHOD_ENTRY:
154                 reply = debuggeeWrapper.vmMirror.setMethodEntry(TESTED_CLASS_NAME);
155                 break;
156             case JDWPConstants.EventKind.METHOD_EXIT:
157                 reply = debuggeeWrapper.vmMirror.setMethodExit(TESTED_CLASS_NAME);
158                 break;
159             case JDWPConstants.EventKind.METHOD_EXIT_WITH_RETURN_VALUE:
160                 reply = debuggeeWrapper.vmMirror.setMethodExitWithReturnValue(TESTED_CLASS_NAME);
161                 break;
162             }
163             checkReplyPacket(reply, "Set " + eventKindName + " event.");  //DBG needless ?
164             int requestId = reply.getNextValueAsInt();
165             requestsMap.put(Byte.valueOf(eventKind), Integer.valueOf(requestId));
166             logWriter.println("==> OK - request " + requestId + " for " + eventKind +
167                     " event is set!");
168         }
169 
170         logWriter.println("==> Send SGNL_CONTINUE signal to debuggee...");
171         synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
172     }
173 
174     /**
175      * Receives events from the debuggee
176      */
receiveEvents()177     private List<ParsedEvent> receiveEvents() {
178         List<ParsedEvent> receivedEvents = new ArrayList<ParsedEvent>();
179         logWriter.println("==> ");
180         logWriter.println("==> Receiving events... ");
181         CommandPacket event = debuggeeWrapper.vmMirror.receiveEvent();
182         ParsedEvent[] parsedEvents = ParsedEvent.parseEventPacket(event);
183 
184         int receivedEventsNumber = parsedEvents.length;
185         logWriter.println("==> Number of received events in event packet = " + receivedEventsNumber);
186         for (int i = 0; i < receivedEventsNumber; ++i) {
187             receivedEvents.add(parsedEvents[i]);
188 
189             byte eventKind = parsedEvents[i].getEventKind();
190             eventKind = parsedEvents[i].getEventKind();
191             logWriter.println("==> Received event[" + i + "] kind = "
192                 +  eventKind
193                 + "(" + JDWPConstants.EventKind.getName(eventKind) + ")");
194         }
195         if (receivedEventsNumber > 2) {
196             String failureMessage = "## FAILURE: Unexpected number of received events in packet = "
197                 + receivedEventsNumber + "\n## Expected number of received events in packet = 1 or 2";
198             printErrorAndFail(failureMessage);
199         }
200         if (receivedEventsNumber == 1) {
201             logWriter.println("==> ");
202             logWriter.println("==> Resume debuggee VM...");
203             debuggeeWrapper.vmMirror.resume();
204             logWriter.println("==> Receiving events... ");
205             event = debuggeeWrapper.vmMirror.receiveEvent();
206             parsedEvents = ParsedEvent.parseEventPacket(event);
207 
208             receivedEventsNumber = parsedEvents.length;
209             logWriter.println("==> Number of received events in event packet = " + receivedEventsNumber);
210             for (int i = 0; i < receivedEventsNumber; ++i) {
211                 receivedEvents.add(parsedEvents[i]);
212 
213                 byte eventKind = parsedEvents[i].getEventKind();
214                 logWriter.println("==> Received event[" + i + "] kind = "
215                     +  eventKind
216                     + "(" + JDWPConstants.EventKind.getName(eventKind) + ")");
217             }
218             if (receivedEventsNumber != 1) {
219                 String failureMessage = "## FAILURE: Unexpected number of received events in packet = "
220                     + receivedEventsNumber + "\n## Expected number of received events in packet = 1";
221                 printErrorAndFail(failureMessage);
222             }
223         }
224         return receivedEvents;
225     }
226 
227     /**
228      * Checks we received expected events from the debuggee.
229      */
checkEvents(List<ParsedEvent> receivedEvents, byte[] expectedEventKinds)230     private void checkEvents(List<ParsedEvent> receivedEvents,
231             byte[] expectedEventKinds) {
232         boolean testCaseIsOk = true;
233         byte[] receivedEventKinds = new byte[receivedEvents.size()];
234         for (int i = 0, e = receivedEvents.size(); i < e; ++i) {
235             logWriter.println("==> ");
236             logWriter.println("==> Check received event #" + i + "...");
237             ParsedEvent parsedEvent = receivedEvents.get(i);
238             byte eventKind = parsedEvent.getEventKind();
239             receivedEventKinds[i] = eventKind;
240             switch (eventKind) {
241             case JDWPConstants.EventKind.METHOD_ENTRY:
242                 testCaseIsOk &= checkMethodEntryEvent(parsedEvent);
243                 break;
244             case JDWPConstants.EventKind.METHOD_EXIT:
245                 testCaseIsOk &= checkMethodExitEvent(parsedEvent);
246                 break;
247             case JDWPConstants.EventKind.METHOD_EXIT_WITH_RETURN_VALUE:
248                 testCaseIsOk &= checkMethodExitWithReturnValueEvent(parsedEvent);
249                 break;
250             }
251         }
252         if (!testCaseIsOk) {
253             String failureMessage = "## FAILURE: Unexpected events attributes are found out!";
254             printErrorAndFail(failureMessage);
255         }
256 
257         // Check that we received all expected events.
258         Arrays.sort(expectedEventKinds);
259         Arrays.sort(receivedEventKinds);
260         if (!Arrays.equals(expectedEventKinds, receivedEventKinds)) {
261             String failureMessage = "## FAILURE: Did not receive all expected events!";
262             printErrorAndFail(failureMessage);
263         }
264     }
265 
checkMethodEntryEvent(ParsedEvent parsedEvent)266     private boolean checkMethodEntryEvent(ParsedEvent parsedEvent) {
267         ParsedEvent.Event_METHOD_ENTRY methodEntryEvent =
268                 (ParsedEvent.Event_METHOD_ENTRY) parsedEvent;
269         Location expectedLocation = new Location(JDWPConstants.TypeTag.CLASS, testedClassID,
270                 testedMethodID, testedMethodStartCodeIndex);
271         return checkEventLocation(methodEntryEvent, expectedLocation);
272     }
273 
checkMethodExitEvent(ParsedEvent parsedEvent)274     private boolean checkMethodExitEvent(ParsedEvent parsedEvent) {
275         ParsedEvent.Event_METHOD_EXIT methodExitEvent =
276                 (ParsedEvent.Event_METHOD_EXIT) parsedEvent;
277         Location expectedLocation = new Location(JDWPConstants.TypeTag.CLASS, testedClassID,
278                 testedMethodID, testedMethodEndCodeIndex);
279         return checkEventLocation(methodExitEvent, expectedLocation);
280     }
281 
checkMethodExitWithReturnValueEvent(ParsedEvent parsedEvent)282     private boolean checkMethodExitWithReturnValueEvent(ParsedEvent parsedEvent) {
283         ParsedEvent.Event_METHOD_EXIT_WITH_RETURN_VALUE methodExitWithReturnValueEvent =
284                 (ParsedEvent.Event_METHOD_EXIT_WITH_RETURN_VALUE) parsedEvent;
285         Location expectedLocation = new Location(JDWPConstants.TypeTag.CLASS, testedClassID,
286                 testedMethodID, testedMethodEndCodeIndex);
287         boolean result = checkEventLocation(methodExitWithReturnValueEvent, expectedLocation);
288         // Expect null return value because method is 'void'.
289         if (methodExitWithReturnValueEvent.getReturnValue() != null) {
290             logWriter.println("## FAILURE: Unexpected return value in event!");
291             logWriter.println("##          Expected null");
292             result = false;
293         } else {
294             logWriter.println("==> OK - it is expected return value tag");
295         }
296         return result;
297     }
298 
299     /**
300      * Clear event requests.
301      */
clearEvents()302     private void clearEvents() {
303         for (Byte eventKind : requestsMap.keySet()) {
304             Integer requestId = requestsMap.get(eventKind);
305             logWriter.println("==> ");
306             logWriter.println("==> Clear request " + requestId.intValue() + " for " +
307                     JDWPConstants.EventKind.getName(eventKind.byteValue()));
308             debuggeeWrapper.vmMirror.clearEvent(eventKind.byteValue(), requestId.intValue());
309         }
310         requestsMap.clear();
311     }
312 }
313