Merge branch 'patch/JAL-4232-disable-unavailable-services' into development/Release_2...
[jalview.git] / test / jalview / ws2 / client / slivka / SlivkaWSDiscovererTest.java
1 package jalview.ws2.client.slivka;
2
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;
7
8 import java.io.IOException;
9 import java.net.MalformedURLException;
10 import java.net.URI;
11 import java.net.URL;
12 import java.util.ArrayList;
13 import java.util.Iterator;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.function.Function;
17
18 import org.hamcrest.Matcher;
19 import org.testng.annotations.BeforeClass;
20 import org.testng.annotations.BeforeMethod;
21 import org.testng.annotations.DataProvider;
22 import org.testng.annotations.Test;
23
24 import jalview.bin.Cache;
25 import jalview.bin.Console;
26 import jalview.ws.params.ValueConstrainI.ValueType;
27 import jalview.ws.params.simple.DoubleParameter;
28 import jalview.ws.params.simple.IntegerParameter;
29 import jalview.ws.params.simple.StringParameter;
30 import jalview.ws2.actions.alignment.AlignmentAction;
31 import jalview.ws2.actions.annotation.AnnotationAction;
32 import jalview.ws2.client.api.WebServiceDiscovererI;
33 import uk.ac.dundee.compbio.slivkaclient.Parameter;
34 import uk.ac.dundee.compbio.slivkaclient.SlivkaClient;
35 import uk.ac.dundee.compbio.slivkaclient.SlivkaService;
36
37 public class SlivkaWSDiscovererTest
38 {
39   private static final String URLS_PROPERTY_NAME = "SLIVKAHOSTURLS";
40
41   SlivkaClient clientMock;
42
43   Function<URL, SlivkaClient> factoryMock;
44
45   @BeforeClass(alwaysRun = true)
46   public void setupProperties()
47   {
48     Cache.loadProperties("test/jalview/ws2/client/slivka/default.jvprops");
49     Console.initLogger();
50   }
51
52   @BeforeMethod
53   public void setupDiscoverer() throws IOException
54   {
55     clientMock = mock(SlivkaClient.class);
56   }
57
58   @Test
59   public void getStatusForUrl_servicesReturned_statusIsOK() throws Exception
60   {
61     when(clientMock.getServices())
62         .thenReturn(List.of(mock(SlivkaService.class)));
63     var discoverer = new SlivkaWSDiscoverer(
64         url -> url.toString().equals("http://example.org") ? clientMock
65             : null);
66     assertThat(discoverer.getStatusForUrl(new URL("http://example.org")),
67         is(WebServiceDiscovererI.STATUS_OK));
68   }
69
70   @Test
71   public void getStatusForUrl_noServicesReturned_statusIsNoServices()
72       throws Exception
73   {
74     when(clientMock.getServices()).thenReturn(List.of());
75     var discoverer = new SlivkaWSDiscoverer(
76         url -> url.toString().equals("http://example.org") ? clientMock
77             : null);
78     assertThat(discoverer.getStatusForUrl(new URL("http://example.org")),
79         is(WebServiceDiscovererI.STATUS_NO_SERVICES));
80   }
81
82   @Test
83   public void getStatusForUrl_exceptionThrown_statusIsInvalid()
84       throws Exception
85   {
86     when(clientMock.getServices()).thenThrow(new IOException());
87     var discoverer = new SlivkaWSDiscoverer(
88         url -> url.toString().equals("http://example.org") ? clientMock
89             : null);
90     assertThat(discoverer.getStatusForUrl(new URL("http://example.org")),
91         is(WebServiceDiscovererI.STATUS_INVALID));
92   }
93
94   @Test
95   public void testGetUrls_noPropEntry_defaultUrlReturned()
96       throws MalformedURLException
97   {
98     var discoverer = SlivkaWSDiscoverer.getInstance();
99     assertThat(discoverer.getUrls(),
100         contains(new URL("https://www.compbio.dundee.ac.uk/slivka/")));
101   }
102
103   @DataProvider
104   public Object[][] urlPropertyValues() throws MalformedURLException
105   {
106     return new Object[][] {
107         { "http://example.org/", List.of(new URL("http://example.org/")) },
108         { "https://example.org/slivka/",
109             List.of(new URL("https://example.org/slivka/")) },
110         { "https://www.compbio.dundee.ac.uk/,http://www.example.org/",
111             List.of(new URL("https://www.compbio.dundee.ac.uk/"),
112                 new URL("http://www.example.org/")) },
113         { "http://example.org/,", List.of(new URL("http://example.org/")) },
114         { ",http://example.org", List.of(new URL("http://example.org")) },
115         { "", List.of() },
116         { ",", List.of() },
117         { "example.org", List.of() },
118         { "example.org,http://example.org",
119             List.of(new URL("http://example.org")) } };
120   }
121
122   @Test(dataProvider = "urlPropertyValues")
123   public void testGetUrls_urlsProperlyParsed(String propValue,
124       List<URL> expected)
125   {
126     Cache.setProperty(URLS_PROPERTY_NAME, propValue);
127     var discoverer = SlivkaWSDiscoverer.getInstance();
128     assertThat(discoverer.getUrls(), equalTo(expected));
129   }
130
131   @Test
132   public void testSetUrls_emptyList_propertyReset()
133   {
134     Cache.setProperty(URLS_PROPERTY_NAME, "http://www.example.org");
135     var discoverer = SlivkaWSDiscoverer.getInstance();
136     discoverer.setUrls(List.of());
137     assertThat(Cache.getProperty(URLS_PROPERTY_NAME), is(nullValue()));
138   }
139
140   @Test
141   public void testSetUrls_null_propertyReset()
142   {
143     Cache.setProperty(URLS_PROPERTY_NAME, "http://www.example.org");
144     var discoverer = SlivkaWSDiscoverer.getInstance();
145     discoverer.setUrls(null);
146     assertThat(Cache.getProperty(URLS_PROPERTY_NAME), is(nullValue()));
147   }
148
149   @DataProvider
150   public Object[][] urlsList() throws MalformedURLException
151   {
152     return new Object[][] {
153         { List.of(new URL("http://example.org")), "http://example.org" },
154         { List.of(new URL("http://example.org/")), "http://example.org/" },
155         { List.of(new URL("http://example.org/slivka/")),
156             "http://example.org/slivka/" },
157         { List.of(new URL("https://www.compbio.dundee.ac.uk/slivka/"),
158             new URL("http://example.org")),
159             "https://www.compbio.dundee.ac.uk/slivka/,http://example.org" }, };
160   }
161
162   @Test(dataProvider = "urlsList")
163   public void testSetUrls_urlsPropertySet(List<URL> urls, String expected)
164       throws MalformedURLException
165   {
166     var discoverer = SlivkaWSDiscoverer.getInstance();
167     discoverer.setUrls(urls);
168     assertThat(Cache.getProperty(URLS_PROPERTY_NAME), equalTo(expected));
169   }
170
171   @Test
172   public void testFetchServices_oneService_basicDataMatches()
173       throws IOException
174   {
175     var service = new SlivkaService(
176         URI.create("http://example.org/api/services/example"),
177         "example", "Example name", "Example service description",
178         "John Smith", "1.0", "MIT License",
179         List.of("operation::analysis::multiple sequence alignment"),
180         List.of(), List.of(), null);
181     when(clientMock.getServices()).thenReturn(List.of(service));
182     when(clientMock.getUrl()).thenReturn(URI.create("http://example.org/"));
183     var discoverer = new SlivkaWSDiscoverer(url -> clientMock);
184     var webServices = discoverer
185         .fetchServices(new URL("http://example.org/"));
186     assertThat(webServices, hasSize(1));
187     var webService = webServices.get(0);
188     assertThat(webService.getUrl(),
189         equalTo(new URL("http://example.org/")));
190     assertThat(webService.getClientName(), equalTo("slivka"));
191     assertThat(webService.getName(), equalTo("Example name"));
192     assertThat(webService.getDescription(),
193         equalTo("Example service description"));
194   }
195
196   @DataProvider
197   public String[] validMultipleSequenceAlignmentClassifiers()
198   {
199     return new String[] {
200         "Operation :: Analysis :: Multiple sequence alignment",
201         "operation :: analysis :: multiple sequence alignment",
202         "Operation\t::\tAnalysis\t::\tMultiple sequence alignment",
203         "Operation::Analysis::Multiple sequence alignment",
204         "Operation :: Analysis :: Multiple Sequence Alignment",
205         "OPERATION :: ANALYSIS :: MULTIPLE SEQUENCE ALIGNMENT",
206         "Operation :: Analysis :: Sequence alignment :: Multiple sequence alignment",
207         "Operation :: Analysis :: Sequence analysis :: Sequence alignment :: Multiple sequence alignment",
208         "Operation :: Alignment :: Multiple sequence alignment",
209         "Operation :: Alignment :: Sequence alignment :: Multiple sequence alignment",
210         "Operation :: Comparison :: Multiple sequence alignment",
211         "Operation :: Comparison :: Sequence comparison :: Sequence alignment :: Multiple sequence alignment" };
212
213   }
214
215   @Test(dataProvider = "validMultipleSequenceAlignmentClassifiers")
216   public void testFetchServices_multipleSequenceAlignmentClassifier_serviceTypeIsMSA(
217       String classifier) throws IOException
218   {
219     var service = new SlivkaService(URI.create("http://example.org/"),
220         "example", "name", "description", "author", "1.0", "MIT",
221         List.of(classifier), List.of(), List.of(), null);
222     when(clientMock.getServices()).thenReturn(List.of(service));
223     when(clientMock.getUrl()).thenReturn(URI.create("http://example.org/"));
224     var discoverer = new SlivkaWSDiscoverer(url -> clientMock);
225     var webServices = discoverer
226         .fetchServices(new URL("http://example.org/"));
227     assertThat(webServices, hasSize(1));
228     assertThat(webServices.get(0).getCategory(), equalTo("Alignment"));
229     assertThat(webServices.get(0).getActionClass(),
230         typeCompatibleWith(AlignmentAction.class));
231   }
232
233   @DataProvider
234   public SlivkaService[] multipleSequenceAlignmentService()
235   {
236     return new SlivkaService[] {
237         new SlivkaService(
238             URI.create("http://example.org/"), "example", "Examaple name",
239             "Example description", "John Smith", "1.0", "MIT",
240             List.of("Operation :: Analysis :: Multiple sequence alignment"),
241             List.of(), List.of(), null),
242         new SlivkaService(
243             URI.create("http://example.org/api/services/muscle"),
244             "muscle", "MUSCLE",
245             "MUltiple Sequence Comparison by Log- Expectation",
246             "Robert C. Edgar", "3.8.31", "Public domain",
247             List.of("Topic :: Computational biology :: Sequence analysis",
248                 "Operation :: Analysis :: Sequence analysis :: Sequence alignment :: Multiple sequence alignment"),
249             List.of(), List.of(), null),
250         new SlivkaService(
251             URI.create("http://example.org/api/services/tcoffee"),
252             "tcoffee", "TCoffee",
253             "Tree-based Consistency Objective Function for Alignment Evaluation",
254             "Cedric Notredame", "13.41.0", "GNU GPL",
255             List.of("Topic :: Computational biology :: Sequence analysis",
256                 "Operation :: Analysis :: Sequence analysis :: Sequence alignment :: Multiple sequence alignment"),
257             List.of(), List.of(), null) };
258   }
259
260   @Test(dataProvider = "multipleSequenceAlignmentService")
261   public void testFetchServices_multipleSequenceAlignmentService_actionTypeIsAlignment(
262       SlivkaService service) throws IOException
263   {
264     when(clientMock.getServices()).thenReturn(List.of(service));
265     when(clientMock.getUrl()).thenReturn(URI.create("http://example.org/"));
266     var discoverer = new SlivkaWSDiscoverer(url -> clientMock);
267     var webServices = discoverer
268         .fetchServices(new URL("http://example.org/"));
269     assertThat(webServices.get(0).getCategory(), equalTo("Alignment"));
270     assertThat(webServices.get(0).getActionClass(),
271         typeCompatibleWith(AlignmentAction.class));
272   }
273
274   @Test(dataProvider = "multipleSequenceAlignmentService")
275   public void testFetchServices_multipleSequenceAlignmentService_serviceIsNonInteractive(
276       SlivkaService service) throws IOException
277   {
278     when(clientMock.getServices()).thenReturn(List.of(service));
279     when(clientMock.getUrl()).thenReturn(URI.create("http://example.org/"));
280     var discoverer = new SlivkaWSDiscoverer(url -> clientMock);
281     var webServices = discoverer
282         .fetchServices(new URL("http://example.org/"));
283     assertThat(webServices.get(0).isInteractive(), is(false));
284   }
285
286   @DataProvider
287   public SlivkaService[] clustalFamilyService()
288   {
289     return new SlivkaService[] {
290         new SlivkaService(
291             URI.create("http://example.org/api/services/clustalo"),
292             "clustalo", "ClustalO",
293             "Clustal Omega is the latest addition to the Clustal family.",
294             "Fabian Sievers, et al.", "1.2.4", "GNU GPL ver. 2",
295             List.of("Topic :: Computational biology :: Sequence analysis",
296                 "Operation :: Analysis :: Sequence analysis :: Sequence alignment :: Multiple sequence alignment"),
297             List.of(), List.of(), null),
298         new SlivkaService(
299             URI.create("http://example.org/api/services/clustalw"),
300             "clustalw", "ClustalW",
301             "ClustalW is a general purpose multiple alignment program.",
302             "Larkin MA, et al.", "2.1", "GNU GPL ver. 3",
303             List.of("Topic :: Computation biology :: Sequence analysis",
304                 "Operation :: Analysis :: Multiple sequence alignment"),
305             List.of(), List.of(), null),
306         new SlivkaService(
307             URI.create("http://example.org/api/services/clustalw2"),
308             "clustalw2", "ClustalW2",
309             "ClustalW is a general purpose multiple alignment program.",
310             "Larkin MA, et al.", "2.1", "GNU GPL ver. 3",
311             List.of("Topic :: Computation biology :: Sequence analysis",
312                 "Operation :: Analysis :: Multiple sequence alignment"),
313             List.of(), List.of(), null), };
314   }
315
316   @Test(dataProvider = "clustalFamilyService")
317   public void testFetchService_clustalFamilyService_containsTwoActions(
318       SlivkaService service) throws IOException
319   {
320     when(clientMock.getServices()).thenReturn(List.of(service));
321     when(clientMock.getUrl()).thenReturn(URI.create("http://example.org"));
322     var discoverer = new SlivkaWSDiscoverer(url -> clientMock);
323     var webServices = discoverer
324         .fetchServices(new URL("http://example.org"));
325     var actions = webServices.get(0).getActions();
326     assertThat(actions, hasSize(2));
327     assertThat(actions.get(0), allOf(hasProperty("name", is("Alignment")),
328         hasProperty("subcategory", is("Align"))));
329     assertThat(actions.get(1),
330         allOf(hasProperty("name", is("Re-alignment")),
331             hasProperty("subcategory", is("Realign"))));
332   }
333
334   @DataProvider
335   public String[] validRNASecondaryStructurePredictionClassifiers()
336   {
337     return new String[] {
338         "Operation :: Analysis :: RNA secondary structure prediction",
339         "operation :: analysis :: rna secondary structure prediction",
340         "OPERATION :: ANALYSIS :: RNA SECONDARY STRUCTURE PREDICTION",
341         "Operation\t::\tAnalysis\t::\tRNA secondary structure prediction",
342         "Operation::Analysis::RNA secondary structure prediction",
343         "Operation :: Analysis :: Structure analysis :: RNA secondary structure prediction",
344         "Operation :: Analysis :: Structure analysis :: Nucleic acid structure analysis :: RNA secondary structure analysis :: RNA secondary structure prediction",
345         "Operation :: Analysis :: Structure analysis :: Nucleic acid structure analysis :: Nucleic acid structure prediction :: RNA secondary structure prediction",
346         "Operation :: Analysis :: Sequence analysis :: Nucleic acid sequence analysis :: Nucleic acid feature detection :: RNA secondary structure prediction",
347         "Operation :: Prediction and recognition :: RNA secondary structure prediction",
348         "Operation :: Prediction and recognition :: Nucleic acid feature detection :: RNA secondary structure prediction",
349         "Operation :: Prediction and recignition :: Nucleic acid structure prediction :: RNA secondary structure prediction", };
350   }
351
352   @DataProvider
353   public Iterator<Object> RNASecondaryStructurePredictionService()
354   {
355     var services = new ArrayList<>();
356     for (var classifier : validRNASecondaryStructurePredictionClassifiers())
357     {
358       services.add(new SlivkaService(URI.create("http://example.org/"),
359           "example", "name", "description", "author", "1.0", "MIT",
360           List.of(classifier), List.of(), List.of(), null));
361     }
362     return services.iterator();
363   }
364
365   @Test(dataProvider = "RNASecondaryStructurePredictionService")
366   public void testFetchServices_RNASecStrPredClassifier_serviceTypeIsRNASecStrPred(
367       SlivkaService service) throws IOException
368   {
369     when(clientMock.getServices()).thenReturn(List.of(service));
370     when(clientMock.getUrl()).thenReturn(URI.create("http://example.org/"));
371     var discoverer = new SlivkaWSDiscoverer(url -> clientMock);
372     var webServices = discoverer
373         .fetchServices(new URL("http://example.org/"));
374     assertThat(webServices, hasSize(1));
375     assertThat(webServices.get(0).getCategory(),
376         equalTo("Secondary Structure Prediction"));
377     assertThat(webServices.get(0).getActionClass(),
378         typeCompatibleWith(AnnotationAction.class));
379   }
380
381   @DataProvider
382   public String[] validConservationAnalysisClassifiers()
383   {
384     return new String[] {
385         "Operation :: Analysis :: Sequence alignment analysis (conservation)",
386         "Operation::Analysis::Sequence alignment analysis (conservation)",
387         "Operation\t::\tAnalysis\t::\tSequence alignment analysis (conservation)",
388         "Operation :: Analysis :: Sequence analysis :: Sequence alignment analysis (conservation)",
389         "Operation :: Analysis :: Sequence analysis :: Sequence alignment analysis :: Sequence alignment analysis (conservation)", };
390   }
391
392   @DataProvider
393   public Iterator<Object> ConservationAnalysisService()
394   {
395     var services = new ArrayList<>();
396     for (var classifier : validConservationAnalysisClassifiers())
397     {
398       services.add(new SlivkaService(URI.create("http://example.org/"),
399           "example", "name", "description", "author", "1.0", "MIT",
400           List.of(classifier), List.of(), List.of(), null));
401     }
402     return services.iterator();
403   }
404
405   @Test(dataProvider = "validConservationAnalysisClassifiers")
406   public void testFetchServices_conservationAnalysisClassifier_serviceTypeIsConservation(
407       String classifier) throws IOException
408   {
409     var service = new SlivkaService(URI.create("http://example.org/"),
410         "example", "name", "description", "author", "1.0", "MIT",
411         List.of(classifier), List.of(), List.of(), null);
412     when(clientMock.getServices()).thenReturn(List.of(service));
413     when(clientMock.getUrl()).thenReturn(URI.create("http://example.org/"));
414     var discoverer = new SlivkaWSDiscoverer(url -> clientMock);
415     var webServices = discoverer
416         .fetchServices(new URL("http://example.org/"));
417     assertThat(webServices, hasSize(1));
418     assertThat(webServices.get(0).getCategory(), equalTo("Conservation"));
419     assertThat(webServices.get(0).getActionClass(),
420         typeCompatibleWith(AnnotationAction.class));
421   }
422
423   @DataProvider
424   public Object[] validProteinSequenceAnalysisClassifiers()
425   {
426     return new Object[] {
427         "Operation :: Analysis :: Sequence analysis :: Protein sequence analysis", };
428   }
429
430   @Test(dataProvider = "validProteinSequenceAnalysisClassifiers")
431   public void testFetchServices_proteinSequenceAnalysisClassifier_serviceTypeIsProtSeqAnalysis(
432       String classifier) throws IOException
433   {
434     var service = new SlivkaService(URI.create("http://example.org/"),
435         "example", "name", "description", "author", "1.0", "MIT",
436         List.of(classifier), List.of(), List.of(), null);
437     when(clientMock.getServices()).thenReturn(List.of(service));
438     when(clientMock.getUrl()).thenReturn(URI.create("http://example.org/"));
439     var discoverer = new SlivkaWSDiscoverer(url -> clientMock);
440     var webServices = discoverer
441         .fetchServices(new URL("http://example.org/"));
442     assertThat(webServices, hasSize(1));
443     assertThat(webServices.get(0).getCategory(),
444         equalTo("Protein Disorder"));
445     assertThat(webServices.get(0).getActionClass(),
446         typeCompatibleWith(AnnotationAction.class));
447   }
448
449   @DataProvider
450   public Object[] validProteinSecondaryStructurePredictionClassifiers()
451   {
452     return new Object[] {
453         "Operation ;: Analysis :: Protein secondary structure prediction",
454         "Operation :: Analysis :: Structure analysis :: Protein structure analysis :: Protein secondary structure analysis :: Protein secondary structure prediction",
455         "Operation :: Analysis :: Sequence analysis :: Protein sequence analysis :: Protein feature detection :: Protein secondary structure prediction",
456         "Operation :: Analysis :: Sequence analysis :: Protein sequence analysis :: Protein secondary structure prediction",
457         "Operation :: Prediction and recognition :: Protein secondary structure prediction",
458         "Operation :: Prediction and recognition :: Protein feature detection :: Protein secondary structure prediction", };
459   }
460
461   @Test(
462     enabled = false, // sec. str. pred. not implemented for slivka
463     dataProvider = "validProteinSecondaryStructurePredictionClassifiers")
464   public void testFetchServices_proteinSecStrPredClassifier_serviceTypeIsProtSecStrPred(
465       String classifier) throws IOException
466   {
467     var service = new SlivkaService(URI.create("http://example.org/"),
468         "example", "name", "description", "author", "1.0", "MIT",
469         List.of(classifier), List.of(), List.of(), null);
470     when(clientMock.getServices()).thenReturn(List.of(service));
471     when(clientMock.getUrl()).thenReturn(URI.create("http://example.org/"));
472     var discoverer = new SlivkaWSDiscoverer(url -> clientMock);
473     var webServices = discoverer
474         .fetchServices(new URL("http://example.org/"));
475     assertThat(webServices, hasSize(1));
476     assertThat(webServices.get(0).getCategory(),
477         equalTo("Protein Disorder"));
478     assertThat(webServices.get(0).getActionClass(),
479         typeCompatibleWith(AnnotationAction.class));
480   }
481
482   @DataProvider
483   public SlivkaService[] unrecognisedService()
484   {
485     return new SlivkaService[] {
486         new SlivkaService(URI.create("http://example.org/"), "example",
487             "Example name", "Example description", "John Smith",
488             "1.0.0", "Apache License, version 2.0",
489             List.of("This :: Classifier :: Does not exist"), List.of(),
490             List.of(), null) };
491   }
492
493   @Test(dataProvider = "unrecognisedService")
494   public void testFetchServices_unrecognisedService_noServiceDiscovered(
495       SlivkaService service) throws IOException
496   {
497     when(clientMock.getServices()).thenReturn(List.of(service));
498     when(clientMock.getUrl()).thenReturn(URI.create("http://example.org"));
499     var discoverer = new SlivkaWSDiscoverer(url -> clientMock);
500     var webServices = discoverer
501         .fetchServices(new URL("http://example.org"));
502     assertThat(webServices, hasSize(0));
503   }
504
505   @DataProvider
506   public Object[] serviceParameterAndMappedClass()
507   {
508     return new Object[][] {
509         {
510             new Parameter.IntegerParameter("param", "Parameter", "Description",
511                 true, false, null, Map.of(), null, null),
512             IntegerParameter.class
513         },
514         {
515             new Parameter.DecimalParameter("param", "Parameter",
516                 "Description", true, false, null, Map.of(), null, null,
517                 false, false),
518             DoubleParameter.class
519         },
520         {
521             new Parameter.TextParameter("param", "Parameter", "Description",
522                 true, false, null, Map.of(), 0, null),
523             StringParameter.class
524         },
525         {
526             new Parameter.FlagParameter("param", "Parameter", "Description",
527                 true, false, null, Map.of()),
528             StringParameter.class
529         },
530         {
531             new Parameter.ChoiceParameter("param", "Parameter", "Description",
532                 true, false, null, Map.of(), List.of()),
533             StringParameter.class
534         },
535     };
536   }
537
538   @Test(dataProvider = "serviceParameterAndMappedClass")
539   public void testServiceParameter_slivkaParameterMappedToJalviewParameter(
540       Parameter slivkaParameter, Class<?> expectedClass)
541       throws IOException
542   {
543     var service = new SlivkaService(URI.create("http://example.org"),
544         "example", "name", "description", "author", "1.0",
545         "MIT License",
546         List.of("Operation :: Analysis :: Multiple sequence alignment"),
547         List.of(slivkaParameter), List.of(), null);
548     when(clientMock.getServices()).thenReturn(List.of(service));
549     when(clientMock.getUrl()).thenReturn(URI.create("http://example.org"));
550     var discoverer = new SlivkaWSDiscoverer(url -> clientMock);
551     var webServices = discoverer
552         .fetchServices(new URL("http://example.org"));
553     var paramDatastore = webServices.get(0).getParamDatastore();
554     var arguments = paramDatastore.getServiceParameters();
555     assertThat(arguments.get(0), instanceOf(expectedClass));
556   }
557
558   @DataProvider
559   public Object[][] serviceParametersAndPropertyMatcher()
560   {
561     return new Object[][] {
562         {
563             new Parameter.IntegerParameter("param1", "Parameter 1",
564                 "Description of parameter 1", true, false, null, Map.of(),
565                 null, null),
566             allOf(
567                 hasProperty("name", equalTo("param1")),
568                 hasProperty("label", equalTo("Parameter 1")),
569                 hasProperty("description", equalTo("Description of parameter 1")),
570                 hasProperty("required", is(true)),
571                 hasProperty("value", nullValue()))
572         },
573         {
574             new Parameter.IntegerParameter("param2", null, null, true, false,
575                 null, Map.of(), null, null),
576             allOf(
577                 hasProperty("name", equalTo("param2")),
578                 hasProperty("label", equalTo("param2")),
579                 hasProperty("description", nullValue()),
580                 hasProperty("required", is(true)),
581                 hasProperty("value", nullValue()))
582         },
583         {
584             new Parameter.IntegerParameter("param3", "Parameter 3", "", false,
585                 false, 12, Map.of(), null, null),
586             allOf(
587                 hasProperty("name", equalTo("param3")),
588                 hasProperty("label", equalTo("Parameter 3")),
589                 hasProperty("description", equalTo("")),
590                 hasProperty("required", is(false)),
591                 hasProperty("value", equalTo("12")))
592         },
593     };
594   }
595
596   @Test(dataProvider = "serviceParametersAndInfoMatcher")
597   public void testServiceParameters_testBasicParameterProperties(
598       Parameter parameter, Matcher<Object> matcher) throws IOException
599   {
600     var service = new SlivkaService(URI.create("http://example.org/"),
601         "example", "Example name", "Example description", "John Smith",
602         "1.0", "MIT",
603         List.of("Operation :: Analysis :: Multiple sequence alignment"),
604         List.of(parameter), List.of(), null);
605     when(clientMock.getServices()).thenReturn(List.of(service));
606     when(clientMock.getUrl()).thenReturn(URI.create("http://example.org/"));
607     var discoverer = new SlivkaWSDiscoverer(url -> clientMock);
608     var webServices = discoverer
609         .fetchServices(new URL("http://example.org/"));
610     var paramDatastore = webServices.get(0).getParamDatastore();
611     var arguments = paramDatastore.getServiceParameters();
612     assertThat(arguments.get(0), matcher);
613   }
614
615   @DataProvider
616   public Object[][] integerParametersAndPropertyMatcher()
617   {
618     return new Object[][] {
619         {
620             new Parameter.IntegerParameter("param", null, null, true, false,
621                 null, Map.of(), null, null),
622             hasProperty("validValue", hasProperty("type", is(ValueType.Integer)))
623         },
624         {
625             new Parameter.IntegerParameter("param", null, null, true, false,
626                 null, Map.of(), null, null),
627             hasProperty("validValue", allOf(
628                 hasProperty("min", nullValue()),
629                 hasProperty("max", nullValue()))),
630         },
631         {
632             new Parameter.IntegerParameter("param", null, null, true, false,
633                 null, Map.of(), -12, 42),
634             hasProperty("validValue", allOf(
635                 hasProperty("min", is(-12)),
636                 hasProperty("max", is(42))))
637         },
638     };
639   }
640
641   @Test(dataProvider = "integerParametersAndPropertyMatcher")
642   public void testServiceParameters_testIntegerProperties(
643       Parameter parameter, Matcher<Object> matcher) throws IOException
644   {
645     var service = new SlivkaService(URI.create("http://example.org"),
646         "example", "Example name", "Example description", "John Smith",
647         "1.0", "MIT",
648         List.of("Operation :: Analysis :: Multiple Sequence Alignment"),
649         List.of(parameter), List.of(), null);
650     when(clientMock.getServices()).thenReturn(List.of(service));
651     when(clientMock.getUrl()).thenReturn(URI.create("http://example.org/"));
652     var discoverer = new SlivkaWSDiscoverer(url -> clientMock);
653     var webServices = discoverer
654         .fetchServices(new URL("http://example.org/"));
655     var paramDatastore = webServices.get(0).getParamDatastore();
656     var arguments = paramDatastore.getServiceParameters();
657     assertThat(arguments.get(0), matcher);
658   }
659 }