package org.aitools.programd.test.aiml;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import org.aitools.programd.Core;
import org.aitools.util.resource.Filesystem;
import org.aitools.util.resource.URLTools;
import org.aitools.util.runtime.DeveloperError;
import org.apache.log4j.Logger;
/**
* A Tester loads one or more test suites and runs them, logging output.
*
* @author Albertas Mickensas
* @author <a href="mailto:noel@aitools.org">Noel Bush</a>
*/
public class Tester {
/** The test suites. */
private HashMap<String, TestSuite> suites = new HashMap<String, TestSuite>();
/** The test successes. */
private LinkedList<TestResult> successes = new LinkedList<TestResult>();
/** The test failures. */
private LinkedList<TestResult> failures = new LinkedList<TestResult>();
/** The Core that this Tester will use. */
private Core _core;
/** The logger to use. */
private Logger logger;
/** The pathspec for the test suites. */
private List<URL> suiteURLs;
/** The path to the test report directory. */
private URL testReportDirectory;
/** The timestamp format to use for reports. */
private static final SimpleDateFormat timestampFormat = new SimpleDateFormat("yyyy-MM-dd-H-mm-ss");
/**
* Loads all test suites from a given pathspec (may use wildcards).
*
* @param suiteList the list of suites
* @param core the Core to assign to the suites
* @param logger the logger to use for tracking progress
*
* @return the map of suite names to suites
*/
protected static HashMap<String, TestSuite> loadTests(List<URL> suiteList, Core core, Logger logger) {
HashMap<String, TestSuite> suites = new HashMap<String, TestSuite>();
for (URL path : suiteList) {
logger.info(String.format("Loading tests from \"%s\".", path));
TestSuite suite = TestSuite.load(path, core, logger);
suites.put(suite.getName(), suite);
}
return suites;
}
/**
* Creates a new Tester which will use the given Core to find out its configuration and run tests.
*
* @param core the Core to use for finding plugin configuration, active multiplexor, etc.
* @param testLogger the logger to which to send output
* @param suitePaths the test suites
* @param testReports the directory in which to store test reports
*/
public Tester(Core core, Logger testLogger, List<URL> suitePaths, URL testReports) {
this._core = core;
this.logger = testLogger;
this.suiteURLs = suitePaths;
try {
this.testReportDirectory = Filesystem.checkOrCreateDirectory(testReports.getFile(), "test report directory")
.getCanonicalFile().toURI().toURL();
}
catch (IOException e) {
assert false : "A directory that Filesystem found cannot be found anymore.";
}
}
/**
* Runs the tests in the given suite on the given botid, a given number of times.
*
* @param suite the suite to run
* @param botid the botid on whom to run the tests
* @param runCount the number of times to run the tests
* @return the path where the test report was written
*/
public String run(String botid, String suite, int runCount) {
this.suites.clear();
this.suites = loadTests(this.suiteURLs, this._core, this.logger);
if (null == botid) {
this.logger.warn("No botid defined for tests.");
return "";
}
if (this.suites.size() == 0) {
this.logger.warn("No suites defined.");
return "";
}
this.successes.clear();
this.failures.clear();
if (suite == null) {
this.runAllSuites(botid, runCount);
}
else {
this.runOneSuite(botid, suite, runCount);
}
TestReport report = new TestReport(this.successes, this.failures);
report.logSummary(this.logger);
String reportPath = URLTools.contextualize(this.testReportDirectory,
"test-report-" + timestampFormat.format(new Date()) + ".xml").getFile();
try {
report.write(reportPath);
}
catch (FileNotFoundException e) {
throw new DeveloperError(String.format("Bad path for test report: \"%s\".", reportPath), e);
}
catch (IOException e) {
throw new DeveloperError(String.format("Error writing test report: \"%s\".", reportPath), e);
}
return reportPath;
}
protected void runAllSuites(String botid, int runCount) {
for (int _runCount = runCount; _runCount > 0; _runCount--) {
for (TestSuite suite : this.suites.values()) {
this.runSuite(botid, suite);
}
}
}
protected void runOneSuite(String botid, String suiteName, int runCount) {
TestSuite suite = this.suites.get(suiteName);
if (suite == null) {
this.logger.warn(String.format("No suite \"%s\" could be found.", suiteName));
return;
}
for (int _runCount = runCount; _runCount > 0; _runCount--) {
this.runSuite(botid, suite);
}
}
protected void runSuite(String botId, TestSuite suite) {
suite.run(botId);
this.failures.addAll(suite.getFailures());
this.successes.addAll(suite.getSuccesses());
}
}