blob: 07df1c3a5198e2363837a2bce2b4c5f40f893f6e [file] [log] [blame]
/*******************************************************************************
* Copyright (C) 2012 The University of Manchester
*
* Modifications to the initial code base are copyright of their
* respective authors, or their employers as appropriate.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
******************************************************************************/
package uk.org.taverna.commandline;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintStream;
import java.net.URI;
import java.net.URL;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.comparator.NameFileComparator;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import uk.org.taverna.commandline.WorkflowTestSuite.Workflows;
import uk.org.taverna.scufl2.api.container.WorkflowBundle;
import uk.org.taverna.scufl2.api.io.WorkflowBundleIO;
import uk.org.taverna.scufl2.rdfxml.RDFXMLReader;
/**
* Regression tests for Taverna Command Line Tool.
*
* @author David Withers
*/
@RunWith(WorkflowTestSuite.class)
public class TavernaCommandLineTest {
private static String baseVersion = "2.4.0";
private static boolean baseVersionReleased = true;
private static String testVersion = "3.0.1-SNAPSHOT";
private static boolean testVersionReleased = false;
private static boolean testVersionSupportsScufl2 = true;
private static String script = "executeworkflow.sh";
private static String baseName = "taverna-commandline-" + baseVersion;
private static String testName = "taverna-command-line-" + testVersion;
private static String releasedLocation = "https://launchpad.net/taverna/t2/";
private static String unreleasedLocation = "http://build.mygrid.org.uk/ci/job/t3-taverna-commandline-product/lastSuccessfulBuild/net.sf.taverna.t2$taverna-commandline/artifact/net.sf.taverna.t2/taverna-commandline/";
private static String baseVersionLocation = (baseVersionReleased ? releasedLocation
: unreleasedLocation) + baseVersion + "/+download/" + baseName + ".zip";
private static String testVersionLocation = (testVersionReleased ? releasedLocation
: unreleasedLocation)
+ testVersion
+ "/"
+ testName
+ (testVersionReleased ? ".zip" : "-bin.zip");
private static String baseCommand;
private static String testCommand;
private static File buildDirectory;
private File workflowDirectory;
private File baseOutput;
private File testOutput;
private boolean secure;
private List<File> inputs;
private String ignorePort;
private String message;
public TavernaCommandLineTest(File workflowDirectory) throws Exception {
this.workflowDirectory = workflowDirectory;
if (buildDirectory == null) {
String buildDirectoryLocation = System.getProperty("buildDirectory");
if (buildDirectoryLocation == null) {
buildDirectoryLocation = System.getProperty("user.dir")
+ System.getProperty("file.separator") + "target";
}
buildDirectory = new File(buildDirectoryLocation);
buildDirectory.mkdirs();
}
if (baseCommand == null) {
File commandDirectory = new File(buildDirectory, baseName);
if (!commandDirectory.exists()) {
System.out.println("Fetching " + baseName);
fetchTaverna(baseVersionLocation, baseName);
}
baseCommand = new File(baseName, script).getPath();
}
if (testCommand == null) {
File commandDirectory = new File(buildDirectory, testName);
if (!commandDirectory.exists()) {
System.out.println("Fetching " + testName);
fetchTaverna(testVersionLocation, testName);
}
testCommand = new File(testName, script).getPath();
}
File outputsDirectory = new File(buildDirectory, "test-outputs");
baseOutput = new File(outputsDirectory, workflowDirectory.getName() + "-" + baseVersion);
testOutput = new File(outputsDirectory, workflowDirectory.getName() + "-" + testVersion);
secure = workflowDirectory.getName().startsWith("secure");
inputs = getInputs();
ignorePort = getIgnorePort();
message = "Running {0} with version {1}";
}
@Workflows
public static List<File> workflows() {
List<File> workflows = new ArrayList<File>();
for (File workflowDirectory : getResources("workflows")) {
workflows.add(workflowDirectory);
}
for (File workflowDirectory : getResources("myexperiment")) {
workflows.add(workflowDirectory);
}
return workflows;
}
@Before
public void setup() throws Exception {
if (!baseOutput.exists()) {
if (baseVersion.equals("2.3.0") && workflowDirectory.getName().equals("tool"))
return;// version 2.3.0 is missing tool plugin
String workflow = getWorkflow().toASCIIString();
System.out.println(MessageFormat.format(message, workflow, baseVersion)
+ (inputs.size() > 0 ? " using input values" : ""));
runWorkflow(baseCommand, workflow, baseOutput, true, secure, false);
assertTrue(String.format("No output produced for %s", workflowDirectory.getName()),
baseOutput.exists());
}
}
public boolean testExcluded() {
// version 3.0.0 is missing biomoby activity
if (testVersion.startsWith("3.") && workflowDirectory.getName().contains("biomoby"))
return true;
// version 3.0.0 is missing tool activity
if (testVersion.startsWith("3.")
&& workflowDirectory.getName().equals("unix_external_tools_with_zip_and_unzip"))
return true;
if (testVersion.startsWith("3.")
&& workflowDirectory.getName().equals("unix_numerically_adding_two_values"))
return true;
if (testVersion.startsWith("3.")
&& workflowDirectory.getName().equals("unix_tool_service_using_string_replacement"))
return true;
// version 3.0.0 is missing looping configuration
if (testVersion.startsWith("3.")
&& workflowDirectory.getName().equals("ebi_interproscan_newservices"))
return true;
if (testVersion.startsWith("3.")
&& workflowDirectory.getName().equals("biomartandembossanalysis"))
return true;
return false;
}
@Test
public void testWorkflowWithoutInputs() throws Exception {
assumeTrue(!testExcluded());
assumeTrue(baseOutput.exists());
assumeTrue(inputs.isEmpty());
FileUtils.deleteDirectory(testOutput);
String workflow = getWorkflow().toASCIIString();
System.out.println(MessageFormat.format(message, workflow, testVersion));
runWorkflow(testCommand, workflow, testOutput, true, secure, false);
assertTrue(String.format("No output produced for %s", workflowDirectory.getName()),
testOutput.exists());
assertOutputsEquals(baseOutput, testOutput);
}
@Test
public void testWorkflowWithInputValues() throws Exception {
assumeTrue(!testExcluded());
assumeTrue(baseOutput.exists());
assumeTrue(inputs.size() > 0);
FileUtils.deleteDirectory(testOutput);
String workflow = getWorkflow().toASCIIString();
System.out.println(MessageFormat.format(message, workflow, testVersion)
+ " using input values");
runWorkflow(testCommand, workflow, testOutput, true, secure, false);
assertTrue(String.format("No output produced for %s", workflowDirectory.getName()),
testOutput.exists());
assertOutputsEquals(baseOutput, testOutput);
}
@Test
public void testWorkflowWithInputFiles() throws Exception {
assumeTrue(!testExcluded());
assumeTrue(baseOutput.exists());
assumeTrue(inputs.size() > 0);
FileUtils.deleteDirectory(testOutput);
String workflow = getWorkflow().toASCIIString();
System.out.println(MessageFormat.format(message, workflow, testVersion)
+ " using input files");
runWorkflow(testCommand, workflow, testOutput, false, secure, false);
assertTrue(String.format("No output produced for %s", workflowDirectory.getName()),
testOutput.exists());
assertOutputsEquals(baseOutput, testOutput);
}
@Test
@Ignore
public void testWorkflowWithDatabase() throws Exception {
assumeTrue(!testExcluded());
assumeTrue(baseOutput.exists());
assumeTrue(inputs.size() > 0);
FileUtils.deleteDirectory(testOutput);
String workflow = getWorkflow().toASCIIString();
System.out
.println(MessageFormat.format(message, workflow, testVersion) + " using database");
runWorkflow(testCommand, workflow, testOutput, true, secure, true);
assertTrue(String.format("No output produced for %s", workflowDirectory.getName()),
testOutput.exists());
assertOutputsEquals(baseOutput, testOutput);
}
@Test
public void testScufl2Workflow() throws Exception {
assumeTrue(!testExcluded());
assumeTrue(baseOutput.exists());
assumeTrue(testVersionSupportsScufl2);
FileUtils.deleteDirectory(testOutput);
String workflow = getScufl2Workflow().toASCIIString();
System.out.println(MessageFormat.format(message, workflow, testVersion)
+ (inputs.size() > 0 ? " using input values" : ""));
runWorkflow(testCommand, workflow, testOutput, true, secure, true);
assertTrue(String.format("No output produced for %s", workflowDirectory.getName()),
testOutput.exists());
assertOutputsEquals(baseOutput, testOutput);
}
private synchronized void runWorkflow(String command, String workflow, File outputsDirectory,
boolean inputValues, boolean secure, boolean database) throws Exception {
ProcessBuilder processBuilder = new ProcessBuilder("sh", command);
processBuilder.redirectErrorStream(true);
processBuilder.directory(buildDirectory);
List<String> args = processBuilder.command();
for (File input : inputs) {
if (inputValues) {
args.add("-inputvalue");
args.add(input.getName());
args.add(IOUtils.toString(new FileReader(input)));
} else {
args.add("-inputfile");
args.add(input.getName());
args.add(input.getAbsolutePath());
}
}
args.add("-outputdir");
args.add(outputsDirectory.getPath());
if (secure) {
args.add("-cmdir");
args.add(getClass().getResource("/security").getFile());
args.add("-cmpassword");
}
if (database) {
args.add("-embedded");
}
args.add(workflow);
Process process = processBuilder.start();
if (secure) {
PrintStream outputStream = new PrintStream(process.getOutputStream());
outputStream.println("test");
outputStream.flush();
}
waitFor(process);
}
private URI getWorkflow() throws Exception {
File workflow = new File(workflowDirectory, workflowDirectory.getName() + ".t2flow");
if (!workflow.exists()) {
workflow = new File(workflowDirectory, workflowDirectory.getName() + ".url");
return new URI(IOUtils.toString(new FileReader(workflow)));
}
return workflow.toURI();
}
private URI getScufl2Workflow() throws Exception {
File workflow = new File(buildDirectory, workflowDirectory.getName() + ".wfbundle");
// if (!workflow.exists()) {
WorkflowBundleIO workflowBundleIO = new WorkflowBundleIO();
WorkflowBundle bundle = workflowBundleIO.readBundle(getWorkflow().toURL(), null);
workflowBundleIO.writeBundle(bundle, workflow,
RDFXMLReader.APPLICATION_VND_TAVERNA_SCUFL2_WORKFLOW_BUNDLE);
// }
return workflow.toURI();
}
private synchronized int waitFor(Process process) throws IOException {
while (true) {
try {
wait(500);
} catch (InterruptedException e) {
}
IOUtils.copy(process.getInputStream(), System.out);
try {
return process.exitValue();
} catch (IllegalThreadStateException e) {
}
}
}
private void assertOutputsEquals(File directory1, File directory2) {
File[] directory1Files = directory1.listFiles();
File[] directory2Files = directory2.listFiles();
// assert directories contain same number of files
assertEquals(String.format("%s has %s files but %s has %s files", directory1.getName(),
directory1Files.length, directory2.getName(), directory2Files.length),
directory1Files.length, directory2Files.length);
// sort files in directory
Arrays.sort(directory1Files, NameFileComparator.NAME_SYSTEM_COMPARATOR);
Arrays.sort(directory2Files, NameFileComparator.NAME_SYSTEM_COMPARATOR);
for (int i = 0; i < directory1Files.length; i++) {
assertFilesEqual(directory1Files[i], directory2Files[i], !directory1Files[i].getName()
.equals(ignorePort));
}
}
private void assertDirectoriesEquals(File directory1, File directory2, boolean checkFileContents) {
if (directory1.exists()) {
assertTrue(String.format("%s exists but %s does not", directory1, directory2),
directory2.exists());
} else {
assertFalse(String.format("%s does not exists but %s does", directory1, directory2),
directory2.exists());
}
File[] directory1Files = directory1.listFiles();
File[] directory2Files = directory2.listFiles();
// assert directories contain same number of files
assertEquals(String.format("%s has %s files but %s has %s files", directory1.getName(),
directory1Files.length, directory2.getName(), directory2Files.length),
directory1Files.length, directory2Files.length);
// sort files in directory
Arrays.sort(directory1Files, NameFileComparator.NAME_SYSTEM_COMPARATOR);
Arrays.sort(directory2Files, NameFileComparator.NAME_SYSTEM_COMPARATOR);
for (int i = 0; i < directory1Files.length; i++) {
assertFilesEqual(directory1Files[i], directory2Files[i], checkFileContents);
}
}
private void assertFilesEqual(File file1, File file2, boolean checkFileContents) {
if (file1.isHidden()) {
assertTrue(String.format("%s is hidden but %s is not", file1, file2), file2.isHidden());
} else {
assertFalse(String.format("%s is not hidden but %s is", file1, file2), file2.isHidden());
assertEquals(file1.getName(), file2.getName());
if (file1.isDirectory()) {
assertTrue(String.format("%s is a directory but %s is not", file1, file2),
file2.isDirectory());
assertDirectoriesEquals(file1, file2, checkFileContents);
} else {
assertFalse(String.format("%s is not a directory but %s is", file1, file2),
file2.isDirectory());
if (isZipFile(file1)) {
assertZipFilesEqual(file1, file2);
} else if (checkFileContents) {
assertEquals(String.format("%s is a different length to %s", file1, file2),
file1.length(), file2.length());
try {
byte[] byteArray1 = IOUtils.toByteArray(new FileReader(file1));
byte[] byteArray2 = IOUtils.toByteArray(new FileReader(file2));
assertArrayEquals(String.format("%s != %s", file1, file2), byteArray1,
byteArray2);
} catch (FileNotFoundException e) {
fail(e.getMessage());
} catch (IOException e) {
fail(e.getMessage());
}
}
}
}
}
private void assertZipFilesEqual(File file1, File file2) {
ZipFile zipFile1 = null;
ZipFile zipFile2 = null;
try {
zipFile1 = new ZipFile(file1);
zipFile2 = new ZipFile(file2);
} catch (Exception e) {
assertTrue(String.format("%s and %s are not both zip files"), zipFile1 == null);
}
if (zipFile1 != null && zipFile2 != null) {
Enumeration<? extends ZipEntry> entries1 = zipFile1.entries();
Enumeration<? extends ZipEntry> entries2 = zipFile2.entries();
while (entries1.hasMoreElements()) {
assertTrue(entries2.hasMoreElements());
ZipEntry zipEntry1 = entries1.nextElement();
ZipEntry zipEntry2 = entries2.nextElement();
assertEquals(
String.format("%s and %s are not both directories", zipEntry1, zipEntry2),
zipEntry1.isDirectory(), zipEntry2.isDirectory());
assertEquals(String.format("%s and %s have different names", zipEntry1, zipEntry2),
zipEntry1.getName(), zipEntry2.getName());
assertEquals(String.format("%s and %s have different sizes", zipEntry1, zipEntry2),
zipEntry1.getSize(), zipEntry2.getSize());
try {
byte[] byteArray1 = IOUtils.toByteArray(zipFile1.getInputStream(zipEntry1));
byte[] byteArray2 = IOUtils.toByteArray(zipFile2.getInputStream(zipEntry2));
assertArrayEquals(String.format("%s != %s", zipEntry1, zipEntry2), byteArray1,
byteArray2);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
assertFalse(entries2.hasMoreElements());
}
}
private boolean isZipFile(File file) {
try {
new ZipFile(file);
return true;
} catch (Exception e) {
return false;
}
}
private static File[] getResources(String directory) {
return new File(TavernaCommandLineTest.class.getResource("/" + directory).getFile())
.listFiles();
}
private List<File> getInputs() {
File inputsDirectory = new File(workflowDirectory, "inputs");
if (inputsDirectory.exists() && inputsDirectory.isDirectory()) {
return Arrays.asList(inputsDirectory.listFiles());
}
return Collections.emptyList();
}
private String getIgnorePort() throws Exception {
File ignorePort = new File(workflowDirectory, "ignorePort");
if (ignorePort.exists()) {
return IOUtils.toString(new FileReader(ignorePort));
}
return "";
}
private void fetchTaverna(String location, String name) throws Exception {
File zipFile = new File(buildDirectory, name + ".zip");
IOUtils.copy(new URL(location).openStream(), new FileOutputStream(zipFile));
ProcessBuilder processBuilder = new ProcessBuilder("unzip", "-q", name);
processBuilder.redirectErrorStream(true);
processBuilder.directory(buildDirectory);
System.out.println(processBuilder.command());
Process process = processBuilder.start();
waitFor(process);
}
}