Merge branch 'master' of git://github.com/castlabs/jclouds

* 'master' of git://github.com/castlabs/jclouds:
  added test for range requests with filesystem backend and corrected behavior
  Improve Range handling. * allowing to GET last n bytes. * start from GET range now spec conform (to field empty instead of Long.MAX_VALUE)
This commit is contained in:
Adrian Cole 2011-08-19 14:38:21 -07:00
commit 2a4e89912b
8 changed files with 807 additions and 733 deletions

View File

@ -567,7 +567,7 @@ public class FilesystemAsyncBlobStore extends BaseAsyncBlobStore {
String[] firstLast = s.split("\\-"); String[] firstLast = s.split("\\-");
int offset = Integer.parseInt(firstLast[0]); int offset = Integer.parseInt(firstLast[0]);
int last = Integer.parseInt(firstLast[1]); int last = Integer.parseInt(firstLast[1]);
int length = (last < data.length) ? last + 1 : data.length - offset; int length = last - offset + 1; // the range end is included
out.write(data, offset, length); out.write(data, offset, length);
} else { } else {
return immediateFailedFuture(new IllegalArgumentException("first and last were null!")); return immediateFailedFuture(new IllegalArgumentException("first and last were null!"));

View File

@ -35,7 +35,9 @@ import java.util.Iterator;
import java.util.Properties; import java.util.Properties;
import java.util.Set; import java.util.Set;
import junit.framework.Assert;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.jclouds.blobstore.BlobStore; import org.jclouds.blobstore.BlobStore;
import org.jclouds.blobstore.BlobStoreContext; import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.BlobStoreContextFactory; import org.jclouds.blobstore.BlobStoreContextFactory;
@ -51,6 +53,7 @@ import org.jclouds.blobstore.options.ListContainerOptions;
import org.jclouds.crypto.CryptoStreams; import org.jclouds.crypto.CryptoStreams;
import org.jclouds.filesystem.reference.FilesystemConstants; import org.jclouds.filesystem.reference.FilesystemConstants;
import org.jclouds.filesystem.utils.TestUtils; import org.jclouds.filesystem.utils.TestUtils;
import org.jclouds.io.payloads.StringPayload;
import org.testng.annotations.AfterMethod; import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod; import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test; import org.testng.annotations.Test;
@ -112,7 +115,6 @@ public class FilesystemAsyncBlobStoreTest {
/** /**
* Checks if context parameters are managed in the correct way * Checks if context parameters are managed in the correct way
*
*/ */
public void testParameters() { public void testParameters() {
// no base directory declared in properties // no base directory declared in properties
@ -145,7 +147,7 @@ public class FilesystemAsyncBlobStoreTest {
assertTrue(containersRetrieved.isEmpty(), "List operation returns a not empty set of container"); assertTrue(containersRetrieved.isEmpty(), "List operation returns a not empty set of container");
// Testing list with some containers // Testing list with some containers
String[] containerNames = new String[] { "34343", "aaaa", "bbbbb" }; String[] containerNames = new String[]{"34343", "aaaa", "bbbbb"};
containersCreated = new HashSet<String>(); containersCreated = new HashSet<String>();
for (String containerName : containerNames) { for (String containerName : containerNames) {
blobStore.createContainerInLocation(null, containerName); blobStore.createContainerInLocation(null, containerName);
@ -707,6 +709,27 @@ public class FilesystemAsyncBlobStoreTest {
} }
} }
public void testRanges() throws IOException {
String payload = "abcdefgh";
Blob blob = blobStore.blobBuilder("test").payload(new StringPayload(payload)).build();
blobStore.putBlob(CONTAINER_NAME, blob);
GetOptions getOptionsRangeStartAt = new GetOptions();
getOptionsRangeStartAt.startAt(1);
Blob blobRangeStartAt = blobStore.getBlob(CONTAINER_NAME, blob.getMetadata().getName(), getOptionsRangeStartAt);
Assert.assertEquals("bcdefgh", IOUtils.toString(blobRangeStartAt.getPayload().getInput()));
GetOptions getOptionsRangeTail = new GetOptions();
getOptionsRangeTail.tail(3);
Blob blobRangeTail = blobStore.getBlob(CONTAINER_NAME, blob.getMetadata().getName(), getOptionsRangeTail);
Assert.assertEquals("fgh", IOUtils.toString(blobRangeTail.getPayload().getInput()));
GetOptions getOptionsFragment = new GetOptions();
getOptionsFragment.range(4, 6);
Blob blobFragment = blobStore.getBlob(CONTAINER_NAME, blob.getMetadata().getName(), getOptionsFragment);
Assert.assertEquals("efg", IOUtils.toString(blobFragment.getPayload().getInput()));
}
// public void testInvalidBlobKey() { // public void testInvalidBlobKey() {
// try { // try {
// blobStore.newBlob(File.separator + "testwrongblobkey"); // blobStore.newBlob(File.separator + "testwrongblobkey");

View File

@ -51,11 +51,11 @@ public class BlobToHttpGetOptions implements Function<org.jclouds.blobstore.opti
httpOptions.ifUnmodifiedSince(from.getIfUnmodifiedSince()); httpOptions.ifUnmodifiedSince(from.getIfUnmodifiedSince());
} }
for (String range : from.getRanges()) { for (String range : from.getRanges()) {
String[] firstLast = range.split("\\-"); String[] firstLast = range.split("\\-", 2);
if (firstLast.length == 2) if (!firstLast[0].isEmpty() && !firstLast[1].isEmpty())
httpOptions.range(Long.parseLong(firstLast[0]), Long.parseLong(firstLast[1])); httpOptions.range(Long.parseLong(firstLast[0]), Long.parseLong(firstLast[1]));
else if (range.startsWith("-")) else if (firstLast[0].isEmpty() && !firstLast[1].isEmpty())
httpOptions.tail(Long.parseLong(firstLast[0])); httpOptions.tail(Long.parseLong(firstLast[1]));
else else
httpOptions.startAt(Long.parseLong(firstLast[0])); httpOptions.startAt(Long.parseLong(firstLast[0]));
} }

View File

@ -55,6 +55,9 @@ public class GetOptions {
/** /**
* download the specified range of the object. * download the specified range of the object.
* @param start first offset included in the response
* @param end last offset included in the response (inclusive).
* @return itself to enable daisy-chaining of expressions
*/ */
public GetOptions range(long start, long end) { public GetOptions range(long start, long end) {
checkArgument(start >= 0, "start must be >= 0"); checkArgument(start >= 0, "start must be >= 0");
@ -72,6 +75,16 @@ public class GetOptions {
return this; return this;
} }
/**
* download the specified range of the object starting from the end of the object.
*/
public GetOptions tail(long length) {
checkArgument(length >= 0, "length must be >= 0");
getRanges().add(String.format("-%d", length));
return this;
}
/** /**
* Only return the object if it has changed since this time. * Only return the object if it has changed since this time.
* <p /> * <p />

View File

@ -104,6 +104,29 @@ public class BlobToHttpGetOptionsTest {
} }
@Test
public void testRangesTail(){
org.jclouds.blobstore.options.GetOptions in = new org.jclouds.blobstore.options.GetOptions();
in.tail(1024);
GetOptions expected = new GetOptions();
expected.tail(1024);
assertEquals(fn.apply(in), expected);
}
@Test
public void testRangesStart(){
org.jclouds.blobstore.options.GetOptions in = new org.jclouds.blobstore.options.GetOptions();
in.startAt(1024);
GetOptions expected = new GetOptions();
expected.startAt(1024);
assertEquals(fn.apply(in), expected);
}
@Test(expectedExceptions = { NullPointerException.class, IllegalStateException.class }) @Test(expectedExceptions = { NullPointerException.class, IllegalStateException.class })
public void testNullIsBad() { public void testNullIsBad() {
fn.apply(null); fn.apply(null);

View File

@ -136,6 +136,21 @@ public class GetOptionsTest {
assertEquals(options.getRanges(), ImmutableList.of("0-5", "10-100")); assertEquals(options.getRanges(), ImmutableList.of("0-5", "10-100"));
} }
@Test
public void testRangeStartAt() {
GetOptions options = new GetOptions();
options.startAt(5);
assertEquals(options.getRanges(), ImmutableList.of("5-"));
}
@Test
public void testRangeTail() {
GetOptions options = new GetOptions();
options.tail(5);
assertEquals(options.getRanges(), ImmutableList.of("-5"));
}
@Test @Test
public void testNoRange() { public void testNoRange() {
GetOptions options = new GetOptions(); GetOptions options = new GetOptions();

View File

@ -80,7 +80,7 @@ public class GetOptions extends BaseHttpRequestOptions {
*/ */
public GetOptions startAt(long start) { public GetOptions startAt(long start) {
checkArgument(start >= 0, "start must be >= 0"); checkArgument(start >= 0, "start must be >= 0");
ranges.add(String.format("%d-%d", start, Long.MAX_VALUE)); ranges.add(String.format("%d-", start));
return this; return this;
} }

View File

@ -155,13 +155,13 @@ public class GetOptionsTest {
public void testStartAt() { public void testStartAt() {
GetOptions options = new GetOptions(); GetOptions options = new GetOptions();
options.startAt(100); options.startAt(100);
assertEquals(options.getRange(), "bytes=100-9223372036854775807"); assertEquals(options.getRange(), "bytes=100-");
} }
@Test @Test
public void testStartAtStatic() { public void testStartAtStatic() {
GetOptions options = startAt(100); GetOptions options = startAt(100);
assertEquals(options.getRange(), "bytes=100-9223372036854775807"); assertEquals(options.getRange(), "bytes=100-");
} }
@Test(expectedExceptions = IllegalArgumentException.class) @Test(expectedExceptions = IllegalArgumentException.class)