From 4527798bd1fc0cf0687fe35eda912b9d458b61a6 Mon Sep 17 00:00:00 2001 From: JinmingHu Date: Mon, 11 Jan 2021 15:13:49 +0800 Subject: [PATCH] Remove blob batch (#1309) --- sdk/storage/azure-storage-blobs/CHANGELOG.md | 1 + .../azure-storage-blobs/CMakeLists.txt | 3 - .../inc/azure/storage/blobs.hpp | 1 - .../azure/storage/blobs/blob_batch_client.hpp | 170 ------- .../src/blob_batch_client.cpp | 432 ------------------ .../test/blob_batch_client_test.cpp | 152 ------ 6 files changed, 1 insertion(+), 758 deletions(-) delete mode 100644 sdk/storage/azure-storage-blobs/inc/azure/storage/blobs/blob_batch_client.hpp delete mode 100644 sdk/storage/azure-storage-blobs/src/blob_batch_client.cpp delete mode 100644 sdk/storage/azure-storage-blobs/test/blob_batch_client_test.cpp diff --git a/sdk/storage/azure-storage-blobs/CHANGELOG.md b/sdk/storage/azure-storage-blobs/CHANGELOG.md index 74daf7821..d05a08daf 100644 --- a/sdk/storage/azure-storage-blobs/CHANGELOG.md +++ b/sdk/storage/azure-storage-blobs/CHANGELOG.md @@ -65,6 +65,7 @@ - Continuation token of result types are changed to nullable. - Rename `Models::DeleteSnapshotsOption::Only` to `Models::DeleteSnapshotsOption::OnlySnapshots`. - Rename `SourceConditions` in API options to `SourceAccessConditions`. +- Remove Blob Batch. ## 12.0.0-beta.5 (2020-11-13) diff --git a/sdk/storage/azure-storage-blobs/CMakeLists.txt b/sdk/storage/azure-storage-blobs/CMakeLists.txt index 2c585fbec..d886a149f 100644 --- a/sdk/storage/azure-storage-blobs/CMakeLists.txt +++ b/sdk/storage/azure-storage-blobs/CMakeLists.txt @@ -30,7 +30,6 @@ set( AZURE_STORAGE_BLOB_HEADER inc/azure/storage/blobs/protocol/blob_rest_client.hpp inc/azure/storage/blobs/append_blob_client.hpp - inc/azure/storage/blobs/blob_batch_client.hpp inc/azure/storage/blobs/blob_client.hpp inc/azure/storage/blobs/blob_container_client.hpp inc/azure/storage/blobs/blob_options.hpp @@ -46,7 +45,6 @@ set( set( AZURE_STORAGE_BLOB_SOURCE src/append_blob_client.cpp - src/blob_batch_client.cpp src/blob_client.cpp src/blob_container_client.cpp src/blob_rest_client.cpp @@ -84,7 +82,6 @@ if(BUILD_TESTING) PRIVATE test/append_blob_client_test.cpp test/append_blob_client_test.hpp - test/blob_batch_client_test.cpp test/blob_container_client_test.cpp test/blob_container_client_test.hpp test/blob_sas_test.cpp diff --git a/sdk/storage/azure-storage-blobs/inc/azure/storage/blobs.hpp b/sdk/storage/azure-storage-blobs/inc/azure/storage/blobs.hpp index 6f88fe282..0c4808dc7 100644 --- a/sdk/storage/azure-storage-blobs/inc/azure/storage/blobs.hpp +++ b/sdk/storage/azure-storage-blobs/inc/azure/storage/blobs.hpp @@ -4,7 +4,6 @@ #pragma once #include "azure/storage/blobs/append_blob_client.hpp" -#include "azure/storage/blobs/blob_batch_client.hpp" #include "azure/storage/blobs/blob_client.hpp" #include "azure/storage/blobs/blob_container_client.hpp" #include "azure/storage/blobs/blob_sas_builder.hpp" diff --git a/sdk/storage/azure-storage-blobs/inc/azure/storage/blobs/blob_batch_client.hpp b/sdk/storage/azure-storage-blobs/inc/azure/storage/blobs/blob_batch_client.hpp deleted file mode 100644 index e9ba4bda1..000000000 --- a/sdk/storage/azure-storage-blobs/inc/azure/storage/blobs/blob_batch_client.hpp +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// SPDX-License-Identifier: MIT - -#pragma once - -#include -#include -#include -#include - -#include "azure/storage/blobs/blob_service_client.hpp" - -namespace Azure { namespace Storage { namespace Blobs { - - /** - * @brief A BlobBatch allows you to batch multiple Azure Storage operations in a single request - * via BlobBatchClient.SubmitBatch. - */ - class BlobBatch { - public: - /** - * @brief Marks the specified blob or snapshot for deletion. - * - * @param blobContainerName The name of the container containing the blob to delete. - * @param blobName - * The name of the blob to delete. - * @param options Optional parameters to execute this - * function. - * @return An index of this operation result in - * SubmitBlobBatchResult.DeleteBlobResults, after this batch is submitted via - * BlobBatchClient.SubmitBatch. - */ - int32_t DeleteBlob( - const std::string& blobContainerName, - const std::string& blobName, - const DeleteBlobOptions& options = DeleteBlobOptions()); - - /** - * @brief Sets the tier on a blob. - * - * @param blobContainerName The name of the - * container containing the blob to set the tier of. - * @param blobName The name of the blob - * to set the tier of. - * @param tier Indicates the tier to be set on the blob. - * - * @param options Optional parameters to execute this function. - * @return An index of this - * operation result in SubmitBlobBatchResult.SetBlobAccessTierResults, after this batch is - * submitted via BlobBatchClient.SubmitBatch. - */ - int32_t SetBlobAccessTier( - const std::string& blobContainerName, - const std::string& blobName, - Models::AccessTier tier, - const SetBlobAccessTierOptions& options = SetBlobAccessTierOptions()); - - private: - friend class BlobBatchClient; - - struct DeleteBlobSubRequest - { - std::string BlobContainerName; - std::string BlobName; - DeleteBlobOptions Options; - }; - - struct SetBlobAccessTierSubRequest - { - std::string BlobContainerName; - std::string BlobName; - Models::AccessTier Tier; - SetBlobAccessTierOptions Options; - }; - - std::vector m_deleteBlobSubRequests; - std::vector m_setBlobAccessTierSubRequests; - }; - - struct SubmitBlobBatchResult - { - std::vector> DeleteBlobResults; - std::vector> SetBlobAccessTierResults; - }; - - /** - * @brief The BlobBatchClient allows you to batch multiple Azure Storage operations in a - * single request. - */ - class BlobBatchClient { - public: - /** - * @brief Initialize a new instance of BlobBatchClient. - * - * @param connectionString A connection string includes the authentication information required - * for your application to access data in an Azure Storage account at runtime. - * @param options Optional client options that define the transport pipeline policies for - * authentication, retries, etc., that are applied to every request and subrequest. - * @return A new BlobBatchClient instance. - */ - static BlobBatchClient CreateFromConnectionString( - const std::string& connectionString, - const BlobClientOptions& options = BlobClientOptions()); - - /** - * @brief Initialize a new instance of BlobBatchClient. - * - * @param serviceUrl A url referencing the blob that includes the name of the account. - * @param credential The shared key credential used to sign requests. - * @param options Optional client options that define the transport pipeline policies for - * authentication, retries, etc., that are applied to every request and subrequest. - */ - explicit BlobBatchClient( - const std::string& serviceUrl, - std::shared_ptr credential, - const BlobClientOptions& options = BlobClientOptions()); - - /** - * @brief Initialize a new instance of BlobBatchClient. - * - * @param serviceUrl A url referencing the blob that includes the name of the account. - * @param credential The token credential used to sign requests. - * @param options Optional client options that define the transport pipeline policies for - * authentication, retries, etc., that are applied to every request and subrequest. - */ - explicit BlobBatchClient( - const std::string& serviceUrl, - std::shared_ptr credential, - const BlobClientOptions& options = BlobClientOptions()); - - /** - * @brief Initialize a new instance of BlobBatchClient. - * - * @param serviceUrl A url referencing the blob that includes the name of the account, and - * possibly also a SAS token. - * @param options Optional client options that define the transport pipeline policies for - * authentication, retries, etc., that are applied to every request and subrequest. - */ - explicit BlobBatchClient( - const std::string& serviceUrl, - const BlobClientOptions& options = BlobClientOptions()); - - /** - * @brief Creates a new BlobBatch to collect sub-operations that can be submitted - * together via SubmitBatch. - * - * @return A new instance of BlobBatch. - */ - static BlobBatch CreateBatch() { return BlobBatch(); } - - /** - * @brief Submit a BlobBatch of sub-operations. - * - * @param batch A BlobBatch - * of sub-operations. - * @param options Optional parameters to execute this function. - * - * @return A SubmitBlobBatchResult on successful submitting. - */ - Azure::Core::Response SubmitBatch( - const BlobBatch& batch, - const SubmitBlobBatchOptions& options = SubmitBlobBatchOptions()) const; - - protected: - Azure::Core::Http::Url m_serviceUrl; - std::shared_ptr m_pipeline; - std::shared_ptr m_subRequestPipeline; - }; - -}}} // namespace Azure::Storage::Blobs diff --git a/sdk/storage/azure-storage-blobs/src/blob_batch_client.cpp b/sdk/storage/azure-storage-blobs/src/blob_batch_client.cpp deleted file mode 100644 index d2bcc20fd..000000000 --- a/sdk/storage/azure-storage-blobs/src/blob_batch_client.cpp +++ /dev/null @@ -1,432 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// SPDX-License-Identifier: MIT - -#include "azure/storage/blobs/blob_batch_client.hpp" - -#include -#include - -#include -#include -#include -#include - -#include "azure/storage/blobs/version.hpp" - -namespace Azure { namespace Storage { namespace Blobs { - - namespace { - class NoopTransportPolicy : public Core::Http::HttpPolicy { - public: - ~NoopTransportPolicy() override {} - - std::unique_ptr Clone() const override - { - return std::make_unique(*this); - } - - std::unique_ptr Send( - Core::Context const& context, - Core::Http::Request& request, - Core::Http::NextHttpPolicy nextHttpPolicy) const override - { - unused(context, request, nextHttpPolicy); - return std::unique_ptr(); - } - }; - } // namespace - - int32_t BlobBatch::DeleteBlob( - const std::string& blobContainerName, - const std::string& blobName, - const DeleteBlobOptions& options) - { - DeleteBlobSubRequest operation; - operation.BlobContainerName = blobContainerName; - operation.BlobName = blobName; - operation.Options = options; - m_deleteBlobSubRequests.emplace_back(std::move(operation)); - return static_cast(m_deleteBlobSubRequests.size() - 1); - } - - int32_t BlobBatch::SetBlobAccessTier( - const std::string& blobContainerName, - const std::string& blobName, - Models::AccessTier tier, - const SetBlobAccessTierOptions& options) - { - SetBlobAccessTierSubRequest operation; - operation.BlobContainerName = blobContainerName; - operation.BlobName = blobName; - operation.Options = options; - operation.Tier = tier; - m_setBlobAccessTierSubRequests.emplace_back(std::move(operation)); - return static_cast(m_setBlobAccessTierSubRequests.size() - 1); - } - - BlobBatchClient BlobBatchClient::CreateFromConnectionString( - const std::string& connectionString, - const BlobClientOptions& options) - { - auto parsedConnectionString = Storage::Details::ParseConnectionString(connectionString); - auto serviceUrl = std::move(parsedConnectionString.BlobServiceUrl); - - if (parsedConnectionString.KeyCredential) - { - return BlobBatchClient( - serviceUrl.GetAbsoluteUrl(), parsedConnectionString.KeyCredential, options); - } - else - { - return BlobBatchClient(serviceUrl.GetAbsoluteUrl(), options); - } - } - - BlobBatchClient::BlobBatchClient( - const std::string& serviceUrl, - std::shared_ptr credential, - const BlobClientOptions& options) - : m_serviceUrl(serviceUrl) - { - std::vector> policies; - policies.emplace_back(std::make_unique( - Storage::Details::BlobServicePackageName, Details::Version::VersionString())); - policies.emplace_back(std::make_unique()); - for (const auto& p : options.PerOperationPolicies) - { - policies.emplace_back(p->Clone()); - } - policies.emplace_back( - std::make_unique(options.RetryOptions)); - for (const auto& p : options.PerRetryPolicies) - { - policies.emplace_back(p->Clone()); - } - policies.emplace_back(std::make_unique()); - policies.emplace_back(std::make_unique(credential)); - policies.emplace_back( - std::make_unique(options.TransportPolicyOptions)); - m_pipeline = std::make_shared(policies); - - policies.clear(); - for (const auto& p : options.PerOperationPolicies) - { - policies.emplace_back(p->Clone()); - } - for (const auto& p : options.PerRetryPolicies) - { - policies.emplace_back(p->Clone()); - } - policies.emplace_back(std::make_unique()); - policies.emplace_back(std::make_unique(credential)); - policies.emplace_back(std::make_unique()); - m_subRequestPipeline = std::make_shared(policies); - } - - BlobBatchClient::BlobBatchClient( - const std::string& serviceUrl, - std::shared_ptr credential, - const BlobClientOptions& options) - : m_serviceUrl(serviceUrl) - { - std::vector> policies; - policies.emplace_back(std::make_unique( - Storage::Details::BlobServicePackageName, Details::Version::VersionString())); - policies.emplace_back(std::make_unique()); - for (const auto& p : options.PerOperationPolicies) - { - policies.emplace_back(p->Clone()); - } - policies.emplace_back( - std::make_unique(options.RetryOptions)); - for (const auto& p : options.PerRetryPolicies) - { - policies.emplace_back(p->Clone()); - } - policies.emplace_back(std::make_unique()); - policies.emplace_back(std::make_unique( - credential, Storage::Details::StorageScope)); - policies.emplace_back( - std::make_unique(options.TransportPolicyOptions)); - m_pipeline = std::make_shared(policies); - - policies.clear(); - for (const auto& p : options.PerOperationPolicies) - { - policies.emplace_back(p->Clone()); - } - for (const auto& p : options.PerRetryPolicies) - { - policies.emplace_back(p->Clone()); - } - policies.emplace_back(std::make_unique()); - policies.emplace_back(std::make_unique( - credential, Storage::Details::StorageScope)); - policies.emplace_back(std::make_unique()); - m_subRequestPipeline = std::make_shared(policies); - } - - BlobBatchClient::BlobBatchClient(const std::string& serviceUrl, const BlobClientOptions& options) - : m_serviceUrl(serviceUrl) - { - std::vector> policies; - policies.emplace_back(std::make_unique( - Storage::Details::BlobServicePackageName, Details::Version::VersionString())); - policies.emplace_back(std::make_unique()); - for (const auto& p : options.PerOperationPolicies) - { - policies.emplace_back(p->Clone()); - } - policies.emplace_back( - std::make_unique(options.RetryOptions)); - for (const auto& p : options.PerRetryPolicies) - { - policies.emplace_back(p->Clone()); - } - policies.emplace_back(std::make_unique()); - policies.emplace_back( - std::make_unique(options.TransportPolicyOptions)); - m_pipeline = std::make_shared(policies); - - policies.clear(); - for (const auto& p : options.PerOperationPolicies) - { - policies.emplace_back(p->Clone()); - } - for (const auto& p : options.PerRetryPolicies) - { - policies.emplace_back(p->Clone()); - } - policies.emplace_back(std::make_unique()); - policies.emplace_back(std::make_unique()); - m_subRequestPipeline = std::make_shared(policies); - } - - Azure::Core::Response BlobBatchClient::SubmitBatch( - const BlobBatch& batch, - const SubmitBlobBatchOptions& options) const - { - const std::string LineEnding = "\r\n"; - const std::string ContentTypePrefix = "multipart/mixed; boundary="; - - std::string boundary = "batch_" + Azure::Core::Uuid::CreateUuid().GetUuidString(); - - enum class RequestType - { - DeleteBlob, - SetBlobAccessTier, - }; - - std::vector requestTypes; - - std::string requestBody; - { - auto getBatchBoundary = [&LineEnding, &boundary, subRequestCounter = 0]() mutable { - std::string ret; - ret += "--" + boundary + LineEnding; - ret += "Content-Type: application/http" + LineEnding + "Content-Transfer-Encoding: binary" - + LineEnding + "Content-ID: " + std::to_string(subRequestCounter++) + LineEnding - + LineEnding; - return ret; - }; - for (const auto& subrequest : batch.m_deleteBlobSubRequests) - { - requestTypes.emplace_back(RequestType::DeleteBlob); - - requestBody += getBatchBoundary(); - - auto blobUrl = m_serviceUrl; - blobUrl.AppendPath(Storage::Details::UrlEncodePath(subrequest.BlobContainerName)); - blobUrl.AppendPath(Storage::Details::UrlEncodePath(subrequest.BlobName)); - Details::BlobRestClient::Blob::DeleteBlobOptions protocolLayerOptions; - protocolLayerOptions.DeleteSnapshots = subrequest.Options.DeleteSnapshots; - protocolLayerOptions.IfModifiedSince = subrequest.Options.AccessConditions.IfModifiedSince; - protocolLayerOptions.IfUnmodifiedSince - = subrequest.Options.AccessConditions.IfUnmodifiedSince; - protocolLayerOptions.IfMatch = subrequest.Options.AccessConditions.IfMatch; - protocolLayerOptions.IfNoneMatch = subrequest.Options.AccessConditions.IfNoneMatch; - protocolLayerOptions.LeaseId = subrequest.Options.AccessConditions.LeaseId; - auto message - = Details::BlobRestClient::Blob::DeleteCreateMessage(blobUrl, protocolLayerOptions); - message.RemoveHeader(Storage::Details::HttpHeaderXMsVersion); - m_subRequestPipeline->Send(options.Context, message); - requestBody += message.GetHTTPMessagePreBody(); - } - for (const auto& subrequest : batch.m_setBlobAccessTierSubRequests) - { - requestTypes.emplace_back(RequestType::SetBlobAccessTier); - - requestBody += getBatchBoundary(); - - auto blobUrl = m_serviceUrl; - blobUrl.AppendPath(Storage::Details::UrlEncodePath(subrequest.BlobContainerName)); - blobUrl.AppendPath(Storage::Details::UrlEncodePath(subrequest.BlobName)); - Details::BlobRestClient::Blob::SetBlobAccessTierOptions protocolLayerOptions; - protocolLayerOptions.Tier = subrequest.Tier; - protocolLayerOptions.RehydratePriority = subrequest.Options.RehydratePriority; - auto message = Details::BlobRestClient::Blob::SetAccessTierCreateMessage( - blobUrl, protocolLayerOptions); - message.RemoveHeader(Storage::Details::HttpHeaderXMsVersion); - m_subRequestPipeline->Send(options.Context, message); - requestBody += message.GetHTTPMessagePreBody(); - } - requestBody += "--" + boundary + "--" + LineEnding; - } - - Details::BlobRestClient::BlobBatch::SubmitBlobBatchOptions protocolLayerOptions; - protocolLayerOptions.ContentType = ContentTypePrefix + boundary; - - Azure::Core::Http::MemoryBodyStream requestBodyStream( - reinterpret_cast(requestBody.data()), requestBody.length()); - - auto rawResponse = Details::BlobRestClient::BlobBatch::SubmitBatch( - options.Context, *m_pipeline, m_serviceUrl, &requestBodyStream, protocolLayerOptions); - - if (rawResponse->ContentType.substr(0, ContentTypePrefix.length()) == ContentTypePrefix) - { - boundary = rawResponse->ContentType.substr(ContentTypePrefix.length()); - } - else - { - throw std::runtime_error("failed to parse Content-Type response header"); - } - - SubmitBlobBatchResult batchResult; - { - const std::vector& responseBody = rawResponse.GetRawResponse().GetBody(); - - const char* const startPos = reinterpret_cast(responseBody.data()); - const char* currPos = startPos; - const char* const endPos = currPos + responseBody.size(); - - auto parseLookAhead = [&currPos, endPos](const std::string& expect) -> bool { - // This doesn't move currPos - for (std::size_t i = 0; i < expect.length(); ++i) - { - if (currPos + i < endPos && currPos[i] == expect[i]) - { - continue; - } - return false; - } - return true; - }; - - auto parseConsume = [&currPos, startPos, &parseLookAhead](const std::string& expect) -> void { - // This moves currPos - if (parseLookAhead(expect)) - { - currPos += expect.length(); - } - else - { - throw std::runtime_error( - "failed to parse response body at " + std::to_string(currPos - startPos)); - } - }; - - auto parseFindNext = [&currPos, endPos](const std::string& expect) -> const char* { - // This doesn't move currPos - return std::search(currPos, endPos, expect.begin(), expect.end()); - }; - - auto parseFindNextAfter = [endPos, &parseFindNext](const std::string& expect) -> const char* { - // This doesn't move currPos - return std::min(endPos, parseFindNext(expect) + expect.length()); - }; - - auto parseGetUntilAfter - = [&currPos, endPos, &parseFindNext](const std::string& expect) -> std::string { - // This moves currPos - auto ePos = parseFindNext(expect); - std::string ret(currPos, ePos); - currPos = std::min(endPos, ePos + expect.length()); - return ret; - }; - - int subRequestCounter = 0; - while (true) - { - parseConsume("--" + boundary); - - if (parseLookAhead("--")) - { - parseConsume("--"); - } - - if (currPos == endPos) - { - break; - } - - currPos = parseFindNextAfter(LineEnding + LineEnding); - auto boundaryPos = parseFindNext("--" + boundary); - - // now (currPos, boundaryPos) is a subresponse body - parseConsume("HTTP/"); - int32_t httpMajorVersion = std::stoi(parseGetUntilAfter(".")); - int32_t httpMinorVersion = std::stoi(parseGetUntilAfter(" ")); - int32_t httpStatusCode = std::stoi(parseGetUntilAfter(" ")); - std::string httpReasonPhrase = parseGetUntilAfter(LineEnding); - - auto rawSubresponse = std::make_unique( - httpMajorVersion, - httpMinorVersion, - static_cast(httpStatusCode), - httpReasonPhrase); - - while (currPos < boundaryPos) - { - if (parseLookAhead(LineEnding)) - { - break; - } - - std::string headerName = parseGetUntilAfter(": "); - std::string headerValue = parseGetUntilAfter(LineEnding); - rawSubresponse->AddHeader(headerName, headerValue); - } - - parseConsume(LineEnding); - - rawSubresponse->SetBody(std::vector(currPos, boundaryPos)); - currPos = boundaryPos; - - RequestType requestType = requestTypes[subRequestCounter++]; - if (requestType == RequestType::DeleteBlob) - { - try - { - batchResult.DeleteBlobResults.emplace_back( - Details::BlobRestClient::Blob::DeleteCreateResponse( - options.Context, std::move(rawSubresponse))); - } - catch (StorageException& e) - { - batchResult.DeleteBlobResults.emplace_back( - Azure::Core::Response( - Models::DeleteBlobResult{}, std::move(e.RawResponse))); - } - } - else if (requestType == RequestType::SetBlobAccessTier) - { - try - { - batchResult.SetBlobAccessTierResults.emplace_back( - Details::BlobRestClient::Blob::SetAccessTierCreateResponse( - options.Context, std::move(rawSubresponse))); - } - catch (StorageException& e) - { - batchResult.SetBlobAccessTierResults.emplace_back( - Azure::Core::Response( - Models::SetBlobAccessTierResult{}, std::move(e.RawResponse))); - } - } - } - } - - return Azure::Core::Response( - std::move(batchResult), rawResponse.ExtractRawResponse()); - } -}}} // namespace Azure::Storage::Blobs diff --git a/sdk/storage/azure-storage-blobs/test/blob_batch_client_test.cpp b/sdk/storage/azure-storage-blobs/test/blob_batch_client_test.cpp deleted file mode 100644 index 47687fe5f..000000000 --- a/sdk/storage/azure-storage-blobs/test/blob_batch_client_test.cpp +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// SPDX-License-Identifier: MIT - -#include - -#include -#include - -#include "test_base.hpp" - -namespace Azure { namespace Storage { namespace Test { - - class BlobBatchClientTest : public ::testing::Test { - protected: - BlobBatchClientTest() - : m_blobBatchClient(Azure::Storage::Blobs::BlobBatchClient::CreateFromConnectionString( - StandardStorageConnectionString())) - { - } - - Azure::Storage::Blobs::BlobBatchClient m_blobBatchClient; - }; - - TEST_F(BlobBatchClientTest, BatchSasAuth) - { - Sas::AccountSasBuilder accountSasBuilder; - accountSasBuilder.Protocol = Sas::SasProtocol::HttpsAndHttp; - accountSasBuilder.StartsOn = Azure::Core::DateTime::Now() - std::chrono::minutes(5); - accountSasBuilder.ExpiresOn = Azure::Core::DateTime::Now() + std::chrono::minutes(60); - accountSasBuilder.Services = Sas::AccountSasServices::Blobs; - accountSasBuilder.ResourceTypes - = Sas::AccountSasResource::Object | Sas::AccountSasResource::BlobContainer; - accountSasBuilder.SetPermissions(Sas::AccountSasPermissions::All); - auto keyCredential - = Details::ParseConnectionString(StandardStorageConnectionString()).KeyCredential; - - auto serviceClient - = Blobs::BlobServiceClient::CreateFromConnectionString(StandardStorageConnectionString()); - std::string containerName = LowercaseRandomString(); - auto containerClient = serviceClient.GetBlobContainerClient(containerName); - containerClient.Create(); - std::string blobName = RandomString(); - auto blobClient = containerClient.GetBlockBlobClient(blobName); - blobClient.UploadFrom(nullptr, 0); - - auto batch = Azure::Storage::Blobs::BlobBatchClient::CreateBatch(); - batch.DeleteBlob(containerName, blobName); - - auto batchClient = Blobs::BlobBatchClient(serviceClient.GetUrl()); - - EXPECT_THROW(batchClient.SubmitBatch(batch), StorageException); - - batchClient = Blobs::BlobBatchClient( - serviceClient.GetUrl() + accountSasBuilder.GenerateSasToken(*keyCredential)); - - EXPECT_NO_THROW(batchClient.SubmitBatch(batch)); - - containerClient.Delete(); - } - - TEST_F(BlobBatchClientTest, Batch) - { - auto serviceClient - = Blobs::BlobServiceClient::CreateFromConnectionString(StandardStorageConnectionString()); - std::string containerName1 = LowercaseRandomString(); - std::string containerName2 = LowercaseRandomString(); - auto containerClient1 = serviceClient.GetBlobContainerClient(containerName1); - containerClient1.Create(); - auto containerClient2 = serviceClient.GetBlobContainerClient(containerName2); - containerClient2.Create(); - - std::string blobName11 = RandomString(); - auto blobClient11 = containerClient1.GetBlockBlobClient(blobName11); - blobClient11.UploadFrom(nullptr, 0); - - std::string blobName12 = RandomString(); - auto blobClient12 = containerClient1.GetBlockBlobClient(blobName12); - blobClient12.UploadFrom(nullptr, 0); - - std::string blobName21 = RandomString(); - auto blobClient21 = containerClient2.GetBlockBlobClient(blobName21); - blobClient21.UploadFrom(nullptr, 0); - - std::string blobName22 = RandomString(); - - auto batch = Azure::Storage::Blobs::BlobBatchClient::CreateBatch(); - int32_t id1 - = batch.SetBlobAccessTier(containerName1, blobName11, Blobs::Models::AccessTier::Cool); - int32_t id2 - = batch.SetBlobAccessTier(containerName1, blobName12, Blobs::Models::AccessTier::Hot); - int32_t id3 - = batch.SetBlobAccessTier(containerName2, blobName21, Blobs::Models::AccessTier::Hot); - int32_t id4 - = batch.SetBlobAccessTier(containerName2, blobName22, Blobs::Models::AccessTier::Cool); - unused(id1, id2, id3, id4); - - std::size_t failedId = static_cast(id4); - std::size_t batchSize = static_cast(id4) + 1; - - auto batchResult = m_blobBatchClient.SubmitBatch(batch); - EXPECT_EQ(batchResult->SetBlobAccessTierResults.size(), batchSize); - EXPECT_TRUE(batchResult->DeleteBlobResults.empty()); - for (std::size_t i = 0; i < batchSize; ++i) - { - if (i != failedId) - { - EXPECT_EQ( - batchResult->SetBlobAccessTierResults[i].GetRawResponse().GetStatusCode(), - Azure::Core::Http::HttpStatusCode::Ok); - } - else - { - EXPECT_NE( - batchResult->SetBlobAccessTierResults[i].GetRawResponse().GetStatusCode(), - Azure::Core::Http::HttpStatusCode::Ok); - } - } - - batch = Azure::Storage::Blobs::BlobBatchClient::CreateBatch(); - id1 = batch.DeleteBlob(containerName1, blobName11); - id2 = batch.DeleteBlob(containerName1, blobName12); - id3 = batch.DeleteBlob(containerName2, blobName21); - id4 = batch.DeleteBlob(containerName2, blobName22); - - failedId = static_cast(id4); - batchSize = static_cast(id4) + 1; - - batchResult = m_blobBatchClient.SubmitBatch(batch); - - EXPECT_EQ(batchResult->DeleteBlobResults.size(), batchSize); - EXPECT_TRUE(batchResult->SetBlobAccessTierResults.empty()); - for (std::size_t i = 0; i < batchSize; ++i) - { - if (i != failedId) - { - EXPECT_EQ( - batchResult->DeleteBlobResults[i].GetRawResponse().GetStatusCode(), - Azure::Core::Http::HttpStatusCode::Accepted); - } - else - { - EXPECT_NE( - batchResult->DeleteBlobResults[i].GetRawResponse().GetStatusCode(), - Azure::Core::Http::HttpStatusCode::Accepted); - } - } - - containerClient1.Delete(); - containerClient2.Delete(); - } - -}}} // namespace Azure::Storage::Test