1f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz/*
2f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz * Licensed to the Apache Software Foundation (ASF) under one or more
3f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz * contributor license agreements.  See the NOTICE file distributed with
4f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz * this work for additional information regarding copyright ownership.
5f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz * The ASF licenses this file to You under the Apache License, Version 2.0
6f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz * (the "License"); you may not use this file except in compliance with
7f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz * the License.  You may obtain a copy of the License at
8f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz *
9f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz *     http://www.apache.org/licenses/LICENSE-2.0
10f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz *
11f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz *  Unless required by applicable law or agreed to in writing, software
12f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz *  distributed under the License is distributed on an "AS IS" BASIS,
13f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz *
15f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz *  See the License for the specific language governing permissions and
16f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz *  limitations under the License.
17f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz */
18f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz
19f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertzpackage org.apache.harmony.jpda.tests.jdwp.share;
20f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz
21f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertzimport org.apache.harmony.jpda.tests.framework.TestErrorException;
22f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertzimport org.apache.harmony.jpda.tests.framework.jdwp.CommandPacket;
23f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertzimport org.apache.harmony.jpda.tests.framework.jdwp.JDWPConstants;
24f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertzimport org.apache.harmony.jpda.tests.framework.jdwp.ReplyPacket;
25f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertzimport org.apache.harmony.jpda.tests.jdwp.share.debuggee.InvokeMethodWithSuspensionDebuggee;
26f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertzimport org.apache.harmony.jpda.tests.share.JPDADebuggeeSynchronizer;
27f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz
28f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertzimport java.io.IOException;
29f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz
30f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz/**
31f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz * Base class for tests checking invoke command with thread suspension.
32f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz */
33f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertzpublic abstract class JDWPInvokeMethodWithSuspensionTestCase extends JDWPSyncTestCase {
34f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz
35f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz    @Override
36f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz    protected final String getDebuggeeClassName() {
37f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        return InvokeMethodWithSuspensionDebuggee.class.getName();
38f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz    }
39f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz
40f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz    /**
41f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz     * This methods runs the {@link InvokeMethodWithSuspensionDebuggee} then sets up the
42f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz     * following breakpoints:
43f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz     * - breakpoint #1 to suspend the current thread only when the debuggee starts
44f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz     * - breakpoint #2 to suspend all threads from a new thread started by a method called through
45f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz     * JDWP.
46f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz     * When we receive the event for breakpoint #1, we issue a request to invoke a method (or a
47f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz     * constructor) in the event thread (suspended on the breakpoint). The event thread starts
48f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz     * another child thread and loops as long as the child is running. However, we do not read the
49f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz     * reply of the invoke yet.
50f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz     * Next, we wait for the new thread to hit breakpoint #2. We resume all threads in the debuggee
51f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz     * and read the reply of the invoke.
52f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz     * Finally, we resume the thread that completed the invoke.
53f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz     *
54f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz     * @param invokedMethodName
55f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz     *          the name of the method to invoke
56f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz     */
57f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz    protected void runInvokeMethodTest(String invokedMethodName) {
58f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        // Wait for debuggee to start.
59f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_READY);
60f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz
61f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        long classID = getClassIDBySignature(getDebuggeeClassSignature());
62f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        long invokeMethodID = getMethodID(classID, invokedMethodName);
63f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz
64f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        // Set breakpoint with EVENT_THREAD suspend policy so only the event thread is suspended.
65f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        // We will invoke the method in this thread.
66f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        int breakpointEventThread = debuggeeWrapper.vmMirror.setBreakpointAtMethodBegin(classID,
67f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz                InvokeMethodWithSuspensionDebuggee.BREAKPOINT_EVENT_THREAD_METHOD_NAME,
68f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz                JDWPConstants.SuspendPolicy.EVENT_THREAD);
69f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz
70f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        // Set breakpoint with ALL suspend policy to suspend all threads. The thread started
71f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        // during the invoke will suspend all threads, including the thread executing the invoke.
72f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        int breakpointAllThreads = debuggeeWrapper.vmMirror.setBreakpointAtMethodBegin(classID,
73f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz                InvokeMethodWithSuspensionDebuggee.BREAKPOINT_ALL_THREADS_METHOD_NAME,
74f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz                JDWPConstants.SuspendPolicy.ALL);
75f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz
76f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        // Tell the debuggee to continue.
77f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
78f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz
79f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        // Wait for breakpoint and get id of suspended thread.
80f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        long eventThreadOne = debuggeeWrapper.vmMirror.waitForBreakpoint(breakpointEventThread);
81f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        int suspendCount = debuggeeWrapper.vmMirror.getThreadSuspendCount(eventThreadOne);
82f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        assertEquals("Invalid suspend count:", 1, suspendCount);
83f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz
84f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        // Send command but does not read reply now. That invoked method starts another thread
85f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        // that is going to hit a breakpoint and suspend all threads, including the thread invoking
86f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        // the method. The invoke can only complete when that new thread terminates, which requires
87f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        // we send a VirtualMachine.Resume command.
88f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        final int invoke_options = 0;  // resume/suspend all threads before/after the invoke.
89f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        CommandPacket invokeMethodCommand = buildInvokeCommand(eventThreadOne, classID,
90f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz                invokeMethodID, invoke_options);
91f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz
92f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        String commandName = getInvokeCommandName();
93f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        logWriter.println("Send " + commandName);
94f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        int invokeMethodCommandID = -1;
95f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        try {
96f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz            invokeMethodCommandID = debuggeeWrapper.vmMirror.sendCommand(invokeMethodCommand);
97f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        } catch (IOException e) {
98f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz            logWriter.printError("Failed to send " + commandName, e);
99f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz            fail();
100f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        }
101f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz
102f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        // Wait for 2nd breakpoint to hit.
103f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        long eventThreadTwo = debuggeeWrapper.vmMirror.waitForBreakpoint(breakpointAllThreads);
104f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        suspendCount = debuggeeWrapper.vmMirror.getThreadSuspendCount(eventThreadTwo);
105f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        assertEquals("Invalid suspend count:", 1, suspendCount);
106f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz
107f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        // At this point, the event thread #1 must have been suspended by event thread #2. Since
108f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        // the invoke has resumed it too, its suspend count must remain 1.
109f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        suspendCount = debuggeeWrapper.vmMirror.getThreadSuspendCount(eventThreadOne);
110f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        assertEquals("Invalid suspend count:", 1, suspendCount);
111f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz
112f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        // Test that sending another invoke command in the same thread returns an error.
113f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        CommandPacket anotherInvokeMethodCommand = buildInvokeCommand(eventThreadOne, classID,
114f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz                invokeMethodID, invoke_options);
115f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        ReplyPacket anotherInvokeMethodReply =
116f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz                debuggeeWrapper.vmMirror.performCommand(anotherInvokeMethodCommand);
117f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        // The RI returns INVALID_THREAD error while ART returns ALREADY_INVOKING error which is
118f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        // more accurate. We only test we get an error so we can run the test with both runtimes.
119f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        assertTrue("Expected an error",
120f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz                anotherInvokeMethodReply.getErrorCode() != JDWPConstants.Error.NONE);
121f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz
122f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        // Send a VirtualMachine.Resume to resume all threads. This will unblock the event thread
123f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        // with the invoke in-progress.
124f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        logWriter.println("Resume all threads");
125f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        resumeDebuggee();
126f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz
127f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        // Now we can read the invoke reply.
128f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        ReplyPacket invokeMethodReply = null;
129f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        try {
130f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz            logWriter.println("Receiving reply for command " + invokeMethodCommandID + " ...");
131f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz            invokeMethodReply = debuggeeWrapper.vmMirror.receiveReply(invokeMethodCommandID);
132f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        } catch (Exception e) {
133f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz            throw new TestErrorException("Did not receive invoke reply", e);
134f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        }
135f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        checkReplyPacket(invokeMethodReply, commandName + " command");
136f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        logWriter.println("Received reply for command " + invokeMethodCommandID + " OK");
137f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz
138f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        checkInvokeReply(invokeMethodReply);
139f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz
140f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        // The invoke is complete but the thread is still suspended: let's resume it now.
141f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        suspendCount = debuggeeWrapper.vmMirror.getThreadSuspendCount(eventThreadOne);
142f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        assertEquals("Invalid suspend count:", 1, suspendCount);
143f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz
144f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        logWriter.println("Resume event thread #1");
145f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz        debuggeeWrapper.vmMirror.resumeThread(eventThreadOne);
146f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz    }
147f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz
148f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz    /**
149f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz     * Builds the packed for the tested JDWP command.
150f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz     *
151f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz     * @param threadId
152f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz     *          the id of the thread that will invoke the method
153f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz     * @param classID
154f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz     *          the class ID of the invoked method
155f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz     * @param methodId
156f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz     *          the ID of the invoke method
157f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz     * @param invokeOptions
158f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz     *          options for the invoke
159f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz     * @return a command
160f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz     */
161f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz    protected abstract CommandPacket buildInvokeCommand(long threadId, long classID,
162f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz                                                        long methodId, int invokeOptions);
163f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz
164f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz    /**
165f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz     * Returns the name of the command returned by {@link #buildInvokeCommand} for printing.
166f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz     *
167f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz     * @return the name of the invoke command sent to the debuggee
168f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz     */
169f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz    protected abstract String getInvokeCommandName();
170f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz
171f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz    /**
172f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz     * Checks the reply for the tested JDWP command.
173f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz     *
174f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz     * @param reply the reply of the invoke
175f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz     */
176f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz    protected abstract void checkInvokeReply(ReplyPacket reply);
177f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz
178f8670f3c29626892e32d30aa00ce8e4b94bd9609Sebastien Hertz}
179