org.dspace.app.rest.utils.MultipartFileSenderTest.java Source code

Java tutorial

Introduction

Here is the source code for org.dspace.app.rest.utils.MultipartFileSenderTest.java

Source

/**
 * The contents of this file are subject to the license and copyright
 * detailed in the LICENSE and NOTICE files at the root of the source
 * tree and available online at
 *
 * http://www.dspace.org/license/
 */
package org.dspace.app.rest.utils;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.CharEncoding;
import org.apache.log4j.Logger;
import org.dspace.authorize.AuthorizeException;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;

/**
 * Test class for MultipartFileSender
 *
 * @author Tom Desair (tom dot desair at atmire dot com)
 * @author Frederic Van Reet (frederic dot vanreet at atmire dot com)
 */
public class MultipartFileSenderTest {

    /**
     * log4j category
     */
    private static final Logger log = Logger.getLogger(MultipartFileSenderTest.class);

    private InputStream is;
    private String mimeType;
    private long lastModified;
    private long length;
    private String fileName;
    private String checksum;

    private HttpServletRequest request;

    private HttpServletResponse response;

    private ContentCachingRequestWrapper requestWrapper;
    private ContentCachingResponseWrapper responseWrapper;

    /**
     * This method will be run before every test as per @Before. It will
     * initialize resources required for the tests.
     * <p>
     * Other methods can be annotated with @Before here or in subclasses
     * but no execution order is guaranteed
     */
    @Before
    public void init() throws AuthorizeException {
        try {
            String content = "0123456789";

            this.is = IOUtils.toInputStream(content, CharEncoding.UTF_8);
            this.fileName = "Test-Item.txt";
            this.mimeType = "text/plain";
            this.lastModified = new Date().getTime();
            this.length = content.getBytes().length;
            this.checksum = "testsum";

            this.request = mock(HttpServletRequest.class);
            this.response = new MockHttpServletResponse();

            //Using wrappers so we can save the content of the bodies and use them for tests
            this.requestWrapper = new ContentCachingRequestWrapper(request);
            this.responseWrapper = new ContentCachingResponseWrapper(response);
        } catch (IOException ex) {
            log.error("IO Error in init", ex);
            fail("SQL Error in init: " + ex.getMessage());
        }
    }

