Clover icon

Coverage Report

  1. Project Clover database Thu Dec 4 2025 14:43:25 GMT
  2. Package jalview.ws2.actions.alignment

File AlignmentActionTest.java

 

Code metrics

0
74
14
2
281
257
15
0.2
5.29
7
1.07

Classes

Class Line # Actions
AlignmentActionTest 43 58 9
0.984848598.5%
AlignmentActionListenerNotifiedTest 210 16 6
1.0100%
 

Contributing tests

This file is covered by 26 tests. .

Source view

1    package jalview.ws2.actions.alignment;
2   
3    import static jalview.testutils.Matchers.matchesSequenceString;
4    import static org.hamcrest.MatcherAssert.assertThat;
5    import static org.hamcrest.Matchers.contains;
6    import static org.hamcrest.Matchers.hasProperty;
7    import static org.hamcrest.Matchers.is;
8    import static org.mockito.ArgumentMatchers.any;
9    import static org.mockito.ArgumentMatchers.anyList;
10    import static org.mockito.ArgumentMatchers.eq;
11    import static org.mockito.Mockito.doAnswer;
12    import static org.mockito.Mockito.doThrow;
13    import static org.mockito.Mockito.inOrder;
14    import static org.mockito.Mockito.mock;
15    import static org.mockito.Mockito.verify;
16    import static org.mockito.Mockito.when;
17   
18    import java.io.IOException;
19    import java.net.URL;
20    import java.util.List;
21    import java.util.concurrent.CountDownLatch;
22    import java.util.concurrent.TimeUnit;
23   
24    import org.mockito.ArgumentCaptor;
25    import org.testng.annotations.BeforeMethod;
26    import org.testng.annotations.DataProvider;
27    import org.testng.annotations.Test;
28   
29    import jalview.datamodel.Alignment;
30    import jalview.datamodel.Sequence;
31    import jalview.datamodel.SequenceI;
32    import jalview.gui.AlignViewport;
33    import jalview.viewmodel.AlignmentViewport;
34    import jalview.ws.params.ParamDatastoreI;
35    import jalview.ws2.actions.PollingTaskExecutor;
36    import jalview.ws2.actions.api.TaskEventListener;
37    import jalview.ws2.api.Credentials;
38    import jalview.ws2.api.JobStatus;
39    import jalview.ws2.api.WebService;
40    import jalview.ws2.api.WebServiceJobHandle;
41    import jalview.ws2.client.api.AlignmentWebServiceClientI;
42   
 
