1 /*
   2  * $Id$
   3  *
   4  * Copyright (c) 2002, 2012, 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.batch;
  28 
  29 import java.io.PrintWriter;
  30 import java.text.DateFormat;
  31 import java.util.Date;
  32 import java.util.Iterator;
  33 import java.util.ListIterator;
  34 
  35 import com.sun.javatest.Harness;
  36 import com.sun.javatest.Parameters;
  37 import com.sun.javatest.Status;
  38 import com.sun.javatest.TestFinder;
  39 import com.sun.javatest.TestResult;
  40 import com.sun.javatest.tool.Command;
  41 import com.sun.javatest.tool.CommandContext;
  42 import com.sun.javatest.tool.VerboseCommand;
  43 import com.sun.javatest.util.HelpTree;
  44 import com.sun.javatest.util.I18NResourceBundle;
  45 
  46 class RunTestsCommand extends Command
  47 {
  48     static String getName() {
  49         return "runTests";
  50     }
  51 
  52     private static final String DATE_OPTION = "date";
  53     private static final String NON_PASS_OPTION = "non-pass";
  54     private static final String START_OPTION = "start";
  55     private static final String FINISH_OPTION = "stop";
  56     private static final String PROGRESS_OPTION = "progress";
  57 
  58     private Harness harness;
  59 
  60     static void initVerboseOptions() {
  61         VerboseCommand.addOption(DATE_OPTION, new HelpTree.Node(i18n, "runTests.verbose.date"));
  62         VerboseCommand.addOption(NON_PASS_OPTION, new HelpTree.Node(i18n, "runTests.verbose.nonPass"));
  63         VerboseCommand.addOption(START_OPTION, new HelpTree.Node(i18n, "runTests.verbose.start"));
  64         VerboseCommand.addOption(FINISH_OPTION, new HelpTree.Node(i18n, "runTests.verbose.stop"));
  65         VerboseCommand.addOption(PROGRESS_OPTION, new HelpTree.Node(i18n, "runTests.verbose.progress"));
  66     }
  67 
  68     RunTestsCommand() {
  69         super(getName());
  70     }
  71 
  72     RunTestsCommand(ListIterator<String> argIter) {
  73         super(getName());
  74     }
  75 
  76     public boolean isActionCommand() {
  77         return true;
  78     }
  79 
  80     public void run(CommandContext ctx) throws Fault {
  81         this.ctx = ctx;
  82 
  83         try {
  84             Parameters p = getConfig(ctx); // throws fault if not set
  85 
  86             // might want to move harness down into CommandContext
  87             // to share with GUI
  88             Harness h = new Harness();
  89             harness = h;
  90 
  91             Harness.Observer[] observers = ctx.getHarnessObservers();
  92             for (int i = 0; i < observers.length; i++)
  93                 h.addObserver(observers[i]);
  94 
  95             // should really merge VerboseObserver and BatchObserver
  96             VerboseObserver vo = new VerboseObserver(ctx);
  97             h.addObserver(vo);
  98 
  99             BatchObserver bo = new BatchObserver();
 100             h.addObserver(bo);
 101             p.getTestSuite().getTestFinder().setErrorHandler(bo);
 102 
 103             boolean ok = h.batch(p);
 104 
 105             if (bo.getFinderErrorCount() > 0) {
 106                 // other problems during run
 107                 ctx.printErrorMessage(i18n, "runTests.warnError");
 108             }
 109 
 110             if (!ctx.isVerboseQuiet()) {
 111                 long tt = h.getElapsedTime();
 112                 long setupT = h.getTotalSetupTime();
 113                 long cleanupT = h.getTotalCleanupTime();
 114                 ctx.printMessage(i18n, "runTests.totalTime", tt/1000L);
 115                 ctx.printMessage(i18n, "runTests.setupTime", setupT/1000L);
 116                 ctx.printMessage(i18n, "runTests.cleanupTime", cleanupT/1000L);
 117 
 118                 showResultStats(bo.getStats());
 119             }
 120 
 121 
 122             int testsFound = h.getTestsFoundCount();
 123 
 124             if (testsFound > 0 && !ctx.isVerboseQuiet())
 125                 ctx.printMessage(i18n, "runTests.resultsDone", p.getWorkDirectory().getPath());
 126             int[] stats = bo.getStats();
 127 
 128             if (!ok) {
 129                 if (testsFound > 0 &&
 130                     testsFound != stats[Status.PASSED]) {
 131                     // some tests are actually not passed, print
 132                     // appropriate message
 133                     ctx.printErrorMessage(i18n, "runTests.testsFailed");
 134                 }
 135             }
 136 
 137             ctx.addTestStats(stats);
 138         }
 139         catch (Harness.Fault e) {
 140             throw new Fault(i18n, "runTests.harnessError", e.getMessage());
 141         }
 142         catch (InterruptedException e) {
 143             throw new Fault(i18n, "runTests.interrupted");
 144         }
 145     }
 146 
 147     private void showResultStats(int[] stats) {
 148         int p = stats[Status.PASSED];
 149         int f = stats[Status.FAILED];
 150         int e = stats[Status.ERROR];
 151         int nr = stats[Status.NOT_RUN] =
 152             harness.getTestsFoundCount() - p - f - e;
 153 
 154 
 155         if (p + f + e + nr == 0)
 156             ctx.printMessage(i18n, "runTests.noTests");
 157         else {
 158             ctx.printMessage(i18n, "runTests.tests",
 159                       new Object[] {
 160                           new Integer(p),
 161                           new Integer((p > 0) && (f + e + nr > 0) ? 1 : 0),
 162                           new Integer(f),
 163                           new Integer((f > 0) && (e + nr > 0) ? 1 : 0),
 164                           new Integer(e),
 165                           new Integer((e > 0) && (nr > 0) ? 1 : 0),
 166                           new Integer(nr)
 167                               });
 168         }
 169     }
 170 
 171     //-------------------------------------------------------------------------
 172 
 173     private CommandContext ctx;
 174 
 175     private static I18NResourceBundle i18n = I18NResourceBundle.getBundleForClass(RunTestsCommand.class);
 176 
 177     //-------------------------------------------------------------------------
 178 
 179     private class BatchObserver
 180         implements Harness.Observer, TestFinder.ErrorHandler {
 181 
 182         int[] getStats() {
 183             return stats;
 184         }
 185 
 186         int getFinderErrorCount() {
 187             return finderErrors;
 188         }
 189 
 190         public void startingTestRun(Parameters params) {
 191             stats = new int[Status.NUM_STATES];
 192         }
 193 
 194         public void startingTest(TestResult tr) { }
 195 
 196         public void finishedTest(TestResult tr) {
 197             stats[tr.getStatus().getType()]++;
 198         }
 199 
 200         public void stoppingTestRun() { }
 201 
 202         public void finishedTesting() { }
 203         public void finishedTestRun(boolean allOK) { }
 204 
 205         public void error(String msg) {
 206             ctx.printMessage(i18n, "runTests.error", msg);
 207             finderErrors++;
 208         }
 209 
 210         private int[] stats;
 211         private int finderErrors;
 212     }
 213 
 214     private class VerboseObserver implements Harness.Observer
 215     {
 216         VerboseObserver(CommandContext ctx) {
 217             this.ctx = ctx;
 218             this.out = ctx.getLogWriter();
 219 
 220             quiet_flag = ctx.isVerboseQuiet();
 221             df = DateFormat.getDateTimeInstance(DateFormat.MEDIUM,
 222                                                 DateFormat.MEDIUM);
 223             ctx.addHarnessObserver(this);
 224 
 225             boolean defaultFlag = ctx.getVerboseOptionValue("default", false);
 226             options = new boolean[OPTION_COUNT];
 227             options[NO_DATE] = !ctx.isVerboseTimestampEnabled();
 228             options[NON_PASS] = ctx.getVerboseOptionValue(NON_PASS_OPTION, false);
 229             options[START] = ctx.getVerboseOptionValue(START_OPTION, false);
 230             options[FINISH] = ctx.getVerboseOptionValue(FINISH_OPTION, false);
 231             options[PROGRESS] = ctx.getVerboseOptionValue(PROGRESS_OPTION, defaultFlag);
 232         }
 233 
 234         public boolean isVerbose(int kind) {
 235             if (quiet_flag)
 236                 return false;
 237 
 238             if (max_flag)
 239                 return true;
 240 
 241             if (kind < OPTION_COUNT)
 242                 return options[kind];
 243             else
 244                 return false;
 245         }
 246 
 247         private void printTimestamp() {
 248             if (quiet_flag || options[NO_DATE])
 249                 return;
 250 
 251             out.print(df.format(new Date()));
 252             out.print(" ");
 253         }
 254 
 255         // ---- Harness.Observer ----
 256         public void startingTestRun(Parameters params) {
 257             stats = new int[Status.NUM_STATES];
 258 
 259             if (!quiet_flag) {
 260                 if (progressOnline)
 261                     out.println();
 262                 printTimestamp();
 263                 ctx.printMessage(i18n, "cmgr.verb.strt",
 264                     params.getEnv().getName());
 265                 out.flush();
 266                 progressOnline = false;
 267             }
 268         }
 269 
 270         public void startingTest(TestResult tr) {
 271             if (!isVerbose(START))
 272                 return;
 273 
 274             if (progressOnline)
 275                 out.println();
 276 
 277             printTimestamp();
 278             ctx.printMessage(i18n, "cmgr.verb.tsts", tr.getTestName());
 279             out.flush();
 280 
 281             progressOnline = false;
 282         }
 283 
 284         public void finishedTest(TestResult tr) {
 285             Status s = tr.getStatus();
 286             stats[s.getType()]++;
 287 
 288             switch(s.getType()) {
 289                 case Status.FAILED:
 290                 case Status.ERROR:
 291                     if (isVerbose(NON_PASS) || isVerbose(FINISH)) {
 292                         printFinish(s, tr);
 293                         progressOnline = false;
 294                     }
 295                     break;
 296                 default:
 297                     if (isVerbose(FINISH)) {
 298                         printFinish(s, tr);
 299                         progressOnline = false;
 300                     }
 301             }   // switch
 302 
 303             printStats();
 304             out.flush();
 305         }
 306 
 307         public void stoppingTestRun() {
 308             if (progressOnline)
 309                 out.println();
 310 
 311             printTimestamp();
 312             ctx.printMessage(i18n, "cmgr.verb.stpng");
 313             out.flush();
 314 
 315             progressOnline = false;
 316         }
 317 
 318         public void finishedTesting() {
 319             if (!quiet_flag) {
 320                 if (progressOnline)
 321                     out.println();
 322 
 323                 printTimestamp();
 324                 ctx.printMessage(i18n, "cmgr.verb.donerun");
 325                 out.flush();
 326 
 327                 progressOnline = false;
 328             }
 329         }
 330 
 331         public void finishedTestRun(boolean allOK) {
 332             if (!quiet_flag) {
 333                 if (progressOnline)
 334                     out.println();
 335 
 336                 printTimestamp();
 337                 ctx.printMessage(i18n, "cmgr.verb.finish");
 338                 out.flush();
 339 
 340                 progressOnline = false;
 341             }
 342         }
 343 
 344         public void error(String msg) {
 345             if (progressOnline)
 346                 out.println();
 347 
 348             printTimestamp();
 349             ctx.printErrorMessage(i18n, "cmgr.verb.err", msg);
 350             out.flush();
 351 
 352             progressOnline = false;
 353         }
 354 
 355         // utility methods
 356         private void printStats() {
 357             if (!isVerbose(PROGRESS))
 358                 return;
 359 
 360             if (progressOnline)
 361                 out.print("\r");
 362 
 363             int p = stats[Status.PASSED];
 364             int f = stats[Status.FAILED];
 365             int e = stats[Status.ERROR];
 366             int nr = stats[Status.NOT_RUN] =
 367                 harness.getTestsFoundCount() - p - f - e;
 368 
 369             out.print(i18n.getString("cmgr.verb.prog",
 370                       new Object[] {
 371                           new Integer(p),
 372                           new Integer(f),
 373                           new Integer(e),
 374                           new Integer(nr)
 375                       }));
 376             out.print("    ");
 377 
 378             progressOnline = true;
 379         }
 380 
 381         private void printFinish(Status s, TestResult tr) {
 382             if (!quiet_flag) {
 383                 // need to create newline if we are doing single-line
 384                 // updates
 385                 if (progressOnline)
 386                     out.println();
 387 
 388                 printTimestamp();
 389                 String[] args = {tr.getTestName(),
 390                                  s.toString()};
 391                 ctx.printMessage(i18n, "cmgr.verb.tstd", args);
 392                 out.flush();
 393                 progressOnline = false;
 394             }
 395         }
 396 
 397         /**
 398          * Is the text being displayed using println during the run?
 399          * This affects our ability to update a progress counter.
 400          */
 401         private boolean isScolling() {
 402             if (!isVerbose(START) && !isVerbose(FINISH))
 403                 return false;
 404             else
 405                 return true;
 406         }
 407 
 408         private boolean[] options;
 409         private boolean quiet_flag = false;
 410         private boolean max_flag = false;
 411         private DateFormat df;
 412         private CommandContext ctx;
 413         private PrintWriter out;
 414         private int[] stats;
 415         private boolean progressOnline = false;
 416 
 417         public static final int NO_DATE = 0;
 418         public static final int NON_PASS = 1;
 419         public static final int START = 2;
 420         public static final int FINISH = 3;
 421         public static final int PROGRESS = 4;
 422 
 423         public static final int DEFAULT = PROGRESS;
 424 
 425         private static final int OPTION_COUNT = 5;
 426     }
 427 }