package org.ga4gh.cts.api.reads; import com.google.protobuf.InvalidProtocolBufferException; import com.mashape.unirest.http.exceptions.UnirestException; import org.ga4gh.ctk.CtkLogs; import org.ga4gh.ctk.transport.GAWrapperException; import org.ga4gh.ctk.transport.URLMAPPING; import org.ga4gh.ctk.transport.protocols.Client; import org.ga4gh.cts.api.TestData; import org.ga4gh.cts.api.Utils; import ga4gh.ReadServiceOuterClass.*; import ga4gh.Reads.*; import org.junit.Test; import org.junit.experimental.categories.Category; import java.net.HttpURLConnection; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; import java.util.stream.IntStream; import static org.assertj.core.api.Assertions.assertThat; import static org.ga4gh.cts.api.Utils.aSingle; import static org.ga4gh.cts.api.Utils.catchGAWrapperException; import static org.ga4gh.cts.api.Utils.getReadGroupId; /** * Verify that data returned from <tt>/reads/search</tt> queries meets expectations. */ @Category(ReadsTests.class) public class ReadsSearchIT implements CtkLogs { private static Client client = new Client(URLMAPPING.getInstance()); /** * Call <tt>/reads/search</tt> with a range that contains zero reads, and verify that it returns none. * (Adapted from an old JavaScript test.) * * @throws GAWrapperException if the server finds the request invalid in some way * @throws UnirestException if there's a problem speaking HTTP to the server * @throws InvalidProtocolBufferException if there's a problem processing the JSON response from the server */ @Test public void searchRangeWithNoReadsReturnsZeroResults() throws InvalidProtocolBufferException, UnirestException, GAWrapperException { final String refId = Utils.getValidReferenceId(client); final long emptyRangeStart = 0; // is this range actually empty? final long emptyRangeEnd = 100; final SearchReadsRequest srReq = SearchReadsRequest.newBuilder() .setReferenceId(refId) .addAllReadGroupIds(aSingle(getReadGroupId(client))) .setStart(emptyRangeStart) .setEnd(emptyRangeEnd) .build(); final SearchReadsResponse srResp = client.reads.searchReads(srReq); final List<ReadAlignment> alignments = srResp.getAlignmentsList(); assertThat(alignments).isEmpty(); } /** * Call <tt>/reads/search</tt> with a range that contains multiple reads, and verify * they are well-formed. * (Adapted from an old JavaScript test.) * * @throws GAWrapperException if the server finds the request invalid in some way * @throws UnirestException if there's a problem speaking HTTP to the server * @throws InvalidProtocolBufferException if there's a problem processing the JSON response from the server */ @Test public void searchReadsProducesWellFormedReads() throws InvalidProtocolBufferException, UnirestException, GAWrapperException { // first get a valid reference final String refId = Utils.getValidReferenceId(client); final long start = 150; final long end = 160; final SearchReadsRequest srReq = SearchReadsRequest.newBuilder() .setReferenceId(refId) .addAllReadGroupIds(aSingle(getReadGroupId(client))) .setStart(start) .setEnd(end) .build(); final SearchReadsResponse srResp = client.reads.searchReads(srReq); final List<ReadAlignment> alignments = srResp.getAlignmentsList(); alignments.stream().forEach(read -> assertThat(read.getNextMatePosition()).isNotNull()); alignments.stream() .forEach(read -> assertThat(read.getNextMatePosition() .getReferenceName()).isEqualTo(TestData.REFERENCE_NAME)); alignments.stream().forEach(read -> assertThat(read.getAlignment()).isNotNull()); alignments.stream().forEach(read -> assertThat(read.getAlignment().getCigarList()).isNotNull()); } /** * Fetch every {@link ReadGroupSet} named in {@link TestData#EXPECTED_READGROUP_NAMES} using * <tt>searchReadGroupSets</tt> and verify that it returns the expected {@link ReadGroupSet}. * * @throws GAWrapperException if the server finds the request invalid in some way * @throws UnirestException if there's a problem speaking HTTP to the server * @throws InvalidProtocolBufferException if there's a problem processing the JSON response from the server */ @Test public void searchReadGroupSetsMustReturnReadGroupSetsWithExpectedNames() throws InvalidProtocolBufferException, UnirestException, GAWrapperException { for (String expectedReadGroupSetName : TestData.EXPECTED_READGROUPSETS_NAMES) { final SearchReadGroupSetsRequest req = SearchReadGroupSetsRequest.newBuilder() .setDatasetId(TestData.getDatasetId()) .setName(expectedReadGroupSetName) .build(); final SearchReadGroupSetsResponse resp = client.reads.searchReadGroupSets(req); final List<ReadGroupSet> readGroupSets = resp.getReadGroupSetsList(); assertThat(readGroupSets).hasSize(1); final ReadGroupSet readGroupSet = readGroupSets.get(0); assertThat(readGroupSet.getName()).isEqualTo(expectedReadGroupSetName); assertThat(readGroupSet.getDatasetId()).isEqualTo(TestData.getDatasetId()); } } /** * Verify that passing zero read group names in a {@link SearchReadsRequest} fails. * * @throws Exception if there's a problem we didn't catch */ @SuppressWarnings("ThrowableResultOfMethodCallIgnored") @Test public void searchReadsWithNoIdsFails() throws Exception { // first get a valid reference final String refId = Utils.getValidReferenceId(client); final SearchReadsRequest request = SearchReadsRequest.newBuilder() .addAllReadGroupIds(Collections.emptyList()) .setStart(0L) .setEnd(150L) .setReferenceId(refId) .build(); final GAWrapperException t = catchGAWrapperException(() -> client.reads.searchReads(request)); assertThat(t.getHttpStatusCode()).isEqualTo(HttpURLConnection.HTTP_BAD_REQUEST); } /** * Verify that passing one read group name in a {@link SearchReadsRequest} * returns valid reads. * * @throws GAWrapperException if the server finds the request invalid in some way * @throws UnirestException if there's a problem speaking HTTP to the server * @throws InvalidProtocolBufferException if there's a problem processing the JSON response from the server */ @Test public void searchReadsWithOneReadGroupIdSucceeds() throws InvalidProtocolBufferException, UnirestException, GAWrapperException { // first get a valid reference final String refId = Utils.getValidReferenceId(client); // get a ReadGroup id final String readGroupId = getReadGroupId(client); final SearchReadsRequest request = SearchReadsRequest.newBuilder() .addAllReadGroupIds(aSingle(readGroupId)) .setStart(0L) .setEnd(150L) .setReferenceId(refId) .build(); final SearchReadsResponse response = client.reads.searchReads(request); assertThat(response.getAlignmentsList()).isNotNull(); response.getAlignmentsList().stream() .forEach(readAlignment -> assertThat(readAlignment.getAlignedSequence()).isNotNull() .matches(TestData.ALIGNED_SEQUENCE_CONTENTS_PATTERN)); } /** * Verify that passing all known read group names in a {@link SearchReadsRequest} * returns all matching read groups. * * @throws GAWrapperException if the server finds the request invalid in some way * @throws UnirestException if there's a problem speaking HTTP to the server * @throws InvalidProtocolBufferException if there's a problem processing the JSON response from the server */ @Test public void searchReadsWithAllIdsReturnsReadsForEach() throws InvalidProtocolBufferException, UnirestException, GAWrapperException { // first get a valid reference final String refId = Utils.getValidReferenceId(client); // get all ReadGroupSets final List<ReadGroupSet> allReadGroupSets = Utils.getAllReadGroupSets(client); // collect all IDs from the ReadGroups final List<String> allReadGroupIds = allReadGroupSets.stream() .flatMap(readGroupSet -> readGroupSet.getReadGroupsList() .stream()) .map(ReadGroup::getId) .collect(Collectors.toList()); final SearchReadsRequest request = SearchReadsRequest.newBuilder() .addAllReadGroupIds(allReadGroupIds) .setStart(0L) .setEnd(150L) .setReferenceId(refId) .build(); final SearchReadsResponse response = client.reads.searchReads(request); assertThat(response.getAlignmentsList()).isNotNull(); response.getAlignmentsList().stream() .forEach(readAlignment -> assertThat(readAlignment.getAlignedSequence()).isNotNull() .matches(TestData.ALIGNED_SEQUENCE_CONTENTS_PATTERN)); } /** * <p>Verify aligned sequences contain only the permitted symbols.</p> * <p>In any {@link ReadAlignment} in our compliance test data, * the <tt>alignedSequence</tt> field can only contain * {@link TestData#ALIGNED_SEQUENCE_CONTENTS_PATTERN}. * * @throws GAWrapperException if the server finds the request invalid in some way * @throws UnirestException if there's a problem speaking HTTP to the server * @throws InvalidProtocolBufferException if there's a problem processing the JSON response from the server */ @Test public void readsResponseMatchesACTGNPattern() throws InvalidProtocolBufferException, UnirestException, GAWrapperException { final String refId = Utils.getValidReferenceId(client); for (String readGroupSetName : TestData.EXPECTED_READGROUPSETS_NAMES) { for (String readGroupName : TestData.EXPECTED_READGROUPSET_READGROUP_NAMES.get(readGroupSetName)) { final String readGroupId = Utils.getReadGroupIdForName(client, readGroupSetName, readGroupName); final SearchReadsRequest request = SearchReadsRequest.newBuilder() .addAllReadGroupIds(aSingle(readGroupId)) .setReferenceId(refId) .setStart(0L) .setEnd(150L) .build(); final SearchReadsResponse response = client.reads.searchReads(request); assertThat(response.getAlignmentsList()).isNotNull(); response.getAlignmentsList().stream() .forEach(readAlignment -> assertThat(readAlignment.getAlignedSequence()).isNotNull() .matches(TestData.ALIGNED_SEQUENCE_CONTENTS_PATTERN)); } } } /** * Verifies that a request for all the readGroupIds in a Read Group Set * returns only alignments with those readgroupIds. * * @throws Exception if there's a problem */ @Test public void testSearchReadsMultipleReadGroupsInReadGroupSet() throws Exception { final String referenceId = Utils.getValidReferenceId(client); final List<ReadGroupSet> allReadGroupSets = Utils.getAllReadGroupSets(client); final ReadGroupSet readGroupSet = allReadGroupSets.get(0); final List<ReadGroup> readGroups = readGroupSet.getReadGroupsList(); final List<String> readGroupIds = readGroups .stream() .map(readGroup -> readGroup.getId()) .collect(Collectors.toList()); SearchReadsRequest.Builder builder = SearchReadsRequest.newBuilder(); IntStream.range(0, readGroupIds.size()).forEach(index -> builder.addReadGroupIds(readGroupIds.get(index))); final SearchReadsRequest request = builder .setStart(0L) .setEnd(150L) .setReferenceId(referenceId) .build(); final SearchReadsResponse response = client.reads.searchReads(request); assertThat(response.getAlignmentsList()).isNotNull(); for (ReadAlignment readAlignment : response.getAlignmentsList()) { final String readGroupId = readAlignment.getReadGroupId(); assertThat(readGroupId).isIn(readGroupIds); assertThat(readAlignment.getAlignedSequence()).isNotNull() .matches(TestData.ALIGNED_SEQUENCE_CONTENTS_PATTERN); } } }