    /**
     * This method will be run after every test as per @After. It will
     * clean resources initialized by the @Before methods.
     * <p>
     * Other methods can be annotated with @After here or in subclasses
     * but no execution order is guaranteed
     */
    @After
    public void destroy() {
        try {
            is.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * Test if Range header is supported and gives back the right range
     *
     * @throws Exception
     */
    @Test
    public void testRangeHeader() throws Exception {
        MultipartFileSender multipartFileSender = MultipartFileSender.fromInputStream(is).with(requestWrapper)
                .with(responseWrapper).withFileName(fileName).withChecksum(checksum).withMimetype(mimeType)
                .withLength(length);

        when(request.getHeader(eq("If-Range"))).thenReturn("not_file_to_serve.txt");
        when(request.getHeader(eq("Range"))).thenReturn("bytes=1-3");

        multipartFileSender.serveResource();

        String content = new String(responseWrapper.getContentAsByteArray(), CharEncoding.UTF_8);

        assertEquals("123", content);
    }

    /**
     * Test if we can just request the full file without ranges
     *
     * @throws Exception
     */
    @Test
    public void testFullFileReturn() throws Exception {
        MultipartFileSender multipartFileSender = MultipartFileSender.fromInputStream(is).with(requestWrapper)
                .with(responseWrapper).withFileName(fileName).withChecksum(checksum).withMimetype(mimeType)
                .withLength(length);

        multipartFileSender.serveResource();

        String content = new String(responseWrapper.getContentAsByteArray(), CharEncoding.UTF_8);

        assertEquals("0123456789", content);
        assertEquals(checksum, responseWrapper.getHeader("ETag"));
    }

    /**
     * Test for support of Open ranges
     *
     * @throws Exception
     */
    @Test
    public void testOpenRange() throws Exception {
        MultipartFileSender multipartFileSender = MultipartFileSender.fromInputStream(is).with(requestWrapper)
                .with(responseWrapper).withFileName(fileName).withChecksum(checksum).withMimetype(mimeType)
                .withLength(length);

        when(request.getHeader(eq("Range"))).thenReturn("bytes=5-");

        multipartFileSender.serveResource();

        String content = new String(responseWrapper.getContentAsByteArray(), CharEncoding.UTF_8);

        assertEquals("56789", content);
    }

    /**
     * Test support for multiple ranges
     *
     * @throws Exception
     */
    @Test
    public void testMultipleRanges() throws Exception {
        MultipartFileSender multipartFileSender = MultipartFileSender.fromInputStream(is).with(requestWrapper)
                .with(responseWrapper).withFileName(fileName).withChecksum(checksum).withMimetype(mimeType)
                .withLength(length);

        when(request.getHeader(eq("Range"))).thenReturn("bytes=1-2,3-4,5-9");

        multipartFileSender.serveResource();

        String content = new String(responseWrapper.getContentAsByteArray(), CharEncoding.UTF_8);

        assertEquals("--MULTIPART_BYTERANGES" + "Content-Type: text/plain" + "Content-Range: bytes 1-2/10" + "12"
                + "--MULTIPART_BYTERANGES" + "Content-Type: text/plain" + "Content-Range: bytes 3-4/10" + "34"
                + "--MULTIPART_BYTERANGES" + "Content-Type: text/plain" + "Content-Range: bytes 5-9/10" + "56789"
                + "--MULTIPART_BYTERANGES--".replace("\n", "").replace("\r", ""),
                content.replace("\n", "").replace("\r", ""));

    }

    /**
     * Test with a unvalid Range header, should return status 416
     *
     * @throws Exception
     */
    @Test
    public void testInvalidRange() throws Exception {
        MultipartFileSender multipartFileSender = MultipartFileSender.fromInputStream(is).with(requestWrapper)
                .with(responseWrapper).withFileName(fileName).withChecksum(checksum).withMimetype(mimeType)
                .withLength(length);

        when(request.getHeader(eq("Range"))).thenReturn("bytes=invalid");

        multipartFileSender.serveResource();

        assertEquals(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE, responseWrapper.getStatusCode());
    }

    /**
     * Test if the ETAG is in the response header
     *
     * @throws Exception
     */
    @Test
    public void testEtagInResponse() throws Exception {
        MultipartFileSender multipartFileSender = MultipartFileSender.fromInputStream(is).with(requestWrapper)
                .with(responseWrapper).withFileName(fileName).withChecksum(checksum).withMimetype(mimeType)
                .withLength(length);

        when(request.getHeader(eq("Range"))).thenReturn("bytes=1-3");

        multipartFileSender.serveResource();

        String etag = responseWrapper.getHeader("Etag");

        assertEquals(checksum, etag);
    }

    //Check that a head request doesn't return any body, but returns the headers
    @Test
    public void testHeadRequest() throws Exception {
        MultipartFileSender multipartFileSender = MultipartFileSender.fromInputStream(is).with(requestWrapper)
                .with(responseWrapper).withFileName(fileName).withChecksum(checksum).withMimetype(mimeType)
                .withLength(length);

        when(request.getMethod()).thenReturn("HEAD");

        multipartFileSender.serveResource();

        String content = new String(responseWrapper.getContentAsByteArray(), CharEncoding.UTF_8);

        assertEquals("bytes", responseWrapper.getHeader("Accept-Ranges"));
        assertEquals(checksum, responseWrapper.getHeader("ETag"));
        assertEquals("", content);
        assertEquals(200, responseWrapper.getStatusCode());

    }

    /**
     * If ETAG is equal to that of the requested Resource then this should return 304
     *
     * @throws Exception
     */
    @Test
    public void testIfNoneMatchFail() throws Exception {
        MultipartFileSender multipartFileSender = MultipartFileSender.fromInputStream(is).with(requestWrapper)
                .with(responseWrapper).withFileName(fileName).withChecksum(checksum).withMimetype(mimeType)
                .withLength(length);

        when(request.getHeader(eq("If-None-Match"))).thenReturn(checksum);

        multipartFileSender.isValid();

        assertEquals(HttpServletResponse.SC_NOT_MODIFIED, responseWrapper.getStatusCode());
    }

    /**
     * Happy path of If-None-Match header
     *
     * @throws Exception
     */
    @Test
    public void testIfNoneMatchPass() throws Exception {
        MultipartFileSender multipartFileSender = MultipartFileSender.fromInputStream(is).with(requestWrapper)
                .with(responseWrapper).withFileName(fileName).withChecksum(checksum).withMimetype(mimeType)
                .withLength(length);

        when(request.getHeader(eq("If-None-Match")))
                .thenReturn("pretendthisisarandomchecksumnotequaltotherequestedbitstream");

        multipartFileSender.isValid();
        multipartFileSender.serveResource();

        assertEquals(HttpServletResponse.SC_OK, responseWrapper.getStatusCode());
    }

    /**
     * If the bitstream has no filename this should throw an internal server error
     *
     * @throws Exception
     */
    @Test
    public void testNoFileName() throws Exception {
        MultipartFileSender multipartFileSender = MultipartFileSender.fromInputStream(is).with(requestWrapper)
                .with(responseWrapper).withChecksum(checksum).withMimetype(mimeType).withLength(length);

        multipartFileSender.isValid();

        assertEquals(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, responseWrapper.getStatusCode());
    }

    /**
     * Test if the Modified Since precondition works, should return 304 if it hasn't been modified
     *
     * @throws Exception
     */
    @Test
    public void testIfModifiedSinceNotModifiedSince() throws Exception {
        Long time = new Date().getTime();
        MultipartFileSender multipartFileSender = MultipartFileSender.fromInputStream(is).with(requestWrapper)
                .withFileName(fileName).with(responseWrapper).withChecksum(checksum).withMimetype(mimeType)
                .withLength(length).withLastModified(time);

        when(request.getDateHeader(eq("If-Modified-Since"))).thenReturn(time + 100000);
        when(request.getDateHeader(eq("If-Unmodified-Since"))).thenReturn(-1L);

        multipartFileSender.isValid();

        assertEquals(HttpServletResponse.SC_NOT_MODIFIED, responseWrapper.getStatusCode());

    }

    /**
     * Happy path for modified since
     *
     * @throws Exception
     */
    @Test
    public void testIfModifiedSinceModifiedSince() throws Exception {
        Long time = new Date().getTime();
        MultipartFileSender multipartFileSender = MultipartFileSender.fromInputStream(is).with(requestWrapper)
                .withFileName(fileName).with(responseWrapper).withChecksum(checksum).withMimetype(mimeType)
                .withLength(length).withLastModified(time);

        when(request.getDateHeader(eq("If-Modified-Since"))).thenReturn(time - 100000);
        when(request.getDateHeader(eq("If-Unmodified-Since"))).thenReturn(-1L);

        multipartFileSender.isValid();
        multipartFileSender.serveResource();

        assertEquals(HttpServletResponse.SC_OK, responseWrapper.getStatusCode());

    }

    /**
     * If the If-Match doesn't match the ETAG then return 416 Status code
     *
     * @throws Exception
     */
    @Test
    public void testIfMatchNoMatch() throws Exception {
        Long time = new Date().getTime();
        MultipartFileSender multipartFileSender = MultipartFileSender.fromInputStream(is).with(requestWrapper)
                .withFileName(fileName).with(responseWrapper).withChecksum(checksum).withMimetype(mimeType)
                .withLength(length).withLastModified(time);

        when(request.getDateHeader(eq("If-Modified-Since"))).thenReturn(-1L);
        when(request.getDateHeader(eq("If-Unmodified-Since"))).thenReturn(-1L);
        when(request.getHeader(eq("If-Match"))).thenReturn("None-Matching-ETAG");

        multipartFileSender.isValid();

        assertEquals(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE, responseWrapper.getStatusCode());
    }

    /**
     * If matches then just return resource
     *
     * @throws Exception
     */
    @Test
    public void testIfMatchMatch() throws Exception {
        Long time = new Date().getTime();
        MultipartFileSender multipartFileSender = MultipartFileSender.fromInputStream(is).with(requestWrapper)
                .withFileName(fileName).with(responseWrapper).withChecksum(checksum).withMimetype(mimeType)
                .withLength(length).withLastModified(time);

        when(request.getDateHeader(eq("If-Modified-Since"))).thenReturn(-1L);
        when(request.getDateHeader(eq("If-Unmodified-Since"))).thenReturn(-1L);
        when(request.getHeader(eq("If-Match"))).thenReturn(checksum);

        multipartFileSender.isValid();

        assertEquals(HttpServletResponse.SC_OK, responseWrapper.getStatusCode());
    }

    /**
     * If not modified since given date then return resource
     *
     * @throws Exception
     */
    @Test
    public void testIfUnmodifiedSinceNotModifiedSince() throws Exception {
        Long time = new Date().getTime();
        MultipartFileSender multipartFileSender = MultipartFileSender.fromInputStream(is).with(requestWrapper)
                .withFileName(fileName).with(responseWrapper).withChecksum(checksum).withMimetype(mimeType)
                .withLength(length).withLastModified(time);

        when(request.getDateHeader(eq("If-Unmodified-Since"))).thenReturn(time + 100000);
        when(request.getDateHeader(eq("If-Modified-Since"))).thenReturn(-1L);

        multipartFileSender.isValid();

        assertEquals(HttpServletResponse.SC_OK, responseWrapper.getStatusCode());

    }

    /**
     * If modified since given date then return 412
     *
     * @throws Exception
     */
    @Test
    public void testIfUnmodifiedSinceModifiedSince() throws Exception {
        Long time = new Date().getTime();
        MultipartFileSender multipartFileSender = MultipartFileSender.fromInputStream(is).with(requestWrapper)
                .withFileName(fileName).with(responseWrapper).withChecksum(checksum).withMimetype(mimeType)
                .withLength(length).withLastModified(time);

        when(request.getDateHeader(eq("If-Unmodified-Since"))).thenReturn(time - 100000);
        when(request.getDateHeader(eq("If-Modified-Since"))).thenReturn(-1L);

        multipartFileSender.isValid();

        assertEquals(HttpServletResponse.SC_PRECONDITION_FAILED, responseWrapper.getStatusCode());

    }

}