Home | History | Annotate | Download | only in Events
      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.Events;
     20 
     21 import org.apache.harmony.jpda.tests.framework.jdwp.EventPacket;
     22 import org.apache.harmony.jpda.tests.framework.jdwp.JDWPConstants;
     23 import org.apache.harmony.jpda.tests.framework.jdwp.JDWPConstants.StepDepth;
     24 import org.apache.harmony.jpda.tests.framework.jdwp.Location;
     25 import org.apache.harmony.jpda.tests.framework.jdwp.ParsedEvent;
     26 import org.apache.harmony.jpda.tests.framework.jdwp.ReplyPacket;
     27 import org.apache.harmony.jpda.tests.share.JPDADebuggeeSynchronizer;
     28 
     29 /**
     30  * JDWP unit test checking that we can report different events, requested during
     31  * an EXCEPTION event where the exception is caught (by a catch handler).
     32  */
     33 public class EventWithExceptionTest extends JDWPEventTestCase {
     34     private static final String TEST_METHOD_NAME = "catchMethod";
     35 
     36     private static final String WATCHED_FIELD_NAME = "watchedField";
     37 
     38     private static final Class<? extends Throwable> EXCEPTION_CLASS =
     39             EventWithExceptionDebuggee.TestException.class;
     40 
     41     @Override
     42     protected String getDebuggeeClassName() {
     43         return EventWithExceptionDebuggee.class.getName();
     44     }
     45 
     46     /**
     47      * Tests we properly SINGLE-STEP OUT to the catch handler.
     48      */
     49     public void testSingleStepOut() {
     50         runSingleStepTest(JDWPConstants.StepDepth.OUT);
     51     }
     52 
     53     /**
     54      * Tests we properly SINGLE-STEP OVER to the catch handler.
     55      */
     56     public void testSingleStepOver() {
     57         runSingleStepTest(JDWPConstants.StepDepth.OVER);
     58     }
     59 
     60     /**
     61      * Tests we properly SINGLE-STEP INTO to the catch handler.
     62      */
     63     public void testSingleStepInto() {
     64         runSingleStepTest(JDWPConstants.StepDepth.INTO);
     65     }
     66 
     67     /**
     68      * Tests we properly BREAKPOINT in the catch handler if we request it before the EXCEPTION
     69      * event happens.
     70      */
     71     public void testBreakpoint_BeforeException() {
     72         logWriter.println(getName() + " STARTS");
     73 
     74         // Wait for debuggee.
     75         synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_READY);
     76 
     77         // Set EXCEPTION event
     78         int exceptionRequestId = setException();
     79 
     80         synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
     81 
     82         // Wait for EXCEPTION event
     83         ParsedEvent exceptionEvent = waitForEvent(JDWPConstants.EventKind.EXCEPTION,
     84                 exceptionRequestId);
     85 
     86         // Get catch handler location
     87         Location catchHandlerLocation =
     88                 ((ParsedEvent.Event_EXCEPTION) exceptionEvent).getCatchLocation();
     89 
     90         // Remove EXCEPTION event.
     91         clearEvent(JDWPConstants.EventKind.EXCEPTION, exceptionRequestId, true);
     92 
     93         // Resume debuggee suspended on EXCEPTION event.
     94         logWriter.println("Resume debuggee after EXCEPTION event");
     95         debuggeeWrapper.resume();
     96 
     97         // Wait for debuggee.
     98         synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_READY);
     99 
    100         // Install BREAKPOINT in catch handler.
    101         int breakpointRequestId = setBreakpoint(catchHandlerLocation);
    102 
    103         synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
    104 
    105         // Wait for BREAKPOINT.
    106         ParsedEvent breakpointEvent = waitForEvent(JDWPConstants.EventKind.BREAKPOINT,
    107                 breakpointRequestId);
    108 
    109         // Check location of BREAKPOINT event.
    110         Location eventLocation = ((ParsedEvent.EventThreadLocation) breakpointEvent).getLocation();
    111         assertEquals("Not the expected location", catchHandlerLocation, eventLocation);
    112 
    113         // Remove BREAKPOINT request.
    114         clearEvent(JDWPConstants.EventKind.BREAKPOINT, breakpointRequestId, true);
    115 
    116         // Resume debuggee suspended on BREAKPOINT event.
    117         logWriter.println("Resume debuggee after BREAKPOINT event");
    118         debuggeeWrapper.resume();
    119 
    120         // Continue debuggee
    121         synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
    122 
    123         logWriter.println(getName() + " ENDS");
    124     }
    125 
    126     /**
    127      * Tests we properly BREAKPOINT in the catch handler if we request it upon the EXCEPTION
    128      * event happens.
    129      */
    130     public void testBreakpoint_UponException() {
    131         logWriter.println(getName() + " STARTS");
    132 
    133         // Wait for debuggee.
    134         synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_READY);
    135 
    136         // Set EXCEPTION event
    137         int exceptionRequestId = setException();
    138 
    139         synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
    140 
    141         // Wait for EXCEPTION event
    142         ParsedEvent exceptionEvent = waitForEvent(JDWPConstants.EventKind.EXCEPTION,
    143                 exceptionRequestId);
    144 
    145         // Get catch handler location
    146         Location catchHandlerLocation =
    147                 ((ParsedEvent.Event_EXCEPTION) exceptionEvent).getCatchLocation();
    148 
    149         // Resume debuggee suspended on EXCEPTION event.
    150         logWriter.println("Resume debuggee after EXCEPTION event");
    151         debuggeeWrapper.resume();
    152 
    153         // Wait for debuggee.
    154         synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_READY);
    155 
    156         synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
    157 
    158         waitForEvent(JDWPConstants.EventKind.EXCEPTION, exceptionRequestId);
    159 
    160         // Install BREAKPOINT in catch handler.
    161         int breakpointRequestId = setBreakpoint(catchHandlerLocation);
    162 
    163         debuggeeWrapper.resume();
    164 
    165         // Wait for BREAKPOINT.
    166         ParsedEvent breakpointEvent = waitForEvent(JDWPConstants.EventKind.BREAKPOINT,
    167                 breakpointRequestId);
    168 
    169         // Check location of BREAKPOINT event.
    170         Location eventLocation = ((ParsedEvent.EventThreadLocation) breakpointEvent).getLocation();
    171         assertEquals("Not the expected location", catchHandlerLocation, eventLocation);
    172 
    173         // Remove BREAKPOINT request.
    174         clearEvent(JDWPConstants.EventKind.BREAKPOINT, breakpointRequestId, true);
    175 
    176         // Resume debuggee suspended on BREAKPOINT event.
    177         logWriter.println("Resume debuggee after BREAKPOINT event");
    178         debuggeeWrapper.resume();
    179 
    180         // Continue debuggee
    181         synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
    182 
    183         logWriter.println(getName() + " ENDS");
    184     }
    185 
    186     /**
    187      * Tests we properly FIELD_ACCESS in the method catching the exception.
    188      */
    189     public void testFieldAccess() {
    190         runFieldWatchpointTest(JDWPConstants.EventKind.FIELD_ACCESS);
    191     }
    192 
    193     /**
    194      * Tests we properly FIELD_MODIFICATION in the method catching the exception.
    195      */
    196     public void testFieldModification() {
    197         runFieldWatchpointTest(JDWPConstants.EventKind.FIELD_MODIFICATION);
    198     }
    199 
    200     /**
    201      * Tests we properly detect METHOD_EXIT event in the method catching the exception.
    202      */
    203     public void testMethodExit() {
    204         runMethodExitTest(JDWPConstants.EventKind.METHOD_EXIT);
    205     }
    206 
    207     /**
    208      * Tests we properly detect METHOD_EXIT event in the method catching the exception.
    209      */
    210     public void testMethodExitWithReturnValue() {
    211         runMethodExitTest(JDWPConstants.EventKind.METHOD_EXIT_WITH_RETURN_VALUE);
    212     }
    213 
    214     /**
    215      * Tests we properly single-step to the catch handler.
    216      *
    217      * @param singleStepDepth
    218      *          the kind of single-step
    219      */
    220     private void runSingleStepTest(byte singleStepDepth) {
    221         logWriter.println(getName() + " STARTS");
    222 
    223         // Wait for debuggee.
    224         synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_READY);
    225 
    226         // Set EXCEPTION event
    227         int exceptionRequestId = setException();
    228 
    229         synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
    230 
    231         // Wait for EXCEPTION event
    232         ParsedEvent exceptionEvent = waitForEvent(JDWPConstants.EventKind.EXCEPTION,
    233                 exceptionRequestId);
    234 
    235         // Get catch handler location
    236         Location catchHandlerLocation =
    237                 ((ParsedEvent.Event_EXCEPTION) exceptionEvent).getCatchLocation();
    238 
    239         // Resume debuggee suspended on EXCEPTION event.
    240         logWriter.println("Resume debuggee after EXCEPTION event #1");
    241         debuggeeWrapper.resume();
    242 
    243         // Wait for debuggee.
    244         synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_READY);
    245 
    246         synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
    247 
    248         // Wait for EXCEPTION event
    249         ParsedEvent parsedEvent = waitForEvent(JDWPConstants.EventKind.EXCEPTION, exceptionRequestId);
    250         long eventThreadId = ((ParsedEvent.EventThread)parsedEvent).getThreadID();
    251 
    252         // Install SINGLE_STEP in catch handler.
    253         int singleStepRequestId = setSingleStep(eventThreadId, singleStepDepth);
    254 
    255         // Resume debuggee suspended on EXCEPTION event.
    256         logWriter.println("Resume debuggee after EXCEPTION event #2");
    257         debuggeeWrapper.resume();
    258 
    259         // Wait for SINGLE_STEP.
    260         ParsedEvent singleStepEvent = waitForEvent(JDWPConstants.EventKind.SINGLE_STEP,
    261                 singleStepRequestId);
    262 
    263         // Check location of SINGLE_STEP event.
    264         Location eventLocation = ((ParsedEvent.EventThreadLocation) singleStepEvent).getLocation();
    265         assertEquals("Not the expected location, ", catchHandlerLocation, eventLocation);
    266 
    267         // Remove SINGLE_STEP request.
    268         clearEvent(JDWPConstants.EventKind.SINGLE_STEP, singleStepRequestId, true);
    269 
    270         // Resume debuggee suspended on SINGLE_STEP event.
    271         logWriter.println("Resume debuggee after SINGLE_STEP event");
    272         debuggeeWrapper.resume();
    273 
    274         // Continue debuggee
    275         synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
    276 
    277         logWriter.println(getName() + " ENDS");
    278     }
    279 
    280     /**
    281      * Tests we properly detect field watchpoint events in the method catching the exception.
    282      *
    283      * @param fieldEventKind
    284      *          the desired field event kind
    285      */
    286     private void runFieldWatchpointTest(byte fieldEventKind) {
    287         logWriter.println(getName() + " STARTS");
    288 
    289         // Skip first method call since we do not need to know the location of
    290         // the catch handler.
    291         synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_READY);
    292         synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
    293 
    294         // Wait for second method call.
    295         synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_READY);
    296 
    297         // Set EXCEPTION event
    298         int exceptionRequestId = setException();
    299 
    300         synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
    301 
    302         // Wait for EXCEPTION event
    303         waitForEvent(JDWPConstants.EventKind.EXCEPTION, exceptionRequestId);
    304 
    305         // Install FIELD watchpoint event
    306         int fieldWatchpointRequestId = setFieldWatchpoint(fieldEventKind);
    307 
    308         // Resume debuggee suspended on EXCEPTION event.
    309         logWriter.println("Resume debuggee after EXCEPTION event");
    310         debuggeeWrapper.resume();
    311 
    312         // Wait for FIELD event.
    313         ParsedEvent fieldWatchpointEvent = waitForEvent(fieldEventKind,
    314                 fieldWatchpointRequestId);
    315 
    316         // Check location of FIELD event.
    317         Location eventLocation =
    318                 ((ParsedEvent.EventThreadLocation) fieldWatchpointEvent).getLocation();
    319         assertNotNull(eventLocation);
    320         long classId = getClassIDBySignature(getDebuggeeClassSignature());
    321         long methodId = getMethodID(classId, TEST_METHOD_NAME);
    322         assertEquals("Invalid class ID", classId, eventLocation.classID);
    323         assertEquals("Invalid method ID", methodId, eventLocation.methodID);
    324 
    325         // Remove FIELD watchpoint request.
    326         clearEvent(fieldEventKind, fieldWatchpointRequestId, true);
    327 
    328         // Resume debuggee suspended on FIELD event.
    329         logWriter.println("Resume debuggee after " +
    330                 JDWPConstants.EventKind.getName(fieldEventKind) + " event");
    331         debuggeeWrapper.resume();
    332 
    333         // Continue debuggee
    334         synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
    335 
    336         logWriter.println(getName() + " ENDS");
    337     }
    338 
    339     /**
    340      * Tests we properly detect method exit event in the method catching the exception.
    341      *
    342      * @param methodExitEventKind
    343      *          the desired method exit event kind
    344      */
    345     private void runMethodExitTest(byte methodExitEventKind) {
    346 
    347         logWriter.println(getName() + " STARTS");
    348 
    349         // Skip first method call since we do not need to know the location of
    350         // the catch handler.
    351         synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_READY);
    352         synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
    353 
    354         // Wait for second method call.
    355         synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_READY);
    356 
    357         // Set EXCEPTION event
    358         int exceptionRequestId = setException();
    359 
    360         synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
    361 
    362         // Wait for EXCEPTION event
    363         waitForEvent(JDWPConstants.EventKind.EXCEPTION, exceptionRequestId);
    364 
    365         // Install METHOD_EXIT event
    366         int methodExitRequestId = setMethodExit(methodExitEventKind);
    367 
    368         logWriter.println("Resume debuggee after EXCEPTION event");
    369         debuggeeWrapper.resume();
    370 
    371         // Wait for METHOD_EXIT event.
    372         ParsedEvent methodExitEvent = waitForEvent(methodExitEventKind, methodExitRequestId);
    373 
    374         // Check location of METHOD_EXIT event.
    375         Location eventLocation =
    376                 ((ParsedEvent.EventThreadLocation) methodExitEvent).getLocation();
    377         assertNotNull(eventLocation);
    378         long classId = getClassIDBySignature(getDebuggeeClassSignature());
    379         long methodId = getMethodID(classId, TEST_METHOD_NAME);
    380         checkLocation(classId, methodId, eventLocation);
    381 
    382         // Remove METHOD_EXIT request.
    383         clearEvent(methodExitEventKind, methodExitRequestId, true);
    384 
    385         // Resume debuggee suspended on METHOD_EXIT event.
    386         logWriter.println("Resume debuggee after " +
    387                 JDWPConstants.EventKind.getName(methodExitEventKind) + " event");
    388         debuggeeWrapper.resume();
    389 
    390         // Continue debuggee
    391         synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
    392 
    393         logWriter.println(getName() + " ENDS");
    394     }
    395 
    396     private void checkLocation(long expectedClassId, long expectedMethodId, Location actualLocation) {
    397         if (expectedClassId != actualLocation.classID || expectedMethodId != actualLocation.methodID) {
    398             String expectedClassName = getClassSignature(expectedClassId);
    399             String expectedMethodName = getMethodName(expectedClassId, expectedMethodId);
    400             String actualClassName = getClassSignature(actualLocation.classID);
    401             String actualMethodName = getMethodName(actualLocation.classID, actualLocation.methodID);
    402             fail(String.format("Invalid method, expected  \"%s.%s\" (classId=%d, methodId=%d)" +
    403                     " but got \"%s.%s\" (classId=%d, methodId=%d)",
    404                     expectedClassName, expectedMethodName, expectedClassId, expectedMethodId,
    405                     actualClassName, actualMethodName, actualLocation.classID, actualLocation.methodID));
    406         }
    407     }
    408 
    409     private int setException() {
    410         logWriter.println("Set EXCEPTION on class " + EXCEPTION_CLASS.getName());
    411         ReplyPacket exceptionReplyPacket =
    412                 debuggeeWrapper.vmMirror.setException(getClassSignature(EXCEPTION_CLASS), true,
    413                         false);
    414         checkReplyPacket(exceptionReplyPacket, "Failed to install EXCEPTION");
    415         return readRequestId(exceptionReplyPacket);
    416     }
    417 
    418     private int setSingleStep(long eventThreadId, byte singleStepDepth) {
    419         logWriter.println("Set SINGLE_STEP " + JDWPConstants.StepDepth.getName(singleStepDepth) +
    420                 " in thread " + eventThreadId);
    421         ReplyPacket replyPacket = debuggeeWrapper.vmMirror.setStep(eventThreadId,
    422                 JDWPConstants.StepSize.LINE, singleStepDepth);
    423         checkReplyPacket(replyPacket, "Failed to set SINGLE_STEP " +
    424                 StepDepth.getName(singleStepDepth));
    425         return readRequestId(replyPacket);
    426     }
    427 
    428     private int setBreakpoint(Location catchHandlerLocation) {
    429         logWriter.println("Set BREAKPOINT at " + catchHandlerLocation);
    430         ReplyPacket breakpointReplyPacket =
    431                 debuggeeWrapper.vmMirror.setBreakpoint(catchHandlerLocation);
    432         checkReplyPacket(breakpointReplyPacket, "Failed to install BREAKPOINT");
    433         return readRequestId(breakpointReplyPacket);
    434     }
    435 
    436     private int setFieldWatchpoint(byte fieldEventKind) {
    437         String eventKindName = JDWPConstants.EventKind.getName(fieldEventKind);
    438         logWriter.println("Set " + eventKindName + " on field " + WATCHED_FIELD_NAME);
    439         final String classSignature = getDebuggeeClassSignature();
    440         final byte classTypeTag = JDWPConstants.TypeTag.CLASS;
    441         ReplyPacket replyPacket = null;
    442         if (fieldEventKind == JDWPConstants.EventKind.FIELD_ACCESS) {
    443             replyPacket = debuggeeWrapper.vmMirror.setFieldAccess(classSignature, classTypeTag,
    444                     WATCHED_FIELD_NAME);
    445         } else if (fieldEventKind == JDWPConstants.EventKind.FIELD_MODIFICATION) {
    446             replyPacket = debuggeeWrapper.vmMirror.setFieldModification(classSignature,
    447                     classTypeTag, WATCHED_FIELD_NAME);
    448         } else {
    449             fail("Unsupported eventkind " + fieldEventKind);
    450         }
    451         checkReplyPacket(replyPacket, "Failed to set " + eventKindName);
    452         return readRequestId(replyPacket);
    453     }
    454 
    455     private int setMethodExit(byte methodExitEventKind) {
    456         String eventKindName = JDWPConstants.EventKind.getName(methodExitEventKind);
    457         logWriter.println("Set " + eventKindName + " on class " + getDebuggeeClassName());
    458         ReplyPacket replyPacket = null;
    459         if (methodExitEventKind == JDWPConstants.EventKind.METHOD_EXIT) {
    460             replyPacket = debuggeeWrapper.vmMirror.setMethodExit(getDebuggeeClassName());
    461         } else if (methodExitEventKind == JDWPConstants.EventKind.METHOD_EXIT_WITH_RETURN_VALUE) {
    462             replyPacket =
    463                     debuggeeWrapper.vmMirror.setMethodExitWithReturnValue(getDebuggeeClassName());
    464         } else {
    465             fail("Not a method exit event: " + methodExitEventKind);
    466         }
    467         checkReplyPacket(replyPacket, "Failed to set " + eventKindName);
    468         return readRequestId(replyPacket);
    469     }
    470 
    471     private int readRequestId(ReplyPacket replyPacket) {
    472         int requestId = replyPacket.getNextValueAsInt();
    473         assertAllDataRead(replyPacket);
    474         return requestId;
    475     }
    476 
    477     private ParsedEvent waitForEvent(byte eventKind, int requestId) {
    478         logWriter.println("Waiting for " + JDWPConstants.EventKind.getName(eventKind) +
    479                 " (request " + requestId + ")");
    480 
    481         // Wait for event.
    482         EventPacket eventPacket = debuggeeWrapper.vmMirror.receiveCertainEvent(eventKind);
    483         ParsedEvent[] parsedEvents = ParsedEvent.parseEventPacket(eventPacket);
    484 
    485         // Check that this event is the expected one.
    486         assertEquals(1, parsedEvents.length);
    487         ParsedEvent parsedEvent = parsedEvents[0];
    488         assertEventKindEquals("Invalid event kind", eventKind,  parsedEvent.getEventKind());
    489         assertEquals("Invalid request id", requestId, parsedEvent.getRequestID());
    490         return parsedEvent;
    491     }
    492 }
    493