43    public class AlignmentActionTest
44    {
45    protected AlignmentWebServiceClientI mockClient;
46   
47    protected AlignmentAction.Builder actionBuilder;
48   
49    protected WebServiceJobHandle jobRef;
50   
 
51  26 toggle @BeforeMethod(alwaysRun = true)
52    public void setupMockClient() throws IOException
53    {
54  26 jobRef = new WebServiceJobHandle(
55    "mock", "mock", "http://example.org", "00000001");
56  26 mockClient = mock(AlignmentWebServiceClientI.class);
57  26 when(mockClient.getUrl()).thenReturn("http://example.org");
58  26 when(mockClient.getClientName()).thenReturn("mock");
59  26 when(mockClient.submit(anyList(), anyList(), any())).thenReturn(jobRef);
60  26 when(mockClient.getLog(jobRef)).thenReturn("");
61  26 when(mockClient.getErrorLog(jobRef)).thenReturn("");
62  26 doThrow(new UnsupportedOperationException()).when(mockClient).cancel(any());
63    }
64   
 
65  26 toggle @BeforeMethod(alwaysRun = true, dependsOnMethods = { "setupMockClient" })
66    public void setupActionBuilder() throws IOException
67    {
68  26 actionBuilder = AlignmentAction.newBuilder(mockClient);
69  26 actionBuilder.name("mock");
70  26 actionBuilder.webService(
71    WebService.<AlignmentAction> newBuilder()
72    .url(new URL("http://example.org"))
73    .clientName("mock")
74    .category("Alignment")
75    .name("mock")
76    .paramDatastore(mock(ParamDatastoreI.class))
77    .actionClass(AlignmentAction.class)
78    .build());
79    }
80   
 
81  8 toggle @DataProvider
82    public Object[][] multipleSequencesUnalignedAndAligned()
83    {
84  8 return new Object[][] {
85    {
86    new Alignment(new SequenceI[]
87    {
88    new Sequence("Seq 1", "----ASTVLITOPDCMMQEGGST-"),
89    new Sequence("Seq 2", "-ASCGLITO------MMQEGGST-"),
90    new Sequence("Seq 3", "AS--TVL--OPDTMMQEL------")
91    }),
92    new Alignment(new SequenceI[]
93    {
94    new Sequence("Sequence0", "ASTV-LITOPDCMMQEGGST----"),
95    new Sequence("Sequence1", "ASC-GLITO---MMQEGGST----"),
96    new Sequence("Sequence2", "ASTV-L--OPDTMMQE--L-----")
97    })
98    }
99    };
100    }
101   
 
102  2 toggle @Test(
103    groups = { "Functional" },
104    dataProvider = "multipleSequencesUnalignedAndAligned")
105    public void submitSequences_verifySequenceNamesUniquified(
106    Alignment unaligned, Alignment aligned)
107    throws IOException
108    {
109  2 var viewport = new AlignViewport(unaligned);
110  2 when(mockClient.getAlignment(jobRef)).thenReturn(aligned);
111  2 when(mockClient.getStatus(jobRef)).thenReturn(JobStatus.COMPLETED);
112  2 actionBuilder.submitGaps(false);
113  2 performAction(viewport, actionBuilder.build());
114  2 ArgumentCaptor<List<SequenceI>> argument = ArgumentCaptor.forClass(List.class);
115  2 verify(mockClient).submit(argument.capture(), eq(List.of()), eq(Credentials.empty()));
116  2 assertThat(argument.getValue(),
117    contains(hasProperty("name", is("Sequence0")),
118    hasProperty("name", is("Sequence1")),
119    hasProperty("name", is("Sequence2"))));
120    }
121   
 
122  2 toggle @Test(
123    groups = { "Functional" },
124    dataProvider = "multipleSequencesUnalignedAndAligned")
125    public void submitSequences_submitGapsOff_verifySequencesSubmittedWithoutGaps(Alignment unaligned, Alignment aligned)
126    throws IOException
127    {
128  2 var viewport = new AlignViewport(unaligned);
129  2 actionBuilder.submitGaps(false);
130  2 when(mockClient.getAlignment(jobRef)).thenReturn(aligned);
131  2 when(mockClient.getStatus(jobRef)).thenReturn(JobStatus.COMPLETED);
132  2 performAction(viewport, actionBuilder.build());
133  2 ArgumentCaptor<List<SequenceI>> argument = ArgumentCaptor.forClass(List.class);
134  2 verify(mockClient).submit(argument.capture(), eq(List.of()), eq(Credentials.empty()));
135  2 assertThat(argument.getValue(),
136    contains(
137    matchesSequenceString("ASTVLITOPDCMMQEGGST"),
138    matchesSequenceString("ASCGLITOMMQEGGST"),
139    matchesSequenceString("ASTVLOPDTMMQEL")));
140    }
141   
 
142  2 toggle @Test(
143    groups = { "Functional" },
144    dataProvider = "multipleSequencesUnalignedAndAligned")
145    public void submitSequences_submitGapsOn_verifySequencesSubmittedWithGaps(
146    Alignment unaligned, Alignment aligned)
147    throws IOException
148    {
149  2 var viewport = new AlignViewport(unaligned);
150  2 actionBuilder.submitGaps(true);
151  2 when(mockClient.getAlignment(jobRef)).thenReturn(aligned);
152  2 when(mockClient.getStatus(jobRef)).thenReturn(JobStatus.COMPLETED);
153  2 performAction(viewport, actionBuilder.build());
154  2 ArgumentCaptor<List<SequenceI>> argument = ArgumentCaptor.forClass(List.class);
155  2 verify(mockClient).submit(argument.capture(), eq(List.of()), eq(Credentials.empty()));
156  2 assertThat(argument.getValue(),
157    contains(
158    matchesSequenceString("----ASTVLITOPDCMMQEGGST-"),
159    matchesSequenceString("-ASCGLITO------MMQEGGST-"),
160    matchesSequenceString("AS--TVL--OPDTMMQEL------")));
161    }
162   
 
163  2 toggle @Test(
164    groups = { "Functional" },
165    dataProvider = "multipleSequencesUnalignedAndAligned")
166    public void retrieveResult_verifySequencesAligned(
167    Alignment unaligned, Alignment aligned)
168    throws IOException
169    {
170  2 var viewport = new AlignViewport(unaligned);
171  2 actionBuilder.submitGaps(false);
172  2 when(mockClient.getAlignment(jobRef)).thenReturn(aligned);
173  2 when(mockClient.getStatus(jobRef)).thenReturn(JobStatus.COMPLETED);
174  2 var mockListener = performAction(viewport, actionBuilder.build());
175  2 var argument = ArgumentCaptor.forClass(AlignmentResult.class);
176  2 verify(mockListener).taskCompleted(any(), argument.capture());
177  2 var alignmentResult = argument.getValue().getAlignment();
178  2 assertThat(alignmentResult, hasProperty("sequences", contains(
179    matchesSequenceString("ASTV-LITOPDCMMQEGGST----"),
180    matchesSequenceString("ASC-GLITO---MMQEGGST----"),
181    matchesSequenceString("ASTV-L--OPDTMMQE--L-----"))));
182    }
183   
 
184  26 toggle protected TaskEventListener<AlignmentResult> performAction(
185    AlignmentViewport viewport, AlignmentAction action)
186    throws IOException
187    {
188  26 TaskEventListener<AlignmentResult> listener = mock(TaskEventListener.class);
189  26 var latch = new CountDownLatch(1);
190  26 doAnswer(invocation -> {
191  26 latch.countDown();
192  26 return null;
193    })
194    .when(listener).taskCompleted(any(), any());
195  26 var executor = PollingTaskExecutor.fromPool(viewport.getServiceExecutor());
196  26 var task = action.createTask(viewport, List.of(), Credentials.empty());
197  26 task.addTaskEventListener(listener);
198  26 var cancellable = executor.submit(task);
199  26 try
200    {
201  26 latch.await(100, TimeUnit.MILLISECONDS);
202    } catch (InterruptedException e)
203    {
204  0 cancellable.cancel(true);
205    }
206  26 return listener;
207    }
208    }
209   
 
