// Copyright (C) 2003-2009 by Object Mentor, Inc. All rights reserved.
// Released under the terms of the CPL Common Public License version 1.0.
package fitnesse.responders.run;
import fitnesse.FitNesseContext;
import fitnesse.authentication.SecureOperation;
import fitnesse.authentication.SecureResponder;
import fitnesse.authentication.SecureTestOperation;
import fitnesse.http.Response;
import fitnesse.responders.ChunkingResponder;
import fitnesse.responders.run.formatters.*;
import fitnesse.responders.templateUtilities.HtmlPage;
import fitnesse.responders.templateUtilities.PageTitle;
import fitnesse.responders.testHistory.PageHistory;
import fitnesse.wiki.*;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.LinkedList;
import java.util.List;
public class TestResponder extends ChunkingResponder implements SecureResponder {
private static LinkedList<TestEventListener> eventListeners = new LinkedList<TestEventListener>();
protected PageData data;
protected CompositeFormatter formatters;
protected boolean isInteractive = false;
private volatile boolean isClosed = false;
private boolean fastTest = false;
private boolean remoteDebug = false;
protected TestSystem testSystem;
int exitCode;
public TestResponder() {
super();
formatters = new CompositeFormatter();
}
protected void doSending() throws Exception {
checkArguments();
data = page.getData();
createFormatters();
if (isInteractive) {
makeHtml().render(response.getWriter());
} else {
doExecuteTests();
}
closeHtmlResponse(exitCode);
}
public void doExecuteTests() throws Exception {
sendPreTestNotification();
performExecution();
exitCode = formatters.getErrorCount();
}
private HtmlPage makeHtml() {
PageCrawler pageCrawler = page.getPageCrawler();
WikiPagePath fullPath = pageCrawler.getFullPath(page);
String fullPathName = PathParser.render(fullPath);
HtmlPage htmlPage = context.pageFactory.newPage();
htmlPage.setTitle(getTitle() + ": " + fullPathName);
htmlPage.setPageTitle(new PageTitle(getTitle(), fullPath));
htmlPage.setNavTemplate("testNav.vm");
htmlPage.put("actions", new WikiPageActions(page).withPageHistory());
htmlPage.setMainTemplate(mainTemplate());
htmlPage.put("testExecutor", new TestExecutor());
htmlPage.setFooterTemplate("wikiFooter.vm");
htmlPage.put("footerContent", new WikiPageFooterRenderer());
WikiImportProperty.handleImportProperties(htmlPage, page, page.getData());
return htmlPage;
}
public class WikiPageFooterRenderer {
public String render() {
return WikiPageUtil.getFooterPageHtml(page);
}
}
public class TestExecutor {
public void execute() throws Exception {
doExecuteTests();
}
}
protected void checkArguments() {
fastTest |= request.hasInput("debug");
remoteDebug |= request.hasInput("remote_debug");
}
protected void createFormatters() {
if (response.isXmlFormat()) {
addXmlFormatter();
} else if (response.isTextFormat()) {
addTextFormatter();
} else if (response.isJavaFormat()) {
addJavaFormatter();
} else {
addHtmlFormatter();
isInteractive = true;
}
if (!request.hasInput("nohistory")) {
addTestHistoryFormatter();
}
addTestInProgressFormatter();
}
protected String getTitle() {
return "Test Results";
}
protected String mainTemplate() {
return "testPage";
}
void addXmlFormatter() {
XmlFormatter.WriterFactory writerSource = new XmlFormatter.WriterFactory() {
public Writer getWriter(FitNesseContext context, WikiPage page, TestSummary counts, long time) {
return response.getWriter();
}
};
formatters.add(new XmlFormatter(context, page, writerSource));
}
void addTextFormatter() {
formatters.add(new TestTextFormatter(response));
}
void addJavaFormatter() {
formatters.add(JavaFormatter.getInstance(new WikiPagePath(page).toString()));
}
void addHtmlFormatter() {
BaseFormatter formatter = new TestHtmlFormatter(context, page) {
@Override
protected void writeData(String output) {
addToResponse(output);
}
};
formatters.add(formatter);
}
protected void addTestHistoryFormatter() {
HistoryWriterFactory writerFactory = new HistoryWriterFactory();
formatters.add(new PageHistoryFormatter(context, page, writerFactory));
}
protected void addTestInProgressFormatter() {
formatters.add(new PageInProgressFormatter(context, page));
}
protected void sendPreTestNotification() throws Exception {
for (TestEventListener eventListener : eventListeners) {
eventListener.notifyPreTest(this, data);
}
}
protected void performExecution() throws Exception {
List<WikiPage> test2run = new SuiteContentsFinder(page, null, root).makePageListForSingleTest();
MultipleTestsRunner runner = new MultipleTestsRunner(test2run, context, page, formatters);
runner.setFastTest(fastTest);
runner.setDebug(isRemoteDebug());
if (isEmpty(page))
formatters.addMessageForBlankHtml();
runner.executeTestPages();
}
private boolean isEmpty(WikiPage page) throws Exception {
return page.getData().getContent().length() == 0;
}
public SecureOperation getSecureOperation() {
return new SecureTestOperation();
}
public static void registerListener(TestEventListener listener) {
eventListeners.add(listener);
}
public void setFastTest(boolean fastTest) {
this.fastTest = fastTest;
}
public boolean isFastTest() {
return fastTest;
}
public void addToResponse(String output) {
if (!isClosed()) {
response.add(output);
}
}
synchronized boolean isClosed() {
return isClosed;
}
synchronized void setClosed() {
isClosed = true;
}
void closeHtmlResponse(int exitCode) throws Exception {
if (!isClosed()) {
setClosed();
response.closeChunks();
response.addTrailingHeader("Exit-Code", String.valueOf(exitCode));
response.closeTrailer();
response.close();
}
}
void closeHtmlResponse() throws Exception {
if (!isClosed()) {
setClosed();
response.closeChunks();
response.close();
}
}
boolean isRemoteDebug() {
return remoteDebug;
}
public Response getResponse() {
return response;
}
public static class HistoryWriterFactory implements XmlFormatter.WriterFactory {
public Writer getWriter(FitNesseContext context, WikiPage page, TestSummary counts, long time) throws IOException {
File resultPath = new File(PageHistory.makePageHistoryFileName(context, page, counts, time));
File resultDirectory = new File(resultPath.getParent());
resultDirectory.mkdirs();
File resultFile = new File(resultDirectory, resultPath.getName());
return new FileWriter(resultFile);
}
}
}