From 17563c7c01db03d4d493026aeae11dd6735610b8 Mon Sep 17 00:00:00 2001 From: microzchang <110015819+microzchang@users.noreply.github.com> Date: Mon, 23 Jun 2025 11:31:03 +0800 Subject: [PATCH] Storage STG99 Features (#6622) * Changed QueueProperties.ApproximateMessagesCount from int to long (#6584) * Storage/STG99 Added ShareSnapshotNotFound in ShareErrorCode (#6612) * Share SnapshotNotFound error code support * add test record * Storage/STG99 Made error message for invalid x-ms-version more user-friendly (#6613) * add invalid version erorr message support * Update find logic * Stg99/Add test records and update change logs (#6620) * Update test records and change logs * update change log --- sdk/storage/assets.json | 2 +- sdk/storage/azure-storage-blobs/CHANGELOG.md | 8 ++--- .../test/ut/block_blob_client_test.cpp | 16 +++++++++ sdk/storage/azure-storage-common/CHANGELOG.md | 6 ++-- .../storage/common/internal/constants.hpp | 5 +++ .../src/storage_exception.cpp | 8 +++++ .../azure-storage-files-datalake/CHANGELOG.md | 8 ++--- .../azure-storage-files-shares/CHANGELOG.md | 9 ++--- .../storage/files/shares/share_constants.hpp | 1 + .../src/share_client.cpp | 2 +- .../test/ut/share_client_test.cpp | 9 +++++ sdk/storage/azure-storage-queues/CHANGELOG.md | 8 ++--- .../inc/azure/storage/queues/queue_client.hpp | 1 + .../azure/storage/queues/queue_responses.hpp | 26 +++++++++++++++ .../inc/azure/storage/queues/rest_client.hpp | 30 +++++++++-------- .../azure-storage-queues/src/queue_client.cpp | 16 ++++++++- .../azure-storage-queues/src/rest_client.cpp | 9 ++--- .../azure-storage-queues/swagger/README.md | 1 + .../test/ut/queue_client_test.cpp | 33 +++++++++++++++++++ 19 files changed, 151 insertions(+), 47 deletions(-) diff --git a/sdk/storage/assets.json b/sdk/storage/assets.json index e7b3381e4..fbaa09004 100644 --- a/sdk/storage/assets.json +++ b/sdk/storage/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "cpp", "TagPrefix": "cpp/storage", - "Tag": "cpp/storage_7bea1dff90" + "Tag": "cpp/storage_7f9ca72801" } diff --git a/sdk/storage/azure-storage-blobs/CHANGELOG.md b/sdk/storage/azure-storage-blobs/CHANGELOG.md index 5365546f8..be2e1d1bf 100644 --- a/sdk/storage/azure-storage-blobs/CHANGELOG.md +++ b/sdk/storage/azure-storage-blobs/CHANGELOG.md @@ -1,14 +1,10 @@ # Release History -## 12.14.0-beta.2 (Unreleased) +## 12.15.0-beta.1 (2025-06-11) ### Features Added -### Breaking Changes - -### Bugs Fixed - -### Other Changes +- Added more useful error message when the SDK encounters an x-ms-version mis-match issue. ## 12.14.0-beta.1 (2025-05-13) diff --git a/sdk/storage/azure-storage-blobs/test/ut/block_blob_client_test.cpp b/sdk/storage/azure-storage-blobs/test/ut/block_blob_client_test.cpp index 4de5e08e4..614cc49c9 100644 --- a/sdk/storage/azure-storage-blobs/test/ut/block_blob_client_test.cpp +++ b/sdk/storage/azure-storage-blobs/test/ut/block_blob_client_test.cpp @@ -2264,4 +2264,20 @@ namespace Azure { namespace Storage { namespace Test { blobProperties = versionClient.GetProperties().Value; EXPECT_TRUE(blobProperties.HasLegalHold); } + + TEST_F(BlockBlobClientTest, InvalidVersionMessage) + { + Blobs::BlobClientOptions options; + options.ApiVersion = "3015-11-11"; + auto blobClient = GetBlockBlobClientForTest(LowercaseRandomString(), options); + try + { + blobClient.Download(); + } + catch (const StorageException& e) + { + EXPECT_EQ(e.ErrorCode, _internal::InvalidHeaderValueErrorCode); + EXPECT_EQ(e.Message, _internal::InvalidVersionHeaderMessage); + } + } }}} // namespace Azure::Storage::Test diff --git a/sdk/storage/azure-storage-common/CHANGELOG.md b/sdk/storage/azure-storage-common/CHANGELOG.md index 31a81c862..1c7dcc2d2 100644 --- a/sdk/storage/azure-storage-common/CHANGELOG.md +++ b/sdk/storage/azure-storage-common/CHANGELOG.md @@ -1,12 +1,10 @@ # Release History -## 12.11.0-beta.1 (Unreleased) +## 12.12.0-beta.1 (2025-06-11) ### Features Added -### Breaking Changes - -### Bugs Fixed +- Added more useful error message when the SDK encounters an x-ms-version mis-match issue. ### Other Changes diff --git a/sdk/storage/azure-storage-common/inc/azure/storage/common/internal/constants.hpp b/sdk/storage/azure-storage-common/inc/azure/storage/common/internal/constants.hpp index df0486cf7..7eb09da54 100644 --- a/sdk/storage/azure-storage-common/inc/azure/storage/common/internal/constants.hpp +++ b/sdk/storage/azure-storage-common/inc/azure/storage/common/internal/constants.hpp @@ -21,6 +21,11 @@ namespace Azure { namespace Storage { namespace _internal { constexpr static const char* HttpHeaderContentType = "content-type"; constexpr static const char* HttpHeaderContentLength = "content-length"; constexpr static const char* HttpHeaderContentRange = "content-range"; + constexpr static const char* InvalidHeaderValueErrorCode = "InvalidHeaderValue"; + constexpr static const char* InvalidVersionHeaderMessage + = "The provided service version is not enabled on this storage account. Please see " + "https://learn.microsoft.com/rest/api/storageservices/" + "versioning-for-the-azure-storage-services for additional information."; constexpr int ReliableStreamRetryCount = 3; }}} // namespace Azure::Storage::_internal diff --git a/sdk/storage/azure-storage-common/src/storage_exception.cpp b/sdk/storage/azure-storage-common/src/storage_exception.cpp index 55e303de6..0b1244827 100644 --- a/sdk/storage/azure-storage-common/src/storage_exception.cpp +++ b/sdk/storage/azure-storage-common/src/storage_exception.cpp @@ -147,6 +147,14 @@ namespace Azure { namespace Storage { errorCode = response->GetHeaders().at("x-ms-error-code"); } + // Optimize error messages + const auto headerName = additionalInformation.find("HeaderName"); + if (errorCode == _internal::InvalidHeaderValueErrorCode + && headerName != additionalInformation.end() && headerName->second == "x-ms-version") + { + message = _internal::InvalidVersionHeaderMessage; + } + StorageException result = StorageException( std::to_string(static_cast::type>( httpStatusCode)) diff --git a/sdk/storage/azure-storage-files-datalake/CHANGELOG.md b/sdk/storage/azure-storage-files-datalake/CHANGELOG.md index a40de080e..7acef9e41 100644 --- a/sdk/storage/azure-storage-files-datalake/CHANGELOG.md +++ b/sdk/storage/azure-storage-files-datalake/CHANGELOG.md @@ -1,14 +1,10 @@ # Release History -## 12.13.0-beta.1 (Unreleased) +## 12.13.0-beta.1 (2025-06-11) ### Features Added -### Breaking Changes - -### Bugs Fixed - -### Other Changes +- Added more useful error message when the SDK encounters an x-ms-version mis-match issue. ## 12.12.0 (2024-09-17) diff --git a/sdk/storage/azure-storage-files-shares/CHANGELOG.md b/sdk/storage/azure-storage-files-shares/CHANGELOG.md index 19a5a84f3..744a15ecd 100644 --- a/sdk/storage/azure-storage-files-shares/CHANGELOG.md +++ b/sdk/storage/azure-storage-files-shares/CHANGELOG.md @@ -1,14 +1,11 @@ # Release History -## 12.14.0-beta.2 (Unreleased) +## 12.15.0-beta.1 (2025-06-11) ### Features Added -### Breaking Changes - -### Bugs Fixed - -### Other Changes +- `ShareClient::DeleteIfExists()` will return `false` when error code is `ShareSnapshotNotFound`. +- Added more useful error message when the SDK encounters an x-ms-version mis-match issue. ## 12.14.0-beta.1 (2025-05-13) diff --git a/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/share_constants.hpp b/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/share_constants.hpp index b0b1bc100..73e0d6786 100644 --- a/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/share_constants.hpp +++ b/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/share_constants.hpp @@ -20,6 +20,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { constexpr static const char* ResourceNotFound = "ResourceNotFound"; constexpr static const char* ShareAlreadyExists = "ShareAlreadyExists"; constexpr static const char* ShareNotFound = "ShareNotFound"; + constexpr static const char* ShareSnapshotNotFound = "ShareSnapshotNotFound"; constexpr static const char* ResourceAlreadyExists = "ResourceAlreadyExists"; } // namespace _detail diff --git a/sdk/storage/azure-storage-files-shares/src/share_client.cpp b/sdk/storage/azure-storage-files-shares/src/share_client.cpp index 0697bd6c8..805108e01 100644 --- a/sdk/storage/azure-storage-files-shares/src/share_client.cpp +++ b/sdk/storage/azure-storage-files-shares/src/share_client.cpp @@ -222,7 +222,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { } catch (StorageException& e) { - if (e.ErrorCode == _detail::ShareNotFound) + if (e.ErrorCode == _detail::ShareNotFound || e.ErrorCode == _detail::ShareSnapshotNotFound) { Models::DeleteShareResult ret; ret.Deleted = false; diff --git a/sdk/storage/azure-storage-files-shares/test/ut/share_client_test.cpp b/sdk/storage/azure-storage-files-shares/test/ut/share_client_test.cpp index def6354e7..82fdc341f 100644 --- a/sdk/storage/azure-storage-files-shares/test/ut/share_client_test.cpp +++ b/sdk/storage/azure-storage-files-shares/test/ut/share_client_test.cpp @@ -124,6 +124,15 @@ namespace Azure { namespace Storage { namespace Test { } } + TEST_F(FileShareClientTest, SnapshotNotFoundErrorCode) + { + auto shareSnapshot = m_shareClient->WithSnapshot("2025-02-04T10:17:47.0000000Z"); + + Files::Shares::Models::DeleteShareResult deleteResult; + EXPECT_NO_THROW(deleteResult = shareSnapshot.DeleteIfExists().Value); + EXPECT_FALSE(deleteResult.Deleted); + } + TEST_F(FileShareClientTest, ShareMetadata) { auto metadata1 = RandomMetadata(); diff --git a/sdk/storage/azure-storage-queues/CHANGELOG.md b/sdk/storage/azure-storage-queues/CHANGELOG.md index b2a584307..b0d858db7 100644 --- a/sdk/storage/azure-storage-queues/CHANGELOG.md +++ b/sdk/storage/azure-storage-queues/CHANGELOG.md @@ -1,14 +1,14 @@ # Release History -## 12.5.0-beta.1 (Unreleased) +## 12.5.0-beta.1 (2025-06-11) ### Features Added +- Added more useful error message when the SDK encounters an x-ms-version mis-match issue. + ### Breaking Changes -### Bugs Fixed - -### Other Changes +- `QueueProperties.ApproximateMessageCount` is deprecated. The value is `-1` if the value exceeds `INT32_MAX`. Use `QueueProperties.ApproximateMessageCountLong` instead. ## 12.4.0 (2024-09-17) diff --git a/sdk/storage/azure-storage-queues/inc/azure/storage/queues/queue_client.hpp b/sdk/storage/azure-storage-queues/inc/azure/storage/queues/queue_client.hpp index b1f4e8c19..64d173a5a 100644 --- a/sdk/storage/azure-storage-queues/inc/azure/storage/queues/queue_client.hpp +++ b/sdk/storage/azure-storage-queues/inc/azure/storage/queues/queue_client.hpp @@ -9,6 +9,7 @@ #pragma once #include "azure/storage/queues/queue_options.hpp" +#include "azure/storage/queues/queue_responses.hpp" #include #include diff --git a/sdk/storage/azure-storage-queues/inc/azure/storage/queues/queue_responses.hpp b/sdk/storage/azure-storage-queues/inc/azure/storage/queues/queue_responses.hpp index decf77dcf..31cb3f260 100644 --- a/sdk/storage/azure-storage-queues/inc/azure/storage/queues/queue_responses.hpp +++ b/sdk/storage/azure-storage-queues/inc/azure/storage/queues/queue_responses.hpp @@ -20,6 +20,32 @@ namespace Azure { namespace Storage { namespace Queues { class QueueServiceClient; + namespace Models { + /** + * @brief Response type for #Azure::Storage::Queues::QueueClient::GetProperties. + */ + struct QueueProperties final + { + /** + * A set of name-value pairs associated with this queue. + */ + Core::CaseInsensitiveMap Metadata; + /** + * The approximate number of messages in the queue. This number is not lower than the actual + * number of messages in the queue, but could be higher. + * + * This field is deprecated. The value is -1 if the value exceeds + * INT32_MAX.Use ApproximateMessageCountLong instead. + */ + std::int32_t ApproximateMessageCount = std::int32_t(); + /** + * The approximate number of messages in the queue. This number is not lower than the actual + * number of messages in the queue, but could be higher. + */ + std::int64_t ApproximateMessageCountLong = std::int64_t(); + }; + } // namespace Models + /** * @brief Response type for #Azure::Storage::Queues::QueueServiceClient::ListQueues. */ diff --git a/sdk/storage/azure-storage-queues/inc/azure/storage/queues/rest_client.hpp b/sdk/storage/azure-storage-queues/inc/azure/storage/queues/rest_client.hpp index 9cd2db0c3..d8031c8f1 100644 --- a/sdk/storage/azure-storage-queues/inc/azure/storage/queues/rest_client.hpp +++ b/sdk/storage/azure-storage-queues/inc/azure/storage/queues/rest_client.hpp @@ -283,21 +283,23 @@ namespace Azure { namespace Storage { namespace Queues { */ bool Deleted = true; }; - /** - * @brief Response type for #Azure::Storage::Queues::QueueClient::GetProperties. - */ - struct QueueProperties final - { + namespace _detail { /** - * A set of name-value pairs associated with this queue. + * @brief Response type for #Azure::Storage::Queues::QueueClient::GetProperties. */ - Core::CaseInsensitiveMap Metadata; - /** - * The approximate number of messages in the queue. This number is not lower than the actual - * number of messages in the queue, but could be higher. - */ - std::int32_t ApproximateMessageCount = std::int32_t(); - }; + struct QueueProperties final + { + /** + * A set of name-value pairs associated with this queue. + */ + Core::CaseInsensitiveMap Metadata; + /** + * The approximate number of messages in the queue. This number is not lower than the actual + * number of messages in the queue, but could be higher. + */ + std::int64_t ApproximateMessageCount = std::int64_t(); + }; + } // namespace _detail /** * @brief Response type for #Azure::Storage::Queues::QueueClient::SetMetadata. */ @@ -554,7 +556,7 @@ namespace Azure { namespace Storage { namespace Queues { struct GetQueuePropertiesOptions final { }; - static Response GetProperties( + static Response GetProperties( Core::Http::_internal::HttpPipeline& pipeline, const Core::Url& url, const GetQueuePropertiesOptions& options, diff --git a/sdk/storage/azure-storage-queues/src/queue_client.cpp b/sdk/storage/azure-storage-queues/src/queue_client.cpp index 9f4ff3b29..d2d87b1c7 100644 --- a/sdk/storage/azure-storage-queues/src/queue_client.cpp +++ b/sdk/storage/azure-storage-queues/src/queue_client.cpp @@ -165,8 +165,22 @@ namespace Azure { namespace Storage { namespace Queues { { (void)options; _detail::QueueClient::GetQueuePropertiesOptions protocolLayerOptions; - return _detail::QueueClient::GetProperties( + auto ret = _detail::QueueClient::GetProperties( *m_pipeline, m_queueUrl, protocolLayerOptions, context); + Models::QueueProperties queueProperties; + queueProperties.Metadata = std::move(ret.Value.Metadata); + if (ret.Value.ApproximateMessageCount > static_cast(INT32_MAX)) + { + queueProperties.ApproximateMessageCount = -1; + } + else + { + queueProperties.ApproximateMessageCount + = static_cast(ret.Value.ApproximateMessageCount); + } + queueProperties.ApproximateMessageCountLong = ret.Value.ApproximateMessageCount; + return Azure::Response( + std::move(queueProperties), std::move(ret.RawResponse)); } Azure::Response QueueClient::SetMetadata( diff --git a/sdk/storage/azure-storage-queues/src/rest_client.cpp b/sdk/storage/azure-storage-queues/src/rest_client.cpp index 614a595ca..97fe80fa6 100644 --- a/sdk/storage/azure-storage-queues/src/rest_client.cpp +++ b/sdk/storage/azure-storage-queues/src/rest_client.cpp @@ -698,7 +698,7 @@ namespace Azure { namespace Storage { namespace Queues { Models::DeleteQueueResult response; return Response(std::move(response), std::move(pRawResponse)); } - Response QueueClient::GetProperties( + Response QueueClient::GetProperties( Core::Http::_internal::HttpPipeline& pipeline, const Core::Url& url, const GetQueuePropertiesOptions& options, @@ -714,7 +714,7 @@ namespace Azure { namespace Storage { namespace Queues { { throw StorageException::CreateFromResponse(std::move(pRawResponse)); } - Models::QueueProperties response; + Models::_detail::QueueProperties response; for (auto i = pRawResponse->GetHeaders().lower_bound("x-ms-meta-"); i != pRawResponse->GetHeaders().end() && i->first.substr(0, 10) == "x-ms-meta-"; ++i) @@ -722,8 +722,9 @@ namespace Azure { namespace Storage { namespace Queues { response.Metadata.emplace(i->first.substr(10), i->second); } response.ApproximateMessageCount - = std::stoi(pRawResponse->GetHeaders().at("x-ms-approximate-messages-count")); - return Response(std::move(response), std::move(pRawResponse)); + = std::stoll(pRawResponse->GetHeaders().at("x-ms-approximate-messages-count")); + return Response( + std::move(response), std::move(pRawResponse)); } Response QueueClient::SetMetadata( Core::Http::_internal::HttpPipeline& pipeline, diff --git a/sdk/storage/azure-storage-queues/swagger/README.md b/sdk/storage/azure-storage-queues/swagger/README.md index 6fc784a06..52ca3649c 100644 --- a/sdk/storage/azure-storage-queues/swagger/README.md +++ b/sdk/storage/azure-storage-queues/swagger/README.md @@ -278,6 +278,7 @@ directive: "type": "object", "x-ms-client-name": "QueueProperties", "x-ms-sealed": false, + "x-namespace": "_detail", "properties": {"__placeHolder": {"type": "integer"}} }; ``` diff --git a/sdk/storage/azure-storage-queues/test/ut/queue_client_test.cpp b/sdk/storage/azure-storage-queues/test/ut/queue_client_test.cpp index 1b4a338da..aef3b6e71 100644 --- a/sdk/storage/azure-storage-queues/test/ut/queue_client_test.cpp +++ b/sdk/storage/azure-storage-queues/test/ut/queue_client_test.cpp @@ -185,6 +185,39 @@ namespace Azure { namespace Storage { namespace Test { EXPECT_TRUE(properties.Metadata.empty()); } + TEST_F(QueueClientTest, ApproximateMessageCount) + { + int messageCount = 0; + m_queueClient->EnqueueMessage("test"); + ++messageCount; + auto res = m_queueClient->GetProperties(); + EXPECT_EQ(res.Value.ApproximateMessageCount, messageCount); + EXPECT_EQ(res.Value.ApproximateMessageCountLong, messageCount); + + for (; messageCount < 10; ++messageCount) + { + m_queueClient->EnqueueMessage("test"); + } + res = m_queueClient->GetProperties(); + EXPECT_EQ(res.Value.ApproximateMessageCount, messageCount); + EXPECT_EQ(res.Value.ApproximateMessageCountLong, messageCount); + } + + TEST_F(QueueClientTest, ApproximateMessageCountLong_PLAYBACKONLY_) + { + // Hardcode the x-ms-approximate-messages-count header to INT32_MAX in recording file. + m_queueClient->EnqueueMessage("test"); + // Mock the recording file to INT32_MAX + auto res = m_queueClient->GetProperties(); + EXPECT_EQ(res.Value.ApproximateMessageCount, INT32_MAX); + EXPECT_EQ(res.Value.ApproximateMessageCountLong, INT32_MAX); + + // Hardcode the x-ms-approximate-messages-count header to INT64_MAX in recording file. + res = m_queueClient->GetProperties(); + EXPECT_EQ(res.Value.ApproximateMessageCount, -1); + EXPECT_EQ(res.Value.ApproximateMessageCountLong, INT64_MAX); + } + TEST_F(QueueClientTest, AccessControlList_LIVEONLY_) { auto clientOptions = InitStorageClientOptions();