blob: 28d1d815e0d09032291e63a8e89aa8fea2875249 [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.*;
import java.util.*;
import com.sun.jdi.*;
import com.sun.jdi.event.*;
import com.sun.jdi.request.*;
import nsk.share.*;
import nsk.share.jpda.*;
import nsk.share.test.StressOptions;
import nsk.share.test.Stresser;
/*
* Class can be used as base debugger class in jdi tests.
* Class contains common method for initializing log, debugee, pipe, vm, and several common auxiliary methods.
* Sublcass should implement doTest() and, if needed, doInit(parse command line parameters) and canRunTest(check if VM support tested functionality)
*/
public class TestDebuggerType2 {
public class EventListenerThread extends Thread {
private EventRequest eventRequest;
private Event event;
private Wicket wicket = new Wicket();
public EventListenerThread(EventRequest eventRequest) {
this.eventRequest = eventRequest;
}
public void run() {
wicket.unlock();
try {
event = debuggee.waitingEvent(eventRequest, argHandler.getWaitTime() * 60000);
} catch (InterruptedException e) {
// ignore
}
}
public void waitStartListen() {
wicket.waitFor();
}
public Event getEvent() {
try {
// wait when EventListenerThread complete execution
this.join();
} catch (InterruptedException e) {
setSuccess(false);
log.complain("Unexpected exception: " + e);
}
return event;
}
}
protected ArgumentHandler argHandler;
protected Log log;
protected IOPipe pipe;
protected Debugee debuggee;
protected VirtualMachine vm;
/*
* this method is called from nsk.share.jdi.SerialExecutionDebugger to set for debugger
* already created instances of ArgumentHandler, Log, IOPipe, Debugee, VirtualMachine
*/
public void initDebugger(ArgumentHandler argHandler, Log log, IOPipe pipe, Debugee debuggee, VirtualMachine vm) {
this.argHandler = argHandler;
this.log = log;
this.pipe = pipe;
this.debuggee = debuggee;
this.vm = vm;
}
private boolean success = true;
protected void setSuccess(boolean value) {
success = value;
}
protected boolean getSuccess() {
return success;
}
// class name used during initialization
protected String debuggeeClassName() {
return null;
}
// select only class name if debuggeeClassName() returns className + debuggee parameters
protected String debuggeeClassNameWithoutArgs() {
String className = debuggeeClassName();
int index = className.indexOf(' ');
if (index > 0) {
return className.substring(0, index);
} else
return className;
}
protected String classpath;
protected String testWorkDir;
// initialize test and remove unsupported by nsk.share.jdi.ArgumentHandler arguments
// (ArgumentHandler constructor throws BadOption exception if command line contains unrecognized by ArgumentHandler options)
// support -testClassPath parameter: path to find classes for custom classloader in debuggee VM
// (note that in this method stressOptions and stresser are created, so if subclasses override this method
// overrided version should first call super.doInit())
protected String[] doInit(String args[], PrintStream out) {
stressOptions = new StressOptions(args);
stresser = new Stresser(stressOptions);
ArrayList<String> standardArgs = new ArrayList<String>();
for (int i = 0; i < args.length; i++) {
if (args[i].equals("-testClassPath") && (i < args.length - 1)) {
classpath = args[i + 1];
i++;
} else if (args[i].equals("-testWorkDir") && (i < args.length - 1)) {
testWorkDir = args[i + 1];
if (testWorkDir.endsWith(File.separator)) {
testWorkDir = testWorkDir.substring(0, testWorkDir.length() - 1);
}
i++;
} else
standardArgs.add(args[i]);
}
return standardArgs.toArray(new String[] {});
}
protected void doTest() {
setSuccess(false);
throw new TestBug("TEST BUG: method doTest not implemented");
}
protected Stresser stresser;
protected StressOptions stressOptions;
// initialize log, debuggee, pipe
public void init(String args[], PrintStream out) {
argHandler = new ArgumentHandler(doInit(args, out));
log = new Log(out, argHandler);
Binder binder = new Binder(argHandler, log);
debuggee = binder.bindToDebugee(debuggeeClassName());
pipe = debuggee.createIOPipe();
debuggee.redirectStderr(log, "Debugger.err> ");
vm = debuggee.VM();
debuggee.resume();
String command = pipe.readln();
if (!command.equals(AbstractDebuggeeTest.COMMAND_READY)) {
setSuccess(false);
log.complain("TEST BUG: unknown debuggee's command: " + command);
}
}
// check that vm support tested functions
protected boolean canRunTest() {
return true;
}
// send quit command to debuggee
protected void quitDebuggee() {
pipe.println(AbstractDebuggeeTest.COMMAND_QUIT);
debuggee.waitFor();
int debStat = debuggee.getStatus();
if (debStat != (Consts.JCK_STATUS_BASE + Consts.TEST_PASSED)) {
setSuccess(false);
log.complain("TEST FAILED: debuggee's process finished with status: " + debStat);
} else
log.display("Debuggee's process finished with status: " + debStat);
}
// init test, execute test, quit debuggee
protected int runIt(String args[], PrintStream out) {
init(args, out);
try {
if (canRunTest())
doTest();
} catch (TestBug testBug) {
setSuccess(false);
log.complain("Test bug: " + testBug);
testBug.printStackTrace(log.getOutStream());
} catch (Throwable t) {
setSuccess(false);
log.complain("Unexpected exception: " + t);
t.printStackTrace(log.getOutStream());
}
quitDebuggee();
if (getSuccess()) {
log.display("TEST PASSED");
return Consts.TEST_PASSED;
} else {
log.display("TEST FAILED");
return Consts.TEST_FAILED;
}
}
// check the debuggee completed pervious command and is ready for new one
protected boolean isDebuggeeReady() {
String command = pipe.readln();
if (!command.equals(AbstractDebuggeeTest.COMMAND_READY)) {
setSuccess(false);
log.complain("TEST BUG: unknown debuggee's command: " + command);
return false;
}
return true;
}
// find in debuggee VM instance of object with given class and check
// that there is only one instance of this class
protected ObjectReference findSingleObjectReference(String className) {
ReferenceType referenceType = debuggee.classByName(className);
if (referenceType == null)
throw new TestBug("There is no class '" + className + "' in debuggee");
List<ObjectReference> instances = referenceType.instances(0);
if (instances.size() == 0)
throw new TestBug("There are no instances of class '" + className + "' in debuggee");
if (instances.size() > 1)
throw new TestBug("There are more than one(" + instances.size() + ") instance of '" + className + " in debuggee");
return instances.get(0);
}
protected BreakpointEvent waitForBreakpoint(BreakpointRequest breakpointRequest) {
BreakpointEvent breakpointEvent;
try {
breakpointEvent = (BreakpointEvent) debuggee.waitingEvent(breakpointRequest, argHandler.getWaitTime() * 60000);
} catch (InterruptedException e) {
setSuccess(false);
e.printStackTrace(log.getOutStream());
log.complain("unexpected InterruptedException: " + e);
breakpointEvent = null;
}
if (breakpointEvent == null) {
setSuccess(false);
log.complain("Didn't get expected breakpoint event");
}
return breakpointEvent;
}
private boolean currentSuccess = false;
protected void forceGC() {
pipe.println(AbstractDebuggeeTest.COMMAND_FORCE_GC);
if (!isDebuggeeReady())
return;
currentSuccess = getSuccess();
}
// Get GC statistics
protected void resetStatusIfGC() {
pipe.println(AbstractDebuggeeTest.COMMAND_GC_COUNT);
String command = pipe.readln();
if (command.startsWith(AbstractDebuggeeTest.COMMAND_GC_COUNT)) {
if (!isDebuggeeReady()) {
return;
}
if (Integer.valueOf(command.substring(AbstractDebuggeeTest.COMMAND_GC_COUNT.length() + 1)) > 0) {
log.display("WARNING: The GC worked during tests. Results are skipped.");
setSuccess(currentSuccess);
}
return;
}
setSuccess(false);
}
protected BreakpointRequest defaultBreakpointRequest;
protected void initDefaultBreakpoint() {
defaultBreakpointRequest = debuggee.makeBreakpoint(debuggee.classByName(debuggeeClassNameWithoutArgs()),
AbstractDebuggeeTest.DEFAULT_BREAKPOINT_METHOD_NAME, AbstractDebuggeeTest.DEFAULT_BREAKPOINT_LINE);
defaultBreakpointRequest.setSuspendPolicy(EventRequest.SUSPEND_ALL);
defaultBreakpointRequest.enable();
}
protected void removeDefaultBreakpoint() {
defaultBreakpointRequest.disable();
debuggee.getEventRequestManager().deleteEventRequest(defaultBreakpointRequest);
defaultBreakpointRequest = null;
}
protected Value createVoidValue() {
return vm.mirrorOfVoid();
}
// force debuggee call 'TestDebuggeeType2.breakpointMethod()'
protected BreakpointEvent forceBreakpoint() {
pipe.println(AbstractDebuggeeTest.COMMAND_FORCE_BREAKPOINT);
BreakpointEvent event = waitForBreakpoint(defaultBreakpointRequest);
return event;
}
protected void unexpectedException(Throwable t) {
setSuccess(false);
log.complain("Unexpected exception: " + t);
t.printStackTrace(log.getOutStream());
}
protected void display(String msg) {
log.display(msg);
}
protected void complain(String msg) {
log.complain("debugger FAILURE> " + msg + "\n");
}
protected boolean isJFR_active() {
return debuggee.isJFR_active();
}
}