1 /*
   2  * $Id$
   3  *
   4  * Copyright (c) 2001, 2009, Oracle and/or its affiliates. All rights reserved.
   5  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   6  *
   7  * This code is free software; you can redistribute it and/or modify it
   8  * under the terms of the GNU General Public License version 2 only, as
   9  * published by the Free Software Foundation.  Oracle designates this
  10  * particular file as subject to the "Classpath" exception as provided
  11  * by Oracle in the LICENSE file that accompanied this code.
  12  *
  13  * This code is distributed in the hope that it will be useful, but WITHOUT
  14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  15  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  16  * version 2 for more details (a copy is included in the LICENSE file that
  17  * accompanied this code).
  18  *
  19  * You should have received a copy of the GNU General Public License version
  20  * 2 along with this work; if not, write to the Free Software Foundation,
  21  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  22  *
  23  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  24  * or visit www.oracle.com if you need additional information or have any
  25  * questions.
  26  */
  27 package com.sun.javatest;
  28 
  29 import java.io.*;
  30 import java.nio.charset.StandardCharsets;
  31 import java.util.Iterator;
  32 
  33 import com.sun.javatest.util.I18NResourceBundle;
  34 import com.sun.javatest.util.Properties;
  35 import com.sun.javatest.util.StringArray;
  36 
  37 /**
  38  * An implementation of Parameters, using data read from a .jtp file.
  39  */
  40 public class FileParameters
  41     extends
  42         BasicParameters
  43     implements
  44         Parameters.LegacyEnvParameters
  45 {
  46     /**
  47      * Determine if the specified file is a parameter file,
  48      * as determined by whether its extension is .jtp or not.
  49      * @param file the file to be checked
  50      * @return true if the specified file is a parameter file,
  51      * and false otherwise
  52      */
  53     public static boolean isParameterFile(File file) {
  54         return file.getPath().endsWith(PARAMFILE_EXTN);
  55     }
  56 
  57     /**
  58      * Create an empty FileParameters object.
  59      */
  60     public FileParameters() {
  61     }
  62 
  63     /**
  64      * Create a FileParameters object, based on data read from a parameter file.
  65      * @param file the file to be read to initialize this object
  66      * @throws FileNotFoundException if the file does not exist
  67      * @throws IOException if there is a problem reading the file
  68      */
  69     public FileParameters(File file)
  70         throws FileNotFoundException, IOException
  71     {
  72         Properties p = new Properties();
  73         Reader in = new BufferedReader(new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8));
  74         p.load(in);
  75         in.close();
  76 
  77         setTestSuite(adjustPath(p.getProperty("javasoft.sqe.javatest.selection.testSuite")));
  78         setWorkDirectory(p.getProperty("javasoft.sqe.javatest.results.workDir"));
  79         setTests(p.getProperty("javasoft.sqe.javatest.selection.tests"));
  80         setExcludeFiles(p.getProperty("javasoft.sqe.javatest.selection.excludeList"));
  81         String keywordOp = p.getProperty("javasoft.sqe.javatest.selection.keywordOp");
  82         String keywords = p.getProperty("javasoft.sqe.javatest.selection.keywords");
  83         setKeywords(keywordOp, keywords);
  84         String statusOp = p.getProperty("javasoft.sqe.javatest.selection.status");
  85         String[] statusTests = new String[Status.NUM_STATES];
  86         statusTests[Status.PASSED] = p.getProperty("javasoft.sqe.javatest.selection.prev.passed");
  87         statusTests[Status.FAILED] = p.getProperty("javasoft.sqe.javatest.selection.prev.failed");
  88         statusTests[Status.ERROR] = p.getProperty("javasoft.sqe.javatest.selection.prev.error");
  89         statusTests[Status.NOT_RUN] = p.getProperty("javasoft.sqe.javatest.selection.prev.notRun");
  90         setPriorStatusValues(statusOp, statusTests);
  91         setEnvFiles(p.getProperty("javasoft.sqe.javatest.execution.envFiles"));
  92         setEnvName(p.getProperty("javasoft.sqe.javatest.execution.environment"));
  93         setConcurrency(p.getProperty("javasoft.sqe.javatest.execution.concurrency"));
  94         setTimeoutFactor(p.getProperty("javasoft.sqe.javatest.execution.timeFactor"));
  95         setReportDir(p.getProperty("javasoft.sqe.javatest.results.reportDir"));
  96     }
  97 
  98     /**
  99      * Create a FileParameters object, based on command-line-like args.
 100      * The args that are accepted are:
 101      * <dl>
 102      * <dt><code>-t</code> <i>testsuite</i><br><code>-testsuite</code> <i>testsuite</i>
 103      * <dd>Specify the test suite
 104      * <dt><code>-keywords</code> <i>expr</i>
 105      * <dd>Specify a keyword expression, used to filter the tests to be run.
 106      * <dt><code>-status</code> <i>status-list</i>
 107      * <dd>Specify the status values used to select tests at runtime.
 108      * <i>status-list</i> should be a comma-separated list of words from
 109      * the following list:
 110      *    <code>passed</code>,
 111      *    <code>failed</code>,
 112      *    <code>error</code>,
 113      *    <code>notRun</code>
 114      * <dt><code>-exclude</code> <i>exclude-list-file</i>
 115      * <dd>Specify an exclude-list file containing a list of tests to
 116      * be excluded from the test run.
 117      * The option can be specified more than once, with different files.
 118      * <dt><code>-envFile</code> <i>environment-file</i>
 119      * <dd>Specify an environment file, containing environment entries
 120      * providing details on how to run tests.
 121      * The option can be specified more than once, with different files.
 122      * <dt><code>-env</code> <i>environment-name</i>
 123      * <dd>Specify the name of the environment to be used from the
 124      * set of environment files.
 125      * <dt><code>-concurrency</code> <i>number</i>
 126      * <dd>Specify how many tests JT Harness may run at once. The default
 127      * is 1.
 128      * <dt><code>-timeoutFactor</code> <i>number</i>
 129      * <dd>Specify a scale factor to be used to multiply the timeout
 130      * value for each test, to allow for running on slow CPUs.
 131      * <dt><code>-report</code> <i>report-dir</i><br><code>-r</code> <i>report-dir</i>
 132      * <dd>Specify a directory in which to write reports at the end of the test run.
 133      * <dt><code>-workDir</code> <i>work-dir</i><br><code>-w</code> <i>work-dir</i>
 134      * <dd>Specify a directory in which to write the results of the individual tests.
 135      * <dt><i>initial-files</i>
 136      * <dd>Trailing file arguments are treated as initial files, used to select
 137      * which parts of the test suite should be run.
 138      * </dl>
 139      * The test suite, work directory and report directory are evaluated
 140      * relative to the user's current directory, unless the location specified
 141      * is an absolute path.  The exclude list and environment files are located
 142      * relative to the test suite location, unless they are absolute paths.
 143      * @param args The args used to initialize the FileParameters object.
 144      * @throws IllegalArgumentException If an unrecognized argument is found.
 145      */
 146     public FileParameters(String[] args) {
 147         String testSuiteArg = null;
 148         String workDirArg = null;
 149         String testsArgs = null;
 150         String exclFilesArgs = null;
 151         String keywordsExprArg = null;
 152         String priorStatusValuesArg = null;
 153         String envFilesArgs = null;
 154         String envNameArg = null;
 155         String concurrencyArg = null;
 156         String timeoutFactorArg = null;
 157         String reportDirArg = null;
 158 
 159         for (int i = 0; i < args.length; i++) {
 160             if ("-testSuite".equalsIgnoreCase(args[i]) || "-t".equalsIgnoreCase(args[i]))
 161                 testSuiteArg = args[++i];
 162             else if ("-keywords".equalsIgnoreCase(args[i]))
 163                 keywordsExprArg = args[++i];
 164             else if ("-status".equalsIgnoreCase(args[i]))
 165                 priorStatusValuesArg = args[++i].toLowerCase();
 166             else if ("-exclude".equalsIgnoreCase(args[i])) {
 167                 if (exclFilesArgs == null)
 168                     exclFilesArgs = args[++i];
 169                 else
 170                     exclFilesArgs += " " + args[++i];
 171             }
 172             else if ("-envFile".equalsIgnoreCase(args[i])) {
 173                 if (envFilesArgs == null)
 174                     envFilesArgs = args[++i];
 175                 else
 176                     envFilesArgs += " " + args[++i];
 177             }
 178             else if ("-env".equalsIgnoreCase(args[i]))
 179                 envNameArg = args[++i];
 180             else if ("-concurrency".equalsIgnoreCase(args[i]))
 181                 concurrencyArg = args[++i];
 182             else if ("-timeoutFactor".equalsIgnoreCase(args[i]))
 183                 timeoutFactorArg = args[++i];
 184             else if ("-report".equalsIgnoreCase(args[i]) || "-r".equalsIgnoreCase(args[i]))
 185                 reportDirArg = args[++i];
 186             else if ("-workDir".equalsIgnoreCase(args[i]) || "-w".equalsIgnoreCase(args[i]))
 187                 workDirArg = args[++i];
 188             else if (args[i].startsWith("-"))
 189                 throw new IllegalArgumentException(args[i]);
 190             else {
 191                 String[] tests = new String[args.length - i];
 192                 System.arraycopy(args, i, tests, 0, tests.length);
 193                 testsArgs = StringArray.join(tests);
 194                 i = args.length;
 195             }
 196         }
 197 
 198         setTestSuite(adjustPath(testSuiteArg));
 199         setWorkDirectory(adjustPath(workDirArg));
 200         setTests(testsArgs);
 201         setExcludeFiles(exclFilesArgs);
 202         setKeywords("expr", keywordsExprArg);
 203         setPriorStatusValues(priorStatusValuesArg);
 204         setEnvFiles(envFilesArgs);
 205         setEnvName(envNameArg);
 206         setConcurrency(concurrencyArg);
 207         setTimeoutFactor(timeoutFactorArg);
 208         setReportDir(adjustPath(reportDirArg));
 209     }
 210 
 211     //---------------------------------------------------------------------
 212 
 213     public Parameters.EnvParameters getEnvParameters() {
 214         return this;
 215     }
 216 
 217     public File[] getEnvFiles() {
 218         return envFiles;
 219     }
 220 
 221     public File[] getAbsoluteEnvFiles() {
 222         updateAbsoluteEnvFiles();
 223         return cachedAbsEnvFiles;
 224     }
 225 
 226     public void setEnvFiles(File[] files) {
 227         envFiles = files;
 228     }
 229 
 230     private void setEnvFiles(String files) {
 231         String[] f = StringArray.split(files);
 232         File[] ff = new File[f.length];
 233 
 234         // legacy behavior requires that paths be relative to the testSuite
 235         // location specified in the JTE or on the cmd line
 236         for (int i = 0; i < ff.length; i++)  {
 237             ff[i] = new File(makeLegacyTsRelative(f[i]));
 238         }
 239         setEnvFiles(ff);
 240     }
 241 
 242     public String getEnvName() {
 243         return envName;
 244     }
 245 
 246     public void setEnvName(String name) {
 247         envName = name;
 248     }
 249 
 250     /**
 251      * Get an object containing the environments read from the environment files.
 252      * @return an object containing all the environments read from the environment files.
 253      * @see #setEnvFiles
 254      * @see #setEnvName
 255      */
 256     public TestEnvContext getEnvTable() {
 257         updateEnvTable();
 258         return cachedEnvTable;
 259     }
 260 
 261     public TestEnvironment getEnv() {
 262         updateEnv();
 263         return cachedEnv;
 264     }
 265 
 266     private void updateAbsoluteEnvFiles() {
 267         TestSuite ts = getTestSuite();
 268         File base = (ts == null ? null : ts.getRootDir());
 269         if (cachedAbsEnvFiles == null ||
 270             cachedAbsEnvFiles_base != base ||
 271             cachedAbsEnvFiles_envFiles != envFiles) {
 272             cachedAbsEnvFiles = getAbsoluteFiles(base, envFiles);
 273         }
 274     }
 275 
 276     private void updateEnvTable() {
 277         updateAbsoluteEnvFiles();
 278         File[] absEnvFiles = cachedAbsEnvFiles;
 279         if (cachedEnvTable == null
 280            || !equal(absEnvFiles, cachedEnvTable_absEnvFiles)) {
 281             try {
 282                 cachedEnvTable = new TestEnvContext(absEnvFiles);
 283                 cachedEnvTable_absEnvFiles = absEnvFiles;
 284                 envTableError = null;
 285             }
 286             catch (TestEnvContext.Fault e) {
 287                 cachedEnvTable = null;
 288                 envTableError = e.getMessage();
 289             }
 290         }
 291     }
 292 
 293     private void updateEnv() {
 294         TestEnvContext envTable = getEnvTable();
 295         if (envTable == null) {
 296             cachedEnv = null;
 297             envError = i18n.getString("fp.noEnvs", envName);
 298             return;
 299         }
 300 
 301         TestEnvironment env;
 302         try {
 303             if (envName == null)
 304                 envName = "";
 305             env = envTable.getEnv(envName);
 306             if (env == null) {
 307                 // note envName==null is always a valid environment
 308                 cachedEnv = null;
 309                 envError = i18n.getString("fp.envNotFound", envName);
 310                 return;
 311             }
 312             for (Iterator i = env.elements().iterator(); i.hasNext(); ) {
 313                 TestEnvironment.Element entry = (TestEnvironment.Element) (i.next());
 314                 if (entry.value.indexOf("VALUE_NOT_DEFINED") >= 0) {
 315                     String eText =
 316                         ( (entry.definedInEnv == null ? "" : "env." +  entry.definedInEnv + ".") +
 317                           entry.key + "=" + entry.value);
 318                     cachedEnv = null;
 319                     envError = i18n.getString("fp.undefinedEntry",
 320                                        new Object[] {eText, entry.definedInFile});
 321                     return;
 322                 }
 323             }
 324         }
 325         catch (TestEnvironment.Fault e) {
 326             cachedEnv = null;
 327             envError = i18n.getString("fp.badEnv", new Object[] {envName, e.getMessage()});
 328             return;
 329         }
 330         cachedEnv = env;
 331         envError = null;
 332     }
 333 
 334     private boolean isEnvOK() {
 335         updateEnv();
 336         return (envTableError == null && envError == null);
 337     }
 338 
 339     private File[] envFiles;
 340     private File[] cachedAbsEnvFiles;
 341     private File cachedAbsEnvFiles_base;
 342     private File[] cachedAbsEnvFiles_envFiles;
 343     private String envName;
 344 
 345     private TestEnvContext cachedEnvTable;
 346     private File[] cachedEnvTable_absEnvFiles;
 347     private String envTableError;
 348 
 349     private TestEnvironment cachedEnv;
 350     private TestEnvContext cachedEnv_envTable;
 351     private String cachedEnv_envName;
 352     private String envError;
 353 
 354     //---------------------------------------------------------------------
 355 
 356     public boolean isValid() {
 357         return ( super.isValid() && isEnvOK() );
 358     }
 359 
 360     public String getErrorMessage() {
 361         String basicError = super.getErrorMessage();
 362         return (basicError != null ? basicError
 363                 : envTableError != null ? envTableError
 364                 : null);
 365     }
 366 
 367     //---------------------------------------------------------------------
 368 
 369     private void setTestSuite(String path) {
 370         legacyTsPath = path;
 371         File p = (path == null ? null : new File(path));
 372 
 373         // we assume that the path has already be made non-relative
 374         // i.e. absolute
 375         if (p != null && p.isFile())
 376             legacyTsPath = p.getParent();
 377 
 378         // this strange arrangement of checks is here because we
 379         // are trying to ensure that users playing around with legacy
 380         // configurations get reasonable results
 381         if (p == null || TestSuite.isTestSuite(p)) {
 382             setTestSuite(p);
 383         }
 384         else {
 385             File parent = p.getParentFile();
 386             // fallback check, check parent of specified location
 387             if (parent != null && TestSuite.isTestSuite(parent)) {
 388                 setTestSuite(parent);
 389             }
 390             else {
 391                 // must do this to ensure proper errors occur
 392                 setTestSuite(p);
 393             }
 394         }
 395     }
 396 
 397     //---------------------------------------------------------------------
 398 
 399     private void setWorkDirectory(String path) {
 400         setWorkDirectory(path == null ? null : new File(path));
 401     }
 402 
 403     //---------------------------------------------------------------------
 404 
 405     private void setTests(String tests) {
 406         setTests(StringArray.split(tests));
 407     }
 408 
 409     //---------------------------------------------------------------------
 410 
 411     private void setExcludeFiles(String files) {
 412         String[] f = StringArray.split(files);
 413         File[] ff = new File[f.length];
 414 
 415         // legacy behavior requires that paths be relative to the testSuite
 416         // location specified in the JTE or on the cmd line
 417         for (int i = 0; i < ff.length; i++)  {
 418             ff[i] = new File(makeLegacyTsRelative(f[i]));
 419         }
 420         setExcludeFiles(ff);
 421     }
 422 
 423     //---------------------------------------------------------------------
 424 
 425     private void setKeywords(String op, String value) {
 426         if (op == null || op.equals("ignore") )
 427             setKeywordsMode(NO_KEYWORDS);
 428         else if (op.equals("expr"))
 429             setKeywords(EXPR, value);
 430         else if (op.equals("allOf"))
 431             setKeywords(ALL_OF, value);
 432         else if (op.equals("anyOf"))
 433             setKeywords(ANY_OF, value);
 434         else
 435             setKeywordsMode(NO_KEYWORDS);
 436     }
 437 
 438     //---------------------------------------------------------------------
 439 
 440     private void setPriorStatusValues(String op, String[] values) {
 441         if (op == null || !op.equals("allOf"))
 442             setPriorStatusValues((boolean[]) null);
 443         else {
 444             boolean[] b = new boolean[Status.NUM_STATES];
 445             for (int i = 0; i < values.length; i++)
 446                 b[i] = "true".equals(values[i]);
 447             setPriorStatusValues(b);
 448         }
 449     }
 450 
 451     private void setPriorStatusValues(String values) {
 452         if (values == null || values.length() == 0)
 453             setPriorStatusValues((boolean[]) null);
 454         else {
 455             boolean[] b = new boolean[Status.NUM_STATES];
 456             b[Status.PASSED]  = (values.indexOf("pass") != -1);
 457             b[Status.FAILED]  = (values.indexOf("fail") != -1);
 458             b[Status.ERROR]   = (values.indexOf("erro") != -1);
 459             b[Status.NOT_RUN] = (values.indexOf("notr") != -1);
 460             setPriorStatusValues(b);
 461         }
 462     }
 463 
 464     //---------------------------------------------------------------------
 465 
 466     private void setConcurrency(String conc) {
 467         if (conc == null)
 468             setConcurrency(1);
 469         else {
 470             try {
 471                 setConcurrency(Integer.parseInt(conc));
 472             }
 473             catch (NumberFormatException e) {
 474                 concurrencyError = i18n.getString("fp.badConcurrency", conc);
 475             }
 476         }
 477     }
 478 
 479     //---------------------------------------------------------------------
 480 
 481     private void setTimeoutFactor(String tf) {
 482         if (tf == null)
 483             setTimeoutFactor(1);
 484         else {
 485             try {
 486                 setTimeoutFactor(Float.parseFloat(tf));
 487             }
 488             catch (NumberFormatException e) {
 489                 timeoutFactorError = i18n.getString("fp.badTimeoutFactor", tf);
 490             }
 491         }
 492     }
 493 
 494     //---------------------------------------------------------------------
 495 
 496     /**
 497      * Get the report directory given in the parameters.
 498      * @return the report directory
 499      * @see #setReportDir
 500      */
 501     public File getReportDir() {
 502         return reportDir;
 503     }
 504 
 505     /**
 506      * Set the report directory.
 507      * @param dir the report directory
 508      * @see #getReportDir
 509      */
 510     public void setReportDir(File dir) {
 511         // check report dir exists?
 512         reportDir = dir;
 513     }
 514 
 515     private void setReportDir(String dir) {
 516         if (dir == null)
 517             setReportDir((File) (null));
 518         else
 519             setReportDir(new File(dir));
 520     }
 521 
 522     private File reportDir;
 523 
 524     //---------------------------------------------------------------------
 525 
 526     /**
 527      * Makes the given path relative to the user's CWD if it is a
 528      * relative value.  So "tests" may be turned into
 529      * <code>/home/me/mytck/tests</code>.
 530      */
 531     private String adjustPath(String path) {
 532         if (path == null)
 533             return path;
 534 
 535         File p = new File(path);
 536         if (p.isAbsolute())
 537             return path;
 538         else {
 539             String userDir = System.getProperty("user.dir");
 540             if (userDir == null)
 541                 return path;
 542             else
 543                 return userDir + File.separator + path;
 544         }
 545     }
 546 
 547     private String makeLegacyTsRelative(String path) {
 548         if (path == null)
 549             return path;
 550 
 551         File p = new File(path);
 552         if (p.isAbsolute())
 553             return path;
 554         else {
 555             if (legacyTsPath == null)
 556                 return path;
 557             else
 558                 return legacyTsPath + File.separator + path;
 559         }
 560     }
 561 
 562     private String legacyTsPath;        // always a directory
 563     private static final String PARAMFILE_EXTN = ".jtp";
 564 
 565     private static final I18NResourceBundle i18n =
 566         I18NResourceBundle.getBundleForClass(FileParameters.class);
 567 }