org.nuxeo.ecm.core.io.download.TestDownloadService.java Source code

Java tutorial

Introduction

Here is the source code for org.nuxeo.ecm.core.io.download.TestDownloadService.java

Source

/*
 * (C) Copyright 2015-2016 Nuxeo SA (http://nuxeo.com/) and others.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Contributors:
 *     Florent Guillaume
 *     Estelle Giuly <egiuly@nuxeo.com>
 */
package org.nuxeo.ecm.core.io.download;

import static java.lang.Boolean.FALSE;
import static java.lang.Boolean.TRUE;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Serializable;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.inject.Inject;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.tuple.Pair;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.nuxeo.ecm.core.api.Blob;
import org.nuxeo.ecm.core.api.Blobs;
import org.nuxeo.ecm.core.api.CoreInstance;
import org.nuxeo.ecm.core.api.CoreSession;
import org.nuxeo.ecm.core.api.DocumentModel;
import org.nuxeo.ecm.core.api.NuxeoPrincipal;
import org.nuxeo.ecm.core.api.impl.UserPrincipal;
import org.nuxeo.ecm.core.api.impl.blob.FileBlob;
import org.nuxeo.ecm.core.api.local.ClientLoginModule;
import org.nuxeo.ecm.core.api.local.LoginStack;
import org.nuxeo.ecm.core.io.download.DownloadServiceImpl.Action;
import org.nuxeo.ecm.core.test.CoreFeature;
import org.nuxeo.runtime.api.Framework;
import org.nuxeo.runtime.test.runner.Deploy;
import org.nuxeo.runtime.test.runner.Features;
import org.nuxeo.runtime.test.runner.FeaturesRunner;
import org.nuxeo.runtime.test.runner.LocalDeploy;

@RunWith(FeaturesRunner.class)
@Features(CoreFeature.class)
@Deploy({ "org.nuxeo.ecm.core.io", "org.nuxeo.ecm.core.cache" })
public class TestDownloadService {

    @Inject
    protected DownloadService downloadService;

    @Test
    public void testBasicDownload() throws Exception {
        // blob to download
        String blobValue = "Hello World";
        Blob blob = Blobs.createBlob(blobValue);
        blob.setFilename("myFile.txt");
        blob.setDigest("12345");

        // prepare mocks
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        HttpServletRequest request = mock(HttpServletRequest.class);
        when(request.getMethod()).thenReturn("GET");

        HttpServletResponse response = mock(HttpServletResponse.class);
        ServletOutputStream sos = new ServletOutputStream() {
            @Override
            public void write(int b) throws IOException {
                out.write(b);
            }
        };
        PrintWriter printWriter = new PrintWriter(sos);
        when(response.getOutputStream()).thenReturn(sos);
        when(response.getWriter()).thenReturn(printWriter);

        // send download request
        downloadService.downloadBlob(request, response, null, null, blob, null, null);

        // check that the blob gets returned
        assertEquals(blobValue, out.toString());
    }

    @Test
    public void testETagHeaderNone() throws Exception {
        doTestETagHeader(null);
    }

    @Test
    public void testETagHeaderNotMatched() throws Exception {
        doTestETagHeader(FALSE);
    }

    @Test
    public void testETagHeaderMatched() throws Exception {
        doTestETagHeader(TRUE);
    }

