--- /dev/null
+package jalview.ws2.actions.alignment;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import javax.help.UnsupportedOperationException;
+
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.TypeSafeMatcher;
+import org.mockito.ArgumentCaptor;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceI;
+import jalview.gui.AlignViewport;
+import jalview.viewmodel.AlignmentViewport;
+import jalview.ws.params.ParamDatastoreI;
+import jalview.ws2.actions.api.JobI;
+import jalview.ws2.actions.api.TaskEventListener;
+import jalview.ws2.api.Credentials;
+import jalview.ws2.api.JobStatus;
+import jalview.ws2.api.WebService;
+import jalview.ws2.api.WebServiceJobHandle;
+import jalview.ws2.client.api.AlignmentWebServiceClientI;
+
+import org.mockito.hamcrest.MockitoHamcrest;
+import org.mockito.internal.hamcrest.HamcrestArgumentMatcher;
+
+import static org.mockito.Mockito.*;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.*;
+
+public class AlignmentActionTest
+{
+ protected AlignmentWebServiceClientI mockClient;
+
+ protected AlignmentAction.Builder actionBuilder;
+
+ protected WebServiceJobHandle jobRef;
+
+ @BeforeMethod
+ public void setupMockClient() throws IOException
+ {
+ jobRef = new WebServiceJobHandle(
+ "mock", "mock", "http://example.org", "00000001");
+ mockClient = mock(AlignmentWebServiceClientI.class);
+ when(mockClient.getUrl()).thenReturn("http://example.org");
+ when(mockClient.getClientName()).thenReturn("mock");
+ when(mockClient.submit(anyList(), anyList(), any())).thenReturn(jobRef);
+ when(mockClient.getLog(jobRef)).thenReturn("");
+ when(mockClient.getErrorLog(jobRef)).thenReturn("");
+ doThrow(new UnsupportedOperationException()).when(mockClient).cancel(any());
+ }
+
+ @BeforeMethod(dependsOnMethods = { "setupMockClient" })
+ public void setupActionBuilder() throws IOException
+ {
+ actionBuilder = AlignmentAction.newBuilder(mockClient);
+ actionBuilder.name("mock");
+ actionBuilder.webService(
+ WebService.<AlignmentAction> newBuilder()
+ .url(new URL("http://example.org"))
+ .clientName("mock")
+ .category("Alignment")
+ .name("mock")
+ .paramDatastore(mock(ParamDatastoreI.class))
+ .actionClass(AlignmentAction.class)
+ .build());
+ }
+
+ @DataProvider
+ public Object[][] multipleSequencesUnalignedAndAligned()
+ {
+ return new Object[][] {
+ {
+ new Alignment(new SequenceI[]
+ {
+ new Sequence("Seq 1", "----ASTVLITOPDCMMQEGGST-"),
+ new Sequence("Seq 2", "-ASCGLITO------MMQEGGST-"),
+ new Sequence("Seq 3", "AS--TVL--OPDTMMQEL------")
+ }),
+ new Alignment(new SequenceI[]
+ {
+ new Sequence("Sequence0", "ASTV-LITOPDCMMQEGGST----"),
+ new Sequence("Sequence1", "ASC-GLITO---MMQEGGST----"),
+ new Sequence("Sequence2", "ASTV-L--OPDTMMQE--L-----")
+ })
+ }
+ };
+ }
+
+ @Test(dataProvider = "multipleSequencesUnalignedAndAligned")
+ public void submitSequences_verifySequenceNamesUniquified(
+ Alignment unaligned, Alignment aligned)
+ throws IOException
+ {
+ var viewport = new AlignViewport(unaligned);
+ when(mockClient.getAlignment(jobRef)).thenReturn(aligned);
+ when(mockClient.getStatus(jobRef)).thenReturn(JobStatus.COMPLETED);
+ actionBuilder.submitGaps(false);
+ performAction(viewport, actionBuilder.build());
+ ArgumentCaptor<List<SequenceI>> argument = ArgumentCaptor.forClass(List.class);
+ verify(mockClient).submit(argument.capture(), eq(List.of()), eq(Credentials.empty()));
+ assertThat(argument.getValue(),
+ contains(hasProperty("name", is("Sequence0")),
+ hasProperty("name", is("Sequence1")),
+ hasProperty("name", is("Sequence2"))));
+ }
+
+ @Test(dataProvider = "multipleSequencesUnalignedAndAligned")
+ public void submitSequences_submitGapsOff_verifySequencesSubmittedWithoutGaps(Alignment unaligned, Alignment aligned)
+ throws IOException
+ {
+ var viewport = new AlignViewport(unaligned);
+ actionBuilder.submitGaps(false);
+ when(mockClient.getAlignment(jobRef)).thenReturn(aligned);
+ when(mockClient.getStatus(jobRef)).thenReturn(JobStatus.COMPLETED);
+ performAction(viewport, actionBuilder.build());
+ ArgumentCaptor<List<SequenceI>> argument = ArgumentCaptor.forClass(List.class);
+ verify(mockClient).submit(argument.capture(), eq(List.of()), eq(Credentials.empty()));
+ assertThat(argument.getValue(),
+ contains(
+ matchesSequence("ASTVLITOPDCMMQEGGST"),
+ matchesSequence("ASCGLITOMMQEGGST"),
+ matchesSequence("ASTVLOPDTMMQEL")));
+ }
+
+ @Test(dataProvider = "multipleSequencesUnalignedAndAligned")
+ public void submitSequences_submitGapsOn_verifySequencesSubmittedWithGaps(
+ Alignment unaligned, Alignment aligned)
+ throws IOException
+ {
+ var viewport = new AlignViewport(unaligned);
+ actionBuilder.submitGaps(true);
+ when(mockClient.getAlignment(jobRef)).thenReturn(aligned);
+ when(mockClient.getStatus(jobRef)).thenReturn(JobStatus.COMPLETED);
+ performAction(viewport, actionBuilder.build());
+ ArgumentCaptor<List<SequenceI>> argument = ArgumentCaptor.forClass(List.class);
+ verify(mockClient).submit(argument.capture(), eq(List.of()), eq(Credentials.empty()));
+ assertThat(argument.getValue(),
+ contains(
+ matchesSequence("----ASTVLITOPDCMMQEGGST-"),
+ matchesSequence("-ASCGLITO------MMQEGGST-"),
+ matchesSequence("AS--TVL--OPDTMMQEL------")));
+ }
+
+ @Test(dataProvider = "multipleSequencesUnalignedAndAligned")
+ public void retrieveResult_verifySequencesAligned(
+ Alignment unaligned, Alignment aligned)
+ throws IOException
+ {
+ var viewport = new AlignViewport(unaligned);
+ actionBuilder.submitGaps(false);
+ when(mockClient.getAlignment(jobRef)).thenReturn(aligned);
+ when(mockClient.getStatus(jobRef)).thenReturn(JobStatus.COMPLETED);
+ var mockListener = performAction(viewport, actionBuilder.build());
+ var argument = ArgumentCaptor.forClass(AlignmentResult.class);
+ verify(mockListener).taskCompleted(any(), argument.capture());
+ var alignmentResult = argument.getValue().getAlignment();
+ assertThat(alignmentResult, hasProperty("sequences", contains(
+ matchesSequence("ASTV-LITOPDCMMQEGGST----"),
+ matchesSequence("ASC-GLITO---MMQEGGST----"),
+ matchesSequence("ASTV-L--OPDTMMQE--L-----"))));
+ }
+
+ protected static Matcher<SequenceI> matchesSequence(String sequence)
+ {
+ return new TypeSafeMatcher<SequenceI>()
+ {
+ @Override
+ public boolean matchesSafely(SequenceI obj)
+ {
+ if (!(obj instanceof SequenceI))
+ return false;
+ var seq = (SequenceI) obj;
+ return seq.getSequenceAsString().equals(sequence);
+ }
+
+ @Override
+ public void describeTo(Description description)
+ {
+ description.appendText("a sequence ").appendValue(sequence);
+ }
+
+ @Override
+ public void describeMismatchSafely(SequenceI item, Description description)
+ {
+ description.appendText("was ").appendValue(item.getSequenceAsString());
+ }
+ };
+ }
+
+ protected TaskEventListener<AlignmentResult> performAction(
+ AlignmentViewport viewport, AlignmentAction action)
+ throws IOException
+ {
+ TaskEventListener<AlignmentResult> listener = mock(TaskEventListener.class);
+ var latch = new CountDownLatch(1);
+ doAnswer(invocation -> {
+ latch.countDown();
+ return null;
+ })
+ .when(listener).taskCompleted(any(), any());
+ action.perform(viewport, List.of(), Credentials.empty(), listener);
+ try
+ {
+ latch.await(100, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e)
+ {
+ }
+ return listener;
+ }
+}
+
+class AlignmentActionListenerNotifiedTest extends AlignmentActionTest
+{
+ private AlignViewport viewport;
+
+ @BeforeMethod
+ public void setupViewport()
+ {
+ viewport = new AlignViewport(new Alignment(new SequenceI[] {
+ new Sequence("Seq 1", "----ASTVLITOPDCMMQEGGST-"),
+ new Sequence("Seq 2", "-ASCGLITO------MMQEGGST-"),
+ new Sequence("Seq 3", "AS--TVL--OPDTMMQEL------")
+ }));
+ }
+
+ @DataProvider
+ public JobStatus[] jobStatuses()
+ {
+ // CREATED, INVALID and READY should not be returned by the server
+ return new JobStatus[] {
+ JobStatus.SUBMITTED,
+ JobStatus.QUEUED,
+ JobStatus.RUNNING,
+ JobStatus.COMPLETED,
+ JobStatus.FAILED,
+ JobStatus.CANCELLED,
+ JobStatus.SERVER_ERROR,
+ JobStatus.UNKNOWN
+ };
+ }
+
+ @Test
+ public void allJobsStarted_taskStartedCalled()
+ throws IOException
+ {
+ when(mockClient.getStatus(jobRef)).thenReturn(JobStatus.COMPLETED);
+ var mockListener = performAction(viewport, actionBuilder.build());
+ verify(mockListener).taskStarted(any(), anyList());
+ }
+
+ @Test
+ public void allJobsStarted_taskStatusChangedCalledWithReadyThenSubmitted()
+ throws IOException
+ {
+ when(mockClient.getStatus(jobRef)).thenReturn(JobStatus.COMPLETED);
+ var mockListener = performAction(viewport, actionBuilder.build());
+ var inOrder = inOrder(mockListener);
+ inOrder.verify(mockListener).taskStatusChanged(any(), eq(JobStatus.READY));
+ inOrder.verify(mockListener).taskStatusChanged(any(), eq(JobStatus.SUBMITTED));
+ }
+
+ @Test(dataProvider = "jobStatuses")
+ public void jobStatusChanged_taskStatusChangedCalledWithJobStatus(JobStatus status)
+ throws IOException
+ {
+ when(mockClient.getStatus(jobRef))
+ .thenReturn(status)
+ .thenReturn(JobStatus.COMPLETED);
+ var mockListener = performAction(viewport, actionBuilder.build());
+ verify(mockListener).taskStatusChanged(any(), eq(status));
+ }
+
+ @Test(dataProvider = "jobStatuses")
+ public void jobStatusChanged_subJobStatusChangedCalledWithJobStatus(JobStatus status)
+ throws IOException
+ {
+ when(mockClient.getStatus(jobRef))
+ .thenReturn(status)
+ .thenReturn(JobStatus.COMPLETED);
+ var mockListener = performAction(viewport, actionBuilder.build());
+ verify(mockListener).subJobStatusChanged(any(), any(), eq(status));
+ }
+}
\ No newline at end of file
package jalview.ws2.client.slivka;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.*;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import org.hamcrest.Matcher;
import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
+import jalview.bin.Cache;
+import jalview.bin.Console;
+import jalview.ws.params.ValueConstrainI.ValueType;
+import jalview.ws.params.simple.DoubleParameter;
+import jalview.ws.params.simple.IntegerParameter;
+import jalview.ws.params.simple.StringParameter;
+import jalview.ws2.actions.alignment.AlignmentAction;
+import jalview.ws2.actions.annotation.AnnotationAction;
+import jalview.ws2.client.api.WebServiceDiscovererI;
+import uk.ac.dundee.compbio.slivkaclient.Parameter;
+import uk.ac.dundee.compbio.slivkaclient.SlivkaClient;
+import uk.ac.dundee.compbio.slivkaclient.SlivkaService;
+
public class SlivkaWSDiscovererTest
{
- @BeforeClass
- public void setupClass() throws IOException
+ private static final String URLS_PROPERTY_NAME = "SLIVKAHOSTURLS";
+
+ SlivkaClient clientMock;
+
+ Function<URL, SlivkaClient> factoryMock;
+
+ @BeforeClass(alwaysRun = true)
+ public void setupProperties()
+ {
+ Cache.loadProperties("test/jalview/ws2/client/slivka/default.jvprops");
+ Console.initLogger();
+ }
+
+ @BeforeMethod
+ public void setupDiscoverer() throws IOException
+ {
+ clientMock = mock(SlivkaClient.class);
+ }
+
+ @Test
+ public void getStatusForUrl_servicesReturned_statusIsOK() throws Exception
+ {
+ when(clientMock.getServices())
+ .thenReturn(List.of(mock(SlivkaService.class)));
+ var discoverer = new SlivkaWSDiscoverer(
+ url -> url.toString().equals("http://example.org") ? clientMock
+ : null);
+ assertThat(discoverer.getStatusForUrl(new URL("http://example.org")),
+ is(WebServiceDiscovererI.STATUS_OK));
+ }
+
+ @Test
+ public void getStatusForUrl_noServicesReturned_statusIsNoServices()
+ throws Exception
+ {
+ when(clientMock.getServices()).thenReturn(List.of());
+ var discoverer = new SlivkaWSDiscoverer(
+ url -> url.toString().equals("http://example.org") ? clientMock
+ : null);
+ assertThat(discoverer.getStatusForUrl(new URL("http://example.org")),
+ is(WebServiceDiscovererI.STATUS_NO_SERVICES));
+ }
+
+ @Test
+ public void getStatusForUrl_exceptionThrown_statusIsInvalid()
+ throws Exception
+ {
+ when(clientMock.getServices()).thenThrow(new IOException());
+ var discoverer = new SlivkaWSDiscoverer(
+ url -> url.toString().equals("http://example.org") ? clientMock
+ : null);
+ assertThat(discoverer.getStatusForUrl(new URL("http://example.org")),
+ is(WebServiceDiscovererI.STATUS_INVALID));
+ }
+
+ @Test
+ public void testGetUrls_noPropEntry_defaultUrlReturned()
+ throws MalformedURLException
{
var discoverer = SlivkaWSDiscoverer.getInstance();
-
+ assertThat(discoverer.getUrls(),
+ contains(new URL("https://www.compbio.dundee.ac.uk/slivka/")));
}
-
+
+ @DataProvider
+ public Object[][] urlPropertyValues() throws MalformedURLException
+ {
+ return new Object[][] {
+ { "http://example.org/", List.of(new URL("http://example.org/")) },
+ { "https://example.org/slivka/",
+ List.of(new URL("https://example.org/slivka/")) },
+ { "https://www.compbio.dundee.ac.uk/,http://www.example.org/",
+ List.of(new URL("https://www.compbio.dundee.ac.uk/"),
+ new URL("http://www.example.org/")) },
+ { "http://example.org/,", List.of(new URL("http://example.org/")) },
+ { ",http://example.org", List.of(new URL("http://example.org")) },
+ { "", List.of() },
+ { ",", List.of() },
+ { "example.org", List.of() },
+ { "example.org,http://example.org",
+ List.of(new URL("http://example.org")) } };
+ }
+
+ @Test(dataProvider = "urlPropertyValues")
+ public void testGetUrls_urlsProperlyParsed(String propValue,
+ List<URL> expected)
+ {
+ Cache.setProperty(URLS_PROPERTY_NAME, propValue);
+ var discoverer = SlivkaWSDiscoverer.getInstance();
+ assertThat(discoverer.getUrls(), equalTo(expected));
+ }
+
@Test
- public void testServiceFetch() throws IOException
+ public void testSetUrls_emptyList_propertyReset()
{
+ Cache.setProperty(URLS_PROPERTY_NAME, "http://www.example.org");
var discoverer = SlivkaWSDiscoverer.getInstance();
- var services = discoverer.fetchServices(discoverer.getDefaultUrl());
- for (var service : services)
+ discoverer.setUrls(List.of());
+ assertThat(Cache.getProperty(URLS_PROPERTY_NAME), is(nullValue()));
+ }
+
+ @Test
+ public void testSetUrls_null_propertyReset()
+ {
+ Cache.setProperty(URLS_PROPERTY_NAME, "http://www.example.org");
+ var discoverer = SlivkaWSDiscoverer.getInstance();
+ discoverer.setUrls(null);
+ assertThat(Cache.getProperty(URLS_PROPERTY_NAME), is(nullValue()));
+ }
+
+ @DataProvider
+ public Object[][] urlsList() throws MalformedURLException
+ {
+ return new Object[][] {
+ { List.of(new URL("http://example.org")), "http://example.org" },
+ { List.of(new URL("http://example.org/")), "http://example.org/" },
+ { List.of(new URL("http://example.org/slivka/")),
+ "http://example.org/slivka/" },
+ { List.of(new URL("https://www.compbio.dundee.ac.uk/slivka/"),
+ new URL("http://example.org")),
+ "https://www.compbio.dundee.ac.uk/slivka/,http://example.org" }, };
+ }
+
+ @Test(dataProvider = "urlsList")
+ public void testSetUrls_urlsPropertySet(List<URL> urls, String expected)
+ throws MalformedURLException
+ {
+ var discoverer = SlivkaWSDiscoverer.getInstance();
+ discoverer.setUrls(urls);
+ assertThat(Cache.getProperty(URLS_PROPERTY_NAME), equalTo(expected));
+ }
+
+ @Test
+ public void testFetchServices_oneService_basicDataMatches()
+ throws IOException
+ {
+ var service = new SlivkaService(
+ URI.create("http://example.org/api/services/example"),
+ "example", "Example name", "Example service description",
+ "John Smith", "1.0", "MIT License",
+ List.of("operation::analysis::multiple sequence alignment"),
+ List.of(), List.of(), null);
+ when(clientMock.getServices()).thenReturn(List.of(service));
+ when(clientMock.getUrl()).thenReturn(URI.create("http://example.org/"));
+ var discoverer = new SlivkaWSDiscoverer(url -> clientMock);
+ var webServices = discoverer
+ .fetchServices(new URL("http://example.org/"));
+ assertThat(webServices, hasSize(1));
+ var webService = webServices.get(0);
+ assertThat(webService.getUrl(),
+ equalTo(new URL("http://example.org/")));
+ assertThat(webService.getClientName(), equalTo("slivka"));
+ assertThat(webService.getName(), equalTo("Example name"));
+ assertThat(webService.getDescription(),
+ equalTo("Example service description"));
+ }
+
+ @DataProvider
+ public String[] validMultipleSequenceAlignmentClassifiers()
+ {
+ return new String[] {
+ "Operation :: Analysis :: Multiple sequence alignment",
+ "operation :: analysis :: multiple sequence alignment",
+ "Operation\t::\tAnalysis\t::\tMultiple sequence alignment",
+ "Operation::Analysis::Multiple sequence alignment",
+ "Operation :: Analysis :: Multiple Sequence Alignment",
+ "OPERATION :: ANALYSIS :: MULTIPLE SEQUENCE ALIGNMENT",
+ "Operation :: Analysis :: Sequence alignment :: Multiple sequence alignment",
+ "Operation :: Analysis :: Sequence analysis :: Sequence alignment :: Multiple sequence alignment",
+ "Operation :: Alignment :: Multiple sequence alignment",
+ "Operation :: Alignment :: Sequence alignment :: Multiple sequence alignment",
+ "Operation :: Comparison :: Multiple sequence alignment",
+ "Operation :: Comparison :: Sequence comparison :: Sequence alignment :: Multiple sequence alignment" };
+
+ }
+
+ @Test(dataProvider = "validMultipleSequenceAlignmentClassifiers")
+ public void testFetchServices_multipleSequenceAlignmentClassifier_serviceTypeIsMSA(
+ String classifier) throws IOException
+ {
+ var service = new SlivkaService(URI.create("http://example.org/"),
+ "example", "name", "description", "author", "1.0", "MIT",
+ List.of(classifier), List.of(), List.of(), null);
+ when(clientMock.getServices()).thenReturn(List.of(service));
+ when(clientMock.getUrl()).thenReturn(URI.create("http://example.org/"));
+ var discoverer = new SlivkaWSDiscoverer(url -> clientMock);
+ var webServices = discoverer
+ .fetchServices(new URL("http://example.org/"));
+ assertThat(webServices, hasSize(1));
+ assertThat(webServices.get(0).getCategory(), equalTo("Alignment"));
+ assertThat(webServices.get(0).getActionClass(),
+ typeCompatibleWith(AlignmentAction.class));
+ }
+
+ @DataProvider
+ public SlivkaService[] multipleSequenceAlignmentService()
+ {
+ return new SlivkaService[] {
+ new SlivkaService(
+ URI.create("http://example.org/"), "example", "Examaple name",
+ "Example description", "John Smith", "1.0", "MIT",
+ List.of("Operation :: Analysis :: Multiple sequence alignment"),
+ List.of(), List.of(), null),
+ new SlivkaService(
+ URI.create("http://example.org/api/services/muscle"),
+ "muscle", "MUSCLE",
+ "MUltiple Sequence Comparison by Log- Expectation",
+ "Robert C. Edgar", "3.8.31", "Public domain",
+ List.of("Topic :: Computational biology :: Sequence analysis",
+ "Operation :: Analysis :: Sequence analysis :: Sequence alignment :: Multiple sequence alignment"),
+ List.of(), List.of(), null),
+ new SlivkaService(
+ URI.create("http://example.org/api/services/tcoffee"),
+ "tcoffee", "TCoffee",
+ "Tree-based Consistency Objective Function for Alignment Evaluation",
+ "Cedric Notredame", "13.41.0", "GNU GPL",
+ List.of("Topic :: Computational biology :: Sequence analysis",
+ "Operation :: Analysis :: Sequence analysis :: Sequence alignment :: Multiple sequence alignment"),
+ List.of(), List.of(), null) };
+ }
+
+ @Test(dataProvider = "multipleSequenceAlignmentService")
+ public void testFetchServices_multipleSequenceAlignmentService_actionTypeIsAlignment(
+ SlivkaService service) throws IOException
+ {
+ when(clientMock.getServices()).thenReturn(List.of(service));
+ when(clientMock.getUrl()).thenReturn(URI.create("http://example.org/"));
+ var discoverer = new SlivkaWSDiscoverer(url -> clientMock);
+ var webServices = discoverer
+ .fetchServices(new URL("http://example.org/"));
+ assertThat(webServices.get(0).getCategory(), equalTo("Alignment"));
+ assertThat(webServices.get(0).getActionClass(),
+ typeCompatibleWith(AlignmentAction.class));
+ }
+
+ @Test(dataProvider = "multipleSequenceAlignmentService")
+ public void testFetchServices_multipleSequenceAlignmentService_serviceIsNonInteractive(
+ SlivkaService service) throws IOException
+ {
+ when(clientMock.getServices()).thenReturn(List.of(service));
+ when(clientMock.getUrl()).thenReturn(URI.create("http://example.org/"));
+ var discoverer = new SlivkaWSDiscoverer(url -> clientMock);
+ var webServices = discoverer
+ .fetchServices(new URL("http://example.org/"));
+ assertThat(webServices.get(0).isInteractive(), is(false));
+ }
+
+ @DataProvider
+ public SlivkaService[] clustalFamilyService()
+ {
+ return new SlivkaService[] {
+ new SlivkaService(
+ URI.create("http://example.org/api/services/clustalo"),
+ "clustalo", "ClustalO",
+ "Clustal Omega is the latest addition to the Clustal family.",
+ "Fabian Sievers, et al.", "1.2.4", "GNU GPL ver. 2",
+ List.of("Topic :: Computational biology :: Sequence analysis",
+ "Operation :: Analysis :: Sequence analysis :: Sequence alignment :: Multiple sequence alignment"),
+ List.of(), List.of(), null),
+ new SlivkaService(
+ URI.create("http://example.org/api/services/clustalw"),
+ "clustalw", "ClustalW",
+ "ClustalW is a general purpose multiple alignment program.",
+ "Larkin MA, et al.", "2.1", "GNU GPL ver. 3",
+ List.of("Topic :: Computation biology :: Sequence analysis",
+ "Operation :: Analysis :: Multiple sequence alignment"),
+ List.of(), List.of(), null),
+ new SlivkaService(
+ URI.create("http://example.org/api/services/clustalw2"),
+ "clustalw2", "ClustalW2",
+ "ClustalW is a general purpose multiple alignment program.",
+ "Larkin MA, et al.", "2.1", "GNU GPL ver. 3",
+ List.of("Topic :: Computation biology :: Sequence analysis",
+ "Operation :: Analysis :: Multiple sequence alignment"),
+ List.of(), List.of(), null), };
+ }
+
+ @Test(dataProvider = "clustalFamilyService")
+ public void testFetchService_clustalFamilyService_containsTwoActions(
+ SlivkaService service) throws IOException
+ {
+ when(clientMock.getServices()).thenReturn(List.of(service));
+ when(clientMock.getUrl()).thenReturn(URI.create("http://example.org"));
+ var discoverer = new SlivkaWSDiscoverer(url -> clientMock);
+ var webServices = discoverer
+ .fetchServices(new URL("http://example.org"));
+ var actions = webServices.get(0).getActions();
+ assertThat(actions, hasSize(2));
+ assertThat(actions.get(0), allOf(hasProperty("name", is("Alignment")),
+ hasProperty("subcategory", is("Align"))));
+ assertThat(actions.get(1),
+ allOf(hasProperty("name", is("Re-alignment")),
+ hasProperty("subcategory", is("Realign"))));
+ }
+
+ @DataProvider
+ public String[] validRNASecondaryStructurePredictionClassifiers()
+ {
+ return new String[] {
+ "Operation :: Analysis :: RNA secondary structure prediction",
+ "operation :: analysis :: rna secondary structure prediction",
+ "OPERATION :: ANALYSIS :: RNA SECONDARY STRUCTURE PREDICTION",
+ "Operation\t::\tAnalysis\t::\tRNA secondary structure prediction",
+ "Operation::Analysis::RNA secondary structure prediction",
+ "Operation :: Analysis :: Structure analysis :: RNA secondary structure prediction",
+ "Operation :: Analysis :: Structure analysis :: Nucleic acid structure analysis :: RNA secondary structure analysis :: RNA secondary structure prediction",
+ "Operation :: Analysis :: Structure analysis :: Nucleic acid structure analysis :: Nucleic acid structure prediction :: RNA secondary structure prediction",
+ "Operation :: Analysis :: Sequence analysis :: Nucleic acid sequence analysis :: Nucleic acid feature detection :: RNA secondary structure prediction",
+ "Operation :: Prediction and recognition :: RNA secondary structure prediction",
+ "Operation :: Prediction and recognition :: Nucleic acid feature detection :: RNA secondary structure prediction",
+ "Operation :: Prediction and recignition :: Nucleic acid structure prediction :: RNA secondary structure prediction", };
+ }
+
+ @DataProvider
+ public Iterator<Object> RNASecondaryStructurePredictionService()
+ {
+ var services = new ArrayList<>();
+ for (var classifier : validRNASecondaryStructurePredictionClassifiers())
+ {
+ services.add(new SlivkaService(URI.create("http://example.org/"),
+ "example", "name", "description", "author", "1.0", "MIT",
+ List.of(classifier), List.of(), List.of(), null));
+ }
+ return services.iterator();
+ }
+
+ @Test(dataProvider = "RNASecondaryStructurePredictionService")
+ public void testFetchServices_RNASecStrPredClassifier_serviceTypeIsRNASecStrPred(
+ SlivkaService service) throws IOException
+ {
+ when(clientMock.getServices()).thenReturn(List.of(service));
+ when(clientMock.getUrl()).thenReturn(URI.create("http://example.org/"));
+ var discoverer = new SlivkaWSDiscoverer(url -> clientMock);
+ var webServices = discoverer
+ .fetchServices(new URL("http://example.org/"));
+ assertThat(webServices, hasSize(1));
+ assertThat(webServices.get(0).getCategory(),
+ equalTo("Secondary Structure Prediction"));
+ assertThat(webServices.get(0).getActionClass(),
+ typeCompatibleWith(AnnotationAction.class));
+ }
+
+ @DataProvider
+ public String[] validConservationAnalysisClassifiers()
+ {
+ return new String[] {
+ "Operation :: Analysis :: Sequence alignment analysis (conservation)",
+ "Operation::Analysis::Sequence alignment analysis (conservation)",
+ "Operation\t::\tAnalysis\t::\tSequence alignment analysis (conservation)",
+ "Operation :: Analysis :: Sequence analysis :: Sequence alignment analysis (conservation)",
+ "Operation :: Analysis :: Sequence analysis :: Sequence alignment analysis :: Sequence alignment analysis (conservation)", };
+ }
+
+ @DataProvider
+ public Iterator<Object> ConservationAnalysisService()
+ {
+ var services = new ArrayList<>();
+ for (var classifier : validConservationAnalysisClassifiers())
{
- System.out.format("Service(%s>%s @%s)%n", service.getCategory(),
- service.getName(), service.getUrl());
- var datastore = service.getParamDatastore();
- for (var param : datastore.getServiceParameters())
- {
- System.out.format(" %s :%s%n", param.getName(), param.getClass().getSimpleName());
- }
+ services.add(new SlivkaService(URI.create("http://example.org/"),
+ "example", "name", "description", "author", "1.0", "MIT",
+ List.of(classifier), List.of(), List.of(), null));
}
+ return services.iterator();
+ }
+
+ @Test(dataProvider = "validConservationAnalysisClassifiers")
+ public void testFetchServices_conservationAnalysisClassifier_serviceTypeIsConservation(
+ String classifier) throws IOException
+ {
+ var service = new SlivkaService(URI.create("http://example.org/"),
+ "example", "name", "description", "author", "1.0", "MIT",
+ List.of(classifier), List.of(), List.of(), null);
+ when(clientMock.getServices()).thenReturn(List.of(service));
+ when(clientMock.getUrl()).thenReturn(URI.create("http://example.org/"));
+ var discoverer = new SlivkaWSDiscoverer(url -> clientMock);
+ var webServices = discoverer
+ .fetchServices(new URL("http://example.org/"));
+ assertThat(webServices, hasSize(1));
+ assertThat(webServices.get(0).getCategory(), equalTo("Conservation"));
+ assertThat(webServices.get(0).getActionClass(),
+ typeCompatibleWith(AnnotationAction.class));
+ }
+
+ @DataProvider
+ public Object[] validProteinSequenceAnalysisClassifiers()
+ {
+ return new Object[] {
+ "Operation :: Analysis :: Sequence analysis :: Protein sequence analysis", };
+ }
+
+ @Test(dataProvider = "validProteinSequenceAnalysisClassifiers")
+ public void testFetchServices_proteinSequenceAnalysisClassifier_serviceTypeIsProtSeqAnalysis(
+ String classifier) throws IOException
+ {
+ var service = new SlivkaService(URI.create("http://example.org/"),
+ "example", "name", "description", "author", "1.0", "MIT",
+ List.of(classifier), List.of(), List.of(), null);
+ when(clientMock.getServices()).thenReturn(List.of(service));
+ when(clientMock.getUrl()).thenReturn(URI.create("http://example.org/"));
+ var discoverer = new SlivkaWSDiscoverer(url -> clientMock);
+ var webServices = discoverer
+ .fetchServices(new URL("http://example.org/"));
+ assertThat(webServices, hasSize(1));
+ assertThat(webServices.get(0).getCategory(),
+ equalTo("Protein Disorder"));
+ assertThat(webServices.get(0).getActionClass(),
+ typeCompatibleWith(AnnotationAction.class));
+ }
+
+ @DataProvider
+ public Object[] validProteinSecondaryStructurePredictionClassifiers()
+ {
+ return new Object[] {
+ "Operation ;: Analysis :: Protein secondary structure prediction",
+ "Operation :: Analysis :: Structure analysis :: Protein structure analysis :: Protein secondary structure analysis :: Protein secondary structure prediction",
+ "Operation :: Analysis :: Sequence analysis :: Protein sequence analysis :: Protein feature detection :: Protein secondary structure prediction",
+ "Operation :: Analysis :: Sequence analysis :: Protein sequence analysis :: Protein secondary structure prediction",
+ "Operation :: Prediction and recognition :: Protein secondary structure prediction",
+ "Operation :: Prediction and recognition :: Protein feature detection :: Protein secondary structure prediction", };
+ }
+
+ @Test(
+ enabled = false, // sec. str. pred. not implemented for slivka
+ dataProvider = "validProteinSecondaryStructurePredictionClassifiers")
+ public void testFetchServices_proteinSecStrPredClassifier_serviceTypeIsProtSecStrPred(
+ String classifier) throws IOException
+ {
+ var service = new SlivkaService(URI.create("http://example.org/"),
+ "example", "name", "description", "author", "1.0", "MIT",
+ List.of(classifier), List.of(), List.of(), null);
+ when(clientMock.getServices()).thenReturn(List.of(service));
+ when(clientMock.getUrl()).thenReturn(URI.create("http://example.org/"));
+ var discoverer = new SlivkaWSDiscoverer(url -> clientMock);
+ var webServices = discoverer
+ .fetchServices(new URL("http://example.org/"));
+ assertThat(webServices, hasSize(1));
+ assertThat(webServices.get(0).getCategory(),
+ equalTo("Protein Disorder"));
+ assertThat(webServices.get(0).getActionClass(),
+ typeCompatibleWith(AnnotationAction.class));
+ }
+
+ @DataProvider
+ public SlivkaService[] unrecognisedService()
+ {
+ return new SlivkaService[] {
+ new SlivkaService(URI.create("http://example.org/"), "example",
+ "Example name", "Example description", "John Smith",
+ "1.0.0", "Apache License, version 2.0",
+ List.of("This :: Classifier :: Does not exist"), List.of(),
+ List.of(), null) };
+ }
+
+ @Test(dataProvider = "unrecognisedService")
+ public void testFetchServices_unrecognisedService_noServiceDiscovered(
+ SlivkaService service) throws IOException
+ {
+ when(clientMock.getServices()).thenReturn(List.of(service));
+ when(clientMock.getUrl()).thenReturn(URI.create("http://example.org"));
+ var discoverer = new SlivkaWSDiscoverer(url -> clientMock);
+ var webServices = discoverer
+ .fetchServices(new URL("http://example.org"));
+ assertThat(webServices, hasSize(0));
+ }
+
+ @DataProvider
+ public Object[] serviceParameterAndMappedClass()
+ {
+ return new Object[][] {
+ {
+ new Parameter.IntegerParameter("param", "Parameter", "Description",
+ true, false, null, Map.of(), null, null),
+ IntegerParameter.class
+ },
+ {
+ new Parameter.DecimalParameter("param", "Parameter",
+ "Description", true, false, null, Map.of(), null, null,
+ false, false),
+ DoubleParameter.class
+ },
+ {
+ new Parameter.TextParameter("param", "Parameter", "Description",
+ true, false, null, Map.of(), 0, null),
+ StringParameter.class
+ },
+ {
+ new Parameter.FlagParameter("param", "Parameter", "Description",
+ true, false, null, Map.of()),
+ StringParameter.class
+ },
+ {
+ new Parameter.ChoiceParameter("param", "Parameter", "Description",
+ true, false, null, Map.of(), List.of()),
+ StringParameter.class
+ },
+ };
+ }
+
+ @Test(dataProvider = "serviceParameterAndMappedClass")
+ public void testServiceParameter_slivkaParameterMappedToJalviewParameter(
+ Parameter slivkaParameter, Class<?> expectedClass)
+ throws IOException
+ {
+ var service = new SlivkaService(URI.create("http://example.org"),
+ "example", "name", "description", "author", "1.0",
+ "MIT License",
+ List.of("Operation :: Analysis :: Multiple sequence alignment"),
+ List.of(slivkaParameter), List.of(), null);
+ when(clientMock.getServices()).thenReturn(List.of(service));
+ when(clientMock.getUrl()).thenReturn(URI.create("http://example.org"));
+ var discoverer = new SlivkaWSDiscoverer(url -> clientMock);
+ var webServices = discoverer
+ .fetchServices(new URL("http://example.org"));
+ var paramDatastore = webServices.get(0).getParamDatastore();
+ var arguments = paramDatastore.getServiceParameters();
+ assertThat(arguments.get(0), instanceOf(expectedClass));
+ }
+
+ @DataProvider
+ public Object[][] serviceParametersAndPropertyMatcher()
+ {
+ return new Object[][] {
+ {
+ new Parameter.IntegerParameter("param1", "Parameter 1",
+ "Description of parameter 1", true, false, null, Map.of(),
+ null, null),
+ allOf(
+ hasProperty("name", equalTo("param1")),
+ hasProperty("label", equalTo("Parameter 1")),
+ hasProperty("description", equalTo("Description of parameter 1")),
+ hasProperty("required", is(true)),
+ hasProperty("value", nullValue()))
+ },
+ {
+ new Parameter.IntegerParameter("param2", null, null, true, false,
+ null, Map.of(), null, null),
+ allOf(
+ hasProperty("name", equalTo("param2")),
+ hasProperty("label", equalTo("param2")),
+ hasProperty("description", nullValue()),
+ hasProperty("required", is(true)),
+ hasProperty("value", nullValue()))
+ },
+ {
+ new Parameter.IntegerParameter("param3", "Parameter 3", "", false,
+ false, 12, Map.of(), null, null),
+ allOf(
+ hasProperty("name", equalTo("param3")),
+ hasProperty("label", equalTo("Parameter 3")),
+ hasProperty("description", equalTo("")),
+ hasProperty("required", is(false)),
+ hasProperty("value", equalTo("12")))
+ },
+ };
+ }
+
+ @Test(dataProvider = "serviceParametersAndInfoMatcher")
+ public void testServiceParameters_testBasicParameterProperties(
+ Parameter parameter, Matcher<Object> matcher) throws IOException
+ {
+ var service = new SlivkaService(URI.create("http://example.org/"),
+ "example", "Example name", "Example description", "John Smith",
+ "1.0", "MIT",
+ List.of("Operation :: Analysis :: Multiple sequence alignment"),
+ List.of(parameter), List.of(), null);
+ when(clientMock.getServices()).thenReturn(List.of(service));
+ when(clientMock.getUrl()).thenReturn(URI.create("http://example.org/"));
+ var discoverer = new SlivkaWSDiscoverer(url -> clientMock);
+ var webServices = discoverer
+ .fetchServices(new URL("http://example.org/"));
+ var paramDatastore = webServices.get(0).getParamDatastore();
+ var arguments = paramDatastore.getServiceParameters();
+ assertThat(arguments.get(0), matcher);
+ }
+
+ @DataProvider
+ public Object[][] integerParametersAndPropertyMatcher()
+ {
+ return new Object[][] {
+ {
+ new Parameter.IntegerParameter("param", null, null, true, false,
+ null, Map.of(), null, null),
+ hasProperty("validValue", hasProperty("type", is(ValueType.Integer)))
+ },
+ {
+ new Parameter.IntegerParameter("param", null, null, true, false,
+ null, Map.of(), null, null),
+ hasProperty("validValue", allOf(
+ hasProperty("min", nullValue()),
+ hasProperty("max", nullValue()))),
+ },
+ {
+ new Parameter.IntegerParameter("param", null, null, true, false,
+ null, Map.of(), -12, 42),
+ hasProperty("validValue", allOf(
+ hasProperty("min", is(-12)),
+ hasProperty("max", is(42))))
+ },
+ };
+ }
+
+ @Test(dataProvider = "integerParametersAndPropertyMatcher")
+ public void testServiceParameters_testIntegerProperties(
+ Parameter parameter, Matcher<Object> matcher) throws IOException
+ {
+ var service = new SlivkaService(URI.create("http://example.org"),
+ "example", "Example name", "Example description", "John Smith",
+ "1.0", "MIT",
+ List.of("Operation :: Analysis :: Multiple Sequence Alignment"),
+ List.of(parameter), List.of(), null);
+ when(clientMock.getServices()).thenReturn(List.of(service));
+ when(clientMock.getUrl()).thenReturn(URI.create("http://example.org/"));
+ var discoverer = new SlivkaWSDiscoverer(url -> clientMock);
+ var webServices = discoverer
+ .fetchServices(new URL("http://example.org/"));
+ var paramDatastore = webServices.get(0).getParamDatastore();
+ var arguments = paramDatastore.getServiceParameters();
+ assertThat(arguments.get(0), matcher);
}
}