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