diff --git a/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/CommandRunner.java b/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/CommandRunner.java index 1d44999e2..c7549e11c 100644 --- a/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/CommandRunner.java +++ b/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/CommandRunner.java @@ -10,6 +10,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import edu.cornell.mannlib.vitro.utilities.testrunner.listener.Listener; + /** *

* A harness that runs a system-level command. diff --git a/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/ModelCleaner.java b/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/ModelCleaner.java index 586ad5f6b..9a698431f 100644 --- a/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/ModelCleaner.java +++ b/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/ModelCleaner.java @@ -8,6 +8,8 @@ import java.io.InputStream; import java.util.ArrayList; import java.util.List; +import edu.cornell.mannlib.vitro.utilities.testrunner.listener.Listener; + /** * Resets the RDF-Model to a known state, in preparation for the next Selenium * test suite. diff --git a/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/OutputManager.java b/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/OutputManager.java index b94b700e3..7426306b0 100644 --- a/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/OutputManager.java +++ b/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/OutputManager.java @@ -8,6 +8,8 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; +import edu.cornell.mannlib.vitro.utilities.testrunner.listener.Listener; + /** * Manages the contents of the output area. Removes old files prior to a run. * Creates a unified summary of the test suite outputs. diff --git a/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/SeleniumRunner.java b/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/SeleniumRunner.java index 41e3c9ff3..e3a21c465 100644 --- a/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/SeleniumRunner.java +++ b/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/SeleniumRunner.java @@ -9,6 +9,8 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; +import edu.cornell.mannlib.vitro.utilities.testrunner.listener.Listener; + /** * Run the Selenium test suites. Provide the properties file and perhaps an * "interactive" flag. diff --git a/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/SeleniumRunnerParameters.java b/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/SeleniumRunnerParameters.java index 7d781a6ab..a6db03cf0 100644 --- a/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/SeleniumRunnerParameters.java +++ b/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/SeleniumRunnerParameters.java @@ -15,6 +15,10 @@ import java.util.Collections; import java.util.List; import java.util.Properties; +import edu.cornell.mannlib.vitro.utilities.testrunner.listener.Listener; +import edu.cornell.mannlib.vitro.utilities.testrunner.listener.LoggingListener; +import edu.cornell.mannlib.vitro.utilities.testrunner.listener.MulticastListener; + /** * Holds the runtime parameters that are read from the properties file, perhaps * with modifications from the GUI if we are running interactively. @@ -48,7 +52,10 @@ public class SeleniumRunnerParameters { private Collection selectedSuites = Collections.emptySet(); private boolean cleanModel = true; private boolean cleanUploads = true; - private Listener listener = new Listener(System.out); + + // If we fail during the parameter parsing, we'll still write the log + // somewhere. + private Listener listener = new LoggingListener(System.out); /** * Read the required properties from the property file, and do some checks @@ -71,7 +78,8 @@ public class SeleniumRunnerParameters { this.outputDirectory = checkOutputDirectory(props); this.logFile = new File(this.outputDirectory, LOGFILE_NAME); - this.listener = new Listener(this.logFile); + this.listener = new MulticastListener(); + addListener(new LoggingListener(this.logFile)); this.suiteParentDirectories = checkSuiteParentDirectories(props); @@ -328,6 +336,15 @@ public class SeleniumRunnerParameters { return seleniumJarPath; } + public void addListener(Listener l) { + if (listener instanceof MulticastListener) { + ((MulticastListener) listener).addListener(l); + } else { + throw new IllegalStateException("Listener is not a multi-cast -- " + + "can't add new listeners."); + } + } + public Listener getListener() { return listener; } diff --git a/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/SuiteRunner.java b/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/SuiteRunner.java index 4052412d2..ffee8c92d 100644 --- a/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/SuiteRunner.java +++ b/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/SuiteRunner.java @@ -6,6 +6,8 @@ import java.io.File; import java.util.ArrayList; import java.util.List; +import edu.cornell.mannlib.vitro.utilities.testrunner.listener.Listener; + /** * Run a Selenium TestSuite in a sub-process. */ diff --git a/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/TomcatController.java b/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/TomcatController.java index a7c2a8ecd..2d89b6ea9 100644 --- a/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/TomcatController.java +++ b/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/TomcatController.java @@ -5,6 +5,8 @@ package edu.cornell.mannlib.vitro.utilities.testrunner; import java.util.ArrayList; import java.util.List; +import edu.cornell.mannlib.vitro.utilities.testrunner.listener.Listener; + /** * Start and stop the webapp, so we can clean the database. */ diff --git a/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/UploadAreaCleaner.java b/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/UploadAreaCleaner.java index 9ddb714f4..8e125597b 100644 --- a/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/UploadAreaCleaner.java +++ b/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/UploadAreaCleaner.java @@ -5,6 +5,8 @@ package edu.cornell.mannlib.vitro.utilities.testrunner; import java.io.File; import java.io.IOException; +import edu.cornell.mannlib.vitro.utilities.testrunner.listener.Listener; + /** * Clean out the file upload area, so the next suite will start with no uploads. */ diff --git a/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/listener/Listener.java b/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/listener/Listener.java new file mode 100644 index 000000000..4fbd20610 --- /dev/null +++ b/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/listener/Listener.java @@ -0,0 +1,90 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.utilities.testrunner.listener; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +/** + * A listener for all events that occur during the run. + */ +public interface Listener { + + void suiteIgnored(File suite); + + void suiteAdded(File suite); + + void runStarted(); + + void runFailed(Exception e); + + void runEndTime(); + + void runStopped(); + + void cleanOutputStart(File outputDirectory); + + void cleanOutputFailed(File outputDirectory, IOException e); + + void cleanOutputStop(File outputDirectory); + + void webappStopping(String tomcatStopCommand); + + void webappStopFailed(int returnCode); + + void webappWaitingForStop(int tomcatStopDelay); + + void webappStopped(); + + void dropDatabaseStarting(String statement); + + void dropDatabaseFailed(int returnCode); + + void dropDatabaseComplete(); + + void loadDatabaseStarting(String statement); + + void loadDatabaseFailed(int returnCode); + + void loadDatabaseComplete(); + + void webappStarting(String tomcatStartCommand); + + void webappStartFailed(int returnCode); + + void webappWaitingForStart(int tomcatStartDelay); + + void webappStarted(); + + void subProcessStart(List command); + + void subProcessStartInBackground(List command); + + void subProcessStdout(String string); + + void subProcessErrout(String string); + + void subProcessStop(List command); + + void suiteStarted(File suiteDir); + + void suiteTestingStarted(File suiteDir); + + void suiteFailed(File suiteDir, int returnCode); + + void suiteFailed(File suiteDir, Exception e); + + void suiteTestingStopped(File suiteDir); + + void suiteStopped(File suiteDir); + + void cleanUploadStart(File uploadDirectory); + + void cleanUploadFailed(File uploadDirectory, IOException e); + + void cleanUploadStop(File uploadDirectory); + + void logWarning(String message); + +} diff --git a/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/Listener.java b/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/listener/LoggingListener.java similarity index 86% rename from utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/Listener.java rename to utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/listener/LoggingListener.java index 1adca197e..a3da549f5 100644 --- a/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/Listener.java +++ b/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/listener/LoggingListener.java @@ -1,6 +1,6 @@ /* $This file is distributed under the terms of the license in /doc/license.txt$ */ -package edu.cornell.mannlib.vitro.utilities.testrunner; +package edu.cornell.mannlib.vitro.utilities.testrunner.listener; import java.io.File; import java.io.FileWriter; @@ -18,7 +18,7 @@ import java.util.List; * implementation, each event is simply formatted and written to a log file or * {@link PrintStream}. */ -public class Listener { +public class LoggingListener implements Listener { private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss.SSS"); @@ -28,11 +28,11 @@ public class Listener { // Constructors // ---------------------------------------------------------------------- - public Listener(PrintStream out) { + public LoggingListener(PrintStream out) { this.writer = new OutputStreamWriter(out); } - public Listener(File logFile) throws IOException { + public LoggingListener(File logFile) throws IOException { this.writer = new FileWriter(logFile); } @@ -40,159 +40,197 @@ public class Listener { // Listener methods // ---------------------------------------------------------------------- + @Override public void suiteIgnored(File suite) { log("Suite '" + suite.getName() + "' ignored."); } + @Override public void suiteAdded(File suite) { log("Suite '" + suite.getName() + "' added."); } + @Override public void runStarted() { log("Run started."); } + @Override public void runFailed(Exception e) { log("Run failed - fatal error"); log(e); } + @Override public void runEndTime() { log("Testing complete."); } + @Override public void runStopped() { log("Run stopped."); } + @Override public void cleanOutputStart(File outputDirectory) { log("Output area cleaning started: " + outputDirectory.getPath()); } + @Override public void cleanOutputFailed(File outputDirectory, IOException e) { log("Output area cleaning failed: " + outputDirectory.getPath()); log(e); } + @Override public void cleanOutputStop(File outputDirectory) { log("Output area cleaning stopped: " + outputDirectory.getPath()); } + @Override public void webappStopping(String tomcatStopCommand) { log("Stopping tomcat: " + tomcatStopCommand); } + @Override public void webappStopFailed(int returnCode) { log("Failed to stop tomcat; return code was " + returnCode); } + @Override public void webappWaitingForStop(int tomcatStopDelay) { log("Waiting " + tomcatStopDelay + " seconds for tomcat to stop."); } + @Override public void webappStopped() { log("Tomcat stopped."); } + @Override public void dropDatabaseStarting(String statement) { log("Dropping database: " + statement); } + @Override public void dropDatabaseFailed(int returnCode) { log("Failed to drop the database; return code was " + returnCode); } + @Override public void dropDatabaseComplete() { log("Dropped database."); } + @Override public void loadDatabaseStarting(String statement) { log("Loading the database: " + statement); } + @Override public void loadDatabaseFailed(int returnCode) { log("Failed to load the database; return code was " + returnCode); } + @Override public void loadDatabaseComplete() { log("Loaded the database."); } + @Override public void webappStarting(String tomcatStartCommand) { log("Starting tomcat: " + tomcatStartCommand); } + @Override public void webappStartFailed(int returnCode) { log("Failed to start tomcat; return code was " + returnCode); } + @Override public void webappWaitingForStart(int tomcatStartDelay) { log("Waiting " + tomcatStartDelay + " seconds for tomcat to start."); } + @Override public void webappStarted() { log("Tomcat started."); } + @Override public void subProcessStart(List command) { log("Subprocess started: " + command); } + @Override public void subProcessStartInBackground(List command) { log("Subprocess started in background: " + command); } + @Override public void subProcessStdout(String string) { logRawText(string); } + @Override public void subProcessErrout(String string) { logRawText(string); } + @Override public void subProcessStop(List command) { log("Subprocess stopped: " + command); } + @Override public void suiteStarted(File suiteDir) { log("Suite started: " + suiteDir.getName()); } + @Override public void suiteTestingStarted(File suiteDir) { log("Suite testing started: " + suiteDir.getName()); } + @Override public void suiteFailed(File suiteDir, int returnCode) { log("Suite failed: " + suiteDir.getName() + ", returnCode=" + returnCode); } + @Override public void suiteFailed(File suiteDir, Exception e) { log("Suite failed: " + suiteDir.getName()); log(e); } + @Override public void suiteTestingStopped(File suiteDir) { log("Suite testing stopped: " + suiteDir.getName()); } + @Override public void suiteStopped(File suiteDir) { log("Suite stopped: " + suiteDir.getName()); } + @Override public void cleanUploadStart(File uploadDirectory) { log("Upload cleaning started: " + uploadDirectory.getPath()); } + @Override public void cleanUploadFailed(File uploadDirectory, IOException e) { log("Upload cleaning failed: " + uploadDirectory.getPath()); log(e); } + @Override public void cleanUploadStop(File uploadDirectory) { log("Upload cleaning stopped: " + uploadDirectory.getPath()); } - + + @Override public void logWarning(String message) { log("WARNING: " + message); } diff --git a/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/listener/MulticastListener.java b/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/listener/MulticastListener.java new file mode 100644 index 000000000..7400c5ba2 --- /dev/null +++ b/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/listener/MulticastListener.java @@ -0,0 +1,291 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.utilities.testrunner.listener; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * A {@link Listener} implementation that holds a list of {@link Listener}s and + * sends each message to all of them. + */ +public class MulticastListener implements Listener { + private final List listeners = new ArrayList(); + + public void addListener(Listener l) { + listeners.add(l); + } + + // ---------------------------------------------------------------------- + // Listener methods + // ---------------------------------------------------------------------- + + @Override + public void suiteIgnored(File suite) { + for (Listener l : listeners) { + l.suiteIgnored(suite); + } + } + + @Override + public void suiteAdded(File suite) { + for (Listener l : listeners) { + l.suiteAdded(suite); + } + } + + @Override + public void runStarted() { + for (Listener l : listeners) { + l.runStarted(); + } + } + + @Override + public void runFailed(Exception e) { + for (Listener l : listeners) { + l.runFailed(e); + } + } + + @Override + public void runEndTime() { + for (Listener l : listeners) { + l.runEndTime(); + } + } + + @Override + public void runStopped() { + for (Listener l : listeners) { + l.runStopped(); + } + } + + @Override + public void cleanOutputStart(File outputDirectory) { + for (Listener l : listeners) { + l.cleanOutputStart(outputDirectory); + } + } + + @Override + public void cleanOutputFailed(File outputDirectory, IOException e) { + for (Listener l : listeners) { + l.cleanOutputFailed(outputDirectory, e); + } + } + + @Override + public void cleanOutputStop(File outputDirectory) { + for (Listener l : listeners) { + l.cleanOutputStop(outputDirectory); + } + } + + @Override + public void webappStopping(String tomcatStopCommand) { + for (Listener l : listeners) { + l.webappStopping(tomcatStopCommand); + } + } + + @Override + public void webappStopFailed(int returnCode) { + for (Listener l : listeners) { + l.webappStopFailed(returnCode); + } + } + + @Override + public void webappWaitingForStop(int tomcatStopDelay) { + for (Listener l : listeners) { + l.webappWaitingForStop(tomcatStopDelay); + } + } + + @Override + public void webappStopped() { + for (Listener l : listeners) { + l.webappStopped(); + } + } + + @Override + public void dropDatabaseStarting(String statement) { + for (Listener l : listeners) { + l.dropDatabaseStarting(statement); + } + } + + @Override + public void dropDatabaseFailed(int returnCode) { + for (Listener l : listeners) { + l.dropDatabaseFailed(returnCode); + } + } + + @Override + public void dropDatabaseComplete() { + for (Listener l : listeners) { + l.dropDatabaseComplete(); + } + } + + @Override + public void loadDatabaseStarting(String statement) { + for (Listener l : listeners) { + l.loadDatabaseStarting(statement); + } + } + + @Override + public void loadDatabaseFailed(int returnCode) { + for (Listener l : listeners) { + l.loadDatabaseFailed(returnCode); + } + } + + @Override + public void loadDatabaseComplete() { + for (Listener l : listeners) { + l.loadDatabaseComplete(); + } + } + + @Override + public void webappStarting(String tomcatStartCommand) { + for (Listener l : listeners) { + l.webappStarting(tomcatStartCommand); + } + } + + @Override + public void webappStartFailed(int returnCode) { + for (Listener l : listeners) { + l.webappStartFailed(returnCode); + } + } + + @Override + public void webappWaitingForStart(int tomcatStartDelay) { + for (Listener l : listeners) { + l.webappWaitingForStart(tomcatStartDelay); + } + } + + @Override + public void webappStarted() { + for (Listener l : listeners) { + l.webappStarted(); + } + } + + @Override + public void subProcessStart(List command) { + for (Listener l : listeners) { + l.subProcessStart(command); + } + } + + @Override + public void subProcessStartInBackground(List command) { + for (Listener l : listeners) { + l.subProcessStartInBackground(command); + } + } + + @Override + public void subProcessStdout(String string) { + for (Listener l : listeners) { + l.subProcessStdout(string); + } + } + + @Override + public void subProcessErrout(String string) { + for (Listener l : listeners) { + l.subProcessErrout(string); + } + } + + @Override + public void subProcessStop(List command) { + for (Listener l : listeners) { + l.subProcessStop(command); + } + } + + @Override + public void suiteStarted(File suiteDir) { + for (Listener l : listeners) { + l.suiteStarted(suiteDir); + } + } + + @Override + public void suiteTestingStarted(File suiteDir) { + for (Listener l : listeners) { + l.suiteTestingStarted(suiteDir); + } + } + + @Override + public void suiteFailed(File suiteDir, int returnCode) { + for (Listener l : listeners) { + l.suiteFailed(suiteDir, returnCode); + } + } + + @Override + public void suiteFailed(File suiteDir, Exception e) { + for (Listener l : listeners) { + l.suiteFailed(suiteDir, e); + } + } + + @Override + public void suiteTestingStopped(File suiteDir) { + for (Listener l : listeners) { + l.suiteTestingStopped(suiteDir); + } + } + + @Override + public void suiteStopped(File suiteDir) { + for (Listener l : listeners) { + l.suiteStopped(suiteDir); + } + } + + @Override + public void cleanUploadStart(File uploadDirectory) { + for (Listener l : listeners) { + l.cleanUploadStart(uploadDirectory); + } + } + + @Override + public void cleanUploadFailed(File uploadDirectory, IOException e) { + for (Listener l : listeners) { + l.cleanUploadFailed(uploadDirectory, e); + } + } + + @Override + public void cleanUploadStop(File uploadDirectory) { + for (Listener l : listeners) { + l.cleanUploadStop(uploadDirectory); + } + } + + @Override + public void logWarning(String message) { + for (Listener l : listeners) { + l.logWarning(message); + } + } + +}