1 /******************************************************************************* 2 * Copyright (c) 2000, 2018 IBM Corporation and others. 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * IBM Corporation - initial API and implementation 13 * Achim Demelt <a.demelt@exxcellent.de> - [junit] Separate UI from non-UI code - https://bugs.eclipse.org/bugs/show_bug.cgi?id=278844 14 * Thirumala Reddy Mutchukota <thirumala@google.com> - [JUnit] Avoid rerun test launch on UI thread - https://bugs.eclipse.org/bugs/show_bug.cgi?id=411841 15 *******************************************************************************/ 16 package org.eclipse.jdt.internal.junit.model; 17 18 import java.io.File; 19 import java.text.DateFormat; 20 import java.text.SimpleDateFormat; 21 import java.util.ArrayList; 22 import java.util.Arrays; 23 import java.util.Date; 24 import java.util.HashMap; 25 import java.util.List; 26 27 import org.eclipse.jdt.junit.model.ITestElement; 28 import org.eclipse.jdt.junit.model.ITestElementContainer; 29 import org.eclipse.jdt.junit.model.ITestRunSession; 30 31 import org.eclipse.core.runtime.Assert; 32 import org.eclipse.core.runtime.CoreException; 33 import org.eclipse.core.runtime.ListenerList; 34 35 import org.eclipse.debug.core.DebugPlugin; 36 import org.eclipse.debug.core.ILaunch; 37 import org.eclipse.debug.core.ILaunchConfiguration; 38 import org.eclipse.debug.core.ILaunchManager; 39 import org.eclipse.debug.core.ILaunchesListener2; 40 41 import org.eclipse.jdt.core.IJavaProject; 42 43 import org.eclipse.jdt.internal.junit.JUnitCorePlugin; 44 import org.eclipse.jdt.internal.junit.JUnitMessages; 45 import org.eclipse.jdt.internal.junit.launcher.ITestKind; 46 import org.eclipse.jdt.internal.junit.launcher.JUnitLaunchConfigurationConstants; 47 import org.eclipse.jdt.internal.junit.model.TestElement.Status; 48 import org.eclipse.jdt.internal.junit.runner.MessageIds; 49 50 51 /** 52 * A test run session holds all information about a test run, i.e. 53 * launch configuration, launch, test tree (including results). 54 */ 55 public class TestRunSession implements ITestRunSession { 56 57 /** 58 * The launch, or <code>null</code> iff this session was run externally. 59 */ 60 private final ILaunch fLaunch; 61 private final String fTestRunName; 62 /** 63 * Java project, or <code>null</code>. 64 */ 65 private final IJavaProject fProject; 66 67 private final ITestKind fTestRunnerKind; 68 69 /** 70 * Test runner client or <code>null</code>. 71 */ 72 private RemoteTestRunnerClient fTestRunnerClient; 73 74 private final ListenerList<ITestSessionListener> fSessionListeners; 75 76 /** 77 * The model root, or <code>null</code> if swapped to disk. 78 */ 79 private TestRoot fTestRoot; 80 81 /** 82 * The test run session's cached result, or <code>null</code> if <code>fTestRoot != null</code>. 83 */ 84 private Result fTestResult; 85 86 /** 87 * Map from testId to testElement. 88 */ 89 private HashMap<String, TestElement> fIdToTest; 90 91 /** 92 * The TestSuites for which additional children are expected. 93 */ 94 private List<IncompleteTestSuite> fIncompleteTestSuites; 95 96 private List<IncompleteTestSuite> fFactoryTestSuites; 97 98 /** 99 * Suite for unrooted test case elements, or <code>null</code>. 100 */ 101 private TestSuiteElement fUnrootedSuite; 102 103 private static final String EMPTY_STRING= ""; //$NON-NLS-1$ 104 105 /** 106 * Tags included in this test run. 107 */ 108 private String fIncludeTags; 109 110 /** 111 * Tags excluded from this test run. 112 */ 113 private String fExcludeTags; 114 115 /** 116 * Number of tests started during this test run. 117 */ 118 volatile int fStartedCount; 119 /** 120 * Number of tests ignored during this test run. 121 */ 122 volatile int fIgnoredCount; 123 /** 124 * Number of tests whose assumption failed during this test run. 125 */ 126 volatile int fAssumptionFailureCount; 127 /** 128 * Number of errors during this test run. 129 */ 130 volatile int fErrorCount; 131 /** 132 * Number of failures during this test run. 133 */ 134 volatile int fFailureCount; 135 /** 136 * Total number of tests to run. 137 */ 138 volatile int fTotalCount; 139 /** 140 * <ul> 141 * <li>If > 0: Start time in millis</li> 142 * <li>If < 0: Unique identifier for imported test run</li> 143 * <li>If = 0: Session not started yet</li> 144 * </ul> 145 */ 146 volatile long fStartTime; 147 volatile boolean fIsRunning; 148 149 volatile boolean fIsStopped; 150 151 152 /** 153 * Creates a test run session. 154 * 155 * @param testRunName name of the test run 156 * @param project may be <code>null</code> 157 */ TestRunSession(String testRunName, IJavaProject project)158 public TestRunSession(String testRunName, IJavaProject project) { 159 //TODO: check assumptions about non-null fields 160 161 fLaunch= null; 162 fProject= project; 163 fStartTime= -System.currentTimeMillis(); 164 165 Assert.isNotNull(testRunName); 166 fTestRunName= testRunName; 167 fTestRunnerKind= ITestKind.NULL; //TODO 168 169 fTestRoot= new TestRoot(this); 170 fIdToTest= new HashMap<>(); 171 172 fTestRunnerClient= null; 173 174 fSessionListeners= new ListenerList<>(); 175 } 176 177 TestRunSession(ILaunch launch, IJavaProject project, int port)178 public TestRunSession(ILaunch launch, IJavaProject project, int port) { 179 Assert.isNotNull(launch); 180 181 fLaunch= launch; 182 fProject= project; 183 184 ILaunchConfiguration launchConfiguration= launch.getLaunchConfiguration(); 185 if (launchConfiguration != null) { 186 fTestRunName= launchConfiguration.getName(); 187 fTestRunnerKind= JUnitLaunchConfigurationConstants.getTestRunnerKind(launchConfiguration); 188 } else { 189 fTestRunName= project.getElementName(); 190 fTestRunnerKind= ITestKind.NULL; 191 } 192 193 fTestRoot= new TestRoot(this); 194 fIdToTest= new HashMap<>(); 195 196 fTestRunnerClient= new RemoteTestRunnerClient(); 197 fTestRunnerClient.startListening(new ITestRunListener2[] { new TestSessionNotifier() }, port); 198 199 final ILaunchManager launchManager= DebugPlugin.getDefault().getLaunchManager(); 200 launchManager.addLaunchListener(new ILaunchesListener2() { 201 @Override 202 public void launchesTerminated(ILaunch[] launches) { 203 if (Arrays.asList(launches).contains(fLaunch)) { 204 if (fTestRunnerClient != null) { 205 fTestRunnerClient.stopWaiting(); 206 } 207 launchManager.removeLaunchListener(this); 208 } 209 } 210 @Override 211 public void launchesRemoved(ILaunch[] launches) { 212 if (Arrays.asList(launches).contains(fLaunch)) { 213 if (fTestRunnerClient != null) { 214 fTestRunnerClient.stopWaiting(); 215 } 216 launchManager.removeLaunchListener(this); 217 } 218 } 219 @Override 220 public void launchesChanged(ILaunch[] launches) { 221 } 222 @Override 223 public void launchesAdded(ILaunch[] launches) { 224 } 225 }); 226 227 fSessionListeners= new ListenerList<>(); 228 addTestSessionListener(new TestRunListenerAdapter(this)); 229 } 230 reset()231 void reset() { 232 fStartedCount= 0; 233 fFailureCount= 0; 234 fAssumptionFailureCount = 0; 235 fErrorCount= 0; 236 fIgnoredCount= 0; 237 fTotalCount= 0; 238 239 fTestRoot= new TestRoot(this); 240 fTestResult= null; 241 fIdToTest= new HashMap<>(); 242 } 243 244 @Override getProgressState()245 public ProgressState getProgressState() { 246 if (isRunning()) { 247 return ProgressState.RUNNING; 248 } 249 if (isStopped()) { 250 return ProgressState.STOPPED; 251 } 252 return ProgressState.COMPLETED; 253 } 254 255 @Override getTestResult(boolean includeChildren)256 public Result getTestResult(boolean includeChildren) { 257 if (fTestRoot != null) { 258 return fTestRoot.getTestResult(true); 259 } else { 260 return fTestResult; 261 } 262 } 263 264 @Override getChildren()265 public ITestElement[] getChildren() { 266 return getTestRoot().getChildren(); 267 } 268 269 @Override getFailureTrace()270 public FailureTrace getFailureTrace() { 271 return null; 272 } 273 274 @Override getParentContainer()275 public ITestElementContainer getParentContainer() { 276 return null; 277 } 278 279 @Override getTestRunSession()280 public ITestRunSession getTestRunSession() { 281 return this; 282 } 283 284 getTestRoot()285 public synchronized TestRoot getTestRoot() { 286 swapIn(); //TODO: TestRoot should stay (e.g. for getTestRoot().getStatus()) 287 return fTestRoot; 288 } 289 290 /* 291 * @see org.eclipse.jdt.junit.model.ITestRunSession#getJavaProject() 292 */ 293 @Override getLaunchedProject()294 public IJavaProject getLaunchedProject() { 295 return fProject; 296 } 297 getTestRunnerKind()298 public ITestKind getTestRunnerKind() { 299 return fTestRunnerKind; 300 } 301 302 303 /** 304 * @return the launch, or <code>null</code> iff this session was run externally 305 */ getLaunch()306 public ILaunch getLaunch() { 307 return fLaunch; 308 } 309 310 @Override getTestRunName()311 public String getTestRunName() { 312 return fTestRunName; 313 } 314 getErrorCount()315 public int getErrorCount() { 316 return fErrorCount; 317 } 318 getFailureCount()319 public int getFailureCount() { 320 return fFailureCount; 321 } 322 getAssumptionFailureCount()323 public int getAssumptionFailureCount() { 324 return fAssumptionFailureCount; 325 } 326 getStartedCount()327 public int getStartedCount() { 328 return fStartedCount; 329 } 330 getIgnoredCount()331 public int getIgnoredCount() { 332 return fIgnoredCount; 333 } 334 getTotalCount()335 public int getTotalCount() { 336 return fTotalCount; 337 } 338 getStartTime()339 public long getStartTime() { 340 return fStartTime; 341 } 342 343 /** 344 * @return <code>true</code> iff the session has been stopped or terminated 345 */ isStopped()346 public boolean isStopped() { 347 return fIsStopped; 348 } 349 addTestSessionListener(ITestSessionListener listener)350 public synchronized void addTestSessionListener(ITestSessionListener listener) { 351 swapIn(); 352 fSessionListeners.add(listener); 353 } 354 removeTestSessionListener(ITestSessionListener listener)355 public void removeTestSessionListener(ITestSessionListener listener) { 356 fSessionListeners.remove(listener); 357 } 358 swapOut()359 public synchronized void swapOut() { 360 if (fTestRoot == null) 361 return; 362 if (isRunning() || isStarting() || isKeptAlive()) 363 return; 364 365 for (ITestSessionListener registered : fSessionListeners) { 366 if (! registered.acceptsSwapToDisk()) 367 return; 368 } 369 370 try { 371 File swapFile= getSwapFile(); 372 373 JUnitModel.exportTestRunSession(this, swapFile); 374 fTestResult= fTestRoot.getTestResult(true); 375 fTestRoot= null; 376 fTestRunnerClient= null; 377 fIdToTest= new HashMap<>(); 378 fIncompleteTestSuites= null; 379 fFactoryTestSuites= null; 380 fUnrootedSuite= null; 381 382 } catch (IllegalStateException e) { 383 JUnitCorePlugin.log(e); 384 } catch (CoreException e) { 385 JUnitCorePlugin.log(e); 386 } 387 } 388 isStarting()389 public boolean isStarting() { 390 return getStartTime() == 0 && fLaunch != null && ! fLaunch.isTerminated(); 391 } 392 393 removeSwapFile()394 public void removeSwapFile() { 395 File swapFile= getSwapFile(); 396 if (swapFile.exists()) 397 swapFile.delete(); 398 } 399 getSwapFile()400 private File getSwapFile() throws IllegalStateException { 401 File historyDir= JUnitCorePlugin.getHistoryDirectory(); 402 String isoTime= new SimpleDateFormat("yyyyMMdd-HHmmss.SSS").format(new Date(getStartTime())); //$NON-NLS-1$ 403 String swapFileName= isoTime + ".xml"; //$NON-NLS-1$ 404 return new File(historyDir, swapFileName); 405 } 406 407 swapIn()408 public synchronized void swapIn() { 409 if (fTestRoot != null) 410 return; 411 412 try { 413 JUnitModel.importIntoTestRunSession(getSwapFile(), this); 414 } catch (IllegalStateException e) { 415 JUnitCorePlugin.log(e); 416 fTestRoot= new TestRoot(this); 417 fTestResult= null; 418 } catch (CoreException e) { 419 JUnitCorePlugin.log(e); 420 fTestRoot= new TestRoot(this); 421 fTestResult= null; 422 } 423 } 424 stopTestRun()425 public void stopTestRun() { 426 if (isRunning() || ! isKeptAlive()) 427 fIsStopped= true; 428 if (fTestRunnerClient != null) 429 fTestRunnerClient.stopTest(); 430 } 431 432 /** 433 * @return <code>true</code> iff the runtime VM of this test session is still alive 434 */ isKeptAlive()435 public boolean isKeptAlive() { 436 if (fTestRunnerClient != null 437 && fLaunch != null 438 && fTestRunnerClient.isRunning() 439 && ILaunchManager.DEBUG_MODE.equals(fLaunch.getLaunchMode())) { 440 ILaunchConfiguration config= fLaunch.getLaunchConfiguration(); 441 try { 442 return config != null 443 && config.getAttribute(JUnitLaunchConfigurationConstants.ATTR_KEEPRUNNING, false); 444 } catch (CoreException e) { 445 return false; 446 } 447 448 } else { 449 return false; 450 } 451 } 452 453 /** 454 * @return <code>true</code> iff this session has been started, but not ended nor stopped nor terminated 455 */ isRunning()456 public boolean isRunning() { 457 return fIsRunning; 458 } 459 460 /** 461 * Reruns the given test method if the session is kept alive. 462 * 463 * @param testId test id 464 * @param className test class name 465 * @param testName test method name 466 * @return <code>false</code> iff the rerun could not be started 467 */ rerunTest(String testId, String className, String testName)468 public boolean rerunTest(String testId, String className, String testName) { 469 if (isKeptAlive()) { 470 Status status= ((TestCaseElement) getTestElement(testId)).getStatus(); 471 if (status == Status.ERROR) { 472 fErrorCount--; 473 } else if (status == Status.FAILURE) { 474 fFailureCount--; 475 } 476 fTestRunnerClient.rerunTest(testId, className, testName); 477 return true; 478 } 479 return false; 480 } 481 getTestElement(String id)482 public TestElement getTestElement(String id) { 483 return fIdToTest.get(id); 484 } 485 addTreeEntry(String treeEntry)486 private TestElement addTreeEntry(String treeEntry) { 487 // format: testId","testName","isSuite","testcount","isDynamicTest","parentId","displayName","parameterTypes","uniqueId 488 int index0= treeEntry.indexOf(','); 489 String id= treeEntry.substring(0, index0); 490 491 StringBuffer testNameBuffer= new StringBuffer(100); 492 int index1= scanTestName(treeEntry, index0 + 1, testNameBuffer); 493 String testName= testNameBuffer.toString().trim(); 494 495 int index2= treeEntry.indexOf(',', index1 + 1); 496 boolean isSuite= treeEntry.substring(index1 + 1, index2).equals("true"); //$NON-NLS-1$ 497 498 int testCount; 499 boolean isDynamicTest; 500 String parentId; 501 String displayName; 502 StringBuffer displayNameBuffer= new StringBuffer(100); 503 String[] parameterTypes; 504 StringBuffer parameterTypesBuffer= new StringBuffer(200); 505 String uniqueId; 506 StringBuffer uniqueIdBuffer= new StringBuffer(200); 507 int index3= treeEntry.indexOf(',', index2 + 1); 508 if (index3 == -1) { 509 testCount= Integer.parseInt(treeEntry.substring(index2 + 1)); 510 isDynamicTest= false; 511 parentId= null; 512 displayName= null; 513 parameterTypes= null; 514 uniqueId= null; 515 } else { 516 testCount= Integer.parseInt(treeEntry.substring(index2 + 1, index3)); 517 518 int index4= treeEntry.indexOf(',', index3 + 1); 519 isDynamicTest= treeEntry.substring(index3 + 1, index4).equals("true"); //$NON-NLS-1$ 520 521 int index5= treeEntry.indexOf(',', index4 + 1); 522 parentId= treeEntry.substring(index4 + 1, index5); 523 if (parentId.equals("-1")) { //$NON-NLS-1$ 524 parentId= null; 525 } 526 527 int index6= scanTestName(treeEntry, index5 + 1, displayNameBuffer); 528 displayName= displayNameBuffer.toString().trim(); 529 if (displayName.equals(testName)) { 530 displayName= null; 531 } 532 533 int index7= scanTestName(treeEntry, index6 + 1, parameterTypesBuffer); 534 String parameterTypesString= parameterTypesBuffer.toString().trim(); 535 if (parameterTypesString.isEmpty()) { 536 parameterTypes= null; 537 } else { 538 parameterTypes= parameterTypesString.split(","); //$NON-NLS-1$ 539 Arrays.parallelSetAll(parameterTypes, i -> parameterTypes[i].trim()); 540 } 541 542 scanTestName(treeEntry, index7 + 1, uniqueIdBuffer); 543 uniqueId= uniqueIdBuffer.toString().trim(); 544 if (uniqueId.isEmpty()) { 545 uniqueId= null; 546 } 547 } 548 549 if (isDynamicTest) { 550 if (parentId != null) { 551 for (IncompleteTestSuite suite : fFactoryTestSuites) { 552 if (parentId.equals(suite.fTestSuiteElement.getId())) { 553 return createTestElement(suite.fTestSuiteElement, id, testName, isSuite, testCount, isDynamicTest, displayName, parameterTypes, uniqueId); 554 } 555 } 556 } 557 return createTestElement(getUnrootedSuite(), id, testName, isSuite, testCount, isDynamicTest, displayName, parameterTypes, uniqueId); // should not reach here 558 } else { 559 if (fIncompleteTestSuites.isEmpty()) { 560 return createTestElement(fTestRoot, id, testName, isSuite, testCount, isDynamicTest, displayName, parameterTypes, uniqueId); 561 } else { 562 int suiteIndex= fIncompleteTestSuites.size() - 1; 563 IncompleteTestSuite openSuite= fIncompleteTestSuites.get(suiteIndex); 564 openSuite.fOutstandingChildren--; 565 if (openSuite.fOutstandingChildren <= 0) 566 fIncompleteTestSuites.remove(suiteIndex); 567 return createTestElement(openSuite.fTestSuiteElement, id, testName, isSuite, testCount, isDynamicTest, displayName, parameterTypes, uniqueId); 568 } 569 } 570 } 571 createTestElement(TestSuiteElement parent, String id, String testName, boolean isSuite, int testCount, boolean isDynamicTest, String displayName, String[] parameterTypes, String uniqueId)572 public TestElement createTestElement(TestSuiteElement parent, String id, String testName, boolean isSuite, int testCount, boolean isDynamicTest, String displayName, String[] parameterTypes, String uniqueId) { 573 TestElement testElement; 574 if (parameterTypes != null && parameterTypes.length > 1) { 575 parameterTypes= Arrays.stream(parameterTypes).map(t -> t.trim()).toArray(String[]::new); 576 } 577 if (isSuite) { 578 TestSuiteElement testSuiteElement= new TestSuiteElement(parent, id, testName, testCount, displayName, parameterTypes, uniqueId); 579 testElement= testSuiteElement; 580 if (testCount > 0) { 581 fIncompleteTestSuites.add(new IncompleteTestSuite(testSuiteElement, testCount)); 582 } else if (fFactoryTestSuites != null) { 583 fFactoryTestSuites.add(new IncompleteTestSuite(testSuiteElement, testCount)); 584 } 585 } else { 586 testElement= new TestCaseElement(parent, id, testName, displayName, isDynamicTest, parameterTypes, uniqueId); 587 } 588 fIdToTest.put(id, testElement); 589 return testElement; 590 } 591 592 /** 593 * Append the test name from <code>s</code> to <code>testName</code>. 594 * 595 * @param s the string to scan 596 * @param start the offset of the first character in <code>s</code> 597 * @param testName the result 598 * 599 * @return the index of the next ',' 600 */ scanTestName(String s, int start, StringBuffer testName)601 private int scanTestName(String s, int start, StringBuffer testName) { 602 boolean inQuote= false; 603 int i= start; 604 for (; i < s.length(); i++) { 605 char c= s.charAt(i); 606 if (c == '\\' && !inQuote) { 607 inQuote= true; 608 continue; 609 } else if (inQuote) { 610 inQuote= false; 611 testName.append(c); 612 } else if (c == ',') 613 break; 614 else 615 testName.append(c); 616 } 617 return i; 618 } 619 getUnrootedSuite()620 private TestSuiteElement getUnrootedSuite() { 621 if (fUnrootedSuite == null) { 622 fUnrootedSuite= (TestSuiteElement) createTestElement(fTestRoot, "-2", JUnitMessages.TestRunSession_unrootedTests, true, 0, false, JUnitMessages.TestRunSession_unrootedTests, null, null); //$NON-NLS-1$ 623 } 624 return fUnrootedSuite; 625 } 626 627 /** 628 * An {@link ITestRunListener2} that listens to events from the 629 * {@link RemoteTestRunnerClient} and translates them into high-level model 630 * events (broadcasted to {@link ITestSessionListener}s). 631 */ 632 private class TestSessionNotifier implements ITestRunListener2 { 633 634 @Override testRunStarted(int testCount)635 public void testRunStarted(int testCount) { 636 fIncompleteTestSuites= new ArrayList<>(); 637 fFactoryTestSuites= new ArrayList<>(); 638 639 fStartedCount= 0; 640 fIgnoredCount= 0; 641 fFailureCount= 0; 642 fAssumptionFailureCount = 0; 643 fErrorCount= 0; 644 fTotalCount= testCount; 645 646 fStartTime= System.currentTimeMillis(); 647 fIsRunning= true; 648 649 for (ITestSessionListener listener : fSessionListeners) { 650 listener.sessionStarted(); 651 } 652 } 653 654 @Override testRunEnded(long elapsedTime)655 public void testRunEnded(long elapsedTime) { 656 fIsRunning= false; 657 658 for (ITestSessionListener listener : fSessionListeners) { 659 listener.sessionEnded(elapsedTime); 660 } 661 } 662 663 @Override testRunStopped(long elapsedTime)664 public void testRunStopped(long elapsedTime) { 665 fIsRunning= false; 666 fIsStopped= true; 667 668 for (ITestSessionListener listener : fSessionListeners) { 669 listener.sessionStopped(elapsedTime); 670 } 671 } 672 673 @Override testRunTerminated()674 public void testRunTerminated() { 675 fIsRunning= false; 676 fIsStopped= true; 677 678 for (ITestSessionListener listener : fSessionListeners) { 679 listener.sessionTerminated(); 680 } 681 } 682 683 @Override testTreeEntry(String description)684 public void testTreeEntry(String description) { 685 TestElement testElement= addTreeEntry(description); 686 687 for (ITestSessionListener listener : fSessionListeners) { 688 listener.testAdded(testElement); 689 } 690 } 691 createUnrootedTestElement(String testId, String testName)692 private TestElement createUnrootedTestElement(String testId, String testName) { 693 TestSuiteElement unrootedSuite= getUnrootedSuite(); 694 TestElement testElement= createTestElement(unrootedSuite, testId, testName, false, 1, false, testName, null, null); 695 696 for (ITestSessionListener listener : fSessionListeners) { 697 listener.testAdded(testElement); 698 } 699 700 return testElement; 701 } 702 703 @Override testStarted(String testId, String testName)704 public void testStarted(String testId, String testName) { 705 if (fStartedCount == 0) { 706 for (ITestSessionListener listener : fSessionListeners) { 707 listener.runningBegins(); 708 } 709 } 710 TestElement testElement= getTestElement(testId); 711 if (testElement == null) { 712 testElement= createUnrootedTestElement(testId, testName); 713 } else if (! (testElement instanceof TestCaseElement)) { 714 logUnexpectedTest(testId, testElement); 715 return; 716 } 717 TestCaseElement testCaseElement= (TestCaseElement) testElement; 718 setStatus(testCaseElement, Status.RUNNING); 719 720 if (testCaseElement.isDynamicTest()) { 721 fTotalCount++; 722 } 723 724 fStartedCount++; 725 726 for (ITestSessionListener listener : fSessionListeners) { 727 listener.testStarted(testCaseElement); 728 } 729 } 730 731 @Override testEnded(String testId, String testName)732 public void testEnded(String testId, String testName) { 733 boolean isIgnored= testName.startsWith(MessageIds.IGNORED_TEST_PREFIX); 734 735 TestElement testElement= getTestElement(testId); 736 if (testElement == null) { 737 testElement= createUnrootedTestElement(testId, testName); 738 } else if (! (testElement instanceof TestCaseElement)) { 739 if (isIgnored) { 740 testElement.setAssumptionFailed(true); 741 fAssumptionFailureCount++; 742 setStatus(testElement, Status.OK); 743 } else { 744 logUnexpectedTest(testId, testElement); 745 } 746 return; 747 } 748 TestCaseElement testCaseElement= (TestCaseElement) testElement; 749 if (isIgnored) { 750 testCaseElement.setIgnored(true); 751 fIgnoredCount++; 752 } 753 754 if (testCaseElement.getStatus() == Status.RUNNING) 755 setStatus(testCaseElement, Status.OK); 756 757 for (ITestSessionListener listener : fSessionListeners) { 758 listener.testEnded(testCaseElement); 759 } 760 } 761 762 763 @Override testFailed(int statusCode, String testId, String testName, String trace, String expected, String actual)764 public void testFailed(int statusCode, String testId, String testName, String trace, String expected, String actual) { 765 TestElement testElement= getTestElement(testId); 766 if (testElement == null) { 767 testElement= createUnrootedTestElement(testId, testName); 768 } 769 770 Status status; 771 if (testName.startsWith(MessageIds.ASSUMPTION_FAILED_TEST_PREFIX)) { 772 testElement.setAssumptionFailed(true); 773 fAssumptionFailureCount++; 774 status = Status.OK; 775 } else { 776 status= Status.convert(statusCode); 777 } 778 779 registerTestFailureStatus(testElement, status, trace, expected, actual); 780 781 for (ITestSessionListener listener : fSessionListeners) { 782 listener.testFailed(testElement, status, trace, expected, actual); 783 } 784 } 785 786 @Override testReran(String testId, String className, String testName, int statusCode, String trace, String expectedResult, String actualResult)787 public void testReran(String testId, String className, String testName, int statusCode, String trace, String expectedResult, String actualResult) { 788 TestElement testElement= getTestElement(testId); 789 if (testElement == null) { 790 testElement= createUnrootedTestElement(testId, testName); 791 } else if (! (testElement instanceof TestCaseElement)) { 792 logUnexpectedTest(testId, testElement); 793 return; 794 } 795 TestCaseElement testCaseElement= (TestCaseElement) testElement; 796 797 Status status= Status.convert(statusCode); 798 registerTestFailureStatus(testElement, status, trace, expectedResult, actualResult); 799 800 for (ITestSessionListener listener : fSessionListeners) { 801 //TODO: post old & new status? 802 listener.testReran(testCaseElement, status, trace, expectedResult, actualResult); 803 } 804 } 805 logUnexpectedTest(String testId, TestElement testElement)806 private void logUnexpectedTest(String testId, TestElement testElement) { 807 JUnitCorePlugin.log(new Exception("Unexpected TestElement type for testId '" + testId + "': " + testElement)); //$NON-NLS-1$ //$NON-NLS-2$ 808 } 809 } 810 811 private static class IncompleteTestSuite { 812 public TestSuiteElement fTestSuiteElement; 813 public int fOutstandingChildren; 814 IncompleteTestSuite(TestSuiteElement testSuiteElement, int outstandingChildren)815 public IncompleteTestSuite(TestSuiteElement testSuiteElement, int outstandingChildren) { 816 fTestSuiteElement= testSuiteElement; 817 fOutstandingChildren= outstandingChildren; 818 } 819 } 820 registerTestFailureStatus(TestElement testElement, Status status, String trace, String expected, String actual)821 public void registerTestFailureStatus(TestElement testElement, Status status, String trace, String expected, String actual) { 822 testElement.setStatus(status, trace, expected, actual); 823 if (!testElement.isAssumptionFailure()) { 824 if (status.isError()) { 825 fErrorCount++; 826 } else if (status.isFailure()) { 827 fFailureCount++; 828 } 829 } 830 } 831 registerTestEnded(TestElement testElement, boolean completed)832 public void registerTestEnded(TestElement testElement, boolean completed) { 833 if (testElement instanceof TestCaseElement) { 834 fTotalCount++; 835 if (! completed) { 836 return; 837 } 838 fStartedCount++; 839 if (((TestCaseElement) testElement).isIgnored()) { 840 fIgnoredCount++; 841 } 842 if (! testElement.getStatus().isErrorOrFailure()) 843 setStatus(testElement, Status.OK); 844 } 845 846 if (testElement.isAssumptionFailure()) { 847 fAssumptionFailureCount++; 848 } 849 } 850 setStatus(TestElement testElement, Status status)851 private void setStatus(TestElement testElement, Status status) { 852 testElement.setStatus(status); 853 } 854 getAllFailedTestElements()855 public TestElement[] getAllFailedTestElements() { 856 ArrayList<ITestElement> failures= new ArrayList<>(); 857 addFailures(failures, getTestRoot()); 858 return failures.toArray(new TestElement[failures.size()]); 859 } 860 addFailures(ArrayList<ITestElement> failures, ITestElement testElement)861 private void addFailures(ArrayList<ITestElement> failures, ITestElement testElement) { 862 Result testResult= testElement.getTestResult(true); 863 if (testResult == Result.ERROR || testResult == Result.FAILURE) { 864 failures.add(testElement); 865 } 866 if (testElement instanceof TestSuiteElement) { 867 TestSuiteElement testSuiteElement= (TestSuiteElement) testElement; 868 ITestElement[] children= testSuiteElement.getChildren(); 869 for (ITestElement child : children) { 870 addFailures(failures, child); 871 } 872 } 873 } 874 875 @Override getElapsedTimeInSeconds()876 public double getElapsedTimeInSeconds() { 877 if (fTestRoot == null) 878 return Double.NaN; 879 880 return fTestRoot.getElapsedTimeInSeconds(); 881 } 882 getIncludeTags()883 public String getIncludeTags() { 884 if (fLaunch != null) { 885 try { 886 ILaunchConfiguration launchConfig= fLaunch.getLaunchConfiguration(); 887 if (launchConfig != null) { 888 boolean hasIncludeTags= launchConfig.getAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_HAS_INCLUDE_TAGS, false); 889 if (hasIncludeTags) { 890 return launchConfig.getAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_INCLUDE_TAGS, EMPTY_STRING); 891 } 892 } 893 } catch (CoreException e) { 894 //ignore 895 } 896 return EMPTY_STRING; 897 } 898 return fIncludeTags; 899 } 900 getExcludeTags()901 public String getExcludeTags() { 902 if (fLaunch != null) { 903 try { 904 ILaunchConfiguration launchConfig= fLaunch.getLaunchConfiguration(); 905 if (launchConfig != null) { 906 boolean hasExcludeTags= launchConfig.getAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_HAS_EXCLUDE_TAGS, false); 907 if (hasExcludeTags) { 908 return launchConfig.getAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_EXCLUDE_TAGS, EMPTY_STRING); 909 } 910 } 911 } catch (CoreException e) { 912 //ignore 913 } 914 return EMPTY_STRING; 915 } 916 return fExcludeTags; 917 } 918 setIncludeTags(String includeTags)919 public void setIncludeTags(String includeTags) { 920 fIncludeTags= includeTags; 921 } 922 923 setExcludeTags(String excludeTags)924 public void setExcludeTags(String excludeTags) { 925 fExcludeTags= excludeTags; 926 } 927 928 @Override toString()929 public String toString() { 930 return fTestRunName + " " + DateFormat.getDateTimeInstance().format(new Date(fStartTime)); //$NON-NLS-1$ 931 } 932 } 933