org.jclouds.rackspace.cloudfiles.CloudFilesClientLiveTest.java Source code

Java tutorial

Introduction

Here is the source code for org.jclouds.rackspace.cloudfiles.CloudFilesClientLiveTest.java

Source

/**
 *
 * Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
 *
 * ====================================================================
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.jclouds.rackspace.cloudfiles;

import static org.jclouds.rackspace.cloudfiles.options.ListContainerOptions.Builder.underPath;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.Map;
import java.util.SortedSet;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;

import org.apache.commons.io.IOUtils;
import org.jclouds.blobstore.ContainerNotFoundException;
import org.jclouds.blobstore.KeyNotFoundException;
import org.jclouds.blobstore.domain.ListResponse;
import org.jclouds.blobstore.integration.internal.BaseBlobStoreIntegrationTest;
import org.jclouds.http.HttpResponseException;
import org.jclouds.http.HttpUtils;
import org.jclouds.http.options.GetOptions;
import org.jclouds.rackspace.cloudfiles.domain.AccountMetadata;
import org.jclouds.rackspace.cloudfiles.domain.CFObject;
import org.jclouds.rackspace.cloudfiles.domain.ContainerCDNMetadata;
import org.jclouds.rackspace.cloudfiles.domain.ContainerMetadata;
import org.jclouds.rackspace.cloudfiles.domain.MutableObjectInfoWithMetadata;
import org.jclouds.rackspace.cloudfiles.domain.ObjectInfo;
import org.jclouds.rackspace.cloudfiles.options.ListCdnContainerOptions;
import org.jclouds.rackspace.cloudfiles.options.ListContainerOptions;
import org.testng.annotations.Test;

import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;

/**
 * Tests behavior of {@code JaxrsAnnotationProcessor}
 * 
 * @author Adrian Cole
 */
