1 package org.testng.internal;
2 
3 import java.lang.reflect.Method;
4 import java.util.Arrays;
5 import java.util.Collection;
6 import java.util.Collections;
7 import java.util.Comparator;
8 import java.util.List;
9 import java.util.Map;
10 import java.util.Set;
11 import java.util.concurrent.atomic.AtomicInteger;
12 import java.util.regex.Pattern;
13 
14 import org.testng.IClass;
15 import org.testng.IRetryAnalyzer;
16 import org.testng.ITestClass;
17 import org.testng.ITestNGMethod;
18 import org.testng.annotations.ITestOrConfiguration;
19 import org.testng.collections.Lists;
20 import org.testng.collections.Maps;
21 import org.testng.collections.Sets;
22 import org.testng.internal.annotations.IAnnotationFinder;
23 import org.testng.xml.XmlClass;
24 import org.testng.xml.XmlInclude;
25 import org.testng.xml.XmlTest;
26 
27 /**
28  * Superclass to represent both @Test and @Configuration methods.
29  */
30 public 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    */
BaseTestMethod(String methodName, Method method, IAnnotationFinder annotationFinder, Object instance)81   public BaseTestMethod(String methodName, Method method, IAnnotationFinder annotationFinder, Object instance) {
82     this(methodName, new ConstructorOrMethod(method), annotationFinder, instance);
83   }
84 
BaseTestMethod(String methodName, ConstructorOrMethod com, IAnnotationFinder annotationFinder, Object instance)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
isAlwaysRun()98   public boolean isAlwaysRun() {
99     return m_isAlwaysRun;
100   }
101 
102   /**
103    * TODO cquezel JavaDoc.
104    *
105    * @param alwaysRun
106    */
setAlwaysRun(boolean alwaysRun)107   protected void setAlwaysRun(boolean alwaysRun) {
108     m_isAlwaysRun = alwaysRun;
109   }
110 
111   /**
112    * {@inheritDoc}
113    */
114   @Override
getRealClass()115   public Class<?> getRealClass() {
116     return m_methodClass;
117   }
118 
119   /**
120    * {@inheritDoc}
121    */
122   @Override
getTestClass()123   public ITestClass getTestClass() {
124     return m_testClass;
125   }
126 
127   /**
128    * {@inheritDoc}
129    */
130   @Override
setTestClass(ITestClass tc)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
compareTo(Object o)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
getMethod()162   public Method getMethod() {
163     return m_method.getMethod();
164   }
165 
166   /**
167    * {@inheritDoc}
168    */
169   @Override
getMethodName()170   public String getMethodName() {
171     return m_methodName;
172   }
173 
174   /**
175    * {@inheritDoc}
176    */
177   @Override
getInstances()178   public Object[] getInstances() {
179     return new Object[] { getInstance() };
180   }
181 
182   @Override
getInstance()183   public Object getInstance() {
184     return m_instance;
185   }
186 
187   /**
188    * {@inheritDoc}
189    */
190   @Override
getInstanceHashCodes()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
getGroups()200   public String[] getGroups() {
201     return m_groups;
202   }
203 
204   /**
205    * {@inheritDoc}
206    */
207   @Override
getGroupsDependedUpon()208   public String[] getGroupsDependedUpon() {
209     return m_groupsDependedUpon;
210   }
211 
212   /**
213    * {@inheritDoc}
214    */
215   @Override
getMethodsDependedUpon()216   public String[] getMethodsDependedUpon() {
217     return m_methodsDependedUpon;
218   }
219 
220   /**
221    * {@inheritDoc}
222    */
223   @Override
isTest()224   public boolean isTest() {
225     return false;
226   }
227 
228   /**
229    * {@inheritDoc}
230    */
231   @Override
isBeforeSuiteConfiguration()232   public boolean isBeforeSuiteConfiguration() {
233     return false;
234   }
235 
236   /**
237    * {@inheritDoc}
238    */
239   @Override
isAfterSuiteConfiguration()240   public boolean isAfterSuiteConfiguration() {
241     return false;
242   }
243 
244   /**
245    * {@inheritDoc}
246    */
247   @Override
isBeforeTestConfiguration()248   public boolean isBeforeTestConfiguration() {
249     return false;
250   }
251 
252   /**
253    * {@inheritDoc}
254    */
255   @Override
isAfterTestConfiguration()256   public boolean isAfterTestConfiguration() {
257     return false;
258   }
259 
260   /**
261    * {@inheritDoc}
262    */
263   @Override
isBeforeGroupsConfiguration()264   public boolean isBeforeGroupsConfiguration() {
265     return false;
266   }
267 
268   /**
269    * {@inheritDoc}
270    */
271   @Override
isAfterGroupsConfiguration()272   public boolean isAfterGroupsConfiguration() {
273     return false;
274   }
275 
276   /**
277    * {@inheritDoc}
278    */
279   @Override
isBeforeClassConfiguration()280   public boolean isBeforeClassConfiguration() {
281     return false;
282   }
283 
284   /**
285    * {@inheritDoc}
286    */
287   @Override
isAfterClassConfiguration()288   public boolean isAfterClassConfiguration() {
289     return false;
290   }
291 
292   /**
293    * {@inheritDoc}
294    */
295   @Override
isBeforeMethodConfiguration()296   public boolean isBeforeMethodConfiguration() {
297     return false;
298   }
299 
300   /**
301    * {@inheritDoc}
302    */
303   @Override
isAfterMethodConfiguration()304   public boolean isAfterMethodConfiguration() {
305     return false;
306   }
307 
308   /**
309    * {@inheritDoc}
310    */
311   @Override
getTimeOut()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
setTimeOut(long timeOut)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
getInvocationCount()327   public int getInvocationCount() {
328     return 1;
329   }
330 
331   /**
332    * No-op.
333    */
334   @Override
setInvocationCount(int counter)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
getTotalInvocationCount()343   public int getTotalInvocationCount() {
344     return 1;
345   }
346 
347   /**
348    * {@inheritDoc} Default value for successPercentage.
349    */
350   @Override
getSuccessPercentage()351   public int getSuccessPercentage() {
352     return 100;
353   }
354 
355   /**
356    * {@inheritDoc}
357    */
358   @Override
getId()359   public String getId() {
360     return m_id;
361   }
362 
363   /**
364    * {@inheritDoc}
365    */
366   @Override
setId(String id)367   public void setId(String id) {
368     m_id = id;
369   }
370 
371 
372   /**
373    * {@inheritDoc}
374    * @return Returns the date.
375    */
376   @Override
getDate()377   public long getDate() {
378     return m_date;
379   }
380 
381   /**
382    * {@inheritDoc}
383    * @param date The date to set.
384    */
385   @Override
setDate(long date)386   public void setDate(long date) {
387     m_date = date;
388   }
389 
390   /**
391    * {@inheritDoc}
392    */
393   @Override
canRunFromClass(IClass testClass)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
equals(Object obj)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
hashCode()429   public int hashCode() {
430     return m_method.hashCode();
431   }
432 
initGroups(Class<? extends ITestOrConfiguration> annotationClass)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 
calculateXmlGroupDependencies(XmlTest xmlTest)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 
getAnnotationFinder()501   protected IAnnotationFinder getAnnotationFinder() {
502     return m_annotationFinder;
503   }
504 
getIClass()505   protected IClass getIClass() {
506     return m_testClass;
507   }
508 
computeSignature()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 
getSignature()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
toString()537   public String toString() {
538     return getSignature();
539   }
540 
getStringArray(String[] methodArray, String[] classArray)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 
setGroups(String[] groups)552   protected void setGroups(String[] groups) {
553     m_groups = groups;
554   }
555 
setGroupsDependedUpon(String[] groups, Collection<String> xmlGroupDependencies)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 
setMethodsDependedUpon(String[] methods)563   protected void setMethodsDependedUpon(String[] methods) {
564     m_methodsDependedUpon = methods;
565   }
566 
567   /**
568    * {@inheritDoc}
569    */
570   @Override
addMethodDependedUpon(String method)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 
ppp(String s)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
getMissingGroup()601   public String getMissingGroup() {
602     return m_missingGroup;
603   }
604 
605   /**
606    * {@inheritDoc}
607    */
608   @Override
setMissingGroup(String group)609   public void setMissingGroup(String group) {
610     m_missingGroup = group;
611   }
612 
613   /**
614    * {@inheritDoc}
615    */
616   @Override
getThreadPoolSize()617   public int getThreadPoolSize() {
618     return 0;
619   }
620 
621   /**
622    * No-op.
623    */
624   @Override
setThreadPoolSize(int threadPoolSize)625   public void setThreadPoolSize(int threadPoolSize) {
626   }
627 
628   @Override
setDescription(String description)629   public void setDescription(String description) {
630     m_description = description;
631   }
632 
633   /**
634    * {@inheritDoc}
635    */
636   @Override
getDescription()637   public String getDescription() {
638     return m_description;
639   }
640 
setEnabled(boolean enabled)641   public void setEnabled(boolean enabled) {
642     m_enabled = enabled;
643   }
644 
645   @Override
getEnabled()646   public boolean getEnabled() {
647     return m_enabled;
648   }
649 
650   /**
651    * {@inheritDoc}
652    */
653   @Override
getBeforeGroups()654   public String[] getBeforeGroups() {
655     return m_beforeGroups;
656   }
657 
658   /**
659    * {@inheritDoc}
660    */
661   @Override
getAfterGroups()662   public String[] getAfterGroups() {
663     return m_afterGroups;
664   }
665 
666   @Override
incrementCurrentInvocationCount()667   public void incrementCurrentInvocationCount() {
668     m_currentInvocationCount.incrementAndGet();
669   }
670 
671   @Override
getCurrentInvocationCount()672   public int getCurrentInvocationCount() {
673     return m_currentInvocationCount.get();
674   }
675 
676   @Override
setParameterInvocationCount(int n)677   public void setParameterInvocationCount(int n) {
678     m_parameterInvocationCount = n;
679   }
680 
681   @Override
getParameterInvocationCount()682   public int getParameterInvocationCount() {
683     return m_parameterInvocationCount;
684   }
685 
686   @Override
clone()687   public abstract ITestNGMethod clone();
688 
689   @Override
getRetryAnalyzer()690   public IRetryAnalyzer getRetryAnalyzer() {
691     return m_retryAnalyzer;
692   }
693 
694   @Override
setRetryAnalyzer(IRetryAnalyzer retryAnalyzer)695   public void setRetryAnalyzer(IRetryAnalyzer retryAnalyzer) {
696     m_retryAnalyzer = retryAnalyzer;
697   }
698 
699   @Override
skipFailedInvocations()700   public boolean skipFailedInvocations() {
701     return m_skipFailedInvocations;
702   }
703 
704   @Override
setSkipFailedInvocations(boolean s)705   public void setSkipFailedInvocations(boolean s) {
706     m_skipFailedInvocations = s;
707   }
708 
setInvocationTimeOut(long timeOut)709   public void setInvocationTimeOut(long timeOut) {
710     m_invocationTimeOut = timeOut;
711   }
712 
713   @Override
getInvocationTimeOut()714   public long getInvocationTimeOut() {
715     return m_invocationTimeOut;
716   }
717 
718   @Override
ignoreMissingDependencies()719   public boolean ignoreMissingDependencies() {
720     return m_ignoreMissingDependencies;
721   }
722 
723   @Override
setIgnoreMissingDependencies(boolean i)724   public void setIgnoreMissingDependencies(boolean i) {
725     m_ignoreMissingDependencies = i;
726   }
727 
728   @Override
getInvocationNumbers()729   public List<Integer> getInvocationNumbers() {
730     return m_invocationNumbers;
731   }
732 
733   @Override
setInvocationNumbers(List<Integer> numbers)734   public void setInvocationNumbers(List<Integer> numbers) {
735     m_invocationNumbers = numbers;
736   }
737 
738   @Override
getFailedInvocationNumbers()739   public List<Integer> getFailedInvocationNumbers() {
740     return m_failedInvocationNumbers;
741   }
742 
743   @Override
addFailedInvocationNumber(int number)744   public void addFailedInvocationNumber(int number) {
745     m_failedInvocationNumbers.add(number);
746   }
747 
748   @Override
getPriority()749   public int getPriority() {
750     return m_priority;
751   }
752 
753   @Override
setPriority(int priority)754   public void setPriority(int priority) {
755     m_priority = priority;
756   }
757 
758   @Override
getXmlTest()759   public XmlTest getXmlTest() {
760     return m_xmlTest;
761   }
762 
setXmlTest(XmlTest xmlTest)763   public void setXmlTest(XmlTest xmlTest) {
764     m_xmlTest = xmlTest;
765   }
766 
767   @Override
getConstructorOrMethod()768   public ConstructorOrMethod getConstructorOrMethod() {
769     return m_method;
770   }
771 
772   @Override
findMethodParameters(XmlTest test)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