org.cruk.genologics.api.GenologicsAPIPaginatedBatchTest.java Source code

Java tutorial

Introduction

Here is the source code for org.cruk.genologics.api.GenologicsAPIPaginatedBatchTest.java

Source

/*
 * CRUK-CI Genologics REST API Java Client.
 * Copyright (C) 2013 Cancer Research UK Cambridge Institute.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.cruk.genologics.api;

import static org.junit.Assert.assertEquals;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Constructor;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.transform.stream.StreamSource;

import org.apache.commons.io.IOUtils;
import org.apache.http.Header;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpResponse;
import org.apache.http.ProtocolVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.entity.AbstractHttpEntity;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicHttpResponse;
import org.apache.http.message.BasicStatusLine;
import org.apache.http.protocol.HttpContext;
import org.cruk.genologics.api.debugging.RestClientSnoopingAspect;
import org.cruk.genologics.api.http.AuthenticatingClientHttpRequestFactory;
import org.cruk.genologics.api.impl.GenologicsAPIImpl;
import org.easymock.EasyMock;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpRequest;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import org.springframework.web.client.RestOperations;
import org.springframework.web.client.RestTemplate;

import com.genologics.ri.LimsLink;
import com.genologics.ri.sample.Sample;
import com.genologics.ri.sample.Samples;

public class GenologicsAPIPaginatedBatchTest {
    ConfigurableApplicationContext context;
    Jaxb2Marshaller marshaller;
    File[] pageFiles;
    ResponseEntity<Samples> response1, response2, response3;

    public GenologicsAPIPaginatedBatchTest() throws MalformedURLException {
        pageFiles = new File[] { new File("src/test/xml/multipagefetch-1.xml"),
                new File("src/test/xml/multipagefetch-2.xml"), new File("src/test/xml/multipagefetch-3.xml") };

        context = new ClassPathXmlApplicationContext("/org/cruk/genologics/api/genologics-client-context.xml");

        marshaller = context.getBean("genologicsJaxbMarshaller", Jaxb2Marshaller.class);

        Samples page1 = (Samples) marshaller.unmarshal(new StreamSource(pageFiles[0]));
        response1 = new ResponseEntity<Samples>(page1, HttpStatus.OK);
        Samples page2 = (Samples) marshaller.unmarshal(new StreamSource(pageFiles[1]));
        response2 = new ResponseEntity<Samples>(page2, HttpStatus.OK);
        Samples page3 = (Samples) marshaller.unmarshal(new StreamSource(pageFiles[2]));
        response3 = new ResponseEntity<Samples>(page3, HttpStatus.OK);
    }

    @Override
    protected void finalize() {
        context.close();
    }

    @Test
    public void testMultipageFetchFind() throws Exception {
        // Part one - mock the rest template to return the already parsed objects.

        RestOperations restMock = EasyMock.createStrictMock(RestOperations.class);

        EasyMock.expect(restMock.getForEntity("http://lims.cri.camres.org:8080/api/v2/samples?projectname=Run 1030",
                Samples.class)).andReturn(response1).once();
        EasyMock.expect(restMock.getForEntity(
                new URI("http://lims.cri.camres.org:8080/api/v2/samples?start-index=500&projectname=Run+1030"),
                Samples.class)).andReturn(response2).once();
        EasyMock.expect(restMock.getForEntity(
                new URI("http://lims.cri.camres.org:8080/api/v2/samples?start-index=1000&projectname=Run+1030"),
                Samples.class)).andReturn(response3).once();

        GenologicsAPIImpl localApi = context.getBean("genologicsAPI", GenologicsAPIImpl.class);
        localApi.setRestClient(restMock);
        localApi.setServer(new URL("http://lims.cri.camres.org:8080"));

        EasyMock.replay(restMock);

        Map<String, Object> terms = new HashMap<String, Object>();
        terms.put("projectname", "Run 1030");

        List<LimsLink<Sample>> links = localApi.find(terms, Sample.class);

        EasyMock.verify(restMock);

        assertEquals("Expected 1150 sample links returned", 1150, links.size());

        // Part two - mock the HTTP client and request factory to ensure that the URIs are
        // being presented as expected without character cludging.

        HttpContext httpContext = HttpClientContext.create();
        HttpClient mockHttpClient = EasyMock.createMock(HttpClient.class);
        AuthenticatingClientHttpRequestFactory mockRequestFactory = EasyMock
                .createMock(AuthenticatingClientHttpRequestFactory.class);

        RestTemplate restTemplate = context.getBean("genologicsRestTemplate", RestTemplate.class);
        restTemplate.setRequestFactory(mockRequestFactory);

        localApi.setHttpClient(mockHttpClient);
        localApi.setRestClient(restTemplate);

        URI pageOne = new URI("http://lims.cri.camres.org:8080/api/v2/samples?projectname=Run%201030");
        URI pageTwo = new URI(
                "http://lims.cri.camres.org:8080/api/v2/samples?start-index=500&projectname=Run+1030");
        URI pageThree = new URI(
                "http://lims.cri.camres.org:8080/api/v2/samples?start-index=1000&projectname=Run+1030");

        HttpGet getOne = new HttpGet(pageOne);
        HttpGet getTwo = new HttpGet(pageOne);
        HttpGet getThree = new HttpGet(pageOne);

        HttpResponse responseOne = createMultipageFetchResponse(pageFiles[0]);
        HttpResponse responseTwo = createMultipageFetchResponse(pageFiles[1]);
        HttpResponse responseThree = createMultipageFetchResponse(pageFiles[2]);

        Class<?> requestClass = Class.forName("org.springframework.http.client.HttpComponentsClientHttpRequest");
        Constructor<?> constructor = requestClass.getDeclaredConstructor(HttpClient.class, HttpUriRequest.class,
                HttpContext.class);
        constructor.setAccessible(true);

        ClientHttpRequest reqOne = (ClientHttpRequest) constructor.newInstance(mockHttpClient, getOne, httpContext);
        ClientHttpRequest reqTwo = (ClientHttpRequest) constructor.newInstance(mockHttpClient, getTwo, httpContext);
        ClientHttpRequest reqThree = (ClientHttpRequest) constructor.newInstance(mockHttpClient, getThree,
                httpContext);

        EasyMock.expect(mockRequestFactory.createRequest(pageOne, HttpMethod.GET)).andReturn(reqOne).once();
        EasyMock.expect(mockRequestFactory.createRequest(pageTwo, HttpMethod.GET)).andReturn(reqTwo).once();
        EasyMock.expect(mockRequestFactory.createRequest(pageThree, HttpMethod.GET)).andReturn(reqThree).once();

        EasyMock.expect(mockHttpClient.execute(getOne, httpContext)).andReturn(responseOne).once();
        EasyMock.expect(mockHttpClient.execute(getTwo, httpContext)).andReturn(responseTwo).once();
        EasyMock.expect(mockHttpClient.execute(getThree, httpContext)).andReturn(responseThree).once();

        EasyMock.replay(mockHttpClient, mockRequestFactory);

        links = localApi.find(terms, Sample.class);

        EasyMock.verify(mockHttpClient, mockRequestFactory);

        assertEquals("Expected 1150 sample links returned", 1150, links.size());
    }

    @Test
    public void testMultipageFetchListSome() throws Exception {
        // Note - reusing the files from above means that the subsequent pages
        // with have "&projectname=Run+1030" as part of the URL. This can be ignored
        // for this test.

        // Part one - mock the rest template to return the already parsed objects.

        RestOperations restMock = EasyMock.createStrictMock(RestOperations.class);

        EasyMock.expect(restMock.getForEntity("http://lims.cri.camres.org:8080/api/v2/samples?start-index=0",
                Samples.class)).andReturn(response1).once();
        EasyMock.expect(restMock.getForEntity(
                new URI("http://lims.cri.camres.org:8080/api/v2/samples?start-index=500&projectname=Run+1030"),
                Samples.class)).andReturn(response2).once();
        // Should get as far as response 3 in this test.

        GenologicsAPIImpl localApi = context.getBean("genologicsAPI", GenologicsAPIImpl.class);
        localApi.setRestClient(restMock);
        localApi.setServer(new URL("http://lims.cri.camres.org:8080"));

        EasyMock.replay(restMock);

        List<LimsLink<Sample>> links = localApi.listSome(Sample.class, 0, 750);

        EasyMock.verify(restMock);

        assertEquals("Expected 750 sample links returned", 750, links.size());

        // Part two - mock the HTTP client and request factory to ensure that the URIs are
        // being presented as expected without character cludging.

        HttpContext httpContext = HttpClientContext.create();
        HttpClient mockHttpClient = EasyMock.createMock(HttpClient.class);
        ClientHttpRequestFactory mockRequestFactory = EasyMock.createMock(ClientHttpRequestFactory.class);

        RestTemplate restTemplate = context.getBean("genologicsRestTemplate", RestTemplate.class);
        restTemplate.setRequestFactory(mockRequestFactory);

        localApi.setHttpClient(mockHttpClient);
        localApi.setRestClient(restTemplate);

        URI pageOne = new URI("http://lims.cri.camres.org:8080/api/v2/samples?start-index=0");
        URI pageTwo = new URI(
                "http://lims.cri.camres.org:8080/api/v2/samples?start-index=500&projectname=Run+1030");

        HttpGet getOne = new HttpGet(pageOne);
        HttpGet getTwo = new HttpGet(pageTwo);

        HttpResponse responseOne = createMultipageFetchResponse(pageFiles[0]);
        HttpResponse responseTwo = createMultipageFetchResponse(pageFiles[1]);

        Class<?> requestClass = Class.forName("org.springframework.http.client.HttpComponentsClientHttpRequest");
        Constructor<?> constructor = requestClass.getDeclaredConstructor(HttpClient.class, HttpUriRequest.class,
                HttpContext.class);
        constructor.setAccessible(true);

        ClientHttpRequest reqOne = (ClientHttpRequest) constructor.newInstance(mockHttpClient, getOne, httpContext);
        ClientHttpRequest reqTwo = (ClientHttpRequest) constructor.newInstance(mockHttpClient, getTwo, httpContext);

        EasyMock.expect(mockRequestFactory.createRequest(pageOne, HttpMethod.GET)).andReturn(reqOne).once();
        EasyMock.expect(mockRequestFactory.createRequest(pageTwo, HttpMethod.GET)).andReturn(reqTwo).once();

        EasyMock.expect(mockHttpClient.execute(getOne, httpContext)).andReturn(responseOne).once();
        EasyMock.expect(mockHttpClient.execute(getTwo, httpContext)).andReturn(responseTwo).once();

        EasyMock.replay(mockHttpClient, mockRequestFactory);

        links = localApi.listSome(Sample.class, 0, 750);

        EasyMock.verify(mockHttpClient, mockRequestFactory);

        assertEquals("Expected 750 sample links returned", 750, links.size());
    }

    private HttpResponse createMultipageFetchResponse(File responseFile) {
        HttpResponse response = new BasicHttpResponse(
                new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
        response.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_XML_VALUE);
        response.setEntity(new HttpEntityForMultipageFetch(responseFile));
        return response;
    }

    private static class HttpEntityForMultipageFetch extends AbstractHttpEntity {
        private Logger logger = LoggerFactory.getLogger(RestClientSnoopingAspect.class);

        private File responseFile;

        public HttpEntityForMultipageFetch(File responseFile) {
            this.responseFile = responseFile;
        }

        @Override
        public InputStream getContent() throws IOException {
            logger.info("Returning body from file, NOT from the live API");
            return new BufferedInputStream(new FileInputStream(responseFile));
        }

        @Override
        public Header getContentType() {
            return new BasicHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_XML_VALUE);
        }

        @Override
        public boolean isRepeatable() {
            return false;
        }

        @Override
        public long getContentLength() {
            return responseFile.length();
        }

        @Override
        public void writeTo(OutputStream outstream) throws IOException {
            IOUtils.copyLarge(getContent(), outstream);
        }

        @Override
        public boolean isStreaming() {
            return false;
        }
    }
}