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-----")
101 @Test(dataProvider = "multipleSequencesUnalignedAndAligned")
102 public void submitSequences_verifySequenceNamesUniquified(
103 Alignment unaligned, Alignment aligned)
106 var viewport = new AlignViewport(unaligned);
107 when(mockClient.getAlignment(jobRef)).thenReturn(aligned);
108 when(mockClient.getStatus(jobRef)).thenReturn(JobStatus.COMPLETED);
109 actionBuilder.submitGaps(false);
110 performAction(viewport, actionBuilder.build());
111 ArgumentCaptor<List<SequenceI>> argument = ArgumentCaptor.forClass(List.class);
112 verify(mockClient).submit(argument.capture(), eq(List.of()), eq(Credentials.empty()));
113 assertThat(argument.getValue(),
114 contains(hasProperty("name", is("Sequence0")),
115 hasProperty("name", is("Sequence1")),
116 hasProperty("name", is("Sequence2"))));
119 @Test(dataProvider = "multipleSequencesUnalignedAndAligned")
120 public void submitSequences_submitGapsOff_verifySequencesSubmittedWithoutGaps(Alignment unaligned, Alignment aligned)
123 var viewport = new AlignViewport(unaligned);
124 actionBuilder.submitGaps(false);
125 when(mockClient.getAlignment(jobRef)).thenReturn(aligned);
126 when(mockClient.getStatus(jobRef)).thenReturn(JobStatus.COMPLETED);
127 performAction(viewport, actionBuilder.build());
128 ArgumentCaptor<List<SequenceI>> argument = ArgumentCaptor.forClass(List.class);
129 verify(mockClient).submit(argument.capture(), eq(List.of()), eq(Credentials.empty()));
130 assertThat(argument.getValue(),
132 matchesSequence("ASTVLITOPDCMMQEGGST"),
133 matchesSequence("ASCGLITOMMQEGGST"),
134 matchesSequence("ASTVLOPDTMMQEL")));
137 @Test(dataProvider = "multipleSequencesUnalignedAndAligned")
138 public void submitSequences_submitGapsOn_verifySequencesSubmittedWithGaps(
139 Alignment unaligned, Alignment aligned)
142 var viewport = new AlignViewport(unaligned);
143 actionBuilder.submitGaps(true);
144 when(mockClient.getAlignment(jobRef)).thenReturn(aligned);
145 when(mockClient.getStatus(jobRef)).thenReturn(JobStatus.COMPLETED);
146 performAction(viewport, actionBuilder.build());
147 ArgumentCaptor<List<SequenceI>> argument = ArgumentCaptor.forClass(List.class);
148 verify(mockClient).submit(argument.capture(), eq(List.of()), eq(Credentials.empty()));
149 assertThat(argument.getValue(),
151 matchesSequence("----ASTVLITOPDCMMQEGGST-"),
152 matchesSequence("-ASCGLITO------MMQEGGST-"),
153 matchesSequence("AS--TVL--OPDTMMQEL------")));
156 @Test(dataProvider = "multipleSequencesUnalignedAndAligned")
157 public void retrieveResult_verifySequencesAligned(
158 Alignment unaligned, Alignment aligned)
161 var viewport = new AlignViewport(unaligned);
162 actionBuilder.submitGaps(false);
163 when(mockClient.getAlignment(jobRef)).thenReturn(aligned);
164 when(mockClient.getStatus(jobRef)).thenReturn(JobStatus.COMPLETED);
165 var mockListener = performAction(viewport, actionBuilder.build());
166 var argument = ArgumentCaptor.forClass(AlignmentResult.class);
167 verify(mockListener).taskCompleted(any(), argument.capture());
168 var alignmentResult = argument.getValue().getAlignment();
169 assertThat(alignmentResult, hasProperty("sequences", contains(
170 matchesSequence("ASTV-LITOPDCMMQEGGST----"),
171 matchesSequence("ASC-GLITO---MMQEGGST----"),
172 matchesSequence("ASTV-L--OPDTMMQE--L-----"))));
175 protected static Matcher<SequenceI> matchesSequence(String sequence)
177 return new TypeSafeMatcher<SequenceI>()
180 public boolean matchesSafely(SequenceI obj)
182 if (!(obj instanceof SequenceI))
184 var seq = (SequenceI) obj;
185 return seq.getSequenceAsString().equals(sequence);
189 public void describeTo(Description description)
191 description.appendText("a sequence ").appendValue(sequence);
195 public void describeMismatchSafely(SequenceI item, Description description)
197 description.appendText("was ").appendValue(item.getSequenceAsString());
202 protected TaskEventListener<AlignmentResult> performAction(
203 AlignmentViewport viewport, AlignmentAction action)
206 TaskEventListener<AlignmentResult> listener = mock(TaskEventListener.class);
207 var latch = new CountDownLatch(1);
208 doAnswer(invocation -> {
212 .when(listener).taskCompleted(any(), any());
213 action.perform(viewport, List.of(), Credentials.empty(), listener);
216 latch.await(100, TimeUnit.MILLISECONDS);
217 } catch (InterruptedException e)
224 class AlignmentActionListenerNotifiedTest extends AlignmentActionTest
226 private AlignViewport viewport;
229 public void setupViewport()
231 viewport = new AlignViewport(new Alignment(new SequenceI[] {
232 new Sequence("Seq 1", "----ASTVLITOPDCMMQEGGST-"),
233 new Sequence("Seq 2", "-ASCGLITO------MMQEGGST-"),
234 new Sequence("Seq 3", "AS--TVL--OPDTMMQEL------")
239 public JobStatus[] jobStatuses()
241 // CREATED, INVALID and READY should not be returned by the server
242 return new JobStatus[] {
249 JobStatus.SERVER_ERROR,
255 public void allJobsStarted_taskStartedCalled()
258 when(mockClient.getStatus(jobRef)).thenReturn(JobStatus.COMPLETED);
259 var mockListener = performAction(viewport, actionBuilder.build());
260 verify(mockListener).taskStarted(any(), anyList());
264 public void allJobsStarted_taskStatusChangedCalledWithReadyThenSubmitted()
267 when(mockClient.getStatus(jobRef)).thenReturn(JobStatus.COMPLETED);
268 var mockListener = performAction(viewport, actionBuilder.build());
269 var inOrder = inOrder(mockListener);
270 inOrder.verify(mockListener).taskStatusChanged(any(), eq(JobStatus.READY));
271 inOrder.verify(mockListener).taskStatusChanged(any(), eq(JobStatus.SUBMITTED));
274 @Test(dataProvider = "jobStatuses")
275 public void jobStatusChanged_taskStatusChangedCalledWithJobStatus(JobStatus status)
278 when(mockClient.getStatus(jobRef))
280 .thenReturn(JobStatus.COMPLETED);
281 var mockListener = performAction(viewport, actionBuilder.build());
282 verify(mockListener).taskStatusChanged(any(), eq(status));
285 @Test(dataProvider = "jobStatuses")
286 public void jobStatusChanged_subJobStatusChangedCalledWithJobStatus(JobStatus status)
289 when(mockClient.getStatus(jobRef))
291 .thenReturn(JobStatus.COMPLETED);
292 var mockListener = performAction(viewport, actionBuilder.build());
293 verify(mockListener).subJobStatusChanged(any(), any(), eq(status));