1 /*
2  * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! templete parameters !!!!
24 
25 // VMDeathEvent  Interface Name VMDeathEvent
26 // _itself_  Method Name                _itself_
27 // vmdeath003  Test Name                vmdeath003
28 // ------------------------------------------------------
29 
30 package nsk.jdi.VMDeathEvent._itself_;
31 
32 import nsk.share.*;
33 import nsk.share.jpda.*;
34 import nsk.share.jdi.*;
35 
36 import com.sun.jdi.*;
37 import com.sun.jdi.event.*;
38 import com.sun.jdi.request.*;
39 
40 import java.util.*;
41 import java.io.*;
42 
43 /**
44  * The test for the implementation of an object of the type     <BR>
45  * VMDeathEvent.                                                <BR>
46  *                                                              <BR>
47  * The test checks that the interface                           <BR>
48  * <code>com.sun.jdi.VMDeathEvent</code>                        <BR>
49  * complies with its spec.                                      <BR>
50  * <BR>
51  * The case to test includes receiving no VMDeathEvent          <BR>
52  * as a response to VirtualMachine.dispose();                   <BR>
53  * <BR>
54  * The test works as follows.                                   <BR>
55  * <BR>
56  * Upon launching debuggee's VM which will be suspended,                <BR>
57  * a debugger waits for the VMStartEvent within a predefined            <BR>
58  * time interval. If no the VMStartEvent received, the test is FAILED.  <BR>
59  * Upon getting the VMStartEvent, it makes the request for debuggee's   <BR>
60  * ClassPrepareEvent with SUSPEND_EVENT_THREAD, resumes the VM,         <BR>
61  * and waits for the event within the predefined time interval.         <BR>
62  * If no the ClassPrepareEvent received, the test is FAILED.            <BR>
63  * Upon getting the ClassPrepareEvent,                                  <BR>
64  * the debugger sets up the breakpoint with SUSPEND_EVENT_THREAD        <BR>
65  * within debuggee's special methodForCommunication().                  <BR>
66  * <BR>
67  * Then to test the interface,                                          <BR>
68  * the debugger invokes the method VirtualMachine.dispose() and         <BR>
69  * checks up on the event received in the response to.                  <BR>
70  * <BR>
71  */
72 
73 public class vmdeath003 {
74 
75     //----------------------------------------------------- templete section
76     static final int PASSED = 0;
77     static final int FAILED = 2;
78     static final int PASS_BASE = 95;
79 
80     //----------------------------------------------------- templete parameters
81     static final String
82     sHeader1 = "\n==> nsk/jdi/VMDeathEvent/_itself_/vmdeath003 ",
83     sHeader2 = "--> debugger: ",
84     sHeader3 = "##> debugger: ";
85 
86     //----------------------------------------------------- main method
87 
main(String argv[])88     public static void main (String argv[]) {
89 
90         int result = run(argv, System.out);
91 
92         System.exit(result + PASS_BASE);
93     }
94 
run(String argv[], PrintStream out)95     public static int run (String argv[], PrintStream out) {
96 
97         int exitCode = new vmdeath003().runThis(argv, out);
98 
99         if (exitCode != PASSED) {
100             System.out.println("TEST FAILED");
101         }
102         return testExitCode;
103     }
104 
105     //--------------------------------------------------   log procedures
106 
107     private static Log  logHandler;
108 
log1(String message)109     private static void log1(String message) {
110         logHandler.display(sHeader1 + message);
111     }
log2(String message)112     private static void log2(String message) {
113         logHandler.display(sHeader2 + message);
114     }
log3(String message)115     private static void log3(String message) {
116         logHandler.complain(sHeader3 + message);
117     }
118 
119     //  ************************************************    test parameters
120 
121     private String debuggeeName =
122         "nsk.jdi.VMDeathEvent._itself_.vmdeath003a";
123 
124     //====================================================== test program
125     //------------------------------------------------------ common section
126 
127     static Debugee          debuggee;
128     static ArgumentHandler  argsHandler;
129 
130     static int waitTime;
131 
132     static VirtualMachine      vm            = null;
133     static EventRequestManager eventRManager = null;
134     static EventQueue          eventQueue    = null;
135     static EventSet            eventSet      = null;
136     static EventIterator       eventIterator = null;
137 
138     static ReferenceType       debuggeeClass = null;
139 
140     static int  testExitCode = PASSED;
141 
142 
143     class JDITestRuntimeException extends RuntimeException {
JDITestRuntimeException(String str)144         JDITestRuntimeException(String str) {
145             super("JDITestRuntimeException : " + str);
146         }
147     }
148 
149     //------------------------------------------------------ methods
150 
runThis(String argv[], PrintStream out)151     private int runThis (String argv[], PrintStream out) {
152 
153         argsHandler     = new ArgumentHandler(argv);
154         logHandler      = new Log(out, argsHandler);
155         Binder binder   = new Binder(argsHandler, logHandler);
156 
157         waitTime        = argsHandler.getWaitTime() * 60000;
158 
159         try {
160             log2("launching a debuggee :");
161             log2("       " + debuggeeName);
162             if (argsHandler.verbose()) {
163                 debuggee = binder.bindToDebugee(debuggeeName + " -vbs");
164             } else {
165                 debuggee = binder.bindToDebugee(debuggeeName);
166             }
167             if (debuggee == null) {
168                 log3("ERROR: no debuggee launched");
169                 return FAILED;
170             }
171             log2("debuggee launched");
172         } catch ( Exception e ) {
173             log3("ERROR: Exception : " + e);
174             log2("       test cancelled");
175             return FAILED;
176         }
177 
178         debuggee.redirectOutput(logHandler);
179 
180         vm = debuggee.VM();
181 
182         eventQueue = vm.eventQueue();
183         if (eventQueue == null) {
184             log3("ERROR: eventQueue == null : TEST ABORTED");
185             vm.exit(PASS_BASE);
186             return FAILED;
187         }
188 
189         log2("invocation of the method runTest()");
190         switch (runTest()) {
191 
192             case 0 :  log2("test phase has finished normally");
193                       log2("   waiting for the debuggee to finish ...");
194                       debuggee.waitFor();
195 
196                       log2("......getting the debuggee's exit status");
197                       int status = debuggee.getStatus();
198                       if (status != PASS_BASE) {
199                           log3("ERROR: debuggee returned UNEXPECTED exit status: " +
200                               status + " != PASS_BASE");
201                           testExitCode = FAILED;
202                       } else {
203                           log2("......debuggee returned expected exit status: " +
204                               status + " == PASS_BASE");
205                       }
206                       break;
207 
208             default : log3("ERROR: runTest() returned unexpected value");
209 
210             case 1 :  log3("test phase has not finished normally: debuggee is still alive");
211                       log2("......forcing: vm.exit();");
212                       testExitCode = FAILED;
213                       try {
214                           vm.exit(PASS_BASE);
215                       } catch ( Exception e ) {
216                           log3("ERROR: Exception : e");
217                       }
218                       break;
219 
220             case 2 :  //log3("test cancelled due to VMDisconnectedException");
221                       log2("......trying: vm.process().destroy();");
222 //                      testExitCode = FAILED;
223                       try {
224                           Process vmProcess = vm.process();
225                           if (vmProcess != null) {
226                               vmProcess.destroy();
227                           }
228                       } catch ( Exception e ) {
229                           log3("ERROR: Exception : e");
230                       }
231                       break;
232             }
233 
234         return testExitCode;
235     }
236 
237 
238    /*
239     * Return value: 0 - normal end of the test
240     *               1 - ubnormal end of the test
241     *               2 - VMDisconnectedException while test phase
242     */
243 
runTest()244     private int runTest() {
245 
246         try {
247             testRun();
248 
249             log2("waiting for VMDisconnectEvent");
250             getEventSet();
251             Event newEvent = eventIterator.nextEvent();
252             if (newEvent instanceof VMDeathEvent)  {
253                 testExitCode = FAILED;
254                 log3("ERROR: last event is the VMDeathEvent");
255                 return 0;
256             }
257             if (newEvent instanceof VMDisconnectEvent) {
258                 log2("......received : VMDisconnectEvent");
259                 return 2;
260             }
261 
262             throw new JDITestRuntimeException("** Unexpected event **");
263         } catch ( VMDisconnectedException e ) {
264             log3("ERROR: VMDisconnectedException : " + e);
265             return 2;
266         } catch ( Exception e ) {
267             log3("ERROR: Exception : " + e);
268             return 1;
269         }
270 
271     }
272 
testRun()273     private void testRun()
274                  throws JDITestRuntimeException, Exception {
275 
276         eventRManager = vm.eventRequestManager();
277 
278         ClassPrepareRequest cpRequest = eventRManager.createClassPrepareRequest();
279         cpRequest.setSuspendPolicy( EventRequest.SUSPEND_EVENT_THREAD);
280         cpRequest.addClassFilter(debuggeeName);
281 
282         cpRequest.enable();
283         vm.resume();
284         getEventSet();
285         cpRequest.disable();
286 
287         ClassPrepareEvent event = (ClassPrepareEvent) eventIterator.next();
288         debuggeeClass = event.referenceType();
289 
290         if (!debuggeeClass.name().equals(debuggeeName))
291            throw new JDITestRuntimeException("** Unexpected ClassName for ClassPrepareEvent **");
292 
293         log2("      received: ClassPrepareEvent for debuggeeClass");
294 
295         String bPointMethod = "methodForCommunication";
296         String lineForComm  = "lineForComm";
297         BreakpointRequest bpRequest;
298 
299         bpRequest = settingBreakpoint(threadByName("main"),
300                                       debuggeeClass,
301                                       bPointMethod, lineForComm, "zero");
302         bpRequest.enable();
303 
304     //------------------------------------------------------  testing section
305 
306         log1("     TESTING BEGINS");
307 
308         for (int i = 0; ; i++) {
309 
310             vm.resume();
311             breakpointForCommunication();
312 
313             int instruction = ((IntegerValue)
314                                (debuggeeClass.getValue(debuggeeClass.fieldByName("instruction")))).value();
315 
316             if (instruction == 0) {
317                 vm.resume();
318                 break;
319             }
320 
321             log1(":::::: case: # " + i);
322 
323             //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ variable part
324 
325             log2("......vm.dispose();  :: VMDeathEvent is NOT excpected");
326 
327             vm.dispose();
328             break;
329 
330             //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
331         }
332         log1("    TESTING ENDS");
333         return;
334     }
335 
threadByName(String name)336     private ThreadReference threadByName(String name)
337                  throws JDITestRuntimeException {
338 
339         List         all = vm.allThreads();
340         ListIterator li  = all.listIterator();
341 
342         for (; li.hasNext(); ) {
343             ThreadReference thread = (ThreadReference) li.next();
344             if (thread.name().equals(name))
345                 return thread;
346         }
347         throw new JDITestRuntimeException("** Thread IS NOT found ** : " + name);
348     }
349 
350    /*
351     * private BreakpointRequest settingBreakpoint(ThreadReference, ReferenceType,
352     *                                             String, String, String)
353     *
354     * It sets up a breakpoint at given line number within a given method in a given class
355     * for a given thread.
356     *
357     * Return value: BreakpointRequest object  in case of success
358     *
359     * JDITestRuntimeException   in case of an Exception thrown within the method
360     */
361 
settingBreakpoint( ThreadReference thread, ReferenceType testedClass, String methodName, String bpLine, String property)362     private BreakpointRequest settingBreakpoint ( ThreadReference thread,
363                                                   ReferenceType testedClass,
364                                                   String methodName,
365                                                   String bpLine,
366                                                   String property)
367             throws JDITestRuntimeException {
368 
369         log2("......setting up a breakpoint:");
370         log2("       thread: " + thread + "; class: " + testedClass +
371                         "; method: " + methodName + "; line: " + bpLine);
372 
373         List              alllineLocations = null;
374         Location          lineLocation     = null;
375         BreakpointRequest breakpRequest    = null;
376 
377         try {
378             Method  method  = (Method) testedClass.methodsByName(methodName).get(0);
379 
380             alllineLocations = method.allLineLocations();
381 
382             int n =
383                 ( (IntegerValue) testedClass.getValue(testedClass.fieldByName(bpLine) ) ).value();
384             if (n > alllineLocations.size()) {
385                 log3("ERROR:  TEST_ERROR_IN_settingBreakpoint(): number is out of bound of method's lines");
386             } else {
387                 lineLocation = (Location) alllineLocations.get(n);
388                 try {
389                     breakpRequest = eventRManager.createBreakpointRequest(lineLocation);
390                     breakpRequest.putProperty("number", property);
391                     breakpRequest.addThreadFilter(thread);
392                     breakpRequest.setSuspendPolicy( EventRequest.SUSPEND_EVENT_THREAD);
393                 } catch ( Exception e1 ) {
394                     log3("ERROR: inner Exception within settingBreakpoint() : " + e1);
395                     breakpRequest    = null;
396                 }
397             }
398         } catch ( Exception e2 ) {
399             log3("ERROR: ATTENTION:  outer Exception within settingBreakpoint() : " + e2);
400             breakpRequest    = null;
401         }
402 
403         if (breakpRequest == null) {
404             log2("      A BREAKPOINT HAS NOT BEEN SET UP");
405             throw new JDITestRuntimeException("**FAILURE to set up a breakpoint**");
406         }
407 
408         log2("      a breakpoint has been set up");
409         return breakpRequest;
410     }
411 
412 
getEventSet()413     private void getEventSet()
414                  throws JDITestRuntimeException {
415         try {
416 //            log2("       eventSet = eventQueue.remove(waitTime);");
417             eventSet = eventQueue.remove(waitTime);
418             if (eventSet == null) {
419                 throw new JDITestRuntimeException("** TIMEOUT while waiting for event **");
420             }
421 //            log2("       eventIterator = eventSet.eventIterator;");
422             eventIterator = eventSet.eventIterator();
423         } catch ( Exception e ) {
424             throw new JDITestRuntimeException("** EXCEPTION while waiting for event ** : " + e);
425         }
426     }
427 
428 
breakpointForCommunication()429     private void breakpointForCommunication()
430                  throws JDITestRuntimeException {
431 
432         log2("breakpointForCommunication");
433         getEventSet();
434 
435         if (eventIterator.nextEvent() instanceof BreakpointEvent)
436             return;
437 
438         throw new JDITestRuntimeException("** event IS NOT a breakpoint **");
439     }
440 
441 }
442