@Test(timeOut = 5 * 60 * 1000, dependsOnMethods = { "testCreateContainer", "testCreatePublicContainer" })
public void testObjectOperations() throws Exception {
String data = "Here is my data";
// Test PUT with string data, ETag hash, and a piece of metadata
AzureBlob object = getApi().newBlob();
object.getProperties().setName("object");
object.setPayload(data);
Payloads.calculateMD5(object);
object.getProperties().getContentMetadata().setContentType("text/plain");
object.getProperties().getMetadata().put("mykey", "metadata-value");
byte[] md5 = object.getProperties().getContentMetadata().getContentMD5();
String newEtag = getApi().putBlob(privateContainer, object);
assertEquals(base16().lowerCase().encode(md5),
base16().lowerCase().encode(object.getProperties().getContentMetadata().getContentMD5()));
// Test HEAD of missing object
assert getApi().getBlobProperties(privateContainer, "non-existent-object") == null;
// Test HEAD of object
BlobProperties metadata = getApi().getBlobProperties(privateContainer, object.getProperties().getName());
// TODO assertEquals(metadata.getName(),
// object.getProperties().getName());
// we can't check this while hacking around lack of content-md5, as GET of
// the first byte will
// show incorrect length 1, the returned size, as opposed to the real
// length. This is an ok
// tradeoff, as a container list will contain the correct size of the
// objects in an
// inexpensive fashion
// http://code.google.com/p/jclouds/issues/detail?id=92
// assertEquals(metadata.getSize(), data.length());
assertEquals(metadata.getContentMetadata().getContentType(), "text/plain");
// Azure doesn't return the Content-MD5 on head request..
assertEquals(base16().lowerCase().encode(md5),
base16().lowerCase().encode(object.getProperties().getContentMetadata().getContentMD5()));
assertEquals(metadata.getETag(), newEtag);
assertEquals(metadata.getMetadata().entrySet().size(), 1);
assertEquals(metadata.getMetadata().get("mykey"), "metadata-value");
// // Test POST to update object's metadata
// Multimap<String, String> userMetadata = LinkedHashMultimap.create();
// userMetadata.put("New-Metadata-1", "value-1");
// userMetadata.put("New-Metadata-2", "value-2");
// assertTrue(getApi().setBlobProperties(privateContainer,
// object.getProperties().getName(),
// userMetadata));
// Test GET of missing object
assert getApi().getBlob(privateContainer, "non-existent-object") == null;
// Test GET of object (including updated metadata)
AzureBlob getBlob = getApi().getBlob(privateContainer, object.getProperties().getName());
assertEquals(Strings2.toString(getBlob.getPayload()), data);
// TODO assertEquals(getBlob.getName(), object.getProperties().getName());
assertEquals(getBlob.getPayload().getContentMetadata().getContentLength(), Long.valueOf(data.length()));
assertEquals(getBlob.getProperties().getContentMetadata().getContentType(), "text/plain");
assertEquals(base16().lowerCase().encode(md5),
base16().lowerCase().encode(getBlob.getProperties().getContentMetadata().getContentMD5()));
assertEquals(newEtag, getBlob.getProperties().getETag());
// wait until we can update metadata
// assertEquals(getBlob.getProperties().getMetadata().entries().size(),
// 2);
// assertEquals(
// Iterables.getLast(getBlob.getProperties().getMetadata().get("New-Metadata-1")),
// "value-1");
// assertEquals(
// Iterables.getLast(getBlob.getProperties().getMetadata().get("New-Metadata-2")),
// "value-2");
assertEquals(metadata.getMetadata().entrySet().size(), 1);
assertEquals(metadata.getMetadata().get("mykey"), "metadata-value");
// test listing
ListBlobsResponse response = getApi().listBlobs(
privateContainer,
ListBlobsOptions.Builder
.prefix(object.getProperties().getName().substring(0, object.getProperties().getName().length() - 1))
.maxResults(1).includeMetadata());
assertEquals(response.size(), 1);
assertEquals(Iterables.getOnlyElement(response).getName(), object.getProperties().getName());
assertEquals(Iterables.getOnlyElement(response).getMetadata(), ImmutableMap.of("mykey", "metadata-value"));
// Test PUT with invalid ETag (as if object's data was corrupted in
// transit)
String correctEtag = newEtag;
String incorrectEtag = "0" + correctEtag.substring(1);
object.getProperties().setETag(incorrectEtag);
try {
getApi().putBlob(privateContainer, object);
} catch (Throwable e) {
assertEquals(e.getCause().getClass(), HttpResponseException.class);
assertEquals(((HttpResponseException) e.getCause()).getResponse().getStatusCode(), 422);
}
ByteArrayInputStream bais = new ByteArrayInputStream(data.getBytes(Charsets.UTF_8));
object = getApi().newBlob();
object.getProperties().setName("chunked-object");
object.setPayload(bais);
object.getPayload().getContentMetadata().setContentLength(Long.valueOf(data.getBytes().length));
newEtag = getApi().putBlob(privateContainer, object);
assertEquals(base16().lowerCase().encode(md5),
base16().lowerCase().encode(getBlob.getProperties().getContentMetadata().getContentMD5()));
// Test GET with options
// Non-matching ETag
try {
getApi().getBlob(privateContainer, object.getProperties().getName(),
GetOptions.Builder.ifETagDoesntMatch(newEtag));
} catch (Exception e) {
HttpResponseException httpEx = Throwables2.getFirstThrowableOfType(e, HttpResponseException.class);
assert (httpEx != null) : "expected http exception, not " + e;
assertEquals(httpEx.getResponse().getStatusCode(), 304);
}
// Matching ETag TODO this shouldn't fail!!!
try {
getBlob = getApi().getBlob(privateContainer, object.getProperties().getName(),
GetOptions.Builder.ifETagMatches(newEtag));
assertEquals(getBlob.getProperties().getETag(), newEtag);
} catch (HttpResponseException e) {
assertEquals(e.getResponse().getStatusCode(), 412);
}
// Range