mirror of https://github.com/apache/jclouds.git
JCLOUDS-929: Implement generic delimiter support.
The patch adds delimiter option support in the generic blob store interface. A live integration test is added to verify that jclouds correctly lists objects separated by a delimiter.
This commit is contained in:
parent
1fe90b03c9
commit
a29d75a5d1
|
@ -30,4 +30,9 @@ public class AtmosContainerLiveTest extends BaseContainerLiveTest {
|
||||||
public void testContainerListWithPrefix() {
|
public void testContainerListWithPrefix() {
|
||||||
throw new SkipException("Prefix option has not been plumbed down to Atmos");
|
throw new SkipException("Prefix option has not been plumbed down to Atmos");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void testDelimiterList() {
|
||||||
|
throw new SkipException("Delimiter support is not yet implemented");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.CRED
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
import org.jclouds.blobstore.integration.internal.BaseContainerLiveTest;
|
import org.jclouds.blobstore.integration.internal.BaseContainerLiveTest;
|
||||||
|
import org.testng.SkipException;
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
@Test(groups = "live", testName = "SwiftContainerLiveTest")
|
@Test(groups = "live", testName = "SwiftContainerLiveTest")
|
||||||
|
@ -36,4 +37,10 @@ public class SwiftContainerLiveTest extends BaseContainerLiveTest {
|
||||||
setIfTestSystemPropertyPresent(props, CREDENTIAL_TYPE);
|
setIfTestSystemPropertyPresent(props, CREDENTIAL_TYPE);
|
||||||
return props;
|
return props;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Test
|
||||||
|
public void testDelimiterList() {
|
||||||
|
throw new SkipException("Delimiter support is not yet implemented");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ package org.jclouds.s3.blobstore.integration;
|
||||||
|
|
||||||
import org.jclouds.blobstore.integration.internal.BaseBlobStoreIntegrationTest;
|
import org.jclouds.blobstore.integration.internal.BaseBlobStoreIntegrationTest;
|
||||||
import org.jclouds.blobstore.integration.internal.BaseContainerLiveTest;
|
import org.jclouds.blobstore.integration.internal.BaseContainerLiveTest;
|
||||||
|
import org.testng.SkipException;
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
@Test(groups = "live", testName = "S3ContainerLiveTest")
|
@Test(groups = "live", testName = "S3ContainerLiveTest")
|
||||||
|
@ -27,4 +28,10 @@ public class S3ContainerLiveTest extends BaseContainerLiveTest {
|
||||||
provider = "s3";
|
provider = "s3";
|
||||||
BaseBlobStoreIntegrationTest.SANITY_CHECK_RETURNED_BUCKET_NAME = true;
|
BaseBlobStoreIntegrationTest.SANITY_CHECK_RETURNED_BUCKET_NAME = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Test
|
||||||
|
public void testDelimiterList() {
|
||||||
|
throw new SkipException("not yet implemented");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,4 +58,9 @@ public class SwiftContainerLiveTest extends BaseContainerLiveTest {
|
||||||
public void testContainerListWithPrefix() {
|
public void testContainerListWithPrefix() {
|
||||||
throw new SkipException("Prefix option has not been plumbed down to Swift");
|
throw new SkipException("Prefix option has not been plumbed down to Swift");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void testDelimiterList() {
|
||||||
|
throw new SkipException("The test fails as the path parameter elides subdirectories");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@ public class ListContainerOptions extends ListOptions implements Cloneable {
|
||||||
public static final ImmutableListContainerOptions NONE = new ImmutableListContainerOptions(
|
public static final ImmutableListContainerOptions NONE = new ImmutableListContainerOptions(
|
||||||
new ListContainerOptions());
|
new ListContainerOptions());
|
||||||
|
|
||||||
|
private String delimiter;
|
||||||
private String dir;
|
private String dir;
|
||||||
private String prefix;
|
private String prefix;
|
||||||
private boolean recursive;
|
private boolean recursive;
|
||||||
|
@ -48,12 +49,13 @@ public class ListContainerOptions extends ListOptions implements Cloneable {
|
||||||
}
|
}
|
||||||
|
|
||||||
ListContainerOptions(Integer maxKeys, String marker, String dir, boolean recursive,
|
ListContainerOptions(Integer maxKeys, String marker, String dir, boolean recursive,
|
||||||
boolean detailed, String prefix) {
|
boolean detailed, String prefix, String delimiter) {
|
||||||
super(maxKeys, marker);
|
super(maxKeys, marker);
|
||||||
this.dir = dir;
|
this.dir = dir;
|
||||||
this.recursive = recursive;
|
this.recursive = recursive;
|
||||||
this.detailed = detailed;
|
this.detailed = detailed;
|
||||||
this.prefix = prefix;
|
this.prefix = prefix;
|
||||||
|
this.delimiter = delimiter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ImmutableListContainerOptions extends ListContainerOptions {
|
public static class ImmutableListContainerOptions extends ListContainerOptions {
|
||||||
|
@ -124,6 +126,16 @@ public class ListContainerOptions extends ListOptions implements Cloneable {
|
||||||
return delegate.clone();
|
return delegate.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ListContainerOptions delimiter(String delimiterString) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDelimiter() {
|
||||||
|
return delegate.getDelimiter();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return delegate.toString();
|
return delegate.toString();
|
||||||
|
@ -135,6 +147,10 @@ public class ListContainerOptions extends ListOptions implements Cloneable {
|
||||||
return dir;
|
return dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getDelimiter() {
|
||||||
|
return delimiter;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isRecursive() {
|
public boolean isRecursive() {
|
||||||
return recursive;
|
return recursive;
|
||||||
}
|
}
|
||||||
|
@ -200,6 +216,15 @@ public class ListContainerOptions extends ListOptions implements Cloneable {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* specify the delimiter to be used when listing
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public ListContainerOptions delimiter(String delimiterString) {
|
||||||
|
this.delimiter = delimiterString;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public static class Builder {
|
public static class Builder {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -249,11 +274,18 @@ public class ListContainerOptions extends ListOptions implements Cloneable {
|
||||||
ListContainerOptions options = new ListContainerOptions();
|
ListContainerOptions options = new ListContainerOptions();
|
||||||
return options.prefix(prefix);
|
return options.prefix(prefix);
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* @see ListContainerOptions#delimiter(String)
|
||||||
|
*/
|
||||||
|
public static ListContainerOptions delimiter(String delimiterString) {
|
||||||
|
ListContainerOptions options = new ListContainerOptions();
|
||||||
|
return options.delimiter(delimiterString);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ListContainerOptions clone() {
|
public ListContainerOptions clone() {
|
||||||
return new ListContainerOptions(getMaxResults(), getMarker(), dir, recursive, detailed, prefix);
|
return new ListContainerOptions(getMaxResults(), getMarker(), dir, recursive, detailed, prefix, delimiter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -382,6 +382,9 @@ public class DeleteAllKeysInList implements ClearListStrategy, ClearContainerStr
|
||||||
|
|
||||||
public void execute(final String containerName,
|
public void execute(final String containerName,
|
||||||
ListContainerOptions listOptions) {
|
ListContainerOptions listOptions) {
|
||||||
|
if (listOptions.getDelimiter() != null || listOptions.getPrefix() != null) {
|
||||||
|
throw new IllegalArgumentException("Prefix and delimiter support has not yet been added");
|
||||||
|
}
|
||||||
final AtomicBoolean deleteFailure = new AtomicBoolean();
|
final AtomicBoolean deleteFailure = new AtomicBoolean();
|
||||||
int retries = maxErrors;
|
int retries = maxErrors;
|
||||||
|
|
||||||
|
|
|
@ -133,6 +133,29 @@ public class BaseContainerLiveTest extends BaseBlobStoreIntegrationTest {
|
||||||
blobStore.putBlob(containerName, blobStore.blobBuilder("foo").payload("").build());
|
blobStore.putBlob(containerName, blobStore.blobBuilder("foo").payload("").build());
|
||||||
checkEqualNames(ImmutableSet.of(prefix, prefix + "foo", prefix + "bar"),
|
checkEqualNames(ImmutableSet.of(prefix, prefix + "foo", prefix + "bar"),
|
||||||
blobStore.list(containerName, ListContainerOptions.Builder.prefix(prefix)));
|
blobStore.list(containerName, ListContainerOptions.Builder.prefix(prefix)));
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
returnContainer(containerName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(groups = "live")
|
||||||
|
public void testDelimiterList() throws InterruptedException {
|
||||||
|
final String containerName = getContainerName();
|
||||||
|
BlobStore blobStore = view.getBlobStore();
|
||||||
|
String payload = "foo";
|
||||||
|
try {
|
||||||
|
blobStore.putBlob(containerName, blobStore.blobBuilder("test/foo/foo").payload(payload).build());
|
||||||
|
blobStore.putBlob(containerName, blobStore.blobBuilder("test/bar/foo").payload(payload).build());
|
||||||
|
blobStore.putBlob(containerName, blobStore.blobBuilder("foo").payload(payload).build());
|
||||||
|
blobStore.putBlob(containerName, blobStore.blobBuilder("test-foo").payload(payload).build());
|
||||||
|
blobStore.putBlob(containerName, blobStore.blobBuilder("test-bar").payload(payload).build());
|
||||||
|
checkEqualNames(ImmutableSet.of("foo", "test/", "test-foo", "test-bar"), blobStore.list(
|
||||||
|
containerName, ListContainerOptions.Builder.delimiter("/")));
|
||||||
|
checkEqualNames(ImmutableSet.of("test/foo/foo", "test/bar/foo", "foo", "test-foo", "test-bar"),
|
||||||
|
blobStore.list(containerName, ListContainerOptions.Builder.delimiter("\\")));
|
||||||
|
checkEqualNames(ImmutableSet.of("test-", "test/foo/foo", "test/bar/foo", "foo"), blobStore.list(
|
||||||
|
containerName, ListContainerOptions.Builder.delimiter("-")));
|
||||||
} finally {
|
} finally {
|
||||||
returnContainer(containerName);
|
returnContainer(containerName);
|
||||||
}
|
}
|
||||||
|
@ -173,5 +196,4 @@ public class BaseContainerLiveTest extends BaseBlobStoreIntegrationTest {
|
||||||
recycleContainerAndAddToPool(containerName);
|
recycleContainerAndAddToPool(containerName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,6 +49,13 @@ public class ListOptionsTest {
|
||||||
assertEquals(options.getDir(), "test");
|
assertEquals(options.getDir(), "test");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDelimiter() {
|
||||||
|
ListContainerOptions options = new ListContainerOptions();
|
||||||
|
options.delimiter("-");
|
||||||
|
assertEquals(options.getDelimiter(), "-");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPathStatic() {
|
public void testPathStatic() {
|
||||||
ListContainerOptions options = inDirectory("test");
|
ListContainerOptions options = inDirectory("test");
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
package org.jclouds.azureblob.blobstore.integration;
|
package org.jclouds.azureblob.blobstore.integration;
|
||||||
|
|
||||||
import org.jclouds.blobstore.integration.internal.BaseContainerLiveTest;
|
import org.jclouds.blobstore.integration.internal.BaseContainerLiveTest;
|
||||||
|
import org.testng.SkipException;
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
@Test(groups = { "live" })
|
@Test(groups = { "live" })
|
||||||
|
@ -24,4 +25,10 @@ public class AzureBlobContainerLiveTest extends BaseContainerLiveTest {
|
||||||
public AzureBlobContainerLiveTest() {
|
public AzureBlobContainerLiveTest() {
|
||||||
provider = "azureblob";
|
provider = "azureblob";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Test
|
||||||
|
public void testDelimiterList() {
|
||||||
|
throw new SkipException("The delimiter support has not been plumbed through to Azure blob");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,4 +34,9 @@ public class HPCloudObjectStorageContainerLiveTest extends BaseContainerLiveTest
|
||||||
@Test
|
@Test
|
||||||
public void testPublicAccessInNonDefaultLocationWithBigBlob() { throw new SkipException("Locations are ignored"); }
|
public void testPublicAccessInNonDefaultLocationWithBigBlob() { throw new SkipException("Locations are ignored"); }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Test
|
||||||
|
public void testDelimiterList() {
|
||||||
|
throw new SkipException("\"path\" parameter elides subdirectories");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue