/*******************************************************************************
* Copyright 2006 - 2014 Vienna University of Technology,
* Department of Software Technology and Interactive Systems, IFS
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations under the License.
******************************************************************************/
package eu.scape_project.planning.services.taverna.generator;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.parsers.ParserConfigurationException;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Node;
import org.dom4j.XPath;
import org.dom4j.io.SAXReader;
import org.junit.BeforeClass;
import org.junit.Test;
import org.xml.sax.SAXException;
import eu.scape_project.planning.services.myexperiment.domain.ComponentConstants;
import eu.scape_project.planning.services.myexperiment.domain.MigrationPath;
import eu.scape_project.planning.services.myexperiment.domain.Port;
import eu.scape_project.planning.services.myexperiment.domain.WorkflowDescription;
import eu.scape_project.planning.services.taverna.generator.T2FlowExecutablePlanGenerator;
import eu.scape_project.planning.services.taverna.generator.T2FlowExecutablePlanGenerator.InputSource;
import eu.scape_project.planning.services.taverna.generator.T2FlowExecutablePlanGenerator.RelatedObject;
/**
* Unit tests for T2FlowExecutablePlanGenerator.
*/
public class T2FlowExecutablePlanGeneratorTest {
private static final String MIGRATION_DATAFLOW_ID = "00000000-0000-0000-0000-000000000000";
private static final String QA_DATAFLOW_ID = "11111111-1111-1111-1111-111111111111";
private static final String CC_DATAFLOW_ID = "22222222-2222-2222-2222-222222222222";
protected static final Map<String, String> T2FLOW_NAMESPACE_MAP = new HashMap<String, String>();
private static final String TOP_WF = "/t2f:workflow/t2f:dataflow[@role='top']";
private static final String NESTED_WF = "/t2f:workflow/t2f:dataflow[@role='nested']";
private static final List<String> DEFAULT_MEASURES = new ArrayList<String>();
protected static final Map<String, String> DEFAULT_PARAMETERS = new HashMap<String, String>();
@BeforeClass
public static void setup() {
T2FLOW_NAMESPACE_MAP.put("t2f", "http://taverna.sf.net/2008/xml/t2flow");
DEFAULT_MEASURES.add("http://purl.org/DP/quality/measures#1");
}
@Test
public void createEmptyWorkflow() throws IOException, ParserConfigurationException, SAXException, DocumentException {
T2FlowExecutablePlanGenerator planGenerator = new T2FlowExecutablePlanGenerator("Name", "Author", "image/tiff",
"image/jp2");
Document doc = getDocument(planGenerator);
assertThat(getContent(doc, TOP_WF + "/t2f:name"), is("Name"));
assertThat(
getContent(
doc,
TOP_WF
+ "/t2f:annotations/t2f:annotation_chain/net.sf.taverna.t2.annotation.AnnotationChainImpl/annotationAssertions/net.sf.taverna.t2.annotation.AnnotationAssertionImpl/annotationBean[@class='net.sf.taverna.t2.annotation.annotationbeans.Author']/text"),
is("Author"));
String wfAnnotations = getSemanticAnnotation(doc, TOP_WF);
assertThat(wfAnnotations, containsString("http://purl.org/DP/components#ExecutablePlan"));
assertThat(wfAnnotations, containsString("image/tiff"));
assertThat(wfAnnotations, containsString("image/jp2"));
}
@Test
public void addSourcePort() throws IOException, ParserConfigurationException, SAXException, DocumentException {
T2FlowExecutablePlanGenerator planGenerator = new T2FlowExecutablePlanGenerator("Name", "Author", "image/tiff",
"image/jp2");
planGenerator.addSourcePort();
Document doc = getDocument(planGenerator);
assertThat(getContent(doc, TOP_WF + "/t2f:inputPorts/t2f:port/t2f:name"), is("source"));
assertThat(getContent(doc, TOP_WF + "/t2f:inputPorts/t2f:port/t2f:depth"), is("0"));
assertThat(getSemanticAnnotation(doc, TOP_WF + "/t2f:inputPorts/t2f:port"),
containsString(ComponentConstants.VALUE_SOURCE_OBJECT));
}
@Test
public void addSourcePort_depth() throws IOException, ParserConfigurationException, SAXException, DocumentException {
T2FlowExecutablePlanGenerator planGenerator = new T2FlowExecutablePlanGenerator("Name", "Author", "image/tiff",
"image/jp2");
planGenerator.addSourcePort(7);
Document doc = getDocument(planGenerator);
assertThat(getContent(doc, TOP_WF + "/t2f:inputPorts/t2f:port/t2f:name"), is("source"));
assertThat(getContent(doc, TOP_WF + "/t2f:inputPorts/t2f:port/t2f:depth"), is("7"));
assertThat(getSemanticAnnotation(doc, TOP_WF + "/t2f:inputPorts/t2f:port"),
containsString(ComponentConstants.VALUE_SOURCE_OBJECT));
}
@Test
public void addTargetPort() throws IOException, ParserConfigurationException, SAXException, DocumentException {
T2FlowExecutablePlanGenerator planGenerator = new T2FlowExecutablePlanGenerator("Name", "Author", "image/tiff",
"image/jp2");
planGenerator.addTargetPort();
Document doc = getDocument(planGenerator);
assertThat(getContent(doc, TOP_WF + "/t2f:outputPorts/t2f:port/t2f:name"), is("target"));
assertThat(getSemanticAnnotation(doc, TOP_WF + "/t2f:outputPorts/t2f:port"),
containsString(ComponentConstants.VALUE_TARGET_OBJECT));
}
@Test
public void addMeasurePort_purlDp() throws IOException, ParserConfigurationException, SAXException,
DocumentException {
T2FlowExecutablePlanGenerator planGenerator = new T2FlowExecutablePlanGenerator("Name", "Author", "image/tiff",
"image/jp2");
planGenerator.addMeasurePort("http://purl.org/DP/quality/measures#1");
Document doc = getDocument(planGenerator);
String portName = getContent(doc, TOP_WF + "/t2f:outputPorts/t2f:port/t2f:name");
assertThat(portName, is("measures_1"));
String portAnnotations = getSemanticAnnotation(doc, TOP_WF + "/t2f:outputPorts/t2f:port");
assertThat(portAnnotations, containsString("http://purl.org/DP/quality/measures#1"));
}
@Test
public void addMeasurePort_generic() throws IOException, ParserConfigurationException, SAXException,
DocumentException {
T2FlowExecutablePlanGenerator planGenerator = new T2FlowExecutablePlanGenerator("Name", "Author", "image/tiff",
"image/jp2");
planGenerator.addMeasurePort("http://example.com/DP/measures#1");
Document doc = getDocument(planGenerator);
String portName = getContent(doc, TOP_WF + "/t2f:outputPorts/t2f:port/t2f:name");
assertThat(portName, is("example_com_DP_measures_1"));
String portAnnotations = getSemanticAnnotation(doc, TOP_WF + "/t2f:outputPorts/t2f:port");
assertThat(portAnnotations, containsString("http://example.com/DP/measures#1"));
}
@Test
public void addMigrationComponent() throws IOException, ParserConfigurationException, SAXException,
DocumentException {
T2FlowExecutablePlanGenerator planGenerator = new T2FlowExecutablePlanGenerator("Name", "Author", "image/tiff",
"image/jp2");
planGenerator.addSourcePort();
planGenerator.addTargetPort();
addMigrationMock(planGenerator);
Document doc = getDocument(planGenerator);
assertThat(getContent(doc, TOP_WF + "/t2f:processors/t2f:processor/t2f:name"), is("Migration"));
assertThat(getContent(doc, NESTED_WF + "/t2f:name"), is("Migration component"));
assertThat(
getContent(doc, TOP_WF
+ "/t2f:processors/t2f:processor/t2f:activities/t2f:activity/t2f:configBean/t2f:dataflow/@ref"),
is(MIGRATION_DATAFLOW_ID));
assertThat(
getSingleNode(doc, TOP_WF + "/t2f:datalinks/t2f:datalink"
+ "[t2f:source[@type='dataflow' and t2f:port/text()='source']" + " and "
+ "t2f:sink[@type='processor' and t2f:port/text()='source']]"), notNullValue());
assertThat(
getSingleNode(doc, TOP_WF + "/t2f:datalinks/t2f:datalink"
+ "[t2f:source[@type='processor' and t2f:port/text()='target']" + " and "
+ "t2f:sink[@type='dataflow' and t2f:port/text()='target']]"), notNullValue());
assertThat(getNodes(doc, TOP_WF + "/t2f:datalinks/t2f:datalink").size(), is(2));
}
@Test
public void addQaComponent_noMigration() throws IOException, ParserConfigurationException, SAXException,
DocumentException {
T2FlowExecutablePlanGenerator planGenerator = new T2FlowExecutablePlanGenerator("Name", "Author", "image/tiff",
"image/jp2");
planGenerator.addSourcePort();
planGenerator.addTargetPort();
WorkflowDescription wf = mockQaAny("QA component");
planGenerator.addQaComponent(wf, generateQaContent(QA_DATAFLOW_ID, "QA component"), DEFAULT_PARAMETERS,
DEFAULT_MEASURES);
Document doc = getDocument(planGenerator);
assertThat(getContent(doc, TOP_WF + "/t2f:processors/t2f:processor/t2f:name"), is("QA_component"));
assertThat(getContent(doc, NESTED_WF + "/t2f:name"), is("QA component"));
assertThat(
getContent(doc, TOP_WF
+ "/t2f:processors/t2f:processor/t2f:activities/t2f:activity/t2f:configBean/t2f:dataflow/@ref"),
is(QA_DATAFLOW_ID));
assertThat(
getSingleNode(doc, TOP_WF + "/t2f:datalinks/t2f:datalink"
+ "[t2f:source[@type='dataflow' and t2f:port/text()='source']" + " and "
+ "t2f:sink[@type='processor' and t2f:port/text()='left']]"), notNullValue());
assertThat(
getSingleNode(doc, TOP_WF + "/t2f:datalinks/t2f:datalink"
+ "[t2f:source[@type='processor' and t2f:port/text()='qa_output']" + " and "
+ "t2f:sink[@type='dataflow' and t2f:port/text()='measures_1']]"), notNullValue());
assertThat(getNodes(doc, TOP_WF + "/t2f:datalinks/t2f:datalink").size(), is(2));
}
@Test
public void addQaComponent_set_sourceLeft_targetRight() throws IOException, ParserConfigurationException,
SAXException, DocumentException {
T2FlowExecutablePlanGenerator planGenerator = new T2FlowExecutablePlanGenerator("Name", "Author", "image/tiff",
"image/jp2");
planGenerator.addSourcePort();
planGenerator.addTargetPort();
addMigrationMock(planGenerator);
WorkflowDescription wf = mockQaAny("QA component");
planGenerator.addQaComponent(wf, generateQaContent(QA_DATAFLOW_ID, "QA component"), InputSource.SOURCE_OBJECT,
InputSource.TARGET_OBJECT, DEFAULT_PARAMETERS, DEFAULT_MEASURES, RelatedObject.RIGHT_OBJECT);
Document doc = getDocument(planGenerator);
assertThat(
getSingleNode(doc, TOP_WF + "/t2f:datalinks/t2f:datalink"
+ "[t2f:source[@type='dataflow' and t2f:port/text()='source']" + " and "
+ "t2f:sink[@type='processor' and t2f:port/text()='left']]"), notNullValue());
assertThat(
getSingleNode(doc, TOP_WF + "/t2f:datalinks/t2f:datalink"
+ "[t2f:source[@type='processor' and t2f:port/text()='target']" + " and "
+ "t2f:sink[@type='processor' and t2f:port/text()='right']]"), notNullValue());
assertThat(
getSingleNode(doc, TOP_WF + "/t2f:datalinks/t2f:datalink"
+ "[t2f:source[@type='processor' and t2f:port/text()='qa_output']" + " and "
+ "t2f:sink[@type='dataflow' and t2f:port/text()='measures_1']]"), notNullValue());
assertThat(getNodes(doc, TOP_WF + "/t2f:datalinks/t2f:datalink").size(), is(5));
}
@Test
public void addQaComponent_set_sourceRight_targetLeft() throws IOException, ParserConfigurationException,
SAXException, DocumentException {
T2FlowExecutablePlanGenerator planGenerator = new T2FlowExecutablePlanGenerator("Name", "Author", "image/tiff",
"image/jp2");
planGenerator.addSourcePort();
planGenerator.addTargetPort();
addMigrationMock(planGenerator);
WorkflowDescription wf = mockQaAny("QA component");
planGenerator.addQaComponent(wf, generateQaContent(QA_DATAFLOW_ID, "QA component"), InputSource.TARGET_OBJECT,
InputSource.SOURCE_OBJECT, DEFAULT_PARAMETERS, DEFAULT_MEASURES, RelatedObject.RIGHT_OBJECT);
Document doc = getDocument(planGenerator);
assertThat(
getSingleNode(doc, TOP_WF + "/t2f:datalinks/t2f:datalink"
+ "[t2f:source[@type='dataflow' and t2f:port/text()='source']" + " and "
+ "t2f:sink[@type='processor' and t2f:port/text()='right']]"), notNullValue());
assertThat(
getSingleNode(doc, TOP_WF + "/t2f:datalinks/t2f:datalink"
+ "[t2f:source[@type='processor' and t2f:port/text()='target']" + " and "
+ "t2f:sink[@type='processor' and t2f:port/text()='left']]"), notNullValue());
assertThat(
getSingleNode(doc, TOP_WF + "/t2f:datalinks/t2f:datalink"
+ "[t2f:source[@type='processor' and t2f:port/text()='qa_output']" + " and "
+ "t2f:sink[@type='dataflow' and t2f:port/text()='measures_1']]"), notNullValue());
assertThat(getNodes(doc, TOP_WF + "/t2f:datalinks/t2f:datalink").size(), is(5));
}
@Test
public void addQaComponent_mimetypePair_sourceLeft_targetRight() throws IOException, ParserConfigurationException,
SAXException, DocumentException {
T2FlowExecutablePlanGenerator planGenerator = new T2FlowExecutablePlanGenerator("Name", "Author", "image/tiff",
"image/jp2");
planGenerator.addSourcePort();
planGenerator.addTargetPort();
addMigrationMock(planGenerator);
WorkflowDescription wf = mockQa("QA component");
when(wf.acceptsMimetypes("image/tiff", "image/jp2")).thenReturn(true);
when(wf.acceptsLeftMimetype("image/tiff")).thenReturn(true);
when(wf.acceptsRightMimetype("image/jp2")).thenReturn(true);
planGenerator.addQaComponent(wf, generateQaContent(QA_DATAFLOW_ID, "QA component"), DEFAULT_PARAMETERS,
DEFAULT_MEASURES);
Document doc = getDocument(planGenerator);
assertThat(
getSingleNode(doc, TOP_WF + "/t2f:datalinks/t2f:datalink"
+ "[t2f:source[@type='dataflow' and t2f:port/text()='source']" + " and "
+ "t2f:sink[@type='processor' and t2f:port/text()='left']]"), notNullValue());
assertThat(
getSingleNode(doc, TOP_WF + "/t2f:datalinks/t2f:datalink"
+ "[t2f:source[@type='processor' and t2f:port/text()='target']" + " and "
+ "t2f:sink[@type='processor' and t2f:port/text()='right']]"), notNullValue());
assertThat(
getSingleNode(doc, TOP_WF + "/t2f:datalinks/t2f:datalink"
+ "[t2f:source[@type='processor' and t2f:port/text()='qa_output']" + " and "
+ "t2f:sink[@type='dataflow' and t2f:port/text()='measures_1']]"), notNullValue());
assertThat(getNodes(doc, TOP_WF + "/t2f:datalinks/t2f:datalink").size(), is(5));
}
@Test
public void addQaComponent_mimetypePair_sourceRight_targetLeft() throws IOException, ParserConfigurationException,
SAXException, DocumentException {
T2FlowExecutablePlanGenerator planGenerator = new T2FlowExecutablePlanGenerator("Name", "Author", "image/tiff",
"image/jp2");
planGenerator.addSourcePort();
planGenerator.addTargetPort();
addMigrationMock(planGenerator);
WorkflowDescription wf = mockQa("QA component");
when(wf.acceptsMimetypes("image/jp2", "image/tiff")).thenReturn(true);
when(wf.acceptsLeftMimetype("image/jp2")).thenReturn(true);
when(wf.acceptsRightMimetype("image/tiff")).thenReturn(true);
planGenerator.addQaComponent(wf, generateQaContent(QA_DATAFLOW_ID, "QA component"), DEFAULT_PARAMETERS,
DEFAULT_MEASURES);
Document doc = getDocument(planGenerator);
assertThat(
getSingleNode(doc, TOP_WF + "/t2f:datalinks/t2f:datalink"
+ "[t2f:source[@type='dataflow' and t2f:port/text()='source']" + " and "
+ "t2f:sink[@type='processor' and t2f:port/text()='right']]"), notNullValue());
assertThat(
getSingleNode(doc, TOP_WF + "/t2f:datalinks/t2f:datalink"
+ "[t2f:source[@type='processor' and t2f:port/text()='target']" + " and "
+ "t2f:sink[@type='processor' and t2f:port/text()='left']]"), notNullValue());
assertThat(
getSingleNode(doc, TOP_WF + "/t2f:datalinks/t2f:datalink"
+ "[t2f:source[@type='processor' and t2f:port/text()='qa_output']" + " and "
+ "t2f:sink[@type='dataflow' and t2f:port/text()='measures_1']]"), notNullValue());
assertThat(getNodes(doc, TOP_WF + "/t2f:datalinks/t2f:datalink").size(), is(5));
}
@Test
public void addQaComponent_mimetypePair_sourceBoth_targetBoth() throws IOException, ParserConfigurationException,
SAXException, DocumentException {
T2FlowExecutablePlanGenerator planGenerator = new T2FlowExecutablePlanGenerator("Name", "Author", "image/tiff",
"image/jp2");
planGenerator.addSourcePort();
planGenerator.addTargetPort();
addMigrationMock(planGenerator);
WorkflowDescription wf = mockQa("QA component");
when(wf.acceptsMimetypes("image/jp2", "image/tiff")).thenReturn(true);
when(wf.acceptsMimetypes("image/tiff", "image/jp2")).thenReturn(true);
when(wf.acceptsLeftMimetype("image/jp2")).thenReturn(true);
when(wf.acceptsLeftMimetype("image/tiff")).thenReturn(true);
when(wf.acceptsRightMimetype("image/jp2")).thenReturn(true);
when(wf.acceptsRightMimetype("image/tiff")).thenReturn(true);
planGenerator.addQaComponent(wf, generateQaContent(QA_DATAFLOW_ID, "QA component"), DEFAULT_PARAMETERS,
DEFAULT_MEASURES);
Document doc = getDocument(planGenerator);
assertThat(
getSingleNode(doc, TOP_WF + "/t2f:datalinks/t2f:datalink"
+ "[t2f:source[@type='dataflow' and t2f:port/text()='source']" + " and "
+ "t2f:sink[@type='processor' and t2f:port/text()='left']]"), notNullValue());
assertThat(
getSingleNode(doc, TOP_WF + "/t2f:datalinks/t2f:datalink"
+ "[t2f:source[@type='processor' and t2f:port/text()='target']" + " and "
+ "t2f:sink[@type='processor' and t2f:port/text()='right']]"), notNullValue());
assertThat(
getSingleNode(doc, TOP_WF + "/t2f:datalinks/t2f:datalink"
+ "[t2f:source[@type='processor' and t2f:port/text()='qa_output']" + " and "
+ "t2f:sink[@type='dataflow' and t2f:port/text()='measures_1']]"), notNullValue());
assertThat(getNodes(doc, TOP_WF + "/t2f:datalinks/t2f:datalink").size(), is(5));
}
@Test
public void addQaComponent_mimetypePair_sourcePair_targetPair() throws IOException, ParserConfigurationException,
SAXException, DocumentException {
T2FlowExecutablePlanGenerator planGenerator = new T2FlowExecutablePlanGenerator("Name", "Author", "image/tiff",
"image/jp2");
planGenerator.addSourcePort();
planGenerator.addTargetPort();
addMigrationMock(planGenerator);
WorkflowDescription wf = mockQa("QA component");
when(wf.acceptsMimetypes("image/tiff", "image/tiff")).thenReturn(true);
when(wf.acceptsMimetypes("image/jp2", "image/jp2")).thenReturn(true);
when(wf.acceptsLeftMimetype("image/jp2")).thenReturn(true);
when(wf.acceptsLeftMimetype("image/tiff")).thenReturn(true);
when(wf.acceptsRightMimetype("image/jp2")).thenReturn(true);
when(wf.acceptsRightMimetype("image/tiff")).thenReturn(true);
planGenerator.addQaComponent(wf, generateQaContent(QA_DATAFLOW_ID, "QA component"), DEFAULT_PARAMETERS,
DEFAULT_MEASURES);
Document doc = getDocument(planGenerator);
assertThat(
getSingleNode(doc, TOP_WF + "/t2f:datalinks/t2f:datalink"
+ "[t2f:source[@type='dataflow' and t2f:port/text()='source']" + " and "
+ "t2f:sink[@type='processor' and t2f:port/text()='left']]"), notNullValue());
assertThat(
getSingleNode(doc, TOP_WF + "/t2f:datalinks/t2f:datalink"
+ "[t2f:source[@type='processor' and t2f:port/text()='target']" + " and "
+ "t2f:sink[@type='processor' and t2f:port/text()='left']]"), nullValue());
assertThat(
getSingleNode(doc, TOP_WF + "/t2f:datalinks/t2f:datalink"
+ "[t2f:source[@type='processor' and t2f:port/text()='target']" + " and "
+ "t2f:sink[@type='processor' and t2f:port/text()='right']]"), nullValue());
assertThat(
getSingleNode(doc, TOP_WF + "/t2f:datalinks/t2f:datalink"
+ "[t2f:source[@type='processor' and t2f:port/text()='qa_output']" + " and "
+ "t2f:sink[@type='dataflow' and t2f:port/text()='measures_1']]"), notNullValue());
assertThat(getNodes(doc, TOP_WF + "/t2f:datalinks/t2f:datalink").size(), is(4));
}
@Test
public void addQaComponent_mimetypePair_sourceLeft_targetNone() throws IOException, ParserConfigurationException,
SAXException, DocumentException {
T2FlowExecutablePlanGenerator planGenerator = new T2FlowExecutablePlanGenerator("Name", "Author", "image/tiff",
"image/jp2");
planGenerator.addSourcePort();
planGenerator.addTargetPort();
addMigrationMock(planGenerator);
WorkflowDescription wf = mockQa("QA component");
when(wf.acceptsLeftMimetype("image/tiff")).thenReturn(true);
planGenerator.addQaComponent(wf, generateQaContent(QA_DATAFLOW_ID, "QA component"), DEFAULT_PARAMETERS,
DEFAULT_MEASURES);
Document doc = getDocument(planGenerator);
assertThat(
getSingleNode(doc, TOP_WF + "/t2f:datalinks/t2f:datalink"
+ "[t2f:source[@type='dataflow' and t2f:port/text()='source']" + " and "
+ "t2f:sink[@type='processor' and t2f:port/text()='left']]"), notNullValue());
assertThat(
getSingleNode(doc, TOP_WF + "/t2f:datalinks/t2f:datalink"
+ "[t2f:source[@type='processor' and t2f:port/text()='target']" + " and "
+ "t2f:sink[@type='processor' and t2f:port/text()='left']]"), nullValue());
assertThat(
getSingleNode(doc, TOP_WF + "/t2f:datalinks/t2f:datalink"
+ "[t2f:source[@type='processor' and t2f:port/text()='target']" + " and "
+ "t2f:sink[@type='processor' and t2f:port/text()='right']]"), nullValue());
assertThat(
getSingleNode(doc, TOP_WF + "/t2f:datalinks/t2f:datalink"
+ "[t2f:source[@type='processor' and t2f:port/text()='qa_output']" + " and "
+ "t2f:sink[@type='dataflow' and t2f:port/text()='measures_1']]"), notNullValue());
assertThat(getNodes(doc, TOP_WF + "/t2f:datalinks/t2f:datalink").size(), is(4));
}
@Test
public void addQaComponent_mimetypePair_sourceRight_targetNone() throws IOException, ParserConfigurationException,
SAXException, DocumentException {
T2FlowExecutablePlanGenerator planGenerator = new T2FlowExecutablePlanGenerator("Name", "Author", "image/tiff",
"image/jp2");
planGenerator.addSourcePort();
planGenerator.addTargetPort();
addMigrationMock(planGenerator);
WorkflowDescription wf = mockQa("QA component");
when(wf.acceptsRightMimetype("image/tiff")).thenReturn(true);
planGenerator.addQaComponent(wf, generateQaContent(QA_DATAFLOW_ID, "QA component"), DEFAULT_PARAMETERS,
DEFAULT_MEASURES);
Document doc = getDocument(planGenerator);
assertThat(
getSingleNode(doc, TOP_WF + "/t2f:datalinks/t2f:datalink"
+ "[t2f:source[@type='dataflow' and t2f:port/text()='source']" + " and "
+ "t2f:sink[@type='processor' and t2f:port/text()='right']]"), notNullValue());
assertThat(
getSingleNode(doc, TOP_WF + "/t2f:datalinks/t2f:datalink"
+ "[t2f:source[@type='processor' and t2f:port/text()='target']" + " and "
+ "t2f:sink[@type='processor' and t2f:port/text()='left']]"), nullValue());
assertThat(
getSingleNode(doc, TOP_WF + "/t2f:datalinks/t2f:datalink"
+ "[t2f:source[@type='processor' and t2f:port/text()='target']" + " and "
+ "t2f:sink[@type='processor' and t2f:port/text()='right']]"), nullValue());
assertThat(
getSingleNode(doc, TOP_WF + "/t2f:datalinks/t2f:datalink"
+ "[t2f:source[@type='processor' and t2f:port/text()='qa_output']" + " and "
+ "t2f:sink[@type='dataflow' and t2f:port/text()='measures_1']]"), notNullValue());
assertThat(getNodes(doc, TOP_WF + "/t2f:datalinks/t2f:datalink").size(), is(4));
}
@Test
public void addQaComponent_mimetypePair_sourceNone_targetLeft() throws IOException, ParserConfigurationException,
SAXException, DocumentException {
T2FlowExecutablePlanGenerator planGenerator = new T2FlowExecutablePlanGenerator("Name", "Author", "image/tiff",
"image/jp2");
planGenerator.addSourcePort();
planGenerator.addTargetPort();
addMigrationMock(planGenerator);
WorkflowDescription wf = mockQa("QA component");
when(wf.acceptsLeftMimetype("image/jp2")).thenReturn(true);
planGenerator.addQaComponent(wf, generateQaContent(QA_DATAFLOW_ID, "QA component"), DEFAULT_PARAMETERS,
DEFAULT_MEASURES);
Document doc = getDocument(planGenerator);
assertThat(
getSingleNode(doc, TOP_WF + "/t2f:datalinks/t2f:datalink"
+ "[t2f:source[@type='dataflow' and t2f:port/text()='source']" + " and "
+ "t2f:sink[@type='processor' and t2f:port/text()='left']]"), nullValue());
assertThat(
getSingleNode(doc, TOP_WF + "/t2f:datalinks/t2f:datalink"
+ "[t2f:source[@type='dataflow' and t2f:port/text()='source']" + " and "
+ "t2f:sink[@type='processor' and t2f:port/text()='right']]"), nullValue());
assertThat(
getSingleNode(doc, TOP_WF + "/t2f:datalinks/t2f:datalink"
+ "[t2f:source[@type='processor' and t2f:port/text()='target']" + " and "
+ "t2f:sink[@type='processor' and t2f:port/text()='left']]"), notNullValue());
assertThat(
getSingleNode(doc, TOP_WF + "/t2f:datalinks/t2f:datalink"
+ "[t2f:source[@type='processor' and t2f:port/text()='qa_output']" + " and "
+ "t2f:sink[@type='dataflow' and t2f:port/text()='measures_1']]"), notNullValue());
assertThat(getNodes(doc, TOP_WF + "/t2f:datalinks/t2f:datalink").size(), is(4));
}
@Test
public void addQaComponent_mimetypePair_sourceNone_targetRight() throws IOException, ParserConfigurationException,
SAXException, DocumentException {
T2FlowExecutablePlanGenerator planGenerator = new T2FlowExecutablePlanGenerator("Name", "Author", "image/tiff",
"image/jp2");
planGenerator.addSourcePort();
planGenerator.addTargetPort();
addMigrationMock(planGenerator);
WorkflowDescription wf = mockQa("QA component");
when(wf.acceptsRightMimetype("image/jp2")).thenReturn(true);
planGenerator.addQaComponent(wf, generateQaContent(QA_DATAFLOW_ID, "QA component"), DEFAULT_PARAMETERS,
DEFAULT_MEASURES);
Document doc = getDocument(planGenerator);
assertThat(
getSingleNode(doc, TOP_WF + "/t2f:datalinks/t2f:datalink"
+ "[t2f:source[@type='dataflow' and t2f:port/text()='source']" + " and "
+ "t2f:sink[@type='processor' and t2f:port/text()='left']]"), nullValue());
assertThat(
getSingleNode(doc, TOP_WF + "/t2f:datalinks/t2f:datalink"
+ "[t2f:source[@type='dataflow' and t2f:port/text()='source']" + " and "
+ "t2f:sink[@type='processor' and t2f:port/text()='right']]"), nullValue());
assertThat(
getSingleNode(doc, TOP_WF + "/t2f:datalinks/t2f:datalink"
+ "[t2f:source[@type='processor' and t2f:port/text()='target']" + " and "
+ "t2f:sink[@type='processor' and t2f:port/text()='right']]"), notNullValue());
assertThat(
getSingleNode(doc, TOP_WF + "/t2f:datalinks/t2f:datalink"
+ "[t2f:source[@type='processor' and t2f:port/text()='qa_output']" + " and "
+ "t2f:sink[@type='dataflow' and t2f:port/text()='measures_1']]"), notNullValue());
assertThat(getNodes(doc, TOP_WF + "/t2f:datalinks/t2f:datalink").size(), is(4));
}
@Test
public void addQaComponent_twoComponents() throws IOException, ParserConfigurationException, SAXException,
DocumentException {
T2FlowExecutablePlanGenerator planGenerator = new T2FlowExecutablePlanGenerator("Name", "Author", "image/tiff",
"image/jp2");
planGenerator.addSourcePort();
planGenerator.addTargetPort();
addMigrationMock(planGenerator);
WorkflowDescription wf1 = mockQaAny("QA component 1");
planGenerator.addQaComponent(wf1, generateQaContent(QA_DATAFLOW_ID, "QA component 1"), DEFAULT_PARAMETERS,
DEFAULT_MEASURES);
WorkflowDescription wf2 = mockQaAny("QA component 2");
planGenerator.addQaComponent(wf2, generateQaContent(QA_DATAFLOW_ID, "QA component 2"), DEFAULT_PARAMETERS,
DEFAULT_MEASURES);
Document doc = getDocument(planGenerator);
assertThat(
getNodes(
doc,
TOP_WF + "/t2f:datalinks/t2f:datalink" + "[t2f:source[@type='dataflow' and t2f:port/text()='source']"
+ " and " + "t2f:sink[@type='processor' and t2f:port/text()='left']]").size(), is(2));
assertThat(
getNodes(
doc,
TOP_WF + "/t2f:datalinks/t2f:datalink" + "[t2f:source[@type='processor' and t2f:port/text()='target']"
+ " and " + "t2f:sink[@type='processor' and t2f:port/text()='right']]").size(), is(2));
assertThat(
getNodes(
doc,
TOP_WF + "/t2f:datalinks/t2f:datalink"
+ "[t2f:source[@type='processor' and t2f:port/text()='qa_output']" + " and "
+ "t2f:sink[@type='merge' and t2f:port/text()='measures_1']]").size(), is(2));
assertThat(getNodes(doc, TOP_WF + "/t2f:datalinks/t2f:datalink").size(), is(8));
}
@Test
public void addCcComponent_source() throws IOException, ParserConfigurationException, SAXException,
DocumentException {
T2FlowExecutablePlanGenerator planGenerator = new T2FlowExecutablePlanGenerator("Name", "Author", "image/tiff",
"image/jp2");
planGenerator.addSourcePort();
WorkflowDescription wf = mockCcAny("CC Component");
planGenerator.addCcComponent(wf, generateCcContent(CC_DATAFLOW_ID, "CC Component"), DEFAULT_PARAMETERS,
DEFAULT_MEASURES, InputSource.SOURCE_OBJECT);
Document doc = getDocument(planGenerator);
assertThat(
getSingleNode(doc, TOP_WF + "/t2f:datalinks/t2f:datalink"
+ "[t2f:source[@type='dataflow' and t2f:port/text()='source']" + " and "
+ "t2f:sink[@type='processor' and t2f:port/text()='source']]"), notNullValue());
assertThat(
getSingleNode(doc, TOP_WF + "/t2f:datalinks/t2f:datalink"
+ "[t2f:source[@type='processor' and t2f:port/text()='cc_output']" + " and "
+ "t2f:sink[@type='dataflow' and t2f:port/text()='measures_1']]"), notNullValue());
assertThat(getNodes(doc, TOP_WF + "/t2f:datalinks/t2f:datalink").size(), is(2));
}
@Test
public void addCcComponent_target() throws IOException, ParserConfigurationException, SAXException,
DocumentException {
T2FlowExecutablePlanGenerator planGenerator = new T2FlowExecutablePlanGenerator("Name", "Author", "image/tiff",
"image/jp2");
planGenerator.addSourcePort();
planGenerator.addTargetPort();
addMigrationMock(planGenerator);
WorkflowDescription wf = mockCcAny("CC Component");
planGenerator.addCcComponent(wf, generateCcContent(CC_DATAFLOW_ID, "CC Component"), DEFAULT_PARAMETERS,
DEFAULT_MEASURES, InputSource.TARGET_OBJECT);
Document doc = getDocument(planGenerator);
assertThat(
getSingleNode(doc, TOP_WF + "/t2f:datalinks/t2f:datalink"
+ "[t2f:source[@type='processor' and t2f:port/text()='target']" + " and "
+ "t2f:sink[@type='processor' and t2f:port/text()='source']]"), notNullValue());
assertThat(
getSingleNode(doc, TOP_WF + "/t2f:datalinks/t2f:datalink"
+ "[t2f:source[@type='processor' and t2f:port/text()='cc_output']" + " and "
+ "t2f:sink[@type='dataflow' and t2f:port/text()='measures_1']]"), notNullValue());
assertThat(getNodes(doc, TOP_WF + "/t2f:datalinks/t2f:datalink").size(), is(4));
}
@Test
public void addCcComponent_twoComponents() throws IOException, ParserConfigurationException, SAXException,
DocumentException {
T2FlowExecutablePlanGenerator planGenerator = new T2FlowExecutablePlanGenerator("Name", "Author", "image/tiff",
"image/jp2");
planGenerator.addSourcePort();
planGenerator.addTargetPort();
addMigrationMock(planGenerator);
WorkflowDescription wf1 = mockCcAny("CC Component 1");
planGenerator.addCcComponent(wf1, generateCcContent(CC_DATAFLOW_ID, "CC Component 1"), DEFAULT_PARAMETERS,
DEFAULT_MEASURES, InputSource.SOURCE_OBJECT);
WorkflowDescription wf2 = mockCcAny("CC Component 2");
planGenerator.addCcComponent(wf2, generateCcContent(CC_DATAFLOW_ID, "CC Component 2"), DEFAULT_PARAMETERS,
DEFAULT_MEASURES, InputSource.TARGET_OBJECT);
Document doc = getDocument(planGenerator);
assertThat(
getSingleNode(doc, TOP_WF + "/t2f:datalinks/t2f:datalink"
+ "[t2f:source[@type='dataflow' and t2f:port/text()='source']" + " and "
+ "t2f:sink[@type='processor' and t2f:port/text()='source' and t2f:processor/text()='CC_Component_1']]"),
notNullValue());
assertThat(
getSingleNode(doc, TOP_WF + "/t2f:datalinks/t2f:datalink"
+ "[t2f:source[@type='processor' and t2f:port/text()='cc_output' and t2f:processor/text()='CC_Component_1']"
+ " and " + "t2f:sink[@type='merge' and t2f:port/text()='measures_1']]"), notNullValue());
assertThat(
getSingleNode(doc, TOP_WF + "/t2f:datalinks/t2f:datalink"
+ "[t2f:source[@type='processor' and t2f:port/text()='target']" + " and "
+ "t2f:sink[@type='processor' and t2f:port/text()='source' and t2f:processor/text()='CC_Component_2']]"),
notNullValue());
assertThat(
getSingleNode(doc, TOP_WF + "/t2f:datalinks/t2f:datalink"
+ "[t2f:source[@type='processor' and t2f:port/text()='cc_output' and t2f:processor/text()='CC_Component_2']"
+ " and " + "t2f:sink[@type='merge' and t2f:port/text()='measures_1']]"), notNullValue());
assertThat(getNodes(doc, TOP_WF + "/t2f:datalinks/t2f:datalink").size(), is(6));
}
/**
* Returns a document generated by the provided plan generator.
*
* @param planGenerator
* the plan generator
* @return a document
* @throws IOException
* if an exception occurred
* @throws ParserConfigurationException
* if an exception occurred
* @throws SAXException
* if an exception occurred
* @throws DocumentException
* if an exception occurred
*/
private Document getDocument(T2FlowExecutablePlanGenerator planGenerator) throws IOException,
ParserConfigurationException, SAXException, DocumentException {
StringWriter w = new StringWriter();
planGenerator.generate(w);
StringReader r = new StringReader(w.toString());
SAXReader reader = new SAXReader();
return reader.read(r);
}
/**
* Returns nodes of the provided document identified by the xPath.
*
* @param document
* the document
* @param xPath
* the xPath to search
* @return a list of nodes
*/
private List<Node> getNodes(Document document, String xPath) {
XPath x = DocumentHelper.createXPath(xPath);
x.setNamespaceURIs(T2FLOW_NAMESPACE_MAP);
return x.selectNodes(document);
}
/**
* Returns a single node of the provided document identified by the xPath.
*
* @param document
* the document
* @param xPath
* the xPath to search
* @return a single node or null if none found
*/
private Node getSingleNode(Document document, String xPath) {
XPath x = DocumentHelper.createXPath(xPath);
x.setNamespaceURIs(T2FLOW_NAMESPACE_MAP);
return x.selectSingleNode(document);
}
/**
* Returns the content of a single node.
*
* @param document
* the document
* @param xPath
* the xPath to search
* @return content of a single node or null if none found
*/
private String getContent(Document document, String xPath) {
Node n = getSingleNode(document, xPath);
if (n == null) {
return null;
} else {
return n.getText();
}
}
/**
* Returns a semantic annotation of a node.
*
* @param document
* the document
* @param xPathPrefix
* the xPath of the node to search
* @return the semantic annotation of the node or null if none found
*/
private String getSemanticAnnotation(Document document, String xPathPrefix) {
return getContent(
document,
xPathPrefix
+ "/t2f:annotations/t2f:annotation_chain_2_2/net.sf.taverna.t2.annotation.AnnotationChainImpl/annotationAssertions/net.sf.taverna.t2.annotation.AnnotationAssertionImpl/annotationBean[@class='net.sf.taverna.t2.annotation.annotationbeans.SemanticAnnotation']/content");
}
/**
* Generates a very simple migration workflow.
*
* @param uuid
* the UUID of the workflow
* @param name
* the name of the workflow
* @return the workflow as string
*/
private String generateMigrationContent(String uuid, String name) {
// @formatter:off
return "<workflow xmlns=\"http://taverna.sf.net/2008/xml/t2flow\" version=\"1\" producedBy=\"taverna-2.4.0\">"
+ "<dataflow id=\"" + uuid + "\" role=\"top\">"
+ "<name>" + name + "</name>"
+ "<inputPorts><port><name>source</name><depth>0</depth><granularDepth>0</granularDepth><annotations/></port></inputPorts>"
+ "<outputPorts><port><name>target</name><annotations/></port></outputPorts>"
+ "<processors/>"
+ "<conditions/>"
+ "<datalinks><datalink><sink type=\"dataflow\"><port>target</port></sink><source type=\"dataflow\"><port>source</port></source></datalink></datalinks>"
+ "<annotations><annotation_chain_2_2 encoding=\"xstream\"><null/></annotation_chain_2_2></annotations>" + "</dataflow>" + "</workflow>";
// @formatter:on
}
/**
* Generates a very simple QA workflow.
*
* @param uuid
* the UUID of the workflow
* @param name
* the name of the workflow
* @return the workflow as string
*/
private String generateQaContent(String uuid, String name) {
// @formatter:off
return "<workflow xmlns=\"http://taverna.sf.net/2008/xml/t2flow\" version=\"1\" producedBy=\"taverna-2.4.0\">"
+ "<dataflow id=\"" + uuid + "\" role=\"top\">"
+ "<name>" + name + "</name>"
+ "<inputPorts><port><name>left</name><depth>0</depth><granularDepth>0</granularDepth><annotations/></port><port><name>right</name><depth>0</depth><granularDepth>0</granularDepth><annotations/></port></inputPorts>"
+ "<outputPorts><port><name>qa_output</name><annotations/></port></outputPorts>"
+ "<processors/>"
+ "<conditions/>"
+ "<datalinks><datalink>"
+ "<sink type=\"merge\"><port>qa_output</port></sink><source type=\"dataflow\"><port>left</port></source>"
+ "</datalink><datalink>"
+ "<sink type=\"merge\"><port>qa_output</port></sink><source type=\"dataflow\"><port>right</port></source>"
+ "</datalink></datalinks>"
+ "<annotations><annotation_chain_2_2 encoding=\"xstream\"><null/></annotation_chain_2_2></annotations>"
+ "</dataflow>"
+ "</workflow>";
// @formatter:on
}
/**
* Generates a very simple CC workflow.
*
* @param uuid
* the UUID of the workflow
* @param name
* the name of the workflow
* @return the workflow as string
*/
private String generateCcContent(String uuid, String name) {
// @formatter:off
return "<workflow xmlns=\"http://taverna.sf.net/2008/xml/t2flow\" version=\"1\" producedBy=\"taverna-2.4.0\">"
+ "<dataflow id=\"" + uuid + "\" role=\"top\">"
+ "<name>" + name + "</name>"
+ "<inputPorts><port><name>source</name><depth>0</depth><granularDepth>0</granularDepth><annotations/></port></inputPorts>"
+ "<outputPorts><port><name>cc_output</name><annotations/></port></outputPorts>"
+ "<processors/>"
+ "<conditions/>"
+ "<datalinks><datalink>"
+ "<sink type=\"dataflow\"><port>cc_output</port></sink><source type=\"dataflow\"><port>source</port></source>"
+ "</datalink></datalinks>"
+ "<annotations><annotation_chain_2_2 encoding=\"xstream\"><null/></annotation_chain_2_2></annotations>"
+ "</dataflow>"
+ "</workflow>";
// @formatter:on
}
/**
* Adds a mock of a migration component to the plan generator.
*
* @param planGenerator
* the plan generator to user
*/
private void addMigrationMock(T2FlowExecutablePlanGenerator planGenerator) {
WorkflowDescription wf = mock(WorkflowDescription.class);
when(wf.getDataflowId()).thenReturn(MIGRATION_DATAFLOW_ID);
List<Port> inputPorts = new ArrayList<Port>(1);
inputPorts.add(new Port("source", "Description", ComponentConstants.VALUE_SOURCE_OBJECT));
when(wf.getInputPorts()).thenReturn(inputPorts);
List<Port> outputPorts = new ArrayList<Port>(1);
outputPorts.add(new Port("target", "Description", ComponentConstants.VALUE_TARGET_OBJECT));
when(wf.getOutputPorts()).thenReturn(outputPorts);
List<MigrationPath> migrationPaths = new ArrayList<MigrationPath>(1);
migrationPaths.add(new MigrationPath("image/tiff", "image/jp2"));
when(wf.getMigrationPaths()).thenReturn(migrationPaths);
planGenerator.setMigrationComponent(wf, generateMigrationContent(MIGRATION_DATAFLOW_ID, "Migration component"),
new HashMap<String, String>(0));
}
/**
* Mock a QA component without accepted mimetypes.
*
* @param name
* the component name
* @return a mock of a QA component
*/
private WorkflowDescription mockQa(String name) {
WorkflowDescription wf = mock(WorkflowDescription.class);
when(wf.getName()).thenReturn(name);
when(wf.getDataflowId()).thenReturn(QA_DATAFLOW_ID);
List<Port> inputPorts = new ArrayList<Port>(2);
inputPorts.add(new Port("left", "Description", ComponentConstants.VALUE_LEFT_OBJECT));
inputPorts.add(new Port("right", "Description", ComponentConstants.VALUE_RIGHT_OBJECT));
when(wf.getInputPorts()).thenReturn(inputPorts);
List<Port> outputPorts = new ArrayList<Port>(1);
outputPorts.add(new Port("qa_output", "Description",
"http://purl.org/DP/quality/measures#1"));
when(wf.getOutputPorts()).thenReturn(outputPorts);
List<String> measures = new ArrayList<String>(1);
measures.add("http://purl.org/DP/quality/measures#1");
return wf;
}
/**
* Mock a QA component that accepts any mimetypes.
*
* @param name
* the component name
* @return a mock of the QA component
*/
private WorkflowDescription mockQaAny(String name) {
WorkflowDescription wf = mockQa(name);
when(wf.acceptsMimetypes(any(String.class), any(String.class))).thenReturn(true);
when(wf.acceptsLeftMimetype(any(String.class))).thenReturn(true);
when(wf.acceptsRightMimetype(any(String.class))).thenReturn(true);
when(wf.handlesMimetype(any(String.class))).thenReturn(true);
return wf;
}
/**
* Adds a mock of a CC component to the plan generator.
*
* @param name
* the component name
* @return a mock of the CC component
*/
private WorkflowDescription mockCcAny(String name) {
WorkflowDescription wf = mock(WorkflowDescription.class);
when(wf.getName()).thenReturn(name);
when(wf.getDataflowId()).thenReturn(CC_DATAFLOW_ID);
List<Port> inputPorts = new ArrayList<Port>(1);
inputPorts.add(new Port("source", "Description", ComponentConstants.VALUE_SOURCE_OBJECT));
when(wf.getInputPorts()).thenReturn(inputPorts);
List<Port> outputPorts = new ArrayList<Port>(1);
outputPorts.add(new Port("cc_output", "Description",
"http://purl.org/DP/quality/measures#1"));
when(wf.getOutputPorts()).thenReturn(outputPorts);
when(wf.handlesMimetype(any(String.class))).thenReturn(true);
return wf;
}
}