NIHVIVO-222 Create the output summary HTML before and after each test suite is run. Include information on pending suites.
This commit is contained in:
parent
f09fcee448
commit
a05c62e30a
10 changed files with 457 additions and 154 deletions
|
@ -17,6 +17,8 @@ import java.util.regex.Pattern;
|
|||
* Extract any summary information from the log file.
|
||||
*/
|
||||
public class LogStats {
|
||||
public static LogStats EMPTY_LOG_STATS = new LogStats();
|
||||
|
||||
private static final Pattern SUITE_NAME_PATTERN = Pattern
|
||||
.compile("Running suite (.*)");
|
||||
private static final Pattern ERROR_PATTERN = Pattern
|
||||
|
@ -35,6 +37,10 @@ public class LogStats {
|
|||
private final List<String> errors = new ArrayList<String>();
|
||||
private final List<String> warnings = new ArrayList<String>();
|
||||
|
||||
private LogStats() {
|
||||
// Nothing to initialize for empty instance.
|
||||
}
|
||||
|
||||
private LogStats(File logFile) {
|
||||
|
||||
BufferedReader reader = null;
|
||||
|
|
|
@ -9,6 +9,7 @@ import java.io.IOException;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import edu.cornell.mannlib.vitro.utilities.testrunner.datamodel.DataModel;
|
||||
import edu.cornell.mannlib.vitro.utilities.testrunner.listener.Listener;
|
||||
import edu.cornell.mannlib.vitro.utilities.testrunner.output.OutputManager;
|
||||
|
||||
|
@ -24,8 +25,7 @@ public class SeleniumRunner {
|
|||
private final ModelCleaner modelCleaner;
|
||||
private final SuiteRunner suiteRunner;
|
||||
private final OutputManager outputManager;
|
||||
|
||||
private final List<File> selectedSuites = new ArrayList<File>();
|
||||
private final DataModel dataModel;
|
||||
|
||||
public SeleniumRunner(SeleniumRunnerParameters parms) {
|
||||
this.parms = parms;
|
||||
|
@ -35,6 +35,7 @@ public class SeleniumRunner {
|
|||
this.modelCleaner = new ModelCleaner(parms, this.tomcatController);
|
||||
this.suiteRunner = new SuiteRunner(parms);
|
||||
this.outputManager = new OutputManager(parms);
|
||||
this.dataModel = new DataModel();
|
||||
|
||||
}
|
||||
|
||||
|
@ -45,7 +46,7 @@ public class SeleniumRunner {
|
|||
Listener listener = parms.getListener();
|
||||
IgnoredTests ignored = parms.getIgnoredTests();
|
||||
|
||||
this.selectedSuites.clear();
|
||||
List<File> suites = new ArrayList<File>();
|
||||
|
||||
for (File parentDir : parms.getSuiteParentDirectories()) {
|
||||
for (File suite : parms.findSuiteDirs(parentDir)) {
|
||||
|
@ -54,10 +55,12 @@ public class SeleniumRunner {
|
|||
listener.suiteIgnored(suite);
|
||||
} else {
|
||||
listener.suiteAdded(suite);
|
||||
this.selectedSuites.add(suite);
|
||||
suites.add(suite);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dataModel.setSelectedSuites(suites);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -76,8 +79,8 @@ public class SeleniumRunner {
|
|||
tomcatController.cleanup();
|
||||
|
||||
listener.runEndTime();
|
||||
Status status = outputManager.summarizeOutput();
|
||||
success = (status == Status.OK);
|
||||
outputManager.summarizeOutput(dataModel);
|
||||
success = (dataModel.getRunStatus() == Status.OK);
|
||||
} catch (IOException e) {
|
||||
listener.runFailed(e);
|
||||
success = false;
|
||||
|
@ -92,7 +95,8 @@ public class SeleniumRunner {
|
|||
}
|
||||
|
||||
public void runSelectedSuites() {
|
||||
for (File suiteDir : this.selectedSuites) {
|
||||
for (File suiteDir : dataModel.getSelectedSuites()) {
|
||||
outputManager.summarizeOutput(dataModel);
|
||||
listener.suiteStarted(suiteDir);
|
||||
try {
|
||||
if (parms.isCleanModel()) {
|
||||
|
|
|
@ -9,6 +9,11 @@ public enum Status {
|
|||
/** All tests passed, and there were no warnings or errors. */
|
||||
OK("good"),
|
||||
|
||||
/**
|
||||
* One or more tests have not been run yet.
|
||||
*/
|
||||
PENDING(""),
|
||||
|
||||
/**
|
||||
* Any test failure was ignored, and any messages were no worse than
|
||||
* warnings.
|
||||
|
@ -20,14 +25,23 @@ public enum Status {
|
|||
* generated.
|
||||
*/
|
||||
ERROR("bad");
|
||||
|
||||
|
||||
private final String htmlClass;
|
||||
|
||||
|
||||
private Status(String htmlClass) {
|
||||
this.htmlClass = htmlClass;
|
||||
}
|
||||
|
||||
|
||||
public String getHtmlClass() {
|
||||
return this.htmlClass;
|
||||
}
|
||||
|
||||
/** When combined, the more severe status (defined later) takes precedence. */
|
||||
public static Status combine(Status s1, Status s2) {
|
||||
if (s1.compareTo(s2) > 0) {
|
||||
return s1;
|
||||
} else {
|
||||
return s2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,273 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.utilities.testrunner.datamodel;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import edu.cornell.mannlib.vitro.utilities.testrunner.LogStats;
|
||||
import edu.cornell.mannlib.vitro.utilities.testrunner.Status;
|
||||
import edu.cornell.mannlib.vitro.utilities.testrunner.output.OutputDataListener;
|
||||
import edu.cornell.mannlib.vitro.utilities.testrunner.output.SuiteResults;
|
||||
import edu.cornell.mannlib.vitro.utilities.testrunner.output.SuiteResults.TestResults;
|
||||
|
||||
/**
|
||||
* Collect all that we know about suites, tests, and their current status.
|
||||
*/
|
||||
public class DataModel {
|
||||
|
||||
/* base data */
|
||||
private Collection<File> selectedSuites = Collections.emptyList();
|
||||
private Collection<SuiteResults> suiteResults = Collections.emptyList();
|
||||
private OutputDataListener.Info dataListenerInfo = OutputDataListener.Info.EMPTY_INFO;
|
||||
private LogStats logStats = LogStats.EMPTY_LOG_STATS; // TODO
|
||||
|
||||
/* derived data */
|
||||
private Status runStatus = Status.PENDING;
|
||||
|
||||
private final List<SuiteData> allSuiteData = new ArrayList<SuiteData>();
|
||||
private final List<SuiteData> pendingSuites = new ArrayList<SuiteData>();
|
||||
private final List<SuiteData> passingSuites = new ArrayList<SuiteData>();
|
||||
private final List<SuiteData> failingSuites = new ArrayList<SuiteData>();
|
||||
private final List<SuiteData> ignoredSuites = new ArrayList<SuiteData>();
|
||||
|
||||
private final List<TestResults> allTests = new ArrayList<TestResults>();
|
||||
private final List<TestResults> pendingTests = new ArrayList<TestResults>();
|
||||
private final List<TestResults> passingTests = new ArrayList<TestResults>();
|
||||
private final List<TestResults> failingTests = new ArrayList<TestResults>();
|
||||
private final List<TestResults> ignoredTests = new ArrayList<TestResults>();
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Constructor
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
public DataModel() {
|
||||
calculate();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Update the base data.
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
public void setSelectedSuites(Collection<File> selectedSuites) {
|
||||
this.selectedSuites = new ArrayList<File>(selectedSuites);
|
||||
calculate();
|
||||
}
|
||||
|
||||
public Collection<File> getSelectedSuites() {
|
||||
return new ArrayList<File>(selectedSuites);
|
||||
}
|
||||
|
||||
public void setSuiteResults(Collection<SuiteResults> suiteResults) {
|
||||
this.suiteResults = new ArrayList<SuiteResults>(suiteResults);
|
||||
calculate();
|
||||
}
|
||||
|
||||
public void captureDataListener(OutputDataListener dataListener) {
|
||||
this.dataListenerInfo = dataListener.getInfo();
|
||||
calculate();
|
||||
}
|
||||
|
||||
public void setLogStats(LogStats logStats) { // TODO
|
||||
this.logStats = logStats;
|
||||
calculate();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Keep the derived data current.
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Data in the model has been updated. Refresh all derived data.
|
||||
*/
|
||||
private void calculate() {
|
||||
// Clear all derived data.
|
||||
runStatus = Status.OK;
|
||||
|
||||
allSuiteData.clear();
|
||||
ignoredSuites.clear();
|
||||
pendingSuites.clear();
|
||||
failingSuites.clear();
|
||||
passingSuites.clear();
|
||||
|
||||
allTests.clear();
|
||||
ignoredTests.clear();
|
||||
pendingTests.clear();
|
||||
failingTests.clear();
|
||||
passingTests.clear();
|
||||
|
||||
/*
|
||||
* Suite data.
|
||||
*/
|
||||
Map<String, SuiteResults> resultsMap = new HashMap<String, SuiteResults>();
|
||||
for (SuiteResults result : suiteResults) {
|
||||
resultsMap.put(result.getName(), result);
|
||||
}
|
||||
|
||||
for (String name : dataListenerInfo.getSuiteNames()) {
|
||||
if (dataListenerInfo.getIgnoredSuiteNames().contains(name)) {
|
||||
allSuiteData.add(new SuiteData(name, true, null));
|
||||
} else if (resultsMap.containsKey(name)) {
|
||||
allSuiteData.add(new SuiteData(name, false, resultsMap
|
||||
.get(name)));
|
||||
} else {
|
||||
allSuiteData.add(new SuiteData(name, false, null));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Tallys of suites and tests.
|
||||
*/
|
||||
for (SuiteData sd : allSuiteData) {
|
||||
SuiteResults result = sd.getResults();
|
||||
if (result != null) {
|
||||
tallyTests(result);
|
||||
}
|
||||
|
||||
if (sd.isIgnored()) {
|
||||
ignoredSuites.add(sd);
|
||||
} else if (result == null) {
|
||||
pendingSuites.add(sd);
|
||||
} else if (result.getStatus() == Status.ERROR) {
|
||||
failingSuites.add(sd);
|
||||
} else {
|
||||
passingSuites.add(sd);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Overall status. Warnings in the log are scary, but ignored tests are
|
||||
* OK.
|
||||
*/
|
||||
if (logStats.hasErrors() || !failingSuites.isEmpty()) {
|
||||
runStatus = Status.ERROR;
|
||||
} else {
|
||||
if (logStats.hasWarnings()) {
|
||||
runStatus = Status.WARN;
|
||||
} else {
|
||||
if (!pendingSuites.isEmpty()) {
|
||||
runStatus = Status.PENDING;
|
||||
} else {
|
||||
runStatus = Status.OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Categorize all test results according to status.
|
||||
*/
|
||||
private void tallyTests(SuiteResults sResult) {
|
||||
for (TestResults tResult : sResult.getTests()) {
|
||||
allTests.add(tResult);
|
||||
switch (tResult.getStatus()) {
|
||||
case OK:
|
||||
passingTests.add(tResult);
|
||||
break;
|
||||
case PENDING:
|
||||
pendingTests.add(tResult);
|
||||
break;
|
||||
case WARN:
|
||||
ignoredTests.add(tResult);
|
||||
break;
|
||||
default: // Status.ERROR
|
||||
failingTests.add(tResult);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Access the derived data.
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
public Status getRunStatus() {
|
||||
return runStatus;
|
||||
}
|
||||
|
||||
public long getStartTime() {
|
||||
return dataListenerInfo.getStartTime();
|
||||
}
|
||||
|
||||
public long getEndTime() {
|
||||
return dataListenerInfo.getEndTime();
|
||||
}
|
||||
|
||||
public long getElapsedTime() {
|
||||
return dataListenerInfo.getElapsedTime();
|
||||
}
|
||||
|
||||
public boolean isAnyPasses() {
|
||||
return !(passingSuites.isEmpty() && passingTests.isEmpty());
|
||||
}
|
||||
|
||||
public boolean isAnyFailures() {
|
||||
return !(failingSuites.isEmpty() && failingTests.isEmpty());
|
||||
}
|
||||
|
||||
public boolean isAnyIgnores() {
|
||||
return !(ignoredSuites.isEmpty() && ignoredTests.isEmpty());
|
||||
}
|
||||
|
||||
public boolean isAnyPending() {
|
||||
return !pendingSuites.isEmpty();
|
||||
}
|
||||
|
||||
public int getTotalSuiteCount() {
|
||||
return allSuiteData.size();
|
||||
}
|
||||
|
||||
public int getPassingSuiteCount() {
|
||||
return passingSuites.size();
|
||||
}
|
||||
|
||||
public int getFailingSuiteCount() {
|
||||
return failingSuites.size();
|
||||
}
|
||||
|
||||
public int getIgnoredSuiteCount() {
|
||||
return ignoredSuites.size();
|
||||
}
|
||||
|
||||
public int getPendingSuitesCount() {
|
||||
return pendingSuites.size();
|
||||
}
|
||||
|
||||
public Collection<SuiteResults> getSuiteResults() {
|
||||
return Collections.unmodifiableCollection(suiteResults);
|
||||
}
|
||||
|
||||
public int getTotalTestCount() {
|
||||
return allTests.size();
|
||||
}
|
||||
|
||||
public int getPassingTestCount() {
|
||||
return passingTests.size();
|
||||
}
|
||||
|
||||
public int getFailingTestCount() {
|
||||
return failingTests.size();
|
||||
}
|
||||
|
||||
public int getIgnoredTestCount() {
|
||||
return ignoredTests.size();
|
||||
}
|
||||
|
||||
public Collection<TestResults> getAllTests() {
|
||||
return Collections.unmodifiableCollection(allTests);
|
||||
}
|
||||
|
||||
public Collection<TestResults> getFailingTests() {
|
||||
return Collections.unmodifiableCollection(failingTests);
|
||||
}
|
||||
|
||||
public Collection<TestResults> getIgnoredTests() {
|
||||
return Collections.unmodifiableCollection(ignoredTests);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.utilities.testrunner.datamodel;
|
||||
|
||||
import edu.cornell.mannlib.vitro.utilities.testrunner.output.SuiteResults;
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*/
|
||||
public class SuiteData {
|
||||
private final String name;
|
||||
private final boolean ignored;
|
||||
private final SuiteResults results;
|
||||
|
||||
public SuiteData(String name, boolean ignored, SuiteResults results) {
|
||||
this.name = name;
|
||||
this.ignored = ignored;
|
||||
this.results = results;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public boolean isIgnored() {
|
||||
return ignored;
|
||||
}
|
||||
|
||||
public SuiteResults getResults() {
|
||||
return results;
|
||||
}
|
||||
|
||||
}
|
|
@ -5,6 +5,7 @@ package edu.cornell.mannlib.vitro.utilities.testrunner.output;
|
|||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -50,35 +51,74 @@ public class OutputDataListener implements Listener {
|
|||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Accessor methods
|
||||
// A class that holds a snapshot of the data.
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
public boolean isRunCompleted() {
|
||||
return runCompleted;
|
||||
}
|
||||
/**
|
||||
* A snapshot of the data that the listener has accumulated so far.
|
||||
*/
|
||||
public static class Info {
|
||||
public static Info EMPTY_INFO = new Info();
|
||||
|
||||
public long getStartTime() {
|
||||
return startTime;
|
||||
}
|
||||
private final boolean runCompleted;
|
||||
private final long startTime;
|
||||
private final long endTime;
|
||||
private final List<String> suiteNames;
|
||||
private final List<String> ignoredSuiteNames;
|
||||
|
||||
public long getEndTime() {
|
||||
return endTime;
|
||||
}
|
||||
Info() {
|
||||
this.runCompleted = false;
|
||||
this.startTime = 0;
|
||||
this.endTime = 0;
|
||||
this.suiteNames = Collections.emptyList();
|
||||
this.ignoredSuiteNames = Collections.emptyList();
|
||||
}
|
||||
|
||||
public long getElapsedTime() {
|
||||
if ((startTime == 0) || (endTime == 0)) {
|
||||
return 0;
|
||||
} else {
|
||||
return endTime - startTime;
|
||||
Info(OutputDataListener parent) {
|
||||
this.runCompleted = parent.runCompleted;
|
||||
this.startTime = parent.startTime;
|
||||
this.endTime = parent.endTime;
|
||||
this.suiteNames = Collections
|
||||
.unmodifiableList(new ArrayList<String>(parent.suiteNames));
|
||||
this.ignoredSuiteNames = Collections
|
||||
.unmodifiableList(new ArrayList<String>(
|
||||
parent.ignoredSuiteNames));
|
||||
}
|
||||
|
||||
public boolean isRunCompleted() {
|
||||
return runCompleted;
|
||||
}
|
||||
|
||||
public long getStartTime() {
|
||||
return startTime;
|
||||
}
|
||||
|
||||
public long getEndTime() {
|
||||
return endTime;
|
||||
}
|
||||
|
||||
public long getElapsedTime() {
|
||||
if ((startTime == 0) || (endTime == 0)) {
|
||||
return 0;
|
||||
} else {
|
||||
return endTime - startTime;
|
||||
}
|
||||
}
|
||||
|
||||
public List<String> getSuiteNames() {
|
||||
return suiteNames;
|
||||
}
|
||||
|
||||
public List<String> getIgnoredSuiteNames() {
|
||||
return ignoredSuiteNames;
|
||||
}
|
||||
}
|
||||
|
||||
public List<String> getSuiteNames() {
|
||||
return suiteNames;
|
||||
}
|
||||
|
||||
public List<String> getIgnoredSuiteNames() {
|
||||
return ignoredSuiteNames;
|
||||
/**
|
||||
* Get a snapshot of the data.
|
||||
*/
|
||||
public Info getInfo() {
|
||||
return new Info(this);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
|
|
@ -5,13 +5,13 @@ package edu.cornell.mannlib.vitro.utilities.testrunner.output;
|
|||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import edu.cornell.mannlib.vitro.utilities.testrunner.FileHelper;
|
||||
import edu.cornell.mannlib.vitro.utilities.testrunner.LogStats;
|
||||
import edu.cornell.mannlib.vitro.utilities.testrunner.SeleniumRunnerParameters;
|
||||
import edu.cornell.mannlib.vitro.utilities.testrunner.Status;
|
||||
import edu.cornell.mannlib.vitro.utilities.testrunner.datamodel.DataModel;
|
||||
|
||||
/**
|
||||
* Manages the contents of the output area. Removes old files prior to a run.
|
||||
|
@ -63,21 +63,23 @@ public class OutputManager {
|
|||
* Parse each of the output files from the test suites, and create a unified
|
||||
* output file.
|
||||
*/
|
||||
public Status summarizeOutput() {
|
||||
public void summarizeOutput(DataModel dataModel) {
|
||||
LogStats log = LogStats.parse(parms.getLogFile());
|
||||
|
||||
Map<String, SuiteResults> suites = new HashMap<String, SuiteResults>();
|
||||
List<SuiteResults> suiteResults = new ArrayList<SuiteResults>();
|
||||
for (File outputFile : parms.getOutputDirectory().listFiles(
|
||||
new HtmlFileFilter())) {
|
||||
SuiteResults suite = SuiteResults.parse(parms, outputFile);
|
||||
if (suite != null) {
|
||||
suites.put(suite.getName(), suite);
|
||||
suiteResults.add(suite);
|
||||
}
|
||||
}
|
||||
|
||||
dataModel.setSuiteResults(suiteResults);
|
||||
dataModel.captureDataListener(dataListener);
|
||||
|
||||
OutputSummaryFormatter formatter = new OutputSummaryFormatter(parms);
|
||||
formatter.format(log, suites, dataListener);
|
||||
return formatter.figureOverallStatus(log, suites);
|
||||
formatter.format(log, dataModel);
|
||||
}
|
||||
|
||||
private static class HtmlFileFilter implements FileFilter {
|
||||
|
|
|
@ -9,15 +9,14 @@ import java.io.InputStream;
|
|||
import java.io.PrintWriter;
|
||||
import java.io.Reader;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import edu.cornell.mannlib.vitro.utilities.testrunner.FileHelper;
|
||||
import edu.cornell.mannlib.vitro.utilities.testrunner.LogStats;
|
||||
import edu.cornell.mannlib.vitro.utilities.testrunner.SeleniumRunnerParameters;
|
||||
import edu.cornell.mannlib.vitro.utilities.testrunner.Status;
|
||||
import edu.cornell.mannlib.vitro.utilities.testrunner.datamodel.DataModel;
|
||||
import edu.cornell.mannlib.vitro.utilities.testrunner.output.SuiteResults.TestResults;
|
||||
|
||||
/**
|
||||
|
@ -31,17 +30,7 @@ public class OutputSummaryFormatter {
|
|||
private final SeleniumRunnerParameters parms;
|
||||
|
||||
private LogStats logStats;
|
||||
private Map<String, SuiteResults> suites;
|
||||
private OutputDataListener dataListener;
|
||||
private Status runStatus;
|
||||
private List<TestResults> allTests = new ArrayList<TestResults>();
|
||||
private int passingTestCount;
|
||||
private List<TestResults> failingTests = new ArrayList<TestResults>();
|
||||
private List<TestResults> ignoredTests = new ArrayList<TestResults>();
|
||||
private List<String> passingSuites = new ArrayList<String>();
|
||||
private List<String> failingSuites = new ArrayList<String>();
|
||||
private List<String> ignoredSuites = new ArrayList<String>();
|
||||
private List<String> remainingSuites = new ArrayList<String>();
|
||||
private DataModel dataModel;
|
||||
|
||||
public OutputSummaryFormatter(SeleniumRunnerParameters parms) {
|
||||
this.parms = parms;
|
||||
|
@ -51,14 +40,9 @@ public class OutputSummaryFormatter {
|
|||
* Create a summary HTML file from the info contained in this log file and
|
||||
* these suite outputs.
|
||||
*/
|
||||
public void format(LogStats logStats, Map<String, SuiteResults> suites,
|
||||
OutputDataListener dataListener) {
|
||||
public void format(LogStats logStats, DataModel dataModel) {
|
||||
this.logStats = logStats;
|
||||
this.suites = suites;
|
||||
this.dataListener = dataListener;
|
||||
this.runStatus = figureOverallStatus(logStats, suites);
|
||||
tallyTests();
|
||||
tallySuites();
|
||||
this.dataModel = dataModel;
|
||||
|
||||
PrintWriter writer = null;
|
||||
try {
|
||||
|
@ -107,67 +91,9 @@ public class OutputSummaryFormatter {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The overall status for the run is the worst status of any component.
|
||||
*/
|
||||
public Status figureOverallStatus(LogStats log,
|
||||
Map<String, SuiteResults> suites) {
|
||||
if (log.hasErrors()) {
|
||||
return Status.ERROR;
|
||||
}
|
||||
boolean hasWarnings = log.hasWarnings();
|
||||
|
||||
for (SuiteResults s : suites.values()) {
|
||||
if (s.getStatus() == Status.ERROR) {
|
||||
return Status.ERROR;
|
||||
} else if (s.getStatus() == Status.WARN) {
|
||||
hasWarnings = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasWarnings) {
|
||||
return Status.WARN;
|
||||
} else {
|
||||
return Status.OK;
|
||||
}
|
||||
}
|
||||
|
||||
private void tallyTests() {
|
||||
for (SuiteResults s : suites.values()) {
|
||||
for (TestResults t : s.getTests()) {
|
||||
this.allTests.add(t);
|
||||
if (t.getStatus() == Status.OK) {
|
||||
this.passingTestCount++;
|
||||
} else if (t.getStatus() == Status.WARN) {
|
||||
this.ignoredTests.add(t);
|
||||
} else {
|
||||
this.failingTests.add(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void tallySuites() {
|
||||
List<String> ignoredSuiteNames = dataListener.getIgnoredSuiteNames();
|
||||
|
||||
for (String name : dataListener.getSuiteNames()) {
|
||||
if (ignoredSuiteNames.contains(name)) {
|
||||
this.ignoredSuites.add(name);
|
||||
} else if (!suites.containsKey(name)) {
|
||||
this.remainingSuites.add(name);
|
||||
} else {
|
||||
SuiteResults s = suites.get(name);
|
||||
if (s.getStatus() == Status.ERROR) {
|
||||
this.failingSuites.add(name);
|
||||
} else {
|
||||
this.passingSuites.add(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void writeHeader(PrintWriter writer) {
|
||||
String startString = formatDateTime(dataListener.getStartTime());
|
||||
Status runStatus = dataModel.getRunStatus();
|
||||
String startString = formatDateTime(dataModel.getStartTime());
|
||||
|
||||
writer.println("<html>");
|
||||
writer.println("<head>");
|
||||
|
@ -180,21 +106,22 @@ public class OutputSummaryFormatter {
|
|||
writer.println();
|
||||
writer.println(" <div class=\"heading\">");
|
||||
writer.println(" Acceptance test results: " + startString);
|
||||
writer.println(" <div class=\"" + this.runStatus.getHtmlClass()
|
||||
+ " one-word\">" + this.runStatus + "</div>");
|
||||
writer.println(" <div class=\"" + runStatus.getHtmlClass()
|
||||
+ " one-word\">" + runStatus + "</div>");
|
||||
writer.println(" </div>");
|
||||
}
|
||||
|
||||
private void writeStatsSection(PrintWriter writer) {
|
||||
String passClass = Status.OK.getHtmlClass();
|
||||
String failClass = this.failingTests.isEmpty() ? "" : Status.ERROR
|
||||
.getHtmlClass();
|
||||
String ignoreClass = this.ignoredTests.isEmpty() ? "" : Status.WARN
|
||||
.getHtmlClass();
|
||||
String passClass = dataModel.isAnyPasses() ? Status.OK.getHtmlClass()
|
||||
: "";
|
||||
String failClass = dataModel.isAnyFailures() ? Status.ERROR
|
||||
.getHtmlClass() : "";
|
||||
String ignoreClass = dataModel.isAnyIgnores() ? Status.WARN
|
||||
.getHtmlClass() : "";
|
||||
|
||||
String start = formatDateTime(dataListener.getStartTime());
|
||||
String end = formatDateTime(dataListener.getEndTime());
|
||||
String elapsed = formatElapsedTime(dataListener.getElapsedTime());
|
||||
String start = formatDateTime(dataModel.getStartTime());
|
||||
String end = formatDateTime(dataModel.getEndTime());
|
||||
String elapsed = formatElapsedTime(dataModel.getElapsedTime());
|
||||
|
||||
writer.println(" <div class=\"section\">Summary</div>");
|
||||
writer.println();
|
||||
|
@ -211,28 +138,24 @@ public class OutputSummaryFormatter {
|
|||
writer.println(" </table>");
|
||||
writer.println(" </td>");
|
||||
writer.println(" <td>");
|
||||
writer.println(" <table cellspacing=\"0\">");
|
||||
writer.println(" <table class=\"tallys\" cellspacing=\"0\">");
|
||||
writer.println(" <tr><th> </th><th>Suites</th><th>Tests</th>");
|
||||
writer.println(" <tr><th>Total</th><td>"
|
||||
+ (this.passingSuites.size() + this.failingSuites.size()
|
||||
+ this.ignoredSuites.size() + this.remainingSuites
|
||||
.size())
|
||||
+ "</td><td>"
|
||||
+ (this.passingTestCount + this.failingTests.size() + this.ignoredTests
|
||||
.size()) + "</td>");
|
||||
writer.println(" <tr class=\"" + passClass
|
||||
+ "\"><th>Passed</th><td>" + this.passingSuites.size()
|
||||
+ "</td><td>" + this.passingTestCount + "</td>");
|
||||
+ "\"><td>Passed</td><td>" + dataModel.getPassingSuiteCount()
|
||||
+ "</td><td>" + dataModel.getPassingTestCount() + "</td>");
|
||||
writer.println(" <tr class=\"" + failClass
|
||||
+ "\"><th>Failed</th><td>" + this.failingSuites.size()
|
||||
+ "</td><td>" + this.failingTests.size() + "</td>");
|
||||
+ "\"><td>Failed</td><td>" + dataModel.getFailingSuiteCount()
|
||||
+ "</td><td>" + dataModel.getFailingTestCount() + "</td>");
|
||||
writer.println(" <tr class=\"" + ignoreClass
|
||||
+ "\"><th>Ignored</th><td>" + this.ignoredSuites.size()
|
||||
+ "</td><td>" + this.ignoredTests.size() + "</td>");
|
||||
if (!this.remainingSuites.isEmpty()) {
|
||||
writer.println(" <tr><th>Remaining</th><td>"
|
||||
+ this.remainingSuites.size() + "</td><td>?</td>");
|
||||
+ "\"><td>Ignored</td><td>" + dataModel.getIgnoredSuiteCount()
|
||||
+ "</td><td>" + dataModel.getIgnoredTestCount() + "</td>");
|
||||
if (dataModel.isAnyPending()) {
|
||||
writer.println(" <tr><td>Pending</td><td>"
|
||||
+ dataModel.getPendingSuitesCount() + "</td><td>?</td>");
|
||||
}
|
||||
writer.println(" <tr><td class=\"total\">Total</td><td>"
|
||||
+ dataModel.getTotalSuiteCount() + "</td><td>"
|
||||
+ dataModel.getTotalTestCount() + "</td>");
|
||||
writer.println(" </table>");
|
||||
writer.println(" </td>");
|
||||
writer.println(" </tr>");
|
||||
|
@ -266,6 +189,7 @@ public class OutputSummaryFormatter {
|
|||
|
||||
private void writeFailureSection(PrintWriter writer) {
|
||||
String errorClass = Status.ERROR.getHtmlClass();
|
||||
Collection<TestResults> failingTests = dataModel.getFailingTests();
|
||||
|
||||
writer.println(" <div class=section>Failing tests</div>");
|
||||
writer.println();
|
||||
|
@ -289,6 +213,7 @@ public class OutputSummaryFormatter {
|
|||
|
||||
private void writeIgnoreSection(PrintWriter writer) {
|
||||
String warnClass = Status.WARN.getHtmlClass();
|
||||
Collection<TestResults> ignoredTests = dataModel.getIgnoredTests();
|
||||
|
||||
writer.println(" <div class=section>Ignored tests</div>");
|
||||
writer.println();
|
||||
|
@ -318,7 +243,7 @@ public class OutputSummaryFormatter {
|
|||
writer.println();
|
||||
writer.println(" <table cellspacing=\"0\">");
|
||||
|
||||
for (SuiteResults s : suites.values()) {
|
||||
for (SuiteResults s : dataModel.getSuiteResults()) {
|
||||
writer.println(" <tr class=\"" + s.getStatus().getHtmlClass()
|
||||
+ "\">");
|
||||
writer.println(" <td><a href=\"" + s.getOutputLink() + "\">"
|
||||
|
@ -331,6 +256,8 @@ public class OutputSummaryFormatter {
|
|||
}
|
||||
|
||||
private void writeAllTestsSection(PrintWriter writer) {
|
||||
Collection<TestResults> allTests = dataModel.getAllTests();
|
||||
|
||||
writer.println(" <div class=section>All tests</div>");
|
||||
writer.println();
|
||||
writer.println(" <table cellspacing=\"0\">");
|
||||
|
|
|
@ -22,7 +22,7 @@ import edu.cornell.mannlib.vitro.utilities.testrunner.Status;
|
|||
* Extract any summary information from an HTML output file, produced by a test
|
||||
* suite.
|
||||
*/
|
||||
public class SuiteResults{
|
||||
public class SuiteResults {
|
||||
/**
|
||||
* If the file doesn't contain a line that includes this pattern, it is not
|
||||
* a suite output file.
|
||||
|
@ -94,11 +94,7 @@ public class SuiteResults{
|
|||
|
||||
status = Status.OK;
|
||||
for (TestResults t : tests) {
|
||||
if (t.status == Status.ERROR) {
|
||||
status = Status.ERROR;
|
||||
} else if ((t.status == Status.WARN) && (status == Status.OK)) {
|
||||
status = Status.WARN;
|
||||
}
|
||||
status = Status.combine(status, t.status);
|
||||
}
|
||||
|
||||
if (isSuiteOutputFile) {
|
||||
|
|
|
@ -40,6 +40,14 @@ table.summary td {
|
|||
vertical-align: top;
|
||||
}
|
||||
|
||||
table.tallys td {
|
||||
align: right;
|
||||
}
|
||||
|
||||
table.tallys td.total {
|
||||
font.weight: bold;
|
||||
}
|
||||
|
||||
.section {
|
||||
background: rgb(70%, 85%, 85%);
|
||||
font-size: larger;
|
||||
|
|
Loading…
Add table
Reference in a new issue