package fitnesse.reporting.history; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; import static org.mockito.Mockito.mock; import java.io.IOException; import java.io.StringWriter; import java.io.Writer; import java.text.ParseException; import java.util.LinkedList; import fitnesse.responders.run.SuiteResponder; import fitnesse.testrunner.WikiTestPage; import fitnesse.testsystems.ExecutionLogListener; import fitnesse.testutil.FitNesseUtil; import fitnesse.util.XmlUtil; import org.junit.After; import org.junit.Before; import org.junit.Test; import fitnesse.util.Clock; import fitnesse.util.DateAlteringClock; import fitnesse.util.DateTimeUtil; import fitnesse.FitNesseContext; import fitnesse.reporting.history.TestExecutionReport.TestResult; import fitnesse.reporting.history.TestXmlFormatter.WriterFactory; import fitnesse.testsystems.TestSummary; import fitnesse.wiki.PageData; import fitnesse.wiki.WikiPage; import fitnesse.wiki.WikiPageDummy; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.xml.sax.SAXException; public class TestXmlFormatterTest { private static final String TEST_TIME = "4/13/2009 15:21:43"; private DateAlteringClock clock; private FitNesseContext context; @Before public void setUp() throws ParseException { clock = new DateAlteringClock(DateTimeUtil.getDateFromString(TEST_TIME)).freeze(); context = FitNesseUtil.makeTestContext(); } @After public void tearDown() { Clock.restoreDefaultClock(); } @Test public void makeFileName() throws Exception { TestSummary summary = new TestSummary(1, 2, 3, 4); assertEquals( "20090413152143_1_2_3_4.xml", SuiteResponder.makeResultFileName(summary, clock.currentClockTimeInMillis())); } @Test public void processTestResultsShouldBuildUpCurrentResultAndFinalSummary() throws Exception { FitNesseContext context = FitNesseUtil.makeTestContext(); WikiTestPage page = new WikiTestPage(new WikiPageDummy("name", "content", null)); page.getData().setAttribute(PageData.PropertySUITES, "tag1"); WriterFactory writerFactory = mock(WriterFactory.class); final TestResult testResult = new TestResult(); TestXmlFormatter formatter = new TestXmlFormatter(context , page.getSourcePage(), writerFactory) { @Override protected TestResult newTestResult() { return testResult; } @Override protected void writeResults() throws IOException { } }; final long startTime = clock.currentClockTimeInMillis(); formatter.testOutputChunk("outputChunk"); formatter.testStarted(page); clock.elapse(27); TestSummary summary = new TestSummary(9,8,7,6); formatter.testComplete(page, summary); formatter.close(); assertThat(formatter.testResponse.getFinalCounts(), equalTo(new TestSummary(0, 1, 0, 0))); assertThat(formatter.testResponse.getResults().size(), is(1)); assertThat(formatter.testResponse.getResults().get(0), is(testResult)); assertThat(testResult.startTime, is(startTime)); assertThat(testResult.content, is("outputChunk")); assertThat(testResult.right, is("9")); assertThat(testResult.wrong, is("8")); assertThat(testResult.ignores, is("7")); assertThat(testResult.exceptions, is("6")); assertThat(testResult.runTimeInMillis, is("27")); assertThat(testResult.relativePageName, is(page.getName())); assertThat(testResult.tags, is("tag1")); } @Test public void allTestingCompleteShouldSetTotalRunTime() throws Exception { FitNesseContext context = mock(FitNesseContext.class); WikiPage page = new WikiPageDummy("name", "content", null); WriterFactory writerFactory = mock(WriterFactory.class); TestXmlFormatter formatter = new TestXmlFormatter(context , page, writerFactory) { @Override protected void writeResults() { } }; formatter.testStarted(new WikiTestPage(page)); clock.elapse(77L); formatter.close(); assertThat(formatter.testResponse.getTotalRunTimeInMillis(), is(77L)); } @Test public void allExecutionOutputShouldBeAddedToHistory() throws IOException, SAXException { FitNesseContext context = FitNesseUtil.makeTestContext(); WikiPage page = new WikiPageDummy("name", "content", null); final LinkedList<StringWriter> writers = new LinkedList<>(); TestXmlFormatter formatter = new TestXmlFormatter(context, page, new WriterFactory() { @Override public Writer getWriter(FitNesseContext context, WikiPage page, TestSummary counts, long time) throws IOException { StringWriter w = new StringWriter(); writers.add(w); return w; } }); WikiTestPage testPage = new WikiTestPage(page); formatter.commandStarted(new ExecutionLogListener.ExecutionContext() { @Override public String getCommand() { return "commandLine"; } @Override public String getTestSystemName() { return "testSystem"; } }); formatter.stdOut("Command started"); formatter.testStarted(testPage); formatter.stdOut("After started"); clock.elapse(77L); formatter.testComplete(testPage, new TestSummary(1, 2, 3, 4)); formatter.exitCode(0); formatter.close(); String output = writers.get(0).toString(); Document document = XmlUtil.newDocument(output); Element testResultsElement = document.getDocumentElement(); assertEquals("testResults", testResultsElement.getNodeName()); Element executionLog = XmlUtil.getElementByTagName(testResultsElement, "executionLog"); Element command = XmlUtil.getElementByTagName(executionLog, "command"); Element stdOut = XmlUtil.getElementByTagName(executionLog, "stdOut"); Element exitCode = XmlUtil.getElementByTagName(executionLog, "exitCode"); assertEquals(output, "commandLine", command.getTextContent()); assertEquals(output, "Command started\nAfter started\n", stdOut.getTextContent()); assertEquals(output, "0", exitCode.getTextContent()); } @Test public void executionReportExceptionsAreThreadSafe() throws IOException { final TestXmlFormatter formatter = getTestXmlFormatterWithDummyWriter(); testThreadSaveOperation(formatter, new Runnable() { @Override public void run() { formatter.exceptionOccurred(new Exception("foo")); } }); } @Test public void executionReportResultsAreThreadSafe() throws IOException { final TestXmlFormatter formatter = getTestXmlFormatterWithDummyWriter(); testThreadSaveOperation(formatter, new Runnable() { @Override public void run() { formatter.testStarted(new WikiTestPage(new WikiPageDummy("name", "content", null))); } }); } private void testThreadSaveOperation(TestXmlFormatter formatter, final Runnable target) throws IOException { final boolean[] sentinel = { true }; Thread dataInjector = new Thread(new Runnable() { @Override public void run() { while (sentinel[0]) { target.run(); Thread.yield(); } } }); dataInjector.setDaemon(true); dataInjector.start(); try { Thread.yield(); formatter.close(); } finally { sentinel[0] = false; } } private TestXmlFormatter getTestXmlFormatterWithDummyWriter() { return new TestXmlFormatter(context, new WikiPageDummy("name", "content", null), new WriterFactory() { @Override public Writer getWriter(FitNesseContext context, WikiPage page, TestSummary counts, long time) throws IOException { return new StringWriter(); } }); } }