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);
+ }
+ }
+
+}