NIHVIVO-222 Use the OWL file of the test user model instead of a MySQL dump.

Embed the OWL file in the source, so we don't need to configure it. 
Break out a separate TomcatController class.
This commit is contained in:
jeb228 2010-08-18 16:38:01 +00:00
parent 60444bb7f8
commit 99c70b5d66
7 changed files with 294 additions and 161 deletions

View file

@ -193,6 +193,10 @@ public class Listener {
log("Upload cleaning stopped: " + uploadDirectory.getPath());
}
public void logWarning(String message) {
log("WARNING: " + message);
}
// ----------------------------------------------------------------------
// Helper methods
// ----------------------------------------------------------------------

View file

@ -3,6 +3,8 @@
package edu.cornell.mannlib.vitro.utilities.testrunner;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
@ -11,14 +13,18 @@ import java.util.List;
* test suite.
*/
public class ModelCleaner {
public static final String TEST_USER_ONTOLOGY_FILENAME = "test-user-model.owl";
private final ModelCleanerProperties properties;
private final TomcatController tomcatController;
private final CommandRunner runner;
private final Listener listener;
public ModelCleaner(SeleniumRunnerParameters parms) {
public ModelCleaner(SeleniumRunnerParameters parms,
TomcatController tomcatController) {
this.properties = parms.getModelCleanerProperties();
this.listener = parms.getListener();
this.runner = new CommandRunner(parms);
this.tomcatController = tomcatController;
sanityCheck();
}
@ -42,42 +48,39 @@ public class ModelCleaner {
* if a problem occurs in a sub-process.
*/
public void clean() throws CommandRunnerException {
stopTheWebapp();
dropDatabase();
createAndLoadDatabase();
startTheWebapp();
tomcatController.stopTheWebapp();
insertTheUserFile();
recreateTheDatabase();
tomcatController.startTheWebapp();
removeTheUserFile();
}
/**
* Stop Tomcat and wait the prescribed number of seconds for it to clean up.
* Copy the test data ontology file into the auth area, so we get our
* pre-defined admin user.
*/
public void stopTheWebapp() throws CommandRunnerException {
String tomcatStopCommand = properties.getTomcatStopCommand();
int tomcatStopDelay = properties.getTomcatStopDelay();
listener.webappStopping(tomcatStopCommand);
runner.run(parseCommandLine(tomcatStopCommand));
int returnCode = runner.getReturnCode();
if (returnCode != 0) {
listener.webappStopFailed(returnCode);
// Throw no exception - this can happen if Tomcat isn't running.
private void insertTheUserFile() {
InputStream userOntologyStream = this.getClass().getResourceAsStream(
TEST_USER_ONTOLOGY_FILENAME);
if (userOntologyStream == null) {
throw new FatalException(
"Couldn't find the Test User Ontology file: '"
+ TEST_USER_ONTOLOGY_FILENAME + "'");
}
listener.webappWaitingForStop(tomcatStopDelay);
File userOntologyTarget = figureUserOntologyTarget();
try {
Thread.sleep(tomcatStopDelay * 1000L);
} catch (InterruptedException e) {
// Just continue.
FileHelper.copy(userOntologyStream, userOntologyTarget);
userOntologyStream.close();
} catch (IOException e) {
e.printStackTrace();
}
listener.webappStopped();
}
/**
* Delete the database.
* Drop the database and create it again, empty.
*/
private void dropDatabase() {
private void recreateTheDatabase() {
String mysqlStatement = "drop database " + properties.getMysqlDbName()
+ "; create database " + properties.getMysqlDbName()
+ " character set utf8;";
@ -96,54 +99,15 @@ public class ModelCleaner {
}
/**
* Rebuild the database.
* Remove the test data ontology file, so we leave no trace.
*/
private void createAndLoadDatabase() {
String mysqlStatement = "source "
+ convertBackslashes(properties.getMysqlDumpfile()) + ";";
listener.loadDatabaseStarting(mysqlStatement);
executeMysqlStatement(mysqlStatement);
int returnCode = runner.getReturnCode();
if (returnCode != 0) {
listener.loadDatabaseFailed(returnCode);
throw new FatalException("loadDatabase() failed: return code="
+ returnCode);
private void removeTheUserFile() {
File userOntologyTarget = figureUserOntologyTarget();
userOntologyTarget.delete();
if (userOntologyTarget.exists()) {
listener.logWarning("Failed to delete the test data ontology "
+ "file: '" + TEST_USER_ONTOLOGY_FILENAME + "'");
}
listener.loadDatabaseComplete();
}
/**
* Start Tomcat and wait for it to initialize.
*/
private void startTheWebapp() {
String tomcatStartCommand = properties.getTomcatStartCommand();
int tomcatStartDelay = properties.getTomcatStartDelay();
listener.webappStarting(tomcatStartCommand);
try {
runner.runAsBackground(parseCommandLine(tomcatStartCommand));
} catch (CommandRunnerException e) {
throw new FatalException(e);
}
int returnCode = runner.getReturnCode();
if (returnCode != 0) {
listener.webappStartFailed(returnCode);
throw new FatalException("startTheWebapp() failed: return code="
+ returnCode);
}
listener.webappWaitingForStart(tomcatStartDelay);
try {
Thread.sleep(tomcatStartDelay * 1000L);
} catch (InterruptedException e) {
// Just continue.
}
listener.webappStarted();
}
/**
@ -166,48 +130,23 @@ public class ModelCleaner {
}
/**
* A command line must be broken into separate arguments, where arguments
* are delimited by blanks unless the blank (and the argument) is enclosed
* in quotes.
* Figure out where the test data ontology file should go. C:\Program
* Files\Apache Software Foundation\Tomcat
* 6.0\webapps\vivo\WEB-INF\ontologies\auth
*/
static List<String> parseCommandLine(String commandLine) {
List<String> pieces = new ArrayList<String>();
StringBuilder piece = null;
boolean inDelimiter = true;
boolean inQuotes = false;
for (int i = 0; i < commandLine.length(); i++) {
char thisChar = commandLine.charAt(i);
if ((thisChar == ' ') && !inQuotes) {
if (inDelimiter) {
// No effect.
} else {
inDelimiter = true;
pieces.add(piece.toString());
}
} else if (thisChar == '"') {
// Quotes are not carried into the parsed strings.
inQuotes = !inQuotes;
} else { // Not a blank or a quote.
if (inDelimiter) {
inDelimiter = false;
piece = new StringBuilder();
}
piece.append(thisChar);
}
private File figureUserOntologyTarget() {
File webappDirectory = properties.getWebappDirectory();
File authDirectory = new File(webappDirectory,
"WEB-INF/ontologies/auth");
if (!authDirectory.exists()) {
throw new FatalException("Target directory for the test data "
+ "ontology file doesn't exist. Webapp directory is '"
+ webappDirectory + "', target directory is '"
+ authDirectory + "'");
}
// There is an implied delimiter at the end of the command line.
if (!inDelimiter) {
pieces.add(piece.toString());
}
// Quotes must appear in pairs
if (inQuotes) {
throw new IllegalArgumentException(
"Command line contains mismatched quotes: " + commandLine);
}
return pieces;
return new File(authDirectory, TEST_USER_ONTOLOGY_FILENAME);
}
static String convertBackslashes(File file) {

View file

@ -17,7 +17,7 @@ public class ModelCleanerProperties {
public static final String PROP_MYSQL_USERNAME = "mysql_username";
public static final String PROP_MYSQL_PASSWORD = "mysql_password";
public static final String PROP_MYSQL_DB_NAME = "mysql_db_name";
public static final String PROP_MYSQL_DUMPFILE = "mysql_dumpfile";
public static final String PROP_WEBAPP_DIRECTORY = "vivo_webapp_directory";
private final String tomcatStartCommand;
private final int tomcatStartDelay;
@ -26,7 +26,7 @@ public class ModelCleanerProperties {
private final String mysqlUsername;
private final String mysqlPassword;
private final String mysqlDbName;
private final File mysqlDumpfile;
private final File webappDirectory;
/**
* Confirm that we have the expected properties, and that their values seem
@ -47,7 +47,7 @@ public class ModelCleanerProperties {
this.mysqlPassword = getRequiredProperty(props, PROP_MYSQL_PASSWORD);
this.mysqlDbName = getRequiredProperty(props, PROP_MYSQL_DB_NAME);
this.mysqlDumpfile = confirmDumpfile(props);
this.webappDirectory = confirmWebappDirectory(props);
}
public String getTomcatStartCommand() {
@ -78,8 +78,8 @@ public class ModelCleanerProperties {
return mysqlDbName;
}
public File getMysqlDumpfile() {
return mysqlDumpfile;
public File getWebappDirectory() {
return webappDirectory;
}
/**
@ -106,33 +106,38 @@ public class ModelCleanerProperties {
}
/**
* The dumpfile parameter must point to an existing file.
* The dumpfile parameter must point to an existing directory.
*/
private File confirmDumpfile(Properties props) {
String filename = getRequiredProperty(props, PROP_MYSQL_DUMPFILE);
File dumpfile = new File(filename);
if (!dumpfile.exists()) {
private File confirmWebappDirectory(Properties props) {
String filename = getRequiredProperty(props, PROP_WEBAPP_DIRECTORY);
File webappDirectory = new File(filename);
if (!webappDirectory.exists()) {
throw new IllegalArgumentException("Invalid value for '"
+ PROP_MYSQL_DUMPFILE + "': file '" + filename
+ PROP_WEBAPP_DIRECTORY + "': directory '" + filename
+ "' does not exist.");
}
if (!dumpfile.isFile()) {
if (!webappDirectory.isDirectory()) {
throw new IllegalArgumentException("Invalid value for '"
+ PROP_MYSQL_DUMPFILE + "': '" + filename
+ "' is not a file.");
+ PROP_WEBAPP_DIRECTORY + "': '" + filename
+ "' is not a directory.");
}
if (!dumpfile.canRead()) {
if (!webappDirectory.canWrite()) {
throw new IllegalArgumentException("Invalid value for '"
+ PROP_MYSQL_DUMPFILE + "': file '" + filename
+ "' is not readable.");
+ PROP_WEBAPP_DIRECTORY + "': directory '" + filename
+ "' is not writeable.");
}
return dumpfile;
return webappDirectory;
}
public String toString() {
return "\n tomcatStartCommand: " + tomcatStartCommand
+ "\n tomcatStartDelay: " + tomcatStartDelay
+ "\n tomcatStopCommand: " + tomcatStopCommand
+ "\n tomcatStopDelay: " + tomcatStopDelay;
+ "\n tomcatStopDelay: " + tomcatStopDelay
+ "\n mysqlUsername: " + mysqlUsername
+ "\n mysqlPassword: " + mysqlPassword
+ "\n mysqlDbName: " + mysqlDbName
+ "\n webappDirectory: " + webappDirectory;
}
}

View file

@ -17,6 +17,7 @@ public class SeleniumRunner {
private final SeleniumRunnerParameters parms;
private final Listener listener;
private final UploadAreaCleaner uploadCleaner;
private final TomcatController tomcatController;
private final ModelCleaner modelCleaner;
private final SuiteRunner suiteRunner;
private final OutputManager outputManager;
@ -25,43 +26,27 @@ public class SeleniumRunner {
this.parms = parms;
this.listener = parms.getListener();
this.uploadCleaner = new UploadAreaCleaner(parms);
this.modelCleaner = new ModelCleaner(parms);
this.tomcatController = new TomcatController(parms);
this.modelCleaner = new ModelCleaner(parms, this.tomcatController);
this.suiteRunner = new SuiteRunner(parms);
this.outputManager = new OutputManager(parms);
}
public boolean runSelectedSuites() {
/**
* Set up the run, run the selected suites, summarize the output, and clean
* up afterwards.
*
* @return <code>true</code> iff all tests passed.
*/
public boolean run() {
boolean success;
try {
listener.runStarted();
outputManager.cleanOutputDirectory();
for (File suiteDir : parms.getSelectedSuites()) {
listener.suiteStarted(suiteDir);
try {
if (parms.isCleanModel()) {
modelCleaner.clean();
}
if (parms.isCleanUploads()) {
uploadCleaner.clean();
}
suiteRunner.runSuite(suiteDir);
} catch (IOException e) {
listener.suiteFailed(suiteDir, e);
} catch (CommandRunnerException e) {
listener.suiteFailed(suiteDir, e);
}
listener.suiteStopped(suiteDir);
}
// If we've been starting and stopping Tomcat,
// stop it one more time.
if (parms.isCleanModel()) {
try {
modelCleaner.stopTheWebapp();
} catch (CommandRunnerException e) {
throw new FatalException(e);
}
}
runSelectedSuites();
tomcatController.cleanup();
listener.runEndTime();
Status status = outputManager.summarizeOutput();
@ -79,6 +64,26 @@ public class SeleniumRunner {
return success;
}
public void runSelectedSuites() {
for (File suiteDir : parms.getSelectedSuites()) {
listener.suiteStarted(suiteDir);
try {
if (parms.isCleanModel()) {
modelCleaner.clean();
}
if (parms.isCleanUploads()) {
uploadCleaner.clean();
}
suiteRunner.runSuite(suiteDir);
} catch (IOException e) {
listener.suiteFailed(suiteDir, e);
} catch (CommandRunnerException e) {
listener.suiteFailed(suiteDir, e);
}
listener.suiteStopped(suiteDir);
}
}
private static void selectAllSuites(SeleniumRunnerParameters parms) {
Listener listener = parms.getListener();
IgnoredTests ignored = parms.getIgnoredTests();
@ -145,7 +150,7 @@ public class SeleniumRunner {
System.out.println(parms);
SeleniumRunner runner = new SeleniumRunner(parms);
success = runner.runSelectedSuites();
success = runner.run();
}
System.out.println("Exiting SeleniumRunner");
System.exit(success ? 0 : -1);

View file

@ -0,0 +1,139 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.utilities.testrunner;
import java.util.ArrayList;
import java.util.List;
/**
* Start and stop the webapp, so we can clean the database.
*/
public class TomcatController {
private final SeleniumRunnerParameters parms;
private final ModelCleanerProperties properties;
private final Listener listener;
public TomcatController(SeleniumRunnerParameters parms) {
this.parms = parms;
this.properties = parms.getModelCleanerProperties();
this.listener = parms.getListener();
}
/**
* Stop Tomcat and wait the prescribed number of seconds for it to clean up.
*/
public void stopTheWebapp() throws CommandRunnerException {
String tomcatStopCommand = properties.getTomcatStopCommand();
int tomcatStopDelay = properties.getTomcatStopDelay();
CommandRunner runner = new CommandRunner(parms);
listener.webappStopping(tomcatStopCommand);
runner.run(parseCommandLine(tomcatStopCommand));
int returnCode = runner.getReturnCode();
if (returnCode != 0) {
listener.webappStopFailed(returnCode);
// Throw no exception - this can happen if Tomcat isn't running.
}
listener.webappWaitingForStop(tomcatStopDelay);
try {
Thread.sleep(tomcatStopDelay * 1000L);
} catch (InterruptedException e) {
// Just continue.
}
listener.webappStopped();
}
/**
* Start Tomcat and wait for it to initialize.
*/
public void startTheWebapp() {
String tomcatStartCommand = properties.getTomcatStartCommand();
int tomcatStartDelay = properties.getTomcatStartDelay();
CommandRunner runner = new CommandRunner(parms);
listener.webappStarting(tomcatStartCommand);
try {
runner.runAsBackground(parseCommandLine(tomcatStartCommand));
} catch (CommandRunnerException e) {
throw new FatalException(e);
}
// Can't check the return code because the process shouldn't end.
listener.webappWaitingForStart(tomcatStartDelay);
try {
Thread.sleep(tomcatStartDelay * 1000L);
} catch (InterruptedException e) {
// Just continue.
}
listener.webappStarted();
}
/**
* A command line must be broken into separate arguments, where arguments
* are delimited by blanks unless the blank (and the argument) is enclosed
* in quotes.
*/
static List<String> parseCommandLine(String commandLine) {
List<String> pieces = new ArrayList<String>();
StringBuilder piece = null;
boolean inDelimiter = true;
boolean inQuotes = false;
for (int i = 0; i < commandLine.length(); i++) {
char thisChar = commandLine.charAt(i);
if ((thisChar == ' ') && !inQuotes) {
if (inDelimiter) {
// No effect.
} else {
inDelimiter = true;
pieces.add(piece.toString());
}
} else if (thisChar == '"') {
// Quotes are not carried into the parsed strings.
inQuotes = !inQuotes;
} else { // Not a blank or a quote.
if (inDelimiter) {
inDelimiter = false;
piece = new StringBuilder();
}
piece.append(thisChar);
}
}
// There is an implied delimiter at the end of the command line.
if (!inDelimiter) {
pieces.add(piece.toString());
}
// Quotes must appear in pairs
if (inQuotes) {
throw new IllegalArgumentException(
"Command line contains mismatched quotes: " + commandLine);
}
return pieces;
}
/**
* The run is finished. Do we need to do anything?
*/
public void cleanup() {
// If we've been starting and stopping Tomcat,
// stop it one more time.
if (parms.isCleanModel()) {
try {
stopTheWebapp();
} catch (CommandRunnerException e) {
throw new FatalException(e);
}
}
}
}

View file

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
xmlns:owl="http://www.w3.org/2002/07/owl#"
xmlns:vitro="http://vitro.mannlib.cornell.edu/ns/vitro/0.7#"
xmlns="http://vitro.mannlib.cornell.edu/ns/vitro/default#"
xml:base="http://vitro.mannlib.cornell.edu/ns/vitro/default">
<vitro:User rdf:about="#defaultAdminUser">
<vitro:username rdf:datatype="http://www.w3.org/2001/XMLSchema#string">testAdmin</vitro:username>
<vitro:md5password rdf:datatype="http://www.w3.org/2001/XMLSchema#string">DC647EB65E6711E155375218212B3964</vitro:md5password>
<vitro:roleURI rdf:datatype="http://www.w3.org/2001/XMLSchema#string">role:/50</vitro:roleURI>
<vitro:firstTime rdf:datatype="http://www.w3.org/2001/XMLSchema#dateTime">2010-03-09T16:06:45</vitro:firstTime>
<vitro:loginCount rdf:datatype="http://www.w3.org/2001/XMLSchema#int">1</vitro:loginCount>
</vitro:User>
<vitro:User rdf:about="http://vivo.mydomain.edu/individual/JoeUser">
<vitro:username rdf:datatype="http://www.w3.org/2001/XMLSchema#string">Joe User</vitro:username>
<vitro:md5password rdf:datatype="http://www.w3.org/2001/XMLSchema#string">8A1A62B7B58B8B95564483BEA60CD99A</vitro:md5password>
<vitro:roleURI rdf:datatype="http://www.w3.org/2001/XMLSchema#string">role:/1</vitro:roleURI>
<vitro:firstTime rdf:datatype="http://www.w3.org/2001/XMLSchema#dateTime">2010-03-09T16:06:45</vitro:firstTime>
<vitro:loginCount rdf:datatype="http://www.w3.org/2001/XMLSchema#int">1</vitro:loginCount>
</vitro:User>
<vitro:User rdf:about="http://vivo.mydomain.edu/individual/SallyEditor">
<vitro:username rdf:datatype="http://www.w3.org/2001/XMLSchema#string">Sally Editor</vitro:username>
<vitro:md5password rdf:datatype="http://www.w3.org/2001/XMLSchema#string">8A1A62B7B58B8B95564483BEA60CD99A</vitro:md5password>
<vitro:roleURI rdf:datatype="http://www.w3.org/2001/XMLSchema#string">role:/4</vitro:roleURI>
<vitro:firstTime rdf:datatype="http://www.w3.org/2001/XMLSchema#dateTime">2010-03-09T16:06:45</vitro:firstTime>
<vitro:loginCount rdf:datatype="http://www.w3.org/2001/XMLSchema#int">1</vitro:loginCount>
</vitro:User>
<vitro:User rdf:about="http://vivo.mydomain.edu/individual/JohnCurator">
<vitro:username rdf:datatype="http://www.w3.org/2001/XMLSchema#string">John Curator</vitro:username>
<vitro:md5password rdf:datatype="http://www.w3.org/2001/XMLSchema#string">8A1A62B7B58B8B95564483BEA60CD99A</vitro:md5password>
<vitro:roleURI rdf:datatype="http://www.w3.org/2001/XMLSchema#string">role:/5</vitro:roleURI>
<vitro:firstTime rdf:datatype="http://www.w3.org/2001/XMLSchema#dateTime">2010-03-09T16:06:45</vitro:firstTime>
<vitro:loginCount rdf:datatype="http://www.w3.org/2001/XMLSchema#int">1</vitro:loginCount>
</vitro:User>
</rdf:RDF>

View file

@ -11,7 +11,7 @@ import org.junit.Test;
/**
* TODO
*/
public class ModelCleanerTest {
public class TomcatControllerTest {
// ----------------------------------------------------------------------
// Tests for parseCommandLine()
@ -45,7 +45,7 @@ public class ModelCleanerTest {
private void assertExpectedParsing(String commandLine,
String... expectedPieces) {
assertEquals("parse", Arrays.asList(expectedPieces), ModelCleaner
.parseCommandLine(commandLine));
assertEquals("parse", Arrays.asList(expectedPieces),
TomcatController.parseCommandLine(commandLine));
}
}