From a856b014f85fe6adc778de80d94d4410b7e78fd2 Mon Sep 17 00:00:00 2001 From: Josh Friedman Date: Mon, 22 Aug 2016 16:44:48 -0700 Subject: [PATCH 01/11] [Java] Support Custom ClassLoader --- .../src/com/microsoft/azure/storage/core/Utility.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/core/Utility.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/core/Utility.java index 919c04bd869f..dc3c3998382f 100644 --- a/microsoft-azure-storage/src/com/microsoft/azure/storage/core/Utility.java +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/core/Utility.java @@ -120,7 +120,11 @@ public final class Utility { /** * A factory to create SAXParser instances. */ - private static final SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); + private static final ThreadLocal saxParserFactory = new ThreadLocal() { + @Override public SAXParserFactory initialValue() { + return SAXParserFactory.newInstance(); + } + }; /** * A factory to create XMLStreamWriter instances. @@ -664,8 +668,8 @@ public static JsonParser getJsonParser(final InputStream inStream) throws JsonPa * @throws SAXException */ public static SAXParser getSAXParser() throws ParserConfigurationException, SAXException { - saxParserFactory.setNamespaceAware(true); - return saxParserFactory.newSAXParser(); + saxParserFactory.get().setNamespaceAware(true); + return saxParserFactory.get().newSAXParser(); } /** From 0a1e903b2a66361a1ec724816aaa6bc27ca166db Mon Sep 17 00:00:00 2001 From: asorrin-msft Date: Thu, 25 Aug 2016 14:51:38 -0700 Subject: [PATCH 02/11] Fixing bug in getShareQuota and removing unnecessary code. --- .../storage/file/CloudFileShareTests.java | 27 +++++++++++++++---- .../azure/storage/file/CloudFileShare.java | 7 +++-- .../azure/storage/file/FileResponse.java | 11 -------- 3 files changed, 27 insertions(+), 18 deletions(-) diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/CloudFileShareTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/CloudFileShareTests.java index f151a7e117d9..4c3360b66deb 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/CloudFileShareTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/CloudFileShareTests.java @@ -288,25 +288,40 @@ public void testCloudFileSharePermissionsToString() { */ @Test public void testCloudFileShareUploadMetadata() throws StorageException, URISyntaxException { + this.share.getMetadata().put("key1", "value1"); this.share.create(); + Assert.assertEquals(1, this.share.getMetadata().size()); + Assert.assertEquals("value1", this.share.getMetadata().get("key1")); CloudFileShare share2 = this.share.getServiceClient().getShareReference(this.share.getName()); share2.downloadAttributes(); - Assert.assertEquals(0, share2.getMetadata().size()); + Assert.assertEquals(1, share2.getMetadata().size()); + Assert.assertEquals("value1", share2.getMetadata().get("key1")); - this.share.getMetadata().put("key1", "value1"); + this.share.getMetadata().put("key2", "value2"); + + Assert.assertEquals(2, this.share.getMetadata().size()); + Assert.assertEquals("value1", this.share.getMetadata().get("key1")); + Assert.assertEquals("value2", this.share.getMetadata().get("key2")); this.share.uploadMetadata(); + Assert.assertEquals(2, this.share.getMetadata().size()); + Assert.assertEquals("value1", this.share.getMetadata().get("key1")); + Assert.assertEquals("value2", this.share.getMetadata().get("key2")); + share2.downloadAttributes(); - Assert.assertEquals(1, share2.getMetadata().size()); - Assert.assertEquals("value1", share2.getMetadata().get("key1")); + + Assert.assertEquals(2, this.share.getMetadata().size()); + Assert.assertEquals("value1", this.share.getMetadata().get("key1")); + Assert.assertEquals("value2", this.share.getMetadata().get("key2")); Iterable shares = this.share.getServiceClient().listShares(this.share.getName(), ShareListingDetails.METADATA, null, null); for (CloudFileShare share3 : shares) { - Assert.assertEquals(1, share3.getMetadata().size()); + Assert.assertEquals(2, share3.getMetadata().size()); Assert.assertEquals("value1", share3.getMetadata().get("key1")); + Assert.assertEquals("value2", this.share.getMetadata().get("key2")); } this.share.getMetadata().clear(); @@ -402,6 +417,8 @@ public void testCloudFileShareQuota() throws StorageException, URISyntaxExceptio this.share = FileTestHelper.getRandomShareReference(); this.share.getProperties().setShareQuota(shareQuota); this.share.create(); + assertNotNull(this.share.getProperties().getShareQuota()); + assertEquals(shareQuota, this.share.getProperties().getShareQuota().intValue()); this.share.downloadAttributes(); assertNotNull(this.share.getProperties().getShareQuota()); assertEquals(shareQuota, this.share.getProperties().getShareQuota().intValue()); diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/file/CloudFileShare.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/file/CloudFileShare.java index ac17d9186b50..64fa0328ac61 100644 --- a/microsoft-azure-storage/src/com/microsoft/azure/storage/file/CloudFileShare.java +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/file/CloudFileShare.java @@ -243,8 +243,12 @@ public Void preProcessResponse(CloudFileShare share, CloudFileClient client, Ope // Set attributes final FileShareAttributes attributes = FileResponse.getFileShareAttributes(this.getConnection(), client.isUsePathStyleUris()); + + // The response from the service does not include the share quota. + // Instead, we keep the existing value. + Integer oldShareQuota = share.properties.getShareQuota(); share.properties = attributes.getProperties(); - share.name = attributes.getName(); + share.properties.setShareQuota(oldShareQuota); return null; } }; @@ -519,7 +523,6 @@ public Void preProcessResponse(CloudFileShare share, CloudFileClient client, Ope client.isUsePathStyleUris()); share.metadata = attributes.getMetadata(); share.properties = attributes.getProperties(); - share.name = attributes.getName(); return null; } }; diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/file/FileResponse.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/file/FileResponse.java index 4ed960a1932b..65ae30aecc91 100644 --- a/microsoft-azure-storage/src/com/microsoft/azure/storage/file/FileResponse.java +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/file/FileResponse.java @@ -88,17 +88,6 @@ public static CopyState getCopyState(final HttpURLConnection request) throws URI public static FileShareAttributes getFileShareAttributes(final HttpURLConnection request, final boolean usePathStyleUris) throws StorageException { final FileShareAttributes shareAttributes = new FileShareAttributes(); - URI tempURI; - try { - tempURI = PathUtility.stripSingleURIQueryAndFragment(request.getURL().toURI()); - } - catch (final URISyntaxException e) { - final StorageException wrappedUnexpectedException = Utility.generateNewUnexpectedStorageException(e); - throw wrappedUnexpectedException; - } - - shareAttributes.setName(PathUtility.getShareNameFromUri(tempURI, usePathStyleUris)); - final FileShareProperties shareProperties = shareAttributes.getProperties(); shareProperties.setEtag(BaseResponse.getEtag(request)); shareProperties.setShareQuota(parseShareQuota(request)); From 0a4b9d464d73481c8ff2f85d25178daa45f1461a Mon Sep 17 00:00:00 2001 From: Josh Friedman Date: Mon, 26 Sep 2016 10:23:33 -0700 Subject: [PATCH 03/11] [Java] Porting over Android changes --- .../azure/storage/AccountSasTests.java | 434 +++++++++--------- .../microsoft/azure/storage/AlwaysRetry.java | 5 +- .../azure/storage/EventFiringTests.java | 22 +- .../microsoft/azure/storage/GenericTests.java | 116 +++-- .../storage/MaximumExecutionTimeTests.java | 34 +- .../storage/MultiLocationTestHelper.java | 4 +- .../azure/storage/SecondaryTests.java | 38 +- .../azure/storage/ServicePropertiesTests.java | 82 ++-- .../azure/storage/StorageAccountTests.java | 51 +- .../azure/storage/StorageUriTests.java | 28 +- .../microsoft/azure/storage/TestRunners.java | 44 +- .../analytics/AnalyticsTestHelper.java | 16 +- .../analytics/CloudAnalyticsClientTests.java | 51 +- .../azure/storage/analytics/Granularity.java | 4 +- .../storage/blob/BlobOutputStreamTests.java | 43 +- .../azure/storage/blob/BlobTestHelper.java | 10 +- .../storage/blob/CloudAppendBlobTests.java | 72 +-- .../storage/blob/CloudBlobClientTests.java | 7 +- .../storage/blob/CloudBlobContainerTests.java | 89 ++-- .../storage/blob/CloudBlobDirectoryTests.java | 22 +- .../blob/CloudBlobServerEncryptionTests.java | 15 +- .../storage/blob/CloudBlockBlobTests.java | 90 ++-- .../storage/blob/CloudPageBlobTests.java | 61 +-- .../azure/storage/blob/LeaseTests.java | 30 +- .../azure/storage/blob/SasTests.java | 46 +- .../storage/file/CloudFileClientTests.java | 21 +- .../storage/file/CloudFileDirectoryTests.java | 31 +- .../storage/file/CloudFileShareTests.java | 40 +- .../azure/storage/file/CloudFileTests.java | 68 +-- .../azure/storage/file/FileSasTests.java | 56 +-- .../azure/storage/file/FileTestHelper.java | 11 +- .../queue/CloudQueueClientGB18030Test.java | 17 +- .../storage/queue/CloudQueueClientTests.java | 38 +- .../azure/storage/queue/CloudQueueTests.java | 35 +- .../azure/storage/queue/QueueTestHelper.java | 6 +- .../table/TableBatchOperationTests.java | 35 +- .../azure/storage/table/TableClientTests.java | 32 +- .../azure/storage/table/TableDateTests.java | 39 +- .../storage/table/TableEscapingTests.java | 22 +- .../azure/storage/table/TableODataTests.java | 13 +- .../storage/table/TableOperationTests.java | 62 +-- .../azure/storage/table/TableQueryTests.java | 32 +- .../storage/table/TableSerializerTests.java | 8 +- .../azure/storage/table/TableTestHelper.java | 8 +- .../azure/storage/table/TableTests.java | 35 +- .../storage/SharedAccessPolicySerializer.java | 14 +- 46 files changed, 1063 insertions(+), 974 deletions(-) diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/AccountSasTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/AccountSasTests.java index 95c53ba1da1f..3f23ea4780c8 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/AccountSasTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/AccountSasTests.java @@ -1,11 +1,11 @@ /** * Copyright Microsoft Corporation - * + * * Licensed 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. @@ -15,34 +15,7 @@ package com.microsoft.azure.storage; -import static org.junit.Assert.*; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.net.HttpURLConnection; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.UnknownHostException; -import java.security.InvalidKeyException; -import java.util.Calendar; -import java.util.Date; -import java.util.EnumSet; -import java.util.GregorianCalendar; -import java.util.HashMap; -import java.util.NoSuchElementException; -import java.util.TimeZone; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.experimental.categories.Category; - -import com.microsoft.azure.storage.StorageException; -import com.microsoft.azure.storage.TestHelper; -import com.microsoft.azure.storage.TestRunners.CloudTests; -import com.microsoft.azure.storage.TestRunners.DevFabricTests; -import com.microsoft.azure.storage.TestRunners.DevStoreTests; import com.microsoft.azure.storage.blob.BlobTestHelper; import com.microsoft.azure.storage.blob.BlobType; import com.microsoft.azure.storage.blob.CloudAppendBlob; @@ -64,8 +37,34 @@ import com.microsoft.azure.storage.table.EntityProperty; import com.microsoft.azure.storage.table.TableOperation; import com.microsoft.azure.storage.table.TableTestHelper; +import com.microsoft.azure.storage.TestRunners.CloudTests; +import com.microsoft.azure.storage.TestRunners.DevFabricTests; +import com.microsoft.azure.storage.TestRunners.DevStoreTests; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.experimental.categories.Category; -@Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.UnknownHostException; +import java.security.InvalidKeyException; +import java.util.Calendar; +import java.util.Date; +import java.util.EnumSet; +import java.util.GregorianCalendar; +import java.util.HashMap; +import java.util.NoSuchElementException; +import java.util.TimeZone; + +import static org.junit.Assert.*; + +@Category({ TestRunners.DevFabricTests.class, TestRunners.DevStoreTests.class, TestRunners.CloudTests.class }) public class AccountSasTests { private static final String DOES_NOT_EXIST_ERROR_MESSAGE = "The specified resource does not exist."; private static final String ENUMERATION_ERROR_MESSAGE = @@ -76,9 +75,9 @@ public class AccountSasTests { "This request is not authorized to perform this operation using this resource type."; private static final String INVALID_SERVICE_MESSAGE = "This request is not authorized to perform this operation using this service."; - private static final String QUERY_PARAM_MISSING_MESSAGE = + private static final String QUERY_PARAM_MISSING_MESSAGE = "Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature."; - + private static final int ADD_CODE = 0x1; private static final int CREATE_CODE = 0x2; private static final int DELETE_CODE = 0x4; @@ -90,22 +89,22 @@ public class AccountSasTests { private static final int OBJECT_CODE = 0x100; private static final int CONTAINER_CODE = 0x200; private static final int SERVICE_CODE = 0x400; - + // 0x7ff private static final int FULL_PERMS_CODE = ADD_CODE | CREATE_CODE | DELETE_CODE | LIST_CODE | PROCESS_CODE | READ_CODE | UPDATE_CODE | WRITE_CODE | OBJECT_CODE | CONTAINER_CODE | SERVICE_CODE; private static final int EMPTY_PERMS_CODE = 0x0; - + private CloudBlobClient blobClient; private CloudBlobContainer blobContainer; - + private CloudFileClient fileClient; private CloudFileShare fileShare; - + private CloudQueueClient queueClient; private CloudQueue queueQueue; - + private CloudTableClient tableClient; private CloudTable tableTable; @@ -114,13 +113,13 @@ public class AccountSasTests { public void accountSasTestMethodSetup() throws URISyntaxException, StorageException, IOException { this.blobClient = TestHelper.createCloudBlobClient(); this.blobContainer = BlobTestHelper.getRandomContainerReference(); - + this.fileClient = TestHelper.createCloudFileClient(); this.fileShare = FileTestHelper.getRandomShareReference(); - + this.queueClient = TestHelper.createCloudQueueClient(); this.queueQueue = QueueTestHelper.getRandomQueueReference(); - + this.tableClient = TestHelper.createCloudTableClient(); this.tableTable = TableTestHelper.getRandomTableReference(); } @@ -132,7 +131,7 @@ public void accountSasTestMethodTearDown() throws StorageException, URISyntaxExc this.queueQueue.deleteIfExists(); this.tableTable.deleteIfExists(); } - + @Test @Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) public void testInvalidIP() throws InvalidKeyException, StorageException, URISyntaxException, IOException { @@ -146,7 +145,7 @@ public void testInvalidIP() throws InvalidKeyException, StorageException, URISyn assertEquals(UnknownHostException.class, ex.getCause().getClass()); assertEquals(String.format(SR.INVALID_IP_ADDRESS, ip), ex.getMessage()); } - + // IPv6 Address ip = "2001:0db8:85a3:0000:0000:8a2e:0370:7334"; try { @@ -162,7 +161,7 @@ public void testInvalidIP() throws InvalidKeyException, StorageException, URISyn @Test @Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) public void testBlobServiceAccountSas() throws InvalidKeyException, StorageException, URISyntaxException, IOException { - // A file policy should not work on blobs or containers + // A file policy should not work on blobs or containers try { testBlobAccountSas(this.blobContainer, false, generatePolicy(AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.FILE, null, null)); @@ -192,14 +191,14 @@ public void testBlobServiceAccountSas() throws InvalidKeyException, StorageExcep assertEquals(AccountSasTests.INVALID_SERVICE_MESSAGE, ex.getMessage()); } } - + @Test @Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) public void testBlobIPAccountSas() throws InvalidKeyException, StorageException, URISyntaxException, IOException { IPRange allIP = new IPRange("0.0.0.0", "255.255.255.255"); IPRange noneIP = new IPRange("0.0.0.0"); - + // Ensure access attempt from invalid IP fails IPRange sourceIP = null; try { @@ -209,35 +208,35 @@ public void testBlobIPAccountSas() throws InvalidKeyException, StorageException, } catch (StorageException ex) { assertEquals(HttpURLConnection.HTTP_FORBIDDEN, ex.getHttpStatusCode()); - + final String[] words = ex.getMessage().split(" "); // final word String lastWord = words[words.length - 1]; // strip trailing period lastWord = lastWord.substring(0, lastWord.length() - 1); - + sourceIP = new IPRange(lastWord); } finally { this.blobContainer.deleteIfExists(); } - + // Ensure access attempt from the single allowed IP succeeds this.blobContainer = BlobTestHelper.getRandomContainerReference(); testBlobAccountSas(this.blobContainer, false, generatePolicy(AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.BLOB, sourceIP, null)); - + // Ensure access attempt from one of many valid IPs succeeds this.blobContainer = BlobTestHelper.getRandomContainerReference(); testBlobAccountSas(this.blobContainer, false, generatePolicy(AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.BLOB, allIP, null)); } - + @Test @Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) public void testBlobProtocolAccountSas() throws InvalidKeyException, StorageException, URISyntaxException, IOException { - + // Ensure attempt from http fails against HTTPS_ONLY try { testBlobAccountSas(this.blobContainer, false, generatePolicy( @@ -255,17 +254,17 @@ public void testBlobProtocolAccountSas() this.blobContainer = BlobTestHelper.getRandomContainerReference(); testBlobAccountSas(this.blobContainer, true, generatePolicy( AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.BLOB, null, SharedAccessProtocols.HTTPS_ONLY)); - + // Ensure attempts from both https and http succeed against HTTPS_HTTP this.blobContainer = BlobTestHelper.getRandomContainerReference(); testBlobAccountSas(this.blobContainer, true, generatePolicy( AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.BLOB, null, SharedAccessProtocols.HTTPS_HTTP)); - + this.blobContainer = BlobTestHelper.getRandomContainerReference(); testBlobAccountSas(this.blobContainer, false, generatePolicy( AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.BLOB, null, SharedAccessProtocols.HTTPS_HTTP)); } - + @Test @Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) public void testBlobAccountSasCombinations() @@ -273,7 +272,7 @@ public void testBlobAccountSasCombinations() // Test full and empty permissions testBlobAccountSas(false, AccountSasTests.FULL_PERMS_CODE); testBlobAccountSas(false, AccountSasTests.EMPTY_PERMS_CODE); - + // Test each individual permission testBlobAccountSas(false, AccountSasTests.ADD_CODE); testBlobAccountSas(false, AccountSasTests.CREATE_CODE); @@ -284,7 +283,7 @@ public void testBlobAccountSasCombinations() testBlobAccountSas(false, AccountSasTests.OBJECT_CODE); testBlobAccountSas(false, AccountSasTests.CONTAINER_CODE); testBlobAccountSas(false, AccountSasTests.SERVICE_CODE); - + // Test an arbitrary combination of permissions. final int bits = AccountSasTests.OBJECT_CODE | AccountSasTests.SERVICE_CODE | AccountSasTests.READ_CODE | AccountSasTests.CREATE_CODE | AccountSasTests.DELETE_CODE; @@ -294,7 +293,7 @@ public void testBlobAccountSasCombinations() @Test @Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) public void testFileServiceAccountSas() throws InvalidKeyException, StorageException, URISyntaxException, IOException { - // A blob policy should not work on files or shares + // A blob policy should not work on files or shares try { testFileAccountSas(this.fileShare, false, generatePolicy(AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.BLOB, null, null)); @@ -324,14 +323,14 @@ public void testFileServiceAccountSas() throws InvalidKeyException, StorageExcep assertEquals(AccountSasTests.INVALID_SERVICE_MESSAGE, ex.getMessage()); } } - + @Test @Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) public void testFileIPAccountSas() throws InvalidKeyException, StorageException, URISyntaxException, IOException { - + IPRange allIP = new IPRange("0.0.0.0", "255.255.255.255"); IPRange noneIP = new IPRange("0.0.0.0"); - + // Ensure access attempt from invalid IP fails IPRange sourceIP = null; try { @@ -341,24 +340,24 @@ public void testFileIPAccountSas() throws InvalidKeyException, StorageException, } catch (StorageException ex) { assertEquals(HttpURLConnection.HTTP_FORBIDDEN, ex.getHttpStatusCode()); - + final String[] words = ex.getMessage().split(" "); // final word String lastWord = words[words.length - 1]; // strip trailing period lastWord = lastWord.substring(0, lastWord.length() - 1); - + sourceIP = new IPRange(lastWord); } finally { this.fileShare.deleteIfExists(); } - + // Ensure access attempt from the single allowed IP succeeds this.fileShare = FileTestHelper.getRandomShareReference(); testFileAccountSas(this.fileShare, false, generatePolicy(AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.FILE, sourceIP, null)); - + // Ensure access attempt from one of many valid IPs succeeds this.fileShare = FileTestHelper.getRandomShareReference(); testFileAccountSas(this.fileShare, false, @@ -369,7 +368,7 @@ public void testFileIPAccountSas() throws InvalidKeyException, StorageException, @Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) public void testFileProtocolAccountSas() throws InvalidKeyException, StorageException, URISyntaxException, IOException { - + // Ensure attempt from http fails against HTTPS_ONLY try { testFileAccountSas(this.fileShare, false, generatePolicy( @@ -382,17 +381,17 @@ public void testFileProtocolAccountSas() finally { this.fileShare.deleteIfExists(); } - + // Ensure attempt from https succeeds against HTTPS_ONLY this.fileShare = FileTestHelper.getRandomShareReference(); testFileAccountSas(this.fileShare, true, generatePolicy( AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.FILE, null, SharedAccessProtocols.HTTPS_ONLY)); - + // Ensure attempts from both https and http succeed against HTTPS_HTTP this.fileShare = FileTestHelper.getRandomShareReference(); testFileAccountSas(this.fileShare, true, generatePolicy( AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.FILE, null, SharedAccessProtocols.HTTPS_HTTP)); - + this.fileShare = FileTestHelper.getRandomShareReference(); testFileAccountSas(this.fileShare, false, generatePolicy( AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.FILE, null, SharedAccessProtocols.HTTPS_HTTP)); @@ -405,7 +404,7 @@ public void testFileAccountSasCombinations() // Test full and empty permissions testFileAccountSas(false, AccountSasTests.FULL_PERMS_CODE); testFileAccountSas(false, AccountSasTests.EMPTY_PERMS_CODE); - + // Test each individual permission testFileAccountSas(false, AccountSasTests.CREATE_CODE); testFileAccountSas(false, AccountSasTests.DELETE_CODE); @@ -415,7 +414,7 @@ public void testFileAccountSasCombinations() testFileAccountSas(false, AccountSasTests.OBJECT_CODE); testFileAccountSas(false, AccountSasTests.CONTAINER_CODE); testFileAccountSas(false, AccountSasTests.SERVICE_CODE); - + // Test an arbitrary combination of permissions. final int bits = AccountSasTests.OBJECT_CODE | AccountSasTests.SERVICE_CODE | AccountSasTests.READ_CODE | AccountSasTests.CREATE_CODE | AccountSasTests.DELETE_CODE; @@ -426,8 +425,8 @@ public void testFileAccountSasCombinations() @Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) public void testQueueServiceAccountSas() throws InvalidKeyException, StorageException, URISyntaxException, IOException, InterruptedException { - - // A blob policy should not work on queues + + // A blob policy should not work on queues try { testQueueAccountSas(this.queueQueue, false, generatePolicy(AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.BLOB, null, null)); @@ -457,15 +456,15 @@ public void testQueueServiceAccountSas() assertEquals(AccountSasTests.INVALID_SERVICE_MESSAGE, ex.getMessage()); } } - + @Test @Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) public void testQueueIPAccountSas() throws InvalidKeyException, StorageException, URISyntaxException, IOException, InterruptedException { - + IPRange allIP = new IPRange("0.0.0.0", "255.255.255.255"); IPRange noneIP = new IPRange("0.0.0.0"); - + // Ensure access attempt from invalid IP fails IPRange sourceIP = null; try { @@ -475,24 +474,24 @@ public void testQueueIPAccountSas() } catch (StorageException ex) { assertEquals(HttpURLConnection.HTTP_FORBIDDEN, ex.getHttpStatusCode()); - + final String[] words = ex.getMessage().split(" "); // final word String lastWord = words[words.length - 1]; // strip trailing period lastWord = lastWord.substring(0, lastWord.length() - 1); - + sourceIP = new IPRange(lastWord); } finally { this.queueQueue.deleteIfExists(); } - + // Ensure access attempt from the single allowed IP succeeds this.queueQueue = QueueTestHelper.getRandomQueueReference(); testQueueAccountSas(this.queueQueue, false, generatePolicy(AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.QUEUE, sourceIP, null)); - + // Ensure access attempt from one of many valid IPs succeeds this.queueQueue = QueueTestHelper.getRandomQueueReference(); testQueueAccountSas(this.queueQueue, false, @@ -503,7 +502,7 @@ public void testQueueIPAccountSas() @Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) public void testQueueProtocolAccountSas() throws InvalidKeyException, StorageException, URISyntaxException, IOException, InterruptedException { - + // Ensure attempt from http fails against HTTPS_ONLY try { testQueueAccountSas(this.queueQueue, false, generatePolicy( @@ -516,17 +515,17 @@ public void testQueueProtocolAccountSas() finally { this.queueQueue.deleteIfExists(); } - + // Ensure attempt from https succeeds against HTTPS_ONLY this.queueQueue = QueueTestHelper.getRandomQueueReference(); testQueueAccountSas(this.queueQueue, true, generatePolicy( AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.QUEUE, null, SharedAccessProtocols.HTTPS_ONLY)); - + // Ensure attempts from both https and http succeed against HTTPS_HTTP this.queueQueue = QueueTestHelper.getRandomQueueReference(); testQueueAccountSas(this.queueQueue, true, generatePolicy( AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.QUEUE, null, SharedAccessProtocols.HTTPS_HTTP)); - + this.queueQueue = QueueTestHelper.getRandomQueueReference(); testQueueAccountSas(this.queueQueue, false, generatePolicy( AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.QUEUE, null, SharedAccessProtocols.HTTPS_HTTP)); @@ -539,7 +538,7 @@ public void testQueueAccountSasCombinations() // Test full and empty permissions testQueueAccountSas(false, AccountSasTests.FULL_PERMS_CODE); testQueueAccountSas(false, AccountSasTests.EMPTY_PERMS_CODE); - + // Test each individual permission testQueueAccountSas(false, AccountSasTests.ADD_CODE); testQueueAccountSas(false, AccountSasTests.CREATE_CODE); @@ -552,7 +551,7 @@ public void testQueueAccountSasCombinations() testQueueAccountSas(false, AccountSasTests.OBJECT_CODE); testQueueAccountSas(false, AccountSasTests.CONTAINER_CODE); testQueueAccountSas(false, AccountSasTests.SERVICE_CODE); - + // Test an arbitrary combination of permissions. final int bits = AccountSasTests.OBJECT_CODE | AccountSasTests.SERVICE_CODE | AccountSasTests.READ_CODE | AccountSasTests.CREATE_CODE | AccountSasTests.DELETE_CODE; @@ -562,7 +561,7 @@ public void testQueueAccountSasCombinations() @Test @Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) public void testTableServiceAccountSas() throws InvalidKeyException, StorageException, URISyntaxException, IOException { - // A blob policy should not work on tables + // A blob policy should not work on tables try { testTableAccountSas(this.tableTable, false, generatePolicy(AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.BLOB, null, null)); @@ -571,7 +570,7 @@ public void testTableServiceAccountSas() throws InvalidKeyException, StorageExce catch (StorageException ex) { assertEquals(AccountSasTests.INVALID_SERVICE_MESSAGE, ex.getMessage()); } - + // A file policy should not work on tables try { testTableAccountSas(this.tableTable, false, @@ -581,7 +580,7 @@ public void testTableServiceAccountSas() throws InvalidKeyException, StorageExce catch (StorageException ex) { assertEquals(AccountSasTests.INVALID_SERVICE_MESSAGE, ex.getMessage()); } - + // A queue policy should not work on tables try { testTableAccountSas(this.tableTable, false, @@ -596,10 +595,10 @@ public void testTableServiceAccountSas() throws InvalidKeyException, StorageExce @Test @Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) public void testTableIPAccountSas() throws InvalidKeyException, StorageException, URISyntaxException, IOException { - + IPRange allIP = new IPRange("0.0.0.0", "255.255.255.255"); IPRange noneIP = new IPRange("0.0.0.0"); - + // Ensure access attempt from invalid IP fails IPRange sourceIP = null; try { @@ -609,24 +608,24 @@ public void testTableIPAccountSas() throws InvalidKeyException, StorageException } catch (StorageException ex) { assertEquals(HttpURLConnection.HTTP_FORBIDDEN, ex.getHttpStatusCode()); - + final String[] words = ex.getMessage().split(" "); // final word String lastWord = words[words.length - 1]; // strip trailing period lastWord = lastWord.substring(0, lastWord.length() - 1); - + sourceIP = new IPRange(lastWord); } finally { this.tableTable.deleteIfExists(); } - + // Ensure access attempt from the single allowed IP succeeds this.tableTable = TableTestHelper.getRandomTableReference(); testTableAccountSas(this.tableTable, false, generatePolicy(AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.TABLE, sourceIP, null)); - + // Ensure access attempt from one of many valid IPs succeeds this.tableTable = TableTestHelper.getRandomTableReference(); testTableAccountSas(this.tableTable, false, @@ -637,7 +636,7 @@ public void testTableIPAccountSas() throws InvalidKeyException, StorageException @Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) public void testTableProtocolAccountSas() throws InvalidKeyException, StorageException, URISyntaxException, IOException { - + // Ensure attempt from http fails against HTTPS_ONLY try { testTableAccountSas(this.tableTable, false, generatePolicy( @@ -650,17 +649,17 @@ public void testTableProtocolAccountSas() finally { this.tableTable.deleteIfExists(); } - + // Ensure attempt from https succeeds against HTTPS_ONLY this.tableTable = TableTestHelper.getRandomTableReference(); testTableAccountSas(this.tableTable, true, generatePolicy( AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.TABLE, null, SharedAccessProtocols.HTTPS_ONLY)); - + // Ensure attempts from both https and http succeed against HTTPS_HTTP this.tableTable = TableTestHelper.getRandomTableReference(); testTableAccountSas(this.tableTable, true, generatePolicy( AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.TABLE, null, SharedAccessProtocols.HTTPS_HTTP)); - + this.tableTable = TableTestHelper.getRandomTableReference(); testTableAccountSas(this.tableTable, false, generatePolicy( AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.TABLE, null, SharedAccessProtocols.HTTPS_HTTP)); @@ -673,7 +672,7 @@ public void testTableAccountSasCombinations() // Test full and empty permissions testTableAccountSas(false, AccountSasTests.FULL_PERMS_CODE); testTableAccountSas(false, AccountSasTests.EMPTY_PERMS_CODE); - + // Test each individual permission testTableAccountSas(false, AccountSasTests.ADD_CODE); testTableAccountSas(false, AccountSasTests.CREATE_CODE); @@ -685,7 +684,7 @@ public void testTableAccountSasCombinations() testTableAccountSas(false, AccountSasTests.OBJECT_CODE); testTableAccountSas(false, AccountSasTests.CONTAINER_CODE); testTableAccountSas(false, AccountSasTests.SERVICE_CODE); - + // Test an arbitrary combination of permissions. final int bits = AccountSasTests.OBJECT_CODE | AccountSasTests.SERVICE_CODE | AccountSasTests.READ_CODE | AccountSasTests.CREATE_CODE | AccountSasTests.DELETE_CODE; @@ -698,7 +697,7 @@ private void testBlobAccountSas(final boolean useHttps, final int bits) throws InvalidKeyException, StorageException, URISyntaxException, IOException { SharedAccessAccountPolicy policy = generatePolicy(bits, SharedAccessAccountService.BLOB, null, null); this.blobContainer = this.blobClient.getContainerReference("blobtest" + bits); - + try { testBlobAccountSas(this.blobContainer, useHttps, policy); } @@ -719,21 +718,21 @@ private void testBlobAccountSas(final boolean useHttps, final int bits) private void testBlobAccountSas(CloudBlobContainer container, boolean useHttps, SharedAccessAccountPolicy policy) throws InvalidKeyException, StorageException, URISyntaxException, IOException { - - assertNotEquals(null, container); - assertNotEquals(null, policy); + + assertNotNull(container); + assertNotNull(policy); assertFalse(container.exists()); - + final CloudBlobClient sasClient = TestHelper.createCloudBlobClient(policy, useHttps); URI sasUri = sasClient.getContainerReference(container.getName()).getUri(); sasUri = sasClient.getCredentials().transformUri(sasUri); final CloudBlobContainer sasContainer = new CloudBlobContainer(sasUri); - - // Test creating the container + + // Test creating the container if (policy.getResourceTypes().contains(SharedAccessAccountResourceType.CONTAINER) && (policy.getPermissions().contains(SharedAccessAccountPermissions.CREATE) || policy.getPermissions().contains(SharedAccessAccountPermissions.WRITE))) { - + sasContainer.create(); } else { @@ -745,7 +744,7 @@ private void testBlobAccountSas(CloudBlobContainer container, boolean useHttps, if (AccountSasTests.QUERY_PARAM_MISSING_MESSAGE.equals(ex.getMessage())) { throw ex; } - + if (policy.getResourceTypes().contains(SharedAccessAccountResourceType.CONTAINER)) { assertMessagesMatch(AccountSasTests.INVALID_PERMISSION_MESSAGE, ex); } @@ -755,13 +754,13 @@ private void testBlobAccountSas(CloudBlobContainer container, boolean useHttps, container.create(); } } - + assertTrue(container.exists()); - + // Test listing the containers on the client if (policy.getResourceTypes().contains(SharedAccessAccountResourceType.SERVICE) && (policy.getPermissions().contains(SharedAccessAccountPermissions.LIST))) { - + assertEquals(sasContainer.getName(), sasClient.listContainers(sasContainer.getName()).iterator().next().getName()); } @@ -778,13 +777,13 @@ private void testBlobAccountSas(CloudBlobContainer container, boolean useHttps, } if (policy.getResourceTypes().contains(SharedAccessAccountResourceType.OBJECT)) { - + // Test creating a new blob CloudAppendBlob blob = null; CloudAppendBlob sasBlob = null; if (policy.getPermissions().contains(SharedAccessAccountPermissions.CREATE) || policy.getPermissions().contains(SharedAccessAccountPermissions.WRITE)) { - + sasBlob = (CloudAppendBlob) BlobTestHelper.uploadNewBlob( sasContainer, BlobType.APPEND_BLOB, null, 0, null); blob = container.getAppendBlobReference(sasBlob.getName()); @@ -803,15 +802,15 @@ private void testBlobAccountSas(CloudBlobContainer container, boolean useHttps, BlobType.APPEND_BLOB, sasContainer, blob.getName()); } } - + assertTrue(blob.exists()); - + // Test uploading data to the blob final int length = 512; ByteArrayInputStream sourceStream = BlobTestHelper.getRandomDataStream(length); if (policy.getPermissions().contains(SharedAccessAccountPermissions.ADD) || policy.getPermissions().contains(SharedAccessAccountPermissions.WRITE)) { - + sasBlob.appendBlock(sourceStream, length); } else { @@ -841,9 +840,9 @@ private void testBlobAccountSas(CloudBlobContainer container, boolean useHttps, blob.download(outStream); } } - + TestHelper.assertStreamsAreEqual(sourceStream, new ByteArrayInputStream(outStream.toByteArray())); - + if (policy.getPermissions().contains(SharedAccessAccountPermissions.DELETE)) { sasBlob.delete(); } @@ -857,7 +856,7 @@ private void testBlobAccountSas(CloudBlobContainer container, boolean useHttps, blob.delete(); } } - + assertFalse(blob.exists()); } else { @@ -870,11 +869,11 @@ private void testBlobAccountSas(CloudBlobContainer container, boolean useHttps, BlobTestHelper.uploadNewBlob(container, BlobType.APPEND_BLOB, null, 0, null); } } - - // Test deleting the container + + // Test deleting the container if (policy.getResourceTypes().contains(SharedAccessAccountResourceType.CONTAINER) && policy.getPermissions().contains(SharedAccessAccountPermissions.DELETE)) { - + sasContainer.delete(); } else { @@ -893,12 +892,12 @@ private void testBlobAccountSas(CloudBlobContainer container, boolean useHttps, } } } - + private void testFileAccountSas(final boolean useHttps, final int bits) throws InvalidKeyException, StorageException, URISyntaxException, IOException { SharedAccessAccountPolicy policy = generatePolicy(bits, SharedAccessAccountService.FILE, null, null); this.fileShare = this.fileClient.getShareReference("filetest" + bits); - + try { testFileAccountSas(this.fileShare, useHttps, policy); } @@ -916,24 +915,24 @@ private void testFileAccountSas(final boolean useHttps, final int bits) this.fileShare.deleteIfExists(); } } - + private void testFileAccountSas(CloudFileShare share, boolean useHttps, SharedAccessAccountPolicy policy) throws InvalidKeyException, StorageException, URISyntaxException, IOException { - assertNotEquals(null, share); - assertNotEquals(null, policy); + assertNotNull(share); + assertNotNull(policy); assertFalse(share.exists()); - + final CloudFileClient sasClient = TestHelper.createCloudFileClient(policy, useHttps); URI sasUri = sasClient.getShareReference(share.getName()).getUri(); sasUri = sasClient.getCredentials().transformUri(sasUri); final CloudFileShare sasShare = new CloudFileShare(sasUri); - - // Test creating the share + + // Test creating the share if (policy.getResourceTypes().contains(SharedAccessAccountResourceType.CONTAINER) && (policy.getPermissions().contains(SharedAccessAccountPermissions.CREATE) || policy.getPermissions().contains(SharedAccessAccountPermissions.WRITE))) { - + sasShare.create(); } else { @@ -945,7 +944,7 @@ private void testFileAccountSas(CloudFileShare share, boolean useHttps, SharedAc if (AccountSasTests.QUERY_PARAM_MISSING_MESSAGE.equals(ex.getMessage())) { throw ex; } - + if (policy.getResourceTypes().contains(SharedAccessAccountResourceType.CONTAINER)) { assertMessagesMatch(AccountSasTests.INVALID_PERMISSION_MESSAGE, ex); } @@ -955,13 +954,13 @@ private void testFileAccountSas(CloudFileShare share, boolean useHttps, SharedAc share.create(); } } - + assertTrue(share.exists()); - + // Test listing the shares on the client if (policy.getResourceTypes().contains(SharedAccessAccountResourceType.SERVICE) && (policy.getPermissions().contains(SharedAccessAccountPermissions.LIST))) { - + assertEquals(sasShare.getName(), sasClient.listShares(sasShare.getName()).iterator().next().getName()); } else { @@ -975,18 +974,18 @@ private void testFileAccountSas(CloudFileShare share, boolean useHttps, SharedAc this.fileClient.listShares(sasShare.getName()).iterator().next().getName()); } } - + final int length = 512; if (policy.getResourceTypes().contains(SharedAccessAccountResourceType.OBJECT)) { - + // Test creating a new file CloudFile file = null; CloudFile sasFile = null; - + sasFile = sasShare.getRootDirectoryReference().getFileReference(FileTestHelper.generateRandomFileName()); if (policy.getPermissions().contains(SharedAccessAccountPermissions.CREATE) || policy.getPermissions().contains(SharedAccessAccountPermissions.WRITE)) { - + sasFile.create(length); file = share.getRootDirectoryReference().getFileReference(sasFile.getName()); } @@ -1001,9 +1000,9 @@ private void testFileAccountSas(CloudFileShare share, boolean useHttps, SharedAc sasFile = sasShare.getRootDirectoryReference().getFileReference(file.getName()); } } - + assertTrue(file.exists()); - + //Test writing data to a file final ByteArrayInputStream sourcestream = FileTestHelper.getRandomDataStream(length); if (policy.getPermissions().contains(SharedAccessAccountPermissions.WRITE)) { @@ -1019,7 +1018,7 @@ private void testFileAccountSas(CloudFileShare share, boolean useHttps, SharedAc file.upload(sourcestream, length); } } - + // Test downloading data from the file final ByteArrayOutputStream outStream = new ByteArrayOutputStream(); if (policy.getPermissions().contains(SharedAccessAccountPermissions.READ)) { @@ -1035,9 +1034,9 @@ private void testFileAccountSas(CloudFileShare share, boolean useHttps, SharedAc file.download(outStream); } } - + TestHelper.assertStreamsAreEqual(sourcestream, new ByteArrayInputStream(outStream.toByteArray())); - + if (policy.getPermissions().contains(SharedAccessAccountPermissions.DELETE)) { sasFile.delete(); } @@ -1051,7 +1050,7 @@ private void testFileAccountSas(CloudFileShare share, boolean useHttps, SharedAc file.delete(); } } - + assertFalse(file.exists()); } else { @@ -1064,11 +1063,11 @@ private void testFileAccountSas(CloudFileShare share, boolean useHttps, SharedAc FileTestHelper.uploadNewFile(share, FileTestHelper.getRandomDataStream(0), length, null); } } - - // Test deleting the share + + // Test deleting the share if (policy.getResourceTypes().contains(SharedAccessAccountResourceType.CONTAINER) && policy.getPermissions().contains(SharedAccessAccountPermissions.DELETE)) { - + sasShare.delete(); } else { @@ -1087,12 +1086,12 @@ private void testFileAccountSas(CloudFileShare share, boolean useHttps, SharedAc } } } - + private void testQueueAccountSas(final boolean useHttps, final int bits) throws InvalidKeyException, StorageException, URISyntaxException, IOException, InterruptedException { SharedAccessAccountPolicy policy = generatePolicy(bits, SharedAccessAccountService.QUEUE, null, null); this.queueQueue = this.queueClient.getQueueReference("queuetest" + bits); - + try { testQueueAccountSas(this.queueQueue, useHttps, policy); } @@ -1114,23 +1113,23 @@ private void testQueueAccountSas(final boolean useHttps, final int bits) private void testQueueAccountSas(CloudQueue queue, boolean useHttps, SharedAccessAccountPolicy policy) throws InvalidKeyException, StorageException, URISyntaxException, IOException, InterruptedException { - assertNotEquals(null, policy); - assertNotEquals(null, queue); + assertNotNull(policy); + assertNotNull(queue); assertFalse(queue.exists()); - + final CloudQueueClient sasClient = TestHelper.createCloudQueueClient(policy, useHttps); URI sasUri = sasClient.getQueueReference(queue.getName()).getUri(); sasUri = sasClient.getCredentials().transformUri(sasUri); final CloudQueue sasQueue = new CloudQueue(sasUri); - + final String key = "testkey"; final String value = "testvalue"; - + if (policy.getResourceTypes().contains(SharedAccessAccountResourceType.CONTAINER)) { - // Test creating the queue + // Test creating the queue if (policy.getPermissions().contains(SharedAccessAccountPermissions.CREATE) || policy.getPermissions().contains(SharedAccessAccountPermissions.WRITE)) { - + sasQueue.create(); } else { @@ -1142,7 +1141,7 @@ private void testQueueAccountSas(CloudQueue queue, boolean useHttps, SharedAcces if (AccountSasTests.QUERY_PARAM_MISSING_MESSAGE.equals(ex.getMessage())) { throw ex; } - + if (policy.getResourceTypes().contains(SharedAccessAccountResourceType.CONTAINER)) { assertMessagesMatch(AccountSasTests.INVALID_PERMISSION_MESSAGE, ex); } @@ -1152,12 +1151,12 @@ private void testQueueAccountSas(CloudQueue queue, boolean useHttps, SharedAcces queue.create(); } } - + // Test queue metadata queue.setMetadata(new HashMap()); queue.getMetadata().put(key, Constants.ID); queue.uploadMetadata(); - + sasQueue.setMetadata(new HashMap()); if (policy.getPermissions().contains(SharedAccessAccountPermissions.WRITE)) { sasQueue.getMetadata().put(key, value); @@ -1171,12 +1170,12 @@ private void testQueueAccountSas(CloudQueue queue, boolean useHttps, SharedAcces } catch (StorageException ex) { assertMessagesMatch(AccountSasTests.INVALID_PERMISSION_MESSAGE, ex); - + queue.getMetadata().put(key, value); queue.uploadMetadata(); } } - + queue.downloadAttributes(); assertEquals(value, queue.getMetadata().get(key)); } @@ -1189,7 +1188,7 @@ private void testQueueAccountSas(CloudQueue queue, boolean useHttps, SharedAcces if (AccountSasTests.QUERY_PARAM_MISSING_MESSAGE.equals(ex.getMessage())) { throw ex; } - + if (policy.getResourceTypes().contains(SharedAccessAccountResourceType.CONTAINER)) { assertMessagesMatch(AccountSasTests.INVALID_PERMISSION_MESSAGE, ex); } @@ -1199,13 +1198,13 @@ private void testQueueAccountSas(CloudQueue queue, boolean useHttps, SharedAcces queue.create(); } } - + assertTrue(queue.exists()); - + // Test listing the queues on the client if (policy.getResourceTypes().contains(SharedAccessAccountResourceType.SERVICE) && (policy.getPermissions().contains(SharedAccessAccountPermissions.LIST))) { - + assertEquals(sasQueue.getName(), sasClient.listQueues(sasQueue.getName()).iterator().next().getName()); } else { @@ -1219,7 +1218,7 @@ private void testQueueAccountSas(CloudQueue queue, boolean useHttps, SharedAcces this.queueClient.listQueues(sasQueue.getName()).iterator().next().getName()); } } - + if (policy.getResourceTypes().contains(SharedAccessAccountResourceType.OBJECT)) { // Test inserting a message into a queue if (policy.getPermissions().contains(SharedAccessAccountPermissions.ADD)) { @@ -1251,9 +1250,9 @@ private void testQueueAccountSas(CloudQueue queue, boolean useHttps, SharedAcces message = queue.peekMessage(); } } - + assertEquals(value, message.getMessageContentAsString()); - + // Test getting a message from the queue if (policy.getPermissions().contains(SharedAccessAccountPermissions.PROCESS_MESSAGES)) { message = sasQueue.retrieveMessage(); @@ -1290,7 +1289,7 @@ private void testQueueAccountSas(CloudQueue queue, boolean useHttps, SharedAcces Thread.sleep(1000); message = queue.peekMessage(); assertEquals(key, message.getMessageContentAsString()); - + // Test clearing all messages from the queue. queue.addMessage(new CloudQueueMessage(key)); queue.addMessage(new CloudQueueMessage(value)); @@ -1307,7 +1306,7 @@ private void testQueueAccountSas(CloudQueue queue, boolean useHttps, SharedAcces queue.clear(); } } - + assertEquals(null, queue.peekMessage()); } else { @@ -1320,11 +1319,11 @@ private void testQueueAccountSas(CloudQueue queue, boolean useHttps, SharedAcces queue.peekMessage(); } } - - // Test deleting the queue + + // Test deleting the queue if (policy.getResourceTypes().contains(SharedAccessAccountResourceType.CONTAINER) && policy.getPermissions().contains(SharedAccessAccountPermissions.DELETE)) { - + sasQueue.delete(); } else { @@ -1343,12 +1342,12 @@ private void testQueueAccountSas(CloudQueue queue, boolean useHttps, SharedAcces } } } - + private void testTableAccountSas(final boolean useHttps, final int bits) throws InvalidKeyException, StorageException, URISyntaxException, IOException { SharedAccessAccountPolicy policy = generatePolicy(bits, SharedAccessAccountService.TABLE, null, null); this.tableTable = this.tableClient.getTableReference("tabletest" + bits); - + try { testTableAccountSas(this.tableTable, useHttps, policy); } @@ -1369,16 +1368,15 @@ private void testTableAccountSas(final boolean useHttps, final int bits) private void testTableAccountSas(CloudTable table, boolean useHttps, SharedAccessAccountPolicy policy) throws InvalidKeyException, StorageException, URISyntaxException, IOException { - - assertNotEquals(null, policy); - assertNotEquals(null, table); + assertNotNull(policy); + assertNotNull(table); assertFalse(table.exists()); - + final CloudTableClient sasClient = TestHelper.createCloudTableClient(policy, useHttps); URI sasUri = sasClient.getTableReference(table.getName()).getUri(); sasUri = sasClient.getCredentials().transformUri(sasUri); final CloudTable sasTable = new CloudTable(sasUri); - + final String key = "testkey"; final String value = "testvalue"; final String value2 = "testvalue2"; @@ -1387,11 +1385,11 @@ private void testTableAccountSas(CloudTable table, boolean useHttps, SharedAcces final String row1 = "testrow1"; final String row2 = "testrow2"; - // Test creating the table + // Test creating the table if (policy.getResourceTypes().contains(SharedAccessAccountResourceType.CONTAINER) && (policy.getPermissions().contains(SharedAccessAccountPermissions.CREATE) || policy.getPermissions().contains(SharedAccessAccountPermissions.WRITE))) { - + sasTable.create(); } else { @@ -1403,7 +1401,7 @@ private void testTableAccountSas(CloudTable table, boolean useHttps, SharedAcces if (AccountSasTests.QUERY_PARAM_MISSING_MESSAGE.equals(ex.getMessage())) { throw ex; } - + if (policy.getResourceTypes().contains(SharedAccessAccountResourceType.CONTAINER)) { assertMessagesMatch(AccountSasTests.INVALID_PERMISSION_MESSAGE, ex); } @@ -1413,13 +1411,13 @@ private void testTableAccountSas(CloudTable table, boolean useHttps, SharedAcces table.create(); } } - + assertTrue(table.exists()); - + // Test listing the tables on the client if (policy.getResourceTypes().contains(SharedAccessAccountResourceType.CONTAINER) && policy.getPermissions().contains(SharedAccessAccountPermissions.LIST)) { - + assertEquals(sasTable.getName(), sasClient.listTables(sasTable.getName()).iterator().next()); } else { @@ -1433,14 +1431,14 @@ private void testTableAccountSas(CloudTable table, boolean useHttps, SharedAcces this.tableClient.listTables(sasTable.getName()).iterator().next()); } } - + if (policy.getResourceTypes().contains(SharedAccessAccountResourceType.OBJECT)) { // Test inserting an entity into a table final HashMap columns = new HashMap(); columns.put(key, new EntityProperty(value)); final DynamicTableEntity entity = new DynamicTableEntity(partition1, row1, columns); TableOperation op = TableOperation.insert(entity); - + if (policy.getPermissions().contains(SharedAccessAccountPermissions.ADD)) { sasTable.execute(op); } @@ -1454,11 +1452,11 @@ private void testTableAccountSas(CloudTable table, boolean useHttps, SharedAcces table.execute(op); } } - + op = TableOperation.retrieve(partition1, row1, DynamicTableEntity.class); DynamicTableEntity result = (DynamicTableEntity) table.execute(op).getResultAsType(); assertEquals(value, result.getProperties().get(key).getValueAsString()); - + // Test merging an entity in a table entity.getProperties().put(key, new EntityProperty(value2)); op = TableOperation.merge(entity); @@ -1492,18 +1490,18 @@ private void testTableAccountSas(CloudTable table, boolean useHttps, SharedAcces result = (DynamicTableEntity) table.execute(op).getResultAsType(); } } - + assertEquals(value2, result.getProperties().get(key).getValueAsString()); - + // Test insert or merge on two entities entity.getProperties().put(key, new EntityProperty(value)); op = TableOperation.insertOrMerge(entity); - + final HashMap columns2 = new HashMap(); columns2.put(key, new EntityProperty(value2)); final DynamicTableEntity entity2 = new DynamicTableEntity(partition2, row2, columns2); TableOperation op2 = TableOperation.insertOrMerge(entity2); - + if (policy.getPermissions().contains(SharedAccessAccountPermissions.ADD) && policy.getPermissions().contains(SharedAccessAccountPermissions.UPDATE)) { sasTable.execute(op); @@ -1531,11 +1529,11 @@ private void testTableAccountSas(CloudTable table, boolean useHttps, SharedAcces TableOperation retrieveOp = TableOperation.retrieve(partition2, row2, DynamicTableEntity.class); result = (DynamicTableEntity) table.execute(retrieveOp).getResultAsType(); assertEquals(value2, result.getProperties().get(key).getValueAsString()); - + retrieveOp = TableOperation.retrieve(partition1, row1, DynamicTableEntity.class); result = (DynamicTableEntity) table.execute(retrieveOp).getResultAsType(); assertEquals(value, result.getProperties().get(key).getValueAsString()); - + // Test deleting an entity from a table. op = TableOperation.delete(entity); if (policy.getPermissions().contains(SharedAccessAccountPermissions.DELETE)) { @@ -1551,7 +1549,7 @@ private void testTableAccountSas(CloudTable table, boolean useHttps, SharedAcces table.execute(op); } } - + try { table.execute(op); } @@ -1570,11 +1568,11 @@ private void testTableAccountSas(CloudTable table, boolean useHttps, SharedAcces table.execute(op); } } - - // Test deleting the share + + // Test deleting the share if (policy.getResourceTypes().contains(SharedAccessAccountResourceType.CONTAINER) && policy.getPermissions().contains(SharedAccessAccountPermissions.DELETE)) { - + sasTable.delete(); } else { @@ -1593,7 +1591,7 @@ private void testTableAccountSas(CloudTable table, boolean useHttps, SharedAcces } } } - + private static void assertMessagesMatch(String expectedMessage, StorageException ex) { final String message = ex.getExtendedErrorInformation().getErrorMessage().split("\n")[0]; assertEquals(expectedMessage, message); @@ -1601,57 +1599,57 @@ private static void assertMessagesMatch(String expectedMessage, StorageException private static SharedAccessAccountPolicy generatePolicy( final int bits, final SharedAccessAccountService service, IPRange ipRange, SharedAccessProtocols protocols) { - + EnumSet services = EnumSet.noneOf(SharedAccessAccountService.class); EnumSet permissions = EnumSet.noneOf(SharedAccessAccountPermissions.class); EnumSet resourceTypes = EnumSet.noneOf(SharedAccessAccountResourceType.class); - + services.add(service); - + if ((bits & AccountSasTests.ADD_CODE) == AccountSasTests.ADD_CODE) { permissions.add(SharedAccessAccountPermissions.ADD); } - + if ((bits & AccountSasTests.CREATE_CODE) == AccountSasTests.CREATE_CODE) { permissions.add(SharedAccessAccountPermissions.CREATE); } - + if ((bits & AccountSasTests.DELETE_CODE) == AccountSasTests.DELETE_CODE) { permissions.add(SharedAccessAccountPermissions.DELETE); } - + if ((bits & AccountSasTests.LIST_CODE) == AccountSasTests.LIST_CODE) { permissions.add(SharedAccessAccountPermissions.LIST); } - + if ((bits & AccountSasTests.PROCESS_CODE) == AccountSasTests.PROCESS_CODE) { permissions.add(SharedAccessAccountPermissions.PROCESS_MESSAGES); } - + if ((bits & AccountSasTests.READ_CODE) == AccountSasTests.READ_CODE) { permissions.add(SharedAccessAccountPermissions.READ); } - + if ((bits & AccountSasTests.UPDATE_CODE) == AccountSasTests.UPDATE_CODE) { permissions.add(SharedAccessAccountPermissions.UPDATE); } - + if ((bits & AccountSasTests.WRITE_CODE) == AccountSasTests.WRITE_CODE) { permissions.add(SharedAccessAccountPermissions.WRITE); } - + if ((bits & AccountSasTests.OBJECT_CODE) == AccountSasTests.OBJECT_CODE) { resourceTypes.add(SharedAccessAccountResourceType.OBJECT); } - + if ((bits & AccountSasTests.CONTAINER_CODE) == AccountSasTests.CONTAINER_CODE) { resourceTypes.add(SharedAccessAccountResourceType.CONTAINER); } - + if ((bits & AccountSasTests.SERVICE_CODE) == AccountSasTests.SERVICE_CODE) { resourceTypes.add(SharedAccessAccountResourceType.SERVICE); } - + Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("UTC")); cal.setTime(new Date()); cal.add(Calendar.SECOND, 300); @@ -1663,7 +1661,7 @@ private static SharedAccessAccountPolicy generatePolicy( policy.setRange(ipRange); policy.setProtocols(protocols); policy.setSharedAccessExpiryTime(cal.getTime()); - + return policy; } } \ No newline at end of file diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/AlwaysRetry.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/AlwaysRetry.java index bbe6d8a536f4..20256c2757c3 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/AlwaysRetry.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/AlwaysRetry.java @@ -14,11 +14,12 @@ */ package com.microsoft.azure.storage; -import static org.junit.Assert.*; - import java.util.ArrayList; import java.util.List; +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertTrue; + public class AlwaysRetry extends RetryPolicy implements RetryPolicyFactory { private final List retryContextList; diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/EventFiringTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/EventFiringTests.java index cafb899bf714..4ea007be63c9 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/EventFiringTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/EventFiringTests.java @@ -14,22 +14,22 @@ */ package com.microsoft.azure.storage; -import static org.junit.Assert.*; +import com.microsoft.azure.storage.blob.BlobRequestOptions; +import com.microsoft.azure.storage.blob.CloudBlobClient; +import com.microsoft.azure.storage.blob.CloudBlobContainer; +import com.microsoft.azure.storage.core.SR; +import com.microsoft.azure.storage.TestRunners.CloudTests; +import com.microsoft.azure.storage.TestRunners.DevFabricTests; +import com.microsoft.azure.storage.TestRunners.DevStoreTests; + +import org.junit.Test; +import org.junit.experimental.categories.Category; import java.net.HttpURLConnection; import java.net.URISyntaxException; import java.util.ArrayList; -import org.junit.Test; -import org.junit.experimental.categories.Category; - -import com.microsoft.azure.storage.TestRunners.CloudTests; -import com.microsoft.azure.storage.TestRunners.DevFabricTests; -import com.microsoft.azure.storage.TestRunners.DevStoreTests; -import com.microsoft.azure.storage.blob.BlobRequestOptions; -import com.microsoft.azure.storage.blob.CloudBlobClient; -import com.microsoft.azure.storage.blob.CloudBlobContainer; -import com.microsoft.azure.storage.core.SR; +import static org.junit.Assert.*; @Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) public class EventFiringTests { diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/GenericTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/GenericTests.java index 08ff216546ae..dbf4ce028c7c 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/GenericTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/GenericTests.java @@ -14,7 +14,28 @@ */ package com.microsoft.azure.storage; -import static org.junit.Assert.*; +import com.microsoft.azure.storage.blob.BlobOutputStream; +import com.microsoft.azure.storage.blob.BlobRequestOptions; +import com.microsoft.azure.storage.blob.BlobTestHelper; +import com.microsoft.azure.storage.blob.CloudBlobClient; +import com.microsoft.azure.storage.blob.CloudBlobContainer; +import com.microsoft.azure.storage.blob.CloudBlockBlob; +import com.microsoft.azure.storage.core.SR; +import com.microsoft.azure.storage.core.Utility; +import com.microsoft.azure.storage.queue.CloudQueue; +import com.microsoft.azure.storage.queue.CloudQueueClient; +import com.microsoft.azure.storage.table.CloudTable; +import com.microsoft.azure.storage.table.CloudTableClient; +import com.microsoft.azure.storage.TestRunners.CloudTests; +import com.microsoft.azure.storage.TestRunners.DevFabricTests; +import com.microsoft.azure.storage.TestRunners.DevStoreTests; +import com.microsoft.azure.storage.TestRunners.SlowTests; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.experimental.categories.Category; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -22,6 +43,7 @@ import java.net.HttpURLConnection; import java.net.InetSocketAddress; import java.net.Proxy; +import java.net.SocketTimeoutException; import java.net.URISyntaxException; import java.text.ParseException; import java.text.SimpleDateFormat; @@ -30,27 +52,7 @@ import java.util.HashMap; import java.util.UUID; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.experimental.categories.Category; - -import com.microsoft.azure.storage.TestRunners.CloudTests; -import com.microsoft.azure.storage.TestRunners.DevFabricTests; -import com.microsoft.azure.storage.TestRunners.DevStoreTests; -import com.microsoft.azure.storage.TestRunners.SlowTests; -import com.microsoft.azure.storage.blob.BlobOutputStream; -import com.microsoft.azure.storage.blob.BlobRequestOptions; -import com.microsoft.azure.storage.blob.BlobTestHelper; -import com.microsoft.azure.storage.blob.CloudBlobClient; -import com.microsoft.azure.storage.blob.CloudBlobContainer; -import com.microsoft.azure.storage.blob.CloudBlockBlob; -import com.microsoft.azure.storage.core.SR; -import com.microsoft.azure.storage.core.Utility; -import com.microsoft.azure.storage.queue.CloudQueue; -import com.microsoft.azure.storage.queue.CloudQueueClient; -import com.microsoft.azure.storage.table.CloudTable; -import com.microsoft.azure.storage.table.CloudTableClient; +import static org.junit.Assert.*; @Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) public class GenericTests { @@ -128,18 +130,17 @@ public void testReadTimeoutIssue() throws URISyntaxException, StorageException, container2.createIfNotExists(); blockBlobRef2.upload(inputStream2, length2); - } - finally { + } finally { inputStream2.close(); container2.deleteIfExists(); } } - + @Test public void testProxy() throws URISyntaxException, StorageException { CloudBlobClient blobClient = TestHelper.createCloudBlobClient(); CloudBlobContainer container = blobClient.getContainerReference("container1"); - + // Use a request-level proxy OperationContext opContext = new OperationContext(); opContext.setProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("10.1.1.1", 8888))); @@ -147,8 +148,8 @@ public void testProxy() throws URISyntaxException, StorageException { // Turn of retries to make the failure happen faster BlobRequestOptions opt = new BlobRequestOptions(); opt.setRetryPolicyFactory(new RetryNoRetry()); - - // Unfortunately HttpURLConnection doesn't expose a getter and the usingProxy method it does have doesn't + + // Unfortunately HttpURLConnection doesn't expose a getter and the usingProxy method it does have doesn't // work as one would expect and will always for us return false. So, we validate by making sure the request // fails when we set a bad proxy rather than check the proxy setting itself. try { @@ -156,24 +157,26 @@ public void testProxy() throws URISyntaxException, StorageException { fail("Bad proxy should throw an exception."); } catch (StorageException e) { - assertEquals(ConnectException.class, e.getCause().getClass()); - assertEquals("Connection timed out: connect", e.getCause().getMessage()); + if (e.getCause().getClass() != ConnectException.class && + e.getCause().getClass() != SocketTimeoutException.class) { + Assert.fail("Unepected exception for bad proxy"); + } } } @Test - public void testDefaultProxy() throws URISyntaxException, StorageException { + public void testDefaultProxy() throws URISyntaxException, StorageException { CloudBlobClient blobClient = TestHelper.createCloudBlobClient(); CloudBlobContainer container = blobClient.getContainerReference("container1"); - + // Use a default proxy OperationContext.setDefaultProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("10.1.1.1", 8888))); // Turn of retries to make the failure happen faster BlobRequestOptions opt = new BlobRequestOptions(); opt.setRetryPolicyFactory(new RetryNoRetry()); - - // Unfortunately HttpURLConnection doesn't expose a getter and the usingProxy method it does have doesn't + + // Unfortunately HttpURLConnection doesn't expose a getter and the usingProxy method it does have doesn't // work as one would expect and will always for us return false. So, we validate by making sure the request // fails when we set a bad proxy rather than check the proxy setting itself succeeding. try { @@ -181,8 +184,10 @@ public void testDefaultProxy() throws URISyntaxException, StorageException { fail("Bad proxy should throw an exception."); } catch (StorageException e) { - assertEquals(ConnectException.class, e.getCause().getClass()); - assertEquals("Connection timed out: connect", e.getCause().getMessage()); + if (e.getCause().getClass() != ConnectException.class && + e.getCause().getClass() != SocketTimeoutException.class) { + Assert.fail("Unepected exception for bad proxy"); + } } } @@ -190,21 +195,38 @@ public void testDefaultProxy() throws URISyntaxException, StorageException { public void testProxyOverridesDefault() throws URISyntaxException, StorageException { CloudBlobClient blobClient = TestHelper.createCloudBlobClient(); CloudBlobContainer container = blobClient.getContainerReference("container1"); - + // Set a default proxy OperationContext.setDefaultProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("10.1.1.1", 8888))); + // Turn off retries to make the failure happen faster + BlobRequestOptions opt = new BlobRequestOptions(); + opt.setRetryPolicyFactory(new RetryNoRetry()); + + // Unfortunately HttpURLConnection doesn't expose a getter and the usingProxy method it does have doesn't + // work as one would expect and will always for us return false. So, we validate by making sure the request + // fails when we set a bad proxy rather than check the proxy setting itself succeeding. + try { + container.exists(null, opt, null); + fail("Bad proxy should throw an exception."); + } catch (StorageException e) { + if (e.getCause().getClass() != ConnectException.class && + e.getCause().getClass() != SocketTimeoutException.class) { + Assert.fail("Unepected exception for bad proxy"); + } + } + // Override it with no proxy OperationContext opContext = new OperationContext(); opContext.setProxy(Proxy.NO_PROXY); - + // Should succeed as request-level proxy should override the bad default proxy container.exists(null, null, opContext); } /** * Make sure that if a request throws an error when it is being built that the request is not sent. - * + * * @throws URISyntaxException * @throws StorageException */ @@ -347,7 +369,7 @@ public void testDateStringParsingWithRounding() throws ParseException { milliDate = Utility.parseDate(fullDateString); assertEquals(milliDate.getTime(), millisSinceEpoch); } - + @Test public void testDateStringParsing() throws ParseException { // 2014-12-07T09:15:12.123Z from Java @@ -377,7 +399,7 @@ public void testDateStringParsingCrossVersion() throws ParseException { // 2015-02-14T03:11:13.0000229Z from .Net testDate("2015-02-14T03:11:13.0000229Z", 1423883473000L, 229, true, false); } - + @Test public void testDateStringParsingWithBackwardCompatibility() throws ParseException { // 2014-12-07T09:15:12.123Z from Java @@ -409,11 +431,11 @@ public void testDateStringParsingCrossVersionWithBackwardCompatibility() throws } private static void testDate(final String dateString, final long intendedMilliseconds, final int ticks, - final boolean writtenPre2, final boolean dateBackwardCompatibility) { + final boolean writtenPre2, final boolean dateBackwardCompatibility) { assertTrue(ticks >= 0); // ticks is non-negative assertTrue(ticks <= 9999); // ticks do not overflow into milliseconds long expectedMilliseconds = intendedMilliseconds; - + if (dateBackwardCompatibility && (intendedMilliseconds % 1000 == 0) && (ticks < 1000)) { // when no milliseconds are present dateBackwardCompatibility causes up to 3 digits of ticks // to be read as milliseconds @@ -422,7 +444,7 @@ private static void testDate(final String dateString, final long intendedMillise // without DateBackwardCompatibility, milliseconds stored by Java prior to 2.0.0 are lost expectedMilliseconds -= expectedMilliseconds % 1000; } - + assertEquals(expectedMilliseconds, Utility.parseDate(dateString, dateBackwardCompatibility).getTime()); } @@ -431,17 +453,17 @@ public void testDateStringFormatting() { String fullDateString = "2014-12-07T09:15:12.123Z"; String outDateString = Utility.getJavaISO8601Time(Utility.parseDate(fullDateString)); assertEquals(fullDateString, outDateString); - + fullDateString = "2015-01-14T14:53:32.800Z"; outDateString = Utility.getJavaISO8601Time(Utility.parseDate(fullDateString)); assertEquals(fullDateString, outDateString); - + // Ensure that trimming of trailing zeroes by the service does not affect this fullDateString = "2015-01-14T14:53:32.8Z"; outDateString = Utility.getJavaISO8601Time(Utility.parseDate(fullDateString)); fullDateString = fullDateString.replace("Z", "00Z"); assertEquals(fullDateString, outDateString); - + // Ensure that trimming of trailing zeroes by the service does not affect this // even with dateBackwardCompatibility fullDateString = "2015-01-14T14:53:32.0000800Z"; diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/MaximumExecutionTimeTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/MaximumExecutionTimeTests.java index d8ab0a66ce98..d1a8ef1c03c5 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/MaximumExecutionTimeTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/MaximumExecutionTimeTests.java @@ -14,20 +14,6 @@ */ package com.microsoft.azure.storage; -import static org.junit.Assert.*; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.net.URISyntaxException; -import java.util.UUID; - -import org.junit.Test; -import org.junit.experimental.categories.Category; - -import com.microsoft.azure.storage.TestRunners.CloudTests; -import com.microsoft.azure.storage.TestRunners.DevFabricTests; -import com.microsoft.azure.storage.TestRunners.DevStoreTests; -import com.microsoft.azure.storage.TestRunners.SlowTests; import com.microsoft.azure.storage.blob.BlobOutputStream; import com.microsoft.azure.storage.blob.BlobRequestOptions; import com.microsoft.azure.storage.blob.BlobTestHelper; @@ -46,6 +32,20 @@ import com.microsoft.azure.storage.table.DynamicTableEntity; import com.microsoft.azure.storage.table.TableOperation; import com.microsoft.azure.storage.table.TableRequestOptions; +import com.microsoft.azure.storage.TestRunners.CloudTests; +import com.microsoft.azure.storage.TestRunners.DevFabricTests; +import com.microsoft.azure.storage.TestRunners.DevStoreTests; +import com.microsoft.azure.storage.TestRunners.SlowTests; + +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.UUID; + +import static org.junit.Assert.*; @Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) public class MaximumExecutionTimeTests { @@ -79,7 +79,7 @@ public void testBlobMaximumExecutionTime() throws URISyntaxException, StorageExc assertEquals(SR.MAXIMUM_EXECUTION_TIMEOUT_EXCEPTION, e.getMessage()); } } - + @Test @Category({ DevFabricTests.class, DevStoreTests.class, SecondaryTests.class }) public void testFileMaximumExecutionTime() throws URISyntaxException, StorageException { @@ -114,7 +114,7 @@ public void eventOccurred(ResponseReceivedEvent eventArg) { assertEquals(SR.MAXIMUM_EXECUTION_TIMEOUT_EXCEPTION, e.getMessage()); } } - + @Test @Category({ DevFabricTests.class, DevStoreTests.class, SecondaryTests.class }) public void testQueueMaximumExecutionTime() throws URISyntaxException, StorageException { @@ -144,7 +144,7 @@ public void testQueueMaximumExecutionTime() throws URISyntaxException, StorageEx assertEquals(SR.MAXIMUM_EXECUTION_TIMEOUT_EXCEPTION, e.getMessage()); } } - + @Test @Category({ DevFabricTests.class, DevStoreTests.class, SecondaryTests.class }) public void testTableMaximumExecutionTime() throws URISyntaxException, StorageException { diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/MultiLocationTestHelper.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/MultiLocationTestHelper.java index 7adbbe7cf554..1ac9f32550ea 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/MultiLocationTestHelper.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/MultiLocationTestHelper.java @@ -14,10 +14,10 @@ */ package com.microsoft.azure.storage; -import static org.junit.Assert.*; - import java.util.List; +import static org.junit.Assert.*; + public class MultiLocationTestHelper { public final StorageLocation initialLocation; private final List retryInfoList; diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/SecondaryTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/SecondaryTests.java index 28683e012e42..71d5f1d0910a 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/SecondaryTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/SecondaryTests.java @@ -14,22 +14,6 @@ */ package com.microsoft.azure.storage; -import static org.junit.Assert.*; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.net.HttpURLConnection; -import java.net.URISyntaxException; -import java.util.ArrayList; -import java.util.List; - -import org.junit.Test; -import org.junit.experimental.categories.Category; - -import com.microsoft.azure.storage.TestRunners.CloudTests; -import com.microsoft.azure.storage.TestRunners.DevFabricTests; -import com.microsoft.azure.storage.TestRunners.DevStoreTests; -import com.microsoft.azure.storage.TestRunners.SlowTests; import com.microsoft.azure.storage.blob.BlobRequestOptions; import com.microsoft.azure.storage.blob.BlobTestHelper; import com.microsoft.azure.storage.blob.BlobType; @@ -46,6 +30,22 @@ import com.microsoft.azure.storage.table.CloudTableClient; import com.microsoft.azure.storage.table.TableRequestOptions; import com.microsoft.azure.storage.table.TableTestHelper; +import com.microsoft.azure.storage.TestRunners.CloudTests; +import com.microsoft.azure.storage.TestRunners.DevFabricTests; +import com.microsoft.azure.storage.TestRunners.DevStoreTests; +import com.microsoft.azure.storage.TestRunners.SlowTests; + +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.List; + +import static org.junit.Assert.*; @Category({ SecondaryTests.class, DevFabricTests.class, DevStoreTests.class, CloudTests.class }) public class SecondaryTests { @@ -316,8 +316,8 @@ public void testTableIfExistsShouldNotHitSecondary() throws StorageException, UR } } - @Category(SlowTests.class) @Test + @Category(SlowTests.class) public void testMultiLocationRetriesBlob() throws URISyntaxException, StorageException { List retryInfoList = new ArrayList(); List retryContextList = new ArrayList(); @@ -425,8 +425,8 @@ public void testMultiLocationRetriesBlob() throws URISyntaxException, StorageExc retryContextList, retryInfoList); } - @Category(SlowTests.class) @Test + @Category(SlowTests.class) public void testMultiLocationRetriesQueue() throws URISyntaxException, StorageException { List retryInfoList = new ArrayList(); List retryContextList = new ArrayList(); @@ -534,8 +534,8 @@ public void testMultiLocationRetriesQueue() throws URISyntaxException, StorageEx retryContextList, retryInfoList); } - @Category(SlowTests.class) @Test + @Category(SlowTests.class) public void testMultiLocationRetriesTable() throws URISyntaxException, StorageException { List retryInfoList = new ArrayList(); List retryContextList = new ArrayList(); diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/ServicePropertiesTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/ServicePropertiesTests.java index be74459a9b78..d8221890f83d 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/ServicePropertiesTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/ServicePropertiesTests.java @@ -1,11 +1,11 @@ /** * Copyright Microsoft Corporation - * + * * Licensed 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. @@ -14,33 +14,33 @@ */ package com.microsoft.azure.storage; -import static org.junit.Assert.*; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.EnumSet; -import java.util.List; - -import org.junit.Test; -import org.junit.experimental.categories.Category; - -import com.microsoft.azure.storage.TestRunners.CloudTests; -import com.microsoft.azure.storage.TestRunners.DevFabricTests; -import com.microsoft.azure.storage.TestRunners.DevStoreTests; -import com.microsoft.azure.storage.TestRunners.SlowTests; import com.microsoft.azure.storage.blob.CloudBlobClient; import com.microsoft.azure.storage.core.SR; import com.microsoft.azure.storage.file.CloudFileClient; import com.microsoft.azure.storage.file.FileServiceProperties; import com.microsoft.azure.storage.queue.CloudQueueClient; import com.microsoft.azure.storage.table.CloudTableClient; +import com.microsoft.azure.storage.TestRunners.CloudTests; +import com.microsoft.azure.storage.TestRunners.DevFabricTests; +import com.microsoft.azure.storage.TestRunners.DevStoreTests; +import com.microsoft.azure.storage.TestRunners.SlowTests; + +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.EnumSet; +import java.util.List; + +import static org.junit.Assert.*; @Category({ SlowTests.class, DevFabricTests.class, DevStoreTests.class, CloudTests.class }) public class ServicePropertiesTests { /** * Test Analytics Disable Service Properties - * + * * @throws StorageException * @throws InterruptedException */ @@ -83,7 +83,7 @@ private void testAnalyticsDisable(ServiceClient client, ServiceProperties props) /** * Test Analytics Default Service Version - * + * * @throws StorageException * @throws InterruptedException */ @@ -143,7 +143,7 @@ private void testAnalyticsDefaultServiceVersion(ServiceClient client, ServicePro /** * Test Analytics Logging Operations - * + * * @throws StorageException * @throws InterruptedException */ @@ -183,7 +183,7 @@ private void testAnalyticsLoggingOperations(ServiceClient client, ServicePropert /** * Test Analytics Hour Metrics Level - * + * * @throws StorageException * @throws InterruptedException */ @@ -201,7 +201,7 @@ public void testAnalyticsHourMetricsLevel() throws StorageException, Interrupted client = TestHelper.createCloudTableClient(); props = new ServiceProperties(); testAnalyticsHourMetricsLevel(client, props, null); - + client = TestHelper.createCloudFileClient(); FileServiceProperties fileProps = new FileServiceProperties(); testAnalyticsHourMetricsLevel(client, null, fileProps); @@ -212,7 +212,7 @@ private void testAnalyticsHourMetricsLevel( throws StorageException, InterruptedException { final MetricsProperties hours = (props == null) ? fileProps.getHourMetrics() : props.getHourMetrics(); - + // None hours.setMetricsLevel(MetricsLevel.DISABLED); hours.setRetentionIntervalInDays(null); @@ -251,7 +251,7 @@ private void testAnalyticsHourMetricsLevel( /** * Test Analytics Minute Metrics Level - * + * * @throws StorageException * @throws InterruptedException */ @@ -269,7 +269,7 @@ public void testAnalyticsMinuteMetricsLevel() throws StorageException, Interrupt client = TestHelper.createCloudTableClient(); props = new ServiceProperties(); testAnalyticsMinuteMetricsLevel(client, props, null); - + client = TestHelper.createCloudFileClient(); FileServiceProperties fileProps = new FileServiceProperties(); testAnalyticsMinuteMetricsLevel(client, null, fileProps); @@ -278,9 +278,9 @@ public void testAnalyticsMinuteMetricsLevel() throws StorageException, Interrupt private void testAnalyticsMinuteMetricsLevel( final ServiceClient client, final ServiceProperties props, final FileServiceProperties fileProps) throws StorageException, InterruptedException { - + final MetricsProperties minutes = (props == null) ? fileProps.getMinuteMetrics() : props.getMinuteMetrics(); - + // None minutes.setMetricsLevel(MetricsLevel.DISABLED); minutes.setRetentionIntervalInDays(null); @@ -319,7 +319,7 @@ private void testAnalyticsMinuteMetricsLevel( /** * Test Analytics Retention Policies - * + * * @throws StorageException * @throws InterruptedException */ @@ -399,7 +399,7 @@ private void testAnalyticsRetentionPolicies(ServiceClient client, ServicePropert /** * Test CORS with different rules. - * + * * @throws StorageException * @throws InterruptedException */ @@ -417,7 +417,7 @@ public void testCloudValidCorsRules() throws StorageException, InterruptedExcept client = TestHelper.createCloudTableClient(); props = new ServiceProperties(); testCloudValidCorsRules(client, props, null); - + client = TestHelper.createCloudFileClient(); testCloudValidCorsRules(client, null, new FileServiceProperties()); } @@ -540,7 +540,7 @@ public void testCorsExpectedExceptions() throws StorageException { client = TestHelper.createCloudTableClient(); props = new ServiceProperties(); testCorsExpectedExceptions(client, props, null); - + client = TestHelper.createCloudFileClient(); testCorsExpectedExceptions(client, null, new FileServiceProperties()); } @@ -585,7 +585,7 @@ private void testCorsExpectedExceptions( /** * Test CORS with a valid and invalid number of origin values sent to server. - * + * * @throws StorageException * @throws InterruptedException */ @@ -603,7 +603,7 @@ public void testCorsMaxOrigins() throws StorageException, InterruptedException { client = TestHelper.createCloudTableClient(); props = new ServiceProperties(); testCorsMaxOrigins(client, props, null); - + client = TestHelper.createCloudFileClient(); testCorsMaxOrigins(client, null, new FileServiceProperties()); } @@ -636,7 +636,7 @@ private void testCorsMaxOrigins( /** * Test CORS with a valid and invalid number of header values sent to server. - * + * * @throws StorageException * @throws InterruptedException */ @@ -654,7 +654,7 @@ public void testCorsMaxHeaders() throws StorageException, InterruptedException { client = TestHelper.createCloudTableClient(); props = new ServiceProperties(); testCorsMaxHeaders(client, props, null); - + client = TestHelper.createCloudFileClient(); testCorsMaxHeaders(client, null, new FileServiceProperties()); } @@ -739,7 +739,7 @@ private void testCorsMaxHeaders( /** * Test Optional Service Properties - * + * * @throws StorageException * @throws InterruptedException */ @@ -813,7 +813,7 @@ private void testOptionalServiceProperties(ServiceClient client, ServiceProperti private void callUploadServiceProps( ServiceClient client, ServiceProperties props, FileServiceProperties fileProps) throws StorageException, InterruptedException { - + if (client.getClass().equals(CloudBlobClient.class)) { ((CloudBlobClient) client).uploadServiceProperties(props); } @@ -829,7 +829,7 @@ else if (client.getClass().equals(CloudFileClient.class)) { else { fail(); } - + Thread.sleep(30000); } @@ -906,7 +906,7 @@ private static void assertServicePropertiesAreEqual(ServiceProperties propsA, Se assertNotNull(propsA); assertNotNull(propsB); } - + if (propsA.getLogging() != null && propsB.getLogging() != null) { assertTrue(propsA.getLogging().getLogOperationTypes().equals(propsB.getLogging().getLogOperationTypes())); assertEquals(propsA.getLogging().getRetentionIntervalInDays(), propsB.getLogging() @@ -975,10 +975,10 @@ private static void assertServicePropertiesAreEqual(ServiceProperties propsA, Se assertNull(propsB.getCors()); } } - + /** * Checks the CORS rules of two FileServiceProperties objects to ensure they match. - * + * * @param original * The FileServiceProperties used as a point of comparison * @param target @@ -991,7 +991,7 @@ private static void assertFileServicePropertiesAreEqual(FileServiceProperties or assertNotNull(original); assertNotNull(target); } - + if (original.getCors() != null && target.getCors() != null) { assertEquals(original.getCors().getCorsRules().size(), target.getCors().getCorsRules().size()); diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/StorageAccountTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/StorageAccountTests.java index c7f0f17e54a0..33281527309f 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/StorageAccountTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/StorageAccountTests.java @@ -1,11 +1,11 @@ /** * Copyright Microsoft Corporation - * + * * Licensed 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. @@ -14,20 +14,6 @@ */ package com.microsoft.azure.storage; -import static org.junit.Assert.*; - -import java.net.URI; -import java.net.URISyntaxException; -import java.security.InvalidKeyException; -import java.util.Locale; -import java.util.UUID; - -import org.junit.Test; -import org.junit.experimental.categories.Category; - -import com.microsoft.azure.storage.TestRunners.CloudTests; -import com.microsoft.azure.storage.TestRunners.DevFabricTests; -import com.microsoft.azure.storage.TestRunners.DevStoreTests; import com.microsoft.azure.storage.blob.CloudBlobClient; import com.microsoft.azure.storage.blob.CloudBlobContainer; import com.microsoft.azure.storage.core.Base64; @@ -38,6 +24,21 @@ import com.microsoft.azure.storage.queue.CloudQueueClient; import com.microsoft.azure.storage.table.CloudTable; import com.microsoft.azure.storage.table.CloudTableClient; +import com.microsoft.azure.storage.TestRunners.CloudTests; +import com.microsoft.azure.storage.TestRunners.DevFabricTests; +import com.microsoft.azure.storage.TestRunners.DevStoreTests; + +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import java.net.URI; +import java.net.URISyntaxException; +import java.security.InvalidKeyException; +import java.util.Locale; +import java.util.UUID; + +import static org.junit.Assert.*; + @Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) public class StorageAccountTests { @@ -75,12 +76,12 @@ public void testStorageCredentialsSharedKey() throws URISyntaxException, Storage cred = new StorageCredentialsAccountAndKey(ACCOUNT_NAME, base64EncodedDummyKey); assertEquals(base64EncodedDummyKey, cred.exportBase64EncodedKey()); } - + @Test public void testStorageCredentialsSharedKeyUpdateKey() throws URISyntaxException, StorageException { StorageCredentialsAccountAndKey cred = new StorageCredentialsAccountAndKey(ACCOUNT_NAME, ACCOUNT_KEY); assertEquals(ACCOUNT_KEY, cred.exportBase64EncodedKey()); - + // Validate update with byte array byte[] dummyKey = { 0, 1, 2 }; cred.updateKey(dummyKey); @@ -312,7 +313,7 @@ public void testCloudStorageAccountClientMethods() throws URISyntaxException { CloudTableClient table = account.createCloudTableClient(); CloudFileClient file = account.createCloudFileClient(); - // check endpoints + // check endpoints assertEquals("Blob endpoint doesn't match account", account.getBlobEndpoint(), blob.getEndpoint()); assertEquals("Queue endpoint doesn't match account", account.getQueueEndpoint(), queue.getEndpoint()); assertEquals("Table endpoint doesn't match account", account.getTableEndpoint(), table.getEndpoint()); @@ -409,7 +410,7 @@ public void testCloudStorageAccountDevStoreFalsePlusEndpointFails() assertEquals(SR.INVALID_CONNECTION_STRING_DEV_STORE_NOT_TRUE, ex.getMessage()); } } - + @Test public void testCloudStorageAccountDevStoreFalsePlusEndpointSuffixFails() throws InvalidKeyException, URISyntaxException { @@ -521,7 +522,7 @@ public void testCloudStorageAccountAnonymousRoundtrip() AccountsAreEqual(account, CloudStorageAccount.parse(account.toString(true))); } - + @Test public void testCloudStorageAccountInvalidAnonymousRoundtrip() throws InvalidKeyException, URISyntaxException { @@ -544,13 +545,13 @@ public void testCloudStorageAccountEmptyValues() throws InvalidKeyException, URI assertEquals(validAccountString, CloudStorageAccount.parse(accountString).toString(true)); } - + @Test public void testCloudStorageAccountEndpointSuffix() throws InvalidKeyException, URISyntaxException, StorageException { final String mooncake = "core.chinacloudapi.cn"; final String fairfax = "core.usgovcloudapi.net"; - + // Endpoint suffix for mooncake CloudStorageAccount accountParse = CloudStorageAccount.parse( "DefaultEndpointsProtocol=http;AccountName=test;" @@ -562,7 +563,7 @@ public void testCloudStorageAccountEndpointSuffix() assertNotNull(accountParse.getBlobEndpoint()); assertEquals(accountParse.getBlobEndpoint(), accountConstruct.getBlobEndpoint()); assertTrue(accountParse.getBlobEndpoint().toString().endsWith(mooncake)); - + // Endpoint suffix for fairfax accountParse = CloudStorageAccount.parse( "TableEndpoint=http://tables/;DefaultEndpointsProtocol=http;" @@ -574,7 +575,7 @@ public void testCloudStorageAccountEndpointSuffix() assertNotNull(accountParse.getBlobEndpoint()); assertEquals(accountParse.getBlobEndpoint(), accountConstruct.getBlobEndpoint()); assertTrue(accountParse.getBlobEndpoint().toString().endsWith(fairfax)); - + // Explicit table endpoint should override endpoint suffix for fairfax CloudTableClient tableClientParse = accountParse.createCloudTableClient(); assertNotNull(tableClientParse); diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/StorageUriTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/StorageUriTests.java index f067a0c30d8b..298cfaff5a0c 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/StorageUriTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/StorageUriTests.java @@ -1,11 +1,11 @@ /** * Copyright Microsoft Corporation - * + * * Licensed 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. @@ -14,18 +14,6 @@ */ package com.microsoft.azure.storage; -import static org.junit.Assert.*; - -import java.net.URI; -import java.net.URISyntaxException; -import java.security.InvalidKeyException; - -import org.junit.Test; -import org.junit.experimental.categories.Category; - -import com.microsoft.azure.storage.TestRunners.CloudTests; -import com.microsoft.azure.storage.TestRunners.DevFabricTests; -import com.microsoft.azure.storage.TestRunners.DevStoreTests; import com.microsoft.azure.storage.blob.CloudBlobClient; import com.microsoft.azure.storage.blob.CloudBlobContainer; import com.microsoft.azure.storage.blob.CloudBlobDirectory; @@ -36,6 +24,18 @@ import com.microsoft.azure.storage.queue.CloudQueueClient; import com.microsoft.azure.storage.table.CloudTable; import com.microsoft.azure.storage.table.CloudTableClient; +import com.microsoft.azure.storage.TestRunners.CloudTests; +import com.microsoft.azure.storage.TestRunners.DevFabricTests; +import com.microsoft.azure.storage.TestRunners.DevStoreTests; + +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import java.net.URI; +import java.net.URISyntaxException; +import java.security.InvalidKeyException; + +import static org.junit.Assert.*; @Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) public class StorageUriTests { diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/TestRunners.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/TestRunners.java index 074d6c8eb8ab..81e98d61af39 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/TestRunners.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/TestRunners.java @@ -1,19 +1,26 @@ +/** + * Copyright Microsoft Corporation + * + * Licensed 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 com.microsoft.azure.storage; -import org.junit.experimental.categories.Categories; -import org.junit.experimental.categories.Categories.ExcludeCategory; -import org.junit.experimental.categories.Categories.IncludeCategory; -import org.junit.runner.RunWith; -import org.junit.runners.Suite; -import org.junit.runners.Suite.SuiteClasses; - import com.microsoft.azure.storage.analytics.CloudAnalyticsClientTests; import com.microsoft.azure.storage.blob.BlobOutputStreamTests; import com.microsoft.azure.storage.blob.CloudAppendBlobTests; +import com.microsoft.azure.storage.blob.CloudBlobClientEncryptionTests; import com.microsoft.azure.storage.blob.CloudBlobClientTests; import com.microsoft.azure.storage.blob.CloudBlobContainerTests; import com.microsoft.azure.storage.blob.CloudBlobDirectoryTests; -import com.microsoft.azure.storage.blob.CloudBlobClientEncryptionTests; import com.microsoft.azure.storage.blob.CloudBlobServerEncryptionTests; import com.microsoft.azure.storage.blob.CloudBlockBlobTests; import com.microsoft.azure.storage.blob.CloudPageBlobTests; @@ -39,9 +46,16 @@ import com.microsoft.azure.storage.table.TableSerializerTests; import com.microsoft.azure.storage.table.TableTests; +import org.junit.experimental.categories.Categories; +import org.junit.experimental.categories.Categories.ExcludeCategory; +import org.junit.experimental.categories.Categories.IncludeCategory; +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + /** * Contains the various test suites and test categories used to run JUnit tests - * + * * To run with junit from command line: * 1. Install junit and add it to the classpath. * 2. Add any project dependencies to the classpath. (ex CLASSPATH=%CLASSPATH%;{path to dependency};) @@ -52,15 +66,15 @@ * 4. Suite: java org.junit.runner.JUnitCore com.microsoft.azure.storage.TestRunners$FastTestSuite * 5. Class: java org.junit.runner.JUnitCore com.microsoft.azure.storage.TableOperationTests * 6. Test: can't do this natively; must make a runner - * + * * To run with maven from command line: * 1. Suite: mvn test -DrunSuite="TestRunners.FastTestSuite" * 2. Class: mvn test -Dtest=TableOperationTests * 3. Test: mvn test -Dtest=TableOperationTests$testDelete - * + * * To run with eclipse: * 1. Right click the suite/class/test you'd like to run in the package explorer and click Run As > JUnit Test - * + * * Other notes about suites: * 1. Can't include or exclude multipe categories, instead make two suites and merge them into one. * 2. With maven you cannot (easily) run tests from inside a jar. @@ -100,7 +114,7 @@ public static class CoreTestSuite { } @RunWith(Suite.class) - @SuiteClasses({ BlobOutputStreamTests.class, CloudBlobClientTests.class, CloudBlobContainerTests.class, + @SuiteClasses({ BlobOutputStreamTests.class, CloudBlobClientTests.class, CloudBlobContainerTests.class, CloudBlobDirectoryTests.class, CloudAppendBlobTests.class, CloudBlockBlobTests.class, CloudPageBlobTests.class, CloudBlobClientEncryptionTests.class, CloudBlobServerEncryptionTests.class, LeaseTests.class, SasTests.class }) public static class BlobTestSuite { @@ -129,7 +143,7 @@ public static class FileTestSuite { @SuiteClasses({ CloudAnalyticsClientTests.class }) public static class AnalyticsTestSuite { } - + @RunWith(Suite.class) @SuiteClasses({ CloudBlobClientEncryptionTests.class, CloudBlobServerEncryptionTests.class, CloudQueueEncryptionTests.class, TableEncryptionTests.class }) @@ -138,7 +152,7 @@ public static class EncryptionTestSuite { @RunWith(Suite.class) @SuiteClasses({ CoreTestSuite.class, BlobTestSuite.class, QueueTestSuite.class, TableTestSuite.class, - FileTestSuite.class, AnalyticsTestSuite.class, EncryptionTestSuite.class }) + FileTestSuite.class, AnalyticsTestSuite.class }) public static class AllTestSuite { } diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/analytics/AnalyticsTestHelper.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/analytics/AnalyticsTestHelper.java index 1c901e146a6f..ae28b8da96fd 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/analytics/AnalyticsTestHelper.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/analytics/AnalyticsTestHelper.java @@ -1,11 +1,11 @@ /** * Copyright Microsoft Corporation - * + * * Licensed 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. @@ -14,6 +14,12 @@ */ package com.microsoft.azure.storage.analytics; +import com.microsoft.azure.storage.StorageException; +import com.microsoft.azure.storage.TestHelper; +import com.microsoft.azure.storage.blob.CloudBlobClient; +import com.microsoft.azure.storage.blob.CloudBlobContainer; +import com.microsoft.azure.storage.blob.CloudBlockBlob; + import java.io.ByteArrayInputStream; import java.io.IOException; import java.net.URISyntaxException; @@ -28,12 +34,6 @@ import java.util.TimeZone; import java.util.UUID; -import com.microsoft.azure.storage.StorageException; -import com.microsoft.azure.storage.TestHelper; -import com.microsoft.azure.storage.blob.CloudBlobClient; -import com.microsoft.azure.storage.blob.CloudBlobContainer; -import com.microsoft.azure.storage.blob.CloudBlockBlob; - /** * Analytics Test Base */ diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/analytics/CloudAnalyticsClientTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/analytics/CloudAnalyticsClientTests.java index 06e5b81322ab..822a4f9bfe16 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/analytics/CloudAnalyticsClientTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/analytics/CloudAnalyticsClientTests.java @@ -1,11 +1,11 @@ /** * Copyright Microsoft Corporation - * + * * Licensed 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. @@ -14,7 +14,22 @@ */ package com.microsoft.azure.storage.analytics; -import static org.junit.Assert.*; +import com.microsoft.azure.storage.Constants; +import com.microsoft.azure.storage.StorageException; +import com.microsoft.azure.storage.StorageLocation; +import com.microsoft.azure.storage.TestRunners; +import com.microsoft.azure.storage.blob.CloudBlobContainer; +import com.microsoft.azure.storage.blob.CloudBlockBlob; +import com.microsoft.azure.storage.blob.ListBlobItem; +import com.microsoft.azure.storage.table.CloudTable; +import com.microsoft.azure.storage.TestRunners.CloudTests; +import com.microsoft.azure.storage.TestRunners.DevFabricTests; +import com.microsoft.azure.storage.TestRunners.DevStoreTests; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.experimental.categories.Category; import java.io.IOException; import java.net.URI; @@ -28,21 +43,7 @@ import java.util.NoSuchElementException; import java.util.UUID; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.experimental.categories.Category; - -import com.microsoft.azure.storage.Constants; -import com.microsoft.azure.storage.StorageException; -import com.microsoft.azure.storage.StorageLocation; -import com.microsoft.azure.storage.TestRunners.CloudTests; -import com.microsoft.azure.storage.TestRunners.DevFabricTests; -import com.microsoft.azure.storage.TestRunners.DevStoreTests; -import com.microsoft.azure.storage.blob.CloudBlobContainer; -import com.microsoft.azure.storage.blob.CloudBlockBlob; -import com.microsoft.azure.storage.blob.ListBlobItem; -import com.microsoft.azure.storage.table.CloudTable; +import static org.junit.Assert.*; /** * Analytics Client Tests @@ -66,7 +67,7 @@ public void analyticsTestMethodTearDown() throws StorageException { /** * Test table getters. - * + * * @throws StorageException * @throws URISyntaxException */ @@ -115,7 +116,7 @@ public void testCloudAnalyticsClientGetTables() throws URISyntaxException, Stora /** * List all logs - * + * * @throws URISyntaxException * @throws StorageException * @throws IOException @@ -142,7 +143,7 @@ public void testCloudAnalyticsClientListLogs() throws URISyntaxException, Storag /** * List Logs with open ended time range - * + * * @throws URISyntaxException * @throws StorageException * @throws IOException @@ -172,7 +173,7 @@ public void testCloudAnalyticsClientListLogsStartTime() throws URISyntaxExceptio /** * List Logs with well defined time range - * + * * @throws URISyntaxException * @throws StorageException * @throws IOException @@ -204,7 +205,7 @@ public void testCloudAnalyticsClientListLogsStartEndTime() throws URISyntaxExcep /** * Validate Log Parser - * + * * @throws ParseException * @throws URISyntaxException * @throws StorageException @@ -302,7 +303,7 @@ public void testCloudAnalyticsClientParseExLogs() throws ParseException, URISynt /** * Validate Log Parser with prod data - * + * * @throws ParseException * @throws URISyntaxException * @throws StorageException @@ -329,7 +330,7 @@ public void testCloudAnalyticsClientParseProdLogs() throws ParseException, URISy /** * Log parser error cases. - * + * * @throws ParseException * @throws URISyntaxException * @throws StorageException diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/analytics/Granularity.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/analytics/Granularity.java index c279560a297d..8126565826dd 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/analytics/Granularity.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/analytics/Granularity.java @@ -1,11 +1,11 @@ /** * Copyright Microsoft Corporation - * + * * Licensed 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. diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/BlobOutputStreamTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/BlobOutputStreamTests.java index 6c3275d86bd0..18556b8a2714 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/BlobOutputStreamTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/BlobOutputStreamTests.java @@ -14,7 +14,20 @@ */ package com.microsoft.azure.storage.blob; -import static org.junit.Assert.*; +import com.microsoft.azure.storage.AccessCondition; +import com.microsoft.azure.storage.Constants; +import com.microsoft.azure.storage.OperationContext; +import com.microsoft.azure.storage.ResponseReceivedEvent; +import com.microsoft.azure.storage.StorageEvent; +import com.microsoft.azure.storage.StorageException; +import com.microsoft.azure.storage.TestRunners; +import com.microsoft.azure.storage.TestRunners.CloudTests; +import com.microsoft.azure.storage.core.SR; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.experimental.categories.Category; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -28,19 +41,7 @@ import java.util.concurrent.Executors; import java.util.concurrent.Future; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.experimental.categories.Category; - -import com.microsoft.azure.storage.AccessCondition; -import com.microsoft.azure.storage.Constants; -import com.microsoft.azure.storage.OperationContext; -import com.microsoft.azure.storage.ResponseReceivedEvent; -import com.microsoft.azure.storage.StorageEvent; -import com.microsoft.azure.storage.StorageException; -import com.microsoft.azure.storage.TestRunners.CloudTests; -import com.microsoft.azure.storage.core.SR; +import static org.junit.Assert.*; /** * Blob Output Stream Tests @@ -60,7 +61,7 @@ public void blobOutputStreamTestMethodSetup() throws URISyntaxException, Storage public void blobOutputStreamTestMethodTearDown() throws StorageException { this.container.deleteIfExists(); } - + @Test public void testEmpty() throws URISyntaxException, StorageException, IOException { String blobName = BlobTestHelper.generateRandomBlobNameWithPrefix("testblob"); @@ -76,7 +77,7 @@ public void testEmpty() throws URISyntaxException, StorageException, IOException ArrayList blocks = blockBlob2.downloadBlockList(BlockListingFilter.ALL, null, null, null); assertEquals(0, blocks.size()); } - + @Test public void testClose() throws URISyntaxException, StorageException, IOException { String blobName = BlobTestHelper.generateRandomBlobNameWithPrefix("testblob"); @@ -101,7 +102,7 @@ public void testClose() throws URISyntaxException, StorageException, IOException blocks = blockBlob.downloadBlockList(BlockListingFilter.COMMITTED, null, null, null); assertEquals(1, blocks.size()); } - + @Test public void testWithAccessCondition() throws URISyntaxException, StorageException, IOException { int blobLengthToUse = 8 * 512; @@ -131,7 +132,7 @@ public void testWithAccessCondition() throws URISyntaxException, StorageExceptio assertEquals(0, result[i]); } } - + @Test public void testWriteStream() throws URISyntaxException, StorageException, IOException { int blobLengthToUse = 8 * 512; @@ -160,7 +161,7 @@ public void testWriteStream() throws URISyntaxException, StorageException, IOExc assertEquals(0, result[i]); } } - + @Test public void testFlush() throws Exception { CloudBlockBlob blockBlob = this.container.getBlockBlobReference( @@ -212,7 +213,7 @@ public void eventOccurred(ResponseReceivedEvent eventArg) { assertEquals(2, blocks.size()); assertEquals(513, blocks.get(1).getSize()); } - + @Test public void testWritesDoubleConcurrency() throws URISyntaxException, StorageException, IOException, InterruptedException { @@ -254,7 +255,7 @@ public void testWritesDoubleConcurrency() throws URISyntaxException, StorageExce blockBlob.downloadAttributes(); assertTrue(blockBlob.getProperties().getLength() == length*writes*tasks); } - + @Test public void testWritesNoConcurrency() throws URISyntaxException, StorageException, IOException { int writes = 10; diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/BlobTestHelper.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/BlobTestHelper.java index 0a2334cf04a6..4e6aa41febdf 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/BlobTestHelper.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/BlobTestHelper.java @@ -14,7 +14,10 @@ */ package com.microsoft.azure.storage.blob; -import static org.junit.Assert.*; +import com.microsoft.azure.storage.OperationContext; +import com.microsoft.azure.storage.StorageCredentials; +import com.microsoft.azure.storage.StorageException; +import com.microsoft.azure.storage.TestHelper; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -27,10 +30,7 @@ import java.util.Random; import java.util.UUID; -import com.microsoft.azure.storage.OperationContext; -import com.microsoft.azure.storage.StorageCredentials; -import com.microsoft.azure.storage.StorageException; -import com.microsoft.azure.storage.TestHelper; +import static org.junit.Assert.*; /** * Blob Test Base diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudAppendBlobTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudAppendBlobTests.java index 429ed23494a7..58ad64baeaf5 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudAppendBlobTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudAppendBlobTests.java @@ -14,7 +14,24 @@ */ package com.microsoft.azure.storage.blob; -import static org.junit.Assert.*; +import com.microsoft.azure.storage.AccessCondition; +import com.microsoft.azure.storage.core.SR; +import com.microsoft.azure.storage.core.Utility; +import com.microsoft.azure.storage.OperationContext; +import com.microsoft.azure.storage.ResponseReceivedEvent; +import com.microsoft.azure.storage.RetryNoRetry; +import com.microsoft.azure.storage.SendingRequestEvent; +import com.microsoft.azure.storage.StorageErrorCodeStrings; +import com.microsoft.azure.storage.StorageEvent; +import com.microsoft.azure.storage.StorageException; +import com.microsoft.azure.storage.TestRunners; +import com.microsoft.azure.storage.TestRunners.CloudTests; +import com.microsoft.azure.storage.TestRunners.DevFabricTests; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.experimental.categories.Category; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -29,23 +46,7 @@ import java.util.EnumSet; import java.util.Random; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.experimental.categories.Category; - -import com.microsoft.azure.storage.AccessCondition; -import com.microsoft.azure.storage.OperationContext; -import com.microsoft.azure.storage.ResponseReceivedEvent; -import com.microsoft.azure.storage.RetryNoRetry; -import com.microsoft.azure.storage.SendingRequestEvent; -import com.microsoft.azure.storage.StorageErrorCodeStrings; -import com.microsoft.azure.storage.StorageEvent; -import com.microsoft.azure.storage.StorageException; -import com.microsoft.azure.storage.TestRunners.CloudTests; -import com.microsoft.azure.storage.TestRunners.DevFabricTests; -import com.microsoft.azure.storage.core.SR; -import com.microsoft.azure.storage.core.Utility; +import static org.junit.Assert.*; @Category({ DevFabricTests.class, CloudTests.class }) public class CloudAppendBlobTests { @@ -193,7 +194,8 @@ public void eventOccurred(SendingRequestEvent eventArg) { * Start copying a blob and then abort */ @Test - public void testCopyFromAppendBlobAbortTest() throws StorageException, URISyntaxException, IOException { + public void testCopyFromAppendBlobAbortTest() throws StorageException, + URISyntaxException, IOException { final int length = 512; CloudAppendBlob originalBlob = (CloudAppendBlob) BlobTestHelper.uploadNewBlob( this.container, BlobType.APPEND_BLOB, "originalBlob", length, null); @@ -559,8 +561,8 @@ public void testCloudAppendBlobUploadFromStreamWithAccessCondition() } @Test - public void testAppendBlobNamePlusEncodingTest() - throws StorageException, URISyntaxException, IOException, InterruptedException { + public void testAppendBlobNamePlusEncodingTest() throws StorageException, + URISyntaxException, IOException, InterruptedException { final int length = 1 * 1024; final CloudAppendBlob originalBlob = (CloudAppendBlob) BlobTestHelper.uploadNewBlob( @@ -607,7 +609,7 @@ public void testAppendBlobInputStream() throws URISyntaxException, blobRef.delete(); } - + @Test public void testAppendBlobUploadNegativeLength() throws URISyntaxException, StorageException, IOException { @@ -626,7 +628,7 @@ public void testAppendBlobUploadNegativeLength() throws URISyntaxException, assertTrue(blobRef.exists()); assertEquals(blobRef.getProperties().getLength(), blobLength); } - + @Test public void testAppendBlobMaxSizeCondition() throws URISyntaxException, StorageException, IOException { @@ -651,7 +653,7 @@ public void testAppendBlobMaxSizeCondition() throws URISyntaxException, assertEquals(SR.INVALID_BLOCK_SIZE, ex.getMessage()); } } - + @Test public void testAppendBlobWriteStreamConditionalRetry() throws URISyntaxException, StorageException, IOException { @@ -747,8 +749,8 @@ public void testUploadDownloadFromFile() throws IOException, } @Test - public void testAppendBlobCopyTest() - throws URISyntaxException, StorageException, InterruptedException, IOException { + public void testAppendBlobCopyTest() throws URISyntaxException, + StorageException, InterruptedException, IOException { Calendar calendar = Calendar.getInstance(Utility.UTC_ZONE); CloudAppendBlob source = this.container @@ -867,8 +869,8 @@ public void testAppendBlobCopyWithMetadataOverride() } @Test - public void testAppendBlobCopyFromSnapshot() - throws StorageException, IOException, URISyntaxException, InterruptedException { + public void testAppendBlobCopyFromSnapshot() throws StorageException, + IOException, URISyntaxException, InterruptedException { CloudAppendBlob source = this.container .getAppendBlobReference("source"); @@ -1108,7 +1110,7 @@ public void testOpenOutputStreamNoArgs() throws URISyntaxException, assertEquals(0, appendBlob2.getProperties().getLength()); assertEquals(BlobType.APPEND_BLOB, appendBlob2.getProperties().getBlobType()); } - + @Test public void testOpenOutputStreamWithConditions() throws StorageException, IOException, URISyntaxException { @@ -1163,7 +1165,7 @@ public void testOpenOutputStreamWithConditions() throws StorageException, IOExce assertEquals("AppendPositionConditionNotMet", internalException.getErrorCode()); } } - + @Test public void testOpenOutputStreamMultiWriterFail() throws StorageException, IOException, URISyntaxException { @@ -1208,7 +1210,7 @@ public void testOpenOutputStreamMultiWriterFail() throws StorageException, internalException.getErrorCode()); } } - + @Test public void testAppendBlockFromStream() throws StorageException, IOException, URISyntaxException { @@ -1236,7 +1238,7 @@ public void testAppendBlockFromStream() throws StorageException, IOException, UR pos = blob.appendBlock(sourceStream, -1); assertEquals(blobSize, pos); } - + @Test public void testAppendBlockFromStreamWithConditions() throws StorageException, IOException, URISyntaxException { @@ -1290,7 +1292,7 @@ public void testAppendBlockFromStreamWithConditions() throws StorageException, I assertEquals("AppendPositionConditionNotMet", ex.getErrorCode()); } } - + @Test public void testAppendBlobUploadFromStream() throws StorageException, IOException, URISyntaxException { @@ -1311,7 +1313,7 @@ public void testAppendBlobUploadFromStream() throws StorageException, IOExceptio blob.downloadAttributes(); assertEquals(6 * 1024 * 1024, blob.getProperties().getLength()); } - + @Test public void testAppendBlobAppendFromStream() throws StorageException, IOException, URISyntaxException { @@ -1334,7 +1336,7 @@ public void testAppendBlobAppendFromStream() throws StorageException, IOExceptio blob.downloadAttributes(); assertEquals(18 * 1024 * 1024, blob.getProperties().getLength()); } - + @Test public void testAppendBlobAppendFromStreamWithLength() throws StorageException, IOException, URISyntaxException { diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlobClientTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlobClientTests.java index 1b07b8e3e3fa..9a8226f56809 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlobClientTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlobClientTests.java @@ -14,8 +14,6 @@ */ package com.microsoft.azure.storage.blob; -import static org.junit.Assert.*; - import java.io.IOException; import java.net.URISyntaxException; import java.util.ArrayList; @@ -25,6 +23,7 @@ import org.junit.experimental.categories.Category; import com.microsoft.azure.storage.Constants; +import com.microsoft.azure.storage.core.SR; import com.microsoft.azure.storage.LocationMode; import com.microsoft.azure.storage.OperationContext; import com.microsoft.azure.storage.ResultContinuation; @@ -35,7 +34,9 @@ import com.microsoft.azure.storage.TestRunners.CloudTests; import com.microsoft.azure.storage.TestRunners.DevFabricTests; import com.microsoft.azure.storage.TestRunners.DevStoreTests; -import com.microsoft.azure.storage.core.SR; +import com.microsoft.azure.storage.TestRunners; + +import static org.junit.Assert.*; /** * Blob Client Tests diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlobContainerTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlobContainerTests.java index ecd82ba788f5..525435966b15 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlobContainerTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlobContainerTests.java @@ -14,29 +14,9 @@ */ package com.microsoft.azure.storage.blob; -import static org.junit.Assert.*; - -import java.io.IOException; -import java.net.HttpURLConnection; -import java.net.URISyntaxException; -import java.security.InvalidKeyException; -import java.util.Calendar; -import java.util.Date; -import java.util.EnumSet; -import java.util.GregorianCalendar; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.TimeZone; -import java.util.UUID; - -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.experimental.categories.Category; import com.microsoft.azure.storage.Constants; +import com.microsoft.azure.storage.core.SR; import com.microsoft.azure.storage.NameValidator; import com.microsoft.azure.storage.OperationContext; import com.microsoft.azure.storage.ResultContinuation; @@ -50,14 +30,33 @@ import com.microsoft.azure.storage.TestRunners.DevFabricTests; import com.microsoft.azure.storage.TestRunners.DevStoreTests; import com.microsoft.azure.storage.TestRunners.SlowTests; -import com.microsoft.azure.storage.core.SR; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.URISyntaxException; +import java.security.InvalidKeyException; +import java.util.Calendar; +import java.util.Date; +import java.util.EnumSet; +import java.util.GregorianCalendar; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.TimeZone; +import java.util.UUID; + +import static org.junit.Assert.*; /** * Blob Container Tests */ @Category({ CloudTests.class }) public class CloudBlobContainerTests { - protected static CloudBlobClient client; protected CloudBlobContainer container; @@ -70,7 +69,7 @@ public void blobContainerTestMethodSetUp() throws StorageException, URISyntaxExc public void blobContainerTestMethodTearDown() throws StorageException { this.container.deleteIfExists(); } - + /** * Test container name validation. */ @@ -218,7 +217,7 @@ public void testCloudBlobContainerReferenceFromServerMissingBlob() throws Storag /** * Create a container - * + * * @throws StorageException */ @Test @@ -251,7 +250,7 @@ public void testCloudBlobContainerCreateIfNotExists() throws StorageException { /** * Try to delete a non-existing container - * + * * @throws StorageException */ @Test @@ -299,7 +298,7 @@ public void eventOccurred(SendingRequestEvent eventArg) { /** * Check a container's existence - * + * * @throws StorageException */ @Test @@ -437,28 +436,28 @@ public void testCloudBlobContainerUploadMetadata() throws StorageException, URIS CloudBlobContainer container2 = this.container.getServiceClient().getContainerReference( this.container.getName()); container2.downloadAttributes(); - Assert.assertEquals(0, container2.getMetadata().size()); + assertEquals(0, container2.getMetadata().size()); this.container.getMetadata().put("key1", "value1"); this.container.uploadMetadata(); container2.downloadAttributes(); - Assert.assertEquals(1, container2.getMetadata().size()); - Assert.assertEquals("value1", container2.getMetadata().get("key1")); + assertEquals(1, container2.getMetadata().size()); + assertEquals("value1", container2.getMetadata().get("key1")); Iterable containers = this.container.getServiceClient().listContainers( this.container.getName(), ContainerListingDetails.METADATA, null, null); for (CloudBlobContainer container3 : containers) { - Assert.assertEquals(1, container3.getMetadata().size()); - Assert.assertEquals("value1", container3.getMetadata().get("key1")); + assertEquals(1, container3.getMetadata().size()); + assertEquals("value1", container3.getMetadata().get("key1")); } this.container.getMetadata().clear(); this.container.uploadMetadata(); container2.downloadAttributes(); - Assert.assertEquals(0, container2.getMetadata().size()); + assertEquals(0, container2.getMetadata().size()); } @Test @@ -550,10 +549,10 @@ public void testCloudBlobContainerListBlobs() throws StorageException, IOExcepti assertTrue(blobNames.size() == 0); } - + /** * List the blobs in a container with a prefix - * + * * @throws URISyntaxException * @throws StorageException * @throws IOException @@ -568,7 +567,7 @@ public void testCloudBlobContainerListBlobsPrefix() throws StorageException, IOE BlobTestHelper.uploadNewBlob(this.container, BlobType.BLOCK_BLOB, "pref/blob1", 128, null); blobNames.add("pref/blob1"); - + BlobTestHelper.uploadNewBlob(this.container, BlobType.BLOCK_BLOB, "pref/blob2", 128, null); blobNames.add("pref/blob2"); @@ -580,7 +579,7 @@ public void testCloudBlobContainerListBlobsPrefix() throws StorageException, IOE count++; } assertEquals(1, count); - + // Flat listing true count = 0; for (ListBlobItem blob : this.container.listBlobs("pref", true)) { @@ -590,12 +589,12 @@ public void testCloudBlobContainerListBlobsPrefix() throws StorageException, IOE } assertEquals(2, count); } - + /** - * List the blobs in a container with next(). This tests for the item in the changelog: "Fixed a bug for all - * listing API's where next() would sometimes throw an exception if hasNext() had not been called even if + * List the blobs in a container with next(). This tests for the item in the changelog: "Fixed a bug for all + * listing API's where next() would sometimes throw an exception if hasNext() had not been called even if * there were more elements to iterate on." - * + * * @throws URISyntaxException * @throws StorageException * @throws IOException @@ -604,7 +603,7 @@ public void testCloudBlobContainerListBlobsPrefix() throws StorageException, IOE @Category({ DevFabricTests.class, DevStoreTests.class }) public void testCloudBlobContainerListBlobsNext() throws StorageException, IOException, URISyntaxException { this.container.create(); - + int numBlobs = 10; List blobNames = BlobTestHelper.uploadNewBlobs(this.container, BlobType.PAGE_BLOB, 10, 512, null); assertEquals(numBlobs, blobNames.size()); @@ -614,16 +613,16 @@ public void testCloudBlobContainerListBlobsNext() throws StorageException, IOExc iter.hasNext(); iter.next(); iter.next(); - + // next without hasNext iter = this.container.listBlobs().iterator(); iter.next(); iter.next(); } - + /** * Try to list the blobs in a container to ensure maxResults validation is working. - * + * * @throws URISyntaxException * @throws StorageException * @throws IOException diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlobDirectoryTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlobDirectoryTests.java index 2b58e6c5f637..c655f4cae358 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlobDirectoryTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlobDirectoryTests.java @@ -1,6 +1,15 @@ package com.microsoft.azure.storage.blob; -import static org.junit.Assert.*; +import com.microsoft.azure.storage.core.PathUtility; +import com.microsoft.azure.storage.ResultContinuation; +import com.microsoft.azure.storage.ResultSegment; +import com.microsoft.azure.storage.StorageException; +import com.microsoft.azure.storage.TestRunners.CloudTests; +import com.microsoft.azure.storage.TestRunners.DevFabricTests; +import com.microsoft.azure.storage.TestRunners.DevStoreTests; + +import org.junit.Test; +import org.junit.experimental.categories.Category; import java.io.IOException; import java.net.URI; @@ -9,16 +18,7 @@ import java.util.EnumSet; import java.util.Iterator; -import org.junit.Test; -import org.junit.experimental.categories.Category; - -import com.microsoft.azure.storage.ResultContinuation; -import com.microsoft.azure.storage.ResultSegment; -import com.microsoft.azure.storage.StorageException; -import com.microsoft.azure.storage.TestRunners.CloudTests; -import com.microsoft.azure.storage.TestRunners.DevFabricTests; -import com.microsoft.azure.storage.TestRunners.DevStoreTests; -import com.microsoft.azure.storage.core.PathUtility; +import static org.junit.Assert.*; @Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) public class CloudBlobDirectoryTests { diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlobServerEncryptionTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlobServerEncryptionTests.java index 22ff702d0cf9..774f94727a6f 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlobServerEncryptionTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlobServerEncryptionTests.java @@ -14,17 +14,10 @@ */ package com.microsoft.azure.storage.blob; -import static org.junit.Assert.*; import java.io.IOException; import java.net.URISyntaxException; -import org.junit.After; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; -import org.junit.experimental.categories.Category; - import com.microsoft.azure.storage.OperationContext; import com.microsoft.azure.storage.RequestCompletedEvent; import com.microsoft.azure.storage.StorageEvent; @@ -33,6 +26,14 @@ import com.microsoft.azure.storage.TestRunners.DevFabricTests; import com.microsoft.azure.storage.TestRunners.DevStoreTests; +import org.junit.After; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import static org.junit.Assert.*; + @Category({ CloudTests.class, DevFabricTests.class, DevStoreTests.class }) @Ignore /* These test only works on accounts with server-side encryption enabled. */ diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlockBlobTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlockBlobTests.java index c4c67ef7d47f..c222b046fa61 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlockBlobTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlockBlobTests.java @@ -14,7 +14,31 @@ */ package com.microsoft.azure.storage.blob; -import static org.junit.Assert.*; +import com.microsoft.azure.storage.AccessCondition; +import com.microsoft.azure.storage.Constants; +import com.microsoft.azure.storage.NameValidator; +import com.microsoft.azure.storage.OperationContext; +import com.microsoft.azure.storage.RetryNoRetry; +import com.microsoft.azure.storage.SendingRequestEvent; +import com.microsoft.azure.storage.StorageCredentialsAnonymous; +import com.microsoft.azure.storage.StorageCredentialsSharedAccessSignature; +import com.microsoft.azure.storage.StorageEvent; +import com.microsoft.azure.storage.StorageException; +import com.microsoft.azure.storage.TestRunners; +import com.microsoft.azure.storage.core.Utility; +import com.microsoft.azure.storage.file.CloudFile; +import com.microsoft.azure.storage.file.CloudFileShare; +import com.microsoft.azure.storage.file.FileProperties; +import com.microsoft.azure.storage.file.FileTestHelper; +import com.microsoft.azure.storage.file.SharedAccessFilePermissions; +import com.microsoft.azure.storage.file.SharedAccessFilePolicy; + +import junit.framework.Assert; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.experimental.categories.Category; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -63,6 +87,8 @@ import com.microsoft.azure.storage.file.SharedAccessFilePermissions; import com.microsoft.azure.storage.file.SharedAccessFilePolicy; +import static org.junit.Assert.*; + /** * Block Blob Tests */ @@ -72,19 +98,19 @@ public class CloudBlockBlobTests { protected CloudBlobContainer container; @Before - public void blockBlobTestMethodSetup() throws URISyntaxException, StorageException { + public void blobEncryptionTestMethodSetUp() throws URISyntaxException, StorageException { this.container = BlobTestHelper.getRandomContainerReference(); this.container.create(); } @After - public void blockBlobTestMethodTearDown() throws StorageException { + public void blobEncryptionTestMethodTearDown() throws StorageException { this.container.deleteIfExists(); } /** * Create a block blob. - * + * * @throws StorageException * @throws URISyntaxException * @throws IOException @@ -126,27 +152,27 @@ public void testBlockBlobCreate() throws StorageException, URISyntaxException, I /** * Delete a block blob. - * + * * @throws StorageException - * @throws URISyntaxException - * @throws IOException + * @throws URISyntaxException + * @throws IOException */ @Test @Category({ DevFabricTests.class, DevStoreTests.class }) public void testBlockBlobDelete() throws StorageException, URISyntaxException, IOException { final CloudBlockBlob blob = this.container.getBlockBlobReference(BlobTestHelper .generateRandomBlobNameWithPrefix("testBlob")); - + assertFalse(blob.exists()); - + // create blob.uploadText("text"); assertTrue(blob.exists()); - + // delete blob.delete(); assertFalse(blob.exists()); - + // delete again, should fail as it doesn't exist try { blob.delete(); @@ -155,7 +181,7 @@ public void testBlockBlobDelete() throws StorageException, URISyntaxException, I assertEquals(HttpURLConnection.HTTP_NOT_FOUND, ex.getHttpStatusCode()); assertEquals("The specified blob does not exist.", ex.getMessage()); assertEquals("BlobNotFound", ex.getErrorCode()); - } + } } /** @@ -170,7 +196,7 @@ public void testCloudBlobNameValidation() NameValidator.validateBlobName("white space"); NameValidator.validateBlobName("0th3r(h@racter$"); NameValidator.validateBlobName(new String(new char[253]).replace("\0", "a/a")); - + invalidBlobTestHelper("", "No empty strings.", "Invalid blob name. The name may not be null, empty, or whitespace only."); invalidBlobTestHelper(null, "No null strings.", "Invalid blob name. The name may not be null, empty, or whitespace only."); invalidBlobTestHelper(new String(new char[1025]).replace("\0", "n"), "Maximum 1024 characters.", "Invalid blob name length. The name must be between 1 and 1024 characters long."); @@ -235,7 +261,7 @@ public void testCopyBlockBlobTest() throws InvalidKeyException, URISyntaxExcepti InterruptedException { this.doCloudBlockBlobCopy(false, false); } - + @Test public void testCopyWithChineseChars() throws StorageException, IOException, URISyntaxException { String data = "sample data chinese chars 阿䶵"; @@ -243,7 +269,7 @@ public void testCopyWithChineseChars() throws StorageException, IOException, URI copySource.uploadText(data); assertEquals(this.container.getUri() + "/sourcechinescharsblob阿䶵.txt", copySource.getUri().toString()); - assertEquals(this.container.getUri() + "/sourcechinescharsblob%E9%98%BF%E4%B6%B5.txt", + assertEquals(this.container.getUri() + "/sourcechinescharsblob%E9%98%BF%E4%B6%B5.txt", copySource.getUri().toASCIIString()); CloudBlockBlob copyDestination = container.getBlockBlobReference("destchinesecharsblob阿䶵.txt"); @@ -257,17 +283,17 @@ public void testCopyWithChineseChars() throws StorageException, IOException, URI @Override public void eventOccurred(SendingRequestEvent eventArg) { HttpURLConnection con = (HttpURLConnection) eventArg.getConnectionObject(); - + // Test the copy destination request url assertEquals(CloudBlockBlobTests.this.container.getUri() + "/destchinesecharsblob%E9%98%BF%E4%B6%B5.txt", con.getURL().toString()); - + // Test the copy source request property assertEquals(CloudBlockBlobTests.this.container.getUri() + "/sourcechinescharsblob%E9%98%BF%E4%B6%B5.txt", con.getRequestProperty("x-ms-copy-source")); } }); - + copyDestination.startCopy(copySource.getUri(), null, null, null, ctx); copyDestination.startCopy(copySource, null, null, null, ctx); } @@ -551,11 +577,11 @@ public void testCopyFileWithMetadataOverride() /** * Start copying a file and then abort - * + * * @throws StorageException * @throws URISyntaxException * @throws IOException - * @throws InvalidKeyException + * @throws InvalidKeyException * @throws InterruptedException */ @Test @@ -570,7 +596,7 @@ public void testCopyFileAbort() // Source SAS must have read permissions SharedAccessFilePolicy policy = new SharedAccessFilePolicy(); policy.setPermissions(EnumSet.of(SharedAccessFilePermissions.READ)); - + Calendar cal = Calendar.getInstance(Utility.UTC_ZONE); cal.add(Calendar.MINUTE, 5); policy.setSharedAccessExpiryTime(cal.getTime()); @@ -754,7 +780,7 @@ public void testBlobDownloadRangeValidationTest() throws StorageException, URISy blockBlobRef.downloadBlockList(); assertEquals(length, blockBlobRef.getProperties().getLength()); } - + @Test @Category({ DevFabricTests.class, DevStoreTests.class }) public void testCommitBlockListContentMd5() throws URISyntaxException, StorageException, IOException { @@ -767,7 +793,7 @@ public void testCommitBlockListContentMd5() throws URISyntaxException, StorageEx for (BlockEntry block : blocks.values()) { blob.uploadBlock(block.getId(), new ByteArrayInputStream(buffer), length); } - + OperationContext ctx = new OperationContext(); ctx.getSendingRequestEventHandler().addListener(new StorageEvent() { @@ -777,12 +803,12 @@ public void eventOccurred(SendingRequestEvent eventArg) { assertNull(conn.getRequestProperty("Content-MD5")); } }); - + blob.commitBlockList(blocks.values(), null, null, ctx); - + BlobRequestOptions opt = new BlobRequestOptions(); opt.setUseTransactionalContentMD5(true); - + ctx = new OperationContext(); ctx.getSendingRequestEventHandler().addListener(new StorageEvent() { @@ -792,7 +818,7 @@ public void eventOccurred(SendingRequestEvent eventArg) { assertNotNull(conn.getRequestProperty("Content-MD5")); } }); - + blob.commitBlockList(blocks.values(), null, opt, ctx); } @@ -836,7 +862,7 @@ public void testDownloadBlockList() throws URISyntaxException, StorageException, assertFalse(extraBlocks.remove(blockItem.getId()) == null); } assertEquals(0, extraBlocks.size()); - + blockList = blob2.downloadBlockList(BlockListingFilter.ALL, null, null, null); assertEquals(5, blockList.size()); } @@ -899,13 +925,13 @@ public void testBlobUploadFromStreamTest() throws URISyntaxException, StorageExc blockBlobRef.download(dstStream); BlobTestHelper.assertStreamsAreEqual(srcStream, new ByteArrayInputStream(dstStream.toByteArray())); } - + @Test - public void testBlobUploadFromStreamAccessConditionTest() throws URISyntaxException, StorageException, IOException { + public void testBlobUploadFromStreamAccessConditionTest() throws URISyntaxException, StorageException, IOException { final String blockBlobName = BlobTestHelper.generateRandomBlobNameWithPrefix("testBlockBlob"); final CloudBlockBlob blockBlobRef = this.container.getBlockBlobReference(blockBlobName); - AccessCondition accessCondition = AccessCondition.generateIfNotModifiedSinceCondition(new Date()); - + AccessCondition accessCondition = AccessCondition.generateIfNotModifiedSinceCondition(new Date()); + int length = 2 * 1024; ByteArrayInputStream srcStream = BlobTestHelper.getRandomDataStream(length); blockBlobRef.upload(srcStream, -1, accessCondition, null, null); diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudPageBlobTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudPageBlobTests.java index bf31bc7d16d2..191643233865 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudPageBlobTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudPageBlobTests.java @@ -1,11 +1,11 @@ /** * Copyright Microsoft Corporation - * + * * Licensed 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. @@ -14,7 +14,25 @@ */ package com.microsoft.azure.storage.blob; -import static org.junit.Assert.*; +import com.microsoft.azure.storage.AccessCondition; +import com.microsoft.azure.storage.core.SR; +import com.microsoft.azure.storage.core.Utility; +import com.microsoft.azure.storage.OperationContext; +import com.microsoft.azure.storage.RetryNoRetry; +import com.microsoft.azure.storage.SendingRequestEvent; +import com.microsoft.azure.storage.StorageEvent; +import com.microsoft.azure.storage.StorageException; +import com.microsoft.azure.storage.TestRunners; +import com.microsoft.azure.storage.TestRunners.CloudTests; +import com.microsoft.azure.storage.TestRunners.DevFabricTests; +import com.microsoft.azure.storage.TestRunners.DevStoreTests; + +import junit.framework.Assert; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.experimental.categories.Category; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -32,22 +50,7 @@ import java.util.List; import java.util.Random; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.experimental.categories.Category; - -import com.microsoft.azure.storage.AccessCondition; -import com.microsoft.azure.storage.OperationContext; -import com.microsoft.azure.storage.RetryNoRetry; -import com.microsoft.azure.storage.SendingRequestEvent; -import com.microsoft.azure.storage.StorageEvent; -import com.microsoft.azure.storage.StorageException; -import com.microsoft.azure.storage.TestRunners.CloudTests; -import com.microsoft.azure.storage.TestRunners.DevFabricTests; -import com.microsoft.azure.storage.TestRunners.DevStoreTests; -import com.microsoft.azure.storage.core.SR; -import com.microsoft.azure.storage.core.Utility; +import static org.junit.Assert.*; @Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) public class CloudPageBlobTests { @@ -66,7 +69,7 @@ public void pageBlobTestMethodTearDown() throws StorageException { /** * Start copying a blob and then abort - * + * * @throws StorageException * @throws URISyntaxException * @throws IOException @@ -92,7 +95,7 @@ public void testCopyFromPageBlobAbortTest() throws StorageException, URISyntaxEx /** * Create a snapshot - * + * * @throws StorageException * @throws URISyntaxException * @throws IOException @@ -171,7 +174,7 @@ public void testPageBlobSnapshotValidationTest() throws StorageException, URISyn /** * Create a blob and try to download a range of its contents - * + * * @throws StorageException * @throws URISyntaxException * @throws IOException @@ -848,7 +851,7 @@ private CloudPageBlob setUpPageRanges() throws StorageException, URISyntaxExcept // Upload pages 2-4 inputStream = new ByteArrayInputStream(buffer, 512, 3 * 512); blobRef.uploadPages(inputStream, 2 * 512, 3 * 512); - + // Upload page 6 inputStream = new ByteArrayInputStream(buffer, 3 * 512, 512); blobRef.uploadPages(inputStream, 6 * 512, 512); @@ -861,7 +864,7 @@ private CloudPageBlob setUpPageRanges() throws StorageException, URISyntaxExcept // Page7-8: 2 * 512 bytes should be 0 return blobRef; } - + @Test public void testDownloadPages() throws StorageException, URISyntaxException, IOException { final CloudPageBlob blobRef = setUpPageRanges(); @@ -882,7 +885,7 @@ public void testDownloadPages() throws StorageException, URISyntaxException, IOE @Test public void testDownloadPageRangesWithOffset() throws StorageException, URISyntaxException, IOException { final CloudPageBlob blobRef = setUpPageRanges(); - + List actualPageRanges = blobRef.downloadPageRanges((long)1*512, null); List expectedPageRanges = new ArrayList(); expectedPageRanges.add(new PageRange(2 * 512, 5 * 512 - 1)); @@ -898,7 +901,7 @@ public void testDownloadPageRangesWithOffset() throws StorageException, URISynta @Test public void testDownloadPageRangesWithOffsetAndLength() throws StorageException, URISyntaxException, IOException { final CloudPageBlob blobRef = setUpPageRanges(); - + List actualPageRanges = blobRef.downloadPageRanges((long)1*512, (long)5*512); List expectedPageRanges = new ArrayList(); expectedPageRanges.add(new PageRange(2 * 512, 5 * 512 - 1)); @@ -940,7 +943,7 @@ public void testDownloadPageRangeDiff() throws StorageException, URISyntaxExcept public void testDownloadPageRangeDiffWithOffsetAndLength() throws StorageException, URISyntaxException, IOException { final CloudPageBlob blobRef = setUpPageRanges(); final CloudPageBlob snapshot = (CloudPageBlob) blobRef.createSnapshot(); - + // Add page 1 InputStream inputStream = new ByteArrayInputStream(BlobTestHelper.getRandomBuffer(512)); blobRef.uploadPages(inputStream, 0, 512); @@ -967,7 +970,7 @@ public void testUploadDownloadBlobProperties() throws URISyntaxException, Storag BlobRequestOptions options = new BlobRequestOptions(); options.setDisableContentMD5Validation(true); - // with explicit upload/download of properties + // with explicit upload/download of properties String pageBlobName1 = BlobTestHelper.generateRandomBlobNameWithPrefix("testBlockBlob"); CloudPageBlob pageBlobRef1 = this.container.getPageBlobReference(pageBlobName1); @@ -982,7 +985,7 @@ public void testUploadDownloadBlobProperties() throws URISyntaxException, Storag BlobTestHelper.assertAreEqual(props1, props2); - // by uploading/downloading the blob + // by uploading/downloading the blob pageBlobName1 = BlobTestHelper.generateRandomBlobNameWithPrefix("testBlockBlob"); pageBlobRef1 = this.container.getPageBlobReference(pageBlobName1); diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/LeaseTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/LeaseTests.java index d553097e50af..1e2b5a1504b0 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/LeaseTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/LeaseTests.java @@ -14,28 +14,30 @@ */ package com.microsoft.azure.storage.blob; -import static org.junit.Assert.*; - -import java.io.IOException; -import java.net.HttpURLConnection; -import java.net.URISyntaxException; -import java.util.UUID; - -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.experimental.categories.Category; - import com.microsoft.azure.storage.AccessCondition; import com.microsoft.azure.storage.OperationContext; import com.microsoft.azure.storage.StorageErrorCodeStrings; import com.microsoft.azure.storage.StorageException; +import com.microsoft.azure.storage.TestRunners; import com.microsoft.azure.storage.TestRunners.CloudTests; import com.microsoft.azure.storage.TestRunners.DevFabricTests; import com.microsoft.azure.storage.TestRunners.DevStoreTests; import com.microsoft.azure.storage.TestRunners.SlowTests; +import junit.framework.Assert; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.URISyntaxException; +import java.util.UUID; + +import static org.junit.Assert.*; + @Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) public class LeaseTests { @@ -51,7 +53,7 @@ public void leaseTestMethodSetup() throws StorageException, URISyntaxException { public void leaseTestMethodTearDown() throws StorageException { this.container.deleteIfExists(); } - + @Test public void testContainerLeaseInvalidParams() throws StorageException, URISyntaxException { try { diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/SasTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/SasTests.java index 5ee15bad276a..f2063326254c 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/SasTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/SasTests.java @@ -15,7 +15,28 @@ package com.microsoft.azure.storage.blob; -import static org.junit.Assert.*; +import com.microsoft.azure.storage.Constants; +import com.microsoft.azure.storage.core.PathUtility; +import com.microsoft.azure.storage.core.SR; +import com.microsoft.azure.storage.IPRange; +import com.microsoft.azure.storage.OperationContext; +import com.microsoft.azure.storage.ResponseReceivedEvent; +import com.microsoft.azure.storage.SecondaryTests; +import com.microsoft.azure.storage.SendingRequestEvent; +import com.microsoft.azure.storage.SharedAccessProtocols; +import com.microsoft.azure.storage.StorageCredentials; +import com.microsoft.azure.storage.StorageCredentialsAnonymous; +import com.microsoft.azure.storage.StorageCredentialsSharedAccessSignature; +import com.microsoft.azure.storage.StorageEvent; +import com.microsoft.azure.storage.StorageException; +import com.microsoft.azure.storage.TestRunners; + +import junit.framework.Assert; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.experimental.categories.Category; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -33,30 +54,13 @@ import java.util.NoSuchElementException; import java.util.TimeZone; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.experimental.categories.Category; - -import com.microsoft.azure.storage.Constants; -import com.microsoft.azure.storage.IPRange; -import com.microsoft.azure.storage.OperationContext; -import com.microsoft.azure.storage.ResponseReceivedEvent; -import com.microsoft.azure.storage.SecondaryTests; -import com.microsoft.azure.storage.SendingRequestEvent; -import com.microsoft.azure.storage.SharedAccessProtocols; -import com.microsoft.azure.storage.StorageCredentials; -import com.microsoft.azure.storage.StorageCredentialsAnonymous; -import com.microsoft.azure.storage.StorageCredentialsSharedAccessSignature; -import com.microsoft.azure.storage.StorageEvent; -import com.microsoft.azure.storage.StorageException; import com.microsoft.azure.storage.TestHelper; import com.microsoft.azure.storage.TestRunners.CloudTests; import com.microsoft.azure.storage.TestRunners.DevFabricTests; import com.microsoft.azure.storage.TestRunners.DevStoreTests; import com.microsoft.azure.storage.TestRunners.SlowTests; -import com.microsoft.azure.storage.core.PathUtility; -import com.microsoft.azure.storage.core.SR; + +import static org.junit.Assert.*; @Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) public class SasTests { @@ -216,7 +220,7 @@ public void testProtocolRestrictions() httpsBlob = httpsContainer.getBlockBlobReference(this.blob.getName()); httpsBlob.download(new ByteArrayOutputStream()); } - + @Test @Category({ SecondaryTests.class, SlowTests.class }) public void testContainerSaS() throws IllegalArgumentException, StorageException, URISyntaxException, diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/CloudFileClientTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/CloudFileClientTests.java index c0a31f01b672..f90b148a85ac 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/CloudFileClientTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/CloudFileClientTests.java @@ -14,22 +14,23 @@ */ package com.microsoft.azure.storage.file; -import static org.junit.Assert.*; - -import java.net.URISyntaxException; -import java.util.ArrayList; -import java.util.UUID; - -import org.junit.Test; -import org.junit.experimental.categories.Category; - +import com.microsoft.azure.storage.core.SR; import com.microsoft.azure.storage.ResultContinuation; import com.microsoft.azure.storage.ResultSegment; import com.microsoft.azure.storage.StorageException; +import com.microsoft.azure.storage.TestRunners; import com.microsoft.azure.storage.TestRunners.CloudTests; import com.microsoft.azure.storage.TestRunners.DevFabricTests; import com.microsoft.azure.storage.TestRunners.DevStoreTests; -import com.microsoft.azure.storage.core.SR; + +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.UUID; + +import static org.junit.Assert.*; /** * File Client Tests diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/CloudFileDirectoryTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/CloudFileDirectoryTests.java index 2cb06fc6b9d9..f32dd907d070 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/CloudFileDirectoryTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/CloudFileDirectoryTests.java @@ -14,7 +14,19 @@ */ package com.microsoft.azure.storage.file; -import static org.junit.Assert.*; +import com.microsoft.azure.storage.NameValidator; +import com.microsoft.azure.storage.OperationContext; +import com.microsoft.azure.storage.ResultSegment; +import com.microsoft.azure.storage.SendingRequestEvent; +import com.microsoft.azure.storage.StorageErrorCodeStrings; +import com.microsoft.azure.storage.StorageEvent; +import com.microsoft.azure.storage.StorageException; +import com.microsoft.azure.storage.TestRunners; +import com.microsoft.azure.storage.TestRunners.CloudTests; +import com.microsoft.azure.storage.TestRunners.DevFabricTests; +import com.microsoft.azure.storage.TestRunners.DevStoreTests; +import com.microsoft.azure.storage.core.PathUtility; +import com.microsoft.azure.storage.core.SR; import java.io.IOException; import java.net.HttpURLConnection; @@ -28,18 +40,7 @@ import org.junit.Test; import org.junit.experimental.categories.Category; -import com.microsoft.azure.storage.NameValidator; -import com.microsoft.azure.storage.OperationContext; -import com.microsoft.azure.storage.ResultSegment; -import com.microsoft.azure.storage.SendingRequestEvent; -import com.microsoft.azure.storage.StorageErrorCodeStrings; -import com.microsoft.azure.storage.StorageEvent; -import com.microsoft.azure.storage.StorageException; -import com.microsoft.azure.storage.TestRunners.CloudTests; -import com.microsoft.azure.storage.TestRunners.DevFabricTests; -import com.microsoft.azure.storage.TestRunners.DevStoreTests; -import com.microsoft.azure.storage.core.PathUtility; -import com.microsoft.azure.storage.core.SR; +import static org.junit.Assert.*; /** * File Directory Tests @@ -50,13 +51,13 @@ public class CloudFileDirectoryTests { private CloudFileShare share; @Before - public void fileTestMethodSetup() throws URISyntaxException, StorageException { + public void cloudFileDirectorySetUp() throws URISyntaxException, StorageException { this.share = FileTestHelper.getRandomShareReference(); this.share.create(); } @After - public void fileTestMethodTearDown() throws StorageException { + public void cloudFileDirectoryTearDown() throws StorageException { this.share.deleteIfExists(); } diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/CloudFileShareTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/CloudFileShareTests.java index 4c3360b66deb..d7e62ed1a0b7 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/CloudFileShareTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/CloudFileShareTests.java @@ -14,7 +14,23 @@ */ package com.microsoft.azure.storage.file; -import static org.junit.Assert.*; +import com.microsoft.azure.storage.core.SR; +import com.microsoft.azure.storage.NameValidator; +import com.microsoft.azure.storage.OperationContext; +import com.microsoft.azure.storage.SendingRequestEvent; +import com.microsoft.azure.storage.StorageErrorCodeStrings; +import com.microsoft.azure.storage.StorageEvent; +import com.microsoft.azure.storage.StorageException; +import com.microsoft.azure.storage.TestRunners.CloudTests; +import com.microsoft.azure.storage.TestRunners.DevFabricTests; +import com.microsoft.azure.storage.TestRunners.DevStoreTests; +import com.microsoft.azure.storage.TestRunners.SlowTests; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.experimental.categories.Category; import java.io.IOException; import java.net.HttpURLConnection; @@ -26,23 +42,7 @@ import java.util.HashMap; import java.util.TimeZone; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.experimental.categories.Category; - -import com.microsoft.azure.storage.NameValidator; -import com.microsoft.azure.storage.OperationContext; -import com.microsoft.azure.storage.SendingRequestEvent; -import com.microsoft.azure.storage.StorageErrorCodeStrings; -import com.microsoft.azure.storage.StorageEvent; -import com.microsoft.azure.storage.StorageException; -import com.microsoft.azure.storage.TestRunners.CloudTests; -import com.microsoft.azure.storage.TestRunners.DevFabricTests; -import com.microsoft.azure.storage.TestRunners.DevStoreTests; -import com.microsoft.azure.storage.TestRunners.SlowTests; -import com.microsoft.azure.storage.core.SR; +import static org.junit.Assert.*; /** * File Share Tests @@ -394,7 +394,7 @@ public void testGetShareStats() throws StorageException, IOException, URISyntaxE * @throws StorageException * @throws URISyntaxException */ - @ Test + @Test public void testCloudFileShareQuota() throws StorageException, URISyntaxException { // Share quota defaults to 5120 this.share.createIfNotExists(); @@ -440,7 +440,7 @@ public void testCloudFileShareQuota() throws StorageException, URISyntaxExceptio * @throws StorageException * @throws URISyntaxException */ - @ Test + @Test public void testCloudFileShareQuotaListing() throws StorageException, URISyntaxException { int shareQuota = 16; this.share.getProperties().setShareQuota(shareQuota); diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/CloudFileTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/CloudFileTests.java index 7343101c27a0..4b452827a121 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/CloudFileTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/CloudFileTests.java @@ -14,7 +14,35 @@ */ package com.microsoft.azure.storage.file; -import static org.junit.Assert.*; +import com.microsoft.azure.storage.Constants; +import com.microsoft.azure.storage.core.Base64; +import com.microsoft.azure.storage.core.Utility; +import com.microsoft.azure.storage.NameValidator; +import com.microsoft.azure.storage.OperationContext; +import com.microsoft.azure.storage.RetryNoRetry; +import com.microsoft.azure.storage.SendingRequestEvent; +import com.microsoft.azure.storage.StorageCredentialsSharedAccessSignature; +import com.microsoft.azure.storage.StorageErrorCodeStrings; +import com.microsoft.azure.storage.StorageEvent; +import com.microsoft.azure.storage.StorageException; +import com.microsoft.azure.storage.TestRunners; +import com.microsoft.azure.storage.blob.BlobProperties; +import com.microsoft.azure.storage.blob.BlobTestHelper; +import com.microsoft.azure.storage.blob.CloudBlob; +import com.microsoft.azure.storage.blob.CloudBlobContainer; +import com.microsoft.azure.storage.blob.CloudBlockBlob; +import com.microsoft.azure.storage.blob.CloudPageBlob; +import com.microsoft.azure.storage.blob.SharedAccessBlobPermissions; +import com.microsoft.azure.storage.blob.SharedAccessBlobPolicy; +import com.microsoft.azure.storage.TestRunners.CloudTests; +import com.microsoft.azure.storage.TestRunners.DevFabricTests; +import com.microsoft.azure.storage.TestRunners.DevStoreTests; +import com.microsoft.azure.storage.TestRunners.SlowTests; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.experimental.categories.Category; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -37,34 +65,7 @@ import java.util.Random; import java.util.TimeZone; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.experimental.categories.Category; - -import com.microsoft.azure.storage.Constants; -import com.microsoft.azure.storage.NameValidator; -import com.microsoft.azure.storage.OperationContext; -import com.microsoft.azure.storage.RetryNoRetry; -import com.microsoft.azure.storage.SendingRequestEvent; -import com.microsoft.azure.storage.StorageCredentialsSharedAccessSignature; -import com.microsoft.azure.storage.StorageErrorCodeStrings; -import com.microsoft.azure.storage.StorageEvent; -import com.microsoft.azure.storage.StorageException; -import com.microsoft.azure.storage.TestRunners.CloudTests; -import com.microsoft.azure.storage.TestRunners.DevFabricTests; -import com.microsoft.azure.storage.TestRunners.DevStoreTests; -import com.microsoft.azure.storage.TestRunners.SlowTests; -import com.microsoft.azure.storage.blob.BlobProperties; -import com.microsoft.azure.storage.blob.BlobTestHelper; -import com.microsoft.azure.storage.blob.CloudBlob; -import com.microsoft.azure.storage.blob.CloudBlobContainer; -import com.microsoft.azure.storage.blob.CloudBlockBlob; -import com.microsoft.azure.storage.blob.CloudPageBlob; -import com.microsoft.azure.storage.blob.SharedAccessBlobPermissions; -import com.microsoft.azure.storage.blob.SharedAccessBlobPolicy; -import com.microsoft.azure.storage.core.Base64; -import com.microsoft.azure.storage.core.Utility; +import static org.junit.Assert.*; /** * File Tests @@ -74,7 +75,7 @@ public class CloudFileTests { protected CloudFileShare share; @Before - public void fileTestMethodSetup() throws URISyntaxException, StorageException { + public void fileTestMethodSetUp() throws URISyntaxException, StorageException { this.share = FileTestHelper.getRandomShareReference(); this.share.create(); } @@ -133,7 +134,7 @@ public void testCloudFileCreateAndDelete() throws URISyntaxException, StorageExc assertTrue(file.exists()); file.delete(); } - + @Test public void testCloudFileCreate() throws StorageException, URISyntaxException { CloudFile file = this.share.getRootDirectoryReference().getFileReference("file1"); @@ -387,7 +388,7 @@ public void testCloudFileCreateWithMetadata() throws URISyntaxException, Storage file.downloadAttributes(); assertEquals(0, file.getMetadata().size()); } - + @Test @Category(SlowTests.class) public void testCopyBlockBlobSas() throws Exception { @@ -445,7 +446,6 @@ public void testCopyFileSasToSas() throws InvalidKeyException, URISyntaxExceptio // There is no testCopyFileToSas() because there is no way for the SAS destination to access a shared key source. // This means it would require the source to have public access, which files do not support. - @Test @Category(SlowTests.class) public void testCopyFileSas() throws InvalidKeyException, URISyntaxException, StorageException, @@ -461,7 +461,7 @@ public void testCopyFile() throws InvalidKeyException, URISyntaxException, Stora // The request is then signed with the key so the service knows we are authorized to access both. this.doCloudFileCopy(false, false); } - + @Test public void testCopyWithChineseChars() throws StorageException, IOException, URISyntaxException { diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/FileSasTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/FileSasTests.java index 98356fa070e5..c620b6ec6cc7 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/FileSasTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/FileSasTests.java @@ -15,29 +15,6 @@ package com.microsoft.azure.storage.file; -import static org.junit.Assert.*; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.net.HttpURLConnection; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.UnknownHostException; -import java.security.InvalidKeyException; -import java.util.Calendar; -import java.util.Date; -import java.util.EnumSet; -import java.util.GregorianCalendar; -import java.util.HashMap; -import java.util.Map; -import java.util.NoSuchElementException; -import java.util.TimeZone; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.experimental.categories.Category; - import com.microsoft.azure.storage.Constants; import com.microsoft.azure.storage.IPRange; import com.microsoft.azure.storage.OperationContext; @@ -51,6 +28,7 @@ import com.microsoft.azure.storage.StorageException; import com.microsoft.azure.storage.StorageUri; import com.microsoft.azure.storage.TestHelper; +import com.microsoft.azure.storage.TestRunners; import com.microsoft.azure.storage.TestRunners.CloudTests; import com.microsoft.azure.storage.TestRunners.DevFabricTests; import com.microsoft.azure.storage.TestRunners.DevStoreTests; @@ -58,8 +36,34 @@ import com.microsoft.azure.storage.core.PathUtility; import com.microsoft.azure.storage.core.SR; +import junit.framework.Assert; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.UnknownHostException; +import java.security.InvalidKeyException; +import java.util.Calendar; +import java.util.Date; +import java.util.EnumSet; +import java.util.GregorianCalendar; +import java.util.HashMap; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.TimeZone; + +import static org.junit.Assert.*; + @Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) public class FileSasTests { + protected static CloudFileClient fileClient = null; protected CloudFileShare share; protected CloudFile file; @@ -79,7 +83,7 @@ public void fileSASTestMethodSetup() throws URISyntaxException, StorageException public void fileSASTestMethodTearDown() throws StorageException { this.share.deleteIfExists(); } - + @Test public void testApiVersion() throws InvalidKeyException, StorageException, URISyntaxException { SharedAccessFilePolicy policy = createSharedAccessPolicy( @@ -104,7 +108,7 @@ public void eventOccurred(ResponseReceivedEvent eventArg) { CloudFile sasFile = new CloudFile(new URI(this.file.getUri().toString() + "?" + sas)); sasFile.uploadMetadata(null, null, ctx); } - + @Test public void testDirectorySas() throws InvalidKeyException, IllegalArgumentException, StorageException, URISyntaxException, InterruptedException { @@ -193,7 +197,7 @@ public void testIpAcl() CloudFile allFile = allShare.getRootDirectoryReference().getFileReference(this.file.getName()); allFile.download(new ByteArrayOutputStream()); } - + @Test @Category({ SecondaryTests.class }) public void testProtocolRestrictions() diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/FileTestHelper.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/FileTestHelper.java index adea6fdc8794..6d4e90c35b03 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/FileTestHelper.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/FileTestHelper.java @@ -14,8 +14,14 @@ */ package com.microsoft.azure.storage.file; + import static org.junit.Assert.*; +import com.microsoft.azure.storage.OperationContext; +import com.microsoft.azure.storage.StorageException; +import com.microsoft.azure.storage.StorageUri; +import com.microsoft.azure.storage.TestHelper; + import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; @@ -24,11 +30,6 @@ import java.util.Random; import java.util.UUID; -import com.microsoft.azure.storage.OperationContext; -import com.microsoft.azure.storage.StorageException; -import com.microsoft.azure.storage.StorageUri; -import com.microsoft.azure.storage.TestHelper; - /** * File Test Base */ diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/queue/CloudQueueClientGB18030Test.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/queue/CloudQueueClientGB18030Test.java index 3b4659b0d512..e7591d0b6bfe 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/queue/CloudQueueClientGB18030Test.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/queue/CloudQueueClientGB18030Test.java @@ -14,20 +14,21 @@ */ package com.microsoft.azure.storage.queue; -import static org.junit.Assert.*; - -import java.net.URISyntaxException; -import java.util.EnumSet; +import com.microsoft.azure.storage.StorageException; +import com.microsoft.azure.storage.TestRunners; +import com.microsoft.azure.storage.TestRunners.CloudTests; +import com.microsoft.azure.storage.TestRunners.DevFabricTests; +import com.microsoft.azure.storage.TestRunners.DevStoreTests; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.experimental.categories.Category; -import com.microsoft.azure.storage.StorageException; -import com.microsoft.azure.storage.TestRunners.CloudTests; -import com.microsoft.azure.storage.TestRunners.DevFabricTests; -import com.microsoft.azure.storage.TestRunners.DevStoreTests; +import java.net.URISyntaxException; +import java.util.EnumSet; + +import static org.junit.Assert.*; @Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) public class CloudQueueClientGB18030Test { diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/queue/CloudQueueClientTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/queue/CloudQueueClientTests.java index 2cfa2411f83b..d6809b6b01b6 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/queue/CloudQueueClientTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/queue/CloudQueueClientTests.java @@ -1,11 +1,11 @@ /** * Copyright Microsoft Corporation - * + * * Licensed 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. @@ -14,7 +14,15 @@ */ package com.microsoft.azure.storage.queue; -import static org.junit.Assert.*; +import com.microsoft.azure.storage.LocationMode; +import com.microsoft.azure.storage.ResultSegment; +import com.microsoft.azure.storage.StorageException; +import com.microsoft.azure.storage.TestHelper; +import com.microsoft.azure.storage.TestRunners; +import com.microsoft.azure.storage.core.SR; + +import org.junit.Test; +import org.junit.experimental.categories.Category; import java.net.URI; import java.net.URISyntaxException; @@ -22,22 +30,16 @@ import java.util.HashMap; import java.util.UUID; -import org.junit.Test; -import org.junit.experimental.categories.Category; - -import com.microsoft.azure.storage.LocationMode; -import com.microsoft.azure.storage.ResultSegment; -import com.microsoft.azure.storage.StorageException; -import com.microsoft.azure.storage.TestHelper; import com.microsoft.azure.storage.TestRunners.CloudTests; import com.microsoft.azure.storage.TestRunners.DevFabricTests; import com.microsoft.azure.storage.TestRunners.DevStoreTests; -import com.microsoft.azure.storage.core.SR; + +import static org.junit.Assert.*; public final class CloudQueueClientTests { - @Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) @Test + @Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) public void testListQueuesSmallNumber() throws URISyntaxException, StorageException { CloudQueueClient qClient = QueueTestHelper.createCloudQueueClient(); int initialCount = 0; @@ -82,8 +84,8 @@ public void testListQueuesSmallNumber() throws URISyntaxException, StorageExcept assertEquals(count, 25); } - @Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) @Test + @Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) public void testListQueuesAndListQueuesSegmentedLargeNumber() throws URISyntaxException, StorageException { CloudQueueClient qClient = QueueTestHelper.createCloudQueueClient(); int count = 0; @@ -111,8 +113,8 @@ public void testListQueuesAndListQueuesSegmentedLargeNumber() throws URISyntaxEx assertTrue(segment.getContinuationToken() != null); } - @Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) @Test + @Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) public void testListQueuesSegmented() throws URISyntaxException, StorageException { CloudQueueClient qClient = QueueTestHelper.createCloudQueueClient(); String prefix = "segment" + UUID.randomUUID().toString().substring(0, 8).toLowerCase(); @@ -148,8 +150,8 @@ public void testListQueuesSegmented() throws URISyntaxException, StorageExceptio assertTrue(segment3.getLength() == 35); } - @Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) @Test + @Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) public void testListQueuesSegmentedMaxResultsValidation() throws URISyntaxException, StorageException { CloudQueueClient qClient = QueueTestHelper.createCloudQueueClient(); @@ -166,9 +168,9 @@ public void testListQueuesSegmentedMaxResultsValidation() throws URISyntaxExcept } assertNotNull(qClient.listQueuesSegmented("thereshouldntbeanyqueueswiththisprefix")); } - - @Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) + @Test + @Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) public void testListQueuesEqual() throws StorageException { CloudQueueClient qClient = QueueTestHelper.createCloudQueueClient(); int count1 = 0; @@ -206,8 +208,8 @@ static String AppendQueueName(URI baseURI, String queueName) { } } - @Category({ CloudTests.class }) @Test + @Category({ CloudTests.class }) public void testGetServiceStats() throws StorageException { CloudQueueClient qClient = QueueTestHelper.createCloudQueueClient(); qClient.getDefaultRequestOptions().setLocationMode(LocationMode.SECONDARY_ONLY); diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/queue/CloudQueueTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/queue/CloudQueueTests.java index 60c8195bfb10..6c694efd3ec8 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/queue/CloudQueueTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/queue/CloudQueueTests.java @@ -14,7 +14,23 @@ */ package com.microsoft.azure.storage.queue; -import static org.junit.Assert.*; +import com.microsoft.azure.storage.LocationMode; +import com.microsoft.azure.storage.NameValidator; +import com.microsoft.azure.storage.OperationContext; +import com.microsoft.azure.storage.RetryNoRetry; +import com.microsoft.azure.storage.SendingRequestEvent; +import com.microsoft.azure.storage.StorageCredentialsSharedAccessSignature; +import com.microsoft.azure.storage.StorageErrorCodeStrings; +import com.microsoft.azure.storage.StorageEvent; +import com.microsoft.azure.storage.StorageException; +import com.microsoft.azure.storage.TestHelper; +import com.microsoft.azure.storage.TestRunners; +import com.microsoft.azure.storage.core.PathUtility; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.experimental.categories.Category; import java.net.HttpURLConnection; import java.net.URI; @@ -51,6 +67,8 @@ import com.microsoft.azure.storage.TestRunners.SlowTests; import com.microsoft.azure.storage.core.PathUtility; +import static org.junit.Assert.*; + /** * Queue Tests */ @@ -103,7 +121,7 @@ private void invalidQueueTestHelper(String queueName, String failMessage, String assertEquals(exceptionMessage, e.getMessage()); } } - + /** * Get permissions from string */ @@ -136,8 +154,8 @@ public void testQueuePermissionsFromString() { assertEquals(EnumSet.of(SharedAccessQueuePermissions.UPDATE), policy.getPermissions()); } - @Category({ SlowTests.class, DevFabricTests.class, DevStoreTests.class }) @Test + @Category({ SlowTests.class, DevFabricTests.class, DevStoreTests.class }) public void testQueueGetSetPermissionTest() throws StorageException, InterruptedException { QueuePermissions expectedPermissions; QueuePermissions testPermissions; @@ -171,8 +189,8 @@ public void testQueueGetSetPermissionTest() throws StorageException, Interrupted assertQueuePermissionsEqual(expectedPermissions, testPermissions); } - @Category({ SlowTests.class, DevFabricTests.class, DevStoreTests.class }) @Test + @Category({ SlowTests.class, DevFabricTests.class, DevStoreTests.class }) public void testQueueSAS() throws StorageException, URISyntaxException, InvalidKeyException, InterruptedException { this.queue.addMessage(new CloudQueueMessage("sas queue test")); QueuePermissions expectedPermissions; @@ -293,7 +311,7 @@ public void testGetMetadata() throws StorageException { @Category({ DevFabricTests.class, DevStoreTests.class }) public void testUploadMetadata() throws URISyntaxException, StorageException { CloudQueue queueForGet = this.queue.getServiceClient().getQueueReference(this.queue.getName()); - + HashMap metadata1 = new HashMap(); metadata1.put("ExistingMetadata1", "ExistingMetadataValue1"); this.queue.setMetadata(metadata1); @@ -828,8 +846,8 @@ public void testAddMessageLargeMessageInput() throws StorageException { this.queue.delete(); } - @Category({ SlowTests.class, DevFabricTests.class, DevStoreTests.class }) @Test + @Category({ SlowTests.class, DevFabricTests.class, DevStoreTests.class }) public void testAddMessageWithVisibilityTimeout() throws StorageException, InterruptedException { this.queue.addMessage(new CloudQueueMessage("message"), 20, 0, null, null); CloudQueueMessage m1 = this.queue.retrieveMessage(); @@ -959,8 +977,8 @@ public void testDeleteMessageNullMessage() throws StorageException { } } - @Category({ SlowTests.class, DevFabricTests.class, DevStoreTests.class }) @Test + @Category({ SlowTests.class, DevFabricTests.class, DevStoreTests.class }) public void testRetrieveMessage() throws StorageException, InterruptedException { this.queue.addMessage(new CloudQueueMessage("message"), 20, 0, null, null); OperationContext opContext = new OperationContext(); @@ -1061,7 +1079,6 @@ public void testDequeueCountIncreases() throws StorageException, InterruptedExce @Test @Category({ DevFabricTests.class, DevStoreTests.class }) public void testRetrieveMessageSpecialVisibilityTimeout() throws StorageException { - try { this.queue.retrieveMessage(-1, null, null); fail(); @@ -1276,7 +1293,6 @@ public void testUpdateMessageFullPass() throws StorageException, InterruptedExce @Test @Category({ DevFabricTests.class, DevStoreTests.class }) public void testUpdateMessageWithContentChange() throws StorageException { - CloudQueueMessage message1 = new CloudQueueMessage("messagetest1"); this.queue.addMessage(message1); @@ -1404,7 +1420,6 @@ public void testQueueUpdateMetaData() throws StorageException { @Test @Category({ DevFabricTests.class, DevStoreTests.class }) public void testSASClientParse() throws StorageException, InvalidKeyException, URISyntaxException { - // Add a policy, check setting and getting. SharedAccessQueuePolicy policy1 = new SharedAccessQueuePolicy(); Calendar now = GregorianCalendar.getInstance(); diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/queue/QueueTestHelper.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/queue/QueueTestHelper.java index a5ac14fc3c03..80db16052211 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/queue/QueueTestHelper.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/queue/QueueTestHelper.java @@ -14,13 +14,13 @@ */ package com.microsoft.azure.storage.queue; +import com.microsoft.azure.storage.StorageException; +import com.microsoft.azure.storage.TestHelper; + import java.net.URI; import java.net.URISyntaxException; import java.util.UUID; -import com.microsoft.azure.storage.StorageException; -import com.microsoft.azure.storage.TestHelper; - /** * Queue Test Base */ diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/table/TableBatchOperationTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/table/TableBatchOperationTests.java index 95a4a5602e67..f7e82bb013fe 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/table/TableBatchOperationTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/table/TableBatchOperationTests.java @@ -1,11 +1,11 @@ /** * Copyright Microsoft Corporation - * + * * Licensed 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. @@ -14,7 +14,19 @@ */ package com.microsoft.azure.storage.table; -import static org.junit.Assert.*; +import com.microsoft.azure.storage.LocationMode; +import com.microsoft.azure.storage.RetryNoRetry; +import com.microsoft.azure.storage.SecondaryTests; +import com.microsoft.azure.storage.StorageErrorCodeStrings; +import com.microsoft.azure.storage.StorageException; +import com.microsoft.azure.storage.core.SR; +import com.microsoft.azure.storage.table.TableTestHelper.Class1; +import com.microsoft.azure.storage.table.TableTestHelper.Class2; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.experimental.categories.Category; import java.net.HttpURLConnection; import java.net.URISyntaxException; @@ -26,22 +38,11 @@ import java.util.Random; import java.util.UUID; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.experimental.categories.Category; - -import com.microsoft.azure.storage.LocationMode; -import com.microsoft.azure.storage.RetryNoRetry; -import com.microsoft.azure.storage.SecondaryTests; -import com.microsoft.azure.storage.StorageErrorCodeStrings; -import com.microsoft.azure.storage.StorageException; import com.microsoft.azure.storage.TestRunners.CloudTests; import com.microsoft.azure.storage.TestRunners.DevFabricTests; import com.microsoft.azure.storage.TestRunners.DevStoreTests; -import com.microsoft.azure.storage.core.SR; -import com.microsoft.azure.storage.table.TableTestHelper.Class1; -import com.microsoft.azure.storage.table.TableTestHelper.Class2; + +import static org.junit.Assert.*; @Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) public class TableBatchOperationTests { @@ -786,7 +787,7 @@ public void testBatchDelete() throws StorageException { private void testBatchDelete(TableRequestOptions options) throws StorageException { Class1 ref = TableTestHelper.generateRandomEntity("jxscl_odata"); - // insert entity + // insert entity this.table.execute(TableOperation.insert(ref), options, null); TableBatchOperation batch = new TableBatchOperation(); diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/table/TableClientTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/table/TableClientTests.java index 27729c251a9b..78e9f8181277 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/table/TableClientTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/table/TableClientTests.java @@ -1,11 +1,11 @@ /** * Copyright Microsoft Corporation - * + * * Licensed 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. @@ -14,8 +14,6 @@ */ package com.microsoft.azure.storage.table; -import static org.junit.Assert.*; - import java.net.HttpURLConnection; import java.net.URISyntaxException; import java.security.InvalidKeyException; @@ -26,6 +24,7 @@ import java.util.Date; import java.util.EnumSet; import java.util.GregorianCalendar; +import java.util.Locale; import java.util.UUID; import org.junit.Test; @@ -52,19 +51,21 @@ import com.microsoft.azure.storage.table.TableTestHelper.Class1; import com.microsoft.azure.storage.table.TableTestHelper.Class2; +import static org.junit.Assert.*; + /** * Table Client Tests */ public class TableClientTests { - @Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) @Test + @Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) public void testListTablesSegmented() throws URISyntaxException, StorageException { TableRequestOptions options = new TableRequestOptions(); TablePayloadFormat[] formats = {TablePayloadFormat.JsonFullMetadata, TablePayloadFormat.Json, - TablePayloadFormat.JsonNoMetadata}; + TablePayloadFormat.JsonNoMetadata}; for (TablePayloadFormat format : formats) { options.setTablePayloadFormat(format); @@ -116,9 +117,9 @@ private void testListTablesSegmented(TableRequestOptions options) throws URISynt } } } - - @Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) + @Test + @Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) public void testListTablesSegmentedMaxResultsValidation() throws URISyntaxException, StorageException { final CloudTableClient tClient = TableTestHelper.createCloudTableClient(); @@ -134,11 +135,12 @@ public void testListTablesSegmentedMaxResultsValidation() .equals(e.getMessage())); } } + assertNotNull(tClient.listTablesSegmented("thereshouldntbeanytableswiththisprefix")); } - @Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) @Test + @Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) public void testListTablesSegmentedNoPrefix() throws URISyntaxException, StorageException { TableRequestOptions options = new TableRequestOptions(); options.setTablePayloadFormat(TablePayloadFormat.Json); @@ -194,8 +196,8 @@ public void testListTablesSegmentedNoPrefix() throws URISyntaxException, Storage } } - @Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) @Test + @Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) public void testListTablesWithIterator() throws URISyntaxException, StorageException { TableRequestOptions options = new TableRequestOptions(); options.setTablePayloadFormat(TablePayloadFormat.Json); @@ -256,8 +258,8 @@ public void testListTablesWithIterator() throws URISyntaxException, StorageExcep } } - @Category({ SlowTests.class, DevFabricTests.class, DevStoreTests.class, CloudTests.class }) @Test + @Category({ SlowTests.class, DevFabricTests.class, DevStoreTests.class, CloudTests.class }) public void testTableSASFromIdentifier() throws StorageException, URISyntaxException, InvalidKeyException, InterruptedException { CloudTable table = TableTestHelper.getRandomTableReference(); @@ -380,8 +382,8 @@ public void testTableSASFromIdentifier() throws StorageException, URISyntaxExcep } } - @Category({ SlowTests.class, DevFabricTests.class, DevStoreTests.class, CloudTests.class }) @Test + @Category({ SlowTests.class, DevFabricTests.class, DevStoreTests.class, CloudTests.class }) public void testTableSASFromPermission() throws StorageException, URISyntaxException, InvalidKeyException { CloudTable table = TableTestHelper.getRandomTableReference(); try { @@ -527,8 +529,8 @@ public void testTableSASFromPermission() throws StorageException, URISyntaxExcep } } - @Category({ SlowTests.class, DevFabricTests.class, DevStoreTests.class, CloudTests.class }) @Test + @Category({ SlowTests.class, DevFabricTests.class, DevStoreTests.class, CloudTests.class }) public void testTableSASPkRk() throws StorageException, URISyntaxException, InvalidKeyException { CloudTable table = TableTestHelper.getRandomTableReference(); try { @@ -584,8 +586,8 @@ public void testTableSASPkRk() throws StorageException, URISyntaxException, Inva } } - @Category({ SlowTests.class, DevFabricTests.class, DevStoreTests.class, CloudTests.class }) @Test + @Category({ SlowTests.class, DevFabricTests.class, DevStoreTests.class, CloudTests.class }) public void testBackoffTimeOverflow() { RetryExponentialRetry exponentialRetry = new RetryExponentialRetry(4000, 100000); testBackoffTimeOverflow(exponentialRetry, 100000); @@ -616,8 +618,8 @@ private void testBackoffTimeOverflow(RetryPolicy retryPolicy, int maxAttempts) { assertNull(retryPolicy.evaluate(retryContext, context)); } - @Category({ CloudTests.class }) @Test + @Category({ CloudTests.class }) public void testGetServiceStats() throws StorageException { CloudTableClient tClient = TableTestHelper.createCloudTableClient(); tClient.getDefaultRequestOptions().setLocationMode(LocationMode.SECONDARY_ONLY); diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/table/TableDateTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/table/TableDateTests.java index 08c68542b259..1113880fbcae 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/table/TableDateTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/table/TableDateTests.java @@ -1,11 +1,11 @@ /** * Copyright Microsoft Corporation - * + * * Licensed 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. @@ -14,8 +14,7 @@ */ package com.microsoft.azure.storage.table; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; import java.net.URISyntaxException; import java.util.Date; @@ -48,7 +47,7 @@ public void tableTestMethodSetUp() throws URISyntaxException, StorageException { public void tableTestMethodTearDown() throws StorageException { this.table.deleteIfExists(); } - + @Test public void testTableQueryRoundTripDate() throws URISyntaxException, StorageException { // 2014-12-07T09:15:12.123Z from Java @@ -76,8 +75,8 @@ public void testRoundTripDateJsonAtom() throws URISyntaxException, StorageExcept // 2015-02-14T03:11:13.0000229Z from .Net testTableQueryRoundTripDate( "2015-02-14T03:11:13.0000229Z", 1423883473000L, 229, false, false, TablePayloadFormat.Json); - - + + // JSON NO METADATA // 2014-12-07T09:15:12.123Z from Java testTableQueryRoundTripDate( @@ -115,7 +114,7 @@ public void testRoundTripDateJsonAtomCrossVersion() // 2015-02-14T03:11:13.0000229Z from .Net testTableQueryRoundTripDate( "2015-02-14T03:11:13.0000229Z", 1423883473000L, 229, true, false, TablePayloadFormat.Json); - + // JSON NO METADATA // 2014-12-07T09:15:12.123Z from Java testTableQueryRoundTripDate( @@ -191,7 +190,7 @@ public void testRoundTripDateJsonAtomCrossVersionWithBackwardCompatibility() // 2015-02-14T03:11:13.0000229Z from .Net testTableQueryRoundTripDate( "2015-02-14T03:11:13.0000229Z", 1423883473000L, 229, true, true, TablePayloadFormat.Json); - + // JSON NO METADATA // 2014-12-07T09:15:12.123Z from Java testTableQueryRoundTripDate( @@ -238,7 +237,7 @@ private void testRoundTripDate(final Date date) throws URISyntaxException, Stora options.setDateBackwardCompatibility(true); entity = this.table.execute(get, options, null).getResultAsType(); assertEquals(date.getTime(), entity.getDate().getTime()); - + // DateBackwardCompatibility off final String dateKey = "date"; final EntityProperty property = new EntityProperty(date); @@ -275,7 +274,7 @@ private void testTableQueryRoundTripDate(final String dateString, final long mil final String partitionKey = "partitionTest"; final String dateKey = "date"; long expectedMilliseconds = milliseconds; - + if (dateBackwardCompatibility && (milliseconds % 1000 == 0) && (ticks < 1000)) { // when no milliseconds are present dateBackwardCompatibility causes up to 3 digits of ticks // to be read as milliseconds @@ -284,7 +283,7 @@ private void testTableQueryRoundTripDate(final String dateString, final long mil // without DateBackwardCompatibility, milliseconds stored by Java prior to 2.0.0 are lost expectedMilliseconds -= expectedMilliseconds % 1000; } - + // Create a property for how the service would store the dateString EntityProperty property = new EntityProperty(dateString, EdmType.DATE_TIME); String rowKey = TableTestHelper.generateRandomKeyName(); @@ -294,35 +293,35 @@ private void testTableQueryRoundTripDate(final String dateString, final long mil // Add the entity to the table TableOperation put = TableOperation.insertOrReplace(dynamicEntity); this.table.execute(put); - + // Specify the options TableRequestOptions options = new TableRequestOptions(); options.setDateBackwardCompatibility(dateBackwardCompatibility); options.setTablePayloadFormat(format); - + // Fetch the entity from the table TableOperation get = TableOperation.retrieve(partitionKey, rowKey, DynamicTableEntity.class); dynamicEntity = this.table.execute(get, options, null).getResultAsType(); - + // Ensure the date matches our expectations assertEquals(expectedMilliseconds, dynamicEntity.getProperties().get(dateKey).getValueAsDate().getTime()); } - + private static class DateTestEntity extends TableServiceEntity { private Date value; - + @SuppressWarnings("unused") public DateTestEntity() { } - + public DateTestEntity(String partition, String key) { super(partition, key); } - + public Date getDate() { return this.value; } - + public void setDate(Date value) { this.value = value; } diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/table/TableEscapingTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/table/TableEscapingTests.java index 96a9be166291..6b46bf11c51e 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/table/TableEscapingTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/table/TableEscapingTests.java @@ -1,11 +1,11 @@ /** * Copyright Microsoft Corporation - * + * * Licensed 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. @@ -14,21 +14,21 @@ */ package com.microsoft.azure.storage.table; -import static org.junit.Assert.*; - -import java.net.URISyntaxException; -import java.util.UUID; +import com.microsoft.azure.storage.StorageException; +import com.microsoft.azure.storage.TestRunners.CloudTests; +import com.microsoft.azure.storage.TestRunners.DevFabricTests; +import com.microsoft.azure.storage.TestRunners.DevStoreTests; +import com.microsoft.azure.storage.table.TableTestHelper.Class1; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.experimental.categories.Category; -import com.microsoft.azure.storage.StorageException; -import com.microsoft.azure.storage.TestRunners.CloudTests; -import com.microsoft.azure.storage.TestRunners.DevFabricTests; -import com.microsoft.azure.storage.TestRunners.DevStoreTests; -import com.microsoft.azure.storage.table.TableTestHelper.Class1; +import java.net.URISyntaxException; +import java.util.UUID; + +import static org.junit.Assert.*; /** * Table Escaping Tests diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/table/TableODataTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/table/TableODataTests.java index 402d8c5019ac..fd49a1a6b4a3 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/table/TableODataTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/table/TableODataTests.java @@ -1,11 +1,11 @@ /** * Copyright Microsoft Corporation - * + * * Licensed 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. @@ -14,24 +14,19 @@ */ package com.microsoft.azure.storage.table; -import static org.junit.Assert.*; - import java.net.URISyntaxException; import java.util.UUID; import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.junit.experimental.categories.Category; import com.microsoft.azure.storage.StorageException; -import com.microsoft.azure.storage.TestRunners.CloudTests; -import com.microsoft.azure.storage.TestRunners.DevFabricTests; -import com.microsoft.azure.storage.TestRunners.DevStoreTests; import com.microsoft.azure.storage.table.TableRequestOptions.PropertyResolver; import com.microsoft.azure.storage.table.TableTestHelper.Class1; -@Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) +import static org.junit.Assert.*; + public class TableODataTests { TableRequestOptions options; diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/table/TableOperationTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/table/TableOperationTests.java index e17fdffb844d..48de0b766dc3 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/table/TableOperationTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/table/TableOperationTests.java @@ -1,11 +1,11 @@ /** * Copyright Microsoft Corporation - * + * * Licensed 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. @@ -14,8 +14,6 @@ */ package com.microsoft.azure.storage.table; -import static org.junit.Assert.*; - import java.net.HttpURLConnection; import java.net.URISyntaxException; import java.util.Arrays; @@ -40,6 +38,8 @@ import com.microsoft.azure.storage.table.TableTestHelper.EmptyClassDynamic; import com.microsoft.azure.storage.table.TableTestHelper.class1class2PropertyResolver; +import static org.junit.Assert.*; + /** * Table Operation Tests */ @@ -87,7 +87,7 @@ public void testRetrieveWithNullResolver() { String.format(SR.ARGUMENT_NULL_OR_EMPTY, SR.QUERY_REQUIRES_VALID_CLASSTYPE_OR_RESOLVER)); } } - + @Test public void testEntityWithSingleQuote() throws StorageException { TableRequestOptions options = new TableRequestOptions(); @@ -96,14 +96,14 @@ public void testEntityWithSingleQuote() throws StorageException { EmptyClass ref = new EmptyClass(); ref.setPartitionKey("partition'key"); ref.setRowKey("row'key"); - - this.table.execute(TableOperation.insert(ref), options, null); - this.table.execute(TableOperation.merge(ref), options, null); - this.table.execute(TableOperation.insertOrReplace(ref), options, null); - this.table.execute(TableOperation.insertOrMerge(ref), options, null); - this.table.execute(TableOperation.replace(ref), options, null); - this.table.execute(TableOperation.retrieve(ref.getPartitionKey(), ref.getRowKey(), EmptyClass.class), options, null); - this.table.execute(TableOperation.delete(ref), options, null); + + this.table.execute(TableOperation.insert(ref), options, null); + this.table.execute(TableOperation.merge(ref), options, null); + this.table.execute(TableOperation.insertOrReplace(ref), options, null); + this.table.execute(TableOperation.insertOrMerge(ref), options, null); + this.table.execute(TableOperation.replace(ref), options, null); + this.table.execute(TableOperation.retrieve(ref.getPartitionKey(), ref.getRowKey(), EmptyClass.class), options, null); + this.table.execute(TableOperation.delete(ref), options, null); } @Test @@ -229,7 +229,7 @@ public void testDeleteFail() throws StorageException { ref.setA("foo_A"); ref.setB("foo_B"); ref.setC("foo_C"); - ref.setD(new byte[] { 0, 1, 2 }); + ref.setD(new byte[]{0, 1, 2}); ref.setPartitionKey("jxscl_odata"); ref.setRowKey(UUID.randomUUID().toString()); @@ -283,7 +283,7 @@ public void testMergeFail() throws StorageException { baseEntity.setA("foo_A"); baseEntity.setB("foo_B"); baseEntity.setC("foo_C"); - baseEntity.setD(new byte[] { 0, 1, 2 }); + baseEntity.setD(new byte[]{0, 1, 2}); baseEntity.setPartitionKey("jxscl_odata"); baseEntity.setRowKey(UUID.randomUUID().toString()); @@ -343,7 +343,7 @@ public void testInsertFail() throws StorageException { ref.setA("foo_A"); ref.setB("foo_B"); ref.setC("foo_C"); - ref.setD(new byte[] { 0, 1, 2 }); + ref.setD(new byte[]{0, 1, 2}); ref.setPartitionKey("jxscl_odata"); ref.setRowKey(UUID.randomUUID().toString()); @@ -371,7 +371,7 @@ public void testReplaceFail() throws StorageException { baseEntity.setA("foo_A"); baseEntity.setB("foo_B"); baseEntity.setC("foo_C"); - baseEntity.setD(new byte[] { 0, 1, 2 }); + baseEntity.setD(new byte[]{0, 1, 2}); baseEntity.setPartitionKey("jxscl_odata"); baseEntity.setRowKey(UUID.randomUUID().toString()); @@ -385,7 +385,7 @@ public void testReplaceFail() throws StorageException { DynamicTableEntity.class), options, null); // Retrieve entity - DynamicTableEntity retrievedEntity = queryResult. getResultAsType(); + DynamicTableEntity retrievedEntity = queryResult.getResultAsType(); assertNotNull("Property D", retrievedEntity.getProperties().get("D")); assertTrue(Arrays.equals(baseEntity.getD(), retrievedEntity.getProperties().get("D").getValueAsByteArray())); @@ -435,7 +435,7 @@ public void testEmptyRetrieve() throws StorageException { ref.setA("foo_A"); ref.setB("foo_B"); ref.setC("foo_C"); - ref.setD(new byte[] { 0, 1, 2 }); + ref.setD(new byte[]{0, 1, 2}); ref.setPartitionKey("jxscl_odata"); ref.setRowKey(UUID.randomUUID().toString()); @@ -485,7 +485,7 @@ private void testDelete(TableRequestOptions options) throws StorageException { ref.setA("foo_A"); ref.setB("foo_B"); ref.setC("foo_C"); - ref.setD(new byte[] { 0, 1, 2 }); + ref.setD(new byte[]{0, 1, 2}); ref.setPartitionKey("jxscl_odata"); ref.setRowKey(UUID.randomUUID().toString()); @@ -522,7 +522,7 @@ private void testInsertOrMerge(TableRequestOptions options, boolean usePropertyR baseEntity.setA("foo_A"); baseEntity.setB("foo_B"); baseEntity.setC("foo_C"); - baseEntity.setD(new byte[] { 0, 1, 2 }); + baseEntity.setD(new byte[]{0, 1, 2}); baseEntity.setPartitionKey("jxscl_odata"); baseEntity.setRowKey(UUID.randomUUID().toString()); @@ -554,7 +554,7 @@ private void testInsertOrMerge(TableRequestOptions options, boolean usePropertyR .execute(TableOperation.retrieve(baseEntity.getPartitionKey(), baseEntity.getRowKey(), DynamicTableEntity.class), options, null); - DynamicTableEntity retrievedEntity = queryResult. getResultAsType(); + DynamicTableEntity retrievedEntity = queryResult.getResultAsType(); assertNotNull("Property A", retrievedEntity.getProperties().get("A")); assertEquals(baseEntity.getA(), retrievedEntity.getProperties().get("A").getValueAsString()); @@ -601,7 +601,7 @@ private void testInsertOrReplace(TableRequestOptions options) throws StorageExce baseEntity.setA("foo_A"); baseEntity.setB("foo_B"); baseEntity.setC("foo_C"); - baseEntity.setD(new byte[] { 0, 1, 2 }); + baseEntity.setD(new byte[]{0, 1, 2}); baseEntity.setPartitionKey("jxscl_odata"); baseEntity.setRowKey(UUID.randomUUID().toString()); @@ -673,7 +673,7 @@ private void testMerge(TableRequestOptions options, boolean usePropertyResolver) baseEntity.setA("foo_A"); baseEntity.setB("foo_B"); baseEntity.setC("foo_C"); - baseEntity.setD(new byte[] { 0, 1, 2 }); + baseEntity.setD(new byte[]{0, 1, 2}); baseEntity.setPartitionKey("jxscl_odata"); baseEntity.setRowKey(UUID.randomUUID().toString()); @@ -747,7 +747,7 @@ private void testReplace(TableRequestOptions options) throws StorageException { baseEntity.setA("foo_A"); baseEntity.setB("foo_B"); baseEntity.setC("foo_C"); - baseEntity.setD(new byte[] { 0, 1, 2 }); + baseEntity.setD(new byte[]{0, 1, 2}); baseEntity.setPartitionKey("jxscl_odata"); baseEntity.setRowKey(UUID.randomUUID().toString()); @@ -758,7 +758,7 @@ private void testReplace(TableRequestOptions options) throws StorageException { .execute(TableOperation.retrieve(baseEntity.getPartitionKey(), baseEntity.getRowKey(), DynamicTableEntity.class), options, null); // Retrieve entity - DynamicTableEntity retrievedEntity = queryResult. getResultAsType(); + DynamicTableEntity retrievedEntity = queryResult.getResultAsType(); assertNotNull("Property D", retrievedEntity.getProperties().get("D")); assertTrue(Arrays.equals(baseEntity.getD(), retrievedEntity.getProperties().get("D").getValueAsByteArray())); @@ -775,7 +775,7 @@ private void testReplace(TableRequestOptions options) throws StorageException { .execute(TableOperation.retrieve(baseEntity.getPartitionKey(), baseEntity.getRowKey(), DynamicTableEntity.class), options, null); - retrievedEntity = queryResult. getResultAsType(); + retrievedEntity = queryResult.getResultAsType(); // Validate assertNotNull("Property A", retrievedEntity.getProperties().get("A")); @@ -849,7 +849,7 @@ private void testRetrieveWithoutEntityResolver(TableRequestOptions options, bool ref.setA("foo_A"); ref.setB("foo_B"); ref.setC("foo_C"); - ref.setD(new byte[] { 0, 1, 2 }); + ref.setD(new byte[]{0, 1, 2}); ref.setPartitionKey("jxscl_odata"); ref.setRowKey(UUID.randomUUID().toString()); @@ -907,7 +907,7 @@ private void testRetrieveWithEntityResolver(TableRequestOptions options, boolean ref.setA("foo_A"); ref.setB("foo_B"); ref.setC("foo_C"); - ref.setD(new byte[] { 0, 1, 2 }); + ref.setD(new byte[]{0, 1, 2}); ref.setPartitionKey("jxscl_odata"); ref.setRowKey(UUID.randomUUID().toString()); @@ -924,7 +924,7 @@ private void testRetrieveWithEntityResolver(TableRequestOptions options, boolean TableOperation.retrieve(ref.getPartitionKey(), ref.getRowKey(), new EntityResolver() { @Override public Class1 resolve(String partitionKey, String rowKey, Date timeStamp, - HashMap properties, String etag) { + HashMap properties, String etag) { Class1 result = new Class1(); result.setA(properties.get("A").getValueAsString()); result.setD(properties.get("D").getValueAsByteArray()); @@ -943,7 +943,7 @@ public Class1 resolve(String partitionKey, String rowKey, Date timeStamp, TableOperation.retrieve(ref.getPartitionKey(), ref.getRowKey(), new EntityResolver() { @Override public Class1 resolve(String partitionKey, String rowKey, Date timeStamp, - HashMap properties, String etag) { + HashMap properties, String etag) { Class1 result = new Class1(); result.setA(properties.get("A").getValueAsString()); result.setD(properties.get("D").getValueAsByteArray()); diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/table/TableQueryTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/table/TableQueryTests.java index 37a0a1ec6d87..d6acf859381a 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/table/TableQueryTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/table/TableQueryTests.java @@ -1,11 +1,11 @@ /** * Copyright Microsoft Corporation - * + * * Licensed 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. @@ -14,8 +14,6 @@ */ package com.microsoft.azure.storage.table; -import static org.junit.Assert.*; - import java.net.HttpURLConnection; import java.net.URISyntaxException; import java.util.ArrayList; @@ -44,6 +42,8 @@ import com.microsoft.azure.storage.table.TableTestHelper.ComplexEntity; import com.microsoft.azure.storage.table.TableTestHelper.EmptyClass; +import static org.junit.Assert.*; + /** * Table Query Tests */ @@ -102,28 +102,28 @@ public void testQueryWithInvalidTakeCount() { assertEquals(ex.getMessage(), "Take count must be positive and greater than 0."); } } - + @Test public void testTableWithSelectOnMissingFields() throws StorageException { TableRequestOptions options = new TableRequestOptions(); options.setTablePayloadFormat(TablePayloadFormat.Json); testTableWithSelectOnMissingFields(options); - + options.setTablePayloadFormat(TablePayloadFormat.JsonNoMetadata); testTableWithSelectOnMissingFields(options); } - + private void testTableWithSelectOnMissingFields(TableRequestOptions options) throws StorageException { TableQuery projectionQuery = TableQuery.from(DynamicTableEntity.class).where( "(PartitionKey eq 'javatables_batch_0') and (RowKey eq '000000')"); - + // A exists, F does not projectionQuery.select(new String[]{"A", "F"}); - + ResultSegment seg = table.executeSegmented(projectionQuery, null, options, null); assertEquals(1, seg.getResults().size()); - + DynamicTableEntity ent = seg.getResults().get(0); assertEquals("foo_A", ent.getProperties().get("A").getValueAsString()); assertEquals(null, ent.getProperties().get("F").getValueAsString()); @@ -207,20 +207,20 @@ public void testTableQueryWithSpecialChars() throws StorageException, URISyntaxE table.deleteIfExists(); } } - - private void testTableQueryWithSpecialChars(char charToTest, CloudTable table) + + private void testTableQueryWithSpecialChars(char charToTest, CloudTable table) throws StorageException, URISyntaxException { String partitionKey = "partition" + charToTest + "key"; String rowKey = "row" + charToTest + "key"; - + EmptyClass ref = new EmptyClass(); ref.setPartitionKey(partitionKey); ref.setRowKey(rowKey); - + table.execute(TableOperation.insert(ref)); String condition = TableQuery.generateFilterCondition(TableConstants.PARTITION_KEY, QueryComparisons.EQUAL, partitionKey); ResultSegment seg = table.executeSegmented(TableQuery.from(EmptyClass.class).where(condition), null); - + assertEquals(1, seg.getLength()); assertEquals(partitionKey, seg.getResults().get(0).getPartitionKey()); } @@ -352,7 +352,7 @@ private void testQueryOnSupportedTypes(TableRequestOptions options, boolean useP TableQuery.generateFilterCondition("BoolPrimitive", QueryComparisons.EQUAL, middleRef.getBool()), 50, options, usePropertyResolver); - // 8. Filter on Binary + // 8. Filter on Binary executeQueryAndAssertResults( TableQuery.generateFilterCondition("Binary", QueryComparisons.EQUAL, middleRef.getBinary()), 1, options, usePropertyResolver); diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/table/TableSerializerTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/table/TableSerializerTests.java index 4dc19f8f29b2..fc5638669a13 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/table/TableSerializerTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/table/TableSerializerTests.java @@ -1,11 +1,11 @@ /** * Copyright Microsoft Corporation - * + * * Licensed 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. @@ -14,8 +14,6 @@ */ package com.microsoft.azure.storage.table; -import static org.junit.Assert.*; - import java.net.URISyntaxException; import java.util.UUID; @@ -37,6 +35,8 @@ import com.microsoft.azure.storage.table.TableTestHelper.StoreAsEntity; import com.microsoft.azure.storage.table.TableTestHelper.StrangeDoubles; +import static org.junit.Assert.*; + /** * Table Serializer Tests */ diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/table/TableTestHelper.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/table/TableTestHelper.java index 522402381136..bee9610e4a71 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/table/TableTestHelper.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/table/TableTestHelper.java @@ -14,16 +14,16 @@ */ package com.microsoft.azure.storage.table; -import static org.junit.Assert.*; +import com.microsoft.azure.storage.StorageException; +import com.microsoft.azure.storage.TestHelper; +import com.microsoft.azure.storage.table.TableRequestOptions.PropertyResolver; import java.net.URISyntaxException; import java.util.Arrays; import java.util.Date; import java.util.UUID; -import com.microsoft.azure.storage.StorageException; -import com.microsoft.azure.storage.TestHelper; -import com.microsoft.azure.storage.table.TableRequestOptions.PropertyResolver; +import static org.junit.Assert.*; /** * Table Test Base diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/table/TableTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/table/TableTests.java index 08fa48e8ea59..3d30576d56a0 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/table/TableTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/table/TableTests.java @@ -15,8 +15,6 @@ package com.microsoft.azure.storage.table; -import static org.junit.Assert.*; - import java.net.HttpURLConnection; import java.net.URI; import java.net.URISyntaxException; @@ -50,15 +48,16 @@ import com.microsoft.azure.storage.core.PathUtility; import com.microsoft.azure.storage.table.TableTestHelper.Class1; +import static org.junit.Assert.*; + @Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) public class TableTests { - - /** - * Tests name validation of tables. - */ - @Test - public void testCloudTableNameValidation() - { + + /** + * Tests name validation of tables. + */ + @Test + public void testCloudTableNameValidation() { NameValidator.validateTableName("alpha"); NameValidator.validateTableName("alphanum3r1c"); NameValidator.validateTableName("CapsLock"); @@ -78,19 +77,16 @@ public void testCloudTableNameValidation() invalidTableTestHelper(new String(new char[64]).replace("\0", "n"), "Between 3 and 63 characters.", "Invalid table name length. The name must be between 3 and 63 characters long."); } - private void invalidTableTestHelper(String tableName, String failMessage, String exceptionMessage) - { - try - { + private void invalidTableTestHelper(String tableName, String failMessage, String exceptionMessage) { + try { NameValidator.validateTableName(tableName); fail(failMessage); } - catch (IllegalArgumentException e) - { + catch (IllegalArgumentException e) { assertEquals(exceptionMessage, e.getMessage()); } } - + @Test public void testIsUsePathStyleUri() throws InvalidKeyException, URISyntaxException, StorageException { // normal account @@ -176,7 +172,6 @@ public void testTableCreateAndAttemptCreateOnceExists() throws StorageException, CloudTableClient tClient = TableTestHelper.createCloudTableClient(); tClient.getDefaultRequestOptions().setTablePayloadFormat(TablePayloadFormat.Json); - String tableName = TableTestHelper.generateRandomTableName(); CloudTable table = tClient.getTableReference(tableName); @@ -202,7 +197,6 @@ public void testTableCreateAndAttemptCreateOnceExists() throws StorageException, @Test public void testTableCreateExistsAndDelete() throws StorageException, URISyntaxException { - CloudTableClient tClient = TableTestHelper.createCloudTableClient(); tClient.getDefaultRequestOptions().setTablePayloadFormat(TablePayloadFormat.Json); @@ -222,7 +216,6 @@ public void testTableCreateExistsAndDelete() throws StorageException, URISyntaxE @Test public void testTableCreateIfNotExists() throws StorageException, URISyntaxException { - CloudTableClient tClient = TableTestHelper.createCloudTableClient(); tClient.getDefaultRequestOptions().setTablePayloadFormat(TablePayloadFormat.Json); @@ -242,10 +235,8 @@ public void testTableCreateIfNotExists() throws StorageException, URISyntaxExcep @Test public void testTableDeleteIfExists() throws StorageException, URISyntaxException { - CloudTableClient tClient = TableTestHelper.createCloudTableClient(); tClient.getDefaultRequestOptions().setTablePayloadFormat(TablePayloadFormat.Json); - String tableName = TableTestHelper.generateRandomTableName(); CloudTable table = tClient.getTableReference(tableName); @@ -446,7 +437,7 @@ public void testTableSas() throws StorageException, URISyntaxException, InvalidK "javatables_batch_9", "9"))); assertEquals(StorageCredentialsSharedAccessSignature.class.toString(), tableFromUri.getServiceClient() .getCredentials().getClass().toString()); - + // create credentials from sas StorageCredentials creds = new StorageCredentialsSharedAccessSignature( table.generateSharedAccessSignature((SharedAccessTablePolicy) null, identifier, "javatables_batch_0", "0", diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/SharedAccessPolicySerializer.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/SharedAccessPolicySerializer.java index d36e66d51878..a87e5c7fbdf7 100644 --- a/microsoft-azure-storage/src/com/microsoft/azure/storage/SharedAccessPolicySerializer.java +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/SharedAccessPolicySerializer.java @@ -1,11 +1,11 @@ /** * Copyright Microsoft Corporation - * + * * Licensed 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. @@ -14,6 +14,9 @@ */ package com.microsoft.azure.storage; +import com.microsoft.azure.storage.core.SR; +import com.microsoft.azure.storage.core.Utility; + import java.io.StringWriter; import java.util.HashMap; import java.util.Map.Entry; @@ -21,18 +24,15 @@ import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; -import com.microsoft.azure.storage.core.SR; -import com.microsoft.azure.storage.core.Utility; - /** * RESERVED FOR INTERNAL USE. A class used to serialize SharedAccessPolicies to a byte array. */ public final class SharedAccessPolicySerializer { /** * RESERVED FOR INTERNAL USE. Writes a collection of shared access policies to the specified stream in XML format. - * + * * @param - * + * * @param sharedAccessPolicies * A collection of shared access policies * @param outWriter From e1e339a3623d91ebefa3fb81948d6787a07e3548 Mon Sep 17 00:00:00 2001 From: Josh Friedman Date: Tue, 15 Nov 2016 13:30:56 -0800 Subject: [PATCH 04/11] May 16 Features except for Incremental Copy --- BreakingChanges.txt | 5 + ChangeLog.txt | 7 ++ .../storage/blob/CloudBlobClientTests.java | 117 ++++++++++++++++-- .../storage/blob/CloudBlockBlobTests.java | 7 ++ .../storage/blob/CloudPageBlobTests.java | 7 ++ .../storage/file/CloudFileDirectoryTests.java | 67 +++++++++- .../azure/storage/file/CloudFileTests.java | 7 ++ .../azure/storage/queue/CloudQueueTests.java | 41 ++++++ .../microsoft/azure/storage/Constants.java | 7 +- .../storage/blob/BlobContainerProperties.java | 58 +++++++-- .../blob/BlobContainerPublicAccessType.java | 41 +++++- .../azure/storage/blob/BlobRequest.java | 12 +- .../azure/storage/blob/BlobResponse.java | 64 +++++++--- .../azure/storage/blob/CloudBlob.java | 17 +-- .../storage/blob/CloudBlobContainer.java | 98 +++++++++++---- .../storage/blob/ContainerListHandler.java | 16 ++- .../azure/storage/file/CloudFile.java | 19 +-- .../storage/file/CloudFileDirectory.java | 81 ++++++++++-- .../azure/storage/file/FileRequest.java | 4 + .../azure/storage/file/FileResponse.java | 36 +++--- .../azure/storage/queue/CloudQueue.java | 28 +++-- 21 files changed, 609 insertions(+), 130 deletions(-) diff --git a/BreakingChanges.txt b/BreakingChanges.txt index c3d74ad6a89f..812e15469587 100644 --- a/BreakingChanges.txt +++ b/BreakingChanges.txt @@ -1,3 +1,8 @@ +Changes in 5.0.0 + +QUEUE + * For addMessage() the CloudQueueMessage message passed in will be populated with the pop receipt, insertion/expiration time, and message ID. + Changes in 4.0.0 TABLE diff --git a/ChangeLog.txt b/ChangeLog.txt index 91d231f0ac3c..ed5d80d62e58 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,3 +1,10 @@ +2016.XX.XX Version 5.0.0 + * Prefix support for listing files and directories. + * Added support for setting public access when creating a blob container + * The public access setting on a blob container is now a container property returned from downloadProperties. + * Add Message now modifies the PopReceipt, Id, NextVisibleTime, InsertionTime, and ExpirationTime properties of its CloudQueueMessage parameter. + * Populate content MD5 for range gets on Blobs and Files. + 2016.08.30 Version 4.4.0 * Fixed a bug in client-side encryption for tables that was preventing the Java client from decrypting entities encrypted with the .NET client, and vice versa. diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlobClientTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlobClientTests.java index 9a8226f56809..791776174c44 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlobClientTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlobClientTests.java @@ -1,11 +1,11 @@ /** * Copyright Microsoft Corporation - * + * * Licensed 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. @@ -17,6 +17,7 @@ import java.io.IOException; import java.net.URISyntaxException; import java.util.ArrayList; +import java.util.Iterator; import java.util.UUID; import org.junit.Test; @@ -43,7 +44,7 @@ */ public class CloudBlobClientTests { /** - * + * * @throws StorageException * @throws URISyntaxException */ @@ -82,10 +83,10 @@ public void testListContainers() throws StorageException, URISyntaxException { assertEquals(0, containerList.size()); } - + /** * Try to list the containers to ensure maxResults validation is working. - * + * * @throws StorageException * @throws URISyntaxException */ @@ -110,10 +111,10 @@ public void testListContainersMaxResultsValidation() } assertNotNull(bClient.listContainersSegmented("thereshouldntbeanycontainersswiththisprefix")); } - + /** * Fetch result segments and ensure pageSize is null when unspecified and will cap at 5000. - * + * * @throws StorageException * @throws URISyntaxException */ @@ -123,17 +124,113 @@ public void testListContainersResultSegment() throws StorageException, URISyntaxException { CloudBlobClient bClient = BlobTestHelper.createCloudBlobClient(); - ResultSegment segment1 = bClient.listContainersSegmented(); + ResultSegment segment1 = bClient.listContainersSegmented(); assertNotNull(segment1); assertNull(segment1.getPageSize()); - + ResultSegment segment2 = bClient.listContainersSegmented(null, - ContainerListingDetails.ALL, 9001, null, null, null); + ContainerListingDetails.ALL, 9001, null, null, null); assertNotNull(segment2); assertNotNull(segment2.getPageSize()); assertEquals(5000, segment2.getPageSize().intValue()); } + /** + * List containers and fetch attributes with public access + * + * @throws StorageException + * @throws URISyntaxException + */ + @Test + @Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) + public void testCreateContainerWithPublicAccess() throws StorageException, URISyntaxException { + CloudBlobClient bClient = BlobTestHelper.createCloudBlobClient(); + BlobContainerPublicAccessType[] accessTypes = { BlobContainerPublicAccessType.CONTAINER, + BlobContainerPublicAccessType.OFF, BlobContainerPublicAccessType.BLOB }; + for(BlobContainerPublicAccessType accessType : accessTypes) + { + String name = UUID.randomUUID().toString(); + CloudBlobContainer container = bClient.getContainerReference(name); + assertNull(container.properties.getPublicAccess()); + container.create(accessType, null, null); + assertEquals(accessType, container.properties.getPublicAccess()); + + CloudBlobContainer containerRef = bClient.getContainerReference(name); + assertNull(containerRef.properties.getPublicAccess()); + BlobContainerPermissions permissions = containerRef.downloadPermissions(); + assertEquals(accessType, containerRef.properties.getPublicAccess()); + assertEquals(accessType, permissions.getPublicAccess()); + + CloudBlobContainer containerRef2 = bClient.getContainerReference(name); + assertEquals(null, containerRef2.properties.getPublicAccess()); + containerRef2.exists(); + assertEquals(accessType, containerRef2.properties.getPublicAccess()); + + String name2 = UUID.randomUUID().toString(); + CloudBlobContainer container2 = bClient.getContainerReference(name2); + assertNull(container2.properties.getPublicAccess()); + container2.create(); + assertEquals(BlobContainerPublicAccessType.OFF, container2.properties.getPublicAccess()); + + BlobContainerPermissions permissions2 = new BlobContainerPermissions(); + permissions2.setPublicAccess(accessType); + container2.uploadPermissions(permissions); + assertEquals(accessType, container2.properties.getPublicAccess()); + + CloudBlobContainer containerRef3 = bClient.getContainerReference(name); + containerRef3.downloadAttributes(); + assertEquals(accessType, containerRef3.properties.getPublicAccess()); + + String name3 = UUID.randomUUID().toString(); + CloudBlobContainer container3 = bClient.getContainerReference(name3); + container3.create(null, null, null); + assertEquals(BlobContainerPublicAccessType.OFF, container3.properties.getPublicAccess()); + + container.delete(); + container2.delete(); + container3.delete(); + } + } + + /** + * List containers and fetch attributes with public access + * + * @throws StorageException + * @throws URISyntaxException + */ + @Test + @Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) + public void testListContainersAndFetchAttributesWithPublicAccess() throws StorageException, URISyntaxException { + CloudBlobClient bClient = BlobTestHelper.createCloudBlobClient(); + String name = UUID.randomUUID().toString(); + CloudBlobContainer container = bClient.getContainerReference(name); + container.create(); + BlobContainerPublicAccessType[] accessTypes = {BlobContainerPublicAccessType.BLOB, + BlobContainerPublicAccessType.CONTAINER, BlobContainerPublicAccessType.OFF}; + BlobContainerPermissions permissions = new BlobContainerPermissions(); + for (BlobContainerPublicAccessType accessType : accessTypes) { + permissions.setPublicAccess(accessType); + container.uploadPermissions(permissions); + assertEquals(accessType, container.properties.getPublicAccess()); + + CloudBlobContainer container2 = bClient.getContainerReference(name); + assertNull(container2.properties.getPublicAccess()); + container2.downloadAttributes(); + assertEquals(accessType, container2.properties.getPublicAccess()); + + CloudBlobContainer container3 = bClient.getContainerReference(name); + assertNull(container3.properties.getPublicAccess()); + assertEquals(accessType, container3.downloadPermissions().getPublicAccess()); + + Iterator results = bClient.listContainers(name, ContainerListingDetails.NONE, null, null).iterator(); + assertTrue(results.hasNext()); + assertEquals(accessType, results.next().properties.getPublicAccess()); + assertFalse(results.hasNext()); + } + + container.delete(); + } + @Test @Category({ CloudTests.class }) public void testGetServiceStats() throws StorageException { diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlockBlobTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlockBlobTests.java index c222b046fa61..d1381adff442 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlockBlobTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlockBlobTests.java @@ -1046,6 +1046,13 @@ public void testBlobUploadWithoutMD5Validation() throws URISyntaxException, Stor options.setDisableContentMD5Validation(true); blockBlobRef.download(new ByteArrayOutputStream(), null, options, null); + + final CloudBlockBlob blockBlobRef2 = this.container.getBlockBlobReference(blockBlobName); + assertNull(blockBlobRef2.getProperties().getContentMD5()); + + byte[] target = new byte[4]; + blockBlobRef2.downloadRangeToByteArray(0L, 4L, target, 0); + assertEquals("MDAwMDAwMDA=", blockBlobRef2.properties.getContentMD5()); } @Test diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudPageBlobTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudPageBlobTests.java index 191643233865..ea96069c03fd 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudPageBlobTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudPageBlobTests.java @@ -247,6 +247,13 @@ public void testBlobUploadWithoutMD5Validation() throws URISyntaxException, Stor options.setDisableContentMD5Validation(true); pageBlobRef.download(new ByteArrayOutputStream(), null, options, null); + + final CloudPageBlob pageBlobRef2 = this.container.getPageBlobReference(pageBlobName); + assertNull(pageBlobRef2.getProperties().getContentMD5()); + + byte[] target = new byte[4]; + pageBlobRef2.downloadRangeToByteArray(0L, 4L, target, 0); + assertEquals("MDAwMDAwMDA=", pageBlobRef2.properties.getContentMD5()); } @Test diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/CloudFileDirectoryTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/CloudFileDirectoryTests.java index f32dd907d070..2675604c85f4 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/CloudFileDirectoryTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/CloudFileDirectoryTests.java @@ -260,6 +260,71 @@ public void testCloudFileDirectoryListFilesAndDirectories() throws StorageExcept } } + /** + * Test listFilesAndDirectories with prefix + * + * @throws StorageException + * @throws URISyntaxException + */ + @Test + @Category({ DevFabricTests.class, CloudTests.class }) + public void testCloudFileDirectoryListFilesAndDirectoriesWithPrefix() throws URISyntaxException, StorageException + { + if (doCloudFileDirectorySetup(this.share)) { + CloudFileDirectory topDir1 = this.share.getRootDirectoryReference().getDirectoryReference("TopDir1"); + Iterable list = topDir1.listFilesAndDirectories("file", null, null); + ArrayList simpleList = new ArrayList(); + for (ListFileItem i : list) { + simpleList.add(i); + } + + assertTrue(simpleList.size() == 1); + ListFileItem item = simpleList.get(0); + assertEquals(this.share.getUri() + "/TopDir1/File1", item.getUri().toString()); + assertEquals("File1", ((CloudFile) item).getName()); + + list = topDir1.listFilesAndDirectories("mid", null, null); + simpleList = new ArrayList(); + for (ListFileItem i : list) { + simpleList.add(i); + } + + assertTrue(simpleList.size() == 2); + item = simpleList.get(0); + ListFileItem item2 = simpleList.get(1); + assertEquals(this.share.getUri() + "/TopDir1/MidDir1", item.getUri().toString()); + assertEquals("MidDir1", ((CloudFileDirectory) item).getName()); + assertEquals(this.share.getUri() + "/TopDir1/MidDir2", item2.getUri().toString()); + assertEquals("MidDir2", ((CloudFileDirectory) item2).getName()); + + ResultSegment segmentResults = topDir1.listFilesAndDirectoriesSegmented( + "mid", + 1, + null, + null, + null); + + assertNotNull(segmentResults.getContinuationToken().getNextMarker()); + assertEquals(1, segmentResults.getResults().size()); + item = segmentResults.getResults().get(0); + assertEquals(this.share.getUri() + "/TopDir1/MidDir1", item.getUri().toString()); + assertEquals("MidDir1", ((CloudFileDirectory)item).getName()); + + segmentResults = topDir1.listFilesAndDirectoriesSegmented( + "mid" /* prefix */, + null /* maxResults */, + segmentResults.getContinuationToken() /* currentToken */, + null /* options */, + null /* operationContext */); + + assertNull(segmentResults.getContinuationToken()); + assertEquals(1, segmentResults.getResults().size()); + item = segmentResults.getResults().get(0); + assertEquals(this.share.getUri() + "/TopDir1/MidDir2", item.getUri().toString()); + assertEquals("MidDir2", ((CloudFileDirectory)item).getName()); + } + } + /** * Test listFilesAndDirectories for maxResults validation. * @@ -277,7 +342,7 @@ public void testCloudFileDirectoryListFilesAndDirectoriesMaxResultsValidation() // Validation should cause each of these to fail for (int i = 0; i >= -2; i--) { try { - topDir.listFilesAndDirectoriesSegmented(i, null, null, null); + topDir.listFilesAndDirectoriesSegmented(null, i, null, null, null); fail(); } catch (IllegalArgumentException e) { diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/CloudFileTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/CloudFileTests.java index 4b452827a121..ae8a3f8b68f5 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/CloudFileTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/CloudFileTests.java @@ -715,6 +715,13 @@ public void testFileUploadMD5Validation() throws URISyntaxException, StorageExce assertEquals(e.getCause().getMessage(), "The conditionals specified for this operation did not match server."); } + + final CloudFile fileRef2 = this.share.getRootDirectoryReference().getFileReference(fileName); + assertNull(fileRef2.getProperties().getContentMD5()); + + byte[] target = new byte[4]; + fileRef2.downloadRangeToByteArray(0L, 4L, target, 0); + assertEquals(calculatedMD5, fileRef2.getProperties().getContentMD5()); } @Test diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/queue/CloudQueueTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/queue/CloudQueueTests.java index 6c694efd3ec8..d9b6e3dc9e63 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/queue/CloudQueueTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/queue/CloudQueueTests.java @@ -51,6 +51,7 @@ import org.junit.Test; import org.junit.experimental.categories.Category; +import com.microsoft.azure.keyvault.extensions.Strings; import com.microsoft.azure.storage.LocationMode; import com.microsoft.azure.storage.NameValidator; import com.microsoft.azure.storage.OperationContext; @@ -678,14 +679,42 @@ public void testQueueExist() throws URISyntaxException, StorageException { } } + @Test + @Category({ DevFabricTests.class, DevStoreTests.class }) + public void testAddMessageVerifyPopReceipt() throws StorageException + { + CloudQueueMessage message1 = new CloudQueueMessage("firstmessagetest1"); + message1.setNextVisibleTime(null); + this.queue.addMessage(message1); + + VerifyAddMessageResult(message1, "firstmessagetest1"); + } + + @Test + @Category({ DevFabricTests.class, DevStoreTests.class }) + public void testDeleteMessageWithAddMessagePopReceipt() throws StorageException + { + CloudQueueMessage message1 = new CloudQueueMessage("messagetest1"); + message1.setNextVisibleTime(null); + this.queue.addMessage(message1); + + VerifyAddMessageResult(message1, "messagetest1"); + + queue.deleteMessage(message1); + + assertNull(queue.retrieveMessage()); + } + @Test @Category({ DevFabricTests.class, DevStoreTests.class }) public void testClearMessages() throws StorageException { CloudQueueMessage message1 = new CloudQueueMessage("messagetest1"); this.queue.addMessage(message1); + VerifyAddMessageResult(message1, "messagetest1"); CloudQueueMessage message2 = new CloudQueueMessage("messagetest2"); this.queue.addMessage(message2); + VerifyAddMessageResult(message2, "messagetest2"); int count = 0; for (CloudQueueMessage m : this.queue.peekMessages(32)) { @@ -730,6 +759,7 @@ public void testAddMessage() throws StorageException { String msgContent = UUID.randomUUID().toString(); final CloudQueueMessage message = new CloudQueueMessage(msgContent); this.queue.addMessage(message); + VerifyAddMessageResult(message, msgContent); CloudQueueMessage msgFromRetrieve1 = this.queue.retrieveMessage(); assertEquals(message.getMessageContentAsString(), msgContent); assertEquals(msgFromRetrieve1.getMessageContentAsString(), msgContent); @@ -1447,4 +1477,15 @@ public void testSASClientParse() throws StorageException, InvalidKeyException, U CloudQueue queue2 = new CloudQueue(queueUri, queueClient2.getCredentials()); queue2.getName(); } + + private void VerifyAddMessageResult(CloudQueueMessage originalMessage, String expectedMessageContent) + { + assertFalse(Strings.isNullOrEmpty(originalMessage.getId())); + assertNotNull(originalMessage.getInsertionTime()); + assertNotNull(originalMessage.getExpirationTime()); + assertFalse(Strings.isNullOrEmpty(originalMessage.getPopReceipt())); + + assertTrue(originalMessage.messageContent.equals(expectedMessageContent)); + assertNotNull(originalMessage.getNextVisibleTime()); + } } diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/Constants.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/Constants.java index 8ef76d172d48..4d2d08cf94b5 100644 --- a/microsoft-azure-storage/src/com/microsoft/azure/storage/Constants.java +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/Constants.java @@ -626,7 +626,7 @@ public static class HeaderConstants { /** * The current storage version header value. */ - public static final String TARGET_STORAGE_VERSION = "2015-12-11"; + public static final String TARGET_STORAGE_VERSION = "2016-05-31"; /** * The header that specifies the next visible time for a queue message. @@ -1160,6 +1160,11 @@ public static class QueryConstants { */ public static final String PROPERTIES = "Properties"; + /** + * XML element for public access + */ + public static final String PUBLIC_ACCESS_ELEMENT = "PublicAccess"; + /** * XML element for the server encryption status. */ diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobContainerProperties.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobContainerProperties.java index e84209155a2a..26a835206c0f 100644 --- a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobContainerProperties.java +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobContainerProperties.java @@ -1,11 +1,11 @@ /** * Copyright Microsoft Corporation - * + * * Licensed 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. @@ -48,6 +48,11 @@ public final class BlobContainerProperties { */ private LeaseDuration leaseDuration; + /** + * Represents the level of public access that is allowed on the container. + */ + private BlobContainerPublicAccessType publicAccess; + /** * Gets the ETag value of the container. *

@@ -57,7 +62,7 @@ public final class BlobContainerProperties { * The {@link AccessCondition#generateIfMatchCondition(String)} and * {@link AccessCondition#generateIfNoneMatchCondition(String)} methods take an ETag value and return an * {@link AccessCondition} object that may be specified on the request. - * + * * @return A String which represents the ETag. */ public String getEtag() { @@ -66,7 +71,7 @@ public String getEtag() { /** * Gets the last modified time on the container. - * + * * @return A java.util.Date object which represents the last modified time. */ public Date getLastModified() { @@ -75,8 +80,8 @@ public Date getLastModified() { /** * Gets the lease status of the container. - * - * @return A {@link LeaseStatus} object which represents the lease status of the container. + * + * @return A {@link LeaseStatus} object which represents the lease status of the container. */ public LeaseStatus getLeaseStatus() { return this.leaseStatus; @@ -84,7 +89,7 @@ public LeaseStatus getLeaseStatus() { /** * Gets the lease state of the container. - * + * * @return A {@link LeaseState} object which represents the lease state of the container. */ public LeaseState getLeaseState() { @@ -93,7 +98,7 @@ public LeaseState getLeaseState() { /** * Gets the lease duration of the container. - * + * * @return A {@link LeaseDuration} object which represents the lease duration of the container. */ public LeaseDuration getLeaseDuration() { @@ -101,8 +106,21 @@ public LeaseDuration getLeaseDuration() { } /** - * Sets the ETag value on the container. + * Gets the public access level for the container. + * This field should only be set using the container's {@link #create(BlobContainerPublicAccessType, + * BlobRequestOptions, OperationContext) create} method or + * {@link #uploadPermissions(BlobContainerPermissions) uploadPermissions} method. * + * @return A {@link BlobContainerPublicAccessLevel} that specifies the level of public access + * that is allowed on the container. + */ + public BlobContainerPublicAccessType getPublicAccess() { + return this.publicAccess; + } + + /** + * Sets the ETag value on the container. + * * @param etag * A String which represents the ETag to set. */ @@ -112,7 +130,7 @@ protected void setEtag(final String etag) { /** * Sets the last modified time on the container. - * + * * @param lastModified * A java.util.Date object which represents the last modified time to set. */ @@ -122,7 +140,7 @@ protected void setLastModified(final Date lastModified) { /** * Sets the lease status on the container. - * + * * @param leaseStatus * A {@link LeaseStatus} object which represents the lease status of the container. */ @@ -132,7 +150,7 @@ protected void setLeaseStatus(final LeaseStatus leaseStatus) { /** * Sets the lease status on the container. - * + * * @param leaseState * A {@link LeaseState} object which represents the lease state of the container. */ @@ -142,11 +160,25 @@ protected void setLeaseState(final LeaseState leaseState) { /** * Sets the lease duration on the container. - * + * * @param leaseDuration * A {@link LeaseDuration} object which represents the lease duration of the container. */ protected void setLeaseDuration(final LeaseDuration leaseDuration) { this.leaseDuration = leaseDuration; } + + /** + * Sets the public access level on the container. + * This should only be set using the container's {@link #create(BlobContainerPublicAccessType, + * BlobRequestOptions, OperationContext) create} method or + * {@link #uploadPermissions(BlobContainerPermissions) uploadPermissions} method. + * @param publicAccess + * A {@link BlobContainerPublicAccessType} object + * which represents the public access level on the container. + */ + protected void setPublicAccess( + final BlobContainerPublicAccessType publicAccess) { + this.publicAccess = publicAccess; + } } diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobContainerPublicAccessType.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobContainerPublicAccessType.java index a0f5ef7862a3..7209e752aa2e 100644 --- a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobContainerPublicAccessType.java +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobContainerPublicAccessType.java @@ -1,11 +1,11 @@ /** * Copyright Microsoft Corporation - * + * * Licensed 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. @@ -14,6 +14,11 @@ */ package com.microsoft.azure.storage.blob; +import java.util.Locale; + +import com.microsoft.azure.storage.core.SR; +import com.microsoft.azure.storage.core.Utility; + /** * Specifies the level of public access that is allowed on the container. *

@@ -46,5 +51,35 @@ public enum BlobContainerPublicAccessType { /** * Specifies no public access. Only the account owner can access resources in this container. */ - OFF + OFF, + + /** + * Specifies that the public access type is unknown. + */ + UNKNOWN; + + /** + * Parses a public access level from the specified string. + * + * @param typeString + * A String which contains the public access level + * to parse. + * + * @return A BlobContainerPublicAccessType value that + * represents the public access level for the container. + */ + protected static BlobContainerPublicAccessType parse(final String typeString) { + if (Utility.isNullOrEmpty(typeString)) { + return OFF; + } + else if (SR.BLOB.equals(typeString.toLowerCase(Locale.US))) { + return BLOB; + } + else if (SR.CONTAINER.equals(typeString.toLowerCase(Locale.US))) { + return CONTAINER; + } + else { + return UNKNOWN; + } + } } diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobRequest.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobRequest.java index 88965861e9a8..ab56bd3c2d5f 100644 --- a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobRequest.java +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobRequest.java @@ -266,14 +266,22 @@ public static HttpURLConnection copyFrom(final URI uri, final BlobRequestOptions * An {@link OperationContext} object that represents the context for the current operation. This object * is used to track requests to the storage service, and to provide additional runtime information about * the operation. + * @param publicAccess + * The type of public access to allow for the container. * @return a HttpURLConnection configured for the operation. * @throws StorageException * @throws IllegalArgumentException */ public static HttpURLConnection createContainer(final URI uri, final BlobRequestOptions blobOptions, - final OperationContext opContext) throws IOException, URISyntaxException, StorageException { + final OperationContext opContext, final BlobContainerPublicAccessType publicAccess) throws IOException, URISyntaxException, StorageException { final UriQueryBuilder containerBuilder = getContainerUriQueryBuilder(); - return BaseRequest.create(uri, blobOptions, containerBuilder, opContext); + final HttpURLConnection request = BaseRequest.create(uri, blobOptions, containerBuilder, opContext); + + if (publicAccess != null && publicAccess != BlobContainerPublicAccessType.OFF) { + request.setRequestProperty(BlobConstants.BLOB_PUBLIC_ACCESS_HEADER, publicAccess.toString().toLowerCase()); + } + + return request; } /** diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobResponse.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobResponse.java index b3d1996e31d9..ed1d59388c68 100644 --- a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobResponse.java +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobResponse.java @@ -1,11 +1,11 @@ /** * Copyright Microsoft Corporation - * + * * Licensed 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. @@ -35,7 +35,7 @@ final class BlobResponse extends BaseResponse { /** * Gets the ACL for the container from the response. - * + * * @param request * the request object for this operation * @return the ACL value indicating the public access level for the container @@ -46,7 +46,7 @@ public static String getAcl(final HttpURLConnection request) { /** * Gets the BlobAttributes from the given request - * + * * @param request * The response from server. * @param resourceURI @@ -68,10 +68,18 @@ public static BlobAttributes getBlobAttributes(final HttpURLConnection request, properties.setContentDisposition(request.getHeaderField(Constants.HeaderConstants.CONTENT_DISPOSITION)); properties.setContentEncoding(request.getHeaderField(Constants.HeaderConstants.CONTENT_ENCODING)); properties.setContentLanguage(request.getHeaderField(Constants.HeaderConstants.CONTENT_LANGUAGE)); - properties.setContentMD5(request.getHeaderField(Constants.HeaderConstants.CONTENT_MD5)); + + // For range gets, only look at 'x-ms-blob-content-md5' for overall MD5 + if (!Utility.isNullOrEmpty(request.getHeaderField(Constants.HeaderConstants.CONTENT_RANGE))) { + properties.setContentMD5(request.getHeaderField(BlobConstants.BLOB_CONTENT_MD5_HEADER)); + } + else { + properties.setContentMD5(request.getHeaderField(Constants.HeaderConstants.CONTENT_MD5)); + } + properties.setContentType(request.getHeaderField(Constants.HeaderConstants.CONTENT_TYPE)); properties.setEtag(BaseResponse.getEtag(request)); - + properties.setServerEncrypted( Constants.TRUE.equals(request.getHeaderField(Constants.HeaderConstants.SERVER_ENCRYPTED))); @@ -102,13 +110,13 @@ else if (!Utility.isNullOrEmpty(xContentLengthHeader)) { properties.setLength(Long.parseLong(contentLength)); } } - + // Get sequence number final String sequenceNumber = request.getHeaderField(Constants.HeaderConstants.BLOB_SEQUENCE_NUMBER); if (!Utility.isNullOrEmpty(sequenceNumber)) { properties.setPageBlobSequenceNumber(Long.parseLong(sequenceNumber)); } - + // Get committed block count final String comittedBlockCount = request.getHeaderField(Constants.HeaderConstants.BLOB_COMMITTED_BLOCK_COUNT); if (!Utility.isNullOrEmpty(comittedBlockCount)) @@ -127,7 +135,7 @@ else if (!Utility.isNullOrEmpty(xContentLengthHeader)) { /** * Gets the BlobContainerAttributes from the given request. - * + * * @param request * the request to get attributes from. * @param usePathStyleUris @@ -158,12 +166,14 @@ public static BlobContainerAttributes getBlobContainerAttributes(final HttpURLCo containerProperties.setLeaseState(getLeaseState(request)); containerProperties.setLeaseDuration(getLeaseDuration(request)); + containerProperties.setPublicAccess(getPublicAccessLevel(request)); + return containerAttributes; } /** * Gets the copyState - * + * * @param request * The response from server. * @return The CopyState. @@ -174,7 +184,7 @@ public static CopyState getCopyState(final HttpURLConnection request) throws URI String copyStatusString = request.getHeaderField(Constants.HeaderConstants.COPY_STATUS); if (!Utility.isNullOrEmpty(copyStatusString)) { final CopyState copyState = new CopyState(); - + copyState.setStatus(CopyStatus.parse(copyStatusString)); copyState.setCopyId(request.getHeaderField(Constants.HeaderConstants.COPY_ID)); copyState.setStatusDescription(request.getHeaderField(Constants.HeaderConstants.COPY_STATUS_DESCRIPTION)); @@ -196,7 +206,7 @@ public static CopyState getCopyState(final HttpURLConnection request) throws URI if (!Utility.isNullOrEmpty(copyCompletionTimeString)) { copyState.setCompletionTime(Utility.parseRFC1123DateFromStringInGMT(copyCompletionTimeString)); } - + return copyState; } else { @@ -206,7 +216,7 @@ public static CopyState getCopyState(final HttpURLConnection request) throws URI /** * Gets the LeaseDuration - * + * * @param request * The response from server. * @return The LeaseDuration. @@ -222,7 +232,7 @@ public static LeaseDuration getLeaseDuration(final HttpURLConnection request) { /** * Gets the lease id from the request header. - * + * * @param request * The response from server. * @return the lease id from the request header. @@ -233,7 +243,7 @@ public static String getLeaseID(final HttpURLConnection request) { /** * Gets the LeaseState - * + * * @param request * The response from server. * @return The LeaseState. @@ -249,7 +259,7 @@ public static LeaseState getLeaseState(final HttpURLConnection request) { /** * Gets the LeaseStatus - * + * * @param request * The response from server. * @return The Etag. @@ -265,7 +275,7 @@ public static LeaseStatus getLeaseStatus(final HttpURLConnection request) { /** * Gets the lease Time from the request header. - * + * * @param request * The response from server. * @return the lease Time from the request header. @@ -276,7 +286,7 @@ public static String getLeaseTime(final HttpURLConnection request) { /** * Gets the snapshot ID from the request header. - * + * * @param request * The response from server. * @return the snapshot ID from the request header. @@ -284,4 +294,22 @@ public static String getLeaseTime(final HttpURLConnection request) { public static String getSnapshotTime(final HttpURLConnection request) { return request.getHeaderField(Constants.HeaderConstants.SNAPSHOT_ID_HEADER); } + + /** + * Gets the public access type for the container + * + * @param request + * The response from server. + * @return the blob container public access type from the request header. + */ + public static BlobContainerPublicAccessType getPublicAccessLevel( + final HttpURLConnection request) { + final String publicAccess = request + .getHeaderField(BlobConstants.BLOB_PUBLIC_ACCESS_HEADER); + if (!Utility.isNullOrEmpty(publicAccess)) { + return BlobContainerPublicAccessType.parse(publicAccess); + } + + return BlobContainerPublicAccessType.OFF; + } } \ No newline at end of file diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudBlob.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudBlob.java index 34a1bdd659ea..3e299659d5e5 100644 --- a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudBlob.java +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudBlob.java @@ -1351,19 +1351,9 @@ public Integer preProcessResponse(CloudBlob blob, CloudBlobClient client, Operat } if (!this.getArePropertiesPopulated()) { - String originalContentMD5 = null; - final BlobAttributes retrievedAttributes = BlobResponse.getBlobAttributes(this.getConnection(), blob.getStorageUri(), blob.snapshotID); - // Do not update Content-MD5 if it is a range get. - if (isRangeGet) { - originalContentMD5 = blob.properties.getContentMD5(); - } - else { - originalContentMD5 = retrievedAttributes.getProperties().getContentMD5(); - } - if (!options.getDisableContentMD5Validation() && options.getUseTransactionalContentMD5() && Utility.isNullOrEmpty(retrievedAttributes.getProperties().getContentMD5())) { throw new StorageException(StorageErrorCodeStrings.MISSING_MD5_HEADER, SR.MISSING_MD5, @@ -1372,8 +1362,11 @@ public Integer preProcessResponse(CloudBlob blob, CloudBlobClient client, Operat blob.properties = retrievedAttributes.getProperties(); blob.metadata = retrievedAttributes.getMetadata(); - this.setContentMD5(retrievedAttributes.getProperties().getContentMD5()); - blob.properties.setContentMD5(originalContentMD5); + + // Need to store the Content MD5 in case we fail part way through. + // We would still need to verify the entire range. + String contentMD5 = this.getConnection().getHeaderField(Constants.HeaderConstants.CONTENT_MD5); + this.setContentMD5(contentMD5); this.setLockedETag(blob.properties.getEtag()); this.setArePropertiesPopulated(true); } diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudBlobContainer.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudBlobContainer.java index 71b52668870b..ad2fcdbaebc3 100644 --- a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudBlobContainer.java +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudBlobContainer.java @@ -73,20 +73,7 @@ public final class CloudBlobContainer { * @return A {@link BlobContainerPermissions} object which represents the ACLs. */ static BlobContainerPermissions getContainerAcl(final String aclString) { - BlobContainerPublicAccessType accessType = BlobContainerPublicAccessType.OFF; - - if (!Utility.isNullOrEmpty(aclString)) { - final String lowerAclString = aclString.toLowerCase(); - if (SR.CONTAINER.equals(lowerAclString)) { - accessType = BlobContainerPublicAccessType.CONTAINER; - } - else if (SR.BLOB.equals(lowerAclString)) { - accessType = BlobContainerPublicAccessType.BLOB; - } - else { - throw new IllegalArgumentException(String.format(SR.INVALID_ACL_ACCESS_TYPE, aclString)); - } - } + BlobContainerPublicAccessType accessType = BlobContainerPublicAccessType.parse(aclString); final BlobContainerPermissions retVal = new BlobContainerPermissions(); retVal.setPublicAccess(accessType); @@ -217,12 +204,12 @@ protected CloudBlobContainer(final String containerName, final CloudBlobClient c */ @DoesServiceRequest public void create() throws StorageException { - this.create(null /* options */, null /* opContext */); + this.create(BlobContainerPublicAccessType.OFF, null /* options */, null /* opContext */); } /** * Creates the container using the specified options and operation context. - * + * * @param options * A {@link BlobRequestOptions} object that specifies any additional options for the request. Specifying * null will use the default request options from the associated service client ( @@ -237,6 +224,29 @@ public void create() throws StorageException { */ @DoesServiceRequest public void create(BlobRequestOptions options, OperationContext opContext) throws StorageException { + this.create(BlobContainerPublicAccessType.OFF, options, opContext); + } + + /** + * Creates the container using the specified options and operation context. + * + * @param accessType + * A {@link BlobContainerPublicAccessType} object that specifies whether data in the container may be + * accessed publicly and what level of access is to be allowed. + * @param options + * A {@link BlobRequestOptions} object that specifies any additional options for the request. Specifying + * null will use the default request options from the associated service client ( + * {@link CloudBlobClient}). + * @param opContext + * An {@link OperationContext} object that represents the context for the current operation. This object + * is used to track requests to the storage service, and to provide additional runtime information about + * the operation. + * + * @throws StorageException + * If a storage service error occurred. + */ + @DoesServiceRequest + public void create(BlobContainerPublicAccessType accessType, BlobRequestOptions options, OperationContext opContext) throws StorageException { if (opContext == null) { opContext = new OperationContext(); } @@ -244,19 +254,20 @@ public void create(BlobRequestOptions options, OperationContext opContext) throw opContext.initialize(); options = BlobRequestOptions.populateAndApplyDefaults(options, BlobType.UNSPECIFIED, this.blobServiceClient); - ExecutionEngine.executeWithRetry(this.blobServiceClient, this, createImpl(options), + ExecutionEngine.executeWithRetry( + this.blobServiceClient, this, createImpl(options, accessType), options.getRetryPolicyFactory(), opContext); - } - private StorageRequest createImpl(final BlobRequestOptions options) { + private StorageRequest createImpl( + final BlobRequestOptions options, final BlobContainerPublicAccessType accessType) { final StorageRequest putRequest = new StorageRequest( options, this.getStorageUri()) { @Override public HttpURLConnection buildRequest(CloudBlobClient client, CloudBlobContainer container, OperationContext context) throws Exception { final HttpURLConnection request = BlobRequest.createContainer( - container.getTransformedAddress().getUri(this.getCurrentLocation()), options, context); + container.getTransformedAddress().getUri(this.getCurrentLocation()), options, context, accessType); return request; } @@ -284,6 +295,13 @@ public Void preProcessResponse(CloudBlobContainer container, CloudBlobClient cli this.getConnection(), client.isUsePathStyleUris()); container.properties = attributes.getProperties(); container.name = attributes.getName(); + if (accessType != null) { + container.properties.setPublicAccess(accessType); + } + else { + container.properties.setPublicAccess(BlobContainerPublicAccessType.OFF); + } + return null; } }; @@ -301,12 +319,12 @@ public Void preProcessResponse(CloudBlobContainer container, CloudBlobClient cli */ @DoesServiceRequest public boolean createIfNotExists() throws StorageException { - return this.createIfNotExists(null /* options */, null /* opContext */); + return this.createIfNotExists(BlobContainerPublicAccessType.OFF, null /* options */, null /* opContext */); } /** * Creates the container if it does not exist, using the specified request options and operation context. - * + * * @param options * A {@link BlobRequestOptions} object that specifies any additional options for the request. * Specifying null will use the default request options from the associated service client @@ -323,6 +341,31 @@ public boolean createIfNotExists() throws StorageException { */ @DoesServiceRequest public boolean createIfNotExists(BlobRequestOptions options, OperationContext opContext) throws StorageException { + return this.createIfNotExists(BlobContainerPublicAccessType.OFF, options, opContext); + } + + /** + * Creates the container if it does not exist, using the specified request options and operation context. + * + * @param accessType + * A {@link BlobContainerPublicAccessType} object that specifies whether data in the container may be + * accessed publicly and what level of access is to be allowed. + * @param options + * A {@link BlobRequestOptions} object that specifies any additional options for the request. + * Specifying null will use the default request options from the associated service client + * ({@link CloudBlobClient}). + * @param opContext + * An {@link OperationContext} object that represents the context for the current operation. This object + * is used to track requests to the storage service, and to provide additional runtime information about + * the operation. + * + * @return true if the container did not already exist and was created; otherwise, false. + * + * @throws StorageException + * If a storage service error occurred. + */ + @DoesServiceRequest + public boolean createIfNotExists(BlobContainerPublicAccessType accessType, BlobRequestOptions options, OperationContext opContext) throws StorageException { options = BlobRequestOptions.populateAndApplyDefaults(options, BlobType.UNSPECIFIED, this.blobServiceClient); boolean exists = this.exists(true /* primaryOnly */, null /* accessCondition */, options, opContext); @@ -331,7 +374,7 @@ public boolean createIfNotExists(BlobRequestOptions options, OperationContext op } else { try { - this.create(options, opContext); + this.create(accessType, options, opContext); return true; } catch (StorageException e) { @@ -644,6 +687,7 @@ public BlobContainerPermissions preProcessResponse(CloudBlobContainer container, container.updatePropertiesFromResponse(this.getConnection()); final String aclString = BlobResponse.getAcl(this.getConnection()); final BlobContainerPermissions containerAcl = getContainerAcl(aclString); + container.properties.setPublicAccess(containerAcl.getPublicAccess()); return containerAcl; } @@ -747,7 +791,12 @@ public void signRequest(HttpURLConnection connection, CloudBlobClient client, Op public Boolean preProcessResponse(CloudBlobContainer container, CloudBlobClient client, OperationContext context) throws Exception { if (this.getResult().getStatusCode() == HttpURLConnection.HTTP_OK) { - container.updatePropertiesFromResponse(this.getConnection()); + // Set attributes + final BlobContainerAttributes attributes = BlobResponse.getBlobContainerAttributes( + this.getConnection(), client.isUsePathStyleUris()); + container.metadata = attributes.getMetadata(); + container.properties = attributes.getProperties(); + container.name = attributes.getName(); return Boolean.valueOf(true); } else if (this.getResult().getStatusCode() == HttpURLConnection.HTTP_NOT_FOUND) { @@ -1817,6 +1866,7 @@ public Void preProcessResponse(CloudBlobContainer container, CloudBlobClient cli } container.updatePropertiesFromResponse(this.getConnection()); + container.getProperties().setPublicAccess(permissions.getPublicAccess()); return null; } }; diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/ContainerListHandler.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/ContainerListHandler.java index 1638c51e426a..3adeefe21a8f 100644 --- a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/ContainerListHandler.java +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/ContainerListHandler.java @@ -1,11 +1,11 @@ /** * Copyright Microsoft Corporation - * + * * Licensed 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. @@ -53,7 +53,7 @@ private ContainerListHandler(CloudBlobClient serviceClient) { /** * Parses a {@link ContainerListResponse} form the given XML stream. - * + * * @param serviceClient * a reference to the client object associated with this object. * @param stream @@ -78,6 +78,7 @@ public void startElement(String uri, String localName, String qName, Attributes if (BlobConstants.CONTAINER_ELEMENT.equals(localName)) { this.containerName = Constants.EMPTY_STRING; this.attributes = new BlobContainerAttributes(); + this.attributes.getProperties().setPublicAccess(BlobContainerPublicAccessType.OFF); } } @@ -193,5 +194,14 @@ else if (currentNode.equals(Constants.LEASE_DURATION_ELEMENT)) { throw new SAXException(SR.INVALID_RESPONSE_RECEIVED); } } + else if (currentNode.equals(Constants.PUBLIC_ACCESS_ELEMENT)) { + final BlobContainerPublicAccessType tempAccessType = BlobContainerPublicAccessType.parse(value); + if (!tempAccessType.equals(BlobContainerPublicAccessType.OFF)) { + this.attributes.getProperties().setPublicAccess(tempAccessType); + } + else { + throw new SAXException(SR.INVALID_RESPONSE_RECEIVED); + } + } } } diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/file/CloudFile.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/file/CloudFile.java index f9844a7e880e..9ef7dba318ac 100644 --- a/microsoft-azure-storage/src/com/microsoft/azure/storage/file/CloudFile.java +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/file/CloudFile.java @@ -1298,7 +1298,6 @@ private final StorageRequest downloadToStre final FileRequestOptions options, OperationContext opContext) { final long startingOffset = fileOffset == null ? 0 : fileOffset; - final boolean isRangeGet = fileOffset != null; final StorageRequest getRequest = new StorageRequest( options, this.getStorageUri()) { @@ -1346,19 +1345,9 @@ public Integer preProcessResponse(CloudFile file, CloudFileClient client, Operat } if (!this.getArePropertiesPopulated()) { - String originalContentMD5 = null; - final FileAttributes retrievedAttributes = FileResponse.getFileAttributes(this.getConnection(), file.getStorageUri()); - // Do not update Content-MD5 if it is a range get. - if (isRangeGet) { - originalContentMD5 = file.properties.getContentMD5(); - } - else { - originalContentMD5 = retrievedAttributes.getProperties().getContentMD5(); - } - if (!options.getDisableContentMD5Validation() && options.getUseTransactionalContentMD5() && Utility.isNullOrEmpty(retrievedAttributes.getProperties().getContentMD5())) { throw new StorageException(StorageErrorCodeStrings.MISSING_MD5_HEADER, SR.MISSING_MD5, @@ -1367,8 +1356,11 @@ public Integer preProcessResponse(CloudFile file, CloudFileClient client, Operat file.properties = retrievedAttributes.getProperties(); file.metadata = retrievedAttributes.getMetadata(); - this.setContentMD5(retrievedAttributes.getProperties().getContentMD5()); - file.properties.setContentMD5(originalContentMD5); + + // Need to store the Content MD5 in case we fail part way through. + // We would still need to verify the entire range. + this.setContentMD5(this.getConnection().getHeaderField(Constants.HeaderConstants.CONTENT_MD5)); + this.setLockedETag(file.properties.getEtag()); this.setArePropertiesPopulated(true); } @@ -1944,6 +1936,7 @@ private FileOutputStream openOutputStreamInternal(Long length, AccessCondition a if (opContext == null) { opContext = new OperationContext(); } + options = FileRequestOptions.populateAndApplyDefaults(options, this.fileServiceClient, false /* setStartTime */); if (length != null) { diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/file/CloudFileDirectory.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/file/CloudFileDirectory.java index 9c10fe9950c0..a479446359aa 100644 --- a/microsoft-azure-storage/src/com/microsoft/azure/storage/file/CloudFileDirectory.java +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/file/CloudFileDirectory.java @@ -716,12 +716,12 @@ public Void preProcessResponse(CloudFileDirectory directory, CloudFileClient cli */ @DoesServiceRequest public Iterable listFilesAndDirectories() { - return this.listFilesAndDirectories(null /* options */, null /* opContext */); + return this.listFilesAndDirectories(null /* prefix */, null /* options */, null /* opContext */); } /** * Returns an enumerable collection of file and directory items for the directory. - * + * * @param options * A {@link FileRequestOptions} object that specifies any additional options for the request. Specifying * null will use the default request options from the associated service client ( @@ -741,6 +741,34 @@ public Iterable listFilesAndDirectories() { */ @DoesServiceRequest public Iterable listFilesAndDirectories(FileRequestOptions options, OperationContext opContext) { + return listFilesAndDirectories(null /* prefix */, options, opContext); + } + + /** + * Returns an enumerable collection of file and directory items for the directory. + * + * @param prefix + * A string containing the file or directory name prefix. + * @param options + * A {@link FileRequestOptions} object that specifies any additional options for the request. Specifying + * null will use the default request options from the associated service client ( + * {@link CloudFileClient}). + * @param opContext + * An {@link OperationContext} object that represents the context for the current operation. This object + * is used to track requests to the storage service, and to provide additional runtime information about + * the operation. + * + * @return An enumerable collection of {@link ListFileItem} objects that represent the file and directory items in + * this directory. + * + * @throws StorageException + * If a storage service error occurred. + * @throws URISyntaxException + * If the resource URI is invalid. + */ + @DoesServiceRequest + public Iterable listFilesAndDirectories( + String prefix, FileRequestOptions options, OperationContext opContext) { if (opContext == null) { opContext = new OperationContext(); } @@ -751,7 +779,8 @@ public Iterable listFilesAndDirectories(FileRequestOptions options SegmentedStorageRequest segmentedRequest = new SegmentedStorageRequest(); return new LazySegmentedIterable( - this.listFilesAndDirectoriesSegmentedImpl(null, options, segmentedRequest), this.fileServiceClient, this, + this.listFilesAndDirectoriesSegmentedImpl(prefix, null /* maxResults */, options, segmentedRequest), + this.fileServiceClient, this, options.getRetryPolicyFactory(), opContext); } @@ -764,14 +793,14 @@ public Iterable listFilesAndDirectories(FileRequestOptions options */ @DoesServiceRequest public ResultSegment listFilesAndDirectoriesSegmented() throws StorageException { - return this.listFilesAndDirectoriesSegmented( - null, null /* continuationToken */, null /* options */, null /* opContext */); + return this.listFilesAndDirectoriesSegmented(null /* prefix */, null /* maxResults */, + null /* continuationToken */, null /* options */, null /* opContext */); } /** * Returns a result segment of an enumerable collection of files and directories for this directory, using the * specified listing details options, request options, and operation context. - * + * * @param maxResults * The maximum number of results to retrieve. If null or greater * than 5000, the server will return up to 5,000 items. Must be at least 1. @@ -797,6 +826,40 @@ public ResultSegment listFilesAndDirectoriesSegmented() throws Sto public ResultSegment listFilesAndDirectoriesSegmented(final Integer maxResults, final ResultContinuation continuationToken, FileRequestOptions options, OperationContext opContext) throws StorageException { + return listFilesAndDirectoriesSegmented(null, maxResults, continuationToken, options, opContext); + } + + /** + * Returns a result segment of an enumerable collection of files and directories for this directory, using the + * specified listing details options, request options, and operation context. + * + * @param prefix + * A string containing the file or directory name prefix. + * @param maxResults + * The maximum number of results to retrieve. If null or greater + * than 5000, the server will return up to 5,000 items. Must be at least 1. + * @param continuationToken + * A {@link ResultContinuation} object that represents a continuation token + * returned by a previous listing operation. + * @param options + * A {@link FileRequestOptions} object that specifies any additional options for + * the request. Specifying null will use the default request options + * from the associated service client ( {@link CloudFileClient}). + * @param opContext + * An {@link OperationContext} object that represents the context for the current + * operation. This object is used to track requests to the storage service, + * and to provide additional runtime information about the operation. + * + * @return A {@link ResultSegment} object that contains a segment of the enumerable collection of + * {@link ListFileItem} objects that represent the files and directories in this directory. + * + * @throws StorageException + * If a storage service error occurred. + */ + @DoesServiceRequest + public ResultSegment listFilesAndDirectoriesSegmented(final String prefix, final Integer maxResults, + final ResultContinuation continuationToken, FileRequestOptions options, OperationContext opContext) + throws StorageException { if (opContext == null) { opContext = new OperationContext(); } @@ -810,16 +873,16 @@ public ResultSegment listFilesAndDirectoriesSegmented(final Intege segmentedRequest.setToken(continuationToken); return ExecutionEngine.executeWithRetry(this.fileServiceClient, this, - this.listFilesAndDirectoriesSegmentedImpl(maxResults, options, segmentedRequest), + this.listFilesAndDirectoriesSegmentedImpl(prefix, maxResults, options, segmentedRequest), options.getRetryPolicyFactory(), opContext); } private StorageRequest> listFilesAndDirectoriesSegmentedImpl( - final Integer maxResults, final FileRequestOptions options, final SegmentedStorageRequest segmentedRequest) { + final String prefix, final Integer maxResults, final FileRequestOptions options, final SegmentedStorageRequest segmentedRequest) { Utility.assertContinuationType(segmentedRequest.getToken(), ResultContinuationType.FILE); - final ListingContext listingContext = new ListingContext(null, maxResults); + final ListingContext listingContext = new ListingContext(prefix, maxResults); final StorageRequest> getRequest = new StorageRequest>( diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/file/FileRequest.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/file/FileRequest.java index 0559349e0015..c119ce899725 100644 --- a/microsoft-azure-storage/src/com/microsoft/azure/storage/file/FileRequest.java +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/file/FileRequest.java @@ -788,6 +788,10 @@ public static HttpURLConnection listFilesAndDirectories(final URI uri, final Fil if (listingContext.getMaxResults() != null && listingContext.getMaxResults() > 0) { builder.add(Constants.QueryConstants.MAX_RESULTS, listingContext.getMaxResults().toString()); } + + if (!Utility.isNullOrEmpty(listingContext.getPrefix())) { + builder.add(Constants.QueryConstants.PREFIX, listingContext.getPrefix().toString()); + } } final HttpURLConnection request = BaseRequest.createURLConnection(uri, fileOptions, builder, opContext); diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/file/FileResponse.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/file/FileResponse.java index 65ae30aecc91..40a1c5166444 100644 --- a/microsoft-azure-storage/src/com/microsoft/azure/storage/file/FileResponse.java +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/file/FileResponse.java @@ -1,11 +1,11 @@ /** * Copyright Microsoft Corporation - * + * * Licensed 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. @@ -34,7 +34,7 @@ final class FileResponse extends BaseResponse { /** * Gets the copyState - * + * * @param request * The response from server. * @return The CopyState. @@ -45,7 +45,7 @@ public static CopyState getCopyState(final HttpURLConnection request) throws URI String copyStatusString = request.getHeaderField(Constants.HeaderConstants.COPY_STATUS); if (!Utility.isNullOrEmpty(copyStatusString)) { final CopyState copyState = new CopyState(); - + copyState.setStatus(CopyStatus.parse(copyStatusString)); copyState.setCopyId(request.getHeaderField(Constants.HeaderConstants.COPY_ID)); copyState.setStatusDescription(request.getHeaderField(Constants.HeaderConstants.COPY_STATUS_DESCRIPTION)); @@ -67,17 +67,17 @@ public static CopyState getCopyState(final HttpURLConnection request) throws URI if (!Utility.isNullOrEmpty(copyCompletionTimeString)) { copyState.setCompletionTime(Utility.parseRFC1123DateFromStringInGMT(copyCompletionTimeString)); } - + return copyState; } else { return null; } } - + /** * Gets the FileShareAttributes from the given request. - * + * * @param request * the request to get attributes from * @param usePathStyleUris @@ -99,7 +99,7 @@ public static FileShareAttributes getFileShareAttributes(final HttpURLConnection /** * Gets the FileDirectoryAttributes from the given request. - * + * * @param request * the request to get attributes from. * @param usePathStyleUris @@ -131,15 +131,14 @@ public static FileDirectoryAttributes getFileDirectoryAttributes(final HttpURLCo /** * Gets the CloudFileAttributes from the given request - * + * * @param request * The response from server. * @param resourceURI * The file uri to set. - * * @return the CloudFileAttributes from the given request - * @throws ParseException - * @throws URISyntaxException + * @throws ParseException + * @throws URISyntaxException */ public static FileAttributes getFileAttributes(final HttpURLConnection request, final StorageUri resourceURI) throws URISyntaxException, ParseException { @@ -150,7 +149,15 @@ public static FileAttributes getFileAttributes(final HttpURLConnection request, properties.setContentDisposition(request.getHeaderField(Constants.HeaderConstants.CONTENT_DISPOSITION)); properties.setContentEncoding(request.getHeaderField(Constants.HeaderConstants.CONTENT_ENCODING)); properties.setContentLanguage(request.getHeaderField(Constants.HeaderConstants.CONTENT_LANGUAGE)); - properties.setContentMD5(request.getHeaderField(Constants.HeaderConstants.CONTENT_MD5)); + + // For range gets, only look at 'x-ms-content-md5' for overall MD5 + if (!Utility.isNullOrEmpty(request.getHeaderField(Constants.HeaderConstants.CONTENT_RANGE))) { + properties.setContentMD5(request.getHeaderField(FileConstants.FILE_CONTENT_MD5_HEADER)); + } + else { + properties.setContentMD5(request.getHeaderField(Constants.HeaderConstants.CONTENT_MD5)); + } + properties.setContentType(request.getHeaderField(Constants.HeaderConstants.CONTENT_TYPE)); properties.setEtag(BaseResponse.getEtag(request)); properties.setCopyState(FileResponse.getCopyState(request)); @@ -180,6 +187,7 @@ else if (!Utility.isNullOrEmpty(xContentLengthHeader)) { } fileAttributes.setStorageUri(resourceURI); + fileAttributes.setMetadata(BaseResponse.getMetadata(request)); return fileAttributes; @@ -187,7 +195,7 @@ else if (!Utility.isNullOrEmpty(xContentLengthHeader)) { /** * Parses out the share quota value from a java.net.HttpURLConnection. - * + * * @param request * the request to get attributes from * @return the share quota (in GB) or null if none is specified diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/queue/CloudQueue.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/queue/CloudQueue.java index e14a0eaf1bf7..114adae9c1cb 100644 --- a/microsoft-azure-storage/src/com/microsoft/azure/storage/queue/CloudQueue.java +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/queue/CloudQueue.java @@ -203,7 +203,9 @@ protected CloudQueue(final String queueName, final CloudQueueClient client) thro * * @param message * A {@link CloudQueueMessage} object that specifies the message to add. - * + * The message object is modified to include the message ID and pop receipt, + * and can be used in subsequent calls to updateMessage and deleteMessage. + * * @throws StorageException * If a storage service error occurred during the operation. */ @@ -217,6 +219,8 @@ public void addMessage(final CloudQueueMessage message) throws StorageException * * @param message * A {@link CloudQueueMessage} object that specifies the message to add. + * The message object is modified to include the message ID and pop receipt, + * and can be used in subsequent calls to updateMessage and deleteMessage. * * @param timeToLiveInSeconds * The maximum time to allow the message to be in the queue. A value of zero will set the time-to-live to @@ -236,7 +240,7 @@ public void addMessage(final CloudQueueMessage message) throws StorageException * An {@link OperationContext} object that represents the context for the current operation. This object * is used to track requests to the storage service, and to provide additional runtime information about * the operation. - * + * * @throws StorageException * If a storage service error occurred during the operation. */ @@ -263,8 +267,8 @@ public void addMessage(final CloudQueueMessage message, final int timeToLiveInSe options.assertPolicyIfRequired(); ExecutionEngine.executeWithRetry(this.queueServiceClient, this, - this.addMessageImpl(message, realTimeToLiveInSeconds, initialVisibilityDelayInSeconds, options), - options.getRetryPolicyFactory(), opContext); + this.addMessageImpl(message, realTimeToLiveInSeconds, initialVisibilityDelayInSeconds, options), + options.getRetryPolicyFactory(), opContext); } private StorageRequest addMessageImpl(final CloudQueueMessage message, @@ -275,8 +279,8 @@ private StorageRequest addMessageImpl(final try { final byte[] messageBytes = QueueMessageSerializer.generateMessageRequestBody(stringToSend); - final StorageRequest putRequest = new StorageRequest( - options, this.getStorageUri()) { + final StorageRequest putRequest = + new StorageRequest(options, this.getStorageUri()) { @Override public HttpURLConnection buildRequest(CloudQueueClient client, CloudQueue queue, @@ -295,13 +299,23 @@ public void signRequest(HttpURLConnection connection, CloudQueueClient client, O } @Override - public Void preProcessResponse(CloudQueue parentObject, CloudQueueClient client, + public Void preProcessResponse(CloudQueue queue, CloudQueueClient client, OperationContext context) throws Exception { if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_CREATED) { this.setNonExceptionedRetryableFailure(true); return null; } + // Parse the returned messages + CloudQueueMessage returnedMessage = QueueMessageHandler.readMessages( + this.getConnection().getInputStream(), queue.shouldEncodeMessage).get(0); + + message.setInsertionTime(returnedMessage.getInsertionTime()); + message.setExpirationTime(returnedMessage.getExpirationTime()); + message.setNextVisibleTime(returnedMessage.getNextVisibleTime()); + message.setMessageId(returnedMessage.getMessageId()); + message.setPopReceipt(returnedMessage.getPopReceipt()); + return null; } }; From c147bde538cc37a4da01cbdd352464b7de1925a2 Mon Sep 17 00:00:00 2001 From: Josh Friedman Date: Tue, 15 Nov 2016 13:41:29 -0800 Subject: [PATCH 05/11] Incremental Copy Support --- ChangeLog.txt | 1 + .../storage/blob/CloudBlobContainerTests.java | 119 ++++++++++++++--- .../storage/blob/CloudPageBlobTests.java | 118 ++++++++++++++--- .../microsoft/azure/storage/Constants.java | 20 +++ .../azure/storage/blob/BlobListHandler.java | 9 ++ .../azure/storage/blob/BlobProperties.java | 30 ++++- .../azure/storage/blob/BlobRequest.java | 22 +++- .../azure/storage/blob/BlobResponse.java | 12 ++ .../azure/storage/blob/CloudBlob.java | 8 +- .../azure/storage/blob/CloudPageBlob.java | 122 ++++++++++++++++++ .../azure/storage/blob/CopyState.java | 29 ++++- 11 files changed, 436 insertions(+), 54 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index ed5d80d62e58..dfab15114a26 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -4,6 +4,7 @@ * The public access setting on a blob container is now a container property returned from downloadProperties. * Add Message now modifies the PopReceipt, Id, NextVisibleTime, InsertionTime, and ExpirationTime properties of its CloudQueueMessage parameter. * Populate content MD5 for range gets on Blobs and Files. + * Added support in Page Blob for incremental copy. 2016.08.30 Version 4.4.0 * Fixed a bug in client-side encryption for tables that was preventing the Java client from decrypting entities encrypted with the .NET client, and vice versa. diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlobContainerTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlobContainerTests.java index 525435966b15..764e534ea8ef 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlobContainerTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlobContainerTests.java @@ -14,44 +14,53 @@ */ package com.microsoft.azure.storage.blob; +import static org.junit.Assert.*; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.URI; +import java.net.URISyntaxException; +import java.security.InvalidKeyException; +import java.util.Calendar; +import java.util.Date; +import java.util.EnumSet; +import java.util.GregorianCalendar; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Random; +import java.util.TimeZone; +import java.util.UUID; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.experimental.categories.Category; import com.microsoft.azure.storage.Constants; import com.microsoft.azure.storage.core.SR; +import com.microsoft.azure.storage.core.UriQueryBuilder; import com.microsoft.azure.storage.NameValidator; import com.microsoft.azure.storage.OperationContext; import com.microsoft.azure.storage.ResultContinuation; import com.microsoft.azure.storage.ResultSegment; import com.microsoft.azure.storage.SendingRequestEvent; +import com.microsoft.azure.storage.SharedAccessAccountPermissions; +import com.microsoft.azure.storage.SharedAccessAccountPolicy; +import com.microsoft.azure.storage.SharedAccessAccountResourceType; +import com.microsoft.azure.storage.SharedAccessAccountService; import com.microsoft.azure.storage.StorageCredentialsSharedAccessSignature; import com.microsoft.azure.storage.StorageErrorCodeStrings; import com.microsoft.azure.storage.StorageEvent; import com.microsoft.azure.storage.StorageException; +import com.microsoft.azure.storage.TestHelper; import com.microsoft.azure.storage.TestRunners.CloudTests; import com.microsoft.azure.storage.TestRunners.DevFabricTests; import com.microsoft.azure.storage.TestRunners.DevStoreTests; import com.microsoft.azure.storage.TestRunners.SlowTests; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.experimental.categories.Category; - -import java.io.IOException; -import java.net.HttpURLConnection; -import java.net.URISyntaxException; -import java.security.InvalidKeyException; -import java.util.Calendar; -import java.util.Date; -import java.util.EnumSet; -import java.util.GregorianCalendar; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.TimeZone; -import java.util.UUID; - -import static org.junit.Assert.*; - /** * Blob Container Tests */ @@ -753,6 +762,74 @@ public void testCloudBlobContainerSharedKey() throws StorageException, Interrupt testPermissions = this.container.downloadPermissions(); assertPermissionsEqual(expectedPermissions, testPermissions); } + + /** + * @throws StorageException + * @throws InterruptedException + * @throws URISyntaxException + * @throws IOException + * @throws InvalidKeyException + */ + @Test + @Category({ DevFabricTests.class, DevStoreTests.class }) + public void testListBlobsWithIncrementalCopiedBlob() throws StorageException, InterruptedException, URISyntaxException, IOException, InvalidKeyException { + this.container.create(); + + String blobName = BlobTestHelper.generateRandomBlobNameWithPrefix("testblob"); + CloudPageBlob source = this.container.getPageBlobReference(blobName); + source.create(1024); + + final Random randGenerator = new Random(); + final byte[] buffer = new byte[1024]; + randGenerator.nextBytes(buffer); + + source.upload(new ByteArrayInputStream(buffer), buffer.length); + CloudPageBlob snapshot = (CloudPageBlob) source.createSnapshot(); + + SharedAccessBlobPolicy policy = new SharedAccessBlobPolicy(); + policy.setPermissions( EnumSet.of(SharedAccessBlobPermissions.READ, SharedAccessBlobPermissions.WRITE)); + + Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("UTC")); + cal.setTime(new Date()); + cal.add(Calendar.SECOND, 5000); + policy.setSharedAccessExpiryTime(cal.getTime()); + + SharedAccessAccountPolicy accountPolicy = new SharedAccessAccountPolicy(); + accountPolicy.setPermissions(EnumSet.of(SharedAccessAccountPermissions.READ, SharedAccessAccountPermissions.WRITE)); + accountPolicy.setServices(EnumSet.of(SharedAccessAccountService.BLOB)); + accountPolicy.setResourceTypes(EnumSet.of(SharedAccessAccountResourceType.OBJECT, SharedAccessAccountResourceType.CONTAINER)); + accountPolicy.setSharedAccessExpiryTime(cal.getTime()); + final CloudBlobClient sasClient = TestHelper.createCloudBlobClient(accountPolicy, false); + + CloudPageBlob sasSnapshotBlob = (CloudPageBlob) sasClient.getContainerReference(container.getName()) + .getBlobReferenceFromServer(snapshot.getName(), snapshot.snapshotID, null, null, null); + sasSnapshotBlob.exists(); + CloudPageBlob copy = this.container.getPageBlobReference("copy"); + + final UriQueryBuilder builder = new UriQueryBuilder(); + builder.add(Constants.QueryConstants.SNAPSHOT, sasSnapshotBlob.snapshotID); + + copy.startIncrementalCopy(BlobTestHelper.defiddler(sasSnapshotBlob)); + + BlobTestHelper.waitForCopy(copy); + + boolean incrementalCopyFound = false; + for (ListBlobItem blobItem : this.container.listBlobs(null, true, EnumSet.allOf(BlobListingDetails.class), null, null)) { + CloudPageBlob blob = (CloudPageBlob) blobItem; + + if (blob.getName().equals("copy") && blob.isSnapshot()) { + // Check that the incremental copied blob is found exactly once + assertFalse(incrementalCopyFound); + assertTrue(blob.properties.isIncrementalCopy()); + incrementalCopyFound = true; + } + else if (blob.getName().equals("copy")) { + assertNotNull(blob.getCopyState().getCopyDestinationSnapshotID()); + } + } + + assertTrue(incrementalCopyFound); + } // Helper Method private static void assertPermissionsEqual(BlobContainerPermissions expected, BlobContainerPermissions actual) { diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudPageBlobTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudPageBlobTests.java index ea96069c03fd..1e81bf33eb30 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudPageBlobTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudPageBlobTests.java @@ -14,26 +14,8 @@ */ package com.microsoft.azure.storage.blob; -import com.microsoft.azure.storage.AccessCondition; -import com.microsoft.azure.storage.core.SR; -import com.microsoft.azure.storage.core.Utility; -import com.microsoft.azure.storage.OperationContext; -import com.microsoft.azure.storage.RetryNoRetry; -import com.microsoft.azure.storage.SendingRequestEvent; -import com.microsoft.azure.storage.StorageEvent; -import com.microsoft.azure.storage.StorageException; -import com.microsoft.azure.storage.TestRunners; -import com.microsoft.azure.storage.TestRunners.CloudTests; -import com.microsoft.azure.storage.TestRunners.DevFabricTests; -import com.microsoft.azure.storage.TestRunners.DevStoreTests; - import junit.framework.Assert; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.experimental.categories.Category; - import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; @@ -42,16 +24,46 @@ import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; +import java.net.URI; import java.net.URISyntaxException; +import java.security.InvalidKeyException; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.EnumSet; +import java.util.GregorianCalendar; import java.util.List; import java.util.Random; +import java.util.TimeZone; import static org.junit.Assert.*; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import com.microsoft.azure.storage.AccessCondition; +import com.microsoft.azure.storage.Constants; +import com.microsoft.azure.storage.OperationContext; +import com.microsoft.azure.storage.RetryNoRetry; +import com.microsoft.azure.storage.SendingRequestEvent; +import com.microsoft.azure.storage.SharedAccessAccountPermissions; +import com.microsoft.azure.storage.SharedAccessAccountPolicy; +import com.microsoft.azure.storage.SharedAccessAccountResourceType; +import com.microsoft.azure.storage.SharedAccessAccountService; +import com.microsoft.azure.storage.StorageCredentials; +import com.microsoft.azure.storage.StorageEvent; +import com.microsoft.azure.storage.StorageException; +import com.microsoft.azure.storage.TestHelper; +import com.microsoft.azure.storage.TestRunners; +import com.microsoft.azure.storage.TestRunners.CloudTests; +import com.microsoft.azure.storage.TestRunners.DevFabricTests; +import com.microsoft.azure.storage.TestRunners.DevStoreTests; +import com.microsoft.azure.storage.core.SR; +import com.microsoft.azure.storage.core.UriQueryBuilder; +import com.microsoft.azure.storage.core.Utility; + @Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) public class CloudPageBlobTests { protected CloudBlobContainer container; @@ -1093,4 +1105,74 @@ public void testOpenOutputStreamNoArgs() throws URISyntaxException, StorageExcep assertEquals(1024, pageBlob2.getProperties().getLength()); assertEquals(BlobType.PAGE_BLOB, pageBlob2.getProperties().getBlobType()); } + + @Test + public void testCopyPageBlobIncrementalSnapshot() throws URISyntaxException, StorageException, IOException, InvalidKeyException, InterruptedException { + for (int i = 0; i < 4; i++) { + testCopyPageBlobIncrementalSnapshotImpl(i); + } + } + + private void testCopyPageBlobIncrementalSnapshotImpl(int overload) throws URISyntaxException, StorageException, IOException, InvalidKeyException, InterruptedException { + String blobName = BlobTestHelper.generateRandomBlobNameWithPrefix("testblob"); + CloudPageBlob source = this.container.getPageBlobReference(blobName); + source.create(1024); + + final Random randGenerator = new Random(); + final byte[] buffer = new byte[1024]; + randGenerator.nextBytes(buffer); + + source.upload(new ByteArrayInputStream(buffer), buffer.length); + CloudPageBlob snapshot = (CloudPageBlob) source.createSnapshot(); + + SharedAccessBlobPolicy policy = new SharedAccessBlobPolicy(); + policy.setPermissions( EnumSet.of(SharedAccessBlobPermissions.READ, SharedAccessBlobPermissions.WRITE)); + + Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("UTC")); + cal.setTime(new Date()); + cal.add(Calendar.SECOND, 5000); + policy.setSharedAccessExpiryTime(cal.getTime()); + + SharedAccessAccountPolicy accountPolicy = new SharedAccessAccountPolicy(); + accountPolicy.setPermissions(EnumSet.of(SharedAccessAccountPermissions.READ, SharedAccessAccountPermissions.WRITE)); + accountPolicy.setServices(EnumSet.of(SharedAccessAccountService.BLOB)); + accountPolicy.setResourceTypes(EnumSet.of(SharedAccessAccountResourceType.OBJECT, SharedAccessAccountResourceType.CONTAINER)); + accountPolicy.setSharedAccessExpiryTime(cal.getTime()); + final CloudBlobClient sasClient = TestHelper.createCloudBlobClient(accountPolicy, false); + + CloudPageBlob sasSnapshotBlob = (CloudPageBlob) sasClient.getContainerReference(container.getName()) + .getBlobReferenceFromServer(snapshot.getName(), snapshot.snapshotID, null, null, null); + sasSnapshotBlob.exists(); + CloudPageBlob copy = this.container.getPageBlobReference(BlobTestHelper.generateRandomBlobNameWithPrefix("copy")); + + final UriQueryBuilder builder = new UriQueryBuilder(); + builder.add(Constants.QueryConstants.SNAPSHOT, sasSnapshotBlob.snapshotID); + URI sourceUri = TestHelper.defiddler(builder.addToURI(sasSnapshotBlob.getTransformedAddress(null).getPrimaryUri())); + + String copyId = null; + if (overload == 0) { + copyId = copy.startIncrementalCopy(BlobTestHelper.defiddler(sasSnapshotBlob)); + } + else if (overload == 1) { + copyId = copy.startIncrementalCopy(BlobTestHelper.defiddler(sasSnapshotBlob), null, null, null); + } + else if (overload == 2) { + copyId = copy.startIncrementalCopy(sourceUri); + } + else { + copyId = copy.startIncrementalCopy(sourceUri, null, null, null); + } + + BlobTestHelper.waitForCopy(copy); + + assertEquals(BlobType.PAGE_BLOB, copy.getProperties().getBlobType()); + assertEquals(CopyStatus.SUCCESS, copy.getCopyState().getStatus()); + assertEquals(sourceUri, copy.getCopyState().getSource()); + assertTrue(buffer.length == copy.getCopyState().getTotalBytes()); + assertTrue(buffer.length == copy.getCopyState().getBytesCopied()); + assertEquals(copyId, copy.getCopyState().getCopyId()); + assertTrue(copy.properties.isIncrementalCopy()); + assertNotNull(copy.properties.getCopyState().getCopyDestinationSnapshotID()); + assertNotNull(copy.getCopyState().getCompletionTime()); + } } diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/Constants.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/Constants.java index 4d2d08cf94b5..d22277fb6b2e 100644 --- a/microsoft-azure-storage/src/com/microsoft/azure/storage/Constants.java +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/Constants.java @@ -425,6 +425,16 @@ public static class HeaderConstants { */ public static final String COPY_STATUS_DESCRIPTION = PREFIX_FOR_STORAGE_HEADER + "copy-status-description"; + /** + * The header that specifies copy type. + */ + public static final String INCREMENTAL_COPY = PREFIX_FOR_STORAGE_HEADER + "incremental-copy"; + + /** + * The header that specifies the snapshot ID of the last successful incremental snapshot. + */ + public static final String COPY_DESTINATION_SNAPSHOT_ID = PREFIX_FOR_STORAGE_HEADER + "copy-destination-snapshot"; + /** * The header that specifies the date. */ @@ -909,6 +919,16 @@ public static class QueryConstants { */ public static final String COPY_STATUS_ELEMENT = "CopyStatus"; + /** + * XML element for the copy type. + */ + public static final String INCREMENTAL_COPY_ELEMENT = "IncrementalCopy"; + + /** + * XML element for the snapshot ID for the last successful incremental copy. + */ + public static final String COPY_DESTINATION_SNAPSHOT_ID_ELEMENT = "CopyDestinationSnapshot"; + /** * Default read timeout. 5 min * 60 seconds * 1000 ms */ diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobListHandler.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobListHandler.java index d0742aba44b3..7cb3f3ba67dd 100644 --- a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobListHandler.java +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobListHandler.java @@ -315,5 +315,14 @@ else if (Constants.COPY_STATUS_DESCRIPTION_ELEMENT.equals(currentNode)) { } this.copyState.setStatusDescription(value); } + else if (Constants.INCREMENTAL_COPY_ELEMENT.equals(currentNode)) { + this.properties.setIncrementalCopy(Constants.TRUE.equals(value)); + } + else if (Constants.COPY_DESTINATION_SNAPSHOT_ID_ELEMENT.equals(currentNode)) { + if (this.copyState == null) { + this.copyState = new CopyState(); + } + this.copyState.setCopyDestinationSnapshotID(value); + } } } \ No newline at end of file diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobProperties.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobProperties.java index 43691708d9b7..b5519acbbb7c 100644 --- a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobProperties.java +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobProperties.java @@ -111,6 +111,11 @@ public final class BlobProperties { * Represents the blob's server-side encryption status. */ private boolean serverEncrypted; + + /** + * Represents whether the blob is an incremental copy. + */ + private boolean isIncrementalCopy; /** * Creates an instance of the BlobProperties class. @@ -144,6 +149,7 @@ public BlobProperties(final BlobProperties other) { this.lastModified = other.lastModified; this.pageBlobSequenceNumber = other.pageBlobSequenceNumber; this.serverEncrypted = other.serverEncrypted; + this.isIncrementalCopy = other.isIncrementalCopy; } /** @@ -313,12 +319,21 @@ public Long getPageBlobSequenceNumber() { /** * Gets the blob's server-side encryption status; * - * @return The blob's server-side encryption status. + * @return A boolean which specifies the blob's encryption status. */ public boolean isServerEncrypted() { return serverEncrypted; } + /** + * Gets if the blob is an incremental copy + * + * @return A boolean which specifies if the blob is an incremental copy. + */ + public boolean isIncrementalCopy() { + return this.isIncrementalCopy; + } + /** * Sets the cache control value for the blob. * @@ -476,7 +491,7 @@ protected void setLength(final long length) { * A long containing the blob's current sequence number. */ protected void setPageBlobSequenceNumber(final Long pageBlobSequenceNumber) { - this.pageBlobSequenceNumber = pageBlobSequenceNumber; + this.pageBlobSequenceNumber = pageBlobSequenceNumber; } /** @@ -485,7 +500,16 @@ protected void setPageBlobSequenceNumber(final Long pageBlobSequenceNumber) { * @param serverEncrypted * A boolean which specifies the encryption status to set. */ - void setServerEncrypted(boolean serverEncrypted) { + protected void setServerEncrypted(boolean serverEncrypted) { this.serverEncrypted = serverEncrypted; } + + /** + * Sets whether the blob is an incremental copy. + * @param isIncrementalCopy + * A boolean which specifies if the blob is an incremental copy. + */ + protected void setIncrementalCopy(boolean isIncrementalCopy) { + this.isIncrementalCopy = isIncrementalCopy; + } } \ No newline at end of file diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobRequest.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobRequest.java index ab56bd3c2d5f..88bf7d3735db 100644 --- a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobRequest.java +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobRequest.java @@ -209,14 +209,16 @@ public static HttpURLConnection appendBlock(final URI uri, final BlobRequestOpti * An {@link OperationContext} object that represents the context for the current operation. This object * is used to track requests to the storage service, and to provide additional runtime information about * the operation. + * @param sourceAccessCondition + * An {@link AccessCondition} object that represents the access conditions for the source blob. + * @param destinationAccessCondition + * An {@link AccessCondition} object that represents the access conditions for the destination blob. * @param source * The canonical path to the source blob, in the form ///. * @param sourceSnapshotID * The snapshot version, if the source blob is a snapshot. - * @param sourceAccessConditionType - * A type of condition to check on the source blob. - * @param sourceAccessConditionValue - * The value of the condition to check on the source blob + * @param incrementalCopy + * A boolean indicating whether or not this is an incremental copy. * @return a HttpURLConnection configured for the operation. * @throws StorageException * an exception representing any error which occurred during the operation. @@ -226,7 +228,8 @@ public static HttpURLConnection appendBlock(final URI uri, final BlobRequestOpti */ public static HttpURLConnection copyFrom(final URI uri, final BlobRequestOptions blobOptions, final OperationContext opContext, final AccessCondition sourceAccessCondition, - final AccessCondition destinationAccessCondition, String source, final String sourceSnapshotID) + final AccessCondition destinationAccessCondition, String source, final String sourceSnapshotID, + final boolean incrementalCopy) throws StorageException, IOException, URISyntaxException { if (sourceSnapshotID != null) { @@ -234,7 +237,14 @@ public static HttpURLConnection copyFrom(final URI uri, final BlobRequestOptions source = source.concat(sourceSnapshotID); } - final HttpURLConnection request = BaseRequest.createURLConnection(uri, blobOptions, null, opContext); + UriQueryBuilder builder = null; + if (incrementalCopy) + { + builder = new UriQueryBuilder(); + builder.add(Constants.QueryConstants.COMPONENT, "incrementalcopy"); + } + + final HttpURLConnection request = BaseRequest.createURLConnection(uri, blobOptions, builder, opContext); request.setFixedLengthStreamingMode(0); request.setDoOutput(true); diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobResponse.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobResponse.java index ed1d59388c68..c31f05ab898a 100644 --- a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobResponse.java +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobResponse.java @@ -124,6 +124,12 @@ else if (!Utility.isNullOrEmpty(xContentLengthHeader)) { properties.setAppendBlobCommittedBlockCount(Integer.parseInt(comittedBlockCount)); } + final String incrementalCopyHeaderString = + request.getHeaderField(Constants.HeaderConstants.INCREMENTAL_COPY); + if (!Utility.isNullOrEmpty(incrementalCopyHeaderString)) { + properties.setIncrementalCopy(Constants.TRUE.equals(incrementalCopyHeaderString)); + } + attributes.setStorageUri(resourceURI); attributes.setSnapshotID(snapshotID); @@ -207,6 +213,12 @@ public static CopyState getCopyState(final HttpURLConnection request) throws URI copyState.setCompletionTime(Utility.parseRFC1123DateFromStringInGMT(copyCompletionTimeString)); } + final String copyDestinationSnapshotString = + request.getHeaderField(Constants.HeaderConstants.COPY_DESTINATION_SNAPSHOT_ID); + if (!Utility.isNullOrEmpty(copyDestinationSnapshotString)) { + copyState.setCopyDestinationSnapshotID(copyDestinationSnapshotString); + } + return copyState; } else { diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudBlob.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudBlob.java index 3e299659d5e5..83f880909eed 100644 --- a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudBlob.java +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudBlob.java @@ -691,12 +691,12 @@ public final String startCopy(final URI source, final AccessCondition sourceAcce options = BlobRequestOptions.populateAndApplyDefaults(options, this.properties.getBlobType(), this.blobServiceClient); return ExecutionEngine.executeWithRetry(this.blobServiceClient, this, - this.startCopyImpl(source, sourceAccessCondition, destinationAccessCondition, options), + this.startCopyImpl(source, false /* incrementalCopy */, sourceAccessCondition, destinationAccessCondition, options), options.getRetryPolicyFactory(), opContext); } - private StorageRequest startCopyImpl( - final URI source, final AccessCondition sourceAccessCondition, + protected StorageRequest startCopyImpl( + final URI source, final boolean incrementalCopy, final AccessCondition sourceAccessCondition, final AccessCondition destinationAccessCondition, final BlobRequestOptions options) { final StorageRequest putRequest = @@ -708,7 +708,7 @@ public HttpURLConnection buildRequest(CloudBlobClient client, CloudBlob blob, Op // toASCIIString() must be used in order to appropriately encode the URI return BlobRequest.copyFrom(blob.getTransformedAddress(context).getUri(this.getCurrentLocation()), options, context, sourceAccessCondition, destinationAccessCondition, source.toASCIIString(), - blob.snapshotID); + blob.snapshotID, incrementalCopy); } @Override diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudPageBlob.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudPageBlob.java index a2429aa1580d..3db79c1371f4 100644 --- a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudPageBlob.java +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudPageBlob.java @@ -39,6 +39,7 @@ import com.microsoft.azure.storage.core.RequestLocationMode; import com.microsoft.azure.storage.core.SR; import com.microsoft.azure.storage.core.StorageRequest; +import com.microsoft.azure.storage.core.UriQueryBuilder; import com.microsoft.azure.storage.core.Utility; /** @@ -220,6 +221,127 @@ public final String startCopy(final CloudPageBlob sourceBlob, final AccessCondit sourceBlob.getQualifiedUri(), sourceAccessCondition, destinationAccessCondition, options, opContext); } + /** + * Requests the service to start an incremental copy of another page blob's contents, properties, and metadata + * to this blob. + * + * @param sourceSnapshot + * A CloudPageBlob object that represents the source blob to copy. Must be a snapshot. + * + * @return A String which represents the copy ID associated with the copy operation. + * + * @throws StorageException + * If a storage service error occurred. + * @throws URISyntaxException + */ + @DoesServiceRequest + public final String startIncrementalCopy(final CloudPageBlob sourceSnapshot) throws StorageException, URISyntaxException { + final UriQueryBuilder builder = new UriQueryBuilder(); + builder.add(Constants.QueryConstants.SNAPSHOT, sourceSnapshot.snapshotID); + URI sourceUri = builder.addToURI(sourceSnapshot.getTransformedAddress(null).getPrimaryUri()); + + return this.startIncrementalCopy(sourceUri, null /* destinationAccessCondition */, + null /* options */, null /* opContext */); + } + + /** + * Requests the service to start an incremental copy of another page blob's contents, properties, and metadata + * to this blob. + * + * @param sourceSnapshot + * A CloudPageBlob object that represents the source blob to copy. Must be a snapshot. + * + * @return A String which represents the copy ID associated with the copy operation. + * + * @throws StorageException + * If a storage service error occurred. + * @throws URISyntaxException + */ + @DoesServiceRequest + public final String startIncrementalCopy(final URI sourceSnapshot) throws StorageException, URISyntaxException { + return this.startIncrementalCopy(sourceSnapshot, null /* destinationAccessCondition */, + null /* options */, null /* opContext */); + } + + /** + * Requests the service to start copying a blob's contents, properties, and metadata to a new blob, using the + * specified access conditions, lease ID, request options, and operation context. + * + * @param sourceSnapshot + * A CloudPageBlob object that represents the source blob to copy. Must be a snapshot. + * @param destinationAccessCondition + * An {@link AccessCondition} object that represents the access conditions for the destination blob. + * @param options + * A {@link BlobRequestOptions} object that specifies any additional options for the request. Specifying + * null will use the default request options from the associated service client ( + * {@link CloudBlobClient}). + * @param opContext + * An {@link OperationContext} object that represents the context for the current operation. This object + * is used to track requests to the storage service, and to provide additional runtime information about + * the operation. + * + * @return A String which represents the copy ID associated with the copy operation. + * + * @throws StorageException + * If a storage service error occurred. + * @throws URISyntaxException + * + */ + @DoesServiceRequest + public final String startIncrementalCopy(final CloudPageBlob sourceSnapshot, + final AccessCondition destinationAccessCondition, BlobRequestOptions options, OperationContext opContext) + throws StorageException, URISyntaxException { + final UriQueryBuilder builder = new UriQueryBuilder(); + builder.add(Constants.QueryConstants.SNAPSHOT, sourceSnapshot.snapshotID); + + URI sourceUri = builder.addToURI(sourceSnapshot.getTransformedAddress(null).getPrimaryUri()); + return this.startIncrementalCopy(sourceUri, destinationAccessCondition, options, opContext); + } + + /** + * Requests the service to start copying a blob's contents, properties, and metadata to a new blob, using the + * specified access conditions, lease ID, request options, and operation context. + * + * @param sourceSnapshot + * A CloudPageBlob object that represents the source blob to copy. Must be a snapshot. + * @param destinationAccessCondition + * An {@link AccessCondition} object that represents the access conditions for the destination blob. + * @param options + * A {@link BlobRequestOptions} object that specifies any additional options for the request. Specifying + * null will use the default request options from the associated service client ( + * {@link CloudBlobClient}). + * @param opContext + * An {@link OperationContext} object that represents the context for the current operation. This object + * is used to track requests to the storage service, and to provide additional runtime information about + * the operation. + * + * @return A String which represents the copy ID associated with the copy operation. + * + * @throws StorageException + * If a storage service error occurred. + * @throws URISyntaxException + * + */ + @DoesServiceRequest + public final String startIncrementalCopy(final URI sourceSnapshot, + final AccessCondition destinationAccessCondition, BlobRequestOptions options, OperationContext opContext) + throws StorageException, URISyntaxException { + Utility.assertNotNull("sourceSnapshot", sourceSnapshot); + this.assertNoWriteOperationForSnapshot(); + + if (opContext == null) { + opContext = new OperationContext(); + } + + opContext.initialize(); + options = BlobRequestOptions.populateAndApplyDefaults(options, this.properties.getBlobType(), this.blobServiceClient); + + return ExecutionEngine.executeWithRetry(this.blobServiceClient, this, + this.startCopyImpl(sourceSnapshot, true /* incrementalCopy */, null /* sourceAccesCondition */, + destinationAccessCondition, options), + options.getRetryPolicyFactory(), opContext); + } + /** * Clears pages from a page blob. *

diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CopyState.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CopyState.java index 99210e226068..624b2836ff56 100644 --- a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CopyState.java +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CopyState.java @@ -57,6 +57,11 @@ public final class CopyState { */ private String statusDescription; + /** + * Holds the snapshot ID of the last successful incremental copy snapshot. + */ + private String copyDestinationSnapshotID; + /** * Gets the ID of the copy operation. * @@ -105,7 +110,7 @@ public Long getBytesCopied() { /** * Gets the number of bytes total number of bytes to copy. * - * @return A long which represents the total number of bytes to copy/ + * @return A long which represents the total number of bytes to copy. */ public Long getTotalBytes() { return this.totalBytes; @@ -119,6 +124,15 @@ public Long getTotalBytes() { public String getStatusDescription() { return this.statusDescription; } + + /** + * Gets the snapshot ID of the last successful incremental copy snapshot. + * + * @return A String which represents the snapshot ID of the last successful incremental copy snapshot. + */ + public String getCopyDestinationSnapshotID() { + return this.copyDestinationSnapshotID; + } /** * Sets the ID of the copy operation. @@ -189,4 +203,15 @@ void setTotalBytes(final Long totalBytes) { */ void setStatusDescription(final String statusDescription) { this.statusDescription = statusDescription; - }} \ No newline at end of file + } + + /** + * Sets the snapshot ID of the last successful incremental copy snapshot. + * + * @param statusDescriptionID + * A String which specifies the snapshot ID of the last successful incremental copy snapshot. + */ + void setCopyDestinationSnapshotID(final String copyDestinationSnapshotID) { + this.copyDestinationSnapshotID = copyDestinationSnapshotID; + } +} \ No newline at end of file From f3918b4dedbac1d92b51df4306ede9d0a31c87f9 Mon Sep 17 00:00:00 2001 From: Josh Friedman Date: Tue, 15 Nov 2016 15:33:40 -0800 Subject: [PATCH 06/11] Throw if BlobContainerPublicAccessType is set to unknown on Create/Upload Permissions --- .../microsoft/azure/storage/blob/BlobRequest.java | 8 ++++++++ .../azure/storage/blob/CloudBlobContainer.java | 12 ++++++++++++ 2 files changed, 20 insertions(+) diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobRequest.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobRequest.java index 88bf7d3735db..904bfbd3ab89 100644 --- a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobRequest.java +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobRequest.java @@ -284,6 +284,10 @@ public static HttpURLConnection copyFrom(final URI uri, final BlobRequestOptions */ public static HttpURLConnection createContainer(final URI uri, final BlobRequestOptions blobOptions, final OperationContext opContext, final BlobContainerPublicAccessType publicAccess) throws IOException, URISyntaxException, StorageException { + if (publicAccess == BlobContainerPublicAccessType.UNKNOWN) { + throw new IllegalArgumentException(String.format(Utility.LOCALE_US, SR.ARGUMENT_OUT_OF_RANGE_ERROR, "accessType", publicAccess)); + } + final UriQueryBuilder containerBuilder = getContainerUriQueryBuilder(); final HttpURLConnection request = BaseRequest.create(uri, blobOptions, containerBuilder, opContext); @@ -1398,6 +1402,10 @@ public static HttpURLConnection resize(final URI uri, final BlobRequestOptions b public static HttpURLConnection setAcl(final URI uri, final BlobRequestOptions blobOptions, final OperationContext opContext, final AccessCondition accessCondition, final BlobContainerPublicAccessType publicAccess) throws IOException, URISyntaxException, StorageException { + if (publicAccess == BlobContainerPublicAccessType.UNKNOWN) { + throw new IllegalArgumentException(String.format(Utility.LOCALE_US, SR.ARGUMENT_OUT_OF_RANGE_ERROR, "accessType", publicAccess)); + } + final UriQueryBuilder builder = getContainerUriQueryBuilder(); builder.add(Constants.QueryConstants.COMPONENT, Constants.QueryConstants.ACL); diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudBlobContainer.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudBlobContainer.java index ad2fcdbaebc3..9687a9fa5210 100644 --- a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudBlobContainer.java +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudBlobContainer.java @@ -247,6 +247,10 @@ public void create(BlobRequestOptions options, OperationContext opContext) throw */ @DoesServiceRequest public void create(BlobContainerPublicAccessType accessType, BlobRequestOptions options, OperationContext opContext) throws StorageException { + if (accessType == BlobContainerPublicAccessType.UNKNOWN) { + throw new IllegalArgumentException(String.format(Utility.LOCALE_US, SR.ARGUMENT_OUT_OF_RANGE_ERROR, "accessType", accessType)); + } + if (opContext == null) { opContext = new OperationContext(); } @@ -366,6 +370,10 @@ public boolean createIfNotExists(BlobRequestOptions options, OperationContext op */ @DoesServiceRequest public boolean createIfNotExists(BlobContainerPublicAccessType accessType, BlobRequestOptions options, OperationContext opContext) throws StorageException { + if (accessType == BlobContainerPublicAccessType.UNKNOWN) { + throw new IllegalArgumentException(String.format(Utility.LOCALE_US, SR.ARGUMENT_OUT_OF_RANGE_ERROR, "accessType", accessType)); + } + options = BlobRequestOptions.populateAndApplyDefaults(options, BlobType.UNSPECIFIED, this.blobServiceClient); boolean exists = this.exists(true /* primaryOnly */, null /* accessCondition */, options, opContext); @@ -1820,6 +1828,10 @@ public void uploadPermissions(final BlobContainerPermissions permissions) throws @DoesServiceRequest public void uploadPermissions(final BlobContainerPermissions permissions, final AccessCondition accessCondition, BlobRequestOptions options, OperationContext opContext) throws StorageException { + if (permissions.getPublicAccess() == BlobContainerPublicAccessType.UNKNOWN) { + throw new IllegalArgumentException(String.format(Utility.LOCALE_US, SR.ARGUMENT_OUT_OF_RANGE_ERROR, "accessType", permissions.getPublicAccess())); + } + if (opContext == null) { opContext = new OperationContext(); } From 8e6e7d5407caa807f53f05c6240bd9206636287a Mon Sep 17 00:00:00 2001 From: Ram B Date: Fri, 18 Nov 2016 14:53:47 -0800 Subject: [PATCH 07/11] lbb upload --- ChangeLog.txt | 6 + .../storage/blob/CloudBlockBlobTests.java | 183 ++++++++-- .../microsoft/azure/storage/Constants.java | 53 ++- .../azure/storage/SubStreamGenerator.java | 59 +++ .../azure/storage/blob/CloudAppendBlob.java | 2 +- .../azure/storage/blob/CloudBlockBlob.java | 221 +++++++++--- .../azure/storage/blob/CloudPageBlob.java | 4 +- .../azure/storage/blob/SubStream.java | 336 ++++++++++++++++++ .../com/microsoft/azure/storage/core/SR.java | 3 + .../azure/storage/file/CloudFile.java | 2 +- 10 files changed, 794 insertions(+), 75 deletions(-) create mode 100644 microsoft-azure-storage/src/com/microsoft/azure/storage/SubStreamGenerator.java create mode 100644 microsoft-azure-storage/src/com/microsoft/azure/storage/blob/SubStream.java diff --git a/ChangeLog.txt b/ChangeLog.txt index dfab15114a26..7bbe45293f8b 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,3 +1,4 @@ +<<<<<<< HEAD 2016.XX.XX Version 5.0.0 * Prefix support for listing files and directories. * Added support for setting public access when creating a blob container @@ -8,6 +9,11 @@ 2016.08.30 Version 4.4.0 * Fixed a bug in client-side encryption for tables that was preventing the Java client from decrypting entities encrypted with the .NET client, and vice versa. +======= +2016.10.15 Version 4.5.0 +* Added large BlockBlob upload support. Blocks can now support sizes up to 100 MB. +* Added a new, memory-optimized upload strategy for the upload* APIs. This algorithm only applies for blocks greater than 4MB and when storeBlobContentMD5 and Client-Side Encryption are disabled. +>>>>>>> 9b002a7... lbb 2016.07.06 Version 4.3.0 * Added support for server-side encryption. diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlockBlobTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlockBlobTests.java index d1381adff442..5a9a04eedcf0 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlockBlobTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlockBlobTests.java @@ -73,6 +73,7 @@ import com.microsoft.azure.storage.SendingRequestEvent; import com.microsoft.azure.storage.StorageCredentialsAnonymous; import com.microsoft.azure.storage.StorageCredentialsSharedAccessSignature; +import com.microsoft.azure.storage.StorageErrorCodeStrings; import com.microsoft.azure.storage.StorageEvent; import com.microsoft.azure.storage.StorageException; import com.microsoft.azure.storage.TestRunners.CloudTests; @@ -751,7 +752,7 @@ public void testBlobSnapshotValidationTest() throws StorageException, URISyntaxE @Test @Category({ DevFabricTests.class, DevStoreTests.class }) public void testBlobDownloadRangeValidationTest() throws StorageException, URISyntaxException, IOException { - final int blockLength = 1024 * 1024; + final int blockLength = Constants.MB; final int length = 5 * blockLength; final String blockBlobName = BlobTestHelper.generateRandomBlobNameWithPrefix("testBlockBlob"); @@ -918,7 +919,7 @@ public void testBlobUploadFromStreamTest() throws URISyntaxException, StorageExc blockBlobRef.download(dstStream); BlobTestHelper.assertStreamsAreEqual(srcStream, new ByteArrayInputStream(dstStream.toByteArray())); - length = 5 * 1024 * 1024; + length = 5 * Constants.MB; srcStream = BlobTestHelper.getRandomDataStream(length); blockBlobRef.upload(srcStream, length); dstStream = new ByteArrayOutputStream(); @@ -939,7 +940,7 @@ public void testBlobUploadFromStreamAccessConditionTest() throws URISyntaxExcept blockBlobRef.download(dstStream); BlobTestHelper.assertStreamsAreEqual(srcStream, new ByteArrayInputStream(dstStream.toByteArray())); - length = 5 * 1024 * 1024; + length = 5 * Constants.MB; srcStream = BlobTestHelper.getRandomDataStream(length); blockBlobRef.upload(srcStream, length); dstStream = new ByteArrayOutputStream(); @@ -975,6 +976,109 @@ public void testBlobUploadFromStreamRequestOptionsTest() throws URISyntaxExcepti assertTrue(context.getRequestResults().size() <= 2); } + @Test + @Category({ DevFabricTests.class, DevStoreTests.class, SlowTests.class }) + public void testLargeBlobUploadFromStreamTest() throws URISyntaxException, StorageException, IOException { + final String blockBlobName = BlobTestHelper.generateRandomBlobNameWithPrefix("testBlockBlob"); + final CloudBlockBlob blockBlobRef = this.container.getBlockBlobReference(blockBlobName); + BlobRequestOptions options = new BlobRequestOptions(); + options.setStoreBlobContentMD5(false); + options.setEncryptionPolicy(null); + + int length = 30 * Constants.MB; + options.setSingleBlobPutThresholdInBytes(length/2); + + ByteArrayInputStream srcStream = BlobTestHelper.getRandomDataStream(length); + blockBlobRef.streamWriteSizeInBytes = 5 * Constants.MB; + options.setConcurrentRequestCount(1); + blockBlobRef.upload(srcStream, length ,null,options,null); + ByteArrayOutputStream dstStream = new ByteArrayOutputStream(); + blockBlobRef.download(dstStream); + BlobTestHelper.assertStreamsAreEqual(srcStream, new ByteArrayInputStream(dstStream.toByteArray())); + + srcStream = BlobTestHelper.getRandomDataStream(length); + options.setConcurrentRequestCount(3); + blockBlobRef.upload(srcStream, length ,null,options,null); + dstStream = new ByteArrayOutputStream(); + blockBlobRef.download(dstStream); + BlobTestHelper.assertStreamsAreEqual(srcStream, new ByteArrayInputStream(dstStream.toByteArray())); + + srcStream = BlobTestHelper.getRandomDataStream(length + 1); + blockBlobRef.streamWriteSizeInBytes = 5 * Constants.MB + 1; + options.setConcurrentRequestCount(1); + blockBlobRef.upload(srcStream, length + 1, null, options, null); + dstStream = new ByteArrayOutputStream(); + blockBlobRef.download(dstStream); + BlobTestHelper.assertStreamsAreEqual(srcStream, new ByteArrayInputStream(dstStream.toByteArray())); + + srcStream = BlobTestHelper.getRandomDataStream(length + 1); + options.setConcurrentRequestCount(5); + blockBlobRef.upload(srcStream, length + 1, null, options, null); + dstStream = new ByteArrayOutputStream(); + blockBlobRef.download(dstStream); + BlobTestHelper.assertStreamsAreEqual(srcStream, new ByteArrayInputStream(dstStream.toByteArray())); + } + + @Test + @Category({ DevFabricTests.class, DevStoreTests.class }) + public void testLargeBlobUploadFromStreamAccessConditionTest() throws URISyntaxException, StorageException, IOException { + final String blockBlobName = BlobTestHelper.generateRandomBlobNameWithPrefix("testBlockBlob"); + final CloudBlockBlob blockBlobRef = this.container.getBlockBlobReference(blockBlobName); + AccessCondition accessCondition = AccessCondition.generateIfNotModifiedSinceCondition(new Date()); + BlobRequestOptions options = new BlobRequestOptions(); + + int length = 30 * Constants.MB; + blockBlobRef.setStreamWriteSizeInBytes(7 * Constants.MB); + options.setConcurrentRequestCount(3); + options.setStoreBlobContentMD5(false); + options.setSingleBlobPutThresholdInBytes(length/2); + ByteArrayInputStream srcStream = BlobTestHelper.getRandomDataStream(length); + blockBlobRef.upload(srcStream, length, accessCondition, options, null); + ByteArrayOutputStream dstStream = new ByteArrayOutputStream(); + blockBlobRef.download(dstStream); + BlobTestHelper.assertStreamsAreEqual(srcStream, new ByteArrayInputStream(dstStream.toByteArray())); + + try + { + srcStream = BlobTestHelper.getRandomDataStream(length); + blockBlobRef.upload(srcStream, length, accessCondition, options, null); + } + catch (StorageException ex) + { + assertEquals(412, ex.getHttpStatusCode()); + assertEquals(StorageErrorCodeStrings.CONDITION_NOT_MET, ex.getErrorCode()); + } + } + + @Test + @Category({ DevFabricTests.class, DevStoreTests.class }) + public void testLargeBlobUploadFromStreamRequestOptionsTest() throws URISyntaxException, StorageException, IOException { + final String blockBlobName1 = BlobTestHelper.generateRandomBlobNameWithPrefix("testBlockBlob"); + final CloudBlockBlob blockBlobRef1 = this.container.getBlockBlobReference(blockBlobName1); + + final String blockBlobName2 = BlobTestHelper.generateRandomBlobNameWithPrefix("testBlockBlob"); + final CloudBlockBlob blockBlobRef2 = this.container.getBlockBlobReference(blockBlobName2); + + final int length = 24 * Constants.MB; + ByteArrayInputStream srcStream = BlobTestHelper.getRandomDataStream(length); + + BlobRequestOptions options = new BlobRequestOptions(); + options.setSingleBlobPutThresholdInBytes(length / 2); + options.setRetryPolicyFactory(RetryNoRetry.getInstance()); + options.setConcurrentRequestCount(3); + options.setStoreBlobContentMD5(false); + OperationContext context = new OperationContext(); + blockBlobRef1.setStreamWriteSizeInBytes(4 * Constants.MB + 1 ); + blockBlobRef1.upload(srcStream, length, null /* accessCondition */, options, context); + assertTrue(context.getRequestResults().size() >= 7); + + srcStream.reset(); + context = new OperationContext(); + blockBlobRef2.setStreamWriteSizeInBytes(8 * Constants.MB); + blockBlobRef2.upload(srcStream, length, null /* accessCondition */, options, context); + assertTrue(context.getRequestResults().size() >= 4); + } + @Test @Category({ DevFabricTests.class, DevStoreTests.class }) public void testUploadDownloadBlobProperties() throws URISyntaxException, StorageException, IOException { @@ -1094,7 +1198,7 @@ public void eventOccurred(SendingRequestEvent eventArg) { } }; - length = 33 * 1024 * 1024; + length = 33 * Constants.MB; srcStream = BlobTestHelper.getRandomDataStream(length); sendingRequestEventContext.getSendingRequestEventHandler().addListener(event); @@ -1135,8 +1239,8 @@ public void testCloudBlockBlobDownloadToByteArray() throws URISyntaxException, S BlobTestHelper.doDownloadTest(blob, 1 * 512, 2 * 512, 0); BlobTestHelper.doDownloadTest(blob, 1 * 512, 2 * 512, 1 * 512); BlobTestHelper.doDownloadTest(blob, 2 * 512, 4 * 512, 1 * 512); - BlobTestHelper.doDownloadTest(blob, 5 * 1024 * 1024, 5 * 1024 * 1024, 0); - BlobTestHelper.doDownloadTest(blob, 5 * 1024 * 1024, 6 * 1024 * 1024, 512); + BlobTestHelper.doDownloadTest(blob, 5 * Constants.MB, 5 * Constants.MB, 0); + BlobTestHelper.doDownloadTest(blob, 5 * Constants.MB, 6 * Constants.MB, 512); } @Test @@ -1145,12 +1249,12 @@ public void testCloudBlockBlobDownloadRangeToByteArray() throws URISyntaxExcepti CloudBlockBlob blob = this.container.getBlockBlobReference(BlobTestHelper .generateRandomBlobNameWithPrefix("downloadrange")); - BlobTestHelper.doDownloadRangeToByteArrayTest(blob, 8 * 1024 * 1024, 8 * 1024 * 1024, 1 * 1024 * 1024, - new Long(1 * 1024 * 1024), new Long(5 * 1024 * 1024)); - BlobTestHelper.doDownloadRangeToByteArrayTest(blob, 8 * 1024 * 1024, 8 * 1024 * 1024, 2 * 1024 * 1024, - new Long(2 * 1024 * 1024), new Long(6 * 1024 * 1024)); - BlobTestHelper.doDownloadRangeToByteArrayTest(blob, 8 * 1024 * 1024, 8 * 1024 * 1024, 1 * 1024 * 1024, - new Long(4 * 1024 * 1024), new Long(4 * 1024 * 1024)); + BlobTestHelper.doDownloadRangeToByteArrayTest(blob, 8 * Constants.MB, 8 * Constants.MB, 1 * Constants.MB, + new Long(1 * Constants.MB), new Long(5 * Constants.MB)); + BlobTestHelper.doDownloadRangeToByteArrayTest(blob, 8 * Constants.MB, 8 * Constants.MB, 2 * Constants.MB, + new Long(2 * Constants.MB), new Long(6 * Constants.MB)); + BlobTestHelper.doDownloadRangeToByteArrayTest(blob, 8 * Constants.MB, 8 * Constants.MB, 1 * Constants.MB, + new Long(4 * Constants.MB), new Long(4 * Constants.MB)); BlobTestHelper.doDownloadRangeToByteArrayTest(blob, 2 * 512, 4 * 512, 0, new Long(1 * 512), new Long(1 * 512)); BlobTestHelper.doDownloadRangeToByteArrayTest(blob, 2 * 512, 4 * 512, 1 * 512, new Long(0), null); @@ -1185,7 +1289,7 @@ public void testCloudBlockBlobUploadFromStreamWithAccessCondition() throws URISy CloudBlockBlob blob1 = this.container.getBlockBlobReference("blob1"); AccessCondition accessCondition = AccessCondition.generateIfNoneMatchCondition("\"*\""); - final int length = 2 * 1024 * 1024; + final int length = 2 * Constants.MB; ByteArrayInputStream srcStream = BlobTestHelper.getRandomDataStream(length); blob1.upload(srcStream, length, accessCondition, null, null); @@ -1363,36 +1467,63 @@ public void testUploadDownloadFromFile() throws IOException, StorageException, U String blobName = BlobTestHelper.generateRandomBlobNameWithPrefix("testblob"); final CloudBlockBlob blob = this.container.getBlockBlobReference(blobName); - //this.doUploadDownloadFileTest(blob, 0); - //this.doUploadDownloadFileTest(blob, 4096); - //this.doUploadDownloadFileTest(blob, 4097); - this.doUploadDownloadFileTest(blob, 5 * 1024 * 1024); - //this.doUploadDownloadFileTest(blob, 11 * 1024 * 1024); + this.doUploadDownloadFileTest(blob, 0); + this.doUploadDownloadFileTest(blob, 4096); + this.doUploadDownloadFileTest(blob, 4097); + } + + @Test + @Category({ DevFabricTests.class, DevStoreTests.class, SlowTests.class }) + public void testLargeUploadDownloadFromFile() throws IOException, StorageException, URISyntaxException { + String blobName = BlobTestHelper.generateRandomBlobNameWithPrefix("testblob"); + final CloudBlockBlob blob = this.container.getBlockBlobReference(blobName); + byte[] buffer = BlobTestHelper.getRandomBuffer(30 * Constants.MB); + this.doUploadDownloadFileTest(blob, buffer, 5 * Constants.MB, 1, false, false); + this.doUploadDownloadFileTest(blob, buffer, 5 * Constants.MB, 5, false, false); + this.doUploadDownloadFileTest(blob, buffer, 7 * Constants.MB, 1, false, false); + this.doUploadDownloadFileTest(blob, buffer, 7 * Constants.MB, 4, false, false); + this.doUploadDownloadFileTest(blob, buffer, 20 * Constants.MB + 1, 1, false, false); + this.doUploadDownloadFileTest(blob, buffer, 20 * Constants.MB + 1, 2, false, false); } private void doUploadDownloadFileTest(CloudBlockBlob blob, int fileSize) throws IOException, StorageException { + + this.doUploadDownloadFileTest(blob, BlobTestHelper.getRandomBuffer(fileSize), blob.getStreamWriteSizeInBytes(), 1, true, true); + } + + private void doUploadDownloadFileTest(CloudBlockBlob blob, byte[] fileBuffer, int blockSize, int parallelThreads, boolean useSingleBlobThreshold, boolean storeBlobContentMD5 ) throws IOException, StorageException { File sourceFile = File.createTempFile("sourceFile", ".tmp"); File destinationFile = new File(sourceFile.getParentFile(), "destinationFile.tmp"); try { - - byte[] buffer = BlobTestHelper.getRandomBuffer(fileSize); FileOutputStream fos = new FileOutputStream(sourceFile); - fos.write(buffer); + fos.write(fileBuffer); fos.close(); - blob.uploadFromFile(sourceFile.getAbsolutePath()); + BlobRequestOptions options = new BlobRequestOptions(); + options.setConcurrentRequestCount(parallelThreads); + options.setStoreBlobContentMD5(storeBlobContentMD5); + if (!useSingleBlobThreshold) + { + options.setSingleBlobPutThresholdInBytes(fileBuffer.length/2); + } + + blob.setStreamWriteSizeInBytes( blockSize); + blob.uploadFromFile(sourceFile.getAbsolutePath(), null, options, null); + + assertTrue("Destination file exists.", !destinationFile.exists()); blob.downloadToFile(destinationFile.getAbsolutePath()); assertTrue("Destination file does not exist.", destinationFile.exists()); - assertEquals("Destination file does not match input file.", fileSize, destinationFile.length()); + assertEquals("Destination file length does not match input file.", fileBuffer.length, destinationFile.length()); + FileInputStream fis = new FileInputStream(destinationFile); - byte[] readBuffer = new byte[fileSize]; + byte[] readBuffer = new byte[fileBuffer.length]; fis.read(readBuffer); fis.close(); - for (int i = 0; i < fileSize; i++) { - assertEquals("File contents do not match.", buffer[i], readBuffer[i]); + for (int i = 0; i < fileBuffer.length; i++) { + assertEquals("File contents do not match.", fileBuffer[i], readBuffer[i]); } } finally { diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/Constants.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/Constants.java index d22277fb6b2e..82bb160ed7a5 100644 --- a/microsoft-azure-storage/src/com/microsoft/azure/storage/Constants.java +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/Constants.java @@ -1110,14 +1110,59 @@ public static class QueryConstants { public static final String MARKER_ELEMENT = "Marker"; /** - * The maximum size of a single block. + * The maximum size of a BlockBlob block. */ - public static int MAX_BLOCK_SIZE = 4 * MB; + public static int MAX_BLOCK_SIZE = 100 * MB; + + /** + * The maximum size of an AppendBlob block. + */ + public static int MAX_APPEND_BLOCK_SIZE = 4 * MB; + + /** + * The maximum write size that can uploaded to a PageBlob at once. + */ + public static int MAX_PAGE_WRITE_SIZE = 4 * MB; + + /** + * The maximum write size for Files + */ + public static int MAX_FILE_WRITE_SIZE = 4 * MB; + + /** + * The minimum suggested write size for Files. + */ + public static int MIN_PERMITTED_FILE_WRITE_SIZE = 512; + + /** + * The maximum number of blocks. + */ + public static final long MAX_BLOCK_NUMBER = 50000; + + /** + * The maximum size of a Block Blob. + */ + public static final long MAX_BLOB_SIZE = Constants.MAX_BLOCK_NUMBER * Constants.MAX_BLOCK_SIZE; + + /** + * The minimum suggested size of a block. + */ + public static final int MIN_PERMITTED_BLOCK_SIZE = 16 * Constants.KB; + + /** + * The minimum size of a block for the large block upload strategy to be employed. + */ + public static int MIN_LARGE_BLOCK_SIZE = (4 * Constants.MB) + 1; + + /** + * The default read buffer size used by the SubStream class. + */ + public static final int SUBSTREAM_BUFFER_SIZE = 4 * Constants.MB; /** * The default write size, in bytes, used by {@link BlobOutputStream} or {@link FileOutputStream}. */ - public static final int DEFAULT_STREAM_WRITE_IN_BYTES = Constants.MAX_BLOCK_SIZE; + public static final int DEFAULT_STREAM_WRITE_IN_BYTES = 4 * Constants.MB; /** * The default minimum read size, in bytes, for a {@link BlobInputStream} or {@link FileInputStream}. @@ -1128,7 +1173,7 @@ public static class QueryConstants { * The maximum size, in bytes, of a given stream mark operation. */ // Note if BlobConstants.MAX_SINGLE_UPLOAD_BLOB_SIZE_IN_BYTES is updated then this needs to be as well. - public static final int MAX_MARK_LENGTH = 64 * MB; + public static final int MAX_MARK_LENGTH = 256 * MB; /** * XML element for maximum results. diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/SubStreamGenerator.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/SubStreamGenerator.java new file mode 100644 index 000000000000..2fb314c7c437 --- /dev/null +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/SubStreamGenerator.java @@ -0,0 +1,59 @@ +package com.microsoft.azure.storage; + +import com.microsoft.azure.storage.blob.SubStream; + +import java.io.InputStream; +import java.util.Iterator; + +public final class SubStreamGenerator implements Iterable { + + private final Object mutex = new Object(); + private final long blockSize; + private final InputStream wrappedStream; + private int currentBlock = 0; + private long lastBlockSize; + private int blocksPending; + + public SubStreamGenerator(InputStream wrappedStream, int totalBlocks, long blockSize) { + this.wrappedStream = wrappedStream; + this.blocksPending = totalBlocks; + this.blockSize = blockSize; + this.lastBlockSize = blockSize; + } + + public void setLastBlockSize(long blockSize) { + this.lastBlockSize = blockSize; + } + + @Override + public Iterator iterator() { + return new SubStreamIterator(); + } + + private class SubStreamIterator implements Iterator { + + @Override + public boolean hasNext() { + return blocksPending > 0; + } + + @Override + public SubStream next() { + blocksPending--; + return new SubStream( + wrappedStream, + currentBlock++ * blockSize, + blocksPending > 0 ? blockSize : lastBlockSize, + mutex); + } + + @Override + public void remove() { + // No-op + } + } +} + + + + diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudAppendBlob.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudAppendBlob.java index b39e1ac51ea9..7987dff78a23 100644 --- a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudAppendBlob.java +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudAppendBlob.java @@ -1008,7 +1008,7 @@ public void upload(final InputStream sourceStream, final long length, final Acce */ @Override public void setStreamWriteSizeInBytes(final int streamWriteSizeInBytes) { - if (streamWriteSizeInBytes > Constants.MAX_BLOCK_SIZE || streamWriteSizeInBytes < 16 * Constants.KB) { + if (streamWriteSizeInBytes > Constants.MAX_APPEND_BLOCK_SIZE || streamWriteSizeInBytes < 16 * Constants.KB) { throw new IllegalArgumentException("StreamWriteSizeInBytes"); } diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudBlockBlob.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudBlockBlob.java index 5d4b98a06c94..f8cd07e92d6f 100644 --- a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudBlockBlob.java +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudBlockBlob.java @@ -14,6 +14,12 @@ */ package com.microsoft.azure.storage.blob; +import com.microsoft.azure.storage.*; +import com.microsoft.azure.storage.core.*; +import com.microsoft.azure.storage.file.CloudFile; + +import javax.crypto.Cipher; +import javax.xml.stream.XMLStreamException; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -22,32 +28,19 @@ import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; - -import javax.crypto.Cipher; -import javax.xml.stream.XMLStreamException; - -import com.microsoft.azure.storage.AccessCondition; -import com.microsoft.azure.storage.Constants; -import com.microsoft.azure.storage.DoesServiceRequest; -import com.microsoft.azure.storage.OperationContext; -import com.microsoft.azure.storage.StorageCredentials; -import com.microsoft.azure.storage.StorageErrorCodeStrings; -import com.microsoft.azure.storage.StorageException; -import com.microsoft.azure.storage.StorageUri; -import com.microsoft.azure.storage.core.Base64; -import com.microsoft.azure.storage.core.ExecutionEngine; -import com.microsoft.azure.storage.core.RequestLocationMode; -import com.microsoft.azure.storage.core.SR; -import com.microsoft.azure.storage.core.StorageRequest; -import com.microsoft.azure.storage.core.StreamMd5AndLength; -import com.microsoft.azure.storage.core.Utility; -import com.microsoft.azure.storage.file.CloudFile; +import java.util.List; +import java.util.concurrent.*; /** * Represents a blob that is uploaded as a set of blocks. */ public final class CloudBlockBlob extends CloudBlob { + /** + * Flag that indicates if the default streamWriteSize has been modified. + */ + private boolean isStreamWriteSizeModified = false; + /** * Creates an instance of the CloudBlockBlob class using the specified absolute URI. * @@ -660,10 +653,11 @@ public void upload(final InputStream sourceStream, final long length, final Acce // data is under the threshold. // Note this will abort at // options.getSingleBlobPutThresholdInBytes() bytes and return -1. - if (!skipPutBlob && options.getEncryptionPolicy() != null) - { + if (!skipPutBlob && options.getEncryptionPolicy() != null) { class GettableByteArrayOutputStream extends ByteArrayOutputStream { - public byte[] getByteArray() { return this.buf; } + public byte[] getByteArray() { + return this.buf; + } } Cipher cipher = options.getEncryptionPolicy().createAndSetEncryptionContext(this.getMetadata(), false /* noPadding */); @@ -676,8 +670,7 @@ class GettableByteArrayOutputStream extends ByteArrayOutputStream { inputDataStream = new ByteArrayInputStream(targetStream.getByteArray()); descriptor.setLength(byteCount); } - else - { + else { // If the encrypted data is over the threshold, skip PutBlob. skipPutBlob = true; } @@ -713,12 +706,130 @@ class GettableByteArrayOutputStream extends ByteArrayOutputStream { this.uploadFullBlob(inputDataStream, descriptor.getLength(), accessCondition, options, opContext); } else { - final BlobOutputStream writeStream = this.openOutputStream(accessCondition, options, opContext); - try { - writeStream.write(inputDataStream, length); + int totalBlocks = (int) Math.ceil((double) length / (double) this.streamWriteSizeInBytes); + + // Check if the upload will fail because the total blocks exceeded the maximum allowable limit. + if (length != -1 && totalBlocks > Constants.MAX_BLOCK_NUMBER) { + if (this.isStreamWriteSizeModified()) { + // User has set the block write size explicitly and will need to adjust it manually. + throw new IOException(SR.BLOB_OVER_MAX_BLOCK_LIMIT); + } + else { + // Scale so the upload succeeds (only if the block write size was not modified). + this.streamWriteSizeInBytes = (int) Math.ceil((double) length / (double) Constants.MAX_BLOCK_NUMBER); + totalBlocks = (int) Math.ceil((double) length / (double) this.streamWriteSizeInBytes); + } + } + + boolean useOpenWrite = options.getEncryptionPolicy() != null + || !inputDataStream.markSupported() + || this.streamWriteSizeInBytes < Constants.MIN_LARGE_BLOCK_SIZE + || options.getStoreBlobContentMD5() + || descriptor.getLength() == -1; + + if (useOpenWrite) { + final BlobOutputStream writeStream = this.openOutputStream(accessCondition, options, opContext); + try { + writeStream.write(inputDataStream, length); + } + finally { + writeStream.close(); + } + } + else { + int blocksAllowedPerBatch = Integer.MAX_VALUE / this.streamWriteSizeInBytes; + List blockList = new ArrayList(); + + while (totalBlocks > 0) { + sourceStream.mark(Integer.MAX_VALUE); + int blocksInBatch = Math.min(totalBlocks, blocksAllowedPerBatch); + SubStreamGenerator subStreamGenerator = new SubStreamGenerator(sourceStream, blocksInBatch, this.streamWriteSizeInBytes); + if (totalBlocks == blocksInBatch && (length % this.streamWriteSizeInBytes != 0)) { + subStreamGenerator.setLastBlockSize(length % this.streamWriteSizeInBytes); + } + + totalBlocks -= blocksInBatch; + this.uploadFromMultiStream(subStreamGenerator, accessCondition, options, opContext, blockList); + } + + this.commitBlockList(blockList,accessCondition, options, opContext); } - finally { - writeStream.close(); + } + } + + /** + * Uploads an Iterable collection of streams using PutBlock. + * + * @param streamList + * An Iterable object of type InputStream that represent the + * source streams to be uploaded. + * @param accessCondition + * An {@link AccessCondition} object that represents the access conditions for the blob. + * @param requestOptions + * A {@link BlobRequestOptions} object that specifies any additional options for the request. Specifying + * null will use the default request options from the associated service client ( + * {@link CloudBlobClient}). + * @param operationContext + * An {@link OperationContext} object that represents the context for the current operation. This object + * is used to track requests to the storage service, and to provide additional runtime information about + * the operation. + * @param blockList + * An List object of type (@link BlockEntry} that will be populated with the BlockEntry for each uploaded block. + * @throws StorageException + * If a storage service error occurred. + * @throws IOException + * If an I/O error occurred. + */ + private void uploadFromMultiStream(Iterable streamList, AccessCondition accessCondition, BlobRequestOptions requestOptions, OperationContext operationContext, List blockList) + throws StorageException, IOException { + int concurrentOpsCount = requestOptions.getConcurrentRequestCount(); + + // The ExecutorService used to schedule putblock tasks for this stream. + ThreadPoolExecutor threadPool = new ThreadPoolExecutor( + concurrentOpsCount, + concurrentOpsCount, + 10, + TimeUnit.SECONDS, + new LinkedBlockingQueue()); + + ExecutorCompletionService completionService = new ExecutorCompletionService(threadPool); + final BlobRequestOptions _requestOptions = requestOptions; + final OperationContext _operationContext = operationContext; + final AccessCondition _accessCondition = accessCondition; + int blockNum = 0; + for (InputStream block : streamList) { + + // Pad block id up to digits in MaxBlockSize + final String blockId = Base64.encode( + String.format("Block_%05d", ++blockNum).getBytes() + ); + + BlockEntry blockEntry = new BlockEntry(blockId); + blockList.add(blockEntry); + final InputStream sourceStream = block; + final long blockSize = block instanceof SubStream ? ((SubStream) block).getLength() : this.streamWriteSizeInBytes; + + Future uploadTask = completionService.submit(new Callable() { + @Override + public Void call() throws IOException, StorageException { + uploadBlock(blockId, sourceStream, blockSize, _accessCondition, _requestOptions, _operationContext); + sourceStream.close(); + return null; + } + }); + } + + for (int i = 0; i < blockNum; i++) { + this.waitAny(completionService); + } + + try { + // Shutdown the thread pool executor. + threadPool.shutdown(); + } + finally { + if (!threadPool.isShutdown()) { + threadPool.shutdownNow(); } } } @@ -874,6 +985,7 @@ public void uploadBlock(final String blockId, final InputStream sourceStream, fi public void uploadBlock(final String blockId, final InputStream sourceStream, final long length, final AccessCondition accessCondition, BlobRequestOptions options, OperationContext opContext) throws StorageException, IOException { + if (length < -1) { throw new IllegalArgumentException(SR.STREAM_LENGTH_NEGATIVE); } @@ -918,8 +1030,9 @@ else if (length < 0 || options.getUseTransactionalContentMD5()) { options.getUseTransactionalContentMD5()); } - if (descriptor.getLength() > 4 * Constants.MB) { - throw new IllegalArgumentException(SR.STREAM_LENGTH_GREATER_THAN_4MB); + if (descriptor.getLength() > Constants.MAX_BLOCK_SIZE) + { + throw new IllegalArgumentException(SR.STREAM_LENGTH_GREATER_THAN_100MB); } this.uploadBlockInternal(blockId, descriptor.getMd5(), bufferedStreamReference, descriptor.getLength(), @@ -1098,20 +1211,46 @@ public String downloadText(final String charsetName, final AccessCondition acces /** * Sets the number of bytes to buffer when writing to a {@link BlobOutputStream}. - * - * @param streamWriteSizeInBytes - * An int which represents the maximum block size, in bytes, for writing to a block blob - * while using a {@link BlobOutputStream} object, ranging from 16 KB to 4 MB, inclusive. - * - * @throws IllegalArgumentException - * If streamWriteSizeInBytes is less than 16 KB or greater than 4 MB. + * + * @param streamWriteSizeInBytes An int which represents the maximum block size, in bytes, for writing to a block blob + * while using a {@link BlobOutputStream} object, ranging from 16 KB to 100 MB, inclusive. + * @throws IllegalArgumentException If streamWriteSizeInBytes is less than 16 KB or greater than 100 MB. */ @Override - public void setStreamWriteSizeInBytes(final int streamWriteSizeInBytes) { - if (streamWriteSizeInBytes > Constants.MAX_BLOCK_SIZE || streamWriteSizeInBytes < 16 * Constants.KB) { + public void setStreamWriteSizeInBytes(final int streamWriteSizeInBytes) + { + if (streamWriteSizeInBytes > Constants.MAX_BLOCK_SIZE || streamWriteSizeInBytes < Constants.MIN_PERMITTED_BLOCK_SIZE) + { throw new IllegalArgumentException("StreamWriteSizeInBytes"); } this.streamWriteSizeInBytes = streamWriteSizeInBytes; + this.isStreamWriteSizeModified = true; + } + + /** + * Gets the flag that indicates whether the default streamWriteSize was modified. + */ + public boolean isStreamWriteSizeModified() + { + return this.isStreamWriteSizeModified; + } + + private void waitAny(ExecutorCompletionService completionService) throws StorageException, IOException { + try { + completionService.take().get(); + } + catch (Exception e) { + Throwable cause = e.getCause(); + while (cause != null) { + if (cause instanceof StorageException) { + throw (StorageException) cause; + } + + cause = cause.getCause(); + } + + throw Utility.initIOException(e); + } } } \ No newline at end of file diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudPageBlob.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudPageBlob.java index 3db79c1371f4..39be1c4ae3ad 100644 --- a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudPageBlob.java +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudPageBlob.java @@ -1353,8 +1353,8 @@ public void uploadPages(final InputStream sourceStream, final long offset, final */ @Override public void setStreamWriteSizeInBytes(final int streamWriteSizeInBytes) { - if (streamWriteSizeInBytes > Constants.MAX_BLOCK_SIZE || streamWriteSizeInBytes < Constants.PAGE_SIZE - || streamWriteSizeInBytes % Constants.PAGE_SIZE != 0) { + if (streamWriteSizeInBytes > Constants.MAX_PAGE_WRITE_SIZE || streamWriteSizeInBytes < Constants.PAGE_SIZE + || streamWriteSizeInBytes % Constants.PAGE_SIZE != 0) { throw new IllegalArgumentException("StreamWriteSizeInBytes"); } diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/SubStream.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/SubStream.java new file mode 100644 index 000000000000..f147b91b36f9 --- /dev/null +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/SubStream.java @@ -0,0 +1,336 @@ +/** + * Copyright Microsoft Corporation + *

+ * Licensed 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 com.microsoft.azure.storage.blob; + +import com.microsoft.azure.storage.Constants; +import com.microsoft.azure.storage.core.SR; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; + +public class SubStream extends InputStream { + // A mutal exclusion lock shared between other related substream instances. + private final Object lock; + + // Stream to be wrapped. + private InputStream wrappedStream; + + // The current, relative position in the substream. + private long substreamCurrentIndex; + + // The position in the wrapped stream (relative to the last mark) where the substream should logically begin. + private long streamBeginIndex; + + // The length of the substream. + private long streamLength; + + // Tracks the marked position in the substream. + private long markIndex; + + // Buffer for read requests. + private byte[] readBuffer; + + private ByteArrayInputStream readBufferStream; + + // Keeps track of the remaining valid bytes available in the read buffer. + private int readBufferLength; + + /** + * Creates a new substream instance that partitions the wrapped stream source from + * startIndex up to streamLength. Each substream instance that wraps the same + * underlying InputStream must share the same mutual exclusion lock to avoid race + * conditions from concurrent operations. + * + * @param source The markable InputStream to be wrapped. + * @param startIndex A valid index in the wrapped stream where the substream should logically begin. + * @param streamLength The length of the substream. + * @param lock An intrinsic lock to ensure thread-safe, concurrent operations + * on substream instances wrapping the same InputStream. + * @throws Exception + */ + public SubStream(InputStream source, long startIndex, long streamLength, Object lock) { + if (startIndex < 0 || streamLength < 1) { + throw new IndexOutOfBoundsException(); + } + else if (source == null) { + throw new NullPointerException("Source stream is null."); + } + else if (!source.markSupported()) { + throw new IllegalArgumentException("The source stream to be wrapped must be markable."); + } + + this.wrappedStream = source; + this.streamBeginIndex = startIndex; + this.substreamCurrentIndex = 0; + this.streamLength = streamLength; + this.lock = lock; + this.readBuffer = new byte[Constants.SUBSTREAM_BUFFER_SIZE]; + this.readBufferStream = new ByteArrayInputStream(this.readBuffer); + + // Set empty read buffer to force refresh upon first read. + this.readBufferLength = 0; + + // By default, mark the beginning of the stream. + this.markIndex = 0; + this.readBufferStream.mark(Integer.MAX_VALUE); + } + + public InputStream getInputStream() { + return this.wrappedStream; + } + + public long getLength() { + return this.streamLength; + } + + /** + * Reads the next byte of data from the wrapped stream. The value byte is + * returned as an int in the range 0 to + * 255. If no byte is available because the end of the substream + * has been reached, the value -1 is returned. This method + * blocks until input data is available, the end of the stream is detected, + * or an exception is thrown. + * + * @return the next byte of data, or -1 if the end of the + * substream is reached. + * @throws IOException if an I/O error occurs. + */ + @Override + public int read() throws IOException { + throw new IOException(); + } + + /** + * Reads some number of bytes from the wrapped stream and stores them into + * the buffer array b. The number of bytes actually read is + * returned as an integer. This method blocks until input data is + * available, end of file is detected, or an exception is thrown. + *

+ *

If the length of b is zero, then no bytes are read and + * 0 is returned; otherwise, there is an attempt to read at + * least one byte. If no byte is available because the substream is at the + * end of the file, the value -1 is returned; otherwise, at + * least one byte is read and stored into b. + *

+ *

The first byte read is stored into element b[0], the + * next one into b[1], and so on. The number of bytes read is, + * at most, equal to the length of b. Let k be the + * number of bytes actually read; these bytes will be stored in elements + * b[0] through b[k-1], + * leaving elements b[k] through + * b[b.length-1] unaffected. + *

+ *

The read(b) method for class SubStream + * has the same effect as:

 read(b, 0, b.length) 
+ * + * @param b the buffer into which the data is read. + * @return the total number of bytes read into the buffer, or + * -1 if there is no more data because the end of + * the stream has been reached. + * @throws IOException If the first byte cannot be read for any reason + * other than the end of the file, if the wrapped stream has been closed, or + * if some other I/O error occurs. + * @throws NullPointerException if b is null. + * @see SubStream#read(byte[], int, int) + */ + @Override + public synchronized int read(byte[] b) throws IOException { + return this.read(b, 0, b.length); + } + + /** + * Reads up to len bytes of data from the substream. Buffers data from the wrapped stream + * in order to minimize skip and read overhead. The wrappedstream will only be invoked if the readBuffer + * cannot fulfil the the read request. + * In order to ensure valid results, the wrapped stream must be marked prior to reading from the substream. + * This allows us to reset to the relative substream position in the wrapped stream. + * The number of bytes actually read is returned as an integer. All these operations are done + * synchronously within an intrinsic lock to ensure other concurrent requests by substream instances + * do not result in race conditions. + *

+ *

The underlying call to the read of the wrapped stream will blocks until input data + * is available, end of file is detected, or an exception is thrown. + *

+ *

If len is zero, then no bytes are read and + * 0 is returned; otherwise, there is an attempt to read at + * least one byte. If no byte is available because the substream is at end of + * file, the value -1 is returned; otherwise, at least one + * byte is read and stored into b. + * + * @param b the buffer into which the data is read. + * @param off the start offset in array b + * at which the data is written. + * @param len the maximum number of bytes to read. + * @return the total number of bytes read into the buffer, or + * -1 if there is no more data because the end of + * the stream has been reached. + * @throws IOException If the first byte cannot be read for any reason + * other than end of file, or if the wrapped stream has been closed, or if + * some other I/O error occurs. + * @throws NullPointerException If b is null. + * @throws IndexOutOfBoundsException If off is negative, + * len is negative, or len is greater than + * b.length - off + * @see SubStream#read() + */ + @Override + public synchronized int read(byte[] b, int off, int len) throws IOException { + if (off < 0 || len < 0 || len > b.length - off) { + throw new IndexOutOfBoundsException(); + } + else if (len == 0) { + return 0; + } + + int bytesRead = -1; + int readLength = len; + + // Ensure we read within the substream bounds. + if (this.substreamCurrentIndex + len > this.streamLength) { + readLength = (int) (this.streamLength - this.substreamCurrentIndex); + } + + // Read from previously buffered data and only up until the valid bytes available in the buffer. + int bytesFromBuffer = readBufferStream.read(b, off, Math.min(this.readBufferLength, readLength)); + bytesRead = Math.max(0, bytesFromBuffer); + this.readBufferLength -= bytesRead; + + // Read request was fully satisfied. + if (bytesFromBuffer == readLength) { + this.substreamCurrentIndex += bytesRead; + return bytesRead; + } + else if (bytesFromBuffer < readLength) { + // Refresh the buffer to fulfil request. + this.readBufferStream.reset(); + this.readBufferLength = this.readHelper(this.readBuffer, 0, readBuffer.length); + if (this.readBufferLength == -1) { + this.readBufferLength = 0; + } + } + + // Read the remaining bytes from the read buffer. + bytesFromBuffer = readBufferStream.read(b, bytesRead + off, Math.min(this.readBufferLength, readLength - bytesRead)); + + if (bytesFromBuffer != -1) { + bytesRead += bytesFromBuffer; + this.readBufferLength -= bytesFromBuffer; + } + + this.substreamCurrentIndex += bytesRead; + return bytesRead; + } + + private int readHelper(byte[] b, int off, int len) throws IOException { + synchronized (this.lock) { + wrappedStream.reset(); + + long bytesSkipped = 0; + byte failSkipCount = 0; + + long streamCurrentIndex = this.streamBeginIndex + this.substreamCurrentIndex; + // Must be done in a loop as skip may return less than the requested number of bytes. + do { + if (failSkipCount > 7) { + throw new IOException(SR.STREAM_SKIP_FAILED); + } + + long skipped = wrappedStream.skip(streamCurrentIndex - bytesSkipped); + if (skipped == 0) { + failSkipCount++; + } + else { + failSkipCount = 0; + bytesSkipped += skipped; + } + } + while (bytesSkipped != streamCurrentIndex); + + return wrappedStream.read(b, off, len); + } + } + + /** + * Advances the current position of the substream by n. + * The skip method does not invoke the underlying skip method + * of the wrapped stream class. The actual skipping of bytes will be accounted for + * during subsequent substream read operations. + * + * @param n the number of bytes to be effectively skipped. + * @return the actual number of bytes skipped. + */ + @Override + public long skip(long n) { + if (this.substreamCurrentIndex + n > this.streamLength) { + n = this.streamLength - this.substreamCurrentIndex; + } + + this.substreamCurrentIndex += n; + this.readBufferLength = (int) Math.max(0, this.readBufferLength - n); + return n; + } + + /** + * Marks the current position in the substream. A subsequent call to + * the reset method will reposition the stream to this stored position. + * + * @param readlimit the maximum limit of bytes that can be read before + * the mark position becomes invalid. + * @see SubStream#reset() + */ + @Override + public synchronized void mark(int readlimit) { + this.markIndex = this.substreamCurrentIndex; + } + + /** + * Repositions the substream position to the index where the mark method + * was last called. + *

+ * The new reset position on substream does not take effect until subsequent reads. + * + * @see SubStream#mark(int) + */ + @Override + public synchronized void reset() { + this.substreamCurrentIndex = this.markIndex; + } + + /** + * The substream wrapper class is only compatible with markable input streams and hence + * will always return true. This requirement is enforced in the class constructor. + * + * @return true + * @see SubStream#mark(int) + * @see SubStream#reset() + */ + @Override + public boolean markSupported() { + return true; + } + + /** + * Closes the substream. + */ + @Override + public void close() throws IOException { + this.wrappedStream = null; + this.readBuffer = null; + this.readBufferStream.close(); + this.readBufferStream = null; + } +} \ No newline at end of file diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/core/SR.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/core/SR.java index def3a4cab928..43973d90aa71 100644 --- a/microsoft-azure-storage/src/com/microsoft/azure/storage/core/SR.java +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/core/SR.java @@ -26,6 +26,7 @@ public class SR { public static final String ARGUMENT_OUT_OF_RANGE_ERROR = "The argument is out of range. Argument name: %s, Value passed: %s."; public static final String ATTEMPTED_TO_SERIALIZE_INACCESSIBLE_PROPERTY = "An attempt was made to access an inaccessible member of the entity during serialization."; public static final String BLOB = "blob"; + public static final String BLOB_OVER_MAX_BLOCK_LIMIT = "The total blocks for this upload exceeds the maximum allowable limit. Please increase the block size."; public static final String BLOB_DATA_CORRUPTED = "Blob data corrupted (integrity check failed), Expected value is %s, retrieved %s"; public static final String BLOB_ENDPOINT_NOT_CONFIGURED = "No blob endpoint configured."; public static final String BLOB_HASH_MISMATCH = "Blob hash mismatch (integrity check failed), Expected value is %s, retrieved %s."; @@ -168,7 +169,9 @@ public class SR { public static final String STOREAS_DIFFERENT_FOR_GETTER_AND_SETTER = "StoreAs Annotation found for both getter and setter for property %s with unequal values."; public static final String STOREAS_USED_ON_EMPTY_PROPERTY = "StoreAs Annotation found for property %s with empty value."; public static final String STREAM_CLOSED = "Stream is already closed."; + public static final String STREAM_SKIP_FAILED = "The supplied stream has failed to skip to the correct position after successive attempts. Please ensure there are bytes available and try your upload again."; public static final String STREAM_LENGTH_GREATER_THAN_4MB = "Invalid stream length, length must be less than or equal to 4 MB in size."; + public static final String STREAM_LENGTH_GREATER_THAN_100MB = "Invalid stream length, length must be less than or equal to 100 MB in size."; public static final String STREAM_LENGTH_NEGATIVE = "Invalid stream length, specify -1 for unknown length stream, or a positive number of bytes."; public static final String STRING_NOT_VALID = "The String is not a valid Base64-encoded string."; public static final String TABLE = "table"; diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/file/CloudFile.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/file/CloudFile.java index 9ef7dba318ac..bc47e34ac8ec 100644 --- a/microsoft-azure-storage/src/com/microsoft/azure/storage/file/CloudFile.java +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/file/CloudFile.java @@ -2900,7 +2900,7 @@ public void setStreamMinimumReadSizeInBytes(final int minimumReadSize) { * If streamWriteSizeInBytes is less than 512 bytes or greater than 4 MB. */ public void setStreamWriteSizeInBytes(final int streamWriteSizeInBytes) { - if (streamWriteSizeInBytes > Constants.MAX_BLOCK_SIZE || streamWriteSizeInBytes < Constants.PAGE_SIZE) { + if (streamWriteSizeInBytes > Constants.MAX_FILE_WRITE_SIZE || streamWriteSizeInBytes < Constants.MIN_PERMITTED_FILE_WRITE_SIZE) { throw new IllegalArgumentException("StreamWriteSizeInBytes"); } From 707886fed7cda8760ff59767b59946c883505f19 Mon Sep 17 00:00:00 2001 From: Ram B Date: Sat, 19 Nov 2016 03:59:16 -0800 Subject: [PATCH 08/11] Update ChangeLog.txt --- ChangeLog.txt | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index 7bbe45293f8b..39ffd8198289 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,4 +1,3 @@ -<<<<<<< HEAD 2016.XX.XX Version 5.0.0 * Prefix support for listing files and directories. * Added support for setting public access when creating a blob container @@ -6,15 +5,12 @@ * Add Message now modifies the PopReceipt, Id, NextVisibleTime, InsertionTime, and ExpirationTime properties of its CloudQueueMessage parameter. * Populate content MD5 for range gets on Blobs and Files. * Added support in Page Blob for incremental copy. + * Added large BlockBlob upload support. Blocks can now support sizes up to 100 MB. + * Added a new, memory-optimized upload strategy for the upload* APIs. This algorithm only applies for blocks greater than 4MB and when storeBlobContentMD5 and Client-Side Encryption are disabled. 2016.08.30 Version 4.4.0 * Fixed a bug in client-side encryption for tables that was preventing the Java client from decrypting entities encrypted with the .NET client, and vice versa. -======= -2016.10.15 Version 4.5.0 -* Added large BlockBlob upload support. Blocks can now support sizes up to 100 MB. -* Added a new, memory-optimized upload strategy for the upload* APIs. This algorithm only applies for blocks greater than 4MB and when storeBlobContentMD5 and Client-Side Encryption are disabled. ->>>>>>> 9b002a7... lbb - + 2016.07.06 Version 4.3.0 * Added support for server-side encryption. * Added support for getBlobReferenceFromServer methods on CloudBlobContainer to support retrieving a blob without knowing its type. From b21330d9f4928e075d76d9c1a3525ef03cb1c750 Mon Sep 17 00:00:00 2001 From: Josh Friedman Date: Mon, 12 Dec 2016 13:28:53 -0800 Subject: [PATCH 09/11] Test fixes to support May16 version --- .../blob/CloudBlobServerEncryptionTests.java | 2 +- .../storage/blob/CloudPageBlobTests.java | 4 ++-- .../storage/file/CloudFileDirectoryTests.java | 7 ++++-- .../azure/storage/file/CloudFileTests.java | 13 ++--------- .../azure/storage/queue/CloudQueueTests.java | 22 +------------------ .../table/TableBatchOperationTests.java | 2 +- .../azure/storage/table/TableQueryTests.java | 2 +- .../azure/storage/core/Canonicalizer.java | 2 +- 8 files changed, 14 insertions(+), 40 deletions(-) diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlobServerEncryptionTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlobServerEncryptionTests.java index 774f94727a6f..685b9a89aa3d 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlobServerEncryptionTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlobServerEncryptionTests.java @@ -35,7 +35,7 @@ import static org.junit.Assert.*; @Category({ CloudTests.class, DevFabricTests.class, DevStoreTests.class }) -@Ignore +//@Ignore /* These test only works on accounts with server-side encryption enabled. */ public class CloudBlobServerEncryptionTests { diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudPageBlobTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudPageBlobTests.java index 1e81bf33eb30..61cb3ee9e887 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudPageBlobTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudPageBlobTests.java @@ -1148,7 +1148,7 @@ private void testCopyPageBlobIncrementalSnapshotImpl(int overload) throws URISyn final UriQueryBuilder builder = new UriQueryBuilder(); builder.add(Constants.QueryConstants.SNAPSHOT, sasSnapshotBlob.snapshotID); URI sourceUri = TestHelper.defiddler(builder.addToURI(sasSnapshotBlob.getTransformedAddress(null).getPrimaryUri())); - + String copyId = null; if (overload == 0) { copyId = copy.startIncrementalCopy(BlobTestHelper.defiddler(sasSnapshotBlob)); @@ -1167,7 +1167,7 @@ else if (overload == 2) { assertEquals(BlobType.PAGE_BLOB, copy.getProperties().getBlobType()); assertEquals(CopyStatus.SUCCESS, copy.getCopyState().getStatus()); - assertEquals(sourceUri, copy.getCopyState().getSource()); + assertEquals(sourceUri.getSchemeSpecificPart(), copy.getCopyState().getSource().getSchemeSpecificPart()); assertTrue(buffer.length == copy.getCopyState().getTotalBytes()); assertTrue(buffer.length == copy.getCopyState().getBytesCopied()); assertEquals(copyId, copy.getCopyState().getCopyId()); diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/CloudFileDirectoryTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/CloudFileDirectoryTests.java index 2675604c85f4..fbf9e898e8b0 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/CloudFileDirectoryTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/CloudFileDirectoryTests.java @@ -313,13 +313,16 @@ public void testCloudFileDirectoryListFilesAndDirectoriesWithPrefix() throws URI segmentResults = topDir1.listFilesAndDirectoriesSegmented( "mid" /* prefix */, null /* maxResults */, - segmentResults.getContinuationToken() /* currentToken */, + null /* currentToken */, null /* options */, null /* operationContext */); assertNull(segmentResults.getContinuationToken()); - assertEquals(1, segmentResults.getResults().size()); + assertEquals(2, segmentResults.getResults().size()); item = segmentResults.getResults().get(0); + assertEquals(this.share.getUri() + "/TopDir1/MidDir1", item.getUri().toString()); + assertEquals("MidDir1", ((CloudFileDirectory)item).getName()); + item = segmentResults.getResults().get(1); assertEquals(this.share.getUri() + "/TopDir1/MidDir2", item.getUri().toString()); assertEquals("MidDir2", ((CloudFileDirectory)item).getName()); } diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/CloudFileTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/CloudFileTests.java index ae8a3f8b68f5..292ba7164385 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/CloudFileTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/CloudFileTests.java @@ -742,17 +742,8 @@ public void eventOccurred(SendingRequestEvent eventArg) { } }); - try { - fileRef.upload(srcStream, length, null, null, context); - fileRef.download(new ByteArrayOutputStream(), null, null, context); - fail("Shouldn't sign empty header, expected a 403."); - } - catch (StorageException e) { - assertEquals(e.getHttpStatusCode(), 403); - assertEquals( - e.getMessage(), - "Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature."); - } + fileRef.upload(srcStream, length, null, null, context); + fileRef.download(new ByteArrayOutputStream(), null, null, context); } /** diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/queue/CloudQueueTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/queue/CloudQueueTests.java index d9b6e3dc9e63..dcea5d8f1c2e 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/queue/CloudQueueTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/queue/CloudQueueTests.java @@ -912,13 +912,6 @@ public void testAddMessageSpecialVisibilityTimeout() throws StorageException { this.queue.addMessage(message, 7 * 24 * 60 * 60, 0, null, null); this.queue.addMessage(message, 7 * 24 * 60 * 60, 7 * 24 * 60 * 60 - 1, null, null); - try { - this.queue.addMessage(message, -1, 0, null, null); - fail(); - } - catch (final IllegalArgumentException e) { - } - try { this.queue.addMessage(message, 0, -1, null, null); fail(); @@ -946,13 +939,6 @@ public void testAddMessageSpecialVisibilityTimeout() throws StorageException { } catch (final IllegalArgumentException e) { } - - try { - this.queue.updateMessage(message, 0, EnumSet.of(MessageUpdateFields.CONTENT), null, null); - fail(); - } - catch (final IllegalArgumentException e) { - } } @Test @@ -1353,13 +1339,7 @@ public void testUpdateMessageNullMessage() throws StorageException { public void testUpdateMessageInvalidMessage() throws StorageException { CloudQueueMessage message = new CloudQueueMessage("test"); this.queue.addMessage(message, 1, 0, null, null); - - try { - this.queue.updateMessage(message, 0, EnumSet.of(MessageUpdateFields.CONTENT), null, null); - fail(); - } - catch (final IllegalArgumentException e) { - } + this.queue.updateMessage(message, 0, EnumSet.of(MessageUpdateFields.CONTENT), null, null); this.queue.delete(); } diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/table/TableBatchOperationTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/table/TableBatchOperationTests.java index f7e82bb013fe..dfa1e47b6cef 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/table/TableBatchOperationTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/table/TableBatchOperationTests.java @@ -429,7 +429,7 @@ public void testBatchOver100Entities() throws StorageException { assertEquals(ex.getMessage(), "Bad Request"); String errorAfterSemiColon = ex.getExtendedErrorInformation().getErrorMessage(); errorAfterSemiColon = errorAfterSemiColon.substring(errorAfterSemiColon.indexOf(":") + 1); - assertTrue(errorAfterSemiColon.startsWith("One of the request inputs is not valid.")); + assertTrue(errorAfterSemiColon.startsWith("The batch request operation exceeds the maximum 100 changes per change set.")); assertEquals(ex.getErrorCode(), StorageErrorCodeStrings.INVALID_INPUT); } } diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/table/TableQueryTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/table/TableQueryTests.java index d6acf859381a..ceb1176ebd36 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/table/TableQueryTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/table/TableQueryTests.java @@ -239,7 +239,7 @@ public void testTableInvalidQuery() throws StorageException { catch (TableServiceException ex) { assertEquals(ex.getMessage(), "Bad Request"); assertTrue(ex.getExtendedErrorInformation().getErrorMessage() - .startsWith("One of the request inputs is not valid.")); + .startsWith("A binary operator with incompatible types was detected. Found operand types 'Edm.String' and 'Edm.Boolean' for operator kind 'And'.")); assertEquals(ex.getExtendedErrorInformation().getErrorCode(), "InvalidInput"); } } diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/core/Canonicalizer.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/core/Canonicalizer.java index ed5ebbc6151f..4b7f16e5832b 100644 --- a/microsoft-azure-storage/src/com/microsoft/azure/storage/core/Canonicalizer.java +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/core/Canonicalizer.java @@ -80,7 +80,7 @@ private static void addCanonicalizedHeaders(final HttpURLConnection conn, final // Go through values, unfold them, and then append them to the // canonicalized element string. for (final String value : values) { - if (!Utility.isNullOrEmpty(value)) { + if (value != null) { appendCanonicalizedElement = true; } From 465e8b60343d3efdeb5816fbd437ffbe2c04dc21 Mon Sep 17 00:00:00 2001 From: Josh Friedman Date: Wed, 14 Dec 2016 09:38:24 -0800 Subject: [PATCH 10/11] Qualified URI changes/bug fix --- BreakingChanges.txt | 8 + ChangeLog.txt | 3 + .../azure/storage/blob/BlobTestHelper.java | 2 +- .../storage/blob/CloudAppendBlobTests.java | 4 +- .../storage/blob/CloudBlobContainerTests.java | 2 +- .../storage/blob/CloudBlockBlobTests.java | 4 +- .../storage/blob/CloudPageBlobTests.java | 5 +- .../azure/storage/blob/SasTests.java | 220 ++++++++++++++++-- .../azure/storage/file/FileSasTests.java | 120 ++++++++-- .../azure/storage/blob/CloudAppendBlob.java | 10 +- .../azure/storage/blob/CloudBlob.java | 47 +++- .../azure/storage/blob/CloudBlockBlob.java | 10 +- .../azure/storage/blob/CloudPageBlob.java | 10 +- .../azure/storage/file/CloudFile.java | 10 +- 14 files changed, 393 insertions(+), 62 deletions(-) diff --git a/BreakingChanges.txt b/BreakingChanges.txt index 812e15469587..3101b223c40e 100644 --- a/BreakingChanges.txt +++ b/BreakingChanges.txt @@ -1,5 +1,13 @@ Changes in 5.0.0 +BLOB + * getQualifiedUri() has been deprecated. Please use getSnapshotQualifiedUri() instead. This new function will return the blob including the snapshot (if present) and no SAS token. + * getQualifiedStorageUri() has been deprecated. Please use getSnapshotQualifiedStorageUri() instead. This new function will return the blob including the snapshot (if present) and no SAS token. + * Fixed a bug where copying from a blob that included a SAS token and a snapshot did not use the SAS token. + + FILE + * Fixed a bug where copying from a blob that included a SAS token and a snapshot did not use the SAS token. + QUEUE * For addMessage() the CloudQueueMessage message passed in will be populated with the pop receipt, insertion/expiration time, and message ID. diff --git a/ChangeLog.txt b/ChangeLog.txt index 39ffd8198289..d4fe4b0acc98 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -7,6 +7,9 @@ * Added support in Page Blob for incremental copy. * Added large BlockBlob upload support. Blocks can now support sizes up to 100 MB. * Added a new, memory-optimized upload strategy for the upload* APIs. This algorithm only applies for blocks greater than 4MB and when storeBlobContentMD5 and Client-Side Encryption are disabled. + * getQualifiedUri() has been deprecated for Blobs. Please use getSnapshotQualifiedUri() instead. This new function will return the blob including the snapshot (if present) and no SAS token. + * getQualifiedStorageUri() has been deprecated for Blobs. Please use getSnapshotQualifiedStorageUri() instead. This new function will return the blob including the snapshot (if present) and no SAS token. + * Fixed a bug where copying from a blob that included a SAS token and a snapshot ommitted the SAS token. 2016.08.30 Version 4.4.0 * Fixed a bug in client-side encryption for tables that was preventing the Java client from decrypting entities encrypted with the .NET client, and vice versa. diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/BlobTestHelper.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/BlobTestHelper.java index 4e6aa41febdf..480aa25771ee 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/BlobTestHelper.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/BlobTestHelper.java @@ -388,7 +388,7 @@ public static void assertAreEqual(CloudBlob blob1, CloudBlob blob2) throws URISy assertEquals(blob1.getUri(), blob2.getUri()); assertEquals(blob1.getSnapshotID(), blob2.getSnapshotID()); assertEquals(blob1.isSnapshot(), blob2.isSnapshot()); - assertEquals(blob1.getQualifiedStorageUri(), blob2.getQualifiedStorageUri()); + assertEquals(blob1.getSnapshotQualifiedStorageUri(), blob2.getSnapshotQualifiedStorageUri()); assertAreEqual(blob1.getProperties(), blob2.getProperties()); assertAreEqual(blob1.getCopyState(), blob2.getCopyState()); } diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudAppendBlobTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudAppendBlobTests.java index 58ad64baeaf5..5e8988ca0430 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudAppendBlobTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudAppendBlobTests.java @@ -767,7 +767,7 @@ public void testAppendBlobCopyTest() throws URISyntaxException, BlobTestHelper.waitForCopy(copy); assertEquals(CopyStatus.SUCCESS, copy.getCopyState().getStatus()); - assertEquals(source.getQualifiedUri().getPath(), copy.getCopyState() + assertEquals(source.getSnapshotQualifiedUri().getPath(), copy.getCopyState() .getSource().getPath()); assertEquals(buffer.length, copy.getCopyState().getTotalBytes() .intValue()); @@ -834,7 +834,7 @@ public void testAppendBlobCopyWithMetadataOverride() BlobTestHelper.waitForCopy(copy); assertEquals(CopyStatus.SUCCESS, copy.getCopyState().getStatus()); - assertEquals(source.getQualifiedUri().getPath(), copy.getCopyState() + assertEquals(source.getSnapshotQualifiedUri().getPath(), copy.getCopyState() .getSource().getPath()); assertEquals(buffer.length, copy.getCopyState().getTotalBytes() .intValue()); diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlobContainerTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlobContainerTests.java index 764e534ea8ef..c92c628675dd 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlobContainerTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlobContainerTests.java @@ -864,7 +864,7 @@ private static void assertCreatedAndListedBlobsEquivalent(CloudBlockBlob created assertEquals(createdBlob.getContainer().getName(), listedBlob.getContainer().getName()); assertEquals(createdBlob.getMetadata(), listedBlob.getMetadata()); assertEquals(createdBlob.getName(), listedBlob.getName()); - assertEquals(createdBlob.getQualifiedUri(), listedBlob.getQualifiedUri()); + assertEquals(createdBlob.getSnapshotQualifiedUri(), listedBlob.getSnapshotQualifiedUri()); assertEquals(createdBlob.getSnapshotID(), listedBlob.getSnapshotID()); assertEquals(createdBlob.getUri(), listedBlob.getUri()); diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlockBlobTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlockBlobTests.java index 5a9a04eedcf0..610ea85022aa 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlockBlobTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlockBlobTests.java @@ -320,7 +320,7 @@ public void testCopyBlockBlobWithMetadataOverride() throws URISyntaxException, S BlobTestHelper.waitForCopy(copy); assertEquals(CopyStatus.SUCCESS, copy.getCopyState().getStatus()); - assertEquals(source.getQualifiedUri().getPath(), copy.getCopyState().getSource().getPath()); + assertEquals(source.getSnapshotQualifiedUri().getPath(), copy.getCopyState().getSource().getPath()); assertEquals(data.length(), copy.getCopyState().getTotalBytes().intValue()); assertEquals(data.length(), copy.getCopyState().getBytesCopied().intValue()); assertEquals(copyId, copy.getCopyState().getCopyId()); @@ -1829,7 +1829,7 @@ private void doCloudBlockBlobCopy(boolean sourceIsSas, boolean destinationIsSas) // Check original blob references for equality assertEquals(CopyStatus.SUCCESS, destination.getCopyState().getStatus()); - assertEquals(source.getQualifiedUri().getPath(), destination.getCopyState().getSource().getPath()); + assertEquals(source.getSnapshotQualifiedUri().getPath(), destination.getCopyState().getSource().getPath()); assertEquals(data.length(), destination.getCopyState().getTotalBytes().intValue()); assertEquals(data.length(), destination.getCopyState().getBytesCopied().intValue()); assertEquals(copyId, destination.getProperties().getCopyState().getCopyId()); diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudPageBlobTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudPageBlobTests.java index 61cb3ee9e887..d292bd749e8a 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudPageBlobTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudPageBlobTests.java @@ -52,7 +52,6 @@ import com.microsoft.azure.storage.SharedAccessAccountPolicy; import com.microsoft.azure.storage.SharedAccessAccountResourceType; import com.microsoft.azure.storage.SharedAccessAccountService; -import com.microsoft.azure.storage.StorageCredentials; import com.microsoft.azure.storage.StorageEvent; import com.microsoft.azure.storage.StorageException; import com.microsoft.azure.storage.TestHelper; @@ -509,7 +508,7 @@ public void testPageBlobCopyTest() throws URISyntaxException, StorageException, BlobTestHelper.waitForCopy(copy); assertEquals(CopyStatus.SUCCESS, copy.getCopyState().getStatus()); - assertEquals(source.getQualifiedUri().getPath(), copy.getCopyState().getSource().getPath()); + assertEquals(source.getSnapshotQualifiedUri().getPath(), copy.getCopyState().getSource().getPath()); assertEquals(buffer.length, copy.getCopyState().getTotalBytes().intValue()); assertEquals(buffer.length, copy.getCopyState().getBytesCopied().intValue()); assertEquals(copyId, copy.getCopyState().getCopyId()); @@ -567,7 +566,7 @@ public void testPageBlobCopyWithMetadataOverride() throws URISyntaxException, St BlobTestHelper.waitForCopy(copy); assertEquals(CopyStatus.SUCCESS, copy.getCopyState().getStatus()); - assertEquals(source.getQualifiedUri().getPath(), copy.getCopyState().getSource().getPath()); + assertEquals(source.getSnapshotQualifiedUri().getPath(), copy.getCopyState().getSource().getPath()); assertEquals(buffer.length, copy.getCopyState().getTotalBytes().intValue()); assertEquals(buffer.length, copy.getCopyState().getBytesCopied().intValue()); assertEquals(copyId, copy.getCopyState().getCopyId()); diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/SasTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/SasTests.java index f2063326254c..bcf0b47cad02 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/SasTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/SasTests.java @@ -15,29 +15,9 @@ package com.microsoft.azure.storage.blob; -import com.microsoft.azure.storage.Constants; -import com.microsoft.azure.storage.core.PathUtility; -import com.microsoft.azure.storage.core.SR; -import com.microsoft.azure.storage.IPRange; -import com.microsoft.azure.storage.OperationContext; -import com.microsoft.azure.storage.ResponseReceivedEvent; -import com.microsoft.azure.storage.SecondaryTests; -import com.microsoft.azure.storage.SendingRequestEvent; -import com.microsoft.azure.storage.SharedAccessProtocols; -import com.microsoft.azure.storage.StorageCredentials; -import com.microsoft.azure.storage.StorageCredentialsAnonymous; -import com.microsoft.azure.storage.StorageCredentialsSharedAccessSignature; -import com.microsoft.azure.storage.StorageEvent; -import com.microsoft.azure.storage.StorageException; -import com.microsoft.azure.storage.TestRunners; - import junit.framework.Assert; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.experimental.categories.Category; - +import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.net.HttpURLConnection; @@ -54,7 +34,32 @@ import java.util.NoSuchElementException; import java.util.TimeZone; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import com.microsoft.azure.storage.Constants; +import com.microsoft.azure.storage.core.PathUtility; +import com.microsoft.azure.storage.core.SR; +import com.microsoft.azure.storage.IPRange; +import com.microsoft.azure.storage.OperationContext; +import com.microsoft.azure.storage.ResponseReceivedEvent; +import com.microsoft.azure.storage.SecondaryTests; +import com.microsoft.azure.storage.SendingRequestEvent; +import com.microsoft.azure.storage.SharedAccessProtocols; +import com.microsoft.azure.storage.SharedAccessAccountPermissions; +import com.microsoft.azure.storage.SharedAccessAccountPolicy; +import com.microsoft.azure.storage.SharedAccessAccountResourceType; +import com.microsoft.azure.storage.SharedAccessAccountService; +import com.microsoft.azure.storage.SharedAccessProtocols; +import com.microsoft.azure.storage.StorageCredentials; +import com.microsoft.azure.storage.StorageCredentialsAnonymous; +import com.microsoft.azure.storage.StorageCredentialsSharedAccessSignature; +import com.microsoft.azure.storage.StorageEvent; +import com.microsoft.azure.storage.StorageException; import com.microsoft.azure.storage.TestHelper; +import com.microsoft.azure.storage.TestRunners; import com.microsoft.azure.storage.TestRunners.CloudTests; import com.microsoft.azure.storage.TestRunners.DevFabricTests; import com.microsoft.azure.storage.TestRunners.DevStoreTests; @@ -487,6 +492,179 @@ public void eventOccurred(SendingRequestEvent eventArg) { sasBlob.download(new ByteArrayOutputStream(), null, null, context); } + @Test + public void testAppendBlobCopyWithSasAndSnapshot() + throws URISyntaxException, StorageException, InterruptedException, IOException, InvalidKeyException { + String blobName = BlobTestHelper.generateRandomBlobNameWithPrefix("testblob"); + CloudAppendBlob source = this.container.getAppendBlobReference(blobName); + source.createOrReplace(); + byte[] buffer = BlobTestHelper.getRandomBuffer(512); + ByteArrayInputStream stream = new ByteArrayInputStream(buffer); + source.upload(stream, buffer.length); + source.getMetadata().put("Test", "value"); + source.uploadMetadata(); + + SharedAccessBlobPolicy policy = createSharedAccessPolicy( + EnumSet.of(SharedAccessBlobPermissions.READ, SharedAccessBlobPermissions.WRITE, + SharedAccessBlobPermissions.LIST, SharedAccessBlobPermissions.DELETE), 5000); + + CloudAppendBlob copy = this.container.getAppendBlobReference("copy"); + String sasToken = copy.generateSharedAccessSignature(policy, null); + CloudAppendBlob copySas = new CloudAppendBlob(new URI(copy.getUri().toString() + "?" + sasToken)); + + // Generate account SAS for the source + // Cannot generate a SAS directly on a snapshot and the SAS for the destination is only for the destination + SharedAccessAccountPolicy accountPolicy = new SharedAccessAccountPolicy(); + accountPolicy.setPermissions(EnumSet.of(SharedAccessAccountPermissions.READ, SharedAccessAccountPermissions.WRITE)); + accountPolicy.setServices(EnumSet.of(SharedAccessAccountService.BLOB)); + accountPolicy.setResourceTypes(EnumSet.of(SharedAccessAccountResourceType.OBJECT, SharedAccessAccountResourceType.CONTAINER)); + accountPolicy.setSharedAccessExpiryTime(policy.getSharedAccessExpiryTime()); + final CloudBlobClient sasClient = TestHelper.createCloudBlobClient(accountPolicy, false); + + CloudAppendBlob snapshot = (CloudAppendBlob) source.createSnapshot(); + CloudAppendBlob sasBlob = (CloudAppendBlob) sasClient.getContainerReference(container.getName()) + .getBlobReferenceFromServer(snapshot.getName(), snapshot.snapshotID, null, null, null); + sasBlob.exists(); + + String copyId = copySas.startCopy(BlobTestHelper.defiddler(sasBlob)); + BlobTestHelper.waitForCopy(copySas); + + copySas.downloadAttributes(); + BlobProperties prop1 = copySas.getProperties(); + BlobProperties prop2 = sasBlob.getProperties(); + + assertEquals(prop1.getCacheControl(), prop2.getCacheControl()); + assertEquals(prop1.getContentEncoding(), prop2.getContentEncoding()); + assertEquals(prop1.getContentDisposition(), + prop2.getContentDisposition()); + assertEquals(prop1.getContentLanguage(), prop2.getContentLanguage()); + assertEquals(prop1.getContentMD5(), prop2.getContentMD5()); + assertEquals(prop1.getContentType(), prop2.getContentType()); + + assertEquals("value", copySas.getMetadata().get("Test")); + assertEquals(copyId, copySas.getCopyState().getCopyId()); + + snapshot.delete(); + source.delete(); + copySas.delete(); + } + + @Test + public void testBlockBlobCopyWithSasAndSnapshot() + throws URISyntaxException, StorageException, InterruptedException, IOException, InvalidKeyException { + String blobName = BlobTestHelper.generateRandomBlobNameWithPrefix("testblob"); + CloudBlockBlob source = this.container.getBlockBlobReference(blobName); + String data = "String data"; + source.uploadText(data, Constants.UTF8_CHARSET, null, null, null); + + byte[] buffer = BlobTestHelper.getRandomBuffer(512); + ByteArrayInputStream stream = new ByteArrayInputStream(buffer); + source.upload(stream, buffer.length); + source.getMetadata().put("Test", "value"); + source.uploadMetadata(); + + SharedAccessBlobPolicy policy = createSharedAccessPolicy( + EnumSet.of(SharedAccessBlobPermissions.READ, SharedAccessBlobPermissions.WRITE, + SharedAccessBlobPermissions.LIST, SharedAccessBlobPermissions.DELETE), 5000); + + CloudBlockBlob copy = this.container.getBlockBlobReference("copy"); + String sasToken = copy.generateSharedAccessSignature(policy, null); + CloudBlockBlob copySas = new CloudBlockBlob(new URI(copy.getUri().toString() + "?" + sasToken)); + + // Generate account SAS for the source + // Cannot generate a SAS directly on a snapshot and the SAS for the destination is only for the destination + SharedAccessAccountPolicy accountPolicy = new SharedAccessAccountPolicy(); + accountPolicy.setPermissions(EnumSet.of(SharedAccessAccountPermissions.READ, SharedAccessAccountPermissions.WRITE)); + accountPolicy.setServices(EnumSet.of(SharedAccessAccountService.BLOB)); + accountPolicy.setResourceTypes(EnumSet.of(SharedAccessAccountResourceType.OBJECT, SharedAccessAccountResourceType.CONTAINER)); + accountPolicy.setSharedAccessExpiryTime(policy.getSharedAccessExpiryTime()); + final CloudBlobClient sasClient = TestHelper.createCloudBlobClient(accountPolicy, false); + + CloudBlockBlob snapshot = (CloudBlockBlob) source.createSnapshot(); + CloudBlockBlob sasBlob = (CloudBlockBlob) sasClient.getContainerReference(container.getName()) + .getBlobReferenceFromServer(snapshot.getName(), snapshot.snapshotID, null, null, null); + sasBlob.exists(); + + String copyId = copySas.startCopy(BlobTestHelper.defiddler(sasBlob)); + BlobTestHelper.waitForCopy(copySas); + + copySas.downloadAttributes(); + BlobProperties prop1 = copySas.getProperties(); + BlobProperties prop2 = sasBlob.getProperties(); + + assertEquals(prop1.getCacheControl(), prop2.getCacheControl()); + assertEquals(prop1.getContentEncoding(), prop2.getContentEncoding()); + assertEquals(prop1.getContentDisposition(), + prop2.getContentDisposition()); + assertEquals(prop1.getContentLanguage(), prop2.getContentLanguage()); + assertEquals(prop1.getContentMD5(), prop2.getContentMD5()); + assertEquals(prop1.getContentType(), prop2.getContentType()); + + assertEquals("value", copySas.getMetadata().get("Test")); + assertEquals(copyId, copySas.getCopyState().getCopyId()); + + snapshot.delete(); + source.delete(); + copySas.delete(); + } + + @Test + public void testPageBlobCopyWithSasAndSnapshot() + throws URISyntaxException, StorageException, InterruptedException, IOException, InvalidKeyException { + String blobName = BlobTestHelper.generateRandomBlobNameWithPrefix("testblob"); + CloudPageBlob source = this.container.getPageBlobReference(blobName); + source.create(1024); + byte[] buffer = BlobTestHelper.getRandomBuffer(512); + ByteArrayInputStream stream = new ByteArrayInputStream(buffer); + source.upload(stream, buffer.length); + source.getMetadata().put("Test", "value"); + source.uploadMetadata(); + + SharedAccessBlobPolicy policy = createSharedAccessPolicy( + EnumSet.of(SharedAccessBlobPermissions.READ, SharedAccessBlobPermissions.WRITE, + SharedAccessBlobPermissions.LIST, SharedAccessBlobPermissions.DELETE), 5000); + + CloudPageBlob copy = this.container.getPageBlobReference("copy"); + String sasToken = copy.generateSharedAccessSignature(policy, null); + CloudPageBlob copySas = new CloudPageBlob(new URI(copy.getUri().toString() + "?" + sasToken)); + + // Generate account SAS for the source + // Cannot generate a SAS directly on a snapshot and the SAS for the destination is only for the destination + SharedAccessAccountPolicy accountPolicy = new SharedAccessAccountPolicy(); + accountPolicy.setPermissions(EnumSet.of(SharedAccessAccountPermissions.READ, SharedAccessAccountPermissions.WRITE)); + accountPolicy.setServices(EnumSet.of(SharedAccessAccountService.BLOB)); + accountPolicy.setResourceTypes(EnumSet.of(SharedAccessAccountResourceType.OBJECT, SharedAccessAccountResourceType.CONTAINER)); + accountPolicy.setSharedAccessExpiryTime(policy.getSharedAccessExpiryTime()); + final CloudBlobClient sasClient = TestHelper.createCloudBlobClient(accountPolicy, false); + + CloudPageBlob snapshot = (CloudPageBlob) source.createSnapshot(); + CloudPageBlob sasBlob = (CloudPageBlob) sasClient.getContainerReference(container.getName()) + .getBlobReferenceFromServer(snapshot.getName(), snapshot.snapshotID, null, null, null); + sasBlob.exists(); + + String copyId = copySas.startCopy(BlobTestHelper.defiddler(sasBlob)); + BlobTestHelper.waitForCopy(copySas); + + copySas.downloadAttributes(); + BlobProperties prop1 = copySas.getProperties(); + BlobProperties prop2 = sasBlob.getProperties(); + + assertEquals(prop1.getCacheControl(), prop2.getCacheControl()); + assertEquals(prop1.getContentEncoding(), prop2.getContentEncoding()); + assertEquals(prop1.getContentDisposition(), + prop2.getContentDisposition()); + assertEquals(prop1.getContentLanguage(), prop2.getContentLanguage()); + assertEquals(prop1.getContentMD5(), prop2.getContentMD5()); + assertEquals(prop1.getContentType(), prop2.getContentType()); + + assertEquals("value", copySas.getMetadata().get("Test")); + assertEquals(copyId, copySas.getCopyState().getCopyId()); + + snapshot.delete(); + source.delete(); + copySas.delete(); + } + private final static SharedAccessBlobPolicy createSharedAccessPolicy(EnumSet sap, int expireTimeInSeconds) { diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/FileSasTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/FileSasTests.java index c620b6ec6cc7..d4a927bc08c7 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/FileSasTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/FileSasTests.java @@ -15,12 +15,40 @@ package com.microsoft.azure.storage.file; +import static org.junit.Assert.*; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.UnknownHostException; +import java.security.InvalidKeyException; +import java.util.Calendar; +import java.util.Date; +import java.util.EnumSet; +import java.util.GregorianCalendar; +import java.util.HashMap; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.TimeZone; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.experimental.categories.Category; + import com.microsoft.azure.storage.Constants; import com.microsoft.azure.storage.IPRange; import com.microsoft.azure.storage.OperationContext; import com.microsoft.azure.storage.ResponseReceivedEvent; import com.microsoft.azure.storage.SecondaryTests; import com.microsoft.azure.storage.SendingRequestEvent; +import com.microsoft.azure.storage.SharedAccessAccountPermissions; +import com.microsoft.azure.storage.SharedAccessAccountPolicy; +import com.microsoft.azure.storage.SharedAccessAccountResourceType; +import com.microsoft.azure.storage.SharedAccessAccountService; import com.microsoft.azure.storage.SharedAccessProtocols; import com.microsoft.azure.storage.StorageCredentials; import com.microsoft.azure.storage.StorageCredentialsSharedAccessSignature; @@ -33,34 +61,18 @@ import com.microsoft.azure.storage.TestRunners.DevFabricTests; import com.microsoft.azure.storage.TestRunners.DevStoreTests; import com.microsoft.azure.storage.TestRunners.SlowTests; +import com.microsoft.azure.storage.blob.BlobProperties; +import com.microsoft.azure.storage.blob.BlobTestHelper; +import com.microsoft.azure.storage.blob.CloudBlobClient; +import com.microsoft.azure.storage.blob.CloudBlobContainer; +import com.microsoft.azure.storage.blob.CloudBlockBlob; +import com.microsoft.azure.storage.blob.SharedAccessBlobPermissions; +import com.microsoft.azure.storage.blob.SharedAccessBlobPolicy; import com.microsoft.azure.storage.core.PathUtility; import com.microsoft.azure.storage.core.SR; import junit.framework.Assert; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.experimental.categories.Category; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.net.HttpURLConnection; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.UnknownHostException; -import java.security.InvalidKeyException; -import java.util.Calendar; -import java.util.Date; -import java.util.EnumSet; -import java.util.GregorianCalendar; -import java.util.HashMap; -import java.util.Map; -import java.util.NoSuchElementException; -import java.util.TimeZone; - -import static org.junit.Assert.*; - @Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) public class FileSasTests { @@ -460,6 +472,68 @@ public void eventOccurred(SendingRequestEvent eventArg) { sasFile.download(new ByteArrayOutputStream(), null, null, context); } + + @Test + public void testFileCopyFromBlobWithSasAndSnapshot() + throws URISyntaxException, StorageException, InterruptedException, IOException, InvalidKeyException { + String blobName = BlobTestHelper.generateRandomBlobNameWithPrefix("testblob"); + CloudBlobContainer container = TestHelper.createCloudBlobClient().getContainerReference(BlobTestHelper.generateRandomContainerName()); + container.createIfNotExists(); + CloudBlockBlob source = container.getBlockBlobReference(blobName); + String data = "String data"; + source.uploadText(data, Constants.UTF8_CHARSET, null, null, null); + + byte[] buffer = BlobTestHelper.getRandomBuffer(512); + ByteArrayInputStream stream = new ByteArrayInputStream(buffer); + source.upload(stream, buffer.length); + source.getMetadata().put("Test", "value"); + source.uploadMetadata(); + + SharedAccessFilePolicy policy = createSharedAccessPolicy( + EnumSet.of(SharedAccessFilePermissions.READ, SharedAccessFilePermissions.WRITE, + SharedAccessFilePermissions.LIST, SharedAccessFilePermissions.DELETE), 5000); + + CloudFile copy = this.share.getRootDirectoryReference().getFileReference("copy"); + String sasToken = copy.generateSharedAccessSignature(policy, null); + CloudFile copySas = new CloudFile(new URI(copy.getUri().toString() + "?" + sasToken)); + + // Generate account SAS for the source + // Cannot generate a SAS directly on a snapshot and the SAS for the destination is only for the destination + SharedAccessAccountPolicy accountPolicy = new SharedAccessAccountPolicy(); + accountPolicy.setPermissions(EnumSet.of(SharedAccessAccountPermissions.READ, SharedAccessAccountPermissions.WRITE)); + accountPolicy.setServices(EnumSet.of(SharedAccessAccountService.BLOB)); + accountPolicy.setResourceTypes(EnumSet.of(SharedAccessAccountResourceType.OBJECT, SharedAccessAccountResourceType.CONTAINER)); + accountPolicy.setSharedAccessExpiryTime(policy.getSharedAccessExpiryTime()); + final CloudBlobClient sasClient = TestHelper.createCloudBlobClient(accountPolicy, false); + + CloudBlockBlob snapshot = (CloudBlockBlob) source.createSnapshot(); + CloudBlockBlob sasBlob = (CloudBlockBlob) sasClient.getContainerReference(container.getName()) + .getBlobReferenceFromServer(snapshot.getName(), snapshot.getSnapshotID(), null, null, null); + sasBlob.exists(); + + String copyId = copySas.startCopy(BlobTestHelper.defiddler(sasBlob)); + FileTestHelper.waitForCopy(copySas); + + copySas.downloadAttributes(); + FileProperties prop1 = copySas.getProperties(); + BlobProperties prop2 = sasBlob.getProperties(); + + assertEquals(prop1.getCacheControl(), prop2.getCacheControl()); + assertEquals(prop1.getContentEncoding(), prop2.getContentEncoding()); + assertEquals(prop1.getContentDisposition(), + prop2.getContentDisposition()); + assertEquals(prop1.getContentLanguage(), prop2.getContentLanguage()); + assertEquals(prop1.getContentMD5(), prop2.getContentMD5()); + assertEquals(prop1.getContentType(), prop2.getContentType()); + + assertEquals("value", copySas.getMetadata().get("Test")); + assertEquals(copyId, copySas.getCopyState().getCopyId()); + + snapshot.delete(); + source.delete(); + copySas.delete(); + container.delete(); + } private final static SharedAccessFilePolicy createSharedAccessPolicy(EnumSet sap, int expireTimeInSeconds) { diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudAppendBlob.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudAppendBlob.java index 7987dff78a23..03cae586d9c6 100644 --- a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudAppendBlob.java +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudAppendBlob.java @@ -216,8 +216,14 @@ public final String startCopy(final CloudAppendBlob sourceBlob, final AccessCond final AccessCondition destinationAccessCondition, BlobRequestOptions options, OperationContext opContext) throws StorageException, URISyntaxException { Utility.assertNotNull("sourceBlob", sourceBlob); - return this.startCopy( - sourceBlob.getQualifiedUri(), sourceAccessCondition, destinationAccessCondition, options, opContext); + + URI source = sourceBlob.getSnapshotQualifiedUri(); + if (sourceBlob.getServiceClient() != null && sourceBlob.getServiceClient().getCredentials() != null) + { + source = sourceBlob.getServiceClient().getCredentials().transformUri(sourceBlob.getSnapshotQualifiedUri()); + } + + return this.startCopy(source, sourceAccessCondition, destinationAccessCondition, options, opContext); } /** diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudBlob.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudBlob.java index 83f880909eed..4992d89cf5d5 100644 --- a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudBlob.java +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudBlob.java @@ -2118,7 +2118,48 @@ public CopyState getCopyState() { } /** - * Returns the snapshot or shared access signature qualified URI for this blob. + * Returns the blob's URI for both the primary and secondary locations, including query string information if the blob is a snapshot. + * + * @return A {@link StorageUri} object containing the blob's URIs for both the primary and secondary locations, + * including snapshot query information if the blob is a snapshot. + * + * @throws StorageException + * If a storage service error occurred. + * @throws URISyntaxException + * If the resource URI is invalid. + */ + public final StorageUri getSnapshotQualifiedStorageUri() throws URISyntaxException, StorageException { + if (this.isSnapshot()) { + return PathUtility.addToQuery(this.getStorageUri(), + String.format("snapshot=%s", this.snapshotID)); + } + + return this.getStorageUri(); + } + + /** + * Returns the absolute URI to the blob, including query string information if the blob is a snapshot. + * + * @return A java.net.URI object specifying the absolute URI to the blob, + * including snapshot query information if the blob is a snapshot. + * + * @throws StorageException + * If a storage service error occurred. + * @throws URISyntaxException + * If the resource URI is invalid. + */ + public final URI getSnapshotQualifiedUri() throws URISyntaxException, StorageException { + if (this.isSnapshot()) { + return PathUtility.addToQuery(this.getUri(), String.format("snapshot=%s", this.snapshotID)); + } + + return this.getUri(); + } + + /** + * Returns the snapshot and/or shared access signature qualified URI for this blob. + * + * @deprecated use {@link #getSnapshotQualifiedStorageUri()} instead. * * @return A {@link StorageUri} object that represents the snapshot or shared access signature. * @@ -2127,6 +2168,7 @@ public CopyState getCopyState() { * @throws URISyntaxException * If the resource URI is invalid. */ + @Deprecated public final StorageUri getQualifiedStorageUri() throws URISyntaxException, StorageException { if (this.isSnapshot()) { StorageUri snapshotQualifiedUri = PathUtility.addToQuery(this.getStorageUri(), @@ -2139,6 +2181,8 @@ public final StorageUri getQualifiedStorageUri() throws URISyntaxException, Stor /** * Returns the snapshot or shared access signature qualified URI for this blob. * + * @deprecated use {@link #getSnapshotQualifiedUri()} instead. + * * @return A java.net.URI object that represents the snapshot or shared access signature. * * @throws StorageException @@ -2146,6 +2190,7 @@ public final StorageUri getQualifiedStorageUri() throws URISyntaxException, Stor * @throws URISyntaxException * If the resource URI is invalid. */ + @Deprecated public final URI getQualifiedUri() throws URISyntaxException, StorageException { if (this.isSnapshot()) { return PathUtility.addToQuery(this.getUri(), String.format("snapshot=%s", this.snapshotID)); diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudBlockBlob.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudBlockBlob.java index f8cd07e92d6f..301ca433e32a 100644 --- a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudBlockBlob.java +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudBlockBlob.java @@ -210,8 +210,14 @@ public final String startCopy(final CloudBlockBlob sourceBlob, final AccessCondi final AccessCondition destinationAccessCondition, BlobRequestOptions options, OperationContext opContext) throws StorageException, URISyntaxException { Utility.assertNotNull("sourceBlob", sourceBlob); - return this.startCopy( - sourceBlob.getQualifiedUri(), sourceAccessCondition, destinationAccessCondition, options, opContext); + + URI source = sourceBlob.getSnapshotQualifiedUri(); + if (sourceBlob.getServiceClient() != null && sourceBlob.getServiceClient().getCredentials() != null) + { + source = sourceBlob.getServiceClient().getCredentials().transformUri(sourceBlob.getSnapshotQualifiedUri()); + } + + return this.startCopy(source, sourceAccessCondition, destinationAccessCondition, options, opContext); } /** diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudPageBlob.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudPageBlob.java index 39be1c4ae3ad..79f6126139e9 100644 --- a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudPageBlob.java +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudPageBlob.java @@ -217,8 +217,14 @@ public final String startCopy(final CloudPageBlob sourceBlob, final AccessCondit final AccessCondition destinationAccessCondition, BlobRequestOptions options, OperationContext opContext) throws StorageException, URISyntaxException { Utility.assertNotNull("sourceBlob", sourceBlob); - return this.startCopy( - sourceBlob.getQualifiedUri(), sourceAccessCondition, destinationAccessCondition, options, opContext); + + URI source = sourceBlob.getSnapshotQualifiedUri(); + if (sourceBlob.getServiceClient() != null && sourceBlob.getServiceClient().getCredentials() != null) + { + source = sourceBlob.getServiceClient().getCredentials().transformUri(sourceBlob.getSnapshotQualifiedUri()); + } + + return this.startCopy(source, sourceAccessCondition, destinationAccessCondition, options, opContext); } /** diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/file/CloudFile.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/file/CloudFile.java index bc47e34ac8ec..3756841cecb3 100644 --- a/microsoft-azure-storage/src/com/microsoft/azure/storage/file/CloudFile.java +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/file/CloudFile.java @@ -352,8 +352,14 @@ public final String startCopy(final CloudBlob sourceBlob, final AccessCondition final AccessCondition destinationAccessCondition, FileRequestOptions options, OperationContext opContext) throws StorageException, URISyntaxException { Utility.assertNotNull("sourceBlob", sourceBlob); - return this.startCopy( - sourceBlob.getQualifiedUri(), sourceAccessCondition, destinationAccessCondition, options, opContext); + + URI source = sourceBlob.getSnapshotQualifiedUri(); + if (sourceBlob.getServiceClient() != null && sourceBlob.getServiceClient().getCredentials() != null) + { + source = sourceBlob.getServiceClient().getCredentials().transformUri(sourceBlob.getSnapshotQualifiedUri()); + } + + return this.startCopy(source, sourceAccessCondition, destinationAccessCondition, options, opContext); } /** From 35124bbf9d8770dc9649297c42ec162adca78e64 Mon Sep 17 00:00:00 2001 From: Ram B Date: Thu, 15 Dec 2016 08:24:22 -0800 Subject: [PATCH 11/11] Constant fixes + testcases fo range md5. --- .../storage/blob/CloudBlockBlobTests.java | 20 +++++++++++++++++++ .../azure/storage/file/CloudFileTests.java | 20 +++++++++++++++++++ .../microsoft/azure/storage/Constants.java | 7 ++++++- .../azure/storage/SubStreamGenerator.java | 14 +++++++++++++ .../azure/storage/blob/BlobRequest.java | 2 +- .../azure/storage/file/FileRequest.java | 2 +- 6 files changed, 62 insertions(+), 3 deletions(-) diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlockBlobTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlockBlobTests.java index 610ea85022aa..5115e01aa8c8 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlockBlobTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlockBlobTests.java @@ -1710,6 +1710,26 @@ public void testBlobConditionalAccess() throws StorageException, IOException, UR assertFalse("ETage should be modified on write metadata", newETag.equals(currentETag)); } + @Test + @Category({ DevFabricTests.class, DevStoreTests.class }) + public void testBlobGetRangeContentMD5Bounds() throws StorageException, IOException, URISyntaxException { + { + CloudBlockBlob blob = (CloudBlockBlob) BlobTestHelper.uploadNewBlob(this.container, BlobType.BLOCK_BLOB, + "test", 5 * Constants.MB, null); + BlobRequestOptions options = new BlobRequestOptions(); + OperationContext opContext = new OperationContext(); + try { + BlobRequest.getBlob(blob.getUri(), options, opContext, null, "", 0L, 4L * Constants.MB, true); + BlobRequest.getBlob(blob.getUri(), options, opContext, null, "", 0L, 4L * Constants.MB + 1, true); + fail("The request for range ContentMD5 should have thrown an Exception for exceeding the limit."); + } + catch (IllegalArgumentException e) + { + assertEquals(e.getMessage(), String.format("The value of the parameter 'count' should be between 1 and %1d.", Constants.MAX_RANGE_CONTENT_MD5)); + } + } + } + private void doUploadDownloadStringTest(CloudBlockBlob blob, int length) throws StorageException, IOException { String stringToUse = this.getRandomUNCString(length); blob.uploadText(stringToUse, Constants.UTF8_CHARSET, null, null, null); diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/CloudFileTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/CloudFileTests.java index 292ba7164385..9d165fb3a1e7 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/CloudFileTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/CloudFileTests.java @@ -1387,6 +1387,26 @@ public void testFileNamePlusEncoding() throws StorageException, URISyntaxExcepti assertEquals(prop1.getContentMD5(), prop2.getContentMD5()); assertEquals(prop1.getContentType(), prop2.getContentType()); } + + @Test + @Category({ DevFabricTests.class, DevStoreTests.class }) + public void testFileGetRangeContentMD5Bounds() throws StorageException, IOException, URISyntaxException { + { + CloudFile file = FileTestHelper.uploadNewFile(this.share, 5 * Constants.MB, null); + + FileRequestOptions options = new FileRequestOptions(); + OperationContext opContext = new OperationContext(); + try { + FileRequest.getFile(file.getUri(), options, opContext, null, 0L, 4L * Constants.MB, true); + FileRequest.getFile(file.getUri(), options, opContext, null, 0L, 4L * Constants.MB + 1, true); + fail("The request for range ContentMD5 should have thrown an Exception for exceeding the limit."); + } + catch (IllegalArgumentException e) + { + assertEquals(e.getMessage(), String.format("The value of the parameter 'count' should be between 1 and %1d.", Constants.MAX_RANGE_CONTENT_MD5)); + } + } + } private CloudFile doCloudBlobCopy(CloudBlob source, int length) throws Exception { Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("UTC")); diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/Constants.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/Constants.java index 82bb160ed7a5..bcf6b08c6ae7 100644 --- a/microsoft-azure-storage/src/com/microsoft/azure/storage/Constants.java +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/Constants.java @@ -1109,6 +1109,11 @@ public static class QueryConstants { */ public static final String MARKER_ELEMENT = "Marker"; + /** + * The maximum size for Range ContentMD5. + */ + public static int MAX_RANGE_CONTENT_MD5 = 4 * MB; + /** * The maximum size of a BlockBlob block. */ @@ -1167,7 +1172,7 @@ public static class QueryConstants { /** * The default minimum read size, in bytes, for a {@link BlobInputStream} or {@link FileInputStream}. */ - public static final int DEFAULT_MINIMUM_READ_SIZE_IN_BYTES = Constants.MAX_BLOCK_SIZE; + public static final int DEFAULT_MINIMUM_READ_SIZE_IN_BYTES = 4 * Constants.MB; /** * The maximum size, in bytes, of a given stream mark operation. diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/SubStreamGenerator.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/SubStreamGenerator.java index 2fb314c7c437..2fe8dd1d7701 100644 --- a/microsoft-azure-storage/src/com/microsoft/azure/storage/SubStreamGenerator.java +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/SubStreamGenerator.java @@ -1,3 +1,17 @@ +/** + * Copyright Microsoft Corporation + * + * Licensed 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 com.microsoft.azure.storage; import com.microsoft.azure.storage.blob.SubStream; diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobRequest.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobRequest.java index 904bfbd3ab89..84b0ec68b8a9 100644 --- a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobRequest.java +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobRequest.java @@ -489,7 +489,7 @@ public static HttpURLConnection getBlob(final URI uri, final BlobRequestOptions if (offset != null && requestRangeContentMD5) { Utility.assertNotNull("count", count); - Utility.assertInBounds("count", count, 1, Constants.MAX_BLOCK_SIZE); + Utility.assertInBounds("count", count, 1, Constants.MAX_RANGE_CONTENT_MD5); } final UriQueryBuilder builder = new UriQueryBuilder(); diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/file/FileRequest.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/file/FileRequest.java index c119ce899725..dc00aa6ccf87 100644 --- a/microsoft-azure-storage/src/com/microsoft/azure/storage/file/FileRequest.java +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/file/FileRequest.java @@ -350,7 +350,7 @@ public static HttpURLConnection getFile(final URI uri, final FileRequestOptions if (offset != null && requestRangeContentMD5) { Utility.assertNotNull("count", count); - Utility.assertInBounds("count", count, 1, Constants.MAX_BLOCK_SIZE); + Utility.assertInBounds("count", count, 1, Constants.MAX_RANGE_CONTENT_MD5); } final UriQueryBuilder builder = new UriQueryBuilder();