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 XMLSuiteResultWriter(XMLReporterConfig config)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 */ writeSuiteResult(XMLStringBuffer xmlBuffer, ISuiteResult suiteResult)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 writeAllToBuffer(XMLStringBuffer xmlBuffer, ISuiteResult suiteResult)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") addAllTestResults(Set<ITestResult> testResults, IResultMap resultMap)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 referenceSuiteResult(XMLStringBuffer xmlBuffer, String parentDir, ISuiteResult suiteResult)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 getSuiteResultAttributes(ISuiteResult suiteResult)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 addTestResults(XMLStringBuffer xmlBuffer, Set<ITestResult> testResults)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 buildTestClassGroups(Set<ITestResult> testResults)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 addTestResult(XMLStringBuffer xmlBuffer, ITestResult testResult)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 getStatusString(int testResultStatus)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 getTestResultAttributes(ITestResult testResult)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 removeClassName(String methodSignature)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 addTestMethodParams(XMLStringBuffer xmlBuffer, ITestResult testResult)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 addParameter(XMLStringBuffer xmlBuffer, Object parameter, int i)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 addTestResultException(XMLStringBuffer xmlBuffer, ITestResult testResult)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 addTestResultOutput(XMLStringBuffer xmlBuffer, ITestResult testResult)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 addTestResultAttributes(XMLStringBuffer xmlBuffer, ITestResult testResult)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