diff --git a/sdk/storage/azure-storage-blob/CHANGELOG.md b/sdk/storage/azure-storage-blob/CHANGELOG.md index 515a5db14bde..93f30a63b262 100644 --- a/sdk/storage/azure-storage-blob/CHANGELOG.md +++ b/sdk/storage/azure-storage-blob/CHANGELOG.md @@ -3,6 +3,7 @@ ## 12.13.0-beta.1 (Unreleased) - Added support to get a blob client that uses an encryption scope and customer provided key. - Added support for the 2020-10-02 service version. +- Added support to list blobs deleted with versioning enabled. - Added support to specify Parquet Input Serialization when querying a blob. ## 12.12.0 (2021-06-09) diff --git a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/implementation/util/ModelHelper.java b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/implementation/util/ModelHelper.java index 22c6f70adbf5..1516679aeba4 100644 --- a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/implementation/util/ModelHelper.java +++ b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/implementation/util/ModelHelper.java @@ -274,6 +274,8 @@ public static BlobItem populateBlobItem(BlobItemInternal blobItemInternal) { blobItem.setObjectReplicationSourcePolicies( transformObjectReplicationMetadata(blobItemInternal.getObjectReplicationMetadata())); + blobItem.setHasVersionsOnly(blobItemInternal.isHasVersionsOnly()); + return blobItem; } diff --git a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/models/BlobItem.java b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/models/BlobItem.java index 8d7f452f3738..c3b02028d4c1 100644 --- a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/models/BlobItem.java +++ b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/models/BlobItem.java @@ -70,6 +70,12 @@ public final class BlobItem { @JsonProperty(value = "IsPrefix") private Boolean isPrefix; + /* + * The HasVersionsOnly property. + */ + @JsonProperty(value = "HasVersionsOnly") + private Boolean hasVersionsOnly; + /** * Get the name property: The name property. * @@ -253,6 +259,26 @@ public BlobItem setObjectReplicationSourcePolicies(List return this; } + /** + * Get the hasVersionsOnly property: The HasVersionsOnly property. + * + * @return the hasVersionsOnly value. + */ + public Boolean hasVersionsOnly() { + return this.hasVersionsOnly; + } + + /** + * Set the hasVersionsOnly property: The HasVersionsOnly property. + * + * @param hasVersionsOnly the hasVersionsOnly value to set. + * @return the BlobItemInternal object itself. + */ + public BlobItem setHasVersionsOnly(Boolean hasVersionsOnly) { + this.hasVersionsOnly = hasVersionsOnly; + return this; + } + /** * Get the isPrefix property: The isPrefix property. * diff --git a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/models/BlobListDetails.java b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/models/BlobListDetails.java index 044dd4ac6e66..6a19f9c7c769 100644 --- a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/models/BlobListDetails.java +++ b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/models/BlobListDetails.java @@ -23,6 +23,7 @@ public final class BlobListDetails { private boolean retrieveUncommittedBlobs; private boolean retrieveDeletedBlobs; private boolean retrieveVersions; + private boolean retrieveDeletedWithVersions; private boolean retrieveImmutabilityPolicy; private boolean retrieveLegalHold; @@ -174,6 +175,26 @@ public BlobListDetails setRetrieveDeletedBlobs(boolean retrieveDeletedBlobs) { return this; } + /** + * Whether blobs which have been deleted with versioning. + * + * @return a flag indicating if deleted blobs with versioning will be returned in the listing + */ + public boolean getRetrieveDeletedBlobsWithVersions() { + return retrieveDeletedWithVersions; + } + + /** + * Whether blobs which have been deleted with versioning should be returned. + * + * @param retrieveDeletedWithVersions Flag indicating whether deleted blobs with versioning should be returned + * @return the updated BlobListDetails object + */ + public BlobListDetails setRetrieveDeletedBlobsWithVersions(boolean retrieveDeletedWithVersions) { + this.retrieveDeletedWithVersions = retrieveDeletedWithVersions; + return this; + } + /** * Whether immutability policy for the blob should be returned. * @@ -240,6 +261,9 @@ public ArrayList toList() { if (this.retrieveVersions) { details.add(ListBlobsIncludeItem.VERSIONS); } + if (this.retrieveDeletedWithVersions) { + details.add(ListBlobsIncludeItem.DELETEDWITHVERSIONS); + } if (this.retrieveImmutabilityPolicy) { details.add(ListBlobsIncludeItem.IMMUTABILITYPOLICY); } diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/ContainerAPITest.groovy b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/ContainerAPITest.groovy index ebdcddea4d7d..bd09796bc6c3 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/ContainerAPITest.groovy +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/ContainerAPITest.groovy @@ -3,15 +3,13 @@ package com.azure.storage.blob -import com.azure.core.http.rest.PagedIterable -import com.azure.core.http.rest.PagedResponse + import com.azure.core.http.rest.Response import com.azure.identity.DefaultAzureCredentialBuilder import com.azure.storage.blob.models.AccessTier import com.azure.storage.blob.models.AppendBlobItem import com.azure.storage.blob.models.BlobAccessPolicy import com.azure.storage.blob.models.BlobErrorCode -import com.azure.storage.blob.models.BlobItem import com.azure.storage.blob.models.BlobListDetails import com.azure.storage.blob.models.BlobProperties import com.azure.storage.blob.models.BlobRequestConditions @@ -31,14 +29,10 @@ import com.azure.storage.blob.options.BlobSetAccessTierOptions import com.azure.storage.blob.options.PageBlobCreateOptions import com.azure.storage.blob.specialized.AppendBlobClient import com.azure.storage.blob.specialized.BlobClientBase -import com.azure.storage.common.StorageSharedKeyCredential import com.azure.storage.common.Utility -import com.azure.storage.common.implementation.StorageImplUtils import com.azure.storage.common.test.shared.extensions.PlaybackOnly import com.azure.storage.common.test.shared.extensions.RequiredServiceVersion import reactor.test.StepVerifier -import spock.lang.Requires -import spock.lang.ResourceLock import spock.lang.Unroll import java.time.Duration @@ -921,6 +915,29 @@ class ContainerAPITest extends APISpec { .verifyComplete() } + @RequiredServiceVersion(clazz = BlobServiceVersion.class, min = "V2020_10_02") + def "list blobs flat options deleted with versions"() { + setup: + def blobName = generateBlobName() + def blob = cc.getBlobClient(blobName).getAppendBlobClient() + blob.create() + def metadata = new HashMap() + metadata.put("foo", "bar") + blob.setMetadata(metadata) + blob.delete() + def options = new ListBlobsOptions().setPrefix(blobName) + .setDetails(new BlobListDetails().setRetrieveDeletedBlobsWithVersions(true)) + + when: + def blobs = cc.listBlobs(options, null).iterator() + + then: + def b = blobs.next() + !blobs.hasNext() + b.getName() == blobName + b.hasVersionsOnly() + } + def "List blobs prefix with comma"() { setup: def prefix = generateBlobName() + ", " + generateBlobName() @@ -1303,6 +1320,29 @@ class ContainerAPITest extends APISpec { } } + @RequiredServiceVersion(clazz = BlobServiceVersion.class, min = "V2020_10_02") + def "list blobs hier options deleted with versions"() { + setup: + def blobName = generateBlobName() + def blob = cc.getBlobClient(blobName).getAppendBlobClient() + blob.create() + def metadata = new HashMap() + metadata.put("foo", "bar") + blob.setMetadata(metadata) + blob.delete() + def options = new ListBlobsOptions().setPrefix(blobName) + .setDetails(new BlobListDetails().setRetrieveDeletedBlobsWithVersions(true)) + + when: + def blobs = cc.listBlobsByHierarchy("", options, null).iterator() + + then: + def b = blobs.next() + !blobs.hasNext() + b.getName() == blobName + b.hasVersionsOnly() + } + @Unroll def "List blobs hier options fail"() { when: diff --git a/sdk/storage/azure-storage-blob/src/test/resources/session-records/ContainerAPITestListBlobsFlatOptionsDeletedWithVersions.json b/sdk/storage/azure-storage-blob/src/test/resources/session-records/ContainerAPITestListBlobsFlatOptionsDeletedWithVersions.json new file mode 100644 index 000000000000..556128b6e9ad --- /dev/null +++ b/sdk/storage/azure-storage-blob/src/test/resources/session-records/ContainerAPITestListBlobsFlatOptionsDeletedWithVersions.json @@ -0,0 +1,112 @@ +{ + "networkCallRecords" : [ { + "Method" : "PUT", + "Uri" : "https://REDACTED.blob.core.windows.net/8295186e08295186e76780860dbc07e929472486d90d?restype=container", + "Headers" : { + "x-ms-version" : "2020-10-02", + "User-Agent" : "azsdk-java-azure-storage-blob/12.12.0-beta.2 (11.0.7; Windows 10; 10.0)", + "x-ms-client-request-id" : "230a2772-1c69-4408-9f21-2424e9a84d78" + }, + "Response" : { + "content-length" : "0", + "x-ms-version" : "2020-10-02", + "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", + "eTag" : "0x8D9252E3D6FD9CB", + "Last-Modified" : "Tue, 01 Jun 2021 18:51:17 GMT", + "retry-after" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "6d10ded9-c01e-0014-6917-5792ad000000", + "x-ms-client-request-id" : "230a2772-1c69-4408-9f21-2424e9a84d78", + "Date" : "Tue, 01 Jun 2021 18:51:17 GMT" + }, + "Exception" : null + }, { + "Method" : "PUT", + "Uri" : "https://REDACTED.blob.core.windows.net/8295186e08295186e76780860dbc07e929472486d90d/8295186e18295186e767817414aac029851164b3b9b8", + "Headers" : { + "x-ms-version" : "2020-10-02", + "User-Agent" : "azsdk-java-azure-storage-blob/12.12.0-beta.2 (11.0.7; Windows 10; 10.0)", + "x-ms-client-request-id" : "4c66d24b-834b-4a3f-845f-996c3121ba78" + }, + "Response" : { + "content-length" : "0", + "x-ms-version" : "2020-10-02", + "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", + "eTag" : "0x8D9252E3DB29E26", + "Last-Modified" : "Tue, 01 Jun 2021 18:51:18 GMT", + "x-ms-version-id" : "2021-06-01T18:51:18.3475238Z", + "retry-after" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "6d10dfab-c01e-0014-5c17-5792ad000000", + "x-ms-request-server-encrypted" : "true", + "x-ms-client-request-id" : "4c66d24b-834b-4a3f-845f-996c3121ba78", + "Date" : "Tue, 01 Jun 2021 18:51:18 GMT" + }, + "Exception" : null + }, { + "Method" : "PUT", + "Uri" : "https://REDACTED.blob.core.windows.net/8295186e08295186e76780860dbc07e929472486d90d/8295186e18295186e767817414aac029851164b3b9b8?comp=metadata", + "Headers" : { + "x-ms-version" : "2020-10-02", + "User-Agent" : "azsdk-java-azure-storage-blob/12.12.0-beta.2 (11.0.7; Windows 10; 10.0)", + "x-ms-client-request-id" : "eb48934a-df4c-47bf-90c5-945199f73eb1" + }, + "Response" : { + "content-length" : "0", + "x-ms-version" : "2020-10-02", + "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", + "eTag" : "0x8D9252E3DCCBA9B", + "Last-Modified" : "Tue, 01 Jun 2021 18:51:18 GMT", + "x-ms-version-id" : "2021-06-01T18:51:18.5196459Z", + "retry-after" : "0", + "StatusCode" : "200", + "x-ms-request-id" : "6d10dfdc-c01e-0014-7c17-5792ad000000", + "x-ms-request-server-encrypted" : "true", + "x-ms-client-request-id" : "eb48934a-df4c-47bf-90c5-945199f73eb1", + "Date" : "Tue, 01 Jun 2021 18:51:18 GMT" + }, + "Exception" : null + }, { + "Method" : "DELETE", + "Uri" : "https://REDACTED.blob.core.windows.net/8295186e08295186e76780860dbc07e929472486d90d/8295186e18295186e767817414aac029851164b3b9b8", + "Headers" : { + "x-ms-version" : "2020-10-02", + "User-Agent" : "azsdk-java-azure-storage-blob/12.12.0-beta.2 (11.0.7; Windows 10; 10.0)", + "x-ms-client-request-id" : "6d85a718-b07e-4d6e-ac99-3b622bdf53b3" + }, + "Response" : { + "content-length" : "0", + "x-ms-version" : "2020-10-02", + "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-delete-type-permanent" : "false", + "retry-after" : "0", + "StatusCode" : "202", + "x-ms-request-id" : "6d10e00a-c01e-0014-1317-5792ad000000", + "x-ms-client-request-id" : "6d85a718-b07e-4d6e-ac99-3b622bdf53b3", + "Date" : "Tue, 01 Jun 2021 18:51:18 GMT" + }, + "Exception" : null + }, { + "Method" : "GET", + "Uri" : "https://REDACTED.blob.core.windows.net/8295186e08295186e76780860dbc07e929472486d90d?restype=container&comp=list&prefix=8295186e18295186e767817414aac029851164b3b9b8&include=deletedwithversions", + "Headers" : { + "x-ms-version" : "2020-10-02", + "User-Agent" : "azsdk-java-azure-storage-blob/12.12.0-beta.2 (11.0.7; Windows 10; 10.0)", + "x-ms-client-request-id" : "7bf450cd-e0d3-45a1-b672-6e34f25fa9d2" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2020-10-02", + "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "StatusCode" : "200", + "x-ms-request-id" : "6d10e03a-c01e-0014-2a17-5792ad000000", + "Body" : "8295186e18295186e767817414aac029851164b3b9b88295186e18295186e767817414aac029851164b3b9b8trueTue, 01 Jun 2021 18:51:18 GMTTue, 01 Jun 2021 18:51:18 GMT0x8D9252E3DCCBA9B0application/octet-streamAppendBlobunlockedavailabletrue", + "x-ms-client-request-id" : "7bf450cd-e0d3-45a1-b672-6e34f25fa9d2", + "Date" : "Tue, 01 Jun 2021 18:51:18 GMT", + "Content-Type" : "application/xml" + }, + "Exception" : null + } ], + "variables" : [ "8295186e08295186e76780860dbc07e929472486d90d", "8295186e18295186e767817414aac029851164b3b9b8" ] +} \ No newline at end of file diff --git a/sdk/storage/azure-storage-blob/src/test/resources/session-records/ContainerAPITestListBlobsHierOptionsDeletedWithVersions.json b/sdk/storage/azure-storage-blob/src/test/resources/session-records/ContainerAPITestListBlobsHierOptionsDeletedWithVersions.json new file mode 100644 index 000000000000..62ca418c4b0a --- /dev/null +++ b/sdk/storage/azure-storage-blob/src/test/resources/session-records/ContainerAPITestListBlobsHierOptionsDeletedWithVersions.json @@ -0,0 +1,112 @@ +{ + "networkCallRecords" : [ { + "Method" : "PUT", + "Uri" : "https://REDACTED.blob.core.windows.net/bd465e190bd465e19dd42664791b7d0f52cdc4260b90?restype=container", + "Headers" : { + "x-ms-version" : "2020-10-02", + "User-Agent" : "azsdk-java-azure-storage-blob/12.12.0-beta.2 (11.0.7; Windows 10; 10.0)", + "x-ms-client-request-id" : "13f95fba-b06f-4ac1-8f87-41bbd13d6845" + }, + "Response" : { + "content-length" : "0", + "x-ms-version" : "2020-10-02", + "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", + "eTag" : "0x8D9252E2EEF2C55", + "Last-Modified" : "Tue, 01 Jun 2021 18:50:53 GMT", + "retry-after" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "c1d30bd1-e01e-0013-0717-57fece000000", + "x-ms-client-request-id" : "13f95fba-b06f-4ac1-8f87-41bbd13d6845", + "Date" : "Tue, 01 Jun 2021 18:50:52 GMT" + }, + "Exception" : null + }, { + "Method" : "PUT", + "Uri" : "https://REDACTED.blob.core.windows.net/bd465e190bd465e19dd42664791b7d0f52cdc4260b90/bd465e191bd465e19dd460231e493f5fe94664b838a3", + "Headers" : { + "x-ms-version" : "2020-10-02", + "User-Agent" : "azsdk-java-azure-storage-blob/12.12.0-beta.2 (11.0.7; Windows 10; 10.0)", + "x-ms-client-request-id" : "06615617-d81d-4083-9358-a120d707f7ef" + }, + "Response" : { + "content-length" : "0", + "x-ms-version" : "2020-10-02", + "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", + "eTag" : "0x8D9252E2F317F9E", + "Last-Modified" : "Tue, 01 Jun 2021 18:50:54 GMT", + "x-ms-version-id" : "2021-06-01T18:50:54.0132254Z", + "retry-after" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "c1d30c55-e01e-0013-7217-57fece000000", + "x-ms-request-server-encrypted" : "true", + "x-ms-client-request-id" : "06615617-d81d-4083-9358-a120d707f7ef", + "Date" : "Tue, 01 Jun 2021 18:50:53 GMT" + }, + "Exception" : null + }, { + "Method" : "PUT", + "Uri" : "https://REDACTED.blob.core.windows.net/bd465e190bd465e19dd42664791b7d0f52cdc4260b90/bd465e191bd465e19dd460231e493f5fe94664b838a3?comp=metadata", + "Headers" : { + "x-ms-version" : "2020-10-02", + "User-Agent" : "azsdk-java-azure-storage-blob/12.12.0-beta.2 (11.0.7; Windows 10; 10.0)", + "x-ms-client-request-id" : "0638132e-5519-4644-96f2-fca545f7f3cf" + }, + "Response" : { + "content-length" : "0", + "x-ms-version" : "2020-10-02", + "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", + "eTag" : "0x8D9252E2F4112D8", + "Last-Modified" : "Tue, 01 Jun 2021 18:50:54 GMT", + "x-ms-version-id" : "2021-06-01T18:50:54.1172991Z", + "retry-after" : "0", + "StatusCode" : "200", + "x-ms-request-id" : "c1d30c8d-e01e-0013-2417-57fece000000", + "x-ms-request-server-encrypted" : "true", + "x-ms-client-request-id" : "0638132e-5519-4644-96f2-fca545f7f3cf", + "Date" : "Tue, 01 Jun 2021 18:50:53 GMT" + }, + "Exception" : null + }, { + "Method" : "DELETE", + "Uri" : "https://REDACTED.blob.core.windows.net/bd465e190bd465e19dd42664791b7d0f52cdc4260b90/bd465e191bd465e19dd460231e493f5fe94664b838a3", + "Headers" : { + "x-ms-version" : "2020-10-02", + "User-Agent" : "azsdk-java-azure-storage-blob/12.12.0-beta.2 (11.0.7; Windows 10; 10.0)", + "x-ms-client-request-id" : "e8931cba-3b55-40cd-ae18-2f6a0db7f608" + }, + "Response" : { + "content-length" : "0", + "x-ms-version" : "2020-10-02", + "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-delete-type-permanent" : "false", + "retry-after" : "0", + "StatusCode" : "202", + "x-ms-request-id" : "c1d30cc2-e01e-0013-5417-57fece000000", + "x-ms-client-request-id" : "e8931cba-3b55-40cd-ae18-2f6a0db7f608", + "Date" : "Tue, 01 Jun 2021 18:50:53 GMT" + }, + "Exception" : null + }, { + "Method" : "GET", + "Uri" : "https://REDACTED.blob.core.windows.net/bd465e190bd465e19dd42664791b7d0f52cdc4260b90?restype=container&comp=list&prefix=bd465e191bd465e19dd460231e493f5fe94664b838a3&delimiter=&include=deletedwithversions", + "Headers" : { + "x-ms-version" : "2020-10-02", + "User-Agent" : "azsdk-java-azure-storage-blob/12.12.0-beta.2 (11.0.7; Windows 10; 10.0)", + "x-ms-client-request-id" : "d0616405-0176-47cd-9682-76988c45dfdc" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2020-10-02", + "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "StatusCode" : "200", + "x-ms-request-id" : "c1d30cfd-e01e-0013-0217-57fece000000", + "Body" : "bd465e191bd465e19dd460231e493f5fe94664b838a3bd465e191bd465e19dd460231e493f5fe94664b838a3trueTue, 01 Jun 2021 18:50:54 GMTTue, 01 Jun 2021 18:50:54 GMT0x8D9252E2F4112D80application/octet-streamAppendBlobunlockedavailabletrue", + "x-ms-client-request-id" : "d0616405-0176-47cd-9682-76988c45dfdc", + "Date" : "Tue, 01 Jun 2021 18:50:53 GMT", + "Content-Type" : "application/xml" + }, + "Exception" : null + } ], + "variables" : [ "bd465e190bd465e19dd42664791b7d0f52cdc4260b90", "bd465e191bd465e19dd460231e493f5fe94664b838a3" ] +} \ No newline at end of file