001: /*
002: *
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
004: *
005: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
006: *
007: * The contents of this file are subject to the terms of either the GNU
008: * General Public License Version 2 only ("GPL") or the Common
009: * Development and Distribution License("CDDL") (collectively, the
010: * "License"). You may not use this file except in compliance with the
011: * License. You can obtain a copy of the License at
012: * http://www.netbeans.org/cddl-gplv2.html
013: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
014: * specific language governing permissions and limitations under the
015: * License. When distributing the software, include this License Header
016: * Notice in each file and include the License file at
017: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
018: * particular file as subject to the "Classpath" exception as provided
019: * by Sun in the GPL Version 2 section of the License file that
020: * accompanied this code. If applicable, add the following below the
021: * License Header, with the fields enclosed by brackets [] replaced by
022: * your own identifying information:
023: * "Portions Copyrighted [year] [name of copyright owner]"
024: *
025: * Contributor(s):
026: *
027: * The Original Software is NetBeans. The Initial Developer of the Original
028: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
029: * Microsystems, Inc. All Rights Reserved.
030: *
031: * If you wish your version of this file to be governed by only the CDDL
032: * or only the GPL Version 2, indicate your decision by adding
033: * "[Contributor] elects to include this software in this distribution
034: * under the [CDDL or GPL Version 2] license." If you do not indicate a
035: * single choice of license, a recipient has the option to distribute
036: * your version of this file under either the CDDL, the GPL Version 2 or
037: * to extend the choice of license to its licensees as provided above.
038: * However, if you add GPL Version 2 code and therefore, elected the GPL
039: * Version 2 license, then the option applies only if the new code is
040: * made subject to such option by the copyright holder.
041: */
042:
043: /*
044: * JUnitTestRunnerTask.java
045: *
046: * Created on November 26, 2002, 2:32 PM
047: */
048:
049: package org.netbeans.xtest.plugin.jvm;
050:
051: import org.apache.tools.ant.*;
052: import org.apache.tools.ant.types.*;
053: import java.io.*;
054: import java.util.*;
055: import org.apache.tools.ant.taskdefs.*; //import org.apache.tools.ant.AntClassLoader;
056: import org.netbeans.xtest.testrunner.*;
057:
058: /**
059: *
060: * @author mb115822
061: */
062: public class JVMTestRunnerTask extends Task implements
063: TestBoardLauncher {
064:
065: /** Creates a new instance of JUnitTestRunnerTask */
066: public JVMTestRunnerTask() {
067: }
068:
069: // sys property
070: public void addSysProperty(Environment.Variable sysp) {
071: log("Adding system property " + sysp.getKey() + "="
072: + sysp.getValue(), Project.MSG_DEBUG);
073: sysProperties.add(sysp);
074:
075: }
076:
077: // sys property file
078: /**
079: * Add a nested syspropertyfile element. This might be useful to tranfer
080: * Ant properties from file to the testcases.
081: */
082: public void addConfiguredSysPropertyFile(FileVariable fileVariable)
083: throws IOException {
084: log("Adding sys property file " + fileVariable.file,
085: Project.MSG_DEBUG);
086: Properties props = new Properties();
087: BufferedInputStream bis = new BufferedInputStream(
088: new FileInputStream(fileVariable.file));
089: props.load(bis);
090: bis.close();
091: Iterator iter = props.entrySet().iterator();
092: while (iter.hasNext()) {
093: Map.Entry entry = (Map.Entry) iter.next();
094: Environment.Variable var = new Environment.Variable();
095: var.setKey((String) entry.getKey());
096: var.setValue((String) entry.getValue());
097: sysProperties.add(var);
098: }
099: }
100:
101: public Path createClasspath() {
102: log("Creating classpath", Project.MSG_DEBUG);
103: return commandLine.createClasspath(getProject()).createPath();
104: }
105:
106: // work directory
107: public void setWorkDir(File workDir) {
108: log("Setting workDir to " + workDir, Project.MSG_DEBUG);
109: this .workDir = workDir;
110: }
111:
112: private String getJavaExecutableName() {
113: if (System.getProperty("os.name").toLowerCase().indexOf(
114: "windows") != -1) {
115: // hey, we're running on windows
116: return "java.exe";
117: } else {
118: // normal OS :-)
119: return "java";
120: }
121: }
122:
123: public void setJdkHome(File jdkHome) {
124: if ((jdkHome != null) & (jdkHome.isDirectory())) {
125: log("jdkHome is " + jdkHome, Project.MSG_DEBUG);
126: // try to find java executable
127: File binDir = new File(jdkHome, "bin");
128: log("Bin is " + binDir, Project.MSG_DEBUG);
129: if (binDir.isDirectory()) {
130: File javaExecutable = new File(binDir,
131: getJavaExecutableName());
132: log("Executable is " + javaExecutable,
133: Project.MSG_DEBUG);
134: if (javaExecutable.exists()
135: & (!javaExecutable.isDirectory())) {
136: log("Setting jdkHome to " + jdkHome,
137: Project.MSG_DEBUG);
138: commandLine.setVm(javaExecutable.getAbsolutePath());
139: return;
140: }
141: }
142: }
143: // java executable not found !!!
144: log("jdkHome is not set to a correct JAVA_HOME directory: "
145: + jdkHome);
146: log(" - using the same Java as the script is running in.");
147: }
148:
149: // jvm args
150: public void setJvmArgs(String jvmArgs) {
151: log("Setting jvm args to " + jvmArgs, Project.MSG_DEBUG);
152: this .jvmArgs = jvmArgs;
153: }
154:
155: /**
156: * when set to true, -ea switch is used to run the JVM
157: */
158: public void setEnableAssertions(boolean enableAssertions) {
159: this .enableAssertions = enableAssertions;
160: }
161:
162: /** Debug address to connect to
163: */
164: public void setDebugAddress(String address) {
165: if (address.equals(""))
166: return;
167:
168: this .debugAddress = address;
169: }
170:
171: /**
172: * when port is set > 0, JVM is started in debugging mode
173: */
174: public void setDebugPort(int port) {
175: if (port == 0)
176: return;
177:
178: this .debugPort = port;
179: }
180:
181: /**
182: * suspend switch of debug
183: */
184: public void setDebugSuspend(boolean suspend) {
185: this .debugSuspend = suspend;
186: }
187:
188: // test mode
189: public void setTestMode(String testMode) {
190: if ((testMode != null) & (!testMode.equals(""))) {
191: log("Setting test modes to " + testMode, Project.MSG_DEBUG);
192: this .testMode = testMode;
193: } else {
194: log("Leaving default setting.", Project.MSG_DEBUG);
195: }
196: }
197:
198: // timeout
199: public void setTimeout(Long value) {
200: this .timeout = value;
201: }
202:
203: public void execute() throws BuildException {
204: try {
205: log("Running JUnit in plain VM");
206: // check validity of input values
207: checkInputValuesValidity();
208: // log input Values
209: logInputValues(Project.MSG_VERBOSE);
210: // execute test run (this depends on testmode)
211: TestRunnerHarness testRunnerHarness = new TestRunnerHarness(
212: this , workDir, testMode);
213: testRunnerHarness.runTests();
214: } catch (IOException ioe) {
215: throw new BuildException(
216: ioe.getMessage() == null ? "IOException caught"
217: : ioe.getMessage(), ioe);
218: }
219: }
220:
221: // private stuff
222:
223: // system properties arraylist
224: private ArrayList sysProperties = new ArrayList();
225:
226: // command line helper - from ant
227: private CommandlineJava commandLine = new CommandlineJava();
228:
229: // test runner class name
230: private static final String TESTRUNNER_CLASS_NAME = "org.netbeans.xtest.plugin.jvm.JUnitTestRunnerLauncher";
231: // testlist filename
232: private static final String TESTLIST_FILENAME = "testrunner.testlist";
233:
234: // test runner property file - is set via prepareTestRunnerProperties and used by prepareCommandLine
235: private File testRunnerPropertyFile = null;
236:
237: // work dir where test runner property file is stored
238: private File workDir;
239: // jvm args
240: private String jvmArgs;
241: // test mode (e.g. tastbag, testsuite ....)
242: private String testMode = TestRunnerHarness.TESTRUN_MODE_TESTSUITE;
243: // timeout
244: private Long timeout = null;
245:
246: // jvm should be started with -ea switch
247: protected boolean enableAssertions = true;
248:
249: // debug should suspend code execution
250: protected boolean debugSuspend = false;
251:
252: // debug port to which debugger is connected. When 0 - debugging is not started
253: protected int debugPort = 0;
254:
255: /** debug address to connect to */
256: private String debugAddress;
257:
258: //
259: private void checkInputValuesValidity() throws BuildException {
260: // workDir
261: if (workDir == null) {
262: throw new BuildException("WorkDir is not set");
263: }
264: }
265:
266: // verbose output of execute (overview of task arguments)
267: private void logInputValues(int logLevel) {
268: // verbose logs
269: log("Using Java from: "
270: + commandLine.getVmCommand().getExecutable(), logLevel);
271: log("Using classpath: " + commandLine.getClasspath(), logLevel);
272: log("Using work dir: " + workDir.getPath(), logLevel);
273: // sys properties
274: Iterator i = sysProperties.iterator();
275: while (i.hasNext()) {
276: Environment.Variable var = (Environment.Variable) i.next();
277: log("Using system property (key=value): " + var.getKey()
278: + "=" + var.getValue(), logLevel);
279: }
280: // jvm args
281: if ((jvmArgs != null) & (!jvmArgs.equals(""))) {
282: log("Using JVM args: " + jvmArgs, logLevel);
283: }
284: // test mode
285: if (testMode != null) {
286: log("Using test mode: " + testMode, logLevel);
287: }
288: }
289:
290: // VM starting method
291: public void launchTestBoard(
292: JUnitTestRunnerProperties testsToBeExecuted)
293: throws TestBoardLauncherException {
294: File runnerPropertiesFile = new File(workDir, TESTLIST_FILENAME);
295: try {
296: // save runner properties to a file
297: testsToBeExecuted.save(runnerPropertiesFile);
298: CommandlineJava preparedCommandLine = prepareCommandLine(
299: commandLine, runnerPropertiesFile);
300: log("Running VM", Project.MSG_VERBOSE);
301: executeCommandLine(preparedCommandLine);
302: } catch (IOException ioe) {
303: throw new TestBoardLauncherException(
304: "During launching tests caught IOException"
305: + ioe.getMessage(), ioe);
306: } finally {
307: // delete runner properties
308: runnerPropertiesFile.delete();
309: }
310: }
311:
312: // save runner properties to a file
313:
314: // propare command line
315: private CommandlineJava prepareCommandLine(
316: CommandlineJava existingCommandLine,
317: File runnerPropertiesFile) throws BuildException {
318: log("Preparing command line", Project.MSG_DEBUG);
319: CommandlineJava commandLine;
320: try {
321: commandLine = (CommandlineJava) existingCommandLine.clone();
322: } catch (Exception ex) {
323: // since ant1.6.3 java.lang.CloneNotSupportedException can be thrown
324: throw new BuildException(ex);
325: }
326: log("Preparing command line", Project.MSG_DEBUG);
327: commandLine.setClassname(TESTRUNNER_CLASS_NAME);
328: // JVM args
329: if ((jvmArgs != null) & (!jvmArgs.equals(""))) {
330: commandLine.createVmArgument().setLine(jvmArgs);
331: }
332: // enable assertions
333: if (enableAssertions) {
334: commandLine.createVmArgument().setValue("-ea");
335: }
336: // debugger
337: if (debugPort > 0) {
338: if (debugAddress != null) {
339: throw new BuildException(
340: "Cannot set debug port and address at once: "
341: + debugPort + " address: "
342: + debugAddress);
343: }
344: String suspendArg = debugSuspend ? "y" : "n";
345: String debugArgument = "-Xdebug -Xnoagent -Xrunjdwp:transport=dt_socket,server=y,suspend="
346: + suspendArg + ",address=" + debugPort;
347: commandLine.createVmArgument().setLine(debugArgument);
348: } else {
349: if (debugAddress != null) {
350: String suspendArg = debugSuspend ? "y" : "n";
351: String debugArgument = "-Xdebug -Xnoagent -Xrunjdwp:transport=dt_socket,server=n,suspend="
352: + suspendArg + ",address=" + debugAddress;
353: commandLine.createVmArgument().setLine(debugArgument);
354: }
355: }
356:
357: // add runnerproperties file sys property
358: Environment.Variable runnerProperties = new Environment.Variable();
359: runnerProperties
360: .setKey(JUnitTestRunner.TESTRUNNER_PROPERTIES_FILENAME_KEY);
361: runnerProperties.setValue(runnerPropertiesFile
362: .getAbsolutePath());
363: commandLine.addSysproperty(runnerProperties);
364:
365: // sys properties
366: Iterator i = sysProperties.iterator();
367: while (i.hasNext()) {
368: Environment.Variable var = (Environment.Variable) i.next();
369: commandLine.addSysproperty(var);
370: }
371: return commandLine;
372: }
373:
374: // execute the command line
375: private void executeCommandLine(CommandlineJava execteCommandLine)
376: throws BuildException {
377: //CommandlineJava cmd = (CommandlineJava) execteCommandLine.clone();
378: CommandlineJava cmd;
379: try {
380: // since ant1.6.3 java.lang.CloneNotSupportedException can be thrown
381: cmd = (CommandlineJava) execteCommandLine.clone();
382: } catch (Exception ex) {
383: throw new BuildException(ex);
384: }
385: ExecuteWatchdog watchdog = createWatchdog();
386: Execute execute = new Execute(new LogStreamHandler(this ,
387: Project.MSG_INFO, Project.MSG_WARN), watchdog);
388: execute.setCommandline(cmd.getCommandline());
389: if (workDir != null) {
390: execute.setWorkingDirectory(workDir);
391: // ????? what does this do ??????
392: execute.setAntRun(getProject());
393: }
394: // execute
395: log("Executing: " + cmd.toString(), Project.MSG_VERBOSE);
396: //log("Executing: "+cmd.toString(), Project.MSG_INFO);
397: try {
398: int result = execute.execute();
399: } catch (IOException e) {
400: throw new BuildException("Process fork failed.", e,
401: getLocation());
402: }
403: }
404:
405: /**
406: * @return <tt>null</tt> if there is a timeout value, otherwise the
407: * watchdog instance.
408: */
409: private ExecuteWatchdog createWatchdog() throws BuildException {
410: if (timeout == null) {
411: return null;
412: }
413: return new JVMExecuteWatchdog(timeout.longValue(), getProject());
414: }
415:
416: /////////////////////////
417: ///////// inner classes
418: /////////////////////////
419:
420: /**
421: * Nested 'syspropertyfile' element. It has only one attribute, file.
422: */
423: public static class FileVariable {
424: private File file;
425:
426: public void setFile(java.io.File file) {
427: this.file = file;
428: }
429: }
430:
431: }
|