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
19package org.apache.harmony.jpda.tests.jdwp.ThreadReference;
20
21import org.apache.harmony.jpda.tests.framework.jdwp.CommandPacket;
22import org.apache.harmony.jpda.tests.framework.jdwp.JDWPCommands;
23import org.apache.harmony.jpda.tests.framework.jdwp.JDWPConstants;
24import org.apache.harmony.jpda.tests.framework.jdwp.ReplyPacket;
25import org.apache.harmony.jpda.tests.framework.jdwp.TaggedObject;
26import org.apache.harmony.jpda.tests.jdwp.share.JDWPSyncTestCase;
27import org.apache.harmony.jpda.tests.share.JPDADebuggeeSynchronizer;
28
29/**
30 * JDWP Unit test for ThreadReference.OwnedMonitorsStackDepthInfo command.
31 */
32public class OwnedMonitorsStackDepthInfoTest extends JDWPSyncTestCase {
33
34    static final String thisCommandName = "ThreadReference.OwnedMonitorsStackDepthInfo command ";
35
36    protected String getDebuggeeClassName() {
37        return "org.apache.harmony.jpda.tests.jdwp.ThreadReference.OwnedMonitorsStackDepthInfoDebuggee";
38    }
39
40    // OwnedMonitorsStackDepthInfo needs canGetMonitorFrameInfo VM capability support
41    private boolean isCapability() {
42        // check capability, relevant for this test
43        logWriter.println("=> Check capability: canGetMonitorFrameInfo");
44        debuggeeWrapper.vmMirror.capabilities();
45        boolean isCapability = debuggeeWrapper.vmMirror.targetVMCapabilities.canGetMonitorFrameInfo;
46        return isCapability;
47    }
48
49    private int jdwpGetFrameCount(long threadID) {
50      CommandPacket packet = new CommandPacket(JDWPCommands.ThreadReferenceCommandSet.CommandSetID,
51                                               JDWPCommands.ThreadReferenceCommandSet.FrameCountCommand);
52      packet.setNextValueAsThreadID(threadID);
53
54      ReplyPacket reply = debuggeeWrapper.vmMirror.performCommand(packet);
55      checkReplyPacket(reply, "ThreadReference::FrameCount command");
56      return reply.getNextValueAsInt();
57    }
58
59    /**
60     * This testcase exercises ThreadReference.OwnedMonitorsStackDepthInfo
61     * command. <BR>
62     * At first the test starts OwnedMonitorsStackDepthInfoDebuggee which runs
63     * the tested thread 'TESTED_THREAD'. <BR>
64     * Then the test performs the ThreadReference.OwnedMonitorsStackDepthInfo
65     * command for the tested thread and gets list of monitor objects.
66     * The returned monitor objects are equal to expected count and their stack depth are
67     *  equal to expected depth. This test will perform MonitorInfo to guarrantee that returend
68     *  monitors do belong to the test thread.
69     */
70    public void testOwnedMonitorsStackDepthInfo() {
71        String thisTestName = "testOwnedMonitorsStackDepthInfo";
72        logWriter.println("==> " + thisTestName + " for " + thisCommandName + ": START...");
73        synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_READY);
74
75        // Ensure we signal the debuggee to continue at the end of the test.
76        finalSyncMessage = JPDADebuggeeSynchronizer.SGNL_CONTINUE;
77
78        if (!isCapability()) {
79            logWriter.println("##WARNING: this VM dosn't possess capability: canGetMonitorFrameInfo");
80            return;
81        }
82
83        // Getting ID of the tested thread
84        logWriter.println("==> testedThreadName = "
85                + OwnedMonitorsStackDepthInfoDebuggee.TESTED_THREAD);
86        logWriter.println("==> Get testedThreadID...");
87        long testedThreadID = debuggeeWrapper.vmMirror
88                .getThreadID(OwnedMonitorsStackDepthInfoDebuggee.TESTED_THREAD);
89
90        // Compose the OwnedMonitorsStackDepthInfo command
91        CommandPacket stackDepthPacket = new CommandPacket(
92                JDWPCommands.ThreadReferenceCommandSet.CommandSetID,
93                JDWPCommands.ThreadReferenceCommandSet.OwnedMonitorsStackDepthInfoCommand);
94        stackDepthPacket.setNextValueAsThreadID(testedThreadID);
95
96        // Suspend the VM before perform command
97        logWriter.println("==> testedThreadID = " + testedThreadID);
98        logWriter.println("==> suspend testedThread...");
99        debuggeeWrapper.vmMirror.suspendThread(testedThreadID);
100
101        // There are various monitors held in the outermost frames, but there may be
102        // implementation-specific locks held below that (since the thread will actually be
103        // suspended somewhere in I/O code). See OwnedMonitorsStackDepthInfoDebuggee.run().
104        int frameCount = jdwpGetFrameCount(testedThreadID);
105        int expectedMonitorCount = 3;
106        int[] expectedStackDepth = new int[] { frameCount - 4, frameCount - 4, frameCount - 2 };
107
108        // Perform the command and attain the reply package
109        ReplyPacket stackDepthReply = debuggeeWrapper.vmMirror.performCommand(stackDepthPacket);
110        checkReplyPacket(stackDepthReply, "ThreadReference::OwnedMonitorsStackDepthInfo command");
111
112        // Analyze the reply package
113        int actualMonitorCount = stackDepthReply.getNextValueAsInt();
114        logWriter.println("==> Owned monitors: " + actualMonitorCount);
115        assertTrue(actualMonitorCount >= expectedMonitorCount);
116        logWriter.println("==> CHECK: PASSED: actualMonitorCount >= expectedMonitorCount");
117
118        int currentMonitor = 0;
119        for (int i = 0; i < actualMonitorCount; ++i) {
120            // Attain monitor object ID
121            TaggedObject monitorObject = stackDepthReply.getNextValueAsTaggedObject();
122
123            // Attain monitor stack depth
124            int actualStackDepth = stackDepthReply.getNextValueAsInt();
125            logWriter.println("==> Stack depth: " + actualStackDepth);
126            if (expectedStackDepth[currentMonitor] != actualStackDepth) {
127                continue;
128            }
129
130            /*
131             *  Test the returned monitor object does belong to the test thread by MonitorInfo Command
132             */
133            // Compose the MonitorInfo Command
134            CommandPacket monitorInfoPacket = new CommandPacket(
135                    JDWPCommands.ObjectReferenceCommandSet.CommandSetID,
136                    JDWPCommands.ObjectReferenceCommandSet.MonitorInfoCommand);
137            monitorInfoPacket.setNextValueAsObjectID(monitorObject.objectID);
138
139            // Perform the command and attain the reply package
140            ReplyPacket monitorInfoReply = debuggeeWrapper.vmMirror.performCommand(monitorInfoPacket);
141            checkReplyPacket(monitorInfoReply, "ObjectReference::MonitorInfo command");
142
143            // Attain thread id from monitor info
144            long ownerThreadID = monitorInfoReply.getNextValueAsThreadID();
145            assertEquals(thisCommandName + "returned monitor is not owned by test thread", ownerThreadID, testedThreadID, null, null);
146
147            logWriter.println("==> CHECK: PASSED: returned monitor does belong to the test thread.");
148            logWriter.println("==> Monitor owner thread ID: " + ownerThreadID);
149
150            ++currentMonitor;
151        }
152
153        assertAllDataRead(stackDepthReply);
154    }
155
156
157    public void testOwnedMonitorsStackDepthInfo_Unsuspended() {
158        String thisTestName = "testOwnedMonitorsStackDepthInfo";
159        logWriter.println("==> " + thisTestName + " for " + thisCommandName
160                + ": START...");
161        synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_READY);
162
163        // Ensure we signal the debuggee to continue at the end of the test.
164        finalSyncMessage = JPDADebuggeeSynchronizer.SGNL_CONTINUE;
165
166        if (!isCapability()) {
167            logWriter
168                    .println("##WARNING: this VM dosn't possess capability: OwnedMonitorsStackDepthInfo");
169            return;
170        }
171
172        // Getting ID of the tested thread
173        logWriter.println("==> testedThreadName = "
174                + OwnedMonitorsStackDepthInfoDebuggee.TESTED_THREAD);
175        logWriter.println("==> Get testedThreadID...");
176        long testedThreadID = debuggeeWrapper.vmMirror
177                .getThreadID(OwnedMonitorsStackDepthInfoDebuggee.TESTED_THREAD);
178
179        // Compose the OwnedMonitorsStackDepthInfo command
180        CommandPacket stackDepthPacket = new CommandPacket(
181                JDWPCommands.ThreadReferenceCommandSet.CommandSetID,
182                JDWPCommands.ThreadReferenceCommandSet.OwnedMonitorsStackDepthInfoCommand);
183        stackDepthPacket.setNextValueAsThreadID(testedThreadID);
184
185        // Perform the command and attain the reply package
186        ReplyPacket checkedReply = debuggeeWrapper.vmMirror
187                .performCommand(stackDepthPacket);
188        short errorCode = checkedReply.getErrorCode();
189        if (errorCode != JDWPConstants.Error.NONE) {
190            if (errorCode == JDWPConstants.Error.THREAD_NOT_SUSPENDED) {
191                logWriter.println("=> CHECK PASSED: Expected error (THREAD_NOT_SUSPENDED) is returned");
192                return;
193            }
194        }
195        printErrorAndFail(thisCommandName + " should throw exception when VM is not suspended.");
196    }
197}
198