package net.thucydides.core.reports.xml; import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.collect.Lists; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.mapper.CannotResolveClassException; import net.thucydides.core.model.TestOutcome; import net.thucydides.core.reports.AcceptanceTestLoader; import net.thucydides.core.reports.AcceptanceTestReporter; import net.thucydides.core.reports.OutcomeFormat; import net.thucydides.core.reports.TestOutcomes; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.*; import java.nio.charset.Charset; import java.util.List; import java.util.Locale; import static net.thucydides.core.model.ReportType.XML; /** * Generates acceptance test results in XML form. * */ public class XMLTestOutcomeReporter implements AcceptanceTestReporter, AcceptanceTestLoader { private File outputDirectory; private static final Logger LOGGER = LoggerFactory.getLogger(XMLTestOutcomeReporter.class); private transient String qualifier; public void setQualifier(final String qualifier) { this.qualifier = qualifier; } /** * We don't need any resources for XML reports. */ public void setResourceDirectory(final String resourceDirectoryPath) { } public String getName() { return "xml"; } @Override public Optional<OutcomeFormat> getFormat() { return Optional.of(OutcomeFormat.XML); } /** * Generate an XML report for a given test run. */ public File generateReportFor(final TestOutcome testOutcome, final TestOutcomes allTestOutcomes) throws IOException { TestOutcome storedTestOutcome = testOutcome.withQualifier(qualifier); Preconditions.checkNotNull(outputDirectory); XStream xstream = new XStream(); xstream.alias("acceptance-test-run", TestOutcome.class); xstream.registerConverter(usingXmlConverter()); String reportFilename = reportFor(storedTestOutcome); OutputStream outputStream = null; OutputStreamWriter writer = null; File report = new File(getOutputDirectory(), reportFilename); LOGGER.info("Generating XML report for {} to file {}", testOutcome.getTitle(), report.getAbsolutePath()); try { outputStream = new FileOutputStream(report); writer = new OutputStreamWriter(outputStream, Charset.forName("UTF-8")); xstream.toXML(storedTestOutcome, writer); LOGGER.info("XML report generated ({} bytes) {}",report.getAbsolutePath(),report.length()); } catch(IOException failedToWriteReport) { throw failedToWriteReport; } finally { writer.flush(); writer.close(); outputStream.close(); } return report; } private TestOutcomeConverter usingXmlConverter() { return new TestOutcomeConverter(); } private String reportFor(final TestOutcome testOutcome) { return testOutcome.withQualifier(qualifier).getReportName(XML); } public Optional<TestOutcome> loadReportFrom(final File reportFile) { InputStream input = null; InputStreamReader reader = null; try { XStream xstream = new XStream(); xstream.alias("acceptance-test-run", TestOutcome.class); xstream.registerConverter(usingXmlConverter()); input = new FileInputStream(reportFile); reader = new InputStreamReader(input, Charset.forName("UTF-8")); return Optional.of((TestOutcome) xstream.fromXML(reader)); } catch (CannotResolveClassException e) { LOGGER.warn("Tried to load a file that is not a thucydides report: " + reportFile); return Optional.absent(); } catch (FileNotFoundException e) { LOGGER.warn("Tried to load a file that is not a thucydides report: " + reportFile); return Optional.absent(); } finally { try { reader.close(); input.close(); } catch (IOException ignored) {} } } public File getOutputDirectory() { return outputDirectory; } public void setOutputDirectory(final File outputDirectory) { this.outputDirectory = outputDirectory; } public List<TestOutcome> loadReportsFrom(File outputDirectory) { File[] reportFiles = getAllXMLFilesFrom(outputDirectory); List<TestOutcome> testOutcomes = Lists.newArrayList(); if (reportFiles != null) { for (File reportFile : reportFiles) { testOutcomes.addAll(loadReportFrom(reportFile).asSet()); } } return testOutcomes; } private File[] getAllXMLFilesFrom(final File reportsDirectory) { return reportsDirectory.listFiles(new XmlFilenameFilter()); } private static final class XmlFilenameFilter implements FilenameFilter { public boolean accept(final File file, final String filename) { return filename.toLowerCase(Locale.getDefault()).endsWith(".xml"); } } }