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 Vitaly A. Provodin, Anatoly F. Bondarenko
21 */
22
23/**
24 * Created on 10.02.2005
25 */
26package org.apache.harmony.jpda.tests.jdwp.VirtualMachine;
27
28import org.apache.harmony.jpda.tests.framework.jdwp.CommandPacket;
29import org.apache.harmony.jpda.tests.framework.jdwp.JDWPCommands;
30import org.apache.harmony.jpda.tests.framework.jdwp.JDWPConstants;
31import org.apache.harmony.jpda.tests.framework.jdwp.ReplyPacket;
32import org.apache.harmony.jpda.tests.framework.jdwp.exceptions.ReplyErrorCodeException;
33import org.apache.harmony.jpda.tests.jdwp.share.JDWPSyncTestCase;
34
35import java.util.ArrayList;
36import java.util.List;
37
38
39/**
40 * JDWP Unit test for VirtualMachine.Resume command.
41 */
42public class ResumeTest extends JDWPSyncTestCase {
43
44    static final String debuggeeSignature =
45        "Lorg/apache/harmony/jpda/tests/jdwp/VirtualMachine/ResumeDebuggee;";
46
47    protected String getDebuggeeClassName() {
48        return ResumeDebuggee.class.getName();
49    }
50
51    @Override
52    protected void internalTearDown() {
53        // We need to finish the tested threads before detaching.
54        logWriter.println("Finish debuggee tested threads");
55        setStaticIntField(debuggeeSignature,
56                ResumeDebuggee.TO_FINISH_DEBUGGEE_FIELD_NAME, 99);
57        super.internalTearDown();
58    }
59
60    /**
61     * This testcase exercises VirtualMachine.Resume command.
62     * <BR>At first the test starts ResumeDebuggee which starts and runs some tested threads.
63     * <BR> Then the test performs VirtualMachine.Suspend command and checks with help of
64     * ThreadReference.Status command that all debuggee tested threads are suspended.
65     * <BR> Then the test performs VirtualMachine.Resume command and checks with help of
66     * ThreadReference.Status command that all debuggee tested threads are resumed.
67     */
68    public void testResume001() {
69        logWriter.println("==> testResume001: START...");
70
71        // The error messages in case of test failure.
72        List<String> errorMessages = new ArrayList<String>();
73
74        // All the threads we're interested in.
75        ThreadInfo[] threadInfos = createThreadInfos();
76
77        // Suspend all threads with VirtualMachine.Suspend command.
78        suspendAll();
79
80        // Check all threads are suspended now.
81        logWriter.println("\n==> Check that all tested threads are suspended " +
82                "after VirtualMachine.Suspend command...");
83        checkThreadStatus(threadInfos, true, errorMessages);
84
85        // Resume all threads with VirtualMachine.Resume command.
86        resumeAll();
87
88        // Check all threads are NOT suspended anymore.
89        logWriter.println("\n==> Check that all tested threads are resumed " +
90                "after VirtualMachine.Resume command...");
91        checkThreadStatus(threadInfos, false, errorMessages);
92
93        if (!errorMessages.isEmpty()) {
94            // Print error messages first.
95            for (String errorMessage : errorMessages) {
96                logWriter.printError(errorMessage + "\n");
97            }
98            printErrorAndFail("\ntestResume001 FAILED");
99        } else {
100            logWriter.println("\n==> testResume001 - OK!");
101        }
102    }
103
104    /**
105     * This testcase exercises VirtualMachine.Resume command.
106     * <BR>At first the test starts ResumeDebuggee which starts and runs some
107     * tested threads.
108     * <BR> Then the test performs VirtualMachine.Suspend command twice and
109     * checks, with help of ThreadReference.Status command, that all debuggee
110     * tested threads are suspended.
111     * <BR> Then the test performs VirtualMachine.Resume command and checks
112     * that all debuggee tested threads are still suspended.
113     * <BR> Then the test performs VirtualMachine.Resume command again and
114     * checks that all debuggee tested threads are resumed.
115     */
116    public void testResume002() {
117        logWriter.println("==> testResume002: START...");
118
119        // The error messages in case of test failure.
120        List<String> errorMessages = new ArrayList<String>();
121
122        // All the threads we're interested in.
123        ThreadInfo[] threadInfos = createThreadInfos();
124
125        // Suspend all threads with VirtualMachine.Suspend command.
126        suspendAll();
127
128        // Check all threads are suspended now.
129        logWriter.println("\n==> Check that all tested threads are suspended " +
130                "after VirtualMachine.Suspend command...");
131        checkThreadStatus(threadInfos, true, errorMessages);
132
133        // Suspend all threads again.
134        suspendAll();
135
136        // Check all threads are still suspended.
137        logWriter.println("\n==> Check that all tested threads are still " +
138                "suspended after another VirtualMachine.Suspend command...");
139        checkThreadStatus(threadInfos, true, errorMessages);
140
141        // Resume all threads with VirtualMachine.Resume command.
142        resumeAll();
143
144        // Check all threads are still suspended.
145        logWriter.println("\n==> Check that all tested threads are still " +
146                "suspended after VirtualMachine.Resume command...");
147        checkThreadStatus(threadInfos, true, errorMessages);
148
149        // Resume all threads again.
150        resumeAll();
151
152        // Check all threads are NOT suspended anymore.
153        logWriter.println("\n==> Check that all tested threads are resumed " +
154                "after VirtualMachine.Resume command...");
155        checkThreadStatus(threadInfos, false, errorMessages);
156
157        if (!errorMessages.isEmpty()) {
158            // Print error messages first.
159            for (String errorMessage : errorMessages) {
160                logWriter.printError(errorMessage + "\n");
161            }
162            printErrorAndFail("\ntestResume002 FAILED");
163        } else {
164            logWriter.println("\n==> testResume002 - OK!");
165        }
166    }
167
168    /**
169     * This testcase exercises VirtualMachine.Resume command.
170     * <BR>At first the test starts ResumeDebuggee which starts and runs some
171     * tested threads.
172     * <BR> Then the test performs VirtualMachine.Resume command and checks it
173     * does not cause any error if we do not perform VirtualMachine.Suspend
174     * before.
175     * <BR> Then the test performs VirtualMachine.Suspend command and checks
176     * that all debuggee tested threads are suspended.
177     * <BR> Then the test performs VirtualMachine.Resume command and checks
178     * that all debuggee tested threads are resumed.
179     */
180    public void testResume003() {
181        logWriter.println("==> testResume002: START...");
182
183        // The error messages in case of test failure.
184        List<String> errorMessages = new ArrayList<String>();
185
186        // All the threads we're interested in.
187        ThreadInfo[] threadInfos = createThreadInfos();
188
189        // Resume all threads: should be a no-op.
190        resumeAll();
191
192        // Check all threads are NOT suspended.
193        logWriter.println("\n==> Check that no tested thread is suspended " +
194                "after VirtualMachine.Resume command...");
195        checkThreadStatus(threadInfos, false, errorMessages);
196
197        // Suspend all threads with VirtualMachine.Suspend command.
198        suspendAll();
199
200        // Check all threads are suspended now.
201        logWriter.println("\n==> Check that all tested threads are suspended " +
202                "after VirtualMachine.Suspend command...");
203        checkThreadStatus(threadInfos, true, errorMessages);
204
205        // Resume all threads with VirtualMachine.Resume command.
206        resumeAll();
207
208        // Check all threads are NOT suspended anymore.
209        logWriter.println("\n==> Check that all tested threads are resumed " +
210                "after VirtualMachine.Resume command...");
211        checkThreadStatus(threadInfos, false, errorMessages);
212
213        if (!errorMessages.isEmpty()) {
214            // Print error messages first.
215            for (String errorMessage : errorMessages) {
216                logWriter.printError(errorMessage + "\n");
217            }
218            printErrorAndFail("\ntestResume002 FAILED");
219        } else {
220            logWriter.println("\n==> testResume002 - OK!");
221        }
222    }
223    private static class ThreadInfo {
224        final String threadName;
225        long threadId = 0;
226
227        public ThreadInfo(String threadName) {
228            this.threadName = threadName;
229        }
230    }
231
232    /**
233     * Suspends all threads using VirtualMachine.Suspend command.
234     */
235    private void suspendAll() {
236        logWriter.println("\n==> Send VirtualMachine.Suspend command...");
237        CommandPacket packet = new CommandPacket(
238                JDWPCommands.VirtualMachineCommandSet.CommandSetID,
239                JDWPCommands.VirtualMachineCommandSet.SuspendCommand);
240        ReplyPacket reply = debuggeeWrapper.vmMirror.performCommand(packet);
241        checkReplyPacket(reply, "VirtualMachine.Suspend");
242        logWriter.println("==> VirtualMachine.Suspend command - OK.");
243    }
244
245    /**
246     * Resumes all threads using VirtualMachine.Resume command.
247     */
248    private void resumeAll() {
249        logWriter.println("\n==> Send VirtualMachine.Resume command...");
250        CommandPacket packet = new CommandPacket(
251                JDWPCommands.VirtualMachineCommandSet.CommandSetID,
252                JDWPCommands.VirtualMachineCommandSet.ResumeCommand);
253        ReplyPacket reply = debuggeeWrapper.vmMirror.performCommand(packet);
254        checkReplyPacket(reply, "VirtualMachine.Resume");
255        logWriter.println("==> VirtualMachine.Resume command - OK.");
256    }
257
258    /**
259     * Returns the number of threads used in the tests (including the main
260     * thread).
261     */
262    private int getThreadsNumber() {
263        String debuggeeMessage = synchronizer.receiveMessage();
264        int testedThreadsNumber = 0;
265        try {
266            testedThreadsNumber = Integer.valueOf(debuggeeMessage).intValue();
267        } catch (NumberFormatException exception) {
268            logWriter.println("## FAILURE: Exception while getting number of"
269                    + " started threads from debuggee = " + exception);
270            printErrorAndFail("\n## Can NOT get number of started threads "
271                    + "from debuggee! ");
272        }
273        return testedThreadsNumber + 1;  // to add debuggee main thread
274    }
275
276    /**
277     * Creates ThreadInfo array containing information about each tested thread:
278     * thread name and thread JDWP id.
279     */
280    private ThreadInfo[] createThreadInfos() {
281        int testedThreadsNumber = getThreadsNumber();
282        logWriter.println("==>  Number of threads in debuggee to test = "
283                + testedThreadsNumber);
284        ThreadInfo[] threadInfos = new ThreadInfo[testedThreadsNumber];
285
286        String debuggeeMainThreadName = synchronizer.receiveMessage();
287        // Initialize all threads
288        for (int i = 0, e = threadInfos.length - 1; i < e; ++i) {
289            threadInfos[i] = new ThreadInfo(ResumeDebuggee.THREAD_NAME_PATTERN + i);
290        }
291        threadInfos[threadInfos.length - 1] = new ThreadInfo(debuggeeMainThreadName);
292
293        // Getting ID of the tested thread using VirtualMachine.AllThreads.
294        ReplyPacket allThreadIDReply = null;
295        try {
296            allThreadIDReply = debuggeeWrapper.vmMirror.getAllThreadID();
297        } catch (ReplyErrorCodeException exception) {
298            logWriter.println
299                ("## FAILURE: Exception in vmMirror.getAllThreadID() = " + exception);
300            printErrorAndFail("\n## Can NOT get all ThreadID in debuggee! ");
301        }
302        int threads = allThreadIDReply.getNextValueAsInt();
303        logWriter.println("==>  Number of all threads in debuggee = " + threads);
304        for (int i = 0; i < threads; i++) {
305            long threadID = allThreadIDReply.getNextValueAsThreadID();
306            String threadName = null;
307            try {
308                threadName = debuggeeWrapper.vmMirror.getThreadName(threadID);
309            } catch (ReplyErrorCodeException exception) {
310                logWriter.println
311                    ("==> WARNING: Can NOT get thread name for threadID = " + threadID);
312                continue;
313            }
314            for (ThreadInfo threadInfo : threadInfos) {
315                if (threadInfo.threadName.equals(threadName) ) {
316                    threadInfo.threadId = threadID;
317                    break;
318                }
319            }
320        }
321
322        // Check we found thread id for each thread.
323        boolean testedThreadNotFound = false;
324        for (ThreadInfo threadInfo : threadInfos) {
325            if (threadInfo.threadId == 0) {
326                logWriter.println("## FAILURE: Tested thread is not found out "
327                        + "among debuggee threads!");
328                logWriter.println("##          Thread name = "
329                        + threadInfo.threadName);
330                testedThreadNotFound = true;
331            }
332        }
333        if (testedThreadNotFound) {
334            printErrorAndFail("\n## Some of tested threads are not found!");
335        }
336
337        return threadInfos;
338    }
339
340    /**
341     * Checks suspend status of each tested thread is the expected one.
342     *
343     * @param threadInfos
344     *          the thread information
345     * @param isSuspended
346     *          if true, thread must be suspended; otherwise thread
347     *          must not be suspended.
348     * @param errorMessages
349     *          a list of String to append error message.
350     */
351    private void checkThreadStatus(ThreadInfo[] threadInfos,
352            boolean isSuspended, List<String> errorMessages) {
353        boolean statusCommandFailed = false;
354        boolean suspendStatusFailed = false;
355
356        for (ThreadInfo threadInfo : threadInfos) {
357            logWriter.println("\n==> Check for Thread: threadID = "
358                    + threadInfo.threadId
359                    + " (" + threadInfo.threadName + ")");
360
361            logWriter.println("==> Send ThreadReference.Status command...");
362            CommandPacket packet = new CommandPacket(
363                    JDWPCommands.ThreadReferenceCommandSet.CommandSetID,
364                    JDWPCommands.ThreadReferenceCommandSet.StatusCommand);
365            packet.setNextValueAsThreadID(threadInfo.threadId);
366            ReplyPacket reply = debuggeeWrapper.vmMirror.performCommand(packet);
367            if (!checkReplyPacketWithoutFail(reply, "ThreadReference.Status command")) {
368                logWriter.println("Can't get thread status for thread " +
369                        threadInfo.threadId +
370                        " \"" + threadInfo.threadName + "\"");
371                statusCommandFailed = true;
372                continue;
373            }
374
375            int threadStatus = reply.getNextValueAsInt();
376            int suspendStatus = reply.getNextValueAsInt();
377
378            logWriter.println("==> threadStatus = " + threadStatus + " ("
379                    + JDWPConstants.ThreadStatus.getName(threadStatus) + ")");
380            logWriter.println("==> suspendStatus = " + suspendStatus + " ("
381                    + JDWPConstants.SuspendStatus.getName(suspendStatus) + ")");
382
383            boolean isThreadSuspended =
384                    (suspendStatus == JDWPConstants.SuspendStatus.SUSPEND_STATUS_SUSPENDED);
385            if (isThreadSuspended != isSuspended) {
386                logWriter.println("## FAILURE: Unexpected suspendStatus for " +
387                        "checked thread " + threadInfo.threadId +
388                        " \"" + threadInfo.threadName + "\"");
389                logWriter.println("##          Expected suspendStatus  = "
390                        + JDWPConstants.SuspendStatus.SUSPEND_STATUS_SUSPENDED
391                        + "(" + JDWPConstants.SuspendStatus.getName
392                        (JDWPConstants.SuspendStatus.SUSPEND_STATUS_SUSPENDED) +")");
393                suspendStatusFailed = true;
394                continue;
395            }
396        }
397
398        if (statusCommandFailed) {
399            errorMessages.add("## Error found out while ThreadReference.Status "
400                    + "command performing!");
401        }
402        if (suspendStatusFailed) {
403            errorMessages.add("## Unexpected suspendStatus found out!");
404        }
405    }
406}
407