1 package jalview.ws2.actions.alignment;
3 import java.io.IOException;
6 import java.util.concurrent.CountDownLatch;
7 import java.util.concurrent.TimeUnit;
9 import javax.help.UnsupportedOperationException;
11 import org.hamcrest.BaseMatcher;
12 import org.hamcrest.Description;
13 import org.hamcrest.Matcher;
14 import org.hamcrest.TypeSafeMatcher;
15 import org.mockito.ArgumentCaptor;
16 import org.testng.annotations.BeforeMethod;
17 import org.testng.annotations.DataProvider;
18 import org.testng.annotations.Test;
20 import jalview.datamodel.Alignment;
21 import jalview.datamodel.AlignmentI;
22 import jalview.datamodel.Sequence;
23 import jalview.datamodel.SequenceI;
24 import jalview.gui.AlignViewport;
25 import jalview.viewmodel.AlignmentViewport;
26 import jalview.ws.params.ParamDatastoreI;
27 import jalview.ws2.actions.api.JobI;
28 import jalview.ws2.actions.api.TaskEventListener;
29 import jalview.ws2.api.Credentials;
30 import jalview.ws2.api.JobStatus;
31 import jalview.ws2.api.WebService;
32 import jalview.ws2.api.WebServiceJobHandle;
33 import jalview.ws2.client.api.AlignmentWebServiceClientI;
35 import org.mockito.hamcrest.MockitoHamcrest;
36 import org.mockito.internal.hamcrest.HamcrestArgumentMatcher;
38 import static org.mockito.Mockito.*;
39 import static org.hamcrest.MatcherAssert.assertThat;
40 import static org.hamcrest.Matchers.*;
42 public class AlignmentActionTest
44 protected AlignmentWebServiceClientI mockClient;
46 protected AlignmentAction.Builder actionBuilder;
48 protected WebServiceJobHandle jobRef;
51 public void setupMockClient() throws IOException
53 jobRef = new WebServiceJobHandle(
54 "mock", "mock", "http://example.org", "00000001");
55 mockClient = mock(AlignmentWebServiceClientI.class);
56 when(mockClient.getUrl()).thenReturn("http://example.org");
57 when(mockClient.getClientName()).thenReturn("mock");
58 when(mockClient.submit(anyList(), anyList(), any())).thenReturn(jobRef);
59 when(mockClient.getLog(jobRef)).thenReturn("");
60 when(mockClient.getErrorLog(jobRef)).thenReturn("");
61 doThrow(new UnsupportedOperationException()).when(mockClient).cancel(any());
64 @BeforeMethod(dependsOnMethods = { "setupMockClient" })
65 public void setupActionBuilder() throws IOException
67 actionBuilder = AlignmentAction.newBuilder(mockClient);
68 actionBuilder.name("mock");
69 actionBuilder.webService(
70 WebService.<AlignmentAction> newBuilder()
71 .url(new URL("http://example.org"))
73 .category("Alignment")
75 .paramDatastore(mock(ParamDatastoreI.class))
76 .actionClass(AlignmentAction.class)
81 public Object[][] multipleSequencesUnalignedAndAligned()
83 return new Object[][] {
85 new Alignment(new SequenceI[]
87 new Sequence("Seq 1", "----ASTVLITOPDCMMQEGGST-"),
88 new Sequence("Seq 2", "-ASCGLITO------MMQEGGST-"),
89 new Sequence("Seq 3", "AS--TVL--OPDTMMQEL------")
91 new Alignment(new SequenceI[]
93 new Sequence("Sequence0", "ASTV-LITOPDCMMQEGGST----"),
94 new Sequence("Sequence1", "ASC-GLITO---MMQEGGST----"),
95 new Sequence("Sequence2", "ASTV-L--OPDTMMQE--L-----")
102 groups = { "Functional" },
103 dataProvider = "multipleSequencesUnalignedAndAligned")
104 public void submitSequences_verifySequenceNamesUniquified(
105 Alignment unaligned, Alignment aligned)
108 var viewport = new AlignViewport(unaligned);
109 when(mockClient.getAlignment(jobRef)).thenReturn(aligned);
110 when(mockClient.getStatus(jobRef)).thenReturn(JobStatus.COMPLETED);
111 actionBuilder.submitGaps(false);
112 performAction(viewport, actionBuilder.build());
113 ArgumentCaptor<List<SequenceI>> argument = ArgumentCaptor.forClass(List.class);
114 verify(mockClient).submit(argument.capture(), eq(List.of()), eq(Credentials.empty()));
115 assertThat(argument.getValue(),
116 contains(hasProperty("name", is("Sequence0")),
117 hasProperty("name", is("Sequence1")),
118 hasProperty("name", is("Sequence2"))));
122 groups = { "Functional" },
123 dataProvider = "multipleSequencesUnalignedAndAligned")
124 public void submitSequences_submitGapsOff_verifySequencesSubmittedWithoutGaps(Alignment unaligned, Alignment aligned)
127 var viewport = new AlignViewport(unaligned);
128 actionBuilder.submitGaps(false);
129 when(mockClient.getAlignment(jobRef)).thenReturn(aligned);
130 when(mockClient.getStatus(jobRef)).thenReturn(JobStatus.COMPLETED);
131 performAction(viewport, actionBuilder.build());
132 ArgumentCaptor<List<SequenceI>> argument = ArgumentCaptor.forClass(List.class);
133 verify(mockClient).submit(argument.capture(), eq(List.of()), eq(Credentials.empty()));
134 assertThat(argument.getValue(),
136 matchesSequence("ASTVLITOPDCMMQEGGST"),
137 matchesSequence("ASCGLITOMMQEGGST"),
138 matchesSequence("ASTVLOPDTMMQEL")));
142 groups = { "Functional" },
143 dataProvider = "multipleSequencesUnalignedAndAligned")
144 public void submitSequences_submitGapsOn_verifySequencesSubmittedWithGaps(
145 Alignment unaligned, Alignment aligned)
148 var viewport = new AlignViewport(unaligned);
149 actionBuilder.submitGaps(true);
150 when(mockClient.getAlignment(jobRef)).thenReturn(aligned);
151 when(mockClient.getStatus(jobRef)).thenReturn(JobStatus.COMPLETED);
152 performAction(viewport, actionBuilder.build());
153 ArgumentCaptor<List<SequenceI>> argument = ArgumentCaptor.forClass(List.class);
154 verify(mockClient).submit(argument.capture(), eq(List.of()), eq(Credentials.empty()));
155 assertThat(argument.getValue(),
157 matchesSequence("----ASTVLITOPDCMMQEGGST-"),
158 matchesSequence("-ASCGLITO------MMQEGGST-"),
159 matchesSequence("AS--TVL--OPDTMMQEL------")));
163 groups = { "Functional" },
164 dataProvider = "multipleSequencesUnalignedAndAligned")
165 public void retrieveResult_verifySequencesAligned(
166 Alignment unaligned, Alignment aligned)
169 var viewport = new AlignViewport(unaligned);
170 actionBuilder.submitGaps(false);
171 when(mockClient.getAlignment(jobRef)).thenReturn(aligned);
172 when(mockClient.getStatus(jobRef)).thenReturn(JobStatus.COMPLETED);
173 var mockListener = performAction(viewport, actionBuilder.build());
174 var argument = ArgumentCaptor.forClass(AlignmentResult.class);
175 verify(mockListener).taskCompleted(any(), argument.capture());
176 var alignmentResult = argument.getValue().getAlignment();
177 assertThat(alignmentResult, hasProperty("sequences", contains(
178 matchesSequence("ASTV-LITOPDCMMQEGGST----"),
179 matchesSequence("ASC-GLITO---MMQEGGST----"),
180 matchesSequence("ASTV-L--OPDTMMQE--L-----"))));
183 protected static Matcher<SequenceI> matchesSequence(String sequence)
185 return new TypeSafeMatcher<SequenceI>()
188 public boolean matchesSafely(SequenceI obj)
190 if (!(obj instanceof SequenceI))
192 var seq = (SequenceI) obj;
193 return seq.getSequenceAsString().equals(sequence);
197 public void describeTo(Description description)
199 description.appendText("a sequence ").appendValue(sequence);
203 public void describeMismatchSafely(SequenceI item, Description description)
205 description.appendText("was ").appendValue(item.getSequenceAsString());
210 protected TaskEventListener<AlignmentResult> performAction(
211 AlignmentViewport viewport, AlignmentAction action)
214 TaskEventListener<AlignmentResult> listener = mock(TaskEventListener.class);
215 var latch = new CountDownLatch(1);
216 doAnswer(invocation -> {
220 .when(listener).taskCompleted(any(), any());
221 action.perform(viewport, List.of(), Credentials.empty(), listener);
224 latch.await(100, TimeUnit.MILLISECONDS);
225 } catch (InterruptedException e)
232 class AlignmentActionListenerNotifiedTest extends AlignmentActionTest
234 private AlignViewport viewport;
237 public void setupViewport()
239 viewport = new AlignViewport(new Alignment(new SequenceI[] {
240 new Sequence("Seq 1", "----ASTVLITOPDCMMQEGGST-"),
241 new Sequence("Seq 2", "-ASCGLITO------MMQEGGST-"),
242 new Sequence("Seq 3", "AS--TVL--OPDTMMQEL------")
247 public JobStatus[] jobStatuses()
249 // CREATED, INVALID and READY should not be returned by the server
250 return new JobStatus[] {
257 JobStatus.SERVER_ERROR,
262 @Test(groups = { "Functional" })
263 public void allJobsStarted_taskStartedCalled()
266 when(mockClient.getStatus(jobRef)).thenReturn(JobStatus.COMPLETED);
267 var mockListener = performAction(viewport, actionBuilder.build());
268 verify(mockListener).taskStarted(any(), anyList());
271 @Test(groups = { "Functional" })
272 public void allJobsStarted_taskStatusChangedCalledWithReadyThenSubmitted()
275 when(mockClient.getStatus(jobRef)).thenReturn(JobStatus.COMPLETED);
276 var mockListener = performAction(viewport, actionBuilder.build());
277 var inOrder = inOrder(mockListener);
278 inOrder.verify(mockListener).taskStatusChanged(any(), eq(JobStatus.READY));
279 inOrder.verify(mockListener).taskStatusChanged(any(), eq(JobStatus.SUBMITTED));
282 @Test(groups = { "Functional" }, dataProvider = "jobStatuses")
283 public void jobStatusChanged_taskStatusChangedCalledWithJobStatus(JobStatus status)
286 when(mockClient.getStatus(jobRef))
288 .thenReturn(JobStatus.COMPLETED);
289 var mockListener = performAction(viewport, actionBuilder.build());
290 verify(mockListener).taskStatusChanged(any(), eq(status));
293 @Test(groups = { "Functional" }, dataProvider = "jobStatuses")
294 public void jobStatusChanged_subJobStatusChangedCalledWithJobStatus(JobStatus status)
297 when(mockClient.getStatus(jobRef))
299 .thenReturn(JobStatus.COMPLETED);
300 var mockListener = performAction(viewport, actionBuilder.build());
301 verify(mockListener).subJobStatusChanged(any(), any(), eq(status));