@Test(groups = "live", testName = "cloudfiles.CloudFilesClientLiveTest")
public class CloudFilesClientLiveTest
        extends BaseBlobStoreIntegrationTest<CloudFilesAsyncClient, CloudFilesClient> {

    /**
     * this method overrides containerName to ensure it isn't found
     */
    @Test(groups = { "integration", "live" })
    public void deleteContainerIfEmptyNotFound() throws Exception {
        assert context.getApi().deleteContainerIfEmpty("dbienf");
    }

    @Test
    public void testCDNOperations() throws Exception {
        final long minimumTTL = 60 * 60; // The minimum TTL is 1 hour

        // Create two new containers for testing
        final String containerNameWithCDN = getContainerName();
        final String containerNameWithoutCDN = getContainerName();
        try {
            try {
                context.getApi().disableCDN(containerNameWithCDN);
                context.getApi().disableCDN(containerNameWithoutCDN);
            } catch (Exception e) {

            }
            ContainerCDNMetadata cdnMetadata = null;

            // Enable CDN with PUT for one container
            final URI cdnUri = context.getApi().enableCDN(containerNameWithCDN);
            assertTrue(cdnUri != null);

            // Confirm CDN is enabled via HEAD request and has default TTL
            cdnMetadata = context.getApi().getCDNMetadata(containerNameWithCDN);

            assertTrue(cdnMetadata.isCDNEnabled());

            assertEquals(cdnMetadata.getCDNUri(), cdnUri);
            final long initialTTL = cdnMetadata.getTTL();

            try {
                cdnMetadata = context.getApi().getCDNMetadata(containerNameWithoutCDN);
                assert cdnMetadata == null || !cdnMetadata.isCDNEnabled() : containerNameWithoutCDN
                        + " should not have metadata";
            } catch (ContainerNotFoundException e) {
            } catch (HttpResponseException e) {
            }

            try {
                cdnMetadata = context.getApi().getCDNMetadata("DoesNotExist");
                assert false : "should not exist";
            } catch (ContainerNotFoundException e) {
            } catch (HttpResponseException e) {
            }
            // List CDN metadata for containers, and ensure all CDN info is available for enabled
            // container
            SortedSet<ContainerCDNMetadata> cdnMetadataList = context.getApi().listCDNContainers();
            assertTrue(cdnMetadataList.size() >= 1);

            assertTrue(cdnMetadataList
                    .contains(new ContainerCDNMetadata(containerNameWithCDN, true, initialTTL, cdnUri)));

            // Test listing with options
            cdnMetadataList = context.getApi().listCDNContainers(ListCdnContainerOptions.Builder.enabledOnly());
            assertTrue(Iterables.all(cdnMetadataList, new Predicate<ContainerCDNMetadata>() {
                public boolean apply(ContainerCDNMetadata cdnMetadata) {
                    return cdnMetadata.isCDNEnabled();
                }
            }));

            cdnMetadataList = context.getApi()
                    .listCDNContainers(ListCdnContainerOptions.Builder
                            .afterMarker(containerNameWithCDN.substring(0, containerNameWithCDN.length() - 1))
                            .maxResults(1));
            assertEquals(cdnMetadataList.size(), 1);

            // Enable CDN with PUT for the same container, this time with a custom TTL
            long ttl = 4000;
            context.getApi().enableCDN(containerNameWithCDN, ttl);

            cdnMetadata = context.getApi().getCDNMetadata(containerNameWithCDN);

            assertTrue(cdnMetadata.isCDNEnabled());

            assertEquals(cdnMetadata.getTTL(), ttl);

            // Check POST by updating TTL settings
            ttl = minimumTTL;
            context.getApi().updateCDN(containerNameWithCDN, minimumTTL);

            cdnMetadata = context.getApi().getCDNMetadata(containerNameWithCDN);
            assertTrue(cdnMetadata.isCDNEnabled());

            assertEquals(cdnMetadata.getTTL(), minimumTTL);

            // Confirm that minimum allowed value for TTL is 3600, lower values are ignored.
            context.getApi().updateCDN(containerNameWithCDN, 3599L);
            cdnMetadata = context.getApi().getCDNMetadata(containerNameWithCDN);
            assertEquals(cdnMetadata.getTTL(), minimumTTL); // Note that TTL is 3600 here, not 3599

            // Disable CDN with POST
            assertTrue(context.getApi().disableCDN(containerNameWithCDN));

            cdnMetadata = context.getApi().getCDNMetadata(containerNameWithCDN);
            assertEquals(cdnMetadata.isCDNEnabled(), false);
        } finally {
            recycleContainer(containerNameWithCDN);
            recycleContainer(containerNameWithoutCDN);
        }
    }

    @Test
    public void testListOwnedContainers() throws Exception {
        String containerPrefix = getContainerName();
        try {
            SortedSet<ContainerMetadata> response = context.getApi().listContainers();
            assertNotNull(response);
            long initialContainerCount = response.size();
            assertTrue(initialContainerCount >= 0);

            // Create test containers
            String[] containerJsr330 = new String[] { containerPrefix + ".testListOwnedContainers1",
                    containerPrefix + ".testListOwnedContainers2" };
            assertTrue(context.getApi().createContainer(containerJsr330[0]));
            assertTrue(context.getApi().createContainer(containerJsr330[1]));

            // Test default listing
            response = context.getApi().listContainers();
            // assertEquals(response.size(), initialContainerCount + 2);// if the containers already
            // exist, this will fail

            // Test listing with options
            response = context.getApi().listContainers(ListContainerOptions.Builder
                    .afterMarker(containerJsr330[0].substring(0, containerJsr330[0].length() - 1)).maxResults(1));
            assertEquals(response.size(), 1);
            assertEquals(response.first().getName(), containerJsr330[0]);

            response = context.getApi()
                    .listContainers(ListContainerOptions.Builder.afterMarker(containerJsr330[0]).maxResults(1));
            assertEquals(response.size(), 1);
            assertEquals(response.first().getName(), containerJsr330[1]);

            // Cleanup and test containers have been removed
            assertTrue(context.getApi().deleteContainerIfEmpty(containerJsr330[0]));
            assertTrue(context.getApi().deleteContainerIfEmpty(containerJsr330[1]));
            response = context.getApi().listContainers();
            // assertEquals(response.size(), initialContainerCount + 2);// if the containers already
            // exist, this will fail
        } finally {
            returnContainer(containerPrefix);
        }
    }

    @Test
    public void testHeadAccountMetadata() throws Exception {
        String containerPrefix = getContainerName();
        String containerName = containerPrefix + ".testHeadAccountMetadata";
        try {
            AccountMetadata metadata = context.getApi().getAccountStatistics();
            assertNotNull(metadata);
            long initialContainerCount = metadata.getContainerCount();

            assertTrue(context.getApi().createContainer(containerName));

            metadata = context.getApi().getAccountStatistics();
            assertNotNull(metadata);
            assertTrue(metadata.getContainerCount() >= initialContainerCount);

            assertTrue(context.getApi().deleteContainerIfEmpty(containerName));
        } finally {
            returnContainer(containerPrefix);
        }
    }

    @Test
    public void testPutContainers() throws Exception {
        String containerName = getContainerName();
        try {
            String containerName1 = containerName + ".hello";
            assertTrue(context.getApi().createContainer(containerName1));
            // List only the container just created, using a marker with the container name less 1 char
            SortedSet<ContainerMetadata> response = context.getApi().listContainers(ListContainerOptions.Builder
                    .afterMarker(containerName1.substring(0, containerName1.length() - 1)).maxResults(1));
            assertNotNull(response);
            assertEquals(response.size(), 1);
            assertEquals(response.first().getName(), containerName + ".hello");

            String containerName2 = containerName + "?should-be-illegal-question-char";
            assert context.getApi().createContainer(containerName2);

            // TODO: Should throw a specific exception, not UndeclaredThrowableException
            try {
                context.getApi().createContainer(containerName + "/illegal-slash-char");
                fail("Should not be able to create container with illegal '/' character");
            } catch (Exception e) {
            }
            assertTrue(context.getApi().deleteContainerIfEmpty(containerName1));
            assertTrue(context.getApi().deleteContainerIfEmpty(containerName2));
        } finally {
            returnContainer(containerName);
        }
    }

    public void testListContainerPath()
            throws InterruptedException, ExecutionException, TimeoutException, IOException {
        String containerName = getContainerName();
        try {

            String data = "foo";

            context.getApi().putObject(containerName, newCFObject(data, "foo"));
            context.getApi().putObject(containerName, newCFObject(data, "path/bar"));

            ListResponse<ObjectInfo> container = context.getApi().listObjects(containerName, underPath(""));
            assert !container.isTruncated();
            assertEquals(container.size(), 1);
            assertEquals(container.first().getName(), "foo");
            container = context.getApi().listObjects(containerName, underPath("path"));
            assert !container.isTruncated();
            assertEquals(container.size(), 1);
            assertEquals(container.first().getName(), "path/bar");
        } finally {
            returnContainer(containerName);
        }

    }

    @Test
    public void testObjectOperations() throws Exception {
        String containerName = getContainerName();
        try {
            // Test PUT with string data, ETag hash, and a piece of metadata
            String data = "Here is my data";
            String key = "object";
            CFObject object = newCFObject(data, key);
            byte[] md5 = object.getInfo().getHash();
            String newEtag = context.getApi().putObject(containerName, object);
            assertEquals(HttpUtils.toHexString(md5), HttpUtils.toHexString(object.getInfo().getHash()));

            // Test HEAD of missing object
            try {
                context.getApi().getObjectInfo(containerName, "non-existent-object");
                assert false;
            } catch (KeyNotFoundException e) {
            }

            // Test HEAD of object
            MutableObjectInfoWithMetadata metadata = context.getApi().getObjectInfo(containerName,
                    object.getInfo().getName());
            // TODO assertEquals(metadata.getName(), object.getMetadata().getName());
            assertEquals(metadata.getBytes(), new Long(data.length()));
            assertEquals(metadata.getContentType(), "text/plain");
            assertEquals(HttpUtils.toHexString(md5), HttpUtils.toHexString(object.getInfo().getHash()));
            assertEquals(metadata.getHash(), HttpUtils.fromHexString(newEtag));
            assertEquals(metadata.getMetadata().entrySet().size(), 1);
            assertEquals(metadata.getMetadata().get("metadata"), "metadata-value");

            // // Test POST to update object's metadata
            Map<String, String> userMetadata = Maps.newHashMap();
            userMetadata.put("New-Metadata-1", "value-1");
            userMetadata.put("New-Metadata-2", "value-2");
            assertTrue(context.getApi().setObjectInfo(containerName, object.getInfo().getName(), userMetadata));

            // Test GET of missing object
            try {
                context.getApi().getObject(containerName, "non-existent-object");
                assert false;
            } catch (KeyNotFoundException e) {
            }
            // Test GET of object (including updated metadata)
            CFObject getBlob = context.getApi().getObject(containerName, object.getInfo().getName());
            assertEquals(IOUtils.toString((InputStream) getBlob.getData()), data);
            // TODO assertEquals(getBlob.getName(), object.getMetadata().getName());
            assertEquals(getBlob.getContentLength(), new Long(data.length()));
            assertEquals(getBlob.getInfo().getContentType(), "text/plain");
            assertEquals(HttpUtils.toHexString(md5), HttpUtils.toHexString(getBlob.getInfo().getHash()));
            assertEquals(HttpUtils.fromHexString(newEtag), getBlob.getInfo().getHash());
            assertEquals(getBlob.getInfo().getMetadata().entrySet().size(), 2);
            assertEquals(getBlob.getInfo().getMetadata().get("new-metadata-1"), "value-1");
            assertEquals(getBlob.getInfo().getMetadata().get("new-metadata-2"), "value-2");

            // Test PUT with invalid ETag (as if object's data was corrupted in transit)
            String correctEtag = newEtag;
            String incorrectEtag = "0" + correctEtag.substring(1);
            object.getInfo().setHash(HttpUtils.fromHexString(incorrectEtag));
            try {
                context.getApi().putObject(containerName, object);
            } catch (HttpResponseException e) {
                assertEquals(e.getResponse().getStatusCode(), 422);
            }

            // Test PUT chunked/streamed upload with data of "unknown" length
            ByteArrayInputStream bais = new ByteArrayInputStream(data.getBytes("UTF-8"));
            CFObject blob = context.getApi().newCFObject();
            blob.getInfo().setName("chunked-object");
            blob.setData(bais);
            newEtag = context.getApi().putObject(containerName, blob);
            assertEquals(HttpUtils.toHexString(md5), HttpUtils.toHexString(getBlob.getInfo().getHash()));

            // Test GET with options
            // Non-matching ETag
            try {
                context.getApi().getObject(containerName, object.getInfo().getName(),
                        GetOptions.Builder.ifETagDoesntMatch(newEtag));
            } catch (HttpResponseException e) {
                assertEquals(e.getResponse().getStatusCode(), 304);
            }

            // Matching ETag
            getBlob = context.getApi().getObject(containerName, object.getInfo().getName(),
                    GetOptions.Builder.ifETagMatches(newEtag));
            assertEquals(getBlob.getInfo().getHash(), HttpUtils.fromHexString(newEtag));
            getBlob = context.getApi().getObject(containerName, object.getInfo().getName(),
                    GetOptions.Builder.startAt(8));
            assertEquals(IOUtils.toString((InputStream) getBlob.getData()), data.substring(8));

        } finally {
            returnContainer(containerName);
        }
    }

    private CFObject newCFObject(String data, String key) throws IOException {
        CFObject object = context.getApi().newCFObject();
        object.getInfo().setName(key);
        object.setData(data);
        object.generateMD5();
        object.getInfo().setContentType("text/plain");
        object.getInfo().getMetadata().put("Metadata", "metadata-value");
        return object;
    }

}