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 
24 package nsk.jdi.WatchpointEvent.field;
25 
26 import com.sun.jdi.*;
27 import com.sun.jdi.event.*;
28 import com.sun.jdi.request.*;
29 
30 import java.io.*;
31 import java.util.Iterator;
32 import java.util.List;
33 
34 import nsk.share.*;
35 import nsk.share.jpda.*;
36 import nsk.share.jdi.*;
37 
38 
39 // This class is the debugger in the test
40 
41 public class field001 {
42     static final int PASSED = 0;
43     static final int FAILED = 2;
44     static final int JCK_STATUS_BASE = 95;
45 
46     static final int TIMEOUT_DELTA = 1000; // milliseconds
47 
48     static final String COMMAND_READY = "ready";
49     static final String COMMAND_QUIT  = "quit";
50     static final String COMMAND_GO    = "go";
51     static final String COMMAND_DONE  = "done";
52 
53     static final String DEBUGGEE_NAME = "nsk.jdi.WatchpointEvent.field.field001a";
54     static final String CHECKED_CLASS_NAME = "nsk.jdi.WatchpointEvent.field.CheckedClass";
55 
56     static final int EXPECTED_ACCESS_EVENTS = field001a.ACCESS_COUNT;
57     static final int EXPECTED_MODIFICATION_EVENTS = field001a.MODIFICATIONS_COUNT;
58 
59     static private Debugee debuggee;
60     static private VirtualMachine vm;
61     static private IOPipe pipe;
62     static private Log log;
63     static private ArgumentHandler argHandler;
64     static private EventSet eventSet;
65 
66     static private ReferenceType rType;
67     static private WatchpointRequest wpRequest;
68     static private List fieldsList;
69 
70     static private volatile boolean testFailed;
71     static private volatile boolean done;
72     static private volatile int requestsCount, awpEventsCount, mwpEventsCount;
73 
main(String args[])74     public static void main (String args[]) {
75           System.exit(run(args, System.out) + JCK_STATUS_BASE);
76     }
77 
run(final String args[], final PrintStream out)78     public static int run(final String args[], final PrintStream out) {
79 
80         testFailed = false;
81         done = false;
82         requestsCount = 0;
83         awpEventsCount = 0;
84         mwpEventsCount = 0;
85 
86         argHandler = new ArgumentHandler(args);
87         log = new Log(out, argHandler);
88 
89         // launch debuggee
90         Binder binder = new Binder(argHandler, log);
91         log.display("Connecting to debuggee");
92         debuggee = binder.bindToDebugee(DEBUGGEE_NAME);
93         debuggee.redirectStderr(log, "field001a >");
94 
95         pipe = debuggee.createIOPipe();
96         vm = debuggee.VM();
97 
98         // resume debuggee
99         log.display("Resuming debuggee");
100         debuggee.resume();
101 
102         // check for debuggee's capabilities
103         if (!debuggee.VM().canWatchFieldAccess()) {
104             log.display("TEST WARNING: test passed because JDI implementation does not support " +
105              "watchpoints for field access");
106             pipe.println(COMMAND_QUIT);
107             debuggee.waitFor();
108             return field001.PASSED;
109         }
110 
111         if (!debuggee.VM().canWatchFieldModification()) {
112             log.display("TEST WARNING: test passed because JDI implementation does not support " +
113              "watchpoints for field modification");
114             pipe.println(COMMAND_QUIT);
115             debuggee.waitFor();
116             return field001.PASSED;
117         }
118 
119         // catch all exceptions while testing
120         try {
121 
122             // wait for debuggee started
123             log.display("Waiting for command: " + COMMAND_READY);
124             String command = pipe.readln();
125             if (command == null || !command.equals(COMMAND_READY)) {
126                 throw new Failure("TEST BUG: unexpected debuggee's command: " + command);
127             }
128 
129             if ((rType = debuggee.classByName(CHECKED_CLASS_NAME)) == null) {
130                 throw new Failure("TEST BUG: cannot find " + CHECKED_CLASS_NAME);
131             }
132 
133             // create event requests
134             log.display("Creating requests for WatchpointEvent");
135             EventRequestManager erManager = debuggee.VM().eventRequestManager();
136             Iterator fieldsIter;
137             try {
138                 fieldsList = rType.fields();
139                 fieldsIter = fieldsList.iterator();
140             } catch (ClassNotPreparedException e) {
141                 throw new Failure( "TEST_BUG: " + rType.name() + " is not prepared");
142             }
143             while (fieldsIter.hasNext()) {
144                 Field refField = (Field)fieldsIter.next();
145                 if ((wpRequest = erManager.createAccessWatchpointRequest(refField)) == null) {
146                     throw new Failure("TEST BUG: unable to create AccessWatchpointRequest");
147                 } else {
148                     log.display("AccessWatchpointRequest for field " +  refField.name() + " created");
149                     wpRequest.enable();
150                 }
151                 if ((wpRequest = erManager.createModificationWatchpointRequest(refField)) == null) {
152                     throw new Failure("TEST BUG: unable to create ModificationWatchpointRequest");
153                 } else {
154                     log.display("ModificationWatchpointRequest for field " +  refField.name() + " created");
155                     wpRequest.enable();
156                 }
157                 requestsCount++;
158             }
159             log.display("Created total " + requestsCount + " WatchpointRequests");
160 
161             // define separate thread for handling events
162             class EventHandler extends Thread {
163                   public void run() {
164                        eventSet = null;
165                        try {
166                             // handle events until all events generated and received
167                             while (!(done
168                                     && awpEventsCount >= EXPECTED_ACCESS_EVENTS
169                                     && mwpEventsCount >= EXPECTED_MODIFICATION_EVENTS)) {
170 
171                                  eventSet = null;
172                                  eventSet = vm.eventQueue().remove(TIMEOUT_DELTA);
173 
174                                  if (eventSet == null)
175                                      continue;
176 
177                                  EventIterator eventIterator = eventSet.eventIterator();
178                                  while (eventIterator.hasNext()) {
179 
180                                     Event event = eventIterator.nextEvent();
181 //                                     log.display("Event received: " + event);
182 
183                                     // handle WatchpointEvent
184                                     if (event instanceof WatchpointEvent) {
185                                         WatchpointEvent castedEvent = (WatchpointEvent)event;
186                                         Field evField  = castedEvent.field();
187                                         Field evField1 = castedEvent.field();
188 
189                                         if (event instanceof AccessWatchpointEvent) {
190                                             awpEventsCount++;
191                                             log.display("AccessWatchpointEvent received for " + evField.name());
192                                         } else if (event instanceof ModificationWatchpointEvent) {
193                                             mwpEventsCount++;
194                                             log.display("ModificationWatchpointEvent received for " + evField.name());
195                                         }
196 
197                                         if (evField == null) {
198                                             log.complain("FAILURE 1: WatchpointEvent.field() returns null");
199                                             testFailed = true;
200                                         } else if (evField != evField1) {
201                                             log.complain("FAILURE 2: method fieldd() returns inconsistent results for " +
202                                                 evField.name() + "\nevField: " + evField + " ; evField1: " + evField1);
203                                             testFailed = true;
204                                         } else if (!(fieldsList.contains(evField))) {
205                                             log.complain("FAILURE 3: Watchpoint.field() returns unknown field");
206                                             testFailed = true;
207                                         } else {
208                                             log.display("WatchpointEvent received for " + evField.name());
209                                         }
210                                     }
211                                 }
212 
213                                 // resume each hamdled event set
214                                 eventSet.resume();
215                             }
216                        } catch (InterruptedException e) {
217                              log.complain("TEST INCOMPLETE: caught InterruptedException while waiting for event");
218                              testFailed = true;
219                        } catch (VMDisconnectedException e) {
220                              log.complain("TEST INCOMPLETE: caught VMDisconnectedException while waiting for event");
221                              testFailed = true;
222                        }
223                        log.display("eventHandler completed");
224                   }
225             }
226 
227             // start event handling thread
228             EventHandler eventHandler = new EventHandler();
229             log.display("Starting eventHandler");
230             eventHandler.start();
231 
232             // force debuggee to generate events
233             log.display("Sending command: " + COMMAND_GO);
234             pipe.println(COMMAND_GO);
235 
236             // wait for confirmation from debugee
237             log.display("Waiting for command: " + COMMAND_DONE);
238             command = pipe.readln();
239             if (command == null || !command.equals(COMMAND_DONE)) {
240                 throw new Failure("TEST BUG: unexpected debuggee's command: " + command);
241             }
242 
243             // notify EventHandler that all events generated
244             done = true;
245 
246             // wait for all expected events received
247             log.display("Waiting for all expected events received");
248             try {
249                 eventHandler.join(argHandler.getWaitTime()*60000);
250                 if (eventHandler.isAlive()) {
251                     log.complain("FAILURE 20: Timeout for waiting of event was exceeded");
252                     eventHandler.interrupt();
253                     testFailed = true;
254                 }
255             } catch (InterruptedException e) {
256                 log.complain("TEST INCOMPLETE: InterruptedException caught while waiting for eventHandler's death");
257                 testFailed = true;
258             }
259 
260             // check for all expected events received
261             if (awpEventsCount == 0) {
262                 log.complain("FAILURE 4: No AccessWatchpointEvents were received");
263                 testFailed = true;
264             } else if (awpEventsCount < EXPECTED_ACCESS_EVENTS) {
265                 log.complain("FAILURE 4: Too few AccessWatchpointEvents were received: "
266                                 + (EXPECTED_ACCESS_EVENTS - awpEventsCount) + " not received");
267                 testFailed = true;
268             } else if (awpEventsCount > EXPECTED_ACCESS_EVENTS) {
269                 log.complain("FAILURE 4: Too many AccessWatchpointEvents were received: "
270                                 + "extra " + (awpEventsCount - EXPECTED_ACCESS_EVENTS) + " received");
271                 testFailed = true;
272             } else {
273                 log.display("All expected AccessWatchpointEvents were received: "
274                                 + awpEventsCount + " events");
275             }
276             if (mwpEventsCount == 0) {
277                 log.complain("FAILURE 4: No ModificationWatchpointEvents were received");
278                 testFailed = true;
279             } else if (mwpEventsCount < EXPECTED_MODIFICATION_EVENTS) {
280                 log.complain("FAILURE 4: Too few ModificationWatchpointEvents were received: "
281                                 + (EXPECTED_MODIFICATION_EVENTS - mwpEventsCount) + " not received");
282                 testFailed = true;
283             } else if (mwpEventsCount > EXPECTED_MODIFICATION_EVENTS) {
284                 log.complain("FAILURE 4: Too many ModificationWatchpointEvents were received: "
285                                 + "extra " + (mwpEventsCount - EXPECTED_MODIFICATION_EVENTS) + " received");
286                 testFailed = true;
287             } else {
288                 log.display("All expected ModificationWatchpointEvents were received: "
289                                 + mwpEventsCount + " events");
290             }
291 
292         } catch (Failure e) {
293             log.complain("TEST FAILURE: " + e.getMessage());
294             testFailed = true;
295         } catch (Exception e) {
296             log.complain("Unexpected exception: " + e);
297             e.printStackTrace(out);
298             testFailed = true;
299         } finally {
300 
301             log.display("");
302 
303             // force debugee to exit
304             log.display("Sending command: " + COMMAND_QUIT);
305             pipe.println(COMMAND_QUIT);
306 
307             // wait for debuggee exits and analize its exit code
308             log.display("Waiting for debuggee terminating");
309             int debuggeeStatus = debuggee.endDebugee();
310             if (debuggeeStatus == PASSED + JCK_STATUS_BASE) {
311                 log.display("Debuggee PASSED with exit code: " + debuggeeStatus);
312             } else {
313                 log.complain("Debuggee FAILED with exit code: " + debuggeeStatus);
314                 testFailed = true;
315             }
316         }
317 
318         // check test results
319         if (testFailed) {
320             log.complain("TEST FAILED");
321             return FAILED;
322         }
323 
324         log.display("TEST PASSED");
325         return PASSED;
326     }
327 }
328