1package org.testng.internal; 2 3import java.lang.reflect.Method; 4import java.util.Arrays; 5import java.util.Collection; 6import java.util.Collections; 7import java.util.Comparator; 8import java.util.List; 9import java.util.Map; 10import java.util.Set; 11import java.util.concurrent.atomic.AtomicInteger; 12import java.util.regex.Pattern; 13 14import org.testng.IClass; 15import org.testng.IRetryAnalyzer; 16import org.testng.ITestClass; 17import org.testng.ITestNGMethod; 18import org.testng.annotations.ITestOrConfiguration; 19import org.testng.collections.Lists; 20import org.testng.collections.Maps; 21import org.testng.collections.Sets; 22import org.testng.internal.annotations.IAnnotationFinder; 23import org.testng.xml.XmlClass; 24import org.testng.xml.XmlInclude; 25import org.testng.xml.XmlTest; 26 27/** 28 * Superclass to represent both @Test and @Configuration methods. 29 */ 30public abstract class BaseTestMethod implements ITestNGMethod { 31 private static final long serialVersionUID = -2666032602580652173L; 32 private static final Pattern SPACE_SEPARATOR_PATTERN = Pattern.compile(" +"); 33 34 /** 35 * The test class on which the test method was found. Note that this is not 36 * necessarily the declaring class. 37 */ 38 protected ITestClass m_testClass; 39 40 protected final transient Class<?> m_methodClass; 41 protected final transient ConstructorOrMethod m_method; 42 private transient String m_signature; 43 protected String m_id = ""; 44 protected long m_date = -1; 45 protected final transient IAnnotationFinder m_annotationFinder; 46 protected String[] m_groups = {}; 47 protected String[] m_groupsDependedUpon = {}; 48 protected String[] m_methodsDependedUpon = {}; 49 protected String[] m_beforeGroups = {}; 50 protected String[] m_afterGroups = {}; 51 private boolean m_isAlwaysRun; 52 private boolean m_enabled; 53 54 private final String m_methodName; 55 // If a depended group is not found 56 private String m_missingGroup; 57 private String m_description = null; 58 protected AtomicInteger m_currentInvocationCount = new AtomicInteger(0); 59 private int m_parameterInvocationCount = 1; 60 private IRetryAnalyzer m_retryAnalyzer = null; 61 private boolean m_skipFailedInvocations = true; 62 private long m_invocationTimeOut = 0L; 63 64 private List<Integer> m_invocationNumbers = Lists.newArrayList(); 65 private final List<Integer> m_failedInvocationNumbers = Collections.synchronizedList(Lists.<Integer>newArrayList()); 66 private long m_timeOut = 0; 67 68 private boolean m_ignoreMissingDependencies; 69 private int m_priority; 70 71 private XmlTest m_xmlTest; 72 private Object m_instance; 73 74 /** 75 * Constructs a <code>BaseTestMethod</code> TODO cquezel JavaDoc. 76 * 77 * @param method 78 * @param annotationFinder 79 * @param instance 80 */ 81 public BaseTestMethod(String methodName, Method method, IAnnotationFinder annotationFinder, Object instance) { 82 this(methodName, new ConstructorOrMethod(method), annotationFinder, instance); 83 } 84 85 public BaseTestMethod(String methodName, ConstructorOrMethod com, IAnnotationFinder annotationFinder, 86 Object instance) { 87 m_methodClass = com.getDeclaringClass(); 88 m_method = com; 89 m_methodName = methodName; 90 m_annotationFinder = annotationFinder; 91 m_instance = instance; 92 } 93 94 /** 95 * {@inheritDoc} 96 */ 97 @Override 98 public boolean isAlwaysRun() { 99 return m_isAlwaysRun; 100 } 101 102 /** 103 * TODO cquezel JavaDoc. 104 * 105 * @param alwaysRun 106 */ 107 protected void setAlwaysRun(boolean alwaysRun) { 108 m_isAlwaysRun = alwaysRun; 109 } 110 111 /** 112 * {@inheritDoc} 113 */ 114 @Override 115 public Class<?> getRealClass() { 116 return m_methodClass; 117 } 118 119 /** 120 * {@inheritDoc} 121 */ 122 @Override 123 public ITestClass getTestClass() { 124 return m_testClass; 125 } 126 127 /** 128 * {@inheritDoc} 129 */ 130 @Override 131 public void setTestClass(ITestClass tc) { 132 assert null != tc; 133 if (! tc.getRealClass().equals(m_method.getDeclaringClass())) { 134 assert m_method.getDeclaringClass().isAssignableFrom(tc.getRealClass()) : 135 "\nMISMATCH : " + tc.getRealClass() + " " + m_method.getDeclaringClass(); 136 } 137 m_testClass = tc; 138 } 139 140 @Override 141 public int compareTo(Object o) { 142 int result = -2; 143 Class<?> thisClass = getRealClass(); 144 Class<?> otherClass = ((ITestNGMethod) o).getRealClass(); 145 if (this == o) { 146 result = 0; 147 } else if (thisClass.isAssignableFrom(otherClass)) { 148 result = -1; 149 } else if (otherClass.isAssignableFrom(thisClass)) { 150 result = 1; 151 } else if (equals(o)) { 152 result = 0; 153 } 154 155 return result; 156 } 157 158 /** 159 * {@inheritDoc} 160 */ 161 @Override 162 public Method getMethod() { 163 return m_method.getMethod(); 164 } 165 166 /** 167 * {@inheritDoc} 168 */ 169 @Override 170 public String getMethodName() { 171 return m_methodName; 172 } 173 174 /** 175 * {@inheritDoc} 176 */ 177 @Override 178 public Object[] getInstances() { 179 return new Object[] { getInstance() }; 180 } 181 182 @Override 183 public Object getInstance() { 184 return m_instance; 185 } 186 187 /** 188 * {@inheritDoc} 189 */ 190 @Override 191 public long[] getInstanceHashCodes() { 192 return m_testClass.getInstanceHashCodes(); 193 } 194 195 /** 196 * {@inheritDoc} 197 * @return the addition of groups defined on the class and on this method. 198 */ 199 @Override 200 public String[] getGroups() { 201 return m_groups; 202 } 203 204 /** 205 * {@inheritDoc} 206 */ 207 @Override 208 public String[] getGroupsDependedUpon() { 209 return m_groupsDependedUpon; 210 } 211 212 /** 213 * {@inheritDoc} 214 */ 215 @Override 216 public String[] getMethodsDependedUpon() { 217 return m_methodsDependedUpon; 218 } 219 220 /** 221 * {@inheritDoc} 222 */ 223 @Override 224 public boolean isTest() { 225 return false; 226 } 227 228 /** 229 * {@inheritDoc} 230 */ 231 @Override 232 public boolean isBeforeSuiteConfiguration() { 233 return false; 234 } 235 236 /** 237 * {@inheritDoc} 238 */ 239 @Override 240 public boolean isAfterSuiteConfiguration() { 241 return false; 242 } 243 244 /** 245 * {@inheritDoc} 246 */ 247 @Override 248 public boolean isBeforeTestConfiguration() { 249 return false; 250 } 251 252 /** 253 * {@inheritDoc} 254 */ 255 @Override 256 public boolean isAfterTestConfiguration() { 257 return false; 258 } 259 260 /** 261 * {@inheritDoc} 262 */ 263 @Override 264 public boolean isBeforeGroupsConfiguration() { 265 return false; 266 } 267 268 /** 269 * {@inheritDoc} 270 */ 271 @Override 272 public boolean isAfterGroupsConfiguration() { 273 return false; 274 } 275 276 /** 277 * {@inheritDoc} 278 */ 279 @Override 280 public boolean isBeforeClassConfiguration() { 281 return false; 282 } 283 284 /** 285 * {@inheritDoc} 286 */ 287 @Override 288 public boolean isAfterClassConfiguration() { 289 return false; 290 } 291 292 /** 293 * {@inheritDoc} 294 */ 295 @Override 296 public boolean isBeforeMethodConfiguration() { 297 return false; 298 } 299 300 /** 301 * {@inheritDoc} 302 */ 303 @Override 304 public boolean isAfterMethodConfiguration() { 305 return false; 306 } 307 308 /** 309 * {@inheritDoc} 310 */ 311 @Override 312 public long getTimeOut() { 313 long result = m_timeOut != 0 ? m_timeOut : (m_xmlTest != null ? m_xmlTest.getTimeOut(0) : 0); 314 return result; 315 } 316 317 @Override 318 public void setTimeOut(long timeOut) { 319 m_timeOut = timeOut; 320 } 321 322 /** 323 * {@inheritDoc} 324 * @return the number of times this method needs to be invoked. 325 */ 326 @Override 327 public int getInvocationCount() { 328 return 1; 329 } 330 331 /** 332 * No-op. 333 */ 334 @Override 335 public void setInvocationCount(int counter) { 336 } 337 338 /** 339 * {@inheritDoc} 340 * @return the number of times this method or one of its clones must be invoked. 341 */ 342 @Override 343 public int getTotalInvocationCount() { 344 return 1; 345 } 346 347 /** 348 * {@inheritDoc} Default value for successPercentage. 349 */ 350 @Override 351 public int getSuccessPercentage() { 352 return 100; 353 } 354 355 /** 356 * {@inheritDoc} 357 */ 358 @Override 359 public String getId() { 360 return m_id; 361 } 362 363 /** 364 * {@inheritDoc} 365 */ 366 @Override 367 public void setId(String id) { 368 m_id = id; 369 } 370 371 372 /** 373 * {@inheritDoc} 374 * @return Returns the date. 375 */ 376 @Override 377 public long getDate() { 378 return m_date; 379 } 380 381 /** 382 * {@inheritDoc} 383 * @param date The date to set. 384 */ 385 @Override 386 public void setDate(long date) { 387 m_date = date; 388 } 389 390 /** 391 * {@inheritDoc} 392 */ 393 @Override 394 public boolean canRunFromClass(IClass testClass) { 395 return m_methodClass.isAssignableFrom(testClass.getRealClass()); 396 } 397 398 /** 399 * {@inheritDoc} Compares two BaseTestMethod using the test class then the associated 400 * Java Method. 401 */ 402 @Override 403 public boolean equals(Object obj) { 404 if (this == obj) { 405 return true; 406 } 407 if (obj == null) { 408 return false; 409 } 410 if (getClass() != obj.getClass()) { 411 return false; 412 } 413 414 BaseTestMethod other = (BaseTestMethod) obj; 415 416 boolean isEqual = m_testClass == null ? other.m_testClass == null 417 : other.m_testClass != null && 418 m_testClass.getRealClass().equals(other.m_testClass.getRealClass()) 419 && m_instance == other.getInstance(); 420 421 return isEqual && getConstructorOrMethod().equals(other.getConstructorOrMethod()); 422 } 423 424 /** 425 * {@inheritDoc} This implementation returns the associated Java Method's hash code. 426 * @return the associated Java Method's hash code. 427 */ 428 @Override 429 public int hashCode() { 430 return m_method.hashCode(); 431 } 432 433 protected void initGroups(Class<? extends ITestOrConfiguration> annotationClass) { 434 // 435 // Init groups 436 // 437 { 438 ITestOrConfiguration annotation = getAnnotationFinder().findAnnotation(getMethod(), annotationClass); 439 ITestOrConfiguration classAnnotation = getAnnotationFinder().findAnnotation(getMethod().getDeclaringClass(), annotationClass); 440 441 setGroups(getStringArray(null != annotation ? annotation.getGroups() : null, 442 null != classAnnotation ? classAnnotation.getGroups() : null)); 443 } 444 445 // 446 // Init groups depended upon 447 // 448 { 449 ITestOrConfiguration annotation = getAnnotationFinder().findAnnotation(getMethod(), annotationClass); 450 ITestOrConfiguration classAnnotation = getAnnotationFinder().findAnnotation(getMethod().getDeclaringClass(), annotationClass); 451 452 Map<String, Set<String>> xgd = calculateXmlGroupDependencies(m_xmlTest); 453 List<String> xmlGroupDependencies = Lists.newArrayList(); 454 for (String g : getGroups()) { 455 Set<String> gdu = xgd.get(g); 456 if (gdu != null) { 457 xmlGroupDependencies.addAll(gdu); 458 } 459 } 460 setGroupsDependedUpon( 461 getStringArray(null != annotation ? annotation.getDependsOnGroups() : null, 462 null != classAnnotation ? classAnnotation.getDependsOnGroups() : null), 463 xmlGroupDependencies); 464 465 String[] methodsDependedUpon = 466 getStringArray(null != annotation ? annotation.getDependsOnMethods() : null, 467 null != classAnnotation ? classAnnotation.getDependsOnMethods() : null); 468 // Qualify these methods if they don't have a package 469 for (int i = 0; i < methodsDependedUpon.length; i++) { 470 String m = methodsDependedUpon[i]; 471 if (!m.contains(".")) { 472 m = MethodHelper.calculateMethodCanonicalName(m_methodClass, methodsDependedUpon[i]); 473 methodsDependedUpon[i] = m != null ? m : methodsDependedUpon[i]; 474 } 475 } 476 setMethodsDependedUpon(methodsDependedUpon); 477 } 478 } 479 480 481 private static Map<String, Set<String>> calculateXmlGroupDependencies(XmlTest xmlTest) { 482 Map<String, Set<String>> result = Maps.newHashMap(); 483 if (xmlTest == null) { 484 return result; 485 } 486 487 for (Map.Entry<String, String> e : xmlTest.getXmlDependencyGroups().entrySet()) { 488 String name = e.getKey(); 489 String dependsOn = e.getValue(); 490 Set<String> set = result.get(name); 491 if (set == null) { 492 set = Sets.newHashSet(); 493 result.put(name, set); 494 } 495 set.addAll(Arrays.asList(SPACE_SEPARATOR_PATTERN.split(dependsOn))); 496 } 497 498 return result; 499 } 500 501 protected IAnnotationFinder getAnnotationFinder() { 502 return m_annotationFinder; 503 } 504 505 protected IClass getIClass() { 506 return m_testClass; 507 } 508 509 private String computeSignature() { 510 String classLong = m_method.getDeclaringClass().getName(); 511 String cls = classLong.substring(classLong.lastIndexOf(".") + 1); 512 StringBuilder result = new StringBuilder(cls).append(".").append(m_method.getName()).append("("); 513 int i = 0; 514 for (Class<?> p : m_method.getParameterTypes()) { 515 if (i++ > 0) { 516 result.append(", "); 517 } 518 result.append(p.getName()); 519 } 520 result.append(")"); 521 result.append("[pri:").append(getPriority()).append(", instance:").append(m_instance).append("]"); 522 523 return result.toString(); 524 } 525 526 protected String getSignature() { 527 if (m_signature == null) { 528 m_signature = computeSignature(); 529 } 530 return m_signature; 531 } 532 533 /** 534 * {@inheritDoc} 535 */ 536 @Override 537 public String toString() { 538 return getSignature(); 539 } 540 541 protected String[] getStringArray(String[] methodArray, String[] classArray) { 542 final Set<String> vResult = Sets.newHashSet(); 543 if (null != methodArray) { 544 Collections.addAll(vResult, methodArray); 545 } 546 if (null != classArray) { 547 Collections.addAll(vResult, classArray); 548 } 549 return vResult.toArray(new String[vResult.size()]); 550 } 551 552 protected void setGroups(String[] groups) { 553 m_groups = groups; 554 } 555 556 protected void setGroupsDependedUpon(String[] groups, Collection<String> xmlGroupDependencies) { 557 List<String> l = Lists.newArrayList(); 558 l.addAll(Arrays.asList(groups)); 559 l.addAll(xmlGroupDependencies); 560 m_groupsDependedUpon = l.toArray(new String[l.size()]); 561 } 562 563 protected void setMethodsDependedUpon(String[] methods) { 564 m_methodsDependedUpon = methods; 565 } 566 567 /** 568 * {@inheritDoc} 569 */ 570 @Override 571 public void addMethodDependedUpon(String method) { 572 String[] newMethods = new String[m_methodsDependedUpon.length + 1]; 573 newMethods[0] = method; 574 System.arraycopy(m_methodsDependedUpon, 0, newMethods, 1, m_methodsDependedUpon.length); 575 m_methodsDependedUpon = newMethods; 576 } 577 578 private static void ppp(String s) { 579 System.out.println("[BaseTestMethod] " + s); 580 } 581 582 /** Compares two ITestNGMethod by date. */ 583 public static final Comparator<?> DATE_COMPARATOR = new Comparator<Object>() { 584 @Override 585 public int compare(Object o1, Object o2) { 586 try { 587 ITestNGMethod m1 = (ITestNGMethod) o1; 588 ITestNGMethod m2 = (ITestNGMethod) o2; 589 return (int) (m1.getDate() - m2.getDate()); 590 } 591 catch(Exception ex) { 592 return 0; // TODO CQ document this logic 593 } 594 } 595 }; 596 597 /** 598 * {@inheritDoc} 599 */ 600 @Override 601 public String getMissingGroup() { 602 return m_missingGroup; 603 } 604 605 /** 606 * {@inheritDoc} 607 */ 608 @Override 609 public void setMissingGroup(String group) { 610 m_missingGroup = group; 611 } 612 613 /** 614 * {@inheritDoc} 615 */ 616 @Override 617 public int getThreadPoolSize() { 618 return 0; 619 } 620 621 /** 622 * No-op. 623 */ 624 @Override 625 public void setThreadPoolSize(int threadPoolSize) { 626 } 627 628 @Override 629 public void setDescription(String description) { 630 m_description = description; 631 } 632 633 /** 634 * {@inheritDoc} 635 */ 636 @Override 637 public String getDescription() { 638 return m_description; 639 } 640 641 public void setEnabled(boolean enabled) { 642 m_enabled = enabled; 643 } 644 645 @Override 646 public boolean getEnabled() { 647 return m_enabled; 648 } 649 650 /** 651 * {@inheritDoc} 652 */ 653 @Override 654 public String[] getBeforeGroups() { 655 return m_beforeGroups; 656 } 657 658 /** 659 * {@inheritDoc} 660 */ 661 @Override 662 public String[] getAfterGroups() { 663 return m_afterGroups; 664 } 665 666 @Override 667 public void incrementCurrentInvocationCount() { 668 m_currentInvocationCount.incrementAndGet(); 669 } 670 671 @Override 672 public int getCurrentInvocationCount() { 673 return m_currentInvocationCount.get(); 674 } 675 676 @Override 677 public void setParameterInvocationCount(int n) { 678 m_parameterInvocationCount = n; 679 } 680 681 @Override 682 public int getParameterInvocationCount() { 683 return m_parameterInvocationCount; 684 } 685 686 @Override 687 public abstract ITestNGMethod clone(); 688 689 @Override 690 public IRetryAnalyzer getRetryAnalyzer() { 691 return m_retryAnalyzer; 692 } 693 694 @Override 695 public void setRetryAnalyzer(IRetryAnalyzer retryAnalyzer) { 696 m_retryAnalyzer = retryAnalyzer; 697 } 698 699 @Override 700 public boolean skipFailedInvocations() { 701 return m_skipFailedInvocations; 702 } 703 704 @Override 705 public void setSkipFailedInvocations(boolean s) { 706 m_skipFailedInvocations = s; 707 } 708 709 public void setInvocationTimeOut(long timeOut) { 710 m_invocationTimeOut = timeOut; 711 } 712 713 @Override 714 public long getInvocationTimeOut() { 715 return m_invocationTimeOut; 716 } 717 718 @Override 719 public boolean ignoreMissingDependencies() { 720 return m_ignoreMissingDependencies; 721 } 722 723 @Override 724 public void setIgnoreMissingDependencies(boolean i) { 725 m_ignoreMissingDependencies = i; 726 } 727 728 @Override 729 public List<Integer> getInvocationNumbers() { 730 return m_invocationNumbers; 731 } 732 733 @Override 734 public void setInvocationNumbers(List<Integer> numbers) { 735 m_invocationNumbers = numbers; 736 } 737 738 @Override 739 public List<Integer> getFailedInvocationNumbers() { 740 return m_failedInvocationNumbers; 741 } 742 743 @Override 744 public void addFailedInvocationNumber(int number) { 745 m_failedInvocationNumbers.add(number); 746 } 747 748 @Override 749 public int getPriority() { 750 return m_priority; 751 } 752 753 @Override 754 public void setPriority(int priority) { 755 m_priority = priority; 756 } 757 758 @Override 759 public XmlTest getXmlTest() { 760 return m_xmlTest; 761 } 762 763 public void setXmlTest(XmlTest xmlTest) { 764 m_xmlTest = xmlTest; 765 } 766 767 @Override 768 public ConstructorOrMethod getConstructorOrMethod() { 769 return m_method; 770 } 771 772 @Override 773 public Map<String, String> findMethodParameters(XmlTest test) { 774 // Get the test+suite parameters 775 Map<String, String> result = test.getAllParameters(); 776 for (XmlClass xmlClass: test.getXmlClasses()) { 777 if (xmlClass.getName().equals(getTestClass().getName())) { 778 result.putAll(xmlClass.getLocalParameters()); 779 for (XmlInclude include : xmlClass.getIncludedMethods()) { 780 if (include.getName().equals(getMethodName())) { 781 result.putAll(include.getLocalParameters()); 782 break; 783 } 784 } 785 } 786 } 787 788 return result; 789 } 790} 791