1 /*
2  * Copyright (c) 2006, 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 package nsk.share.jdi;
24 
25 import java.io.PrintStream;
26 import java.lang.reflect.*;
27 import java.util.*;
28 
29 import com.sun.jdi.*;
30 import com.sun.jdi.event.*;
31 import com.sun.jdi.request.*;
32 import nsk.share.TestBug;
33 
34 /*
35  *  Class is used as base debugger in tests for following events and event requests:
36  *  - MonitorContendedEnterRequest / MonitorContendedEnterEvent
37  *  - MonitorContendedEnteredRequest / MonitorContendedEnteredEvent
38  *  - MonitorWaitRequest / MonitorWaitEvent
39  *  - MonitorWaitedRequest / MonitorWaitedEvent
40  *
41  * In all these tests similar scenario is used:
42  *  - debugger VM forces debuggee VM to create number of objects which should generate events during test
43  *  - if any event filters are used each generating event object is checked is this object accepted by all filters,
44  *    if object was accepted it should save information about all generated events and this information is available for debugger
45  * - debuggee performs event generation and stop at breakpoint
46  * - debugger reads data saved by event generators and checks is only expected events was generated
47  */
48 public class JDIEventsDebugger extends TestDebuggerType2 {
49     // types of tested events
50     static public enum EventType {
51         MONITOR_CONTENTED_ENTER,
52         MONITOR_CONTENTED_ENTERED,
53         MONITOR_WAIT,
54         MONITOR_WAITED
55     }
56 
57     /*
58      * Class contains information required for event testing
59      */
60     static class TestedEventData {
61         // event class
62         public Class<?> eventClass;
63 
64         // class representing event data on debuggee's side
65         public Class<?> eventDataMirrorClass;
66 
67         // class representing event data on debugger's side
68         public Class<?> eventDataClass;
69 
TestedEventData(Class<?> eventClass, Class<?> eventDataMirrorClass, Class<?> eventDataClass)70         public TestedEventData(Class<?> eventClass, Class<?> eventDataMirrorClass, Class<?> eventDataClass) {
71             this.eventClass = eventClass;
72             this.eventDataMirrorClass = eventDataMirrorClass;
73             this.eventDataClass = eventDataClass;
74         }
75     }
76 
77     static public Map<EventType, TestedEventData> testedEventData = new HashMap<EventType, TestedEventData>();
78 
79     static {
testedEventData.put(EventType.MONITOR_CONTENTED_ENTER, new TestedEventData(MonitorContendedEnterEvent.class, DebuggeeEventData.DebugMonitorEnterEventData.class, DebuggerEventData.DebugMonitorEnterEventData.class))80         testedEventData.put(EventType.MONITOR_CONTENTED_ENTER, new TestedEventData(MonitorContendedEnterEvent.class,
81                 DebuggeeEventData.DebugMonitorEnterEventData.class, DebuggerEventData.DebugMonitorEnterEventData.class));
82 
testedEventData.put(EventType.MONITOR_CONTENTED_ENTERED, new TestedEventData(MonitorContendedEnteredEvent.class, DebuggeeEventData.DebugMonitorEnteredEventData.class, DebuggerEventData.DebugMonitorEnteredEventData.class))83         testedEventData.put(EventType.MONITOR_CONTENTED_ENTERED, new TestedEventData(MonitorContendedEnteredEvent.class,
84                 DebuggeeEventData.DebugMonitorEnteredEventData.class, DebuggerEventData.DebugMonitorEnteredEventData.class));
85 
testedEventData.put(EventType.MONITOR_WAIT, new TestedEventData(MonitorWaitEvent.class, DebuggeeEventData.DebugMonitorWaitEventData.class, DebuggerEventData.DebugMonitorWaitEventData.class))86         testedEventData.put(EventType.MONITOR_WAIT, new TestedEventData(MonitorWaitEvent.class, DebuggeeEventData.DebugMonitorWaitEventData.class,
87                 DebuggerEventData.DebugMonitorWaitEventData.class));
88 
testedEventData.put(EventType.MONITOR_WAITED, new TestedEventData(MonitorWaitedEvent.class, DebuggeeEventData.DebugMonitorWaitedEventData.class, DebuggerEventData.DebugMonitorWaitedEventData.class))89         testedEventData.put(EventType.MONITOR_WAITED, new TestedEventData(MonitorWaitedEvent.class,
90                 DebuggeeEventData.DebugMonitorWaitedEventData.class, DebuggerEventData.DebugMonitorWaitedEventData.class));
91     }
92 
eventDataByEventTypes(EventType[] eventTypes)93     static public TestedEventData[] eventDataByEventTypes(EventType[] eventTypes) {
94         TestedEventData[] result = new TestedEventData[eventTypes.length];
95 
96         int i = 0;
97         for (EventType eventType : eventTypes) {
98             TestedEventData eventData = testedEventData.get(eventType);
99 
100             if (eventData == null)
101                 throw new TestBug("Unsupported event type: " + eventType);
102 
103             result[i++] = eventData;
104         }
105 
106         return result;
107     }
108 
109     /*
110      * Dummy event listener, just accepts all events
111      */
112     public class DummyEventListener extends EventHandler.EventListener {
113         private volatile boolean breakpointEventReceived;
114 
eventReceived(Event event)115         public boolean eventReceived(Event event) {
116             if (event instanceof BreakpointEvent) {
117                 breakpointEventReceived = true;
118                 vm.resume();
119             }
120 
121             return true;
122         }
123 
waitBreakpoint()124         public void waitBreakpoint() {
125             while (!breakpointEventReceived)
126                 Thread.yield();
127         }
128     }
129 
130     /*
131      * Parse common for event tests parameters
132      */
doInit(String[] args, PrintStream out)133     protected String[] doInit(String[] args, PrintStream out) {
134         args = super.doInit(args, out);
135 
136         ArrayList<String> standardArgs = new ArrayList<String>();
137 
138         for (int i = 0; i < args.length; i++) {
139             if (args[i].equals("-allowExtraEvents")) {
140                 extraEventClasses = createEventClassArray(args[i + 1]);
141 
142                 i++;
143             } else if (args[i].equals("-allowMissedEvents")) {
144                 missedEventClasses = createEventClassArray(args[i + 1]);
145 
146                 i++;
147             } else
148                 standardArgs.add(args[i]);
149         }
150 
151         return standardArgs.toArray(new String[standardArgs.size()]);
152     }
153 
154     // can't control some kinds of events (events from system libraries) and
155     // not all events should be saved for analysis
156     // (should be implemented in subclasses)
shouldSaveEvent(Event event)157     protected boolean shouldSaveEvent(Event event) {
158         return true;
159     }
160 
findEventDataClass(TestedEventData[] testedEventData, Event event)161     public Class<?> findEventDataClass(TestedEventData[] testedEventData, Event event) {
162         for (TestedEventData eventData : testedEventData) {
163             if (eventData.eventClass.isAssignableFrom(event.getClass()))
164                 return eventData.eventClass;
165         }
166 
167         return null;
168     }
169 
170     /*
171      * This event listener stores received monitor events until BreakpointEvent
172      * is not received, after getting of BreakpointEvent checks only expected
173      * events were received
174      */
175     public class EventListener extends EventHandler.EventListener {
176 
177         private TestedEventData[] testedEventData;
178 
EventListener(TestedEventData[] testedEventData)179         public EventListener(TestedEventData[] testedEventData) {
180             this.testedEventData = testedEventData;
181         }
182 
shouldHandleEvent(Event event)183         private boolean shouldHandleEvent(Event event) {
184             return findEventDataClass(testedEventData, event) == null ? false : true;
185         }
186 
187         volatile boolean breakpointWasReceived;
188 
189         // execution was interrupted because of timeout
190         volatile boolean executionWasInterrupted;
191 
eventReceived(Event event)192         public boolean eventReceived(Event event) {
193             if (shouldHandleEvent(event)) {
194                 if (shouldSaveEvent(event)) {
195 
196                     Class<?> eventClass;
197 
198                     eventClass = findEventDataClass(testedEventData, event);
199                     List<Event> events = allReceivedEvents.get(eventClass);
200 
201                     if (events == null) {
202                         events = new LinkedList<Event>();
203                         allReceivedEvents.put(eventClass, events);
204                     }
205 
206                     events.add(event);
207                 }
208 
209                 return true;
210             }
211             // debuggee should stop at the end of test
212             else if (event instanceof BreakpointEvent) {
213                 breakpointWasReceived = true;
214 
215                 try {
216                     // if execution was interrupted because of timeout don't check received
217                     // events because it can consume too much time
218                     if (!executionWasInterrupted) {
219                         // get data from debuggee about all generated events
220                         initExpectedEvents(testedEventData);
221 
222                         checkEvents();
223                     } else
224                         log.complain("WARNING: execution was interrupted because of timeout, test doesn't check received events");
225                 } catch (Throwable t) {
226                     unexpectedException(t);
227                 }
228 
229                 vm.resume();
230 
231                 return true;
232             }
233 
234             return false;
235         }
236     }
237 
238     protected Class<?> extraEventClasses[];
239 
240     protected Class<?> missedEventClasses[];
241 
242     /*
243      * If test can't strictly control event generation it may allow generation
244      * of extra events and unexpected events aren't treated as error
245      * (subclasses should specify what kinds of extra events are allowed)
246      */
allowedExtraEvents()247     private Class<?>[] allowedExtraEvents() {
248         return extraEventClasses;
249     }
250 
251     /*
252      * If test can't strictly control event generation case when debugger doesn't
253      * receive expected event may be not treated as failure
254      * (subclasses should specify what kinds of expected events can be not received)
255      */
allowedMissedEvents()256     private Class<?>[] allowedMissedEvents() {
257         return missedEventClasses;
258     }
259 
isExtraEventAllowed(Class<?> eventClass)260     private boolean isExtraEventAllowed(Class<?> eventClass) {
261         return checkEvent(eventClass, allowedExtraEvents());
262     }
263 
isMissedEventAllowed(Class<?> eventClass)264     private boolean isMissedEventAllowed(Class<?> eventClass) {
265         return checkEvent(eventClass, allowedMissedEvents());
266     }
267 
checkEvent(Class<?> eventClass, Class<?> classes[])268     private boolean checkEvent(Class<?> eventClass, Class<?> classes[]) {
269         if (classes == null)
270             return false;
271 
272         for (Class<?> klass : classes) {
273             if (klass.isAssignableFrom(eventClass))
274                 return true;
275         }
276 
277         return false;
278     }
279 
280     // flag is modified from the event listener thread
281     private volatile boolean eventsNotGenerated;
282 
283     /*
284      * Method returns true if test expects event generation, but events weren't
285      * generated. If test can't strictly control event generation such case isn't
286      * necessarily treated as test failure (sublasses of JDIEventsDebugger can
287      * for example try to rerun test several times).
288      */
eventsNotGenerated()289     protected boolean eventsNotGenerated() {
290         return eventsNotGenerated;
291     }
292 
293     /*
294      * Print debug information about expected and received events(this data
295      * should be stored in lists 'allExpectedEvents' and 'allReceivedEvents')
296      * and check that only expected events were received
297      */
checkEvents()298     private void checkEvents() {
299         if (getAllExpectedEvents().size() > 0 && getAllReceivedEvents().size() == 0 && allowedMissedEvents() != null) {
300             log.display("WARNING: didn't receive any event");
301             eventsNotGenerated = true;
302         }
303 
304         log.display("ALL RECEIVED EVENTS: ");
305         for (Event event : getAllReceivedEvents())
306             log.display("received event: " + eventToString(event));
307 
308         log.display("ALL EXPECTED EVENTS: ");
309         for (DebuggerEventData.DebugEventData eventData : getAllExpectedEvents())
310             log.display("expected event: " + eventData);
311 
312         // try to find received event in the list of expected events, if this event
313         // was found remove data about events from both lists
314         for (Class<?> eventClass : allReceivedEvents.keySet()) {
315             List<Event> receivedEvents = allReceivedEvents.get(eventClass);
316             List<DebuggerEventData.DebugEventData> expectedEvents = allExpectedEvents.get(eventClass);
317 
318             for (Iterator<Event> allReceivedEventsIterator = receivedEvents.iterator();
319                 allReceivedEventsIterator.hasNext();) {
320 
321                 Event event = allReceivedEventsIterator.next();
322 
323                 for (Iterator<DebuggerEventData.DebugEventData> allExpectedEventsIterator = expectedEvents.iterator();
324                     allExpectedEventsIterator.hasNext();) {
325 
326                     DebuggerEventData.DebugEventData debugEventData = allExpectedEventsIterator.next();
327 
328                     if (debugEventData.shouldCheckEvent(event)) {
329                         if (debugEventData.checkEvent(event)) {
330                             allExpectedEventsIterator.remove();
331                             allReceivedEventsIterator.remove();
332                             break;
333                         }
334                     }
335                 }
336             }
337         }
338 
339         List<Event> receivedEventsLeft = getAllReceivedEvents();
340 
341         // check is all received events were found in expected
342         if (receivedEventsLeft.size() > 0) {
343             // if allowExtraEvents = true extra events are not treated as error
344             for (Event event : receivedEventsLeft) {
345                 if (!isExtraEventAllowed(event.getClass())) {
346                     setSuccess(false);
347                     log.complain("Unexpected event " + eventToString(event));
348                 }
349             }
350         }
351 
352         List<DebuggerEventData.DebugEventData> expectedEventsLeft = getAllExpectedEvents();
353 
354         // check is all expected events were received
355         if (expectedEventsLeft.size() > 0) {
356             for (DebuggerEventData.DebugEventData eventData : expectedEventsLeft) {
357                 if (!isMissedEventAllowed(eventData.eventClass)) {
358                     setSuccess(false);
359                     log.complain("Expected event was not generated: " + eventData);
360                 }
361             }
362         }
363     }
364 
eventToString(Event event)365     private String eventToString(Event event) {
366         try {
367             if (event instanceof MonitorContendedEnterEvent)
368                 return event + ". Details(MonitorContendedEnterEvent):" + " Monitor: " + ((MonitorContendedEnterEvent) event).monitor() + " Thread: "
369                         + ((MonitorContendedEnterEvent) event).thread();
370             else if (event instanceof MonitorContendedEnteredEvent)
371                 return event + ". Details(MonitorContendedEnteredEvent):" + " Monitor: " + ((MonitorContendedEnteredEvent) event).monitor()
372                         + " Thread: " + ((MonitorContendedEnteredEvent) event).thread();
373             else if (event instanceof MonitorWaitEvent)
374                 return event + ". Details(MonitorWaitEvent):" + " Monitor: " + ((MonitorWaitEvent) event).monitor() + " Thread: "
375                         + ((MonitorWaitEvent) event).thread() + " Timeout: " + ((MonitorWaitEvent) event).timeout();
376             else if (event instanceof MonitorWaitedEvent)
377                 return event + ". Details(MonitorWaitedEvent):" + " Monitor: " + ((MonitorWaitedEvent) event).monitor() + " Thread: "
378                         + ((MonitorWaitedEvent) event).thread() + " Timedout: " + ((MonitorWaitedEvent) event).timedout();
379 
380             return event.toString();
381         }
382         // this exception can occur when unexpected event was received
383         catch (ObjectCollectedException e) {
384             // allowExtraEvents=true extra events are not treated as error
385             if (!isExtraEventAllowed(event.getClass())) {
386                 setSuccess(false);
387                 e.printStackTrace(log.getOutStream());
388                 log.complain("Unexpected ObjectCollectedException was caught, possible unexpected event was received");
389             }
390 
391             return event.getClass().getName() + " [ Can't get full description, ObjectCollectedException was thrown ]";
392         }
393     }
394 
395     // events received during test execution are stored here
396     private Map<Class<?>, List<Event>> allReceivedEvents = new HashMap<Class<?>, List<Event>>();
397 
getAllReceivedEvents()398     private List<Event> getAllReceivedEvents() {
399         List<Event> result = new LinkedList<Event>();
400 
401         for (Class<?> eventClass : allReceivedEvents.keySet()) {
402             result.addAll(allReceivedEvents.get(eventClass));
403         }
404 
405         return result;
406     }
407 
408     protected Map<Class<?>, List<DebuggerEventData.DebugEventData>> allExpectedEvents = new HashMap<Class<?>, List<DebuggerEventData.DebugEventData>>();
409 
getAllExpectedEvents()410     private List<DebuggerEventData.DebugEventData> getAllExpectedEvents() {
411         List<DebuggerEventData.DebugEventData> result = new LinkedList<DebuggerEventData.DebugEventData>();
412 
413         for (Class<?> eventClass : allExpectedEvents.keySet()) {
414             result.addAll(allExpectedEvents.get(eventClass));
415         }
416 
417         return result;
418     }
419 
420     // find in debuggee VM and add to the list 'allExpectedEvents' instances
421     // of classes representing generated events
initExpectedEvents(TestedEventData testedEventData[])422     protected void initExpectedEvents(TestedEventData testedEventData[]) {
423         List<DebuggerEventData.DebugEventData> events;
424 
425         ReferenceType referenceType = debuggee.classByName(debuggeeClassNameWithoutArgs());
426 
427         ArrayReference generatedEvents = (ArrayReference) referenceType.getValue(referenceType.fieldByName("generatedEvents"));
428 
429         for (TestedEventData eventData : testedEventData) {
430             events = new LinkedList<DebuggerEventData.DebugEventData>();
431             allExpectedEvents.put(eventData.eventClass, events);
432         }
433 
434         for (int i = 0; i < generatedEvents.length(); i++) {
435             ObjectReference debuggeeMirror = (ObjectReference) generatedEvents.getValue(i);
436 
437             for (TestedEventData eventData : testedEventData) {
438 
439                 if (debuggeeMirror.referenceType().name().equals(eventData.eventDataMirrorClass.getName())) {
440                     events = allExpectedEvents.get(eventData.eventClass);
441 
442                     /*
443                      * Use reflection to create object representing generated
444                      * event Event data class should has constructor with single
445                      * parameter of type com.sun.jdi.ObjectReference
446                      */
447                     Constructor<?> constructor;
448 
449                     try {
450                         constructor = eventData.eventDataClass.getConstructor(new Class[] { ObjectReference.class });
451                     } catch (NoSuchMethodException e) {
452                         TestBug testBug = new TestBug(
453                                 "Class representing debug event data should implement constructor with single parameter of type com.sun.jdi.ObjectReference");
454                         testBug.initCause(e);
455                         throw testBug;
456                     }
457 
458                     DebuggerEventData.DebugEventData expectedEvent;
459 
460                     try {
461                         expectedEvent = (DebuggerEventData.DebugEventData) constructor.newInstance(new Object[] { debuggeeMirror });
462                     } catch (Exception e) {
463                         TestBug testBug = new TestBug("Error when create debug event data: " + e);
464                         testBug.initCause(e);
465                         throw testBug;
466                     }
467                     events.add(expectedEvent);
468                 }
469             }
470         }
471     }
472 
printFiltersInfo()473     private void printFiltersInfo() {
474         if (eventFilters.size() > 0) {
475             log.display("Use following filters: ");
476 
477             for (EventFilters.DebugEventFilter filter : eventFilters)
478                 log.display("" + filter);
479         } else {
480             log.display("Don't use event filters");
481         }
482     }
483 
484     // filters used in test
485     protected List<EventFilters.DebugEventFilter> eventFilters = new LinkedList<EventFilters.DebugEventFilter>();
486 
487     // Check is object generating events matches all filters,
488     // if object was accepted by all filters set this object's field
489     // 'saveEventData' to 'true', otherwise to 'false',
checkEventGenerator(ThreadReference eventThread, ObjectReference executor)490     private void checkEventGenerator(ThreadReference eventThread, ObjectReference executor) {
491         boolean acceptedByFilters = true;
492 
493         for (EventFilters.DebugEventFilter eventFilter : eventFilters) {
494             if (!eventFilter.isObjectMatch(executor, eventThread)) {
495                 acceptedByFilters = false;
496                 break;
497             }
498         }
499 
500         try {
501             executor.setValue(executor.referenceType().fieldByName("saveEventData"), vm.mirrorOf(acceptedByFilters));
502         } catch (Exception e) {
503             throw new TestBug("Unexpected exception when change object field in debugee VM: " + e, e);
504         }
505     }
506 
507     /*
508      * Find all event generating threads in debuggee VM (instances of
509      * nsk.share.jdi.MonitorEventsDebuggee$MonitorActionsThread) all these
510      * threads have special field - 'executor', this is object which generates
511      * events. If event generating thread and event generating object was
512      * accepted by all filters generating object should store information about
513      * all generated events and this information will be available for debugger
514      */
initializeEventGenerators()515     protected void initializeEventGenerators() {
516         printFiltersInfo();
517 
518         List<ThreadReference> eventThreads = getEventThreads();
519 
520         for (ThreadReference eventThread : eventThreads) {
521             ObjectReference executor = (ObjectReference) eventThread.getValue(eventThread.referenceType().fieldByName("executor"));
522             checkEventGenerator(eventThread, executor);
523         }
524 
525         // debuggee's main thread also can generate events, need to filter it in
526         // the same way as other threads
527         checkEventGenerator(debuggee.threadByName(JDIEventsDebuggee.MAIN_THREAD_NAME), findSingleObjectReference(debuggeeClassNameWithoutArgs()));
528     }
529 
530     // find instances of nsk.share.jdi.MonitorEventsDebuggee$MonitorActionsThread
getEventThreads()531     protected List<ThreadReference> getEventThreads() {
532         ReferenceType referenceType = debuggee.classByName(JDIEventsDebuggee.EventActionsThread.class.getName());
533         List<ObjectReference> debuggeeEventThreads = referenceType.instances(0);
534 
535         List<ThreadReference> result = new LinkedList<ThreadReference>();
536         for (ObjectReference threadReference : debuggeeEventThreads)
537             result.add((ThreadReference) threadReference);
538 
539         return result;
540     }
541 
542     // find instances of nsk.share.jdi.MonitorEventsDebuggee$MonitorActionsThread,
543     // and get value of this object's field with name 'executor'
getEventObjects()544     protected List<ObjectReference> getEventObjects() {
545         List<ObjectReference> eventObjects = new LinkedList<ObjectReference>();
546 
547         List<ThreadReference> eventThreads = getEventThreads();
548 
549         for (ThreadReference eventThread : eventThreads) {
550             eventObjects.add((ObjectReference) eventThread.getValue(eventThread.referenceType().fieldByName("executor")));
551         }
552 
553         return eventObjects;
554     }
555 
556     // remove all filters, received and expected events
clearTestData()557     private void clearTestData() {
558         allExpectedEvents.clear();
559         allReceivedEvents.clear();
560         eventFilters.clear();
561         eventsNotGenerated = false;
562     }
563 
isEventSupported(EventType eventType)564     private boolean isEventSupported(EventType eventType) {
565         switch (eventType) {
566         case MONITOR_CONTENTED_ENTER:
567         case MONITOR_CONTENTED_ENTERED:
568         case MONITOR_WAIT:
569         case MONITOR_WAITED:
570             return vm.canRequestMonitorEvents();
571 
572         default:
573             throw new TestBug("Invalid tested event type: " + eventType);
574         }
575     }
576 
577     // create instance of EventRequest depending on given eventType
createTestRequest(EventType eventType)578     private EventRequest createTestRequest(EventType eventType) {
579         switch (eventType) {
580         case MONITOR_CONTENTED_ENTER:
581             return debuggee.getEventRequestManager().createMonitorContendedEnterRequest();
582         case MONITOR_CONTENTED_ENTERED:
583             return debuggee.getEventRequestManager().createMonitorContendedEnteredRequest();
584         case MONITOR_WAIT:
585             return debuggee.getEventRequestManager().createMonitorWaitRequest();
586         case MONITOR_WAITED:
587             return debuggee.getEventRequestManager().createMonitorWaitedRequest();
588 
589         default:
590             throw new TestBug("Invalid tested event type: " + eventType);
591         }
592     }
593 
594     // create command depending on given eventType
createCommand(EventType eventTypes[], int eventsNumber)595     private String createCommand(EventType eventTypes[], int eventsNumber) {
596         String command = JDIEventsDebuggee.COMMAND_CREATE_ACTIONS_EXECUTORS + ":" + eventsNumber + ":";
597 
598         for (EventType eventType : eventTypes) {
599             switch (eventType) {
600             case MONITOR_CONTENTED_ENTER:
601             case MONITOR_CONTENTED_ENTERED:
602             case MONITOR_WAIT:
603             case MONITOR_WAITED:
604                 command += " " + eventType.name();
605                 break;
606 
607             default:
608                 throw new TestBug("Invalid tested event type: " + eventType);
609             }
610         }
611 
612         return command;
613     }
614 
615     // get list of event requests from EventRequestManager depending on the given eventType
getEventRequestsFromManager(EventType eventType)616     private List<?> getEventRequestsFromManager(EventType eventType) {
617         switch (eventType) {
618         case MONITOR_CONTENTED_ENTER:
619             return debuggee.getEventRequestManager().monitorContendedEnterRequests();
620         case MONITOR_CONTENTED_ENTERED:
621             return debuggee.getEventRequestManager().monitorContendedEnteredRequests();
622         case MONITOR_WAIT:
623             return debuggee.getEventRequestManager().monitorWaitRequests();
624         case MONITOR_WAITED:
625             return debuggee.getEventRequestManager().monitorWaitedRequests();
626 
627         default:
628             throw new TestBug("Invalid tested event type: " + eventType);
629         }
630     }
631 
632     protected EventHandler eventHandler;
633 
634     private EventListener eventListener;
635 
636     // perform event generation before test begins to load all using classes
637     // and avoid unexpected events related to classloading
prepareDebuggee(EventType[] eventTypes)638     protected void prepareDebuggee(EventType[] eventTypes) {
639         initDefaultBreakpoint();
640 
641         eventHandler = new EventHandler(debuggee, log);
642         eventHandler.startListening();
643 
644         // use event listener which just skip all received events
645         DummyEventListener dummyEventListener = new DummyEventListener();
646         eventHandler.addListener(dummyEventListener);
647 
648         EventRequest eventRequests[] = new EventRequest[eventTypes.length];
649 
650         for (int i = 0; i < eventRequests.length; i++) {
651             eventRequests[i] = createTestRequest(eventTypes[i]);
652             eventRequests[i].setSuspendPolicy(EventRequest.SUSPEND_NONE);
653             eventRequests[i].enable();
654         }
655 
656         // debuggee should create event generators
657         pipe.println(createCommand(eventTypes, 1));
658 
659         if (!isDebuggeeReady())
660             return;
661 
662         // start event generation
663         pipe.println(JDIEventsDebuggee.COMMAND_START_EXECUTION);
664 
665         if (!isDebuggeeReady())
666             return;
667 
668         for (int i = 0; i < eventRequests.length; i++)
669             eventRequests[i].disable();
670 
671         dummyEventListener.waitBreakpoint();
672 
673         eventHandler.removeListener(dummyEventListener);
674 
675         pipe.println(JDIEventsDebuggee.COMMAND_WAIT_EXECUTION_COMPLETION);
676 
677         if (!isDebuggeeReady())
678             return;
679 
680         eventListener = new EventListener(eventDataByEventTypes(eventTypes));
681         eventHandler.addListener(eventListener);
682     }
683 
684     /*
685      * Method for stress testing, allows specify requests for several event
686      * types, number of events which should be generated during test and number
687      * of threads which simultaneously generate events
688      */
stressTestTemplate(EventType[] eventTypes, int eventsNumber, int threadsNumber)689     protected void stressTestTemplate(EventType[] eventTypes, int eventsNumber, int threadsNumber) {
690         for (EventType eventType : eventTypes) {
691             if (!isEventSupported(eventType)) {
692                 log.complain("Can't test event because of it isn't supported: " + eventType);
693                 return;
694             }
695         }
696 
697         // Used framework is intended for testing event filters and debuggee
698         // creates 3 threads performing event generation and there is possibility
699         // to filter events from some threads
700         for (int i = 0; i < threadsNumber; i++) {
701             pipe.println(createCommand(eventTypes, eventsNumber));
702 
703             if (!isDebuggeeReady())
704                 return;
705         }
706 
707         // clear data(if this method is executed several times)
708         clearTestData();
709 
710         initializeEventGenerators();
711 
712         EventRequest eventRequests[] = new EventRequest[eventTypes.length];
713 
714         // create event requests
715         for (int i = 0; i < eventTypes.length; i++) {
716             eventRequests[i] = createTestRequest(eventTypes[i]);
717             eventRequests[i].setSuspendPolicy(EventRequest.SUSPEND_NONE);
718             eventRequests[i].enable();
719 
720             log.display("Use following event request: " + eventRequests[i]);
721         }
722 
723         // stressTestTemplate can control only execution time, so ignore iteration count
724         stresser.start(0);
725         try {
726             // start event generation
727             pipe.println(JDIEventsDebuggee.COMMAND_START_EXECUTION);
728 
729             if (!isDebuggeeReady())
730                 return;
731 
732             // check is stressTime exceeded
733             while (stresser.continueExecution()) {
734                 try {
735                     Thread.sleep(100);
736                 } catch (InterruptedException e) {
737                     unexpectedException(e);
738                 }
739 
740                 // periodically check is test completed
741                 if (eventListener.breakpointWasReceived)
742                     break;
743             }
744         } finally {
745             stresser.finish();
746         }
747 
748         // debugger should interrupt test because of timeout
749         if (!eventListener.breakpointWasReceived) {
750 
751             eventListener.executionWasInterrupted = true;
752 
753             log.complain("WARNING: time is exceeded, interrupt test");
754 
755             pipe.println(JDIEventsDebuggee.COMMAND_STOP_EXECUTION);
756 
757             if (!isDebuggeeReady())
758                 return;
759         }
760 
761         pipe.println(JDIEventsDebuggee.COMMAND_WAIT_EXECUTION_COMPLETION);
762 
763         if (!isDebuggeeReady())
764             return;
765 
766         for (int i = 0; i < eventRequests.length; i++)
767             eventRequests[i].disable();
768     }
769 
770     /*
771      * Hook method for subclasses implementing tests against event filters (it is called from eventFilterTestTemplate)
772      */
createTestFilters(int testedFilterIndex)773     protected EventFilters.DebugEventFilter[] createTestFilters(int testedFilterIndex) {
774         throw new TestBug("Not implemented");
775     }
776 
777     /*
778      * Test event request with filter
779      *
780      * Also this method check following:
781      * - InvalidRequestStateException is thrown if add filter for deleted or enabled request
782      * - EventRequestManager.xxxRequests() returns created event request
783      */
eventFilterTestTemplate(EventType eventType, int testedFilterIndex)784     protected void eventFilterTestTemplate(EventType eventType, int testedFilterIndex) {
785         if (!isEventSupported(eventType)) {
786             log.complain("Can't test event because of it isn't supported: " + eventType);
787             return;
788         }
789 
790         // debuggee create event generators
791         pipe.println(createCommand(new EventType[] { eventType }, 1));
792 
793         if (!isDebuggeeReady())
794             return;
795 
796         clearTestData();
797 
798         EventFilters.DebugEventFilter[] filters = createTestFilters(testedFilterIndex);
799 
800         for (EventFilters.DebugEventFilter filter : filters) {
801             if (filter.isSupported(vm))
802                 eventFilters.add(filter);
803             else {
804                 log.complain("Can't test filter because of it isn't supported: " + filter);
805                 return;
806             }
807         }
808 
809         initializeEventGenerators();
810 
811         // create event request
812         EventRequest request = createTestRequest(eventType);
813         request.setSuspendPolicy(EventRequest.SUSPEND_NONE);
814 
815         // try add filter to enabled request, expect
816         // 'InvalidRequestStateException'
817         request.enable();
818         try {
819             for (EventFilters.DebugEventFilter filter : filters)
820                 filter.addFilter(request);
821 
822             setSuccess(false);
823             log.complain("Expected 'InvalidRequestStateException' was not thrown");
824         } catch (InvalidRequestStateException e) {
825             // expected exception
826         } catch (Throwable e) {
827             setSuccess(false);
828             log.complain("Unexpected exception: " + e);
829             e.printStackTrace(log.getOutStream());
830         }
831 
832         // add event filter
833         request.disable();
834 
835         for (EventFilters.DebugEventFilter filter : filters)
836             addFilter(filter, request);
837 
838         request.enable();
839 
840         log.display("Use following event request: " + request);
841 
842         // start event generation
843         pipe.println(JDIEventsDebuggee.COMMAND_START_EXECUTION);
844 
845         if (!isDebuggeeReady())
846             return;
847 
848         // wait execution completion
849         pipe.println(JDIEventsDebuggee.COMMAND_WAIT_EXECUTION_COMPLETION);
850 
851         if (!isDebuggeeReady())
852             return;
853 
854         // check that method EventRequestManager.xxxRequests() return created
855         // request
856         if (!getEventRequestsFromManager(eventType).contains(request)) {
857             setSuccess(false);
858             log.complain("EventRequestManager doesn't return request: " + request);
859         }
860 
861         // delete event request
862         debuggee.getEventRequestManager().deleteEventRequest(request);
863 
864         // try add filter to removed request, expect
865         // 'InvalidRequestStateException'
866         try {
867             for (EventFilters.DebugEventFilter filter : filters)
868                 filter.addFilter(request);
869             setSuccess(false);
870             log.complain("Expected 'InvalidRequestStateException' was not thrown");
871         } catch (InvalidRequestStateException e) {
872             // expected exception
873         } catch (Throwable t) {
874             unexpectedException(t);
875         }
876     }
877 
addFilter(EventFilters.DebugEventFilter filter, EventRequest request)878     private void addFilter(EventFilters.DebugEventFilter filter, EventRequest request) {
879         try {
880             filter.addFilter(request);
881         } catch (Throwable t) {
882             unexpectedException(t);
883         }
884     }
885 
886     // used to parse parameters -allowExtraEvents and -allowMissedEvents
createEventClassArray(String string)887     private Class<?>[] createEventClassArray(String string) {
888         String eventTypesNames[] = string.split(":");
889         EventType eventTypes[] = new EventType[eventTypesNames.length];
890         try {
891             for (int i = 0; i < eventTypesNames.length; i++) {
892                 eventTypes[i] = EventType.valueOf(eventTypesNames[i]);
893             }
894         } catch (IllegalArgumentException e) {
895             throw new TestBug("Invalid event type", e);
896         }
897 
898         if (eventTypesNames.length == 0)
899             throw new TestBug("Event types weren't specified");
900 
901         Class<?>[] result = new Class[eventTypesNames.length];
902 
903         for (int i = 0; i < result.length; i++)
904             result[i] = testedEventData.get(eventTypes[i]).eventClass;
905 
906         return result;
907     }
908 
909 }
910