1 package jalview.ws2.client.slivka;
3 import static org.hamcrest.MatcherAssert.assertThat;
4 import static org.hamcrest.Matchers.*;
5 import static org.mockito.Mockito.mock;
6 import static org.mockito.Mockito.when;
8 import java.io.IOException;
9 import java.net.MalformedURLException;
12 import java.util.ArrayList;
13 import java.util.Iterator;
14 import java.util.List;
15 import java.util.function.Function;
17 import org.testng.annotations.BeforeClass;
18 import org.testng.annotations.BeforeMethod;
19 import org.testng.annotations.DataProvider;
20 import org.testng.annotations.Test;
22 import jalview.bin.Cache;
23 import jalview.bin.Console;
24 import jalview.ws2.actions.alignment.AlignmentAction;
25 import jalview.ws2.actions.annotation.AnnotationAction;
26 import jalview.ws2.client.api.WebServiceDiscovererI;
27 import uk.ac.dundee.compbio.slivkaclient.SlivkaClient;
28 import uk.ac.dundee.compbio.slivkaclient.SlivkaService;
30 public class SlivkaWSDiscovererTest
32 private static final String URLS_PROPERTY_NAME = "SLIVKAHOSTURLS";
34 SlivkaClient clientMock;
36 Function<URL, SlivkaClient> factoryMock;
38 @BeforeClass(alwaysRun = true)
39 public void setupProperties()
41 Cache.loadProperties("test/jalview/ws2/client/slivka/default.jvprops");
46 public void setupDiscoverer() throws IOException
48 clientMock = mock(SlivkaClient.class);
52 public void getStatusForUrl_servicesReturned_statusIsOK() throws Exception
54 when(clientMock.getServices())
55 .thenReturn(List.of(mock(SlivkaService.class)));
56 var discoverer = new SlivkaWSDiscoverer(
57 url -> url.toString().equals("http://example.org") ? clientMock
59 assertThat(discoverer.getStatusForUrl(new URL("http://example.org")),
60 is(WebServiceDiscovererI.STATUS_OK));
64 public void getStatusForUrl_noServicesReturned_statusIsNoServices()
67 when(clientMock.getServices()).thenReturn(List.of());
68 var discoverer = new SlivkaWSDiscoverer(
69 url -> url.toString().equals("http://example.org") ? clientMock
71 assertThat(discoverer.getStatusForUrl(new URL("http://example.org")),
72 is(WebServiceDiscovererI.STATUS_NO_SERVICES));
76 public void getStatusForUrl_exceptionThrown_statusIsInvalid()
79 when(clientMock.getServices()).thenThrow(new IOException());
80 var discoverer = new SlivkaWSDiscoverer(
81 url -> url.toString().equals("http://example.org") ? clientMock
83 assertThat(discoverer.getStatusForUrl(new URL("http://example.org")),
84 is(WebServiceDiscovererI.STATUS_INVALID));
88 public void testGetUrls_noPropEntry_defaultUrlReturned()
89 throws MalformedURLException
91 var discoverer = SlivkaWSDiscoverer.getInstance();
92 assertThat(discoverer.getUrls(),
93 contains(new URL("https://www.compbio.dundee.ac.uk/slivka/")));
97 public Object[][] urlPropertyValues() throws MalformedURLException
99 return new Object[][] {
100 { "http://example.org/", List.of(new URL("http://example.org/")) },
101 { "https://example.org/slivka/",
102 List.of(new URL("https://example.org/slivka/")) },
103 { "https://www.compbio.dundee.ac.uk/,http://www.example.org/",
104 List.of(new URL("https://www.compbio.dundee.ac.uk/"),
105 new URL("http://www.example.org/")) },
106 { "http://example.org/,", List.of(new URL("http://example.org/")) },
107 { ",http://example.org", List.of(new URL("http://example.org")) },
110 { "example.org", List.of() },
111 { "example.org,http://example.org",
112 List.of(new URL("http://example.org")) } };
115 @Test(dataProvider = "urlPropertyValues")
116 public void testGetUrls_urlsProperlyParsed(String propValue,
119 Cache.setProperty(URLS_PROPERTY_NAME, propValue);
120 var discoverer = SlivkaWSDiscoverer.getInstance();
121 assertThat(discoverer.getUrls(), equalTo(expected));
125 public void testSetUrls_emptyList_propertyReset()
127 Cache.setProperty(URLS_PROPERTY_NAME, "http://www.example.org");
128 var discoverer = SlivkaWSDiscoverer.getInstance();
129 discoverer.setUrls(List.of());
130 assertThat(Cache.getProperty(URLS_PROPERTY_NAME), is(nullValue()));
134 public void testSetUrls_null_propertyReset()
136 Cache.setProperty(URLS_PROPERTY_NAME, "http://www.example.org");
137 var discoverer = SlivkaWSDiscoverer.getInstance();
138 discoverer.setUrls(null);
139 assertThat(Cache.getProperty(URLS_PROPERTY_NAME), is(nullValue()));
143 public Object[][] urlsList() throws MalformedURLException
145 return new Object[][] {
146 { List.of(new URL("http://example.org")), "http://example.org" },
147 { List.of(new URL("http://example.org/")), "http://example.org/" },
148 { List.of(new URL("http://example.org/slivka/")),
149 "http://example.org/slivka/" },
150 { List.of(new URL("https://www.compbio.dundee.ac.uk/slivka/"),
151 new URL("http://example.org")),
152 "https://www.compbio.dundee.ac.uk/slivka/,http://example.org" }, };
155 @Test(dataProvider = "urlsList")
156 public void testSetUrls_urlsPropertySet(List<URL> urls, String expected)
157 throws MalformedURLException
159 var discoverer = SlivkaWSDiscoverer.getInstance();
160 discoverer.setUrls(urls);
161 assertThat(Cache.getProperty(URLS_PROPERTY_NAME), equalTo(expected));
165 public void testFetchServices_oneService_basicDataMatches()
168 var service = new SlivkaService(
169 URI.create("http://example.org/api/services/example"),
170 "example", "Example name", "Example service description",
171 "John Smith", "1.0", "MIT License",
172 List.of("operation::analysis::multiple sequence alignment"),
173 List.of(), List.of(), null);
174 when(clientMock.getServices()).thenReturn(List.of(service));
175 when(clientMock.getUrl()).thenReturn(URI.create("http://example.org/"));
176 var discoverer = new SlivkaWSDiscoverer(url -> clientMock);
177 var webServices = discoverer
178 .fetchServices(new URL("http://example.org/"));
179 assertThat(webServices, hasSize(1));
180 var webService = webServices.get(0);
181 assertThat(webService.getUrl(),
182 equalTo(new URL("http://example.org/")));
183 assertThat(webService.getClientName(), equalTo("slivka"));
184 assertThat(webService.getName(), equalTo("Example name"));
185 assertThat(webService.getDescription(),
186 equalTo("Example service description"));
190 public String[] validMultipleSequenceAlignmentClassifiers()
192 return new String[] {
193 "Operation :: Analysis :: Multiple sequence alignment",
194 "operation :: analysis :: multiple sequence alignment",
195 "Operation\t::\tAnalysis\t::\tMultiple sequence alignment",
196 "Operation::Analysis::Multiple sequence alignment",
197 "Operation :: Analysis :: Multiple Sequence Alignment",
198 "OPERATION :: ANALYSIS :: MULTIPLE SEQUENCE ALIGNMENT",
199 "Operation :: Analysis :: Sequence alignment :: Multiple sequence alignment",
200 "Operation :: Analysis :: Sequence analysis :: Sequence alignment :: Multiple sequence alignment",
201 "Operation :: Alignment :: Multiple sequence alignment",
202 "Operation :: Alignment :: Sequence alignment :: Multiple sequence alignment",
203 "Operation :: Comparison :: Multiple sequence alignment",
204 "Operation :: Comparison :: Sequence comparison :: Sequence alignment :: Multiple sequence alignment" };
208 @Test(dataProvider = "validMultipleSequenceAlignmentClassifiers")
209 public void testFetchServices_multipleSequenceAlignmentClassifier_serviceTypeIsMSA(
210 String classifier) throws IOException
212 var service = new SlivkaService(URI.create("http://example.org/"),
213 "example", "name", "description", "author", "1.0", "MIT",
214 List.of(classifier), List.of(), List.of(), null);
215 when(clientMock.getServices()).thenReturn(List.of(service));
216 when(clientMock.getUrl()).thenReturn(URI.create("http://example.org/"));
217 var discoverer = new SlivkaWSDiscoverer(url -> clientMock);
218 var webServices = discoverer
219 .fetchServices(new URL("http://example.org/"));
220 assertThat(webServices, hasSize(1));
221 assertThat(webServices.get(0).getCategory(), equalTo("Alignment"));
222 assertThat(webServices.get(0).getActionClass(),
223 typeCompatibleWith(AlignmentAction.class));
227 public SlivkaService[] multipleSequenceAlignmentService()
229 return new SlivkaService[] { new SlivkaService(
230 URI.create("http://example.org/"), "example", "Examaple name",
231 "Example description", "John Smith", "1.0", "MIT",
232 List.of("Operation :: Analysis :: Multiple sequence alignment"),
233 List.of(), List.of(), null),
235 URI.create("http://example.org/api/services/muscle"),
237 "MUltiple Sequence Comparison by Log- Expectation",
238 "Robert C. Edgar", "3.8.31", "Public domain",
239 List.of("Topic :: Computational biology :: Sequence analysis",
240 "Operation :: Analysis :: Sequence analysis :: Sequence alignment :: Multiple sequence alignment"),
241 List.of(), List.of(), null),
243 URI.create("http://example.org/api/services/tcoffee"),
244 "tcoffee", "TCoffee",
245 "Tree-based Consistency Objective Function for Alignment Evaluation",
246 "Cedric Notredame", "13.41.0", "GNU GPL",
247 List.of("Topic :: Computational biology :: Sequence analysis",
248 "Operation :: Analysis :: Sequence analysis :: Sequence alignment :: Multiple sequence alignment"),
249 List.of(), List.of(), null) };
252 @Test(dataProvider = "multipleSequenceAlignmentService")
253 public void testFetchServices_multipleSequenceAlignmentService_actionTypeIsAlignment(
254 SlivkaService service) throws IOException
256 when(clientMock.getServices()).thenReturn(List.of(service));
257 when(clientMock.getUrl()).thenReturn(URI.create("http://example.org/"));
258 var discoverer = new SlivkaWSDiscoverer(url -> clientMock);
259 var webServices = discoverer
260 .fetchServices(new URL("http://example.org/"));
261 assertThat(webServices.get(0).getCategory(), equalTo("Alignment"));
262 assertThat(webServices.get(0).getActionClass(),
263 typeCompatibleWith(AlignmentAction.class));
266 @Test(dataProvider = "multipleSequenceAlignmentService")
267 public void testFetchServices_multipleSequenceAlignmentService_serviceIsNonInteractive(
268 SlivkaService service) throws IOException
270 when(clientMock.getServices()).thenReturn(List.of(service));
271 when(clientMock.getUrl()).thenReturn(URI.create("http://example.org/"));
272 var discoverer = new SlivkaWSDiscoverer(url -> clientMock);
273 var webServices = discoverer
274 .fetchServices(new URL("http://example.org/"));
275 assertThat(webServices.get(0).isInteractive(), is(false));
279 public SlivkaService[] clustalFamilyService()
281 return new SlivkaService[] { new SlivkaService(
282 URI.create("http://example.org/api/services/clustalo"),
283 "clustalo", "ClustalO",
284 "Clustal Omega is the latest addition to the Clustal family.",
285 "Fabian Sievers, et al.", "1.2.4", "GNU GPL ver. 2",
286 List.of("Topic :: Computational biology :: Sequence analysis",
287 "Operation :: Analysis :: Sequence analysis :: Sequence alignment :: Multiple sequence alignment"),
288 List.of(), List.of(), null),
290 URI.create("http://example.org/api/services/clustalw"),
291 "clustalw", "ClustalW",
292 "ClustalW is a general purpose multiple alignment program.",
293 "Larkin MA, et al.", "2.1", "GNU GPL ver. 3",
294 List.of("Topic :: Computation biology :: Sequence analysis",
295 "Operation :: Analysis :: Multiple sequence alignment"),
296 List.of(), List.of(), null),
298 URI.create("http://example.org/api/services/clustalw2"),
299 "clustalw2", "ClustalW2",
300 "ClustalW is a general purpose multiple alignment program.",
301 "Larkin MA, et al.", "2.1", "GNU GPL ver. 3",
302 List.of("Topic :: Computation biology :: Sequence analysis",
303 "Operation :: Analysis :: Multiple sequence alignment"),
304 List.of(), List.of(), null), };
307 @Test(dataProvider = "clustalFamilyService")
308 public void testFetchService_clustalFamilyService_containsTwoActions(
309 SlivkaService service) throws IOException
311 when(clientMock.getServices()).thenReturn(List.of(service));
312 when(clientMock.getUrl()).thenReturn(URI.create("http://example.org"));
313 var discoverer = new SlivkaWSDiscoverer(url -> clientMock);
314 var webServices = discoverer
315 .fetchServices(new URL("http://example.org"));
316 var actions = webServices.get(0).getActions();
317 assertThat(actions, hasSize(2));
318 assertThat(actions.get(0), allOf(hasProperty("name", is("Alignment")),
319 hasProperty("subcategory", is("Align"))));
320 assertThat(actions.get(1),
321 allOf(hasProperty("name", is("Re-alignment")),
322 hasProperty("subcategory", is("Realign"))));
326 public String[] validRNASecondaryStructurePredictionClassifiers()
328 return new String[] {
329 "Operation :: Analysis :: RNA secondary structure prediction",
330 "operation :: analysis :: rna secondary structure prediction",
331 "OPERATION :: ANALYSIS :: RNA SECONDARY STRUCTURE PREDICTION",
332 "Operation\t::\tAnalysis\t::\tRNA secondary structure prediction",
333 "Operation::Analysis::RNA secondary structure prediction",
334 "Operation :: Analysis :: Structure analysis :: RNA secondary structure prediction",
335 "Operation :: Analysis :: Structure analysis :: Nucleic acid structure analysis :: RNA secondary structure analysis :: RNA secondary structure prediction",
336 "Operation :: Analysis :: Structure analysis :: Nucleic acid structure analysis :: Nucleic acid structure prediction :: RNA secondary structure prediction",
337 "Operation :: Analysis :: Sequence analysis :: Nucleic acid sequence analysis :: Nucleic acid feature detection :: RNA secondary structure prediction",
338 "Operation :: Prediction and recognition :: RNA secondary structure prediction",
339 "Operation :: Prediction and recognition :: Nucleic acid feature detection :: RNA secondary structure prediction",
340 "Operation :: Prediction and recignition :: Nucleic acid structure prediction :: RNA secondary structure prediction", };
344 public Iterator<Object> RNASecondaryStructurePredictionService()
346 var services = new ArrayList<>();
347 for (var classifier : validRNASecondaryStructurePredictionClassifiers())
349 services.add(new SlivkaService(URI.create("http://example.org/"),
350 "example", "name", "description", "author", "1.0", "MIT",
351 List.of(classifier), List.of(), List.of(), null));
353 return services.iterator();
356 @Test(dataProvider = "RNASecondaryStructurePredictionService")
357 public void testFetchServices_RNASecStrPredClassifier_serviceTypeIsRNASecStrPred(
358 SlivkaService service) throws IOException
360 when(clientMock.getServices()).thenReturn(List.of(service));
361 when(clientMock.getUrl()).thenReturn(URI.create("http://example.org/"));
362 var discoverer = new SlivkaWSDiscoverer(url -> clientMock);
363 var webServices = discoverer
364 .fetchServices(new URL("http://example.org/"));
365 assertThat(webServices, hasSize(1));
366 assertThat(webServices.get(0).getCategory(),
367 equalTo("Secondary Structure Prediction"));
368 assertThat(webServices.get(0).getActionClass(),
369 typeCompatibleWith(AnnotationAction.class));
373 public String[] validConservationAnalysisClassifiers()
375 return new String[] {
376 "Operation :: Analysis :: Sequence alignment analysis (conservation)",
377 "Operation::Analysis::Sequence alignment analysis (conservation)",
378 "Operation\t::\tAnalysis\t::\tSequence alignment analysis (conservation)",
379 "Operation :: Analysis :: Sequence analysis :: Sequence alignment analysis (conservation)",
380 "Operation :: Analysis :: Sequence analysis :: Sequence alignment analysis :: Sequence alignment analysis (conservation)", };
384 public Iterator<Object> ConservationAnalysisService()
386 var services = new ArrayList<>();
387 for (var classifier : validConservationAnalysisClassifiers())
389 services.add(new SlivkaService(URI.create("http://example.org/"),
390 "example", "name", "description", "author", "1.0", "MIT",
391 List.of(classifier), List.of(), List.of(), null));
393 return services.iterator();
396 @Test(dataProvider = "validConservationAnalysisClassifiers")
397 public void testFetchServices_conservationAnalysisClassifier_serviceTypeIsConservation(
398 String classifier) throws IOException
400 var service = new SlivkaService(URI.create("http://example.org/"),
401 "example", "name", "description", "author", "1.0", "MIT",
402 List.of(classifier), List.of(), List.of(), null);
403 when(clientMock.getServices()).thenReturn(List.of(service));
404 when(clientMock.getUrl()).thenReturn(URI.create("http://example.org/"));
405 var discoverer = new SlivkaWSDiscoverer(url -> clientMock);
406 var webServices = discoverer
407 .fetchServices(new URL("http://example.org/"));
408 assertThat(webServices, hasSize(1));
409 assertThat(webServices.get(0).getCategory(), equalTo("Conservation"));
410 assertThat(webServices.get(0).getActionClass(),
411 typeCompatibleWith(AnnotationAction.class));
415 public Object[] validProteinSequenceAnalysisClassifiers()
417 return new Object[] {
418 "Operation :: Analysis :: Sequence analysis :: Protein sequence analysis", };
421 @Test(dataProvider = "validProteinSequenceAnalysisClassifiers")
422 public void testFetchServices_proteinSequenceAnalysisClassifier_serviceTypeIsProtSeqAnalysis(
423 String classifier) throws IOException
425 var service = new SlivkaService(URI.create("http://example.org/"),
426 "example", "name", "description", "author", "1.0", "MIT",
427 List.of(classifier), List.of(), List.of(), null);
428 when(clientMock.getServices()).thenReturn(List.of(service));
429 when(clientMock.getUrl()).thenReturn(URI.create("http://example.org/"));
430 var discoverer = new SlivkaWSDiscoverer(url -> clientMock);
431 var webServices = discoverer
432 .fetchServices(new URL("http://example.org/"));
433 assertThat(webServices, hasSize(1));
434 assertThat(webServices.get(0).getCategory(),
435 equalTo("Protein Disorder"));
436 assertThat(webServices.get(0).getActionClass(),
437 typeCompatibleWith(AnnotationAction.class));
441 public Object[] validProteinSecondaryStructurePredictionClassifiers()
443 return new Object[] {
444 "Operation ;: Analysis :: Protein secondary structure prediction",
445 "Operation :: Analysis :: Structure analysis :: Protein structure analysis :: Protein secondary structure analysis :: Protein secondary structure prediction",
446 "Operation :: Analysis :: Sequence analysis :: Protein sequence analysis :: Protein feature detection :: Protein secondary structure prediction",
447 "Operation :: Analysis :: Sequence analysis :: Protein sequence analysis :: Protein secondary structure prediction",
448 "Operation :: Prediction and recognition :: Protein secondary structure prediction",
449 "Operation :: Prediction and recognition :: Protein feature detection :: Protein secondary structure prediction", };
453 enabled = false, // sec. str. pred. not implemented for slivka
454 dataProvider = "validProteinSecondaryStructurePredictionClassifiers")
455 public void testFetchServices_proteinSecStrPredClassifier_serviceTypeIsProtSecStrPred(
456 String classifier) throws IOException
458 var service = new SlivkaService(URI.create("http://example.org/"),
459 "example", "name", "description", "author", "1.0", "MIT",
460 List.of(classifier), List.of(), List.of(), null);
461 when(clientMock.getServices()).thenReturn(List.of(service));
462 when(clientMock.getUrl()).thenReturn(URI.create("http://example.org/"));
463 var discoverer = new SlivkaWSDiscoverer(url -> clientMock);
464 var webServices = discoverer
465 .fetchServices(new URL("http://example.org/"));
466 assertThat(webServices, hasSize(1));
467 assertThat(webServices.get(0).getCategory(),
468 equalTo("Protein Disorder"));
469 assertThat(webServices.get(0).getActionClass(),
470 typeCompatibleWith(AnnotationAction.class));