/*
 * 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.apache.brooklyn.core.mgmt.persist.jclouds;

import java.io.IOException;

import org.apache.brooklyn.api.mgmt.ManagementContext;
import org.apache.brooklyn.core.entity.Entities;
import org.apache.brooklyn.core.internal.BrooklynProperties;
import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests;
import org.apache.brooklyn.location.jclouds.BlobStoreContextFactoryImpl;
import org.apache.brooklyn.location.jclouds.JcloudsLocation;
import org.apache.brooklyn.util.stream.Streams;
import org.apache.brooklyn.util.text.Identifiers;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.PageSet;
import org.jclouds.blobstore.domain.StorageMetadata;
import org.jclouds.blobstore.options.ListContainerOptions;
import org.testng.Assert;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

@Test(groups={"Live", "Live-sanity"})
public class BlobStoreTest {

    /**
     * Live tests as written require a location defined as follows:
     * 
     * <code>
     * brooklyn.location.named.brooklyn-jclouds-objstore-test-1==jclouds:openstack-swift:https://ams01.objectstorage.softlayer.net/auth/v1.0
     * brooklyn.location.named.brooklyn-jclouds-objstore-test-1.identity=IBMOS1234-5:yourname
     * brooklyn.location.named.brooklyn-jclouds-objstore-test-1.credential=0123abcd.......
     * brooklyn.location.named.brooklyn-jclouds-objstore-test-1.jclouds.keystone.credential-type=tempAuthCredentials
     * </code>
     */
    public static final String PERSIST_TO_OBJECT_STORE_FOR_TEST_SPEC = "named:brooklyn-jclouds-objstore-test-1";
    
    public static final String CONTAINER_PREFIX = "brooklyn-persistence-test";
    
    private String locationSpec = PERSIST_TO_OBJECT_STORE_FOR_TEST_SPEC;
    
    private JcloudsLocation location;
    private BlobStoreContext context;

    private ManagementContext mgmt;
    private String testContainerName;

    @BeforeMethod(alwaysRun=true)
    public void setup() {
        testContainerName = CONTAINER_PREFIX+"-"+Identifiers.makeRandomId(8);
        mgmt = new LocalManagementContextForTests(BrooklynProperties.Factory.newDefault());
        location = (JcloudsLocation) mgmt.getLocationRegistry().getLocationManaged(locationSpec);
        context = BlobStoreContextFactoryImpl.INSTANCE.newBlobStoreContext(location);
    }
    
    @AfterMethod(alwaysRun=true)
    public void teardown() {
        Entities.destroyAll(mgmt);
    }
    
    public void testCreateListDestroyContainer() throws IOException {
        context.getBlobStore().createContainerInLocation(null, testContainerName);
        context.getBlobStore().list(testContainerName);
        PageSet<? extends StorageMetadata> ps = context.getBlobStore().list();
        assertHasItemNamed(ps, testContainerName);
        
        Blob b = context.getBlobStore().blobBuilder("my-blob-1").payload(Streams.newInputStreamWithContents("hello world")).build();
        context.getBlobStore().putBlob(testContainerName, b);
        
        Blob b2 = context.getBlobStore().getBlob(testContainerName, "my-blob-1");
        Assert.assertEquals(Streams.readFullyStringAndClose(b2.getPayload().openStream()), "hello world");
        
        context.getBlobStore().deleteContainer(testContainerName);
    }
    
    public void testCreateListDestroySimpleDirInContainer() throws IOException {
        context.getBlobStore().createContainerInLocation(null, testContainerName);
        context.getBlobStore().createDirectory(testContainerName, "my-dir-1");
        
        PageSet<? extends StorageMetadata> ps = context.getBlobStore().list(testContainerName);
        assertHasItemNamed(ps, "my-dir-1");
        
        Blob b = context.getBlobStore().blobBuilder("my-blob-1").payload(Streams.newInputStreamWithContents("hello world")).build();
        context.getBlobStore().putBlob(testContainerName+"/"+"my-dir-1", b);
        
        ps = context.getBlobStore().list(testContainerName, ListContainerOptions.Builder.inDirectory("my-dir-1"));
        assertHasItemNamed(ps, "my-dir-1/my-blob-1");

        // both these syntaxes work:
        Blob b2 = context.getBlobStore().getBlob(testContainerName+"/"+"my-dir-1", "my-blob-1");
        Assert.assertEquals(Streams.readFullyStringAndClose(b2.getPayload().openStream()), "hello world");

        Blob b3 = context.getBlobStore().getBlob(testContainerName, "my-dir-1"+"/"+"my-blob-1");
        Assert.assertEquals(Streams.readFullyStringAndClose(b3.getPayload().openStream()), "hello world");

        context.getBlobStore().deleteContainer(testContainerName);
    }

    static void assertHasItemNamed(PageSet<? extends StorageMetadata> ps, String name) {
        if (!hasItemNamed(ps, name))
            Assert.fail("No item named '"+name+"' in "+ps);
    }

    static boolean hasItemNamed(PageSet<? extends StorageMetadata> ps, String name) {
        for (StorageMetadata sm: ps)
            if (name==null || name.equals(sm.getName())) return true;
        return false;
    }

}
