| /******************************************************************************* |
| * 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 org.apache.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 org.apache.taverna.commandline.WorkflowTestSuite.Workflows; |
| import org.apache.taverna.scufl2.api.container.WorkflowBundle; |
| import org.apache.taverna.scufl2.api.io.WorkflowBundleIO; |
| import org.apache.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); |
| } |
| |
| } |