001: // THIS SOFTWARE IS PROVIDED BY SOFTARIS PTY.LTD. AND OTHER METABOSS
002: // CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
003: // BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
004: // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SOFTARIS PTY.LTD.
005: // OR OTHER METABOSS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
006: // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
007: // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
008: // OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
009: // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
010: // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
011: // EVEN IF SOFTARIS PTY.LTD. OR OTHER METABOSS CONTRIBUTORS ARE ADVISED OF THE
012: // POSSIBILITY OF SUCH DAMAGE.
013: //
014: // Copyright 2000-2005 © Softaris Pty.Ltd. All Rights Reserved.
015: package com.metaboss.sdlctools.applications.anttasks.scenariorunner;
016:
017: import java.io.File;
018:
019: import org.apache.tools.ant.BuildException;
020: import org.apache.tools.ant.taskdefs.Java;
021: import org.apache.tools.ant.types.Commandline;
022: import org.apache.tools.ant.types.Environment;
023: import org.apache.tools.ant.types.Path;
024: import org.apache.tools.ant.types.Reference;
025:
026: import com.metaboss.sdlctools.applications.anttasks.MetaBossTask;
027:
028: /** Special Ant task used to run test scenarios.
029: * The source UML Model must conform to UML Profile For MetaBoss Design Model.
030: * This task extends abstract {@link com.metaboss.sdlctools.applications.anttasks.MetaBossTask MetaBossTask}
031: * and therefore suports all of its attributes. In addition it supports the following attributes:
032: * <table border="1" cellpadding="2" cellspacing="0">
033: * <tr>
034: * <th>Attribute Name</th>
035: * <th>Attribute Description</th>
036: * </tr>
037: * <tr>
038: * <td valign="top">scenarioname</td>
039: * <td valign="top">The optional name of the scenario. If this attribute is not present the name will be set to the
040: * 'UnnamedScenario'. This name will appear on the console log and will also form part of the log file name.</td>
041: * </tr>
042: * <tr>
043: * <td valign="top">runname</td>
044: * <td valign="top">The optional name of the scenario run. This name is appended as a suffix to the
045: * scenario name to form full name of the scenario run (This name which appears on the console log and forms the
046: * part of the log file name). Suffix is used to specify additional important feature of the particuar
047: * scenario run. For example scenario 'SearchForClients' can have two runs: 'OnCORBA' and 'OnJ2EE'. If this attribute is not present it is simply omitted.</td>
048: * </tr>
049: * <tr>
050: * <td valign="top">scenariopath</td>
051: * <td valign="top">This mandatory attribute contains list of one or more directories
052: * (accepting : and ; as path separators. relative path names will be interpreted as relative to the project's basedir).
053: * This is where scenario files will be read from. The directories will be read from left to right, but the test case files
054: * in each directory will be picked up and executed in the ascending alphabetical order.</td>
055: * </tr>
056: * <tr>
057: * <td valign="top">includepath</td>
058: * <td valign="top">This optional attribute contains list of zero or more directories
059: * (accepting : and ; as path separators. relative path names will be interpreted as relative to the project's basedir).
060: * This is where include scenario files will be read from. The directories will be searched from the
061: * left to right and the first file with matching name will be included.</td>
062: * </tr>
063: * <tr>
064: * <td valign="top">classpath</td>
065: * <td valign="top">Alternatively to the classpath subelement or classpathref attribute,
066: * the classpath can be specified using this attribute with the single string containing one or more
067: * directories or files (accepting : and ; as path separators. relative path names will be interpreted as relative to the project's basedir).
068: * See the classpath subelement documentation below for more details.</td>
069: * </tr>
070: * <tr>
071: * <td valign="top">classpathref</td>
072: * <td valign="top">Alternatively to the classpath subelement or classpath attribute, the classpath can be specified
073: * using this attribute using path reference id of the path defined elsewhere. See the classpath subelement documentation below for more details.</td>
074: * </tr>
075: * <tr>
076: * <td valign="top">clientclasspathdir</td>
077: * <td valign="top">THis optional attribute must point to the root directory of the client classpath tree. The invocation of every servicemodule
078: * can be done using dedicated classpath. For example when HatMaker.CRM.MarketingQueries servicemodule is invoked
079: * the classpath is build from the following components:
080: * <UL>
081: * <LI>All jarfiles located in the ${clientclasspathdir}/HatMaker.CRM.MarketingQueries directory, if it is present.</LI>
082: * <LI>All jarfiles located in the ${clientclasspathdir} directory, if it is present.</LI>
083: * <LI>All classes defined in the classpath subelements of this element.</LI>
084: * </UL>
085: * Note that this feature is very advanced and is used mainly in the big testing installations where many systems
086: * built on separate technologies are tested toghether.</td>
087: * </tr>
088: * <tr>
089: * <td valign="top">failonerror</td>
090: * <td valign="top">The optional boolean flag which tells scenario runner whether to fail or not
091: * if the test scenario run itself has failed. Default is true, which means the scenario runner will
092: * fail if any of the tests will fail.</td>
093: * </tr>
094: * <tr>
095: * <td valign="top">logperformance</td>
096: * <td valign="top">The optional boolean flag which tells scenario runner whether to log the performance
097: * data or not. Default is true, which means the scenario runner will log performance data.</td>
098: * </tr>
099: * <tr>
100: * <td valign="top">specimenfile</td>
101: * <td valign="top">The optional path and name of the file where the original specimen log should be obtained from.
102: * If this is attrribute is given, the regression analysis will be performed at the end of the test. If this attribute is
103: * not given - the regression analysis will not be performed.</td>
104: * </tr>
105: * <tr>
106: * <td valign="top">rundir</td>
107: * <td valign="top">The optional path and name of the directory where to run the scenario runner from.
108: * If this is attrribute is not given, the project's base directory is used.</td>
109: * </tr>
110: * <tr>
111: * <td valign="top">logdir</td>
112: * <td valign="top">The optional path and name of the directory where the logs should be stored.
113: * If this is attrribute is not given, the directory where scenario runner is running from is used.
114: * This directory will be created if required.</td>
115: * </tr>
116: * </table>
117: * <p>This task also supports following subelements:
118: * <table border="1" cellpadding="2" cellspacing="0">
119: * <tr>
120: * <th>SubElement Name</th>
121: * <th>SubElement Description</th>
122: * </tr>
123: * <tr>
124: * <td valign="top">classpath</td>
125: * <td valign="top">This optional Ant's Path-like element should occur once or not at all. It
126: * defines the classpath of the JVM which executes the ScenarioRunner. The classpath should include all the required
127: * jars apart from the following jars which are always included by default:
128: * <UL>
129: * <LI>MetaBossSystemTester.jar - the scenario runner</LI>
130: * <LI>MetaBossComponentNamingProvider.jar - the jndi component naming provider</LI>
131: * <LI>MetaBossCore.jar - the core framework classes</LI>
132: * <LI>MetaBossEnterprise.jar - the enterprise framework</LI>
133: * <LI>commons-logging-x.x.x.jar and log4j-x.x.x.jar - logging framework</LI>
134: * </UL></td>
135: * </tr>
136: * <tr>
137: * <td valign="top">sysproperty</td>
138: * <td valign="top">This optional Environment variable like element can occur any number of times.
139: * The specified value of the system properties will be passed to the underlying JVM which executes the ScenarioRunner.</td>
140: * </tr>
141: * </table></p>
142: */
143: public class ScenarioRunnerTask extends MetaBossTask {
144: private Java mJavaTask = null;
145: private String mScenarioName = null;
146: private String mRunName = null;
147: private File mSpecimenFile = null;
148: private File mClientClasspathDir = null;
149: private File mRunDir = null;
150: private File mLogDir = null;
151: private Path mClasspath = null;
152: private boolean mFailOnError = true;
153: private boolean mLogPerformance = true;
154: private Path mScenarioPath = null;
155: private Path mIncludePath = null;
156:
157: /** Default constructor */
158: public ScenarioRunnerTask() {
159: }
160:
161: /** Adds a system property */
162: public void addSysproperty(Environment.Variable pSystemProperty) {
163: // Precreate task so we can delegate some atttribute straight to it
164: createJavaTaskIfNecessary();
165: mJavaTask.addSysproperty(pSystemProperty);
166: }
167:
168: /** Adds a system property */
169: public Commandline.Argument createJvmarg() {
170: // Precreate task so we can delegate some atttribute straight to it
171: createJavaTaskIfNecessary();
172: return mJavaTask.createJvmarg();
173: }
174:
175: /** The setter for the optional "classpath" subelement */
176: public Path createClasspath() {
177: if (mClasspath != null)
178: throw new BuildException(
179: "Only one of the 'classpath', 'classpathref' attributes or <classpath> subelement can be present.");
180: mClasspath = new Path(getProject());
181: return mClasspath;
182: }
183:
184: /** The setter for the optional "classpath" attribute */
185: public void setClasspath(Path pClasspath) {
186: if (mClasspath != null)
187: throw new BuildException(
188: "Only one of the 'classpath', 'classpathref' attributes or <classpath> subelement can be present.");
189: mClasspath = pClasspath;
190: }
191:
192: /** The setter for the optional "classpath" attribute */
193: public void setClasspathRef(String pClasspathRef) {
194: if (mClasspath != null)
195: throw new BuildException(
196: "Only one of the 'classpath', 'classpathref' attributes or <classpath> subelement can be present.");
197: mClasspath = new Path(getProject());
198: mClasspath.setRefid(new Reference(pClasspathRef));
199: }
200:
201: /** The getter for the optional "classpath" attribute */
202: public Path getClasspath() {
203: return mClasspath;
204: }
205:
206: /** The setter for the optional "scenarioname" attribute */
207: public void setScenarioName(String pScenarioName) {
208: mScenarioName = pScenarioName;
209: }
210:
211: /** The getter for the optional "scenarioname" attribute */
212: public String getScenarioName() {
213: return mScenarioName;
214: }
215:
216: /** The setter for the optional "runname" attribute */
217: public void setRunName(String pRunName) {
218: mRunName = pRunName;
219: }
220:
221: /** The getter for the optional "runname" attribute */
222: public String getRunName() {
223: return mRunName;
224: }
225:
226: /** The setter for the optional "specimenfile" attribute */
227: public void setSpecimenFile(File pSpecimenFile) {
228: if (pSpecimenFile != null) {
229: if (!pSpecimenFile.isFile())
230: throw new BuildException(
231: "The value of the 'specimenfile' must point to the existing and readable file. The "
232: + pSpecimenFile.getAbsolutePath()
233: + " is not a file.");
234: if (!pSpecimenFile.canRead())
235: throw new BuildException(
236: "The value of the 'specimenfile' must point to the existing and readable file. The "
237: + pSpecimenFile.getAbsolutePath()
238: + " is not readable.");
239: }
240: mSpecimenFile = pSpecimenFile;
241: }
242:
243: /** The getter for the optional "specimenfile" attribute */
244: public File getSpecimenFile() {
245: return mSpecimenFile;
246: }
247:
248: /** The setter for the mandatory "scenariopath" attribute */
249: public void setScenarioPath(Path pScenarioPath) {
250: mScenarioPath = pScenarioPath;
251: }
252:
253: /** The getter for the mandatory "scenariopath" attribute */
254: public Path getScenarioPath() {
255: if (mScenarioPath == null || mScenarioPath.list().length == 0)
256: throw new BuildException(
257: "The 'scenariopath' attribute is mandatory and must contain the path consisting of one or more directories where scenario files are located.");
258: return mScenarioPath;
259: }
260:
261: /** The setter for the mandatory "includepath" attribute */
262: public void setIncludePath(Path pIncludePath) {
263: mIncludePath = pIncludePath;
264: }
265:
266: /** The getter for the mandatory "includepath" attribute */
267: public Path getIncludePath() {
268: return mIncludePath;
269: }
270:
271: /** The setter for the optional "clientclasspathdir" attribute */
272: public void setClientClasspathDir(File pClientClasspathDir) {
273: if (pClientClasspathDir != null) {
274: if (!pClientClasspathDir.isDirectory())
275: throw new BuildException(
276: "The value of the 'clientclasspathdir' must point to the directory. The "
277: + pClientClasspathDir.getAbsolutePath()
278: + " is not a directory.");
279: }
280: mClientClasspathDir = pClientClasspathDir;
281: }
282:
283: /** The getter for the optional "clientclasspathdir" attribute */
284: public File getClientClasspathDir() {
285: return mClientClasspathDir;
286: }
287:
288: /** The setter for the optional "logdir" attribute */
289: public void setLogDir(File pLogDir) {
290: if (pLogDir != null) {
291: if (pLogDir.exists() == true
292: && pLogDir.isDirectory() == false)
293: throw new BuildException(
294: "The value of the 'logdir' must point to the directory. The "
295: + pLogDir.getAbsolutePath()
296: + " is not a directory.");
297: }
298: mLogDir = pLogDir;
299: }
300:
301: /** The getter for the optional "logdir" attribute */
302: public File getLogDir() {
303: return mLogDir;
304: }
305:
306: /** The setter for the optional "rundir" attribute */
307: public void setRunDir(File pRunDir) {
308: if (pRunDir != null) {
309: if (!pRunDir.isDirectory())
310: throw new BuildException(
311: "The value of the 'rundir' must point to the existing directory. The "
312: + pRunDir.getAbsolutePath()
313: + " is not a directory.");
314: if (!pRunDir.exists())
315: throw new BuildException(
316: "The value of the 'rundir' must point to the existing directory. The "
317: + pRunDir.getAbsolutePath()
318: + " does not exist.");
319: }
320: mRunDir = pRunDir;
321: }
322:
323: /** The getter for the optional "rundir" attribute */
324: public File getRunDir() {
325: return mRunDir;
326: }
327:
328: /** The setter for the optional "failonerror" attribute */
329: public void setFailOnError(boolean pFailOnError) {
330: mFailOnError = pFailOnError;
331: }
332:
333: /** The getter for the optional "failonerror" attribute */
334: public boolean getFailOnError() {
335: return mFailOnError;
336: }
337:
338: /** The setter for the optional "logperformance" attribute */
339: public void setLogPerformance(boolean pLogPerformance) {
340: mLogPerformance = pLogPerformance;
341: }
342:
343: /** The getter for the optional "logperformance" attribute */
344: public boolean getLogPerformance() {
345: return mLogPerformance;
346: }
347:
348: // The method actually executing the task.
349: public void execute() throws BuildException {
350: // Now create and execute the java task
351: createJavaTaskIfNecessary();
352: mJavaTask.setTaskName(getTaskName());
353: mJavaTask
354: .setClassname("com.metaboss.sdlctools.applications.systemtester.ScenarioRunner");
355: mJavaTask.setFailonerror(getFailOnError());
356: mJavaTask.setFork(true);
357: mJavaTask.setDir(getRunDir() != null ? getRunDir()
358: : getProject().getBaseDir());
359: // Work on classpath
360: if (getClasspath() != null) {
361: Path lClasspath = mJavaTask.createClasspath();
362: // Add the default classpath
363: lClasspath
364: .addExisting(getPath("TestScenarioRunnerClasspath"));
365: // Add additional classpath specified in the task
366: if (getClasspath() != null)
367: lClasspath.addExisting(getClasspath());
368: }
369: // Work on the sysproperties connecting the xalan transformation processor instead of the default one
370: {
371: {
372: Environment.Variable lTransformerFactoryProperty = new Environment.Variable();
373: lTransformerFactoryProperty
374: .setKey("javax.xml.transform.TransformerFactory");
375: lTransformerFactoryProperty
376: .setValue("org.apache.xalan.xsltc.trax.TransformerFactoryImpl");
377: mJavaTask.addSysproperty(lTransformerFactoryProperty);
378: }
379: {
380: Environment.Variable lEndorsedDirProperty = new Environment.Variable();
381: lEndorsedDirProperty.setKey("java.endorsed.dirs");
382: lEndorsedDirProperty.setValue(getMetaBossHome()
383: .getAbsolutePath()
384: + "/thirdpartylib/xalan-j_2_6_0");
385: mJavaTask.addSysproperty(lEndorsedDirProperty);
386: }
387: }
388:
389: // Work on arguments
390: // - scenario Name
391: if (getScenarioName() != null) {
392: Commandline.Argument lTaskArgument = mJavaTask.createArg();
393: lTaskArgument
394: .setValue("-scenarioName=" + getScenarioName());
395: }
396: // - -scenario Run Name
397: if (getRunName() != null) {
398: Commandline.Argument lTaskArgument = mJavaTask.createArg();
399: lTaskArgument.setValue("-scenarioRunName=" + getRunName());
400: }
401: // - scenario Path
402: {
403: // Ensure that the semicolumns only are used
404: String[] lPathElements = getScenarioPath().list();
405: StringBuffer lBuffer = new StringBuffer();
406: for (int i = 0; i < lPathElements.length; i++) {
407: if (i > 0)
408: lBuffer.append(";");
409: lBuffer.append(lPathElements[i]);
410: }
411: Commandline.Argument lTaskArgument = mJavaTask.createArg();
412: lTaskArgument.setValue("-scenarioPath="
413: + lBuffer.toString());
414: }
415:
416: // - include Path
417: if (getIncludePath() != null) {
418: // Ensure that the semicolumns only are used
419: String[] lPathElements = getIncludePath().list();
420: StringBuffer lBuffer = new StringBuffer();
421: for (int i = 0; i < lPathElements.length; i++) {
422: if (i > 0)
423: lBuffer.append(";");
424: lBuffer.append(lPathElements[i]);
425: }
426: Commandline.Argument lTaskArgument = mJavaTask.createArg();
427: lTaskArgument
428: .setValue("-includePath=" + lBuffer.toString());
429: }
430:
431: // - specimen File
432: if (getSpecimenFile() != null) {
433: Commandline.Argument lTaskArgument = mJavaTask.createArg();
434: lTaskArgument.setValue("-specimenFile="
435: + getSpecimenFile().getAbsolutePath());
436: }
437: // -logging Path
438: {
439: File lLogPath = getLogDir() != null ? getLogDir()
440: : getProject().getBaseDir();
441: Commandline.Argument lTaskArgument = mJavaTask.createArg();
442: lTaskArgument.setValue("-loggingPath="
443: + lLogPath.getAbsolutePath());
444: }
445:
446: // - client Path
447: if (getClientClasspathDir() != null) {
448: Commandline.Argument lTaskArgument = mJavaTask.createArg();
449: lTaskArgument.setValue("-clientPath="
450: + getClientClasspathDir().getAbsolutePath());
451: }
452:
453: // - log Test Performance
454: {
455: Commandline.Argument lTaskArgument = mJavaTask.createArg();
456: lTaskArgument.setValue("-logTestPerformance="
457: + Boolean.toString(getLogPerformance()));
458: }
459:
460: mJavaTask.execute();
461: }
462:
463: // Helper. Ensures that the java task created when it is needed
464: private void createJavaTaskIfNecessary() {
465: if (mJavaTask == null)
466: mJavaTask = (Java) getProject().createTask("java");
467: }
468: }
|