    protected void doTestETagHeader(Boolean match) throws Exception {
        // Given a blob
        String blobValue = "Hello World";
        Blob blob = Blobs.createBlob(blobValue);
        blob.setFilename("myFile.txt");
        blob.setDigest("12345");

        String digestToTest;
        if (match == null) {
            digestToTest = null;
        } else if (TRUE.equals(match)) {
            digestToTest = "12345";
        } else {
            digestToTest = "78787";
        }

        // When I send a request a given digest
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        HttpServletRequest req = mock(HttpServletRequest.class);
        when(req.getHeader("If-None-Match")).thenReturn('"' + digestToTest + '"');
        when(req.getMethod()).thenReturn("GET");

        HttpServletResponse resp = mock(HttpServletResponse.class);
        ServletOutputStream sos = new ServletOutputStream() {
            @Override
            public void write(int b) throws IOException {
                out.write(b);
            }
        };
        @SuppressWarnings("resource")
        PrintWriter printWriter = new PrintWriter(sos);
        when(resp.getOutputStream()).thenReturn(sos);
        when(resp.getWriter()).thenReturn(printWriter);

        downloadService.downloadBlob(req, resp, null, null, blob, null, null);

        verify(req, atLeast(1)).getHeader("If-None-Match");

        // Then the response differs if the digest match
        if (TRUE.equals(match)) {
            assertEquals(0, out.toByteArray().length);
            verify(resp).sendError(HttpServletResponse.SC_NOT_MODIFIED);
        } else {
            assertEquals(blobValue, out.toString());
            verify(resp).setHeader("ETag", '"' + blob.getDigest() + '"');
        }
    }

    @Test
    public void testETagHeaderNoDigest() throws Exception {
        String blobValue = "Hello World";
        Blob blob = Blobs.createBlob(blobValue);
        blob.setFilename("myFile.txt");

        ByteArrayOutputStream out = new ByteArrayOutputStream();
        HttpServletRequest req = mock(HttpServletRequest.class);
        when(req.getHeader("If-None-Match")).thenReturn("\"b10a8db164e0754105b7a99be72e3fe5\"");
        when(req.getMethod()).thenReturn("GET");

        HttpServletResponse resp = mock(HttpServletResponse.class);
        ServletOutputStream sos = new ServletOutputStream() {
            @Override
            public void write(int b) throws IOException {
                out.write(b);
            }
        };
        @SuppressWarnings("resource")
        PrintWriter printWriter = new PrintWriter(sos);
        when(resp.getOutputStream()).thenReturn(sos);
        when(resp.getWriter()).thenReturn(printWriter);

        downloadService.downloadBlob(req, resp, null, null, blob, null, "test");

        verify(req, atLeastOnce()).getHeader("If-None-Match");
        assertEquals(0, out.toByteArray().length);
        verify(resp).sendError(HttpServletResponse.SC_NOT_MODIFIED);
    }

    @Test
    @LocalDeploy("org.nuxeo.ecm.core.io.test:OSGI-INF/test-download-service-permission.xml")
    public void testDownloadPermission() throws Exception {
        // blob to download
        String blobValue = "Hello World";
        Blob blob = Blobs.createBlob(blobValue);
        blob.setFilename("myfile.txt");
        blob.setDigest("12345");

        // mock request
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        HttpServletRequest request = mock(HttpServletRequest.class);
        when(request.getMethod()).thenReturn("GET");

        // mock response
        HttpServletResponse response = mock(HttpServletResponse.class);
        ServletOutputStream sos = new ServletOutputStream() {
            @Override
            public void write(int b) throws IOException {
                out.write(b);
            }
        };
        @SuppressWarnings("resource")
        PrintWriter printWriter = new PrintWriter(sos);
        when(response.getOutputStream()).thenReturn(sos);
        when(response.getWriter()).thenReturn(printWriter);

        // mock document
        DocumentModel doc = mock(DocumentModel.class);
        when(doc.getPropertyValue("dc:format")).thenReturn("pdf");

        // extended infos with rendition
        String reason = "rendition";
        Map<String, Serializable> extendedInfos = Collections.singletonMap("rendition", "myrendition");

        // principal
        NuxeoPrincipal principal = new UserPrincipal("bob", Collections.singletonList("members"), false, false);

        // do tests while logged in
        LoginStack loginStack = ClientLoginModule.getThreadLocalLogin();
        loginStack.push(principal, null, null);
        try {
            // send download request for file:content, should be denied
            downloadService.downloadBlob(request, response, doc, "file:content", blob, null, reason, extendedInfos);
            assertEquals("", out.toString());
            verify(response, atLeastOnce()).sendError(403, "Permission denied");

            // but another xpath is allowed, per the javascript rule
            downloadService.downloadBlob(request, response, doc, "other:blob", blob, null, reason, extendedInfos);
            assertEquals(blobValue, out.toString());
        } finally {
            loginStack.pop();
        }
    }

