org.cloudifysource.dsl.download.ResourceDownloaderTest.java Source code

Java tutorial

Introduction

Here is the source code for org.cloudifysource.dsl.download.ResourceDownloaderTest.java

Source

/*******************************************************************************
 * Copyright (c) 2013 GigaSpaces Technologies Ltd. All rights reserved
 *
 * 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.
 *******************************************************************************/
package org.cloudifysource.dsl.download;

import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.net.URL;
import java.text.MessageFormat;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import org.apache.commons.io.FileUtils;
import org.cloudifysource.dsl.internal.tools.download.ChecksumVerifierException;
import org.cloudifysource.dsl.internal.tools.download.ResourceDownloadException;
import org.cloudifysource.dsl.internal.tools.download.ResourceDownloadFacade;
import org.cloudifysource.dsl.internal.tools.download.ResourceDownloadFacadeImpl;
import org.cloudifysource.dsl.internal.tools.download.ResourceDownloader;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ResourceHandler;
import org.eclipse.jetty.util.resource.FileResource;
import org.eclipse.jetty.util.resource.Resource;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;

/**
 * This test starts an embedded Jetty server on the localhost and tests download requests made by the download facade
 * utility.
 *
 * @author adaml
 * @since 2.6.0
 */
public class ResourceDownloaderTest {

    // default resource params.
    private static final String RESOURCE_NAME = "testResource.txt";
    private static final String DESTINATION_FOLDER = "src/test/resources/resourceDownloader/downloadFolder/";
    private static final String RESOURCE_DESTINATION = DESTINATION_FOLDER + RESOURCE_NAME;
    private static final String RESOURCE_URL = "http://localhost:8080/" + RESOURCE_NAME;
    private static final String RESOURCE_FOLDER = "src/test/resources/resourceDownloader/";

    // used for testing checksum failure.
    private static final String DUMMY_RESOURCE_NAME = "dummyTestResource.txt";
    private static final String DUMMY_RESOURCE_URL = "http://localhost:8080/" + DUMMY_RESOURCE_NAME;
    private static final ResourceDownloadFacade rdf = new ResourceDownloadFacadeImpl(new ResourceDownloader());

    private static final Server server = new Server(8080);

    @BeforeClass
    public static void beforeClass() throws Exception {

        // Start embedded jetty server.
        final URL resourceUrl = new File(RESOURCE_FOLDER).getAbsoluteFile().toURI().toURL();
        final Resource resource = new FileResource(resourceUrl);
        final ResourceHandler handler = new ResourceHandler();
        handler.setBaseResource(resource);
        server.setHandler(handler);
        server.start();

        // Create the destination folder if does not exist 
        final File destinationFolder = new File(DESTINATION_FOLDER);
        if (!destinationFolder.exists()) {
            destinationFolder.mkdirs();
        }
    }

    @AfterClass
    public static void afterClass() throws Exception {
        server.stop();
        final File destinationFolder = new File(DESTINATION_FOLDER);
        if (destinationFolder.exists()) {
            FileUtils.deleteQuietly(destinationFolder);
        }
    }

    @Test
    public void testTimeout() {
        // Try doGet with very short timeout.
        try {
            rdf.get(RESOURCE_URL, RESOURCE_DESTINATION, false, 1, TimeUnit.MICROSECONDS);
            Assert.fail("Expected timeout exception.");
        } catch (TimeoutException e) {
            // test passed.
        } catch (ResourceDownloadException e) {
            Assert.fail("Expecting timeout exception. got " + e.getMessage());
        }
    }

    @Test
    public void testBadChecksumVerification() throws Exception {
        // run doGet on a dummy file and try to verify it against
        // non-matching checksum files.
        assertChecksumFailure(RESOURCE_URL + ".md5");
        cleanDownloadFolder();
        assertChecksumFailure(RESOURCE_URL + ".sha1");
        cleanDownloadFolder();
        assertChecksumFailure(RESOURCE_URL + ".sha256");
        cleanDownloadFolder();
        assertChecksumFailure(RESOURCE_URL + ".sha384");
        cleanDownloadFolder();
        assertChecksumFailure(RESOURCE_URL + ".sha512");
        cleanDownloadFolder();
    }

    void assertChecksumFailure(final String hashUrl) {
        try {
            rdf.get(DUMMY_RESOURCE_URL, RESOURCE_DESTINATION, false, hashUrl);
            Assert.fail("File checksum verified. This is not suppose to happen.");
        } catch (Exception e) {
            if (!(e.getCause() instanceof ChecksumVerifierException)) {
                Assert.fail("expecting failure due to checksum validation");
            }
        }
    }

    @Test
    public void testResourceDownload() throws Exception {
        // test get with checksum verification.
        // Hashing algorithm determined by the checksum file extension.
        cleanDownloadFolder();
        rdf.get(RESOURCE_URL, RESOURCE_DESTINATION);
        cleanDownloadFolder();
        assertDownloadSuccess(RESOURCE_URL + ".md5");
        cleanDownloadFolder();
        assertDownloadSuccess(RESOURCE_URL + ".sha1");
        cleanDownloadFolder();
        assertDownloadSuccess(RESOURCE_URL + ".sha256");
        cleanDownloadFolder();
        assertDownloadSuccess(RESOURCE_URL + ".sha384");
        cleanDownloadFolder();
        assertDownloadSuccess(RESOURCE_URL + ".sha512");
        cleanDownloadFolder();
    }

