From 39de027f5af6f001e405b8b51b34ce845e693bb1 Mon Sep 17 00:00:00 2001 From: Alex Heneveld Date: Wed, 19 Nov 2014 13:00:15 +0000 Subject: [PATCH] fix bug *listing* in object store when container name is a virtual path previously if container name contained a /, when listing, all items included container name portions after the initial /. better test coverage now too. --- .../JcloudsBlobStoreBasedObjectStore.java | 6 +- .../JcloudsBlobStoreBasedObjectStoreTest.java | 119 ++++++++++++++++++ .../main/java/brooklyn/util/text/Strings.java | 2 +- 3 files changed, 125 insertions(+), 2 deletions(-) create mode 100644 locations/jclouds/src/test/java/brooklyn/entity/rebind/persister/jclouds/JcloudsBlobStoreBasedObjectStoreTest.java diff --git a/locations/jclouds/src/main/java/brooklyn/entity/rebind/persister/jclouds/JcloudsBlobStoreBasedObjectStore.java b/locations/jclouds/src/main/java/brooklyn/entity/rebind/persister/jclouds/JcloudsBlobStoreBasedObjectStore.java index 93759d6b0b..6acaa97cb1 100644 --- a/locations/jclouds/src/main/java/brooklyn/entity/rebind/persister/jclouds/JcloudsBlobStoreBasedObjectStore.java +++ b/locations/jclouds/src/main/java/brooklyn/entity/rebind/persister/jclouds/JcloudsBlobStoreBasedObjectStore.java @@ -179,7 +179,10 @@ public List listContentsWithSubPath(final String parentSubPath) { .transform(new Function() { @Override public String apply(@javax.annotation.Nullable StorageMetadata input) { - return input.getName(); + String result = input.getName(); + result = Strings.removeFromStart(result, containerSubPath); + result = Strings.removeFromStart(result, "/"); + return result; } }).toList(); } @@ -205,6 +208,7 @@ public void injectManagementContext(ManagementContext mgmt) { this.mgmt = mgmt; } + @SuppressWarnings("deprecation") @Override public void prepareForSharedUse(@Nullable PersistMode persistMode, HighAvailabilityMode haMode) { if (mgmt==null) throw new NullPointerException("Must inject ManagementContext before preparing "+this); diff --git a/locations/jclouds/src/test/java/brooklyn/entity/rebind/persister/jclouds/JcloudsBlobStoreBasedObjectStoreTest.java b/locations/jclouds/src/test/java/brooklyn/entity/rebind/persister/jclouds/JcloudsBlobStoreBasedObjectStoreTest.java new file mode 100644 index 0000000000..acb5df7b65 --- /dev/null +++ b/locations/jclouds/src/test/java/brooklyn/entity/rebind/persister/jclouds/JcloudsBlobStoreBasedObjectStoreTest.java @@ -0,0 +1,119 @@ +/* + * 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 brooklyn.entity.rebind.persister.jclouds; + + +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.Assert; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import brooklyn.entity.basic.Entities; +import brooklyn.entity.rebind.persister.BrooklynPersistenceUtils; +import brooklyn.entity.rebind.persister.PersistenceObjectStore; +import brooklyn.entity.rebind.persister.PersistenceObjectStore.StoreObjectAccessor; +import brooklyn.management.internal.LocalManagementContext; +import brooklyn.test.entity.LocalManagementContextForTests; +import brooklyn.util.collections.MutableList; +import brooklyn.util.text.Identifiers; +import brooklyn.util.time.Duration; + +import com.google.common.base.Stopwatch; + +/** + * @author Andrea Turli + */ +@Test(groups={"Live", "Live-sanity"}) +public class JcloudsBlobStoreBasedObjectStoreTest { + + private static final Logger log = LoggerFactory.getLogger(JcloudsBlobStoreBasedObjectStoreTest.class); + + private List objectStores = MutableList.of();; + private LocalManagementContext mgmt; + + @BeforeMethod(alwaysRun=true) + public void setUp() throws Exception { + mgmt = LocalManagementContextForTests.builder(true).useDefaultProperties().build(); + } + + @AfterMethod(alwaysRun=true) + public void tearDown() throws Exception { + for (PersistenceObjectStore store: objectStores) store.deleteCompletely(); + Entities.destroyAll(mgmt); + objectStores.clear(); + } + + public PersistenceObjectStore newObjectStore(String spec, String container) { + PersistenceObjectStore newObjectStore = BrooklynPersistenceUtils.newPersistenceObjectStore(mgmt, spec, container); + objectStores.add(newObjectStore); + return newObjectStore; + } + + @Test(groups={"Integration"}) + public void testLocalhost() throws Exception { + doTestWithStore( newObjectStore(null, + BlobStoreTest.CONTAINER_PREFIX+"-"+Identifiers.makeRandomId(4)) ); + } + + @Test(groups={"Integration"}) + public void testLocalhostWithSubPathInContainerName() throws Exception { + doTestWithStore( newObjectStore(null, + BlobStoreTest.CONTAINER_PREFIX+"-"+Identifiers.makeRandomId(4)+"/subpath1/subpath2") ); + } + + @Test(groups={"Live", "Live-sanity"}) + public void testJclouds() throws Exception { + doTestWithStore( newObjectStore(BlobStoreTest.PERSIST_TO_OBJECT_STORE_FOR_TEST_SPEC, + BlobStoreTest.CONTAINER_PREFIX+"-"+Identifiers.makeRandomId(4)) ); + } + + @Test(groups={"Live", "Live-sanity"}) + public void testJcloudsWithSubPathInContainerName() throws Exception { + doTestWithStore( newObjectStore(BlobStoreTest.PERSIST_TO_OBJECT_STORE_FOR_TEST_SPEC, + BlobStoreTest.CONTAINER_PREFIX+"-"+Identifiers.makeRandomId(4)+"/subpath1/subpath2") ); + } + + protected void doTestWithStore(PersistenceObjectStore objectStore) { + log.info("testing against "+objectStore.getSummaryName()); + + objectStore.createSubPath("foo"); + StoreObjectAccessor f = objectStore.newAccessor("foo/file1.txt"); + Assert.assertFalse(f.exists()); + + Stopwatch timer = Stopwatch.createStarted(); + f.append("Hello world"); + log.info("created in "+Duration.of(timer)); + timer.reset(); + Assert.assertEquals(f.get(), "Hello world"); + log.info("retrieved in "+Duration.of(timer)); + Assert.assertTrue(f.exists()); + + timer.reset(); + List files = objectStore.listContentsWithSubPath("foo"); + log.info("list retrieved in "+Duration.of(timer)+"; is: "+files); + Assert.assertEquals(files, MutableList.of("foo/file1.txt")); + + f.delete(); + } + +} diff --git a/utils/common/src/main/java/brooklyn/util/text/Strings.java b/utils/common/src/main/java/brooklyn/util/text/Strings.java index 03b7c67b7d..7145eaa76e 100644 --- a/utils/common/src/main/java/brooklyn/util/text/Strings.java +++ b/utils/common/src/main/java/brooklyn/util/text/Strings.java @@ -150,7 +150,7 @@ public static String removeAllFromEnd(String string, String ...suffixes) { public static String removeFromStart(String string, String ...prefixes) { if (isEmpty(string)) return string; for (String prefix : prefixes) - if (string.startsWith(prefix)) return string.substring(prefix.length()); + if (prefix!=null && string.startsWith(prefix)) return string.substring(prefix.length()); return string; }