    @Test
    public void testTransientCleanup() throws IOException {
        // transfert temporary file into a blob
        Path path = Files.createTempFile("pfouh", "pfouh");
        FileBlob blob = new FileBlob("pfouh");
        Files.move(path, blob.getFile().toPath(), REPLACE_EXISTING);

        // store the blob for downloading
        String key = downloadService.storeBlobs(Collections.singletonList(blob));

        // mock request
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        HttpServletRequest request = mock(HttpServletRequest.class);
        when(request.getMethod()).thenReturn("GET");

        // mock response
        HttpServletResponse response = mock(HttpServletResponse.class);
        ServletOutputStream sos = new ServletOutputStream() {
            @Override
            public void write(int b) throws IOException {
                out.write(b);
            }
        };
        @SuppressWarnings("resource")
        PrintWriter printWriter = new PrintWriter(sos);
        when(response.getOutputStream()).thenReturn(sos);
        when(response.getWriter()).thenReturn(printWriter);

        NuxeoPrincipal principal = new UserPrincipal("bob", Collections.singletonList("members"), false, false);

        // do tests while logged in
        LoginStack loginStack = ClientLoginModule.getThreadLocalLogin();
        loginStack.push(principal, null, null);

        try {
            downloadService.downloadBlob(request, response, key, "download");
        } finally {
            loginStack.pop();
        }

        // the file is gone
        assertFalse(blob.getFile().exists());
    }

    @Test
    public void testGetDownloadPathAndAction() {
        DownloadServiceImpl downloadServiceImpl = new DownloadServiceImpl();
        String path = "nxfile/default/3727ef6b-cf8c-4f27-ab2c-79de0171a2c8/files:files/0/file/image.png";
        Pair<String, Action> pair = downloadServiceImpl.getDownloadPathAndAction(path);
        assertEquals("default/3727ef6b-cf8c-4f27-ab2c-79de0171a2c8/files:files/0/file/image.png", pair.getLeft());
        assertEquals(Action.DOWNLOAD_FROM_DOC, pair.getRight());

        path = "plop/default/3727ef6b-cf8c-4f27-ab2c-79de0171a2c8/files:files/0/file/image.png";
        pair = downloadServiceImpl.getDownloadPathAndAction(path);
        assertNull(pair);
    }

    @Test
    public void testResolveBlobFromDownloadUrl() throws IOException {
        String repositoryName = "test";
        CoreSession session = CoreInstance.openCoreSession(repositoryName);
        Framework.getProperties().setProperty("nuxeo.url", "http://localhost:8080/nuxeo");
        DocumentModel doc = session.createDocumentModel("/", "James-Bond", "File");
        doc.setProperty("dublincore", "title", "Diamonds are forever");

        FileBlob blob = new FileBlob("Synopsis");
        String blobFilename = "synopsis.txt";
        blob.setFilename(blobFilename);

        Map<String, Object> fileMap = new HashMap<>();
        fileMap.put("file", blob);
        List<Map<String, Object>> docFiles = new ArrayList<>();
        docFiles.add(fileMap);

        doc.setProperty("files", "files", docFiles);
        doc = session.createDocument(doc);
        session.save();

        String url = "http://localhost:8080/nuxeo/nxfile/" + repositoryName + "/" + doc.getId()
                + "/files:files/0/file/" + blobFilename;
        Blob resolvedBlob = downloadService.resolveBlobFromDownloadUrl(url);
        assertEquals(blob, resolvedBlob);
        session.close();
    }

}