    private class DownloadTask implements Callable<Exception> {

        @Override
        public Exception call() throws Exception {
            try {
                rdf.get(RESOURCE_URL, RESOURCE_DESTINATION);
            } catch (ResourceDownloadException e) {
                return e;
            } catch (TimeoutException e) {
                return e;
            }
            return null;
        }

    }

    @Test
    public void testConcurrentDownload() throws Exception {
        for (int i = 0; i < 10; ++i) {
            cleanDownloadFolder();
            ExecutorService pool = Executors.newFixedThreadPool(3);

            try {
                DownloadTask task1 = new DownloadTask();
                DownloadTask task2 = new DownloadTask();
                DownloadTask task3 = new DownloadTask();

                Future<Exception> future1 = pool.submit(task1);
                Future<Exception> future2 = pool.submit(task2);
                Future<Exception> future3 = pool.submit(task3);

                Exception e1 = future1.get();
                Exception e2 = future2.get();
                Exception e3 = future3.get();

                Assert.assertNull("concurrent download failed: " + e1, e1);
                Assert.assertNull("concurrent download failed: " + e2, e2);
                Assert.assertNull("concurrent download failed: " + e3, e3);

                final File destinationFolder = new File(DESTINATION_FOLDER);
                File[] files = destinationFolder.listFiles();
                Assert.assertEquals("Expecting only one file", 1, files.length);

            } finally {
                pool.shutdown();
                pool.awaitTermination(10, TimeUnit.SECONDS);
                cleanDownloadFolder();
            }
        }

    }

    @Test
    public void testChecksumFormatting() throws Exception {
        // Tests checksum verification on checksum files that
        // are formatted using format type '{0}'.
        assertFormattedChecksumVerification("testResourceFormatted.txt.md5");
        cleanDownloadFolder();
        assertFormattedChecksumVerification("testResourceFormatted.txt.sha1");
        cleanDownloadFolder();
        assertFormattedChecksumVerification("testResourceFormatted.txt.sha256");
        cleanDownloadFolder();
        assertFormattedChecksumVerification("testResourceFormatted.txt.sha384");
        cleanDownloadFolder();
        assertFormattedChecksumVerification("testResourceFormatted.txt.sha512");
        cleanDownloadFolder();
    }

    @Test
    public void testSkipExistingFlag() throws Exception {
        // asserts file was not overridden.
        rdf.get(RESOURCE_URL, RESOURCE_DESTINATION, false, RESOURCE_URL + ".md5");

        File downloadedResource = new File(DESTINATION_FOLDER, RESOURCE_NAME);
        long lastModified = downloadedResource.lastModified();

        rdf.get(RESOURCE_URL, RESOURCE_DESTINATION, true, RESOURCE_URL + ".md5");
        Assert.assertTrue("File was modified but skip existing flag is true",
                downloadedResource.lastModified() == lastModified);
        cleanDownloadFolder();
    }

    void assertFormattedChecksumVerification(final String hashFileName) throws ResourceDownloadException {

        // test verification for special checksum format types
        final ResourceDownloader downloader = new ResourceDownloader();
        final File resourceFile = new File(RESOURCE_FOLDER, RESOURCE_NAME);
        final File hashFile = new File(RESOURCE_FOLDER, hashFileName);

        downloader.setFormat(new MessageFormat("{0}"));
        downloader.setResourceDest(resourceFile);
        // Expecting not to throw exception.
        downloader.verifyResourceChecksum(hashFile);
    }

    void assertDownloadSuccess(final String hashUrl)
            throws ResourceDownloadException, TimeoutException, IOException {
        rdf.get(RESOURCE_URL, RESOURCE_DESTINATION, false, hashUrl);
        assertFilesDownloaded("testResource.txt", getResourceName(hashUrl));
    }

    private String getResourceName(final String url) {
        final int slashIndex = url.lastIndexOf('/');
        final String filename = url.substring(slashIndex + 1);
        return filename;
    }

    private void assertFilesDownloaded(final String resourceFileName, final String hashFileName)
            throws IOException {

        final File downloadedResourceFile = new File(DESTINATION_FOLDER, resourceFileName);
        final File downloadedHashFile = new File(DESTINATION_FOLDER, hashFileName);
        Assert.assertTrue("Resource file download failed", downloadedResourceFile.exists());
        Assert.assertTrue("Hash file download failed", downloadedHashFile.exists());

        final File destinationFolder = new File(DESTINATION_FOLDER);
        File[] partFiles = destinationFolder.listFiles(new FilenameFilter() {

            @Override
            public boolean accept(final File dir, final String name) {
                return name.contains(".part.");

            }
        });

        Assert.assertEquals("Expected no part files to be found", 0, partFiles.length);

        final File originalResourceFile = new File(RESOURCE_FOLDER, resourceFileName);
        final File originalHashFile = new File(RESOURCE_FOLDER, hashFileName);
        // asserting file content is the same.
        Assert.assertTrue("Resource file was not downloaded properly", FileUtils
                .readFileToString(downloadedResourceFile).equals(FileUtils.readFileToString(originalResourceFile)));
        Assert.assertTrue("Hash file was not downloaded properly", FileUtils.readFileToString(downloadedHashFile)
                .equals(FileUtils.readFileToString(originalHashFile)));

    }

    private void cleanDownloadFolder() throws IOException {
        FileUtils.cleanDirectory(new File(DESTINATION_FOLDER));
    }
}