1 package org.junit.runners; 2 3 import static org.junit.internal.Checks.notNull; 4 import static org.junit.internal.runners.rules.RuleMemberValidator.CLASS_RULE_METHOD_VALIDATOR; 5 import static org.junit.internal.runners.rules.RuleMemberValidator.CLASS_RULE_VALIDATOR; 6 7 import java.lang.annotation.Annotation; 8 import java.lang.reflect.Method; 9 import java.util.ArrayList; 10 import java.util.Collections; 11 import java.util.Comparator; 12 import java.util.Iterator; 13 import java.util.LinkedHashMap; 14 import java.util.List; 15 import java.util.Map; 16 import java.util.concurrent.locks.Lock; 17 import java.util.concurrent.locks.ReentrantLock; 18 19 import org.junit.AfterClass; 20 import org.junit.BeforeClass; 21 import org.junit.ClassRule; 22 import org.junit.FixMethodOrder; 23 import org.junit.Ignore; 24 import org.junit.Rule; 25 import org.junit.internal.AssumptionViolatedException; 26 import org.junit.internal.runners.model.EachTestNotifier; 27 import org.junit.internal.runners.statements.RunAfters; 28 import org.junit.internal.runners.statements.RunBefores; 29 import org.junit.rules.RunRules; 30 import org.junit.rules.TestRule; 31 import org.junit.runner.Description; 32 import org.junit.runner.Runner; 33 import org.junit.runner.manipulation.Filter; 34 import org.junit.runner.manipulation.Filterable; 35 import org.junit.runner.manipulation.Orderer; 36 import org.junit.runner.manipulation.InvalidOrderingException; 37 import org.junit.runner.manipulation.NoTestsRemainException; 38 import org.junit.runner.manipulation.Orderable; 39 import org.junit.runner.manipulation.Sorter; 40 import org.junit.runner.notification.RunNotifier; 41 import org.junit.runner.notification.StoppedByUserException; 42 import org.junit.runners.model.FrameworkMember; 43 import org.junit.runners.model.FrameworkMethod; 44 import org.junit.runners.model.InitializationError; 45 import org.junit.runners.model.InvalidTestClassError; 46 import org.junit.runners.model.MemberValueConsumer; 47 import org.junit.runners.model.RunnerScheduler; 48 import org.junit.runners.model.Statement; 49 import org.junit.runners.model.TestClass; 50 import org.junit.validator.AnnotationsValidator; 51 import org.junit.validator.TestClassValidator; 52 53 /** 54 * Provides most of the functionality specific to a Runner that implements a 55 * "parent node" in the test tree, with children defined by objects of some data 56 * type {@code T}. (For {@link BlockJUnit4ClassRunner}, {@code T} is 57 * {@link Method} . For {@link Suite}, {@code T} is {@link Class}.) Subclasses 58 * must implement finding the children of the node, describing each child, and 59 * running each child. ParentRunner will filter and sort children, handle 60 * {@code @BeforeClass} and {@code @AfterClass} methods, 61 * handle annotated {@link ClassRule}s, create a composite 62 * {@link Description}, and run children sequentially. 63 * 64 * @since 4.5 65 */ 66 public abstract class ParentRunner<T> extends Runner implements Filterable, 67 Orderable { 68 private static final List<TestClassValidator> VALIDATORS = Collections.<TestClassValidator>singletonList( 69 new AnnotationsValidator()); 70 71 private final Lock childrenLock = new ReentrantLock(); 72 private final TestClass testClass; 73 74 // Guarded by childrenLock 75 private volatile List<T> filteredChildren = null; 76 77 private volatile RunnerScheduler scheduler = new RunnerScheduler() { 78 public void schedule(Runnable childStatement) { 79 childStatement.run(); 80 } 81 82 public void finished() { 83 // do nothing 84 } 85 }; 86 87 /** 88 * Constructs a new {@code ParentRunner} that will run {@code @TestClass} 89 */ ParentRunner(Class<?> testClass)90 protected ParentRunner(Class<?> testClass) throws InitializationError { 91 this.testClass = createTestClass(testClass); 92 validate(); 93 } 94 95 /** 96 * Constructs a new {@code ParentRunner} that will run the {@code TestClass}. 97 * 98 * @since 4.13 99 */ ParentRunner(TestClass testClass)100 protected ParentRunner(TestClass testClass) throws InitializationError { 101 this.testClass = notNull(testClass); 102 validate(); 103 } 104 105 /** 106 * @deprecated Please use {@link #ParentRunner(org.junit.runners.model.TestClass)}. 107 * @since 4.12 108 */ 109 @Deprecated createTestClass(Class<?> testClass)110 protected TestClass createTestClass(Class<?> testClass) { 111 return new TestClass(testClass); 112 } 113 114 // 115 // Must be overridden 116 // 117 118 /** 119 * Returns a list of objects that define the children of this Runner. 120 */ getChildren()121 protected abstract List<T> getChildren(); 122 123 /** 124 * Returns a {@link Description} for {@code child}, which can be assumed to 125 * be an element of the list returned by {@link ParentRunner#getChildren()} 126 */ describeChild(T child)127 protected abstract Description describeChild(T child); 128 129 /** 130 * Runs the test corresponding to {@code child}, which can be assumed to be 131 * an element of the list returned by {@link ParentRunner#getChildren()}. 132 * Subclasses are responsible for making sure that relevant test events are 133 * reported through {@code notifier} 134 */ runChild(T child, RunNotifier notifier)135 protected abstract void runChild(T child, RunNotifier notifier); 136 137 // 138 // May be overridden 139 // 140 141 /** 142 * Adds to {@code errors} a throwable for each problem noted with the test class (available from {@link #getTestClass()}). 143 * Default implementation adds an error for each method annotated with 144 * {@code @BeforeClass} or {@code @AfterClass} that is not 145 * {@code public static void} with no arguments. 146 */ collectInitializationErrors(List<Throwable> errors)147 protected void collectInitializationErrors(List<Throwable> errors) { 148 validatePublicVoidNoArgMethods(BeforeClass.class, true, errors); 149 validatePublicVoidNoArgMethods(AfterClass.class, true, errors); 150 validateClassRules(errors); 151 applyValidators(errors); 152 } 153 applyValidators(List<Throwable> errors)154 private void applyValidators(List<Throwable> errors) { 155 if (getTestClass().getJavaClass() != null) { 156 for (TestClassValidator each : VALIDATORS) { 157 errors.addAll(each.validateTestClass(getTestClass())); 158 } 159 } 160 } 161 162 /** 163 * Adds to {@code errors} if any method in this class is annotated with 164 * {@code annotation}, but: 165 * <ul> 166 * <li>is not public, or 167 * <li>takes parameters, or 168 * <li>returns something other than void, or 169 * <li>is static (given {@code isStatic is false}), or 170 * <li>is not static (given {@code isStatic is true}). 171 * </ul> 172 */ validatePublicVoidNoArgMethods(Class<? extends Annotation> annotation, boolean isStatic, List<Throwable> errors)173 protected void validatePublicVoidNoArgMethods(Class<? extends Annotation> annotation, 174 boolean isStatic, List<Throwable> errors) { 175 List<FrameworkMethod> methods = getTestClass().getAnnotatedMethods(annotation); 176 177 for (FrameworkMethod eachTestMethod : methods) { 178 eachTestMethod.validatePublicVoidNoArg(isStatic, errors); 179 } 180 } 181 validateClassRules(List<Throwable> errors)182 private void validateClassRules(List<Throwable> errors) { 183 CLASS_RULE_VALIDATOR.validate(getTestClass(), errors); 184 CLASS_RULE_METHOD_VALIDATOR.validate(getTestClass(), errors); 185 } 186 187 /** 188 * Constructs a {@code Statement} to run all of the tests in the test class. 189 * Override to add pre-/post-processing. Here is an outline of the 190 * implementation: 191 * <ol> 192 * <li>Determine the children to be run using {@link #getChildren()} 193 * (subject to any imposed filter and sort).</li> 194 * <li>If there are any children remaining after filtering and ignoring, 195 * construct a statement that will: 196 * <ol> 197 * <li>Apply all {@code ClassRule}s on the test-class and superclasses.</li> 198 * <li>Run all non-overridden {@code @BeforeClass} methods on the test-class 199 * and superclasses; if any throws an Exception, stop execution and pass the 200 * exception on.</li> 201 * <li>Run all remaining tests on the test-class.</li> 202 * <li>Run all non-overridden {@code @AfterClass} methods on the test-class 203 * and superclasses: exceptions thrown by previous steps are combined, if 204 * necessary, with exceptions from AfterClass methods into a 205 * {@link org.junit.runners.model.MultipleFailureException}.</li> 206 * </ol> 207 * </li> 208 * </ol> 209 * 210 * @return {@code Statement} 211 */ classBlock(final RunNotifier notifier)212 protected Statement classBlock(final RunNotifier notifier) { 213 Statement statement = childrenInvoker(notifier); 214 if (!areAllChildrenIgnored()) { 215 statement = withBeforeClasses(statement); 216 statement = withAfterClasses(statement); 217 statement = withClassRules(statement); 218 statement = withInterruptIsolation(statement); 219 } 220 return statement; 221 } 222 areAllChildrenIgnored()223 private boolean areAllChildrenIgnored() { 224 for (T child : getFilteredChildren()) { 225 if (!isIgnored(child)) { 226 return false; 227 } 228 } 229 return true; 230 } 231 232 /** 233 * Returns a {@link Statement}: run all non-overridden {@code @BeforeClass} methods on this class 234 * and superclasses before executing {@code statement}; if any throws an 235 * Exception, stop execution and pass the exception on. 236 */ withBeforeClasses(Statement statement)237 protected Statement withBeforeClasses(Statement statement) { 238 List<FrameworkMethod> befores = testClass 239 .getAnnotatedMethods(BeforeClass.class); 240 return befores.isEmpty() ? statement : 241 new RunBefores(statement, befores, null); 242 } 243 244 /** 245 * Returns a {@link Statement}: run all non-overridden {@code @AfterClass} methods on this class 246 * and superclasses after executing {@code statement}; all AfterClass methods are 247 * always executed: exceptions thrown by previous steps are combined, if 248 * necessary, with exceptions from AfterClass methods into a 249 * {@link org.junit.runners.model.MultipleFailureException}. 250 */ withAfterClasses(Statement statement)251 protected Statement withAfterClasses(Statement statement) { 252 List<FrameworkMethod> afters = testClass 253 .getAnnotatedMethods(AfterClass.class); 254 return afters.isEmpty() ? statement : 255 new RunAfters(statement, afters, null); 256 } 257 258 /** 259 * Returns a {@link Statement}: apply all 260 * static fields assignable to {@link TestRule} 261 * annotated with {@link ClassRule}. 262 * 263 * @param statement the base statement 264 * @return a RunRules statement if any class-level {@link Rule}s are 265 * found, or the base statement 266 */ withClassRules(Statement statement)267 private Statement withClassRules(Statement statement) { 268 List<TestRule> classRules = classRules(); 269 return classRules.isEmpty() ? statement : 270 new RunRules(statement, classRules, getDescription()); 271 } 272 273 /** 274 * @return the {@code ClassRule}s that can transform the block that runs 275 * each method in the tested class. 276 */ classRules()277 protected List<TestRule> classRules() { 278 ClassRuleCollector collector = new ClassRuleCollector(); 279 testClass.collectAnnotatedMethodValues(null, ClassRule.class, TestRule.class, collector); 280 testClass.collectAnnotatedFieldValues(null, ClassRule.class, TestRule.class, collector); 281 return collector.getOrderedRules(); 282 } 283 284 /** 285 * Returns a {@link Statement}: Call {@link #runChild(Object, RunNotifier)} 286 * on each object returned by {@link #getChildren()} (subject to any imposed 287 * filter and sort) 288 */ childrenInvoker(final RunNotifier notifier)289 protected Statement childrenInvoker(final RunNotifier notifier) { 290 return new Statement() { 291 @Override 292 public void evaluate() { 293 runChildren(notifier); 294 } 295 }; 296 } 297 298 /** 299 * @return a {@link Statement}: clears interrupt status of current thread after execution of statement 300 */ 301 protected final Statement withInterruptIsolation(final Statement statement) { 302 return new Statement() { 303 @Override 304 public void evaluate() throws Throwable { 305 try { 306 statement.evaluate(); 307 } finally { 308 Thread.interrupted(); // clearing thread interrupted status for isolation 309 } 310 } 311 }; 312 } 313 314 /** 315 * Evaluates whether a child is ignored. The default implementation always 316 * returns <code>false</code>. 317 * 318 * <p>{@link BlockJUnit4ClassRunner}, for example, overrides this method to 319 * filter tests based on the {@link Ignore} annotation. 320 */ 321 protected boolean isIgnored(T child) { 322 return false; 323 } 324 325 private void runChildren(final RunNotifier notifier) { 326 final RunnerScheduler currentScheduler = scheduler; 327 try { 328 for (final T each : getFilteredChildren()) { 329 currentScheduler.schedule(new Runnable() { 330 public void run() { 331 ParentRunner.this.runChild(each, notifier); 332 } 333 }); 334 } 335 } finally { 336 currentScheduler.finished(); 337 } 338 } 339 340 /** 341 * Returns a name used to describe this Runner 342 */ 343 protected String getName() { 344 return testClass.getName(); 345 } 346 347 // 348 // Available for subclasses 349 // 350 351 /** 352 * Returns a {@link TestClass} object wrapping the class to be executed. 353 */ 354 public final TestClass getTestClass() { 355 return testClass; 356 } 357 358 /** 359 * Runs a {@link Statement} that represents a leaf (aka atomic) test. 360 */ 361 protected final void runLeaf(Statement statement, Description description, 362 RunNotifier notifier) { 363 EachTestNotifier eachNotifier = new EachTestNotifier(notifier, description); 364 eachNotifier.fireTestStarted(); 365 try { 366 statement.evaluate(); 367 } catch (AssumptionViolatedException e) { 368 eachNotifier.addFailedAssumption(e); 369 } catch (Throwable e) { 370 eachNotifier.addFailure(e); 371 } finally { 372 eachNotifier.fireTestFinished(); 373 } 374 } 375 376 /** 377 * @return the annotations that should be attached to this runner's 378 * description. 379 */ 380 protected Annotation[] getRunnerAnnotations() { 381 return testClass.getAnnotations(); 382 } 383 384 // 385 // Implementation of Runner 386 // 387 388 @Override 389 public Description getDescription() { 390 Class<?> clazz = getTestClass().getJavaClass(); 391 Description description; 392 // if subclass overrides `getName()` then we should use it 393 // to maintain backwards compatibility with JUnit 4.12 394 if (clazz == null || !clazz.getName().equals(getName())) { 395 description = Description.createSuiteDescription(getName(), getRunnerAnnotations()); 396 } else { 397 description = Description.createSuiteDescription(clazz, getRunnerAnnotations()); 398 } 399 400 for (T child : getFilteredChildren()) { 401 description.addChild(describeChild(child)); 402 } 403 return description; 404 } 405 406 @Override 407 public void run(final RunNotifier notifier) { 408 EachTestNotifier testNotifier = new EachTestNotifier(notifier, 409 getDescription()); 410 testNotifier.fireTestSuiteStarted(); 411 try { 412 Statement statement = classBlock(notifier); 413 statement.evaluate(); 414 } catch (AssumptionViolatedException e) { 415 testNotifier.addFailedAssumption(e); 416 } catch (StoppedByUserException e) { 417 throw e; 418 } catch (Throwable e) { 419 testNotifier.addFailure(e); 420 } finally { 421 testNotifier.fireTestSuiteFinished(); 422 } 423 } 424 425 // 426 // Implementation of Filterable and Sortable 427 // 428 429 public void filter(Filter filter) throws NoTestsRemainException { 430 childrenLock.lock(); 431 try { 432 List<T> children = new ArrayList<T>(getFilteredChildren()); 433 for (Iterator<T> iter = children.iterator(); iter.hasNext(); ) { 434 T each = iter.next(); 435 if (shouldRun(filter, each)) { 436 try { 437 filter.apply(each); 438 } catch (NoTestsRemainException e) { 439 iter.remove(); 440 } 441 } else { 442 iter.remove(); 443 } 444 } 445 filteredChildren = Collections.unmodifiableList(children); 446 if (filteredChildren.isEmpty()) { 447 throw new NoTestsRemainException(); 448 } 449 } finally { 450 childrenLock.unlock(); 451 } 452 } 453 454 public void sort(Sorter sorter) { 455 if (shouldNotReorder()) { 456 return; 457 } 458 459 childrenLock.lock(); 460 try { 461 for (T each : getFilteredChildren()) { 462 sorter.apply(each); 463 } 464 List<T> sortedChildren = new ArrayList<T>(getFilteredChildren()); 465 Collections.sort(sortedChildren, comparator(sorter)); 466 filteredChildren = Collections.unmodifiableList(sortedChildren); 467 } finally { 468 childrenLock.unlock(); 469 } 470 } 471 472 /** 473 * Implementation of {@link Orderable#order(Orderer)}. 474 * 475 * @since 4.13 476 */ 477 public void order(Orderer orderer) throws InvalidOrderingException { 478 if (shouldNotReorder()) { 479 return; 480 } 481 482 childrenLock.lock(); 483 try { 484 List<T> children = getFilteredChildren(); 485 // In theory, we could have duplicate Descriptions. De-dup them before ordering, 486 // and add them back at the end. 487 Map<Description, List<T>> childMap = new LinkedHashMap<Description, List<T>>( 488 children.size()); 489 for (T child : children) { 490 Description description = describeChild(child); 491 List<T> childrenWithDescription = childMap.get(description); 492 if (childrenWithDescription == null) { 493 childrenWithDescription = new ArrayList<T>(1); 494 childMap.put(description, childrenWithDescription); 495 } 496 childrenWithDescription.add(child); 497 orderer.apply(child); 498 } 499 500 List<Description> inOrder = orderer.order(childMap.keySet()); 501 502 children = new ArrayList<T>(children.size()); 503 for (Description description : inOrder) { 504 children.addAll(childMap.get(description)); 505 } 506 filteredChildren = Collections.unmodifiableList(children); 507 } finally { 508 childrenLock.unlock(); 509 } 510 } 511 512 // 513 // Private implementation 514 // 515 516 private boolean shouldNotReorder() { 517 // If the test specifies a specific order, do not reorder. 518 return getDescription().getAnnotation(FixMethodOrder.class) != null; 519 } 520 521 private void validate() throws InitializationError { 522 List<Throwable> errors = new ArrayList<Throwable>(); 523 collectInitializationErrors(errors); 524 if (!errors.isEmpty()) { 525 throw new InvalidTestClassError(testClass.getJavaClass(), errors); 526 } 527 } 528 529 private List<T> getFilteredChildren() { 530 if (filteredChildren == null) { 531 childrenLock.lock(); 532 try { 533 if (filteredChildren == null) { 534 filteredChildren = Collections.unmodifiableList( 535 new ArrayList<T>(getChildren())); 536 } 537 } finally { 538 childrenLock.unlock(); 539 } 540 } 541 return filteredChildren; 542 } 543 544 private boolean shouldRun(Filter filter, T each) { 545 return filter.shouldRun(describeChild(each)); 546 } 547 548 private Comparator<? super T> comparator(final Sorter sorter) { 549 return new Comparator<T>() { 550 public int compare(T o1, T o2) { 551 return sorter.compare(describeChild(o1), describeChild(o2)); 552 } 553 }; 554 } 555 556 /** 557 * Sets a scheduler that determines the order and parallelization 558 * of children. Highly experimental feature that may change. 559 */ 560 public void setScheduler(RunnerScheduler scheduler) { 561 this.scheduler = scheduler; 562 } 563 564 private static class ClassRuleCollector implements MemberValueConsumer<TestRule> { 565 final List<RuleContainer.RuleEntry> entries = new ArrayList<RuleContainer.RuleEntry>(); 566 567 public void accept(FrameworkMember<?> member, TestRule value) { 568 ClassRule rule = member.getAnnotation(ClassRule.class); 569 entries.add(new RuleContainer.RuleEntry(value, RuleContainer.RuleEntry.TYPE_TEST_RULE, 570 rule != null ? rule.order() : null)); 571 } 572 573 public List<TestRule> getOrderedRules() { 574 Collections.sort(entries, RuleContainer.ENTRY_COMPARATOR); 575 List<TestRule> result = new ArrayList<TestRule>(entries.size()); 576 for (RuleContainer.RuleEntry entry : entries) { 577 result.add((TestRule) entry.rule); 578 } 579 return result; 580 } 581 } 582 } 583