210    class AlignmentActionListenerNotifiedTest extends AlignmentActionTest
211    {
212    private AlignViewport viewport;
213   
 
214  22 toggle @BeforeMethod(alwaysRun = true)
215    public void setupViewport()
216    {
217  22 viewport = new AlignViewport(new Alignment(new SequenceI[] {
218    new Sequence("Seq 1", "----ASTVLITOPDCMMQEGGST-"),
219    new Sequence("Seq 2", "-ASCGLITO------MMQEGGST-"),
220    new Sequence("Seq 3", "AS--TVL--OPDTMMQEL------")
221    }));
222    }
223   
 
224  2 toggle @DataProvider
225    public JobStatus[] jobStatuses()
226    {
227    // CREATED, INVALID and READY should not be returned by the server
228  2 return new JobStatus[] {
229    JobStatus.SUBMITTED,
230    JobStatus.QUEUED,
231    JobStatus.RUNNING,
232    JobStatus.COMPLETED,
233    JobStatus.FAILED,
234    JobStatus.CANCELLED,
235    JobStatus.SERVER_ERROR,
236    JobStatus.UNKNOWN
237    };
238    }
239   
 
240  1 toggle @Test(groups = { "Functional" })
241    public void allJobsStarted_taskStartedCalled()
242    throws IOException
243    {
244  1 when(mockClient.getStatus(jobRef)).thenReturn(JobStatus.COMPLETED);
245  1 var mockListener = performAction(viewport, actionBuilder.build());
246  1 verify(mockListener).taskStarted(any(), anyList());
247    }
248   
 
249  1 toggle @Test(groups = { "Functional" })
250    public void allJobsStarted_taskStatusChangedCalledWithReadyThenSubmitted()
251    throws IOException
252    {
253  1 when(mockClient.getStatus(jobRef)).thenReturn(JobStatus.COMPLETED);
254  1 var mockListener = performAction(viewport, actionBuilder.build());
255  1 var inOrder = inOrder(mockListener);
256  1 inOrder.verify(mockListener).taskStatusChanged(any(), eq(JobStatus.READY));
257  1 inOrder.verify(mockListener).taskStatusChanged(any(), eq(JobStatus.SUBMITTED));
258    }
259   
 
260  8 toggle @Test(groups = { "Functional" }, dataProvider = "jobStatuses")
261    public void jobStatusChanged_taskStatusChangedCalledWithJobStatus(JobStatus status)
262    throws IOException
263    {
264  8 when(mockClient.getStatus(jobRef))
265    .thenReturn(status)
266    .thenReturn(JobStatus.COMPLETED);
267  8 var mockListener = performAction(viewport, actionBuilder.build());
268  8 verify(mockListener).taskStatusChanged(any(), eq(status));
269    }
270   
 
271  8 toggle @Test(groups = { "Functional" }, dataProvider = "jobStatuses")
272    public void jobStatusChanged_subJobStatusChangedCalledWithJobStatus(JobStatus status)
273    throws IOException
274    {
275  8 when(mockClient.getStatus(jobRef))
276    .thenReturn(status)
277    .thenReturn(JobStatus.COMPLETED);
278  8 var mockListener = performAction(viewport, actionBuilder.build());
279  8 verify(mockListener).subJobStatusChanged(any(), any(), eq(status));
280    }
281    }