Home | History | Annotate | Download | only in reporters
      1 package org.testng.reporters;
      2 
      3 import org.testng.IResultMap;
      4 import org.testng.ISuiteResult;
      5 import org.testng.ITestContext;
      6 import org.testng.ITestResult;
      7 import org.testng.Reporter;
      8 import org.testng.annotations.Test;
      9 import org.testng.collections.Lists;
     10 import org.testng.collections.Maps;
     11 import org.testng.collections.Sets;
     12 import org.testng.internal.ConstructorOrMethod;
     13 import org.testng.internal.Utils;
     14 import org.testng.util.Strings;
     15 
     16 import java.io.File;
     17 import java.text.SimpleDateFormat;
     18 import java.util.ArrayList;
     19 import java.util.Collections;
     20 import java.util.Comparator;
     21 import java.util.List;
     22 import java.util.Map;
     23 import java.util.Properties;
     24 import java.util.Set;
     25 
     26 /**
     27  * Utility writing an ISuiteResult to an XMLStringBuffer. Depending on the settings in the <code>config</code> property
     28  * it might generate an additional XML file with the actual content and only reference the file with an <code>url</code>
     29  * attribute in the passed XMLStringBuffer.
     30  *
     31  * @author Cosmin Marginean, Mar 16, 2007
     32  */
     33 
     34 public class XMLSuiteResultWriter {
     35 
     36   private XMLReporterConfig config;
     37 
     38   public XMLSuiteResultWriter(XMLReporterConfig config) {
     39     this.config = config;
     40   }
     41 
     42   /**
     43    * Writes the specified ISuiteResult in the given XMLStringBuffer. Please consider that depending on the settings in
     44    * the <code>config</code> property it might generate an additional XML file with the actual content and only
     45    * reference the file with an <code>url</code> attribute in the passed XMLStringBuffer.
     46    *
     47    * @param xmlBuffer   The XML buffer where to write or reference the suite result
     48    * @param suiteResult The <code>ISuiteResult</code> to serialize
     49    */
     50   public void writeSuiteResult(XMLStringBuffer xmlBuffer, ISuiteResult suiteResult) {
     51     if (XMLReporterConfig.FF_LEVEL_SUITE_RESULT != config.getFileFragmentationLevel()) {
     52       writeAllToBuffer(xmlBuffer, suiteResult);
     53     } else {
     54       String parentDir =
     55               config.getOutputDirectory() + File.separatorChar + suiteResult.getTestContext().getSuite().getName();
     56       File file = referenceSuiteResult(xmlBuffer, parentDir, suiteResult);
     57       XMLStringBuffer suiteXmlBuffer = new XMLStringBuffer();
     58       writeAllToBuffer(suiteXmlBuffer, suiteResult);
     59       Utils.writeUtf8File(file.getAbsoluteFile().getParent(), file.getName(), suiteXmlBuffer.toXML());
     60     }
     61   }
     62 
     63   private void writeAllToBuffer(XMLStringBuffer xmlBuffer, ISuiteResult suiteResult) {
     64     xmlBuffer.push(XMLReporterConfig.TAG_TEST, getSuiteResultAttributes(suiteResult));
     65     Set<ITestResult> testResults = Sets.newHashSet();
     66     ITestContext testContext = suiteResult.getTestContext();
     67     addAllTestResults(testResults, testContext.getPassedTests());
     68     addAllTestResults(testResults, testContext.getFailedTests());
     69     addAllTestResults(testResults, testContext.getSkippedTests());
     70     addAllTestResults(testResults, testContext.getPassedConfigurations());
     71     addAllTestResults(testResults, testContext.getSkippedConfigurations());
     72     addAllTestResults(testResults, testContext.getFailedConfigurations());
     73     addAllTestResults(testResults, testContext.getFailedButWithinSuccessPercentageTests());
     74     addTestResults(xmlBuffer, testResults);
     75     xmlBuffer.pop();
     76   }
     77 
     78   @SuppressWarnings("unchecked")
     79   private void addAllTestResults(Set<ITestResult> testResults, IResultMap resultMap) {
     80     if (resultMap != null) {
     81       // Sort the results chronologically before adding them
     82       List<ITestResult> allResults = new ArrayList<>();
     83       allResults.addAll(resultMap.getAllResults());
     84 
     85       Collections.sort(new ArrayList(allResults), new Comparator<ITestResult>() {
     86         @Override
     87         public int compare(ITestResult o1, ITestResult o2) {
     88           return (int) (o1.getStartMillis() - o2.getStartMillis());
     89         }
     90       });
     91 
     92       testResults.addAll(allResults);
     93     }
     94   }
     95 
     96   private File referenceSuiteResult(XMLStringBuffer xmlBuffer, String parentDir, ISuiteResult suiteResult) {
     97     Properties attrs = new Properties();
     98     String suiteResultName = suiteResult.getTestContext().getName() + ".xml";
     99     attrs.setProperty(XMLReporterConfig.ATTR_URL, suiteResultName);
    100     xmlBuffer.addEmptyElement(XMLReporterConfig.TAG_TEST, attrs);
    101     return new File(parentDir + File.separatorChar + suiteResultName);
    102   }
    103 
    104   private Properties getSuiteResultAttributes(ISuiteResult suiteResult) {
    105     Properties attributes = new Properties();
    106     ITestContext tc = suiteResult.getTestContext();
    107     attributes.setProperty(XMLReporterConfig.ATTR_NAME, tc.getName());
    108     XMLReporter.addDurationAttributes(config, attributes, tc.getStartDate(), tc.getEndDate());
    109     return attributes;
    110   }
    111 
    112   private void addTestResults(XMLStringBuffer xmlBuffer, Set<ITestResult> testResults) {
    113     Map<String, List<ITestResult>> testsGroupedByClass = buildTestClassGroups(testResults);
    114     for (Map.Entry<String, List<ITestResult>> result : testsGroupedByClass.entrySet()) {
    115       Properties attributes = new Properties();
    116       String className = result.getKey();
    117       if (config.isSplitClassAndPackageNames()) {
    118         int dot = className.lastIndexOf('.');
    119         attributes.setProperty(XMLReporterConfig.ATTR_NAME,
    120                 dot > -1 ? className.substring(dot + 1, className.length()) : className);
    121         attributes.setProperty(XMLReporterConfig.ATTR_PACKAGE, dot > -1 ? className.substring(0, dot) : "[default]");
    122       } else {
    123         attributes.setProperty(XMLReporterConfig.ATTR_NAME, className);
    124       }
    125 
    126       xmlBuffer.push(XMLReporterConfig.TAG_CLASS, attributes);
    127       List<ITestResult> sortedResults = result.getValue();
    128       Collections.sort( sortedResults );
    129       for (ITestResult testResult : sortedResults) {
    130         addTestResult(xmlBuffer, testResult);
    131       }
    132       xmlBuffer.pop();
    133     }
    134   }
    135 
    136   private Map<String, List<ITestResult>> buildTestClassGroups(Set<ITestResult> testResults) {
    137     Map<String, List<ITestResult>> map = Maps.newHashMap();
    138     for (ITestResult result : testResults) {
    139       String className = result.getTestClass().getName();
    140       List<ITestResult> list = map.get(className);
    141       if (list == null) {
    142         list = Lists.newArrayList();
    143         map.put(className, list);
    144       }
    145       list.add(result);
    146     }
    147     return map;
    148   }
    149 
    150   private void addTestResult(XMLStringBuffer xmlBuffer, ITestResult testResult) {
    151     Properties attribs = getTestResultAttributes(testResult);
    152     attribs.setProperty(XMLReporterConfig.ATTR_STATUS, getStatusString(testResult.getStatus()));
    153     xmlBuffer.push(XMLReporterConfig.TAG_TEST_METHOD, attribs);
    154     addTestMethodParams(xmlBuffer, testResult);
    155     addTestResultException(xmlBuffer, testResult);
    156     addTestResultOutput(xmlBuffer, testResult);
    157     if (config.isGenerateTestResultAttributes()) {
    158       addTestResultAttributes(xmlBuffer, testResult);
    159     }
    160     xmlBuffer.pop();
    161   }
    162 
    163   private String getStatusString(int testResultStatus) {
    164     switch (testResultStatus) {
    165       case ITestResult.SUCCESS:
    166         return "PASS";
    167       case ITestResult.FAILURE:
    168         return "FAIL";
    169       case ITestResult.SKIP:
    170         return "SKIP";
    171       case ITestResult.SUCCESS_PERCENTAGE_FAILURE:
    172         return "SUCCESS_PERCENTAGE_FAILURE";
    173     }
    174     return null;
    175   }
    176 
    177   private Properties getTestResultAttributes(ITestResult testResult) {
    178     Properties attributes = new Properties();
    179     if (!testResult.getMethod().isTest()) {
    180       attributes.setProperty(XMLReporterConfig.ATTR_IS_CONFIG, "true");
    181     }
    182     attributes.setProperty(XMLReporterConfig.ATTR_NAME, testResult.getMethod().getMethodName());
    183     String testInstanceName = testResult.getTestName();
    184     if (null != testInstanceName) {
    185       attributes.setProperty(XMLReporterConfig.ATTR_TEST_INSTANCE_NAME, testInstanceName);
    186     }
    187     String description = testResult.getMethod().getDescription();
    188     if (!Utils.isStringEmpty(description)) {
    189       attributes.setProperty(XMLReporterConfig.ATTR_DESC, description);
    190     }
    191 
    192     attributes.setProperty(XMLReporterConfig.ATTR_METHOD_SIG, removeClassName(testResult.getMethod().toString()));
    193 
    194     SimpleDateFormat format = new SimpleDateFormat(config.getTimestampFormat());
    195     String startTime = format.format(testResult.getStartMillis());
    196     String endTime = format.format(testResult.getEndMillis());
    197     attributes.setProperty(XMLReporterConfig.ATTR_STARTED_AT, startTime);
    198     attributes.setProperty(XMLReporterConfig.ATTR_FINISHED_AT, endTime);
    199     long duration = testResult.getEndMillis() - testResult.getStartMillis();
    200     String strDuration = Long.toString(duration);
    201     attributes.setProperty(XMLReporterConfig.ATTR_DURATION_MS, strDuration);
    202 
    203     if (config.isGenerateGroupsAttribute()) {
    204       String groupNamesStr = Utils.arrayToString(testResult.getMethod().getGroups());
    205       if (!Utils.isStringEmpty(groupNamesStr)) {
    206         attributes.setProperty(XMLReporterConfig.ATTR_GROUPS, groupNamesStr);
    207       }
    208     }
    209 
    210     if (config.isGenerateDependsOnMethods()) {
    211       String dependsOnStr = Utils.arrayToString(testResult.getMethod().getMethodsDependedUpon());
    212       if (!Utils.isStringEmpty(dependsOnStr)) {
    213         attributes.setProperty(XMLReporterConfig.ATTR_DEPENDS_ON_METHODS, dependsOnStr);
    214       }
    215     }
    216 
    217     if (config.isGenerateDependsOnGroups()) {
    218       String dependsOnStr = Utils.arrayToString(testResult.getMethod().getGroupsDependedUpon());
    219       if (!Utils.isStringEmpty(dependsOnStr)) {
    220         attributes.setProperty(XMLReporterConfig.ATTR_DEPENDS_ON_GROUPS, dependsOnStr);
    221       }
    222     }
    223 
    224     ConstructorOrMethod cm = testResult.getMethod().getConstructorOrMethod();
    225     Test testAnnotation;
    226     if (cm.getMethod() != null) {
    227       testAnnotation = cm.getMethod().getAnnotation(Test.class);
    228       if (testAnnotation != null) {
    229         String dataProvider = testAnnotation.dataProvider();
    230         if (!Strings.isNullOrEmpty(dataProvider)) {
    231           attributes.setProperty(XMLReporterConfig.ATTR_DATA_PROVIDER, dataProvider);
    232         }
    233       }
    234     }
    235 
    236     return attributes;
    237   }
    238 
    239   private String removeClassName(String methodSignature) {
    240     int firstParanthesisPos = methodSignature.indexOf("(");
    241     int dotAferClassPos = methodSignature.substring(0, firstParanthesisPos).lastIndexOf(".");
    242     return methodSignature.substring(dotAferClassPos + 1, methodSignature.length());
    243   }
    244 
    245   public void addTestMethodParams(XMLStringBuffer xmlBuffer, ITestResult testResult) {
    246     Object[] parameters = testResult.getParameters();
    247     if ((parameters != null) && (parameters.length > 0)) {
    248       xmlBuffer.push(XMLReporterConfig.TAG_PARAMS);
    249       for (int i = 0; i < parameters.length; i++) {
    250         addParameter(xmlBuffer, parameters[i], i);
    251       }
    252       xmlBuffer.pop();
    253     }
    254   }
    255 
    256   private void addParameter(XMLStringBuffer xmlBuffer, Object parameter, int i) {
    257     Properties attrs = new Properties();
    258     attrs.setProperty(XMLReporterConfig.ATTR_INDEX, String.valueOf(i));
    259     xmlBuffer.push(XMLReporterConfig.TAG_PARAM, attrs);
    260     if (parameter == null) {
    261       Properties valueAttrs = new Properties();
    262       valueAttrs.setProperty(XMLReporterConfig.ATTR_IS_NULL, "true");
    263       xmlBuffer.addEmptyElement(XMLReporterConfig.TAG_PARAM_VALUE, valueAttrs);
    264     } else {
    265       xmlBuffer.push(XMLReporterConfig.TAG_PARAM_VALUE);
    266       xmlBuffer.addCDATA(parameter.toString());
    267       xmlBuffer.pop();
    268     }
    269     xmlBuffer.pop();
    270   }
    271 
    272   private void addTestResultException(XMLStringBuffer xmlBuffer, ITestResult testResult) {
    273     Throwable exception = testResult.getThrowable();
    274     if (exception != null) {
    275       Properties exceptionAttrs = new Properties();
    276       exceptionAttrs.setProperty(XMLReporterConfig.ATTR_CLASS, exception.getClass().getName());
    277       xmlBuffer.push(XMLReporterConfig.TAG_EXCEPTION, exceptionAttrs);
    278 
    279       if (!Utils.isStringEmpty(exception.getMessage())) {
    280         xmlBuffer.push(XMLReporterConfig.TAG_MESSAGE);
    281         xmlBuffer.addCDATA(exception.getMessage());
    282         xmlBuffer.pop();
    283       }
    284 
    285       String[] stackTraces = Utils.stackTrace(exception, false);
    286       if ((config.getStackTraceOutputMethod() & XMLReporterConfig.STACKTRACE_SHORT) == XMLReporterConfig
    287               .STACKTRACE_SHORT) {
    288         xmlBuffer.push(XMLReporterConfig.TAG_SHORT_STACKTRACE);
    289         xmlBuffer.addCDATA(stackTraces[0]);
    290         xmlBuffer.pop();
    291       }
    292       if ((config.getStackTraceOutputMethod() & XMLReporterConfig.STACKTRACE_FULL) == XMLReporterConfig
    293               .STACKTRACE_FULL) {
    294         xmlBuffer.push(XMLReporterConfig.TAG_FULL_STACKTRACE);
    295         xmlBuffer.addCDATA(stackTraces[1]);
    296         xmlBuffer.pop();
    297       }
    298 
    299       xmlBuffer.pop();
    300     }
    301   }
    302 
    303   private void addTestResultOutput(XMLStringBuffer xmlBuffer, ITestResult testResult) {
    304     // TODO: Cosmin - maybe a <line> element isn't indicated for each line
    305     xmlBuffer.push(XMLReporterConfig.TAG_REPORTER_OUTPUT);
    306     List<String> output = Reporter.getOutput(testResult);
    307     for (String line : output) {
    308       if (line != null) {
    309         xmlBuffer.push(XMLReporterConfig.TAG_LINE);
    310         xmlBuffer.addCDATA(line);
    311         xmlBuffer.pop();
    312       }
    313     }
    314     xmlBuffer.pop();
    315   }
    316 
    317   private void addTestResultAttributes(XMLStringBuffer xmlBuffer, ITestResult testResult) {
    318     if (testResult.getAttributeNames() != null && testResult.getAttributeNames().size() > 0) {
    319       xmlBuffer.push(XMLReporterConfig.TAG_ATTRIBUTES);
    320       for (String attrName: testResult.getAttributeNames()) {
    321         if (attrName == null) {
    322           continue;
    323         }
    324         Object attrValue = testResult.getAttribute(attrName);
    325 
    326         Properties attributeAttrs = new Properties();
    327         attributeAttrs.setProperty(XMLReporterConfig.ATTR_NAME, attrName);
    328         if (attrValue == null) {
    329           attributeAttrs.setProperty(XMLReporterConfig.ATTR_IS_NULL, "true");
    330           xmlBuffer.addEmptyElement(XMLReporterConfig.TAG_ATTRIBUTE, attributeAttrs);
    331         } else {
    332           xmlBuffer.push(XMLReporterConfig.TAG_ATTRIBUTE, attributeAttrs);
    333           xmlBuffer.addCDATA(attrValue.toString());
    334           xmlBuffer.pop();
    335         }
    336       }
    337       xmlBuffer.pop();
    338     }
    339   }
    340 
    341 }
    342