blob: d63598b452ca3401b01d51f184f5474e9b2121f3 [file] [log] [blame]
/*
* Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package nsk.share.jdi;
import java.io.PrintStream;
import java.lang.reflect.*;
import java.util.*;
import com.sun.jdi.*;
import com.sun.jdi.event.*;
import com.sun.jdi.request.*;
import nsk.share.TestBug;
/*
* Class is used as base debugger in tests for following events and event requests:
* - MonitorContendedEnterRequest / MonitorContendedEnterEvent
* - MonitorContendedEnteredRequest / MonitorContendedEnteredEvent
* - MonitorWaitRequest / MonitorWaitEvent
* - MonitorWaitedRequest / MonitorWaitedEvent
*
* In all these tests similar scenario is used:
* - debugger VM forces debuggee VM to create number of objects which should generate events during test
* - if any event filters are used each generating event object is checked is this object accepted by all filters,
* if object was accepted it should save information about all generated events and this information is available for debugger
* - debuggee performs event generation and stop at breakpoint
* - debugger reads data saved by event generators and checks is only expected events was generated
*/
public class JDIEventsDebugger extends TestDebuggerType2 {
// types of tested events
static public enum EventType {
MONITOR_CONTENTED_ENTER,
MONITOR_CONTENTED_ENTERED,
MONITOR_WAIT,
MONITOR_WAITED
}
/*
* Class contains information required for event testing
*/
static class TestedEventData {
// event class
public Class<?> eventClass;
// class representing event data on debuggee's side
public Class<?> eventDataMirrorClass;
// class representing event data on debugger's side
public Class<?> eventDataClass;
public TestedEventData(Class<?> eventClass, Class<?> eventDataMirrorClass, Class<?> eventDataClass) {
this.eventClass = eventClass;
this.eventDataMirrorClass = eventDataMirrorClass;
this.eventDataClass = eventDataClass;
}
}
static public Map<EventType, TestedEventData> testedEventData = new HashMap<EventType, TestedEventData>();
static {
testedEventData.put(EventType.MONITOR_CONTENTED_ENTER, new TestedEventData(MonitorContendedEnterEvent.class,
DebuggeeEventData.DebugMonitorEnterEventData.class, DebuggerEventData.DebugMonitorEnterEventData.class));
testedEventData.put(EventType.MONITOR_CONTENTED_ENTERED, new TestedEventData(MonitorContendedEnteredEvent.class,
DebuggeeEventData.DebugMonitorEnteredEventData.class, DebuggerEventData.DebugMonitorEnteredEventData.class));
testedEventData.put(EventType.MONITOR_WAIT, new TestedEventData(MonitorWaitEvent.class, DebuggeeEventData.DebugMonitorWaitEventData.class,
DebuggerEventData.DebugMonitorWaitEventData.class));
testedEventData.put(EventType.MONITOR_WAITED, new TestedEventData(MonitorWaitedEvent.class,
DebuggeeEventData.DebugMonitorWaitedEventData.class, DebuggerEventData.DebugMonitorWaitedEventData.class));
}
static public TestedEventData[] eventDataByEventTypes(EventType[] eventTypes) {
TestedEventData[] result = new TestedEventData[eventTypes.length];
int i = 0;
for (EventType eventType : eventTypes) {
TestedEventData eventData = testedEventData.get(eventType);
if (eventData == null)
throw new TestBug("Unsupported event type: " + eventType);
result[i++] = eventData;
}
return result;
}
/*
* Dummy event listener, just accepts all events
*/
public class DummyEventListener extends EventHandler.EventListener {
private volatile boolean breakpointEventReceived;
public boolean eventReceived(Event event) {
if (event instanceof BreakpointEvent) {
breakpointEventReceived = true;
vm.resume();
}
return true;
}
public void waitBreakpoint() {
while (!breakpointEventReceived)
Thread.yield();
}
}
/*
* Parse common for event tests parameters
*/
protected String[] doInit(String[] args, PrintStream out) {
args = super.doInit(args, out);
ArrayList<String> standardArgs = new ArrayList<String>();
for (int i = 0; i < args.length; i++) {
if (args[i].equals("-allowExtraEvents")) {
extraEventClasses = createEventClassArray(args[i + 1]);
i++;
} else if (args[i].equals("-allowMissedEvents")) {
missedEventClasses = createEventClassArray(args[i + 1]);
i++;
} else
standardArgs.add(args[i]);
}
return standardArgs.toArray(new String[standardArgs.size()]);
}
// can't control some kinds of events (events from system libraries) and
// not all events should be saved for analysis
// (should be implemented in subclasses)
protected boolean shouldSaveEvent(Event event) {
return true;
}
public Class<?> findEventDataClass(TestedEventData[] testedEventData, Event event) {
for (TestedEventData eventData : testedEventData) {
if (eventData.eventClass.isAssignableFrom(event.getClass()))
return eventData.eventClass;
}
return null;
}
/*
* This event listener stores received monitor events until BreakpointEvent
* is not received, after getting of BreakpointEvent checks only expected
* events were received
*/
public class EventListener extends EventHandler.EventListener {
private TestedEventData[] testedEventData;
public EventListener(TestedEventData[] testedEventData) {
this.testedEventData = testedEventData;
}
private boolean shouldHandleEvent(Event event) {
return findEventDataClass(testedEventData, event) == null ? false : true;
}
volatile boolean breakpointWasReceived;
// execution was interrupted because of timeout
volatile boolean executionWasInterrupted;
public boolean eventReceived(Event event) {
if (shouldHandleEvent(event)) {
if (shouldSaveEvent(event)) {
Class<?> eventClass;
eventClass = findEventDataClass(testedEventData, event);
List<Event> events = allReceivedEvents.get(eventClass);
if (events == null) {
events = new LinkedList<Event>();
allReceivedEvents.put(eventClass, events);
}
events.add(event);
}
return true;
}
// debuggee should stop at the end of test
else if (event instanceof BreakpointEvent) {
breakpointWasReceived = true;
try {
// if execution was interrupted because of timeout don't check received
// events because it can consume too much time
if (!executionWasInterrupted) {
// get data from debuggee about all generated events
initExpectedEvents(testedEventData);
checkEvents();
} else
log.complain("WARNING: execution was interrupted because of timeout, test doesn't check received events");
} catch (Throwable t) {
unexpectedException(t);
}
vm.resume();
return true;
}
return false;
}
}
protected Class<?> extraEventClasses[];
protected Class<?> missedEventClasses[];
/*
* If test can't strictly control event generation it may allow generation
* of extra events and unexpected events aren't treated as error
* (subclasses should specify what kinds of extra events are allowed)
*/
private Class<?>[] allowedExtraEvents() {
return extraEventClasses;
}
/*
* If test can't strictly control event generation case when debugger doesn't
* receive expected event may be not treated as failure
* (subclasses should specify what kinds of expected events can be not received)
*/
private Class<?>[] allowedMissedEvents() {
return missedEventClasses;
}
private boolean isExtraEventAllowed(Class<?> eventClass) {
return checkEvent(eventClass, allowedExtraEvents());
}
private boolean isMissedEventAllowed(Class<?> eventClass) {
return checkEvent(eventClass, allowedMissedEvents());
}
private boolean checkEvent(Class<?> eventClass, Class<?> classes[]) {
if (classes == null)
return false;
for (Class<?> klass : classes) {
if (klass.isAssignableFrom(eventClass))
return true;
}
return false;
}
// flag is modified from the event listener thread
private volatile boolean eventsNotGenerated;
/*
* Method returns true if test expects event generation, but events weren't
* generated. If test can't strictly control event generation such case isn't
* necessarily treated as test failure (sublasses of JDIEventsDebugger can
* for example try to rerun test several times).
*/
protected boolean eventsNotGenerated() {
return eventsNotGenerated;
}
/*
* Print debug information about expected and received events(this data
* should be stored in lists 'allExpectedEvents' and 'allReceivedEvents')
* and check that only expected events were received
*/
private void checkEvents() {
if (getAllExpectedEvents().size() > 0 && getAllReceivedEvents().size() == 0 && allowedMissedEvents() != null) {
log.display("WARNING: didn't receive any event");
eventsNotGenerated = true;
}
log.display("ALL RECEIVED EVENTS: ");
for (Event event : getAllReceivedEvents())
log.display("received event: " + eventToString(event));
log.display("ALL EXPECTED EVENTS: ");
for (DebuggerEventData.DebugEventData eventData : getAllExpectedEvents())
log.display("expected event: " + eventData);
// try to find received event in the list of expected events, if this event
// was found remove data about events from both lists
for (Class<?> eventClass : allReceivedEvents.keySet()) {
List<Event> receivedEvents = allReceivedEvents.get(eventClass);
List<DebuggerEventData.DebugEventData> expectedEvents = allExpectedEvents.get(eventClass);
for (Iterator<Event> allReceivedEventsIterator = receivedEvents.iterator();
allReceivedEventsIterator.hasNext();) {
Event event = allReceivedEventsIterator.next();
for (Iterator<DebuggerEventData.DebugEventData> allExpectedEventsIterator = expectedEvents.iterator();
allExpectedEventsIterator.hasNext();) {
DebuggerEventData.DebugEventData debugEventData = allExpectedEventsIterator.next();
if (debugEventData.shouldCheckEvent(event)) {
if (debugEventData.checkEvent(event)) {
allExpectedEventsIterator.remove();
allReceivedEventsIterator.remove();
break;
}
}
}
}
}
List<Event> receivedEventsLeft = getAllReceivedEvents();
// check is all received events were found in expected
if (receivedEventsLeft.size() > 0) {
// if allowExtraEvents = true extra events are not treated as error
for (Event event : receivedEventsLeft) {
if (!isExtraEventAllowed(event.getClass())) {
setSuccess(false);
log.complain("Unexpected event " + eventToString(event));
}
}
}
List<DebuggerEventData.DebugEventData> expectedEventsLeft = getAllExpectedEvents();
// check is all expected events were received
if (expectedEventsLeft.size() > 0) {
for (DebuggerEventData.DebugEventData eventData : expectedEventsLeft) {
if (!isMissedEventAllowed(eventData.eventClass)) {
setSuccess(false);
log.complain("Expected event was not generated: " + eventData);
}
}
}
}
private String eventToString(Event event) {
try {
if (event instanceof MonitorContendedEnterEvent)
return event + ". Details(MonitorContendedEnterEvent):" + " Monitor: " + ((MonitorContendedEnterEvent) event).monitor() + " Thread: "
+ ((MonitorContendedEnterEvent) event).thread();
else if (event instanceof MonitorContendedEnteredEvent)
return event + ". Details(MonitorContendedEnteredEvent):" + " Monitor: " + ((MonitorContendedEnteredEvent) event).monitor()
+ " Thread: " + ((MonitorContendedEnteredEvent) event).thread();
else if (event instanceof MonitorWaitEvent)
return event + ". Details(MonitorWaitEvent):" + " Monitor: " + ((MonitorWaitEvent) event).monitor() + " Thread: "
+ ((MonitorWaitEvent) event).thread() + " Timeout: " + ((MonitorWaitEvent) event).timeout();
else if (event instanceof MonitorWaitedEvent)
return event + ". Details(MonitorWaitedEvent):" + " Monitor: " + ((MonitorWaitedEvent) event).monitor() + " Thread: "
+ ((MonitorWaitedEvent) event).thread() + " Timedout: " + ((MonitorWaitedEvent) event).timedout();
return event.toString();
}
// this exception can occur when unexpected event was received
catch (ObjectCollectedException e) {
// allowExtraEvents=true extra events are not treated as error
if (!isExtraEventAllowed(event.getClass())) {
setSuccess(false);
e.printStackTrace(log.getOutStream());
log.complain("Unexpected ObjectCollectedException was caught, possible unexpected event was received");
}
return event.getClass().getName() + " [ Can't get full description, ObjectCollectedException was thrown ]";
}
}
// events received during test execution are stored here
private Map<Class<?>, List<Event>> allReceivedEvents = new HashMap<Class<?>, List<Event>>();
private List<Event> getAllReceivedEvents() {
List<Event> result = new LinkedList<Event>();
for (Class<?> eventClass : allReceivedEvents.keySet()) {
result.addAll(allReceivedEvents.get(eventClass));
}
return result;
}
protected Map<Class<?>, List<DebuggerEventData.DebugEventData>> allExpectedEvents = new HashMap<Class<?>, List<DebuggerEventData.DebugEventData>>();
private List<DebuggerEventData.DebugEventData> getAllExpectedEvents() {
List<DebuggerEventData.DebugEventData> result = new LinkedList<DebuggerEventData.DebugEventData>();
for (Class<?> eventClass : allExpectedEvents.keySet()) {
result.addAll(allExpectedEvents.get(eventClass));
}
return result;
}
// find in debuggee VM and add to the list 'allExpectedEvents' instances
// of classes representing generated events
protected void initExpectedEvents(TestedEventData testedEventData[]) {
List<DebuggerEventData.DebugEventData> events;
ReferenceType referenceType = debuggee.classByName(debuggeeClassNameWithoutArgs());
ArrayReference generatedEvents = (ArrayReference) referenceType.getValue(referenceType.fieldByName("generatedEvents"));
for (TestedEventData eventData : testedEventData) {
events = new LinkedList<DebuggerEventData.DebugEventData>();
allExpectedEvents.put(eventData.eventClass, events);
}
for (int i = 0; i < generatedEvents.length(); i++) {
ObjectReference debuggeeMirror = (ObjectReference) generatedEvents.getValue(i);
for (TestedEventData eventData : testedEventData) {
if (debuggeeMirror.referenceType().name().equals(eventData.eventDataMirrorClass.getName())) {
events = allExpectedEvents.get(eventData.eventClass);
/*
* Use reflection to create object representing generated
* event Event data class should has constructor with single
* parameter of type com.sun.jdi.ObjectReference
*/
Constructor<?> constructor;
try {
constructor = eventData.eventDataClass.getConstructor(new Class[] { ObjectReference.class });
} catch (NoSuchMethodException e) {
TestBug testBug = new TestBug(
"Class representing debug event data should implement constructor with single parameter of type com.sun.jdi.ObjectReference");
testBug.initCause(e);
throw testBug;
}
DebuggerEventData.DebugEventData expectedEvent;
try {
expectedEvent = (DebuggerEventData.DebugEventData) constructor.newInstance(new Object[] { debuggeeMirror });
} catch (Exception e) {
TestBug testBug = new TestBug("Error when create debug event data: " + e);
testBug.initCause(e);
throw testBug;
}
events.add(expectedEvent);
}
}
}
}
private void printFiltersInfo() {
if (eventFilters.size() > 0) {
log.display("Use following filters: ");
for (EventFilters.DebugEventFilter filter : eventFilters)
log.display("" + filter);
} else {
log.display("Don't use event filters");
}
}
// filters used in test
protected List<EventFilters.DebugEventFilter> eventFilters = new LinkedList<EventFilters.DebugEventFilter>();
// Check is object generating events matches all filters,
// if object was accepted by all filters set this object's field
// 'saveEventData' to 'true', otherwise to 'false',
private void checkEventGenerator(ThreadReference eventThread, ObjectReference executor) {
boolean acceptedByFilters = true;
for (EventFilters.DebugEventFilter eventFilter : eventFilters) {
if (!eventFilter.isObjectMatch(executor, eventThread)) {
acceptedByFilters = false;
break;
}
}
try {
executor.setValue(executor.referenceType().fieldByName("saveEventData"), vm.mirrorOf(acceptedByFilters));
} catch (Exception e) {
throw new TestBug("Unexpected exception when change object field in debugee VM: " + e, e);
}
}
/*
* Find all event generating threads in debuggee VM (instances of
* nsk.share.jdi.MonitorEventsDebuggee$MonitorActionsThread) all these
* threads have special field - 'executor', this is object which generates
* events. If event generating thread and event generating object was
* accepted by all filters generating object should store information about
* all generated events and this information will be available for debugger
*/
protected void initializeEventGenerators() {
printFiltersInfo();
List<ThreadReference> eventThreads = getEventThreads();
for (ThreadReference eventThread : eventThreads) {
ObjectReference executor = (ObjectReference) eventThread.getValue(eventThread.referenceType().fieldByName("executor"));
checkEventGenerator(eventThread, executor);
}
// debuggee's main thread also can generate events, need to filter it in
// the same way as other threads
checkEventGenerator(debuggee.threadByName(JDIEventsDebuggee.MAIN_THREAD_NAME), findSingleObjectReference(debuggeeClassNameWithoutArgs()));
}
// find instances of nsk.share.jdi.MonitorEventsDebuggee$MonitorActionsThread
protected List<ThreadReference> getEventThreads() {
ReferenceType referenceType = debuggee.classByName(JDIEventsDebuggee.EventActionsThread.class.getName());
List<ObjectReference> debuggeeEventThreads = referenceType.instances(0);
List<ThreadReference> result = new LinkedList<ThreadReference>();
for (ObjectReference threadReference : debuggeeEventThreads)
result.add((ThreadReference) threadReference);
return result;
}
// find instances of nsk.share.jdi.MonitorEventsDebuggee$MonitorActionsThread,
// and get value of this object's field with name 'executor'
protected List<ObjectReference> getEventObjects() {
List<ObjectReference> eventObjects = new LinkedList<ObjectReference>();
List<ThreadReference> eventThreads = getEventThreads();
for (ThreadReference eventThread : eventThreads) {
eventObjects.add((ObjectReference) eventThread.getValue(eventThread.referenceType().fieldByName("executor")));
}
return eventObjects;
}
// remove all filters, received and expected events
private void clearTestData() {
allExpectedEvents.clear();
allReceivedEvents.clear();
eventFilters.clear();
eventsNotGenerated = false;
}
private boolean isEventSupported(EventType eventType) {
switch (eventType) {
case MONITOR_CONTENTED_ENTER:
case MONITOR_CONTENTED_ENTERED:
case MONITOR_WAIT:
case MONITOR_WAITED:
return vm.canRequestMonitorEvents();
default:
throw new TestBug("Invalid tested event type: " + eventType);
}
}
// create instance of EventRequest depending on given eventType
private EventRequest createTestRequest(EventType eventType) {
switch (eventType) {
case MONITOR_CONTENTED_ENTER:
return debuggee.getEventRequestManager().createMonitorContendedEnterRequest();
case MONITOR_CONTENTED_ENTERED:
return debuggee.getEventRequestManager().createMonitorContendedEnteredRequest();
case MONITOR_WAIT:
return debuggee.getEventRequestManager().createMonitorWaitRequest();
case MONITOR_WAITED:
return debuggee.getEventRequestManager().createMonitorWaitedRequest();
default:
throw new TestBug("Invalid tested event type: " + eventType);
}
}
// create command depending on given eventType
private String createCommand(EventType eventTypes[], int eventsNumber) {
String command = JDIEventsDebuggee.COMMAND_CREATE_ACTIONS_EXECUTORS + ":" + eventsNumber + ":";
for (EventType eventType : eventTypes) {
switch (eventType) {
case MONITOR_CONTENTED_ENTER:
case MONITOR_CONTENTED_ENTERED:
case MONITOR_WAIT:
case MONITOR_WAITED:
command += " " + eventType.name();
break;
default:
throw new TestBug("Invalid tested event type: " + eventType);
}
}
return command;
}
// get list of event requests from EventRequestManager depending on the given eventType
private List<?> getEventRequestsFromManager(EventType eventType) {
switch (eventType) {
case MONITOR_CONTENTED_ENTER:
return debuggee.getEventRequestManager().monitorContendedEnterRequests();
case MONITOR_CONTENTED_ENTERED:
return debuggee.getEventRequestManager().monitorContendedEnteredRequests();
case MONITOR_WAIT:
return debuggee.getEventRequestManager().monitorWaitRequests();
case MONITOR_WAITED:
return debuggee.getEventRequestManager().monitorWaitedRequests();
default:
throw new TestBug("Invalid tested event type: " + eventType);
}
}
protected EventHandler eventHandler;
private EventListener eventListener;
// perform event generation before test begins to load all using classes
// and avoid unexpected events related to classloading
protected void prepareDebuggee(EventType[] eventTypes) {
initDefaultBreakpoint();
eventHandler = new EventHandler(debuggee, log);
eventHandler.startListening();
// use event listener which just skip all received events
DummyEventListener dummyEventListener = new DummyEventListener();
eventHandler.addListener(dummyEventListener);
EventRequest eventRequests[] = new EventRequest[eventTypes.length];
for (int i = 0; i < eventRequests.length; i++) {
eventRequests[i] = createTestRequest(eventTypes[i]);
eventRequests[i].setSuspendPolicy(EventRequest.SUSPEND_NONE);
eventRequests[i].enable();
}
// debuggee should create event generators
pipe.println(createCommand(eventTypes, 1));
if (!isDebuggeeReady())
return;
// start event generation
pipe.println(JDIEventsDebuggee.COMMAND_START_EXECUTION);
if (!isDebuggeeReady())
return;
for (int i = 0; i < eventRequests.length; i++)
eventRequests[i].disable();
dummyEventListener.waitBreakpoint();
eventHandler.removeListener(dummyEventListener);
pipe.println(JDIEventsDebuggee.COMMAND_WAIT_EXECUTION_COMPLETION);
if (!isDebuggeeReady())
return;
eventListener = new EventListener(eventDataByEventTypes(eventTypes));
eventHandler.addListener(eventListener);
}
/*
* Method for stress testing, allows specify requests for several event
* types, number of events which should be generated during test and number
* of threads which simultaneously generate events
*/
protected void stressTestTemplate(EventType[] eventTypes, int eventsNumber, int threadsNumber) {
for (EventType eventType : eventTypes) {
if (!isEventSupported(eventType)) {
log.complain("Can't test event because of it isn't supported: " + eventType);
return;
}
}
// Used framework is intended for testing event filters and debuggee
// creates 3 threads performing event generation and there is possibility
// to filter events from some threads
for (int i = 0; i < threadsNumber; i++) {
pipe.println(createCommand(eventTypes, eventsNumber));
if (!isDebuggeeReady())
return;
}
// clear data(if this method is executed several times)
clearTestData();
initializeEventGenerators();
EventRequest eventRequests[] = new EventRequest[eventTypes.length];
// create event requests
for (int i = 0; i < eventTypes.length; i++) {
eventRequests[i] = createTestRequest(eventTypes[i]);
eventRequests[i].setSuspendPolicy(EventRequest.SUSPEND_NONE);
eventRequests[i].enable();
log.display("Use following event request: " + eventRequests[i]);
}
// stressTestTemplate can control only execution time, so ignore iteration count
stresser.start(0);
try {
// start event generation
pipe.println(JDIEventsDebuggee.COMMAND_START_EXECUTION);
if (!isDebuggeeReady())
return;
// check is stressTime exceeded
while (stresser.continueExecution()) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
unexpectedException(e);
}
// periodically check is test completed
if (eventListener.breakpointWasReceived)
break;
}
} finally {
stresser.finish();
}
// debugger should interrupt test because of timeout
if (!eventListener.breakpointWasReceived) {
eventListener.executionWasInterrupted = true;
log.complain("WARNING: time is exceeded, interrupt test");
pipe.println(JDIEventsDebuggee.COMMAND_STOP_EXECUTION);
if (!isDebuggeeReady())
return;
}
pipe.println(JDIEventsDebuggee.COMMAND_WAIT_EXECUTION_COMPLETION);
if (!isDebuggeeReady())
return;
for (int i = 0; i < eventRequests.length; i++)
eventRequests[i].disable();
}
/*
* Hook method for subclasses implementing tests against event filters (it is called from eventFilterTestTemplate)
*/
protected EventFilters.DebugEventFilter[] createTestFilters(int testedFilterIndex) {
throw new TestBug("Not implemented");
}
/*
* Test event request with filter
*
* Also this method check following:
* - InvalidRequestStateException is thrown if add filter for deleted or enabled request
* - EventRequestManager.xxxRequests() returns created event request
*/
protected void eventFilterTestTemplate(EventType eventType, int testedFilterIndex) {
if (!isEventSupported(eventType)) {
log.complain("Can't test event because of it isn't supported: " + eventType);
return;
}
// debuggee create event generators
pipe.println(createCommand(new EventType[] { eventType }, 1));
if (!isDebuggeeReady())
return;
clearTestData();
EventFilters.DebugEventFilter[] filters = createTestFilters(testedFilterIndex);
for (EventFilters.DebugEventFilter filter : filters) {
if (filter.isSupported(vm))
eventFilters.add(filter);
else {
log.complain("Can't test filter because of it isn't supported: " + filter);
return;
}
}
initializeEventGenerators();
// create event request
EventRequest request = createTestRequest(eventType);
request.setSuspendPolicy(EventRequest.SUSPEND_NONE);
// try add filter to enabled request, expect
// 'InvalidRequestStateException'
request.enable();
try {
for (EventFilters.DebugEventFilter filter : filters)
filter.addFilter(request);
setSuccess(false);
log.complain("Expected 'InvalidRequestStateException' was not thrown");
} catch (InvalidRequestStateException e) {
// expected exception
} catch (Throwable e) {
setSuccess(false);
log.complain("Unexpected exception: " + e);
e.printStackTrace(log.getOutStream());
}
// add event filter
request.disable();
for (EventFilters.DebugEventFilter filter : filters)
addFilter(filter, request);
request.enable();
log.display("Use following event request: " + request);
// start event generation
pipe.println(JDIEventsDebuggee.COMMAND_START_EXECUTION);
if (!isDebuggeeReady())
return;
// wait execution completion
pipe.println(JDIEventsDebuggee.COMMAND_WAIT_EXECUTION_COMPLETION);
if (!isDebuggeeReady())
return;
// check that method EventRequestManager.xxxRequests() return created
// request
if (!getEventRequestsFromManager(eventType).contains(request)) {
setSuccess(false);
log.complain("EventRequestManager doesn't return request: " + request);
}
// delete event request
debuggee.getEventRequestManager().deleteEventRequest(request);
// try add filter to removed request, expect
// 'InvalidRequestStateException'
try {
for (EventFilters.DebugEventFilter filter : filters)
filter.addFilter(request);
setSuccess(false);
log.complain("Expected 'InvalidRequestStateException' was not thrown");
} catch (InvalidRequestStateException e) {
// expected exception
} catch (Throwable t) {
unexpectedException(t);
}
}
private void addFilter(EventFilters.DebugEventFilter filter, EventRequest request) {
try {
filter.addFilter(request);
} catch (Throwable t) {
unexpectedException(t);
}
}
// used to parse parameters -allowExtraEvents and -allowMissedEvents
private Class<?>[] createEventClassArray(String string) {
String eventTypesNames[] = string.split(":");
EventType eventTypes[] = new EventType[eventTypesNames.length];
try {
for (int i = 0; i < eventTypesNames.length; i++) {
eventTypes[i] = EventType.valueOf(eventTypesNames[i]);
}
} catch (IllegalArgumentException e) {
throw new TestBug("Invalid event type", e);
}
if (eventTypesNames.length == 0)
throw new TestBug("Event types weren't specified");
Class<?>[] result = new Class[eventTypesNames.length];
for (int i = 0; i < result.length; i++)
result[i] = testedEventData.get(eventTypes[i]).eventClass;
return result;
}
}