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.VirtualMachine;
20 
21 import org.apache.harmony.jpda.tests.framework.TestErrorException;
22 import org.apache.harmony.jpda.tests.framework.jdwp.CommandPacket;
23 import org.apache.harmony.jpda.tests.framework.jdwp.JDWPCommands;
24 import org.apache.harmony.jpda.tests.framework.jdwp.JDWPConstants;
25 import org.apache.harmony.jpda.tests.framework.jdwp.Value;
26 import org.apache.harmony.jpda.tests.jdwp.share.JDWPSyncTestCase;
27 import org.apache.harmony.jpda.tests.share.JPDADebuggeeSynchronizer;
28 
29 import java.io.IOException;
30 
31 /**
32  * JDWP Unit test for VirtualMachine.Dispose command while a thread is invoking a method.
33  */
34 public class DisposeDuringInvokeTest extends JDWPSyncTestCase {
35 
36     @Override
getDebuggeeClassName()37     protected String getDebuggeeClassName() {
38         return DisposeDuringInvokeDebuggee.class.getName();
39     }
40 
41     /**
42      * This testcase exercises VirtualMachine.Dispose command when a thread, suspended by an
43      * event, is still invoking a method.
44      * <BR>At first the test starts DisposeDuringInvokeDebuggee debuggee.
45      * <BR>Then the test sets a breakpoint so that the tested thread (DebuggeeThread) gets suspended
46      * by an event. Once this thread is suspended, we send it an ObjectReference.InvokeMethod
47      * command to initiate a method invocation executing in that thread. The method will synchronize
48      * with the test, waiting for a signal to continue its execution.
49      * <BR>While the tested thread waits for the signal, we send a VirtualMachine.Dispose command to
50      * the debuggee and sends the expected signal so the tested thread completes the method
51      * invocation.
52      * <BR>Finally, we wait for the debuggee's main thread to signal us when the tested thread has
53      * normally terminated after we dispose the JDWP connection.
54      */
testDisposeDuringInvoke()55     public void testDisposeDuringInvoke() {
56         synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_READY);
57 
58         // Set breakpoint so the DebuggeeThread suspends itself only.
59         long classID = getClassIDBySignature(getDebuggeeClassSignature());
60         long invokedMethodId = getMethodID(classID,
61                 DisposeDuringInvokeDebuggee.INVOKED_METHOD_NAME);
62         int breakpointID = debuggeeWrapper.vmMirror.setBreakpointAtMethodBegin(classID,
63                 DisposeDuringInvokeDebuggee.BREAKPOINT_METHOD_NAME,
64                 JDWPConstants.SuspendPolicy.EVENT_THREAD);
65         long thisObjectId = getReceiverObjectId(classID);
66 
67         // Continue debuggee.
68         synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
69 
70         // Wait for the DebuggeeThread to suspend on the breakpoint.
71         long threadID = debuggeeWrapper.vmMirror.waitForBreakpoint(breakpointID);
72 
73         // Send ObjectReference.InvokeMethod command.
74         CommandPacket command = new CommandPacket(
75                 JDWPCommands.ObjectReferenceCommandSet.CommandSetID,
76                 JDWPCommands.ObjectReferenceCommandSet.InvokeMethodCommand);
77         command.setNextValueAsThreadID(thisObjectId);
78         command.setNextValueAsThreadID(threadID);
79         command.setNextValueAsClassID(classID);
80         command.setNextValueAsMethodID(invokedMethodId);
81         command.setNextValueAsInt(0);
82         command.setNextValueAsInt(0);
83         try {
84             debuggeeWrapper.vmMirror.sendCommand(command);
85         } catch (IOException e) {
86             throw new TestErrorException("Failed to send ObjectReference.InvokeMethod command", e);
87         }
88 
89         // Wait for the DebuggeeThread to start method invocation.
90         synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_READY);
91 
92         // Detach from debuggee with a VirtualMachine.Dispose command.
93         debuggeeWrapper.vmMirror.dispose();
94 
95         // Signal DebuggeeThread to continue so it completes method invocation.
96         synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
97 
98         // Wait for the DebuggeeThread to terminate. The debuggee's main thread waits for it
99         // (using Thread.join) before signaling us.
100         synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_READY);
101 
102         // The test is a success: resume the debuggee to finish
103         synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
104     }
105 
106     /**
107      * Returns the object ID of the debuggee object to issue the ObjectReference.InvokeMethod
108      * command.
109      *
110      * @param classID
111      *          the debuggee class ID.
112      * @return the object ID of the debuggee
113      */
getReceiverObjectId(long classID)114     private long getReceiverObjectId(long classID) {
115         long thisObjectFieldID = checkField(classID, DisposeDuringInvokeDebuggee.THIS_FIELD_NAME);
116         Value thisObjectValue =
117                 debuggeeWrapper.vmMirror.getReferenceTypeValue(classID, thisObjectFieldID);
118         assertEquals("Invalid value tag:", JDWPConstants.Tag.OBJECT_TAG, thisObjectValue.getTag());
119         return thisObjectValue.getLongValue();
120     }
121 }
122