1 /* 2 * $Id$ 3 * 4 * Copyright (c) 1996, 2016, 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.File; 30 import java.io.IOException; 31 import java.util.*; 32 33 import com.sun.javatest.TestResultTable.TreeIterator; 34 import com.sun.javatest.httpd.HttpdServer; 35 import com.sun.javatest.httpd.RootRegistry; 36 import com.sun.javatest.util.BackupPolicy; 37 import com.sun.javatest.util.DynamicArray; 38 import com.sun.javatest.util.I18NResourceBundle; 39 import com.sun.javatest.util.ReadAheadIterator; 40 41 /** 42 * The object responsible for coordinating the execution of a test run. 43 */ 44 public class Harness 45 { 46 /** 47 * This exception is used to report problems while executing a test run. 48 */ 49 public static class Fault extends Exception 50 { 51 Fault(I18NResourceBundle i18n, String s) { 52 super(i18n.getString(s)); 53 } 54 55 Fault(I18NResourceBundle i18n, String s, Throwable cause) { 56 super(i18n.getString(s), cause); 57 } 58 59 Fault(I18NResourceBundle i18n, String s, Object o) { 60 super(i18n.getString(s, o)); 61 } 62 63 Fault(I18NResourceBundle i18n, String s, Object[] o) { 64 super(i18n.getString(s, o)); 65 } 66 } 67 68 /** 69 * This interface provides a means for Harness to report 70 * on events that might be of interest as it executes. 71 */ 72 public interface Observer 73 { 74 /** 75 * The harness is beginning to execute tests. 76 * @param params the parameters for the test run 77 */ 78 void startingTestRun(Parameters params); 79 80 /** 81 * The harness is about to run the given test. 82 * 83 * @param tr The test result which is going to receive the data 84 * from the current execution of that test. 85 */ 86 void startingTest(TestResult tr); 87 88 /** 89 * The harness has finished running the given test. 90 * This message is sent without respect to the resulting test's 91 * completion status (pass, fail, etc...). 92 * 93 * @param tr The result object containing the results from the 94 * execution which was just completed. 95 */ 96 void finishedTest(TestResult tr); 97 98 /** 99 * The harness is about to stop a test run, before it has finished 100 * executing all the specified tests. The method is not notified if 101 * the test run completes normally, after executing all the specified 102 * tests. 103 */ 104 void stoppingTestRun(); 105 106 /** 107 * The harness has finished running tests and is doing other activities 108 * (writing the report, updating caches, etc...). This message will 109 * be broadcast both when error conditions terminate the run or when 110 * a test completes normally. It may provide a reasonable opportunity 111 * for a client to clean up any resources that were used during the test 112 * run, before a new run is started. 113 */ 114 void finishedTesting(); 115 116 /** 117 * The test run has been completed, either because the user requested 118 * that the harness stop, the harness decided to terminate the test run, 119 * or all requested tests have been run. The harness is now ready to 120 * perform another test run. Note that since the actions of other observers 121 * are undefined, a new test run may have already been started by the time 122 * this method is called for any specific observer. 123 * 124 * @param allOK True if all tests passed, false otherwise. 125 */ 126 void finishedTestRun(boolean allOK); 127 128 /** 129 * The given error occurred. 130 * 131 * @param msg A description of the error event. 132 */ 133 void error(String msg); 134 } 135 136 137 /** 138 * Instantiate a harness. 139 * @param classDir The class dir to put in the environment for otherJVM tests 140 * @deprecated Use Harness() instead 141 * @see #Harness() 142 * @see #setClassDir 143 */ 144 public Harness(File classDir) { 145 this(); 146 setClassDir(classDir); 147 } 148 149 /** 150 * Instantiate a harness. 151 */ 152 public Harness() { 153 backupPolicy = BackupPolicy.noBackups(); 154 155 params = null; 156 157 if (!Boolean.getBoolean("javatest.noTraceRequired")) { 158 trace = new Trace(backupPolicy); 159 addObserver(trace); 160 } 161 162 // web server 163 if (HttpdServer.isActive()) { 164 httpHandler = new HarnessHttpHandler(this); 165 RootRegistry.getInstance().addHandler("/harness", "JT Harness", 166 httpHandler); 167 } 168 } 169 170 //-------------------------------------------------------------------------- 171 172 /** 173 * Get the backup policy object used by this harness, used to determine 174 * the policy for backing up files before overwriting them. 175 * @return the backup policy object used by this harness 176 * @see #setBackupPolicy 177 */ 178 public BackupPolicy getBackupPolicy() { 179 return backupPolicy; 180 } 181 182 /** 183 * Set the backup policy object to be used by this harness, 184 * used to determine the policy for backing up files before 185 * overwriting them. 186 * @param bp the backup policy object used by this harness 187 * @see #getBackupPolicy 188 */ 189 public void setBackupPolicy(BackupPolicy bp) { 190 backupPolicy = bp; 191 } 192 193 /** 194 * Check if a trace file should be generated while performing a test run. 195 * @return true if and only if a trace file should be generated 196 * @see #setTracingRequired 197 */ 198 public boolean isTracingRequired() { 199 return (trace != null); 200 } 201 202 /** 203 * Set whether a trace file should be generated while performing a test run. 204 * @param b whether or not a trace file should be generated 205 * @see #isTracingRequired 206 */ 207 public void setTracingRequired(boolean b) { 208 if (b && trace == null) { 209 trace = new Trace(backupPolicy); 210 addObserver(trace); 211 //currentResults.addObserver(trace); 212 } 213 else if (!b && trace != null) { 214 removeObserver(trace); 215 //currentResults.removeObserver(trace); 216 trace = null; 217 } 218 } 219 220 /** 221 * Get the class directory or jar file containing JT Harness. 222 * @return the class directory or jar file containing JT Harness 223 * @see #setClassDir 224 */ 225 public static File getClassDir() { 226 return classDir; 227 } 228 229 /** 230 * Specify the class directory or jar file containing JT Harness. 231 * @param classDir the class directory or jar file containing JT Harness 232 * @see #getClassDir 233 */ 234 public static void setClassDir(File classDir) { 235 if (Harness.classDir != null && Harness.classDir != classDir) 236 throw new IllegalStateException(i18n.getString("harness.classDirAlreadySet")); 237 Harness.classDir = classDir; 238 } 239 240 241 //-------------------------------------------------------------------------- 242 243 /** 244 * Get the current parameters of the harness. 245 * 246 * @return null if the parameters have not been set. 247 */ 248 public Parameters getParameters() { 249 return params; 250 } 251 252 //-------------------------------------------------------------------------- 253 254 /** 255 * Get the current test environment being used by the harness. 256 * This is similar to getParameters().getEnv(), except that the environment 257 * returned here has some standard additional fields set by the harness 258 * itself. 259 * 260 * @return null if the environment has not been set. 261 */ 262 public TestEnvironment getEnv() { 263 return env; 264 } 265 266 //-------------------------------------------------------------------------- 267 268 /** 269 * Get the current set of results. This will either be the set of results 270 * from which are currently running, or the results from the last run. 271 * 272 * @return null if no results are currently available. This will be the case 273 * if the Harness has not been run, or the parameters have been changed 274 * without doing a new run. 275 */ 276 public TestResultTable getResultTable() { 277 WorkDirectory wd = (params == null ? null : params.getWorkDirectory()); 278 return (wd == null ? null : wd.getTestResultTable()); 279 } 280 281 //-------------------------------------------------------------------------- 282 283 /** 284 * Add an observer to be notified during the execution of a test run. 285 * Observers are notified of events in the reverse order they were added -- 286 * the most recently added observer gets notified first. 287 * @param o the observer to be added 288 * @see #removeObserver 289 */ 290 public void addObserver(Observer o) { 291 notifier.addObserver(o); 292 } 293 294 /** 295 * Remove a previously registered observer so that it will no longer 296 * be notified during the execution of a test run. 297 * It is safe for observers to remove themselves during a notification; 298 * most obviously, an observer may remove itself during finishedTesting() 299 * or finishedTestRun(). 300 * @param o the observer to be removed 301 * @see #addObserver 302 */ 303 public void removeObserver(Observer o) { 304 notifier.removeObserver(o); 305 } 306 307 //-------------------------------------------------------------------------- 308 309 /** 310 * Start running all the tests defined by a new set of parameters. 311 * The tests are run asynchronously, in a separate worker thread. 312 * @param p The parameters to be set when the tests are run. 313 * Any errors in the parameters are reported to 314 * any registered observers. 315 * @throws Harness.Fault if the harness is currently running tests 316 * and so cannot start running any more tests right now. 317 * @see #isRunning 318 * @see #stop 319 * @see #waitUntilDone 320 */ 321 public void start(Parameters p) throws Fault { 322 startWorker(p); 323 } 324 325 /** 326 * Wait until the harness completes the current task. 327 * @exception InterruptedException if the thread making the call is 328 * interrupted. 329 */ 330 public synchronized void waitUntilDone() throws InterruptedException { 331 while (worker != null) { 332 wait(); 333 } 334 } 335 336 337 /** 338 * Stop the harness executing any tests. If no tests are running, 339 * the method does nothing; otherwise it notifies any observers, 340 * and interrupts the thread doing the work. The worker may carry 341 * on for a short time after this method is called, while it waits 342 * for all the related tasks to complete. 343 * @see #waitUntilDone 344 */ 345 public synchronized void stop() { 346 if (worker != null) { 347 if (!stopping) { 348 notifier.stoppingTestRun(); 349 stopping = true; 350 } 351 worker.interrupt(); 352 } 353 } 354 355 /** 356 * Run the tests defined by a new set of parameters. 357 * @param params The parameters to be used; they will be validated first. 358 * @return true if and only if all the selected tests were executed successfully, and all passed 359 * @throws Harness.Fault if the harness is currently running tests 360 * and cannot start running any more tests right now. 361 * @throws InterruptedException if the thread making the call is 362 * interrupted, perhaps because of an asynchronous call of stop(). 363 * @see #isRunning 364 * @see #stop 365 * @see #waitUntilDone 366 */ 367 public boolean batch(Parameters params) 368 throws Fault, InterruptedException 369 { 370 isBatchRun = true; 371 // allow full read-ahead by default now - as of 3.2.1 372 // this allows the not run field of verbose mode to work 373 if (Boolean.getBoolean("javatest.noReadAhead")) 374 readAheadMode = ReadAheadIterator.NONE; 375 376 synchronized (this) { 377 if (worker != null) 378 throw new Fault(i18n, "harness.alreadyRunning"); 379 worker = Thread.currentThread(); 380 } 381 382 // parameters will be checked later, in runTests, but check here 383 // too to specifically verify that workDir is set 384 if (!params.isValid()) 385 throw new Harness.Fault(i18n, "harness.incompleteParameters", 386 params.getErrorMessage()); 387 388 boolean ok = false; 389 try { 390 workDir = params.getWorkDirectory(); 391 resultTable = workDir.getTestResultTable(); 392 // XXX this was a performance enhancer for 3.x 393 // it will not work if the user expects previous results 394 // to be erased/hidden if they no longer exist in the test 395 // suite. that goal and this one are fundamentally opposed 396 //resultTable.suppressFinderScan(true); 397 ok = runTests(params, ZERO_TESTS_OK); 398 } 399 catch (TestSuite.Fault e) { 400 throw new Fault(i18n, "harness.testsuiteError", e.getMessage()); 401 } 402 finally { 403 synchronized (this) { 404 worker = null; 405 notifyAll(); 406 } 407 408 notifier.finishedTestRun(ok); 409 isBatchRun = false; 410 } 411 412 return ok; 413 } 414 415 /** 416 * Check if the harness is currently executing a test suite or not. 417 * @return true if and only if the harness is currently executing a test suite. 418 * @see #start 419 * @see #batch 420 * @see #stop 421 * @see #waitUntilDone 422 */ 423 public boolean isRunning() { 424 return (worker != null); 425 } 426 427 /** 428 * Was the harness invoked in batch mode? If it is not in batch mode, this 429 * typically implies that the user is using an interactive GUI interface. 430 * @return True if the harness is running and was invoked in batch mode. 431 * @throws IllegalStateException If the harness is not running, care should 432 * be taken to handle this in case the run terminates. 433 */ 434 public synchronized boolean isBatchRun() throws IllegalStateException { 435 if (!isRunning()) 436 throw new IllegalStateException(); 437 438 return isBatchRun; 439 } 440 441 /** 442 * Indicates whether the harness has located all the tests it will execute. 443 * If true, then <tt>getTestsFoundCount()</tt> will return the number of test 444 * which will be executed during this test run; assuming the harness does not 445 * halt for special cases (errors, user request, etc...). If false, 446 * <tt>getTestsFoundCount()</tt> returns the number of tests located so 447 * far. 448 * @return True if all tests have been located. False if the harness is 449 * still looking for tests. Always false if the harness is not 450 * running. 451 * @see #isRunning() 452 * @see #getTestsFoundCount() 453 */ 454 public boolean isAllTestsFound() { 455 if (isRunning() && raTestIter != null) 456 return raTestIter.isSourceExhausted(); 457 else 458 return false; 459 } 460 461 /** 462 * Find time since the start of the current or last run. 463 * If no run is in progress, this is the time it took to complete the 464 * last run. 465 * 466 * @return Zero if no run has ever been started yet. Elapsed time in 467 * milliseconds otherwise. 468 */ 469 public long getElapsedTime() { 470 long time = 0L; 471 472 if (startTime == -1L) 473 time = 0L; // no data avail. 474 else if (cleanupFinishTime == -1L) { // isRunning() isn't good enough 475 long now = System.currentTimeMillis(); 476 time = now - startTime; // we are still running 477 } 478 else 479 time = cleanupFinishTime - startTime; 480 481 return time; 482 } 483 484 /** 485 * Get the time at which the last run start. 486 * 487 * @return Time when the last run started in milliseconds. -1 if there is 488 * no previous run. 489 * @see #getFinishTime 490 */ 491 public long getStartTime() { 492 return startTime; 493 } 494 495 /** 496 * Get the time at which the last run finished. This is the time when 497 * the last test completed, and does not include post-run cleanup time. 498 * 499 * @return Time when the last run finished in milliseconds. -1 if there is 500 * no previous run or a run is in progress. 501 * @see #getStartTime 502 */ 503 public long getFinishTime() { 504 return finishTime; 505 } 506 507 /** 508 * Get the time at which cleanup of the entire run was completed. 509 * This is after the time when the last test completed. 510 * 511 * @return Time when the run finished in milliseconds. -1 if there is 512 * no previous run or a run is in progress. 513 * @see #getStartTime 514 */ 515 public long getCleanupFinishTime() { 516 return cleanupFinishTime; 517 } 518 519 public long getTotalCleanupTime() { 520 if (cleanupFinishTime < finishTime || cleanupFinishTime == -1l) 521 return -1l; 522 else 523 return cleanupFinishTime - finishTime; 524 } 525 526 public long getTotalSetupTime() { 527 if (testsStartTime < startTime || testsStartTime == -1l) 528 return -1l; 529 else 530 return testsStartTime - startTime; 531 } 532 533 /** 534 * Find out the estimated time required to complete the remaining tests. 535 * 536 * @return A time estimate in milliseconds. Zero if no run is in progress or 537 * no estimate is available. 538 */ 539 public long getEstimatedTime() { 540 if (isRunning() == false || numTestsDone == 0) 541 return 0L; 542 543 long estRemain = getElapsedTime() * (getTestsFoundCount() - numTestsDone) / numTestsDone; 544 return estRemain; 545 } 546 547 /** 548 * Find out how many tests to run have been located so far. Data will pertain 549 * to the previous run (if any) if isRunning() is false. The return will be 550 * zero if isRunning() is false and there is no previous run for this instance 551 * of the Harness. 552 * 553 * @return Number of tests which the harness will try to run. Greater than or 554 * equal to zero and less than or equal to the total number of tests in 555 * the testsuite. 556 * @see #isRunning() 557 */ 558 public int getTestsFoundCount() { 559 if (raTestIter == null) 560 return 0; 561 562 synchronized (raTestIter) { 563 return raTestIter.getUsedElementCount() + raTestIter.getOutputQueueSize(); 564 } 565 } 566 567 /** 568 * Set the threshold for automatic halting of a test run. 569 * The current algorithm is to begin at zero, add one for every failure, 570 * five for every error and subtract two for each pass. This value must be 571 * set before the run begins, do not change it during a run. 572 * @see #getAutostopThreshold 573 */ 574 public void setAutostopThreshold(int n) { 575 autostopThreshold = n; 576 } 577 578 /** 579 * @see #setAutostopThreshold 580 */ 581 public int getAutostopThreshold(int n) { 582 return autostopThreshold; 583 } 584 585 /** 586 * Start a worker thread going to perform run tests asynchronously. 587 */ 588 private synchronized void startWorker(final Parameters p) throws Fault { 589 if (worker != null) 590 throw new Fault(i18n, "harness.alreadyRunning"); 591 592 worker = new Thread() { 593 @Override 594 public void run() { 595 boolean ok = false; 596 try { 597 ok = runTests(p, ZERO_TESTS_ERROR); 598 } 599 catch (Fault e) { 600 notifyLocalizedError(e.getMessage()); 601 } 602 catch (TestSuite.Fault e) { 603 notifyLocalizedError(e.getMessage()); 604 } 605 catch (InterruptedException e) { 606 notifyError(i18n, "harness.interrupted"); 607 } 608 finally { 609 synchronized (Harness.this) { 610 worker = null; 611 Harness.this.notifyAll(); 612 } 613 614 notifier.finishedTestRun(ok); 615 } 616 } 617 }; 618 619 worker.setName("Harness:Worker"); 620 worker.setPriority(Thread.NORM_PRIORITY - 2); // below AWT! 621 worker.start(); 622 } 623 624 625 /** 626 * This method is the one that does the work and runs the tests. Any parameters 627 * should have been set up in the constructor. 628 * @return The result is `true' if and only if all tests passed. 629 */ 630 // This methods notifies observers for startingTestRun and stoppingTestRun. 631 // The caller should notify finishedTestRun when it is OK to run start again 632 // (i.e. when worker has been reset to null. 633 private boolean runTests(Parameters p, boolean zeroTestsOK) 634 throws Fault, TestSuite.Fault, InterruptedException { 635 636 boolean ok = true; // default return/finished notification value 637 stopping = false; 638 startTime = System.currentTimeMillis(); 639 testsStartTime = -1l; 640 cleanupFinishTime= -1l; 641 finishTime = -1l; 642 numTestsDone = 0; 643 644 if (!p.isValid()) 645 throw new Harness.Fault(i18n, "harness.incompleteParameters", 646 p.getErrorMessage()); 647 params = p; 648 649 // get lots of necessary values from parameters 650 testSuite = params.getTestSuite(); 651 workDir = params.getWorkDirectory(); 652 resultTable = workDir.getTestResultTable(); 653 excludeList = params.getExcludeList(); 654 655 workDir.log(i18n, "harness.starting"); 656 657 // for compatibility with scripts that expect the timeout factor 658 // to be an integer, we write out the timeout factor as both an 659 // integer and a floating point number. The integer value is 660 // determined by rounding up the floating point number. 661 float tf = params.getTimeoutFactor(); 662 if (Float.isNaN(tf)) 663 tf = 1.0f; 664 665 String[] timeoutFactors = { 666 String.valueOf((int) (Math.ceil(tf))), 667 String.valueOf(tf) 668 }; 669 670 env = params.getEnv(); 671 env.put("javatestTimeoutFactor", timeoutFactors); 672 env.putUrlAndFile("javatestClassDir", classDir); 673 env.putUrlAndFile("harnessClassDir", classDir); // backwards compatibility 674 env.putUrlAndFile("javatestWorkDir", workDir.getRoot()); 675 676 // allow architect to reset root of TS in env. if needed 677 // esp. for backwards compatibility with JT 2.x test suites 678 String altTSRoot = testSuite.getTestSuiteInfo("env.tsRoot"); 679 // need to validate alt and change into File 680 File atsr = (altTSRoot == null ? null : new File(altTSRoot)); 681 682 if (atsr != null && atsr.exists()) { 683 env.putUrlAndFile("testSuiteRoot", atsr); 684 env.putUrlAndFile("testSuiteRootDir", 685 (atsr.isDirectory() ? atsr : atsr.getParentFile())); 686 } 687 else { 688 // normal case 689 env.putUrlAndFile("testSuiteRoot", testSuite.getRoot()); 690 env.putUrlAndFile("testSuiteRootDir", testSuite.getRootDir()); 691 } 692 693 694 // notify the test suite we are starting 695 testSuite.starting(this); 696 notifier.startingTestRun(params); 697 698 testIter = createTreeIterator(); 699 raTestIter = getTestsIterator(testIter); 700 701 // autostopThreshold is currently defined by a system property, 702 // but could come from parameters 703 if (autostopThreshold > 0) 704 addObserver(new Autostop(autostopThreshold)); 705 706 TestRunner r = testSuite.createTestRunner(); 707 r.setWorkDirectory(workDir); 708 r.setBackupPolicy(backupPolicy); 709 r.setEnvironment(env); 710 r.setExcludeList(excludeList); 711 712 int concurrency = params.getConcurrency(); 713 concurrency = Math.max(1, Math.min(concurrency, 714 Parameters.ConcurrencyParameters.MAX_CONCURRENCY)); 715 r.setConcurrency(concurrency); 716 717 r.setNotifier(notifier); 718 719 TestURLCollector testURLCollector = new TestURLCollector(); 720 notifier.addObserver(testURLCollector); 721 testsStartTime = System.currentTimeMillis(); 722 try { 723 ok = r.runTests(new Iterator() { 724 public boolean hasNext() { 725 return (stopping ? false : raTestIter.hasNext()); 726 } 727 public Object next() { 728 TestResult tr = (TestResult) (raTestIter.next()); 729 try { 730 return tr.getDescription(); 731 } 732 catch (TestResult.Fault e) { 733 stopping = true; 734 throw new JavaTestError(i18n, "harness.trProb", tr.getWorkRelativePath(), e); 735 } 736 } 737 public void remove() { 738 throw new UnsupportedOperationException(); 739 } 740 }); 741 } 742 catch (InterruptedException e) { 743 // swallow interrupts, because we're just going to wind up the run 744 } 745 notifier.removeObserver(testURLCollector); 746 747 finishTime = System.currentTimeMillis(); 748 749 notifier.finishedTesting(); 750 751 // calculate number of tests executed 752 // NOTE: the stats here don't indicate what the results of the test run were 753 int[] stats = testIter.getResultStats(); 754 int iteratorCount = 0; 755 for (int i = 0; i < stats.length; i++) 756 iteratorCount += stats[i]; 757 758 if (iteratorCount == 0 && !zeroTestsOK) { 759 TestFilter[] filters = params.getFilters(); 760 // no tests are in the error, pass, fail categories -> none selected 761 notifyError(i18n, "harness.noTests", 762 new Object[] { 763 formatFilterList(listFilterNames(filters)), 764 testIter.getRejectCount(), 765 formatFilterStats(params.getTests(), testIter) 766 }); 767 ok = false; 768 } 769 else { 770 /* user is notified of this in real-time 771 although it may not be evident in batch mode 772 if (resultTable.getTestFinder().getErrorCount() > 0) { 773 notifyError(i18n, "harness.finderError"); 774 ok = false; 775 } 776 */ 777 } 778 779 if (ok && (notifier.getErrorCount() > 0 || notifier.getFailedCount() > 0)) 780 ok = false; 781 782 try { 783 LastRunInfo.writeInfo(workDir, startTime, finishTime, 784 env.getName(), testURLCollector.testURLs); 785 } 786 catch (IOException e) { 787 // ignore 788 } 789 790 // TRT may need to reread the entire cache 791 resultTable.waitUntilReady(); 792 793 workDir.log(i18n, "harness.done", new Integer(ok ? 0 : 1)); 794 cleanupFinishTime = System.currentTimeMillis(); 795 return ok; 796 } 797 798 public ReadAheadIterator getTestsIterator(TreeIterator iter) throws Fault { 799 if (iter == null) { 800 iter = createTreeIterator(); 801 } 802 return new ReadAheadIterator(iter, readAheadMode, DEFAULT_READ_AHEAD); 803 } 804 805 private TreeIterator createTreeIterator() throws Fault { 806 // get items required to select the tests to be run 807 String[] tests = params.getTests(); 808 TestFilter[] filters = params.getFilters(); 809 810 resultTable.waitUntilReady(); 811 812 TreeIterator iter; 813 814 // get the appropriate iterator from TRT 815 if (tests == null || tests.length == 0) 816 iter = resultTable.getIterator(filters); 817 else { 818 try { 819 // CLEANUP REQUIRED: validation only occurs on Files, not Strings 820 // resultTable.getIterator should validate strings too 821 File[] files = new File[tests.length]; 822 for (int i = 0; i < tests.length; i++) 823 files[i] = new File(tests[i]); 824 iter = resultTable.getIterator(files, filters); 825 } 826 catch (TestResultTable.Fault err) { 827 throw new Harness.Fault(i18n, "harness.badInitFiles", 828 err.getMessage()); 829 } 830 } 831 832 return iter; 833 } 834 835 private static ArrayList<String> listFilterNames(final TestFilter[] filters) { 836 ArrayList<String> result = new ArrayList<>(); 837 838 if (filters == null || filters.length == 0) 839 return result; // i.e. empty 840 841 for (TestFilter f: filters) { 842 // we don't care about composite wrappers, recurse into them 843 if (f instanceof CompositeFilter) { 844 result.addAll(listFilterNames(((CompositeFilter)f).getFilters())); 845 } 846 else if (f instanceof AllTestsFilter) { 847 continue; 848 } 849 else { 850 result.add(f.getName()); 851 } 852 } 853 854 // for convienence, null is never returned 855 return result; 856 } 857 858 private static String formatFilterList(final ArrayList<String> names) { 859 if (names == null || names.size() == 0) 860 return ""; 861 862 StringBuilder sb = new StringBuilder(); 863 for (String s: names) { 864 sb.append("- "); 865 sb.append(s); 866 sb.append("\n"); 867 } 868 869 return sb.toString(); 870 } 871 872 private static String formatFilterStats(final String[] tests, 873 final TreeIterator iter) { 874 TRT_Iterator treeit = null; 875 876 if (iter == null || !(iter instanceof TRT_Iterator)) { 877 return ""; 878 } 879 else { 880 treeit = ((TRT_Iterator)iter); 881 } 882 883 TestFilter[] filters = treeit.getFilters(); 884 HashMap<TestFilter, ArrayList<TestDescription>> map = treeit.getFilterStats(); 885 Set<TestFilter> keyset = map.keySet(); 886 StringBuilder sb = new StringBuilder(); 887 888 // special case for Tests to Run because there is no associated 889 // TestFilter 890 if (tests != null && tests.length > 0) { 891 sb.append("- "); 892 sb.append("Tests to Run (" + tests.length + " path(s) specified)"); 893 sb.append("\n"); 894 } 895 896 for (TestFilter f: keyset) { 897 ArrayList<TestDescription> tds = map.get(f); 898 // this works, should consider switching to something which has more 899 // rendering control - RTF 900 sb.append("- "); 901 sb.append(tds.size()); 902 sb.append(" due to "); // could use upgrade for readability 903 sb.append(f.getName()); 904 sb.append("\n"); 905 sb.append(" "); // indentation 906 sb.append(f.getReason()); 907 sb.append("\n"); 908 } // for 909 910 return sb.toString(); 911 } 912 913 914 private void notifyError(I18NResourceBundle i18n, String key) { 915 notifyLocalizedError(i18n.getString(key)); 916 } 917 918 private void notifyError(I18NResourceBundle i18n, String key, Object arg) { 919 notifyLocalizedError(i18n.getString(key, arg)); 920 } 921 922 private void notifyError(I18NResourceBundle i18n, String key, Object[] args) { 923 notifyLocalizedError(i18n.getString(key, args)); 924 } 925 926 private void notifyLocalizedError(String msg) { 927 notifier.error(msg); 928 } 929 930 //----------member variables----------------------------------------------------- 931 932 private BackupPolicy backupPolicy; 933 private int autostopThreshold; 934 { Integer i = Integer.getInteger("javatest.autostop.threshold"); 935 autostopThreshold = (i == null ? 0 : i.intValue()); 936 } 937 938 private HarnessHttpHandler httpHandler; 939 private Trace trace; 940 941 private Thread worker; 942 private Parameters params; 943 private TestSuite testSuite; 944 private WorkDirectory workDir; 945 private ExcludeList excludeList; 946 private TestResultTable.TreeIterator testIter; 947 private int readAheadMode = ReadAheadIterator.FULL; 948 private ReadAheadIterator raTestIter; 949 private int numTestsDone; 950 private TestEnvironment env; 951 private TestResultTable resultTable; 952 private Notifier notifier = new Notifier(); 953 954 private long startTime = -1l; 955 private long finishTime = -1l; 956 private long cleanupFinishTime = -1l; 957 private long testsStartTime = -1l; 958 private boolean isBatchRun; 959 private boolean stopping; 960 961 private static File classDir; 962 private static final boolean ZERO_TESTS_OK = true; 963 private static final boolean ZERO_TESTS_ERROR = false; 964 private static final int DEFAULT_READ_AHEAD = 100; 965 private static I18NResourceBundle i18n = I18NResourceBundle.getBundleForClass(Harness.class); 966 967 private class Notifier implements Harness.Observer 968 { 969 void addObserver(Observer o) { 970 if (o == null) 971 throw new NullPointerException(); 972 observers = DynamicArray.append(observers, o); 973 } 974 975 void removeObserver(Observer o) { 976 observers = DynamicArray.remove(observers, o); 977 } 978 979 public void startingTestRun(Parameters params) { 980 resultTable.starting(); 981 982 // protect against removing observers during notification 983 Observer[] stableObservers = observers; 984 for (int i = stableObservers.length - 1; i >= 0; i--) 985 stableObservers[i].startingTestRun(params); 986 } 987 988 public void startingTest(TestResult tr) { 989 // protect against removing observers during notification 990 Observer[] stableObservers = observers; 991 for (int i = stableObservers.length - 1; i >= 0; i--) 992 stableObservers[i].startingTest(tr); 993 } 994 995 public void finishedTest(TestResult tr) { 996 numTestsDone++; 997 resultTable.update(tr); 998 // protect against removing observers during notification 999 Observer[] stableObservers = observers; 1000 for (int i = stableObservers.length - 1; i >= 0; i--) 1001 stableObservers[i].finishedTest(tr); 1002 1003 switch (tr.getStatus().getType()) { 1004 case Status.FAILED: 1005 synchronized(this) { 1006 failCount++; 1007 } 1008 break; 1009 case Status.ERROR: 1010 synchronized(this) { 1011 errCount++; 1012 } 1013 break; 1014 // XXX possibility exists for NOT_RUN, this should also 1015 // be recorded as a problem, or is it a "problem"? 1016 default: 1017 } // switch 1018 } 1019 1020 public void stoppingTestRun() { 1021 // protect against removing observers during notification 1022 Observer[] stableObservers = observers; 1023 for (int i = stableObservers.length - 1; i >= 0; i--) 1024 stableObservers[i].stoppingTestRun(); 1025 } 1026 1027 public void finishedTesting() { 1028 resultTable.finished(); 1029 1030 // protect against removing observers during notification 1031 Observer[] stableObservers = observers; 1032 for (int i = stableObservers.length - 1; i >= 0; i--) 1033 stableObservers[i].finishedTesting(); 1034 } 1035 1036 public void finishedTestRun(boolean allOK) { 1037 // protect against removing observers during notification 1038 Observer[] stableObservers = observers; 1039 for (int i = stableObservers.length - 1; i >= 0; i--) 1040 stableObservers[i].finishedTestRun(allOK); 1041 } 1042 1043 public void error(String msg) { 1044 // protect against removing observers during notification 1045 Observer[] stableObservers = observers; 1046 for (int i = stableObservers.length - 1; i >= 0; i--) 1047 stableObservers[i].error(msg); 1048 } 1049 1050 synchronized int getErrorCount() { 1051 return errCount; 1052 } 1053 1054 synchronized int getFailedCount() { 1055 return failCount; 1056 } 1057 1058 private Observer[] observers = new Observer[0]; 1059 private volatile int errCount, failCount; 1060 } 1061 1062 1063 class Autostop implements Harness.Observer { 1064 Autostop(int threshold) { 1065 this.threshold = threshold; 1066 } 1067 1068 public void startingTestRun(Parameters p) { } 1069 1070 public void startingTest(TestResult tr) { } 1071 1072 public void finishedTest(TestResult tr) { 1073 switch (tr.getStatus().getType()) { 1074 case Status.FAILED: 1075 level++; 1076 break; 1077 case Status.ERROR: 1078 level += 5; 1079 break; 1080 default: 1081 level = Math.max(level - 2, 0); 1082 } 1083 if (level >= threshold) { 1084 Harness.this.notifyError(i18n, "harness.tooManyErrors"); 1085 stop(); 1086 } 1087 } 1088 public void stoppingTestRun() { } 1089 1090 public void finishedTesting() { } 1091 1092 public void finishedTestRun(boolean allOK) { } 1093 1094 public void error(String msg) { } 1095 1096 private int level; 1097 private int threshold; 1098 } 1099 1100 /** 1101 * Class that collects executed tests 1102 */ 1103 class TestURLCollector implements Harness.Observer { 1104 TestURLCollector() { 1105 } 1106 1107 final List<String> testURLs = new ArrayList<>(); 1108 1109 public void startingTestRun(Parameters p) { } 1110 1111 public synchronized void startingTest(TestResult tr) { 1112 testURLs.add(tr.getTestName()); 1113 } 1114 1115 public void finishedTest(TestResult tr) { } 1116 1117 public void stoppingTestRun() { } 1118 1119 public void finishedTesting() { } 1120 1121 public void finishedTestRun(boolean allOK) { } 1122 1123 public void error(String msg) { } 1124 } 1125 }