mirror of https://github.com/apache/jclouds.git
JCLOUDS-251: Swift: Delete chunks when deleting a multipart blob
Also: - Make SwiftBlobIntegrationLiveTest.testMultipartChunkedFileStream more realistic by uploading a file large enough to be split into parts. - JavaDoc fixes for SwiftBlobStore: don't reference nonexistent methods.
This commit is contained in:
parent
d6bb789efb
commit
44e8487230
|
@ -16,10 +16,15 @@
|
||||||
*/
|
*/
|
||||||
package org.jclouds.cloudfiles.blobstore.integration;
|
package org.jclouds.cloudfiles.blobstore.integration;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.jclouds.blobstore.BlobStore;
|
||||||
import org.jclouds.blobstore.domain.Blob;
|
import org.jclouds.blobstore.domain.Blob;
|
||||||
import org.jclouds.openstack.swift.blobstore.integration.SwiftBlobIntegrationLiveTest;
|
import org.jclouds.openstack.swift.blobstore.integration.SwiftBlobIntegrationLiveTest;
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import static org.testng.Assert.assertEquals;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author Adrian Cole
|
* @author Adrian Cole
|
||||||
|
@ -38,4 +43,22 @@ public class CloudFilesBlobIntegrationLiveTest extends SwiftBlobIntegrationLiveT
|
||||||
.getMetadata().getContentMetadata().getContentDisposition();
|
.getMetadata().getContentMetadata().getContentDisposition();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(groups = { "integration", "live" })
|
||||||
|
public void testChunksAreDeletedWhenMultipartBlobIsDeleted() throws IOException, InterruptedException {
|
||||||
|
String containerName = getContainerName();
|
||||||
|
try {
|
||||||
|
BlobStore blobStore = view.getBlobStore();
|
||||||
|
|
||||||
|
long countBefore = blobStore.countBlobs(containerName);
|
||||||
|
String blobName = "deleteme.txt";
|
||||||
|
addMultipartBlobToContainer(containerName, blobName);
|
||||||
|
|
||||||
|
blobStore.removeBlob(containerName, blobName);
|
||||||
|
long countAfter = blobStore.countBlobs(containerName);
|
||||||
|
|
||||||
|
assertEquals(countAfter, countBefore);
|
||||||
|
} finally {
|
||||||
|
returnContainer(containerName);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,8 +16,10 @@
|
||||||
*/
|
*/
|
||||||
package org.jclouds.openstack.swift.blobstore;
|
package org.jclouds.openstack.swift.blobstore;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkArgument;
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
import static org.jclouds.blobstore.util.BlobStoreUtils.createParentIfNeededAsync;
|
import static org.jclouds.blobstore.util.BlobStoreUtils.createParentIfNeededAsync;
|
||||||
|
import static org.jclouds.openstack.swift.options.ListContainerOptions.Builder.withPrefix;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
@ -25,6 +27,7 @@ import javax.inject.Inject;
|
||||||
import javax.inject.Provider;
|
import javax.inject.Provider;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import org.jclouds.blobstore.BlobStoreContext;
|
import org.jclouds.blobstore.BlobStoreContext;
|
||||||
import org.jclouds.blobstore.domain.Blob;
|
import org.jclouds.blobstore.domain.Blob;
|
||||||
import org.jclouds.blobstore.domain.BlobMetadata;
|
import org.jclouds.blobstore.domain.BlobMetadata;
|
||||||
|
@ -50,8 +53,11 @@ import org.jclouds.openstack.swift.blobstore.functions.ObjectToBlob;
|
||||||
import org.jclouds.openstack.swift.blobstore.functions.ObjectToBlobMetadata;
|
import org.jclouds.openstack.swift.blobstore.functions.ObjectToBlobMetadata;
|
||||||
import org.jclouds.openstack.swift.blobstore.strategy.internal.MultipartUploadStrategy;
|
import org.jclouds.openstack.swift.blobstore.strategy.internal.MultipartUploadStrategy;
|
||||||
import org.jclouds.openstack.swift.domain.ContainerMetadata;
|
import org.jclouds.openstack.swift.domain.ContainerMetadata;
|
||||||
|
import org.jclouds.openstack.swift.domain.MutableObjectInfoWithMetadata;
|
||||||
|
import org.jclouds.openstack.swift.domain.ObjectInfo;
|
||||||
|
|
||||||
import com.google.common.base.Function;
|
import com.google.common.base.Function;
|
||||||
|
import com.google.common.base.Strings;
|
||||||
import com.google.common.base.Supplier;
|
import com.google.common.base.Supplier;
|
||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
|
|
||||||
|
@ -118,7 +124,7 @@ public class SwiftBlobStore extends BaseBlobStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This implementation invokes {@link CommonSwiftClient#putBucketInRegion}
|
* This implementation invokes {@link CommonSwiftClient#createContainer}
|
||||||
*
|
*
|
||||||
* @param location
|
* @param location
|
||||||
* currently ignored
|
* currently ignored
|
||||||
|
@ -145,7 +151,7 @@ public class SwiftBlobStore extends BaseBlobStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This implementation invokes {@link CommonSwiftClient#blobExists}
|
* This implementation invokes {@link CommonSwiftClient#objectExists}
|
||||||
*
|
*
|
||||||
* @param container
|
* @param container
|
||||||
* container name
|
* container name
|
||||||
|
@ -225,7 +231,53 @@ public class SwiftBlobStore extends BaseBlobStore {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void removeBlob(String container, String key) {
|
public void removeBlob(String container, String key) {
|
||||||
|
String objectManifest = getObjectManifestOrNull(container, key);
|
||||||
|
|
||||||
sync.removeObject(container, key);
|
sync.removeObject(container, key);
|
||||||
|
|
||||||
|
if (!Strings.isNullOrEmpty(objectManifest)) {
|
||||||
|
removeObjectsWithPrefix(objectManifest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getObjectManifestOrNull(String container, String key) {
|
||||||
|
MutableObjectInfoWithMetadata objectInfo = sync.getObjectInfo(container, key);
|
||||||
|
return objectInfo == null ? null : objectInfo.getObjectManifest();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeObjectsWithPrefix(String containerAndPrefix) {
|
||||||
|
String[] parts = splitContainerAndKey(containerAndPrefix);
|
||||||
|
|
||||||
|
String container = parts[0];
|
||||||
|
String prefix = parts[1];
|
||||||
|
|
||||||
|
removeObjectsWithPrefix(container, prefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
static String[] splitContainerAndKey(String containerAndKey) {
|
||||||
|
String[] parts = containerAndKey.split("/", 2);
|
||||||
|
checkArgument(parts.length == 2,
|
||||||
|
"No / separator found in \"%s\"",
|
||||||
|
containerAndKey);
|
||||||
|
return parts;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeObjectsWithPrefix(String container, String prefix) {
|
||||||
|
String nextMarker = null;
|
||||||
|
do {
|
||||||
|
org.jclouds.openstack.swift.options.ListContainerOptions listContainerOptions =
|
||||||
|
withPrefix(prefix);
|
||||||
|
if (nextMarker != null) {
|
||||||
|
listContainerOptions = listContainerOptions.afterMarker(nextMarker);
|
||||||
|
}
|
||||||
|
|
||||||
|
PageSet<ObjectInfo> chunks = sync.listObjects(container, listContainerOptions);
|
||||||
|
for (ObjectInfo chunk : chunks) {
|
||||||
|
sync.removeObject(container, chunk.getName());
|
||||||
|
}
|
||||||
|
nextMarker = chunks.getNextMarker();
|
||||||
|
} while (nextMarker != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -48,4 +48,7 @@ public interface MutableObjectInfoWithMetadata extends ObjectInfo {
|
||||||
|
|
||||||
Map<String, String> getMetadata();
|
Map<String, String> getMetadata();
|
||||||
|
|
||||||
|
String getObjectManifest();
|
||||||
|
|
||||||
|
void setObjectManifest(String objectManifest);
|
||||||
}
|
}
|
||||||
|
|
|
@ -147,4 +147,14 @@ public class DelegatingMutableObjectInfoWithMetadata extends BaseMutableContentM
|
||||||
public URI getUri() {
|
public URI getUri() {
|
||||||
return delegate.getUri();
|
return delegate.getUri();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setObjectManifest(String objectManifest) {
|
||||||
|
delegate.setObjectManifest(objectManifest);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getObjectManifest() {
|
||||||
|
return delegate.getObjectManifest();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,7 @@ public class MutableObjectInfoWithMetadataImpl implements MutableObjectInfoWithM
|
||||||
private byte[] hash;
|
private byte[] hash;
|
||||||
private String contentType = MediaType.APPLICATION_OCTET_STREAM;
|
private String contentType = MediaType.APPLICATION_OCTET_STREAM;
|
||||||
private Date lastModified;
|
private Date lastModified;
|
||||||
|
private String objectManifest;
|
||||||
private final Map<String, String> metadata = Maps.newLinkedHashMap();
|
private final Map<String, String> metadata = Maps.newLinkedHashMap();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -121,6 +122,7 @@ public class MutableObjectInfoWithMetadataImpl implements MutableObjectInfoWithM
|
||||||
int result = 1;
|
int result = 1;
|
||||||
result = prime * result + ((container == null) ? 0 : container.hashCode());
|
result = prime * result + ((container == null) ? 0 : container.hashCode());
|
||||||
result = prime * result + ((name == null) ? 0 : name.hashCode());
|
result = prime * result + ((name == null) ? 0 : name.hashCode());
|
||||||
|
result = prime * result + ((objectManifest == null) ? 0 : objectManifest.hashCode());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,6 +145,11 @@ public class MutableObjectInfoWithMetadataImpl implements MutableObjectInfoWithM
|
||||||
return false;
|
return false;
|
||||||
} else if (!name.equals(other.name))
|
} else if (!name.equals(other.name))
|
||||||
return false;
|
return false;
|
||||||
|
if (objectManifest == null) {
|
||||||
|
if (other.objectManifest != null)
|
||||||
|
return false;
|
||||||
|
} else if (!objectManifest.equals(other.objectManifest))
|
||||||
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,10 +203,20 @@ public class MutableObjectInfoWithMetadataImpl implements MutableObjectInfoWithM
|
||||||
return uri;
|
return uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getObjectManifest() {
|
||||||
|
return objectManifest;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setObjectManifest(String objectManifest) {
|
||||||
|
this.objectManifest = objectManifest;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return String.format("[name=%s, container=%s, uri=%s, bytes=%s, contentType=%s, lastModified=%s, hash=%s]", name,
|
return String.format("[name=%s, container=%s, uri=%s, bytes=%s, contentType=%s, lastModified=%s, hash=%s, objectManifest=%s]",
|
||||||
container, uri, bytes, contentType, lastModified, Arrays.toString(hash));
|
name, container, uri, bytes, contentType, lastModified, Arrays.toString(hash), objectManifest);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,6 +65,8 @@ public class ParseObjectInfoFromHeaders implements Function<HttpResponse, Mutabl
|
||||||
if (eTagHeader != null) {
|
if (eTagHeader != null) {
|
||||||
to.setHash(ETagUtils.convertHexETagToByteArray(eTagHeader));
|
to.setHash(ETagUtils.convertHexETagToByteArray(eTagHeader));
|
||||||
}
|
}
|
||||||
|
to.setObjectManifest(from.getFirstHeaderOrNull("X-Object-Manifest"));
|
||||||
|
|
||||||
return to;
|
return to;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* 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.openstack.swift.blobstore;
|
||||||
|
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import static org.testng.Assert.assertEquals;
|
||||||
|
|
||||||
|
@Test(groups = "unit")
|
||||||
|
public class SwiftBlobStoreTest {
|
||||||
|
@Test
|
||||||
|
public void testSplitContainerAndKey() {
|
||||||
|
String container = "test-container";
|
||||||
|
String key = "key/with/some/slashes/in/it/and/a/trailing/slash/";
|
||||||
|
|
||||||
|
String containerAndKey = container + "/" + key;
|
||||||
|
|
||||||
|
String[] split = SwiftBlobStore.splitContainerAndKey(containerAndKey);
|
||||||
|
String actualContainer = split[0];
|
||||||
|
String actualKey = split[1];
|
||||||
|
|
||||||
|
assertEquals(actualContainer, container);
|
||||||
|
assertEquals(actualKey, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expectedExceptions = IllegalArgumentException.class,
|
||||||
|
expectedExceptionsMessageRegExp = "No / separator found in \"not-a-container-and-key\"")
|
||||||
|
public void testSplitContainerAndKeyWithNoSeparator() {
|
||||||
|
SwiftBlobStore.splitContainerAndKey("not-a-container-and-key");
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,11 +21,13 @@ import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import com.google.common.io.ByteStreams;
|
||||||
import org.jclouds.blobstore.BlobStore;
|
import org.jclouds.blobstore.BlobStore;
|
||||||
import org.jclouds.blobstore.domain.Blob;
|
import org.jclouds.blobstore.domain.Blob;
|
||||||
import org.jclouds.blobstore.integration.internal.BaseBlobIntegrationTest;
|
import org.jclouds.blobstore.integration.internal.BaseBlobIntegrationTest;
|
||||||
import org.jclouds.blobstore.options.PutOptions;
|
import org.jclouds.blobstore.options.PutOptions;
|
||||||
import org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties;
|
import org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties;
|
||||||
|
import org.jclouds.openstack.swift.blobstore.strategy.MultipartUpload;
|
||||||
import org.testng.ITestContext;
|
import org.testng.ITestContext;
|
||||||
import org.testng.annotations.BeforeClass;
|
import org.testng.annotations.BeforeClass;
|
||||||
import org.testng.annotations.DataProvider;
|
import org.testng.annotations.DataProvider;
|
||||||
|
@ -34,6 +36,9 @@ import org.testng.annotations.Test;
|
||||||
import com.google.common.io.Files;
|
import com.google.common.io.Files;
|
||||||
import com.google.common.io.InputSupplier;
|
import com.google.common.io.InputSupplier;
|
||||||
|
|
||||||
|
import static org.testng.Assert.assertNotEquals;
|
||||||
|
import static org.testng.Assert.assertTrue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author James Murty
|
* @author James Murty
|
||||||
|
@ -41,15 +46,21 @@ import com.google.common.io.InputSupplier;
|
||||||
*/
|
*/
|
||||||
@Test(groups = "live")
|
@Test(groups = "live")
|
||||||
public class SwiftBlobIntegrationLiveTest extends BaseBlobIntegrationTest {
|
public class SwiftBlobIntegrationLiveTest extends BaseBlobIntegrationTest {
|
||||||
|
/**
|
||||||
|
* Use the minimum part size to minimise the file size that we have to
|
||||||
|
* upload to get a multipart blob thereby make the test run faster
|
||||||
|
*/
|
||||||
|
private static final long PART_SIZE = MultipartUpload.MIN_PART_SIZE;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Properties setupProperties() {
|
protected Properties setupProperties() {
|
||||||
Properties props = super.setupProperties();
|
Properties props = super.setupProperties();
|
||||||
setIfTestSystemPropertyPresent(props, KeystoneProperties.CREDENTIAL_TYPE);
|
setIfTestSystemPropertyPresent(props, KeystoneProperties.CREDENTIAL_TYPE);
|
||||||
|
props.setProperty("jclouds.mpu.parts.size", String.valueOf(PART_SIZE));
|
||||||
return props;
|
return props;
|
||||||
}
|
}
|
||||||
|
|
||||||
private InputSupplier<InputStream> oneHundredOneConstitutions;
|
private InputSupplier<InputStream> oneHundredOneConstitutions;
|
||||||
private byte[] oneHundredOneConstitutionsMD5;
|
|
||||||
|
|
||||||
public SwiftBlobIntegrationLiveTest() {
|
public SwiftBlobIntegrationLiveTest() {
|
||||||
provider = System.getProperty("test.swift.provider", "swift");
|
provider = System.getProperty("test.swift.provider", "swift");
|
||||||
|
@ -66,7 +77,6 @@ public class SwiftBlobIntegrationLiveTest extends BaseBlobIntegrationTest {
|
||||||
public void setUpResourcesOnThisThread(ITestContext testContext) throws Exception {
|
public void setUpResourcesOnThisThread(ITestContext testContext) throws Exception {
|
||||||
super.setUpResourcesOnThisThread(testContext);
|
super.setUpResourcesOnThisThread(testContext);
|
||||||
oneHundredOneConstitutions = getTestDataSupplier();
|
oneHundredOneConstitutions = getTestDataSupplier();
|
||||||
oneHundredOneConstitutionsMD5 = md5Supplier(oneHundredOneConstitutions);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -91,21 +101,54 @@ public class SwiftBlobIntegrationLiveTest extends BaseBlobIntegrationTest {
|
||||||
{ "asteri*k" }, { "{great<r}" }, { "lesst>en" }, { "p|pe" } };
|
{ "asteri*k" }, { "{great<r}" }, { "lesst>en" }, { "p|pe" } };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(groups = { "integration", "live" })
|
||||||
public void testMultipartChunkedFileStream() throws IOException, InterruptedException {
|
public void testMultipartChunkedFileStream() throws IOException, InterruptedException {
|
||||||
Files.copy(oneHundredOneConstitutions, new File("target/const.txt"));
|
|
||||||
String containerName = getContainerName();
|
String containerName = getContainerName();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
BlobStore blobStore = view.getBlobStore();
|
BlobStore blobStore = view.getBlobStore();
|
||||||
blobStore.createContainerInLocation(null, containerName);
|
long countBefore = blobStore.countBlobs(containerName);
|
||||||
Blob blob = blobStore.blobBuilder("const.txt")
|
|
||||||
.payload(new File("target/const.txt")).contentMD5(oneHundredOneConstitutionsMD5).build();
|
addMultipartBlobToContainer(containerName, "const.txt");
|
||||||
blobStore.putBlob(containerName, blob, PutOptions.Builder.multipart());
|
|
||||||
|
long countAfter = blobStore.countBlobs(containerName);
|
||||||
|
assertNotEquals(countBefore, countAfter,
|
||||||
|
"No blob was created");
|
||||||
|
assertTrue(countAfter - countBefore > 1,
|
||||||
|
"A multipart blob wasn't actually created - " +
|
||||||
|
"there was only 1 extra blob but there should be one manifest blob and multiple chunk blobs");
|
||||||
} finally {
|
} finally {
|
||||||
returnContainer(containerName);
|
returnContainer(containerName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void addMultipartBlobToContainer(String containerName, String key) throws IOException {
|
||||||
|
File fileToUpload = createFileBiggerThan(PART_SIZE);
|
||||||
|
|
||||||
|
BlobStore blobStore = view.getBlobStore();
|
||||||
|
blobStore.createContainerInLocation(null, containerName);
|
||||||
|
Blob blob = blobStore.blobBuilder(key)
|
||||||
|
.payload(fileToUpload)
|
||||||
|
.build();
|
||||||
|
blobStore.putBlob(containerName, blob, PutOptions.Builder.multipart());
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private File createFileBiggerThan(long partSize) throws IOException {
|
||||||
|
long copiesNeeded = (partSize / getOneHundredOneConstitutionsLength()) + 1;
|
||||||
|
|
||||||
|
InputSupplier<InputStream> temp = ByteStreams.join(oneHundredOneConstitutions);
|
||||||
|
|
||||||
|
for (int i = 0; i < copiesNeeded; i++) {
|
||||||
|
temp = ByteStreams.join(temp, oneHundredOneConstitutions);
|
||||||
|
}
|
||||||
|
|
||||||
|
File fileToUpload = new File("target/lots-of-const.txt");
|
||||||
|
Files.copy(temp, fileToUpload);
|
||||||
|
|
||||||
|
assertTrue(fileToUpload.length() > partSize);
|
||||||
|
return fileToUpload;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected int getIncorrectContentMD5StatusCode() {
|
protected int getIncorrectContentMD5StatusCode() {
|
||||||
return 422;
|
return 422;
|
||||||
|
|
|
@ -122,6 +122,13 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static long getOneHundredOneConstitutionsLength() throws IOException {
|
||||||
|
if (oneHundredOneConstitutionsLength == 0) {
|
||||||
|
getTestDataSupplier();
|
||||||
|
}
|
||||||
|
return oneHundredOneConstitutionsLength;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempt to capture the issue detailed in
|
* Attempt to capture the issue detailed in
|
||||||
* http://groups.google.com/group/jclouds/browse_thread/thread/4a7c8d58530b287f
|
* http://groups.google.com/group/jclouds/browse_thread/thread/4a7c8d58530b287f
|
||||||
|
|
Loading…
Reference in New Issue