bebd49cf84
Reviewed-by: sspitsyn, cjplummer, amenkov
463 lines
19 KiB
Java
463 lines
19 KiB
Java
/*
|
|
* 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.*;
|
|
import java.util.*;
|
|
|
|
import com.sun.jdi.*;
|
|
import com.sun.jdi.event.*;
|
|
import nsk.share.Consts;
|
|
import nsk.share.TestBug;
|
|
|
|
/*
|
|
* Class contains debugger classes based on JDIEventsDebugger intended for JDI events testing
|
|
*/
|
|
public class EventTestTemplates {
|
|
|
|
// how many times rerun test in case when tested events aren't generated
|
|
static final int MAX_TEST_RUN_NUMBER = 10;
|
|
|
|
/*
|
|
* Method contains common code used by EventFilterTests and StressTestTemplate
|
|
*/
|
|
static void runTestWithRerunPossibilty(JDIEventsDebugger debugger, Runnable testRunner) {
|
|
for (int i = 0; i < MAX_TEST_RUN_NUMBER; i++) {
|
|
testRunner.run();
|
|
|
|
/*
|
|
* If events weren't generated at all but test accepts missing events
|
|
* try to rerun test (rerun test only if it didn't fail yet)
|
|
*/
|
|
if (debugger.eventsNotGenerated() && debugger.getSuccess()) {
|
|
if (i < MAX_TEST_RUN_NUMBER - 1) {
|
|
debugger.log.display("\nWARNING: tested events weren't generated at all, trying to rerun test (rerun attempt " + (i + 1) + ")\n");
|
|
continue;
|
|
} else {
|
|
debugger.setSuccess(false);
|
|
debugger.log.complain("Tested events weren't generated after " + MAX_TEST_RUN_NUMBER + " runs, test FAILED");
|
|
}
|
|
} else
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Debugger class for testing event filters, subclasses should parse command
|
|
* line and call method JDIEventsDebugger.eventFilterTestTemplate with
|
|
* required arguments.
|
|
*
|
|
* Class handles common for event filter tests parameters:
|
|
* - debuggee class name (e.g. -debuggeeClassName nsk.share.jdi.MonitorEventsDebuggee)
|
|
* - tested event type (e.g. -eventType MONITOR_CONTENTED_ENTER)
|
|
*/
|
|
public static abstract class EventFilterTest extends JDIEventsDebugger {
|
|
protected String debuggeeClassName;
|
|
|
|
protected EventType eventType;
|
|
|
|
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("-debuggeeClassName") && (i < args.length - 1)) {
|
|
debuggeeClassName = args[i + 1];
|
|
i++;
|
|
} else if (args[i].equals("-eventType") && (i < args.length - 1)) {
|
|
try {
|
|
eventType = EventType.valueOf(args[i + 1]);
|
|
} catch (IllegalArgumentException e) {
|
|
TestBug testBug = new TestBug("Invalid event type : " + args[i + 1], e);
|
|
throw testBug;
|
|
}
|
|
i++;
|
|
} else
|
|
standardArgs.add(args[i]);
|
|
}
|
|
|
|
if (eventType == null)
|
|
throw new TestBug("Test requires 'eventType' parameter");
|
|
|
|
if (debuggeeClassName == null)
|
|
throw new TestBug("Test requires 'debuggeeClassName' parameter");
|
|
|
|
return standardArgs.toArray(new String[] {});
|
|
}
|
|
|
|
abstract protected int getTestFiltersNumber();
|
|
|
|
// This class is required to call runTestWithRerunPossibilty()
|
|
class FilterTestRunner implements Runnable {
|
|
private int filterIndex;
|
|
|
|
FilterTestRunner(int filterIndex) {
|
|
this.filterIndex = filterIndex;
|
|
}
|
|
|
|
public void run() {
|
|
eventFilterTestTemplate(eventType, filterIndex);
|
|
}
|
|
}
|
|
|
|
public final void doTest() {
|
|
prepareDebuggee(new EventType[] {eventType});
|
|
|
|
int filtersNumber = getTestFiltersNumber();
|
|
|
|
if (filtersNumber <= 0)
|
|
throw new TestBug("Invalid filtersNumber: " + filtersNumber);
|
|
|
|
for (int filterIndex = 0; filterIndex < getTestFiltersNumber(); filterIndex++) {
|
|
runTestWithRerunPossibilty(this, new FilterTestRunner(filterIndex));
|
|
}
|
|
|
|
eventHandler.stopEventHandler();
|
|
removeDefaultBreakpoint();
|
|
}
|
|
|
|
// can't control events from system libraries, so save events only from nsk packages
|
|
protected boolean shouldSaveEvent(Event event) {
|
|
return isEventFromNSK(event, debuggee);
|
|
}
|
|
|
|
protected String debuggeeClassName() {
|
|
return debuggeeClassName;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Class for testing class exclusion filter, this filter is added by
|
|
* request's method addClassExclusionFilter(String classPattern) Expected
|
|
* command line parameter:
|
|
* - class patterns which should be passed to adding filter method (e.g. -classPatterns java.*:*.Foo)
|
|
*/
|
|
public static class ClassExclusionFilterTest extends EventFilterTest {
|
|
protected String classPatterns[];
|
|
|
|
public static void main(String argv[]) {
|
|
System.exit(run(argv, System.out) + Consts.JCK_STATUS_BASE);
|
|
}
|
|
|
|
public static int run(String argv[], PrintStream out) {
|
|
return new ClassExclusionFilterTest().runIt(argv, out);
|
|
}
|
|
|
|
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("-classPatterns") && (i < args.length - 1)) {
|
|
classPatterns = args[i + 1].split(":");
|
|
i++;
|
|
} else
|
|
standardArgs.add(args[i]);
|
|
}
|
|
|
|
if (classPatterns == null || classPatterns.length == 0)
|
|
throw new TestBug("Test requires at least one class name pattern");
|
|
|
|
return standardArgs.toArray(new String[] {});
|
|
}
|
|
|
|
protected int getTestFiltersNumber() {
|
|
return classPatterns.length;
|
|
}
|
|
|
|
protected EventFilters.DebugEventFilter[] createTestFilters(int testedFilterIndex) {
|
|
if (testedFilterIndex < 0 || testedFilterIndex >= classPatterns.length)
|
|
throw new TestBug("Invalid testedFilterIndex: " + testedFilterIndex);
|
|
|
|
return new EventFilters.DebugEventFilter[]{new EventFilters.ClassExclusionFilter(classPatterns[testedFilterIndex])};
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Subclass of ClassExclusionFilterTest, create ClassFilter instead of
|
|
* ClassExclusionFilter, this filter is added by request's method
|
|
* addClassFilter(String classPattern)
|
|
*/
|
|
public static class ClassFilterTest_ClassName extends ClassExclusionFilterTest {
|
|
public static void main(String argv[]) {
|
|
System.exit(run(argv, System.out) + Consts.JCK_STATUS_BASE);
|
|
}
|
|
|
|
public static int run(String argv[], PrintStream out) {
|
|
return new ClassFilterTest_ClassName().runIt(argv, out);
|
|
}
|
|
|
|
protected EventFilters.DebugEventFilter[] createTestFilters(int testedFilterIndex) {
|
|
if (testedFilterIndex < 0 || testedFilterIndex >= classPatterns.length)
|
|
throw new TestBug("Invalid testedFilterIndex: " + testedFilterIndex);
|
|
|
|
return new EventFilters.DebugEventFilter[]{new EventFilters.ClassFilter(classPatterns[testedFilterIndex])};
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Subclass of ClassExclusionFilterTest, create ClassReferenceFilter instead
|
|
* of ClassExclusionFilter, this filter is added by request's method
|
|
* addClassFilter(ReferenceType referenceType)
|
|
*/
|
|
public static class ClassFilterTest_ReferenceType extends ClassExclusionFilterTest {
|
|
public static void main(String argv[]) {
|
|
System.exit(run(argv, System.out) + Consts.JCK_STATUS_BASE);
|
|
}
|
|
|
|
public static int run(String argv[], PrintStream out) {
|
|
return new ClassFilterTest_ReferenceType().runIt(argv, out);
|
|
}
|
|
|
|
protected int getTestFiltersNumber() {
|
|
return classPatterns.length;
|
|
}
|
|
|
|
protected EventFilters.DebugEventFilter[] createTestFilters(int testedFilterIndex) {
|
|
if (testedFilterIndex < 0 || testedFilterIndex >= classPatterns.length)
|
|
throw new TestBug("Invalid testedFilterIndex: " + testedFilterIndex);
|
|
|
|
ReferenceType referenceType = debuggee.classByName(classPatterns[testedFilterIndex]);
|
|
if (referenceType == null)
|
|
throw new TestBug("Invalid class name is passed: " + classPatterns[testedFilterIndex]);
|
|
|
|
return new EventFilters.DebugEventFilter[]{new EventFilters.ClassReferenceFilter(referenceType)};
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Class for testing instance filter, this filter is added by request's
|
|
* method addInstanceFilter(ObjectReference instance). Class tests 3 following
|
|
* cases:
|
|
* - add filter for single object
|
|
* - add filter for the same object 2 times, expect behavior such as in previous case
|
|
* - add filter for 2 different objects, so events shouldn't be received
|
|
*/
|
|
public static class InstanceFilterTest extends EventFilterTest {
|
|
public static void main(String argv[]) {
|
|
System.exit(run(argv, System.out) + Consts.JCK_STATUS_BASE);
|
|
}
|
|
|
|
public static int run(String argv[], PrintStream out) {
|
|
return new InstanceFilterTest().runIt(argv, out);
|
|
}
|
|
|
|
protected int getTestFiltersNumber() {
|
|
return 3;
|
|
}
|
|
|
|
protected EventFilters.DebugEventFilter[] createTestFilters(int testedFilterIndex) {
|
|
List<ObjectReference> objects = getEventObjects();
|
|
|
|
if (objects.size() < 2) {
|
|
throw new TestBug("Debuggee didn't create event generating objects");
|
|
}
|
|
|
|
switch (testedFilterIndex) {
|
|
case 0:
|
|
// filter for 1 object
|
|
return new EventFilters.DebugEventFilter[]{new EventFilters.ObjectReferenceFilter(objects.get(0))};
|
|
case 1:
|
|
// add 2 filters for the same object
|
|
return new EventFilters.DebugEventFilter[]{new EventFilters.ObjectReferenceFilter(objects.get(0)),
|
|
new EventFilters.ObjectReferenceFilter(objects.get(0))};
|
|
case 2:
|
|
// add 2 filters for 2 different objects, so don't expect any event
|
|
return new EventFilters.DebugEventFilter[]{new EventFilters.ObjectReferenceFilter(objects.get(0)),
|
|
new EventFilters.ObjectReferenceFilter(objects.get(1))};
|
|
default:
|
|
throw new TestBug("Invalid testedFilterIndex: " + testedFilterIndex);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Class for testing thread filter, this filter is added by request's method
|
|
* addThreadFilter(ThreadReference thread). Class test 3 follows cases:
|
|
* - add filter for single thread
|
|
* - add filter for the same thread 2 times, expect behavior such as in previous case
|
|
* - add filter for 2 different threads, so events shouldn't be received
|
|
*/
|
|
public static class ThreadFilterTest extends EventFilterTest {
|
|
public static void main(String argv[]) {
|
|
System.exit(run(argv, System.out) + Consts.JCK_STATUS_BASE);
|
|
}
|
|
|
|
public static int run(String argv[], PrintStream out) {
|
|
return new ThreadFilterTest().runIt(argv, out);
|
|
}
|
|
|
|
protected int getTestFiltersNumber() {
|
|
return 3;
|
|
}
|
|
|
|
protected EventFilters.DebugEventFilter[] createTestFilters(int testedFilterIndex) {
|
|
List<ThreadReference> threads = getEventThreads();
|
|
|
|
if (threads.size() < 2) {
|
|
throw new TestBug("Debuggee didn't create event generating threads");
|
|
}
|
|
|
|
switch (testedFilterIndex) {
|
|
case 0:
|
|
// filter for 1 thread
|
|
return new EventFilters.DebugEventFilter[]{new EventFilters.ThreadFilter(threads.get(0))};
|
|
case 1:
|
|
// add 2 filters for the same thread
|
|
return new EventFilters.DebugEventFilter[]{new EventFilters.ThreadFilter(threads.get(0)),
|
|
new EventFilters.ThreadFilter(threads.get(0))};
|
|
case 2:
|
|
// add 2 filters for 2 different threads, so don't expect any event
|
|
return new EventFilters.DebugEventFilter[]{new EventFilters.ThreadFilter(threads.get(0)),
|
|
new EventFilters.ThreadFilter(threads.get(1))};
|
|
default:
|
|
throw new TestBug("Invalid testedFilterIndex: " + testedFilterIndex);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Class is intended for stress testing, expected command line parameters:
|
|
* - debuggee class name (e.g.: -debuggeeClassName nsk.share.jdi.MonitorEventsDebuggee)
|
|
* - one or more tested event types (e.g.: -eventTypes MONITOR_CONTENTED_ENTER:MONITOR_CONTENTED_ENTERED)
|
|
* - number of events which should be generated during test execution (e.g.: -eventsNumber 500)
|
|
* - number of threads which simultaneously generate events (e.g.: -threadsNumber 10)
|
|
*
|
|
* Class parses command line and calls method JDIEventsDebugger.stressTestTemplate.
|
|
*/
|
|
public static class StressTestTemplate extends JDIEventsDebugger {
|
|
protected String debuggeeClassName;
|
|
|
|
protected EventType testedEventTypes[];
|
|
|
|
protected int eventsNumber = 1;
|
|
|
|
protected int threadsNumber = 1;
|
|
|
|
public static void main(String argv[]) {
|
|
System.exit(run(argv, System.out) + Consts.JCK_STATUS_BASE);
|
|
}
|
|
|
|
public static int run(String argv[], PrintStream out) {
|
|
return new StressTestTemplate().runIt(argv, out);
|
|
}
|
|
|
|
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("-eventsNumber") && (i < args.length - 1)) {
|
|
eventsNumber = Integer.parseInt(args[i + 1]);
|
|
|
|
// for this stress test events number is equivalent of iterations
|
|
// (don't support 0 value of IterationsFactor)
|
|
if (stressOptions.getIterationsFactor() != 0)
|
|
eventsNumber *= stressOptions.getIterationsFactor();
|
|
|
|
i++;
|
|
} else if (args[i].equals("-threadsNumber") && (i < args.length - 1)) {
|
|
threadsNumber = Integer.parseInt(args[i + 1]);
|
|
|
|
// if 'threadsNumber' is specified test should take in account stress options
|
|
threadsNumber *= stressOptions.getThreadsFactor();
|
|
|
|
i++;
|
|
} else if (args[i].equals("-debuggeeClassName") && (i < args.length - 1)) {
|
|
debuggeeClassName = args[i + 1];
|
|
i++;
|
|
} else if (args[i].equals("-eventTypes") && (i < args.length - 1)) {
|
|
String eventTypesNames[] = args[i + 1].split(":");
|
|
testedEventTypes = new EventType[eventTypesNames.length];
|
|
try {
|
|
for (int j = 0; j < eventTypesNames.length; j++)
|
|
testedEventTypes[j] = EventType.valueOf(eventTypesNames[j]);
|
|
} catch (IllegalArgumentException e) {
|
|
throw new TestBug("Invalid event type", e);
|
|
}
|
|
|
|
i++;
|
|
} else
|
|
standardArgs.add(args[i]);
|
|
}
|
|
|
|
if (testedEventTypes == null || testedEventTypes.length == 0)
|
|
throw new TestBug("Test requires 'eventTypes' parameter");
|
|
|
|
if (debuggeeClassName == null)
|
|
throw new TestBug("Test requires 'debuggeeClassName' parameter");
|
|
|
|
return standardArgs.toArray(new String[] {});
|
|
}
|
|
|
|
// can't control events from system libraries, so save events only from nsk packages
|
|
protected boolean shouldSaveEvent(Event event) {
|
|
return isEventFromNSK(event, debuggee);
|
|
}
|
|
|
|
protected String debuggeeClassName() {
|
|
return debuggeeClassName;
|
|
}
|
|
|
|
public void doTest() {
|
|
prepareDebuggee(testedEventTypes);
|
|
|
|
runTestWithRerunPossibilty(this, new Runnable() {
|
|
public void run() {
|
|
stressTestTemplate(testedEventTypes, eventsNumber, threadsNumber);
|
|
}
|
|
});
|
|
|
|
eventHandler.stopEventHandler();
|
|
removeDefaultBreakpoint();
|
|
}
|
|
}
|
|
|
|
static public boolean isEventFromNSK(Event event, Debugee debuggee) {
|
|
try {
|
|
if (event instanceof MonitorContendedEnterEvent) {
|
|
return ((MonitorContendedEnterEvent) event).location() != null && ((MonitorContendedEnterEvent) event).monitor().type().name().startsWith("nsk.");
|
|
}
|
|
if (event instanceof MonitorContendedEnteredEvent) {
|
|
return ((MonitorContendedEnteredEvent) event).location() != null && ((MonitorContendedEnteredEvent) event).monitor().type().name().startsWith("nsk.");
|
|
}
|
|
if (event instanceof MonitorWaitEvent) {
|
|
return ((MonitorWaitEvent) event).monitor().type().name().startsWith("nsk.");
|
|
}
|
|
if (event instanceof MonitorWaitedEvent) {
|
|
return ((MonitorWaitedEvent) event).monitor().type().name().startsWith("nsk.");
|
|
}
|
|
} catch (ObjectCollectedException ex) {
|
|
// The monitor object the event refers to might be already collected. Ignore this exception.
|
|
debuggee.getLog().display("Exception caught:" + ex);
|
|
return false;
|
|
}
|
|
// don't filter other events
|
|
return true;
|
|
}
|
|
|
|
}
|