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
This commit is contained in:
parent
d9eacda722
commit
17563c7c01
@ -2,5 +2,5 @@
|
|||||||
"AssetsRepo": "Azure/azure-sdk-assets",
|
"AssetsRepo": "Azure/azure-sdk-assets",
|
||||||
"AssetsRepoPrefixPath": "cpp",
|
"AssetsRepoPrefixPath": "cpp",
|
||||||
"TagPrefix": "cpp/storage",
|
"TagPrefix": "cpp/storage",
|
||||||
"Tag": "cpp/storage_7bea1dff90"
|
"Tag": "cpp/storage_7f9ca72801"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,14 +1,10 @@
|
|||||||
# Release History
|
# Release History
|
||||||
|
|
||||||
## 12.14.0-beta.2 (Unreleased)
|
## 12.15.0-beta.1 (2025-06-11)
|
||||||
|
|
||||||
### Features Added
|
### Features Added
|
||||||
|
|
||||||
### Breaking Changes
|
- Added more useful error message when the SDK encounters an x-ms-version mis-match issue.
|
||||||
|
|
||||||
### Bugs Fixed
|
|
||||||
|
|
||||||
### Other Changes
|
|
||||||
|
|
||||||
## 12.14.0-beta.1 (2025-05-13)
|
## 12.14.0-beta.1 (2025-05-13)
|
||||||
|
|
||||||
|
|||||||
@ -2264,4 +2264,20 @@ namespace Azure { namespace Storage { namespace Test {
|
|||||||
blobProperties = versionClient.GetProperties().Value;
|
blobProperties = versionClient.GetProperties().Value;
|
||||||
EXPECT_TRUE(blobProperties.HasLegalHold);
|
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
|
}}} // namespace Azure::Storage::Test
|
||||||
|
|||||||
@ -1,12 +1,10 @@
|
|||||||
# Release History
|
# Release History
|
||||||
|
|
||||||
## 12.11.0-beta.1 (Unreleased)
|
## 12.12.0-beta.1 (2025-06-11)
|
||||||
|
|
||||||
### Features Added
|
### Features Added
|
||||||
|
|
||||||
### Breaking Changes
|
- Added more useful error message when the SDK encounters an x-ms-version mis-match issue.
|
||||||
|
|
||||||
### Bugs Fixed
|
|
||||||
|
|
||||||
### Other Changes
|
### Other Changes
|
||||||
|
|
||||||
|
|||||||
@ -21,6 +21,11 @@ namespace Azure { namespace Storage { namespace _internal {
|
|||||||
constexpr static const char* HttpHeaderContentType = "content-type";
|
constexpr static const char* HttpHeaderContentType = "content-type";
|
||||||
constexpr static const char* HttpHeaderContentLength = "content-length";
|
constexpr static const char* HttpHeaderContentLength = "content-length";
|
||||||
constexpr static const char* HttpHeaderContentRange = "content-range";
|
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;
|
constexpr int ReliableStreamRetryCount = 3;
|
||||||
}}} // namespace Azure::Storage::_internal
|
}}} // namespace Azure::Storage::_internal
|
||||||
|
|||||||
@ -147,6 +147,14 @@ namespace Azure { namespace Storage {
|
|||||||
errorCode = response->GetHeaders().at("x-ms-error-code");
|
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(
|
StorageException result = StorageException(
|
||||||
std::to_string(static_cast<std::underlying_type<Azure::Core::Http::HttpStatusCode>::type>(
|
std::to_string(static_cast<std::underlying_type<Azure::Core::Http::HttpStatusCode>::type>(
|
||||||
httpStatusCode))
|
httpStatusCode))
|
||||||
|
|||||||
@ -1,14 +1,10 @@
|
|||||||
# Release History
|
# Release History
|
||||||
|
|
||||||
## 12.13.0-beta.1 (Unreleased)
|
## 12.13.0-beta.1 (2025-06-11)
|
||||||
|
|
||||||
### Features Added
|
### Features Added
|
||||||
|
|
||||||
### Breaking Changes
|
- Added more useful error message when the SDK encounters an x-ms-version mis-match issue.
|
||||||
|
|
||||||
### Bugs Fixed
|
|
||||||
|
|
||||||
### Other Changes
|
|
||||||
|
|
||||||
## 12.12.0 (2024-09-17)
|
## 12.12.0 (2024-09-17)
|
||||||
|
|
||||||
|
|||||||
@ -1,14 +1,11 @@
|
|||||||
# Release History
|
# Release History
|
||||||
|
|
||||||
## 12.14.0-beta.2 (Unreleased)
|
## 12.15.0-beta.1 (2025-06-11)
|
||||||
|
|
||||||
### Features Added
|
### Features Added
|
||||||
|
|
||||||
### Breaking 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.
|
||||||
### Bugs Fixed
|
|
||||||
|
|
||||||
### Other Changes
|
|
||||||
|
|
||||||
## 12.14.0-beta.1 (2025-05-13)
|
## 12.14.0-beta.1 (2025-05-13)
|
||||||
|
|
||||||
|
|||||||
@ -20,6 +20,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
|
|||||||
constexpr static const char* ResourceNotFound = "ResourceNotFound";
|
constexpr static const char* ResourceNotFound = "ResourceNotFound";
|
||||||
constexpr static const char* ShareAlreadyExists = "ShareAlreadyExists";
|
constexpr static const char* ShareAlreadyExists = "ShareAlreadyExists";
|
||||||
constexpr static const char* ShareNotFound = "ShareNotFound";
|
constexpr static const char* ShareNotFound = "ShareNotFound";
|
||||||
|
constexpr static const char* ShareSnapshotNotFound = "ShareSnapshotNotFound";
|
||||||
constexpr static const char* ResourceAlreadyExists = "ResourceAlreadyExists";
|
constexpr static const char* ResourceAlreadyExists = "ResourceAlreadyExists";
|
||||||
} // namespace _detail
|
} // namespace _detail
|
||||||
|
|
||||||
|
|||||||
@ -222,7 +222,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
|
|||||||
}
|
}
|
||||||
catch (StorageException& e)
|
catch (StorageException& e)
|
||||||
{
|
{
|
||||||
if (e.ErrorCode == _detail::ShareNotFound)
|
if (e.ErrorCode == _detail::ShareNotFound || e.ErrorCode == _detail::ShareSnapshotNotFound)
|
||||||
{
|
{
|
||||||
Models::DeleteShareResult ret;
|
Models::DeleteShareResult ret;
|
||||||
ret.Deleted = false;
|
ret.Deleted = false;
|
||||||
|
|||||||
@ -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)
|
TEST_F(FileShareClientTest, ShareMetadata)
|
||||||
{
|
{
|
||||||
auto metadata1 = RandomMetadata();
|
auto metadata1 = RandomMetadata();
|
||||||
|
|||||||
@ -1,14 +1,14 @@
|
|||||||
# Release History
|
# Release History
|
||||||
|
|
||||||
## 12.5.0-beta.1 (Unreleased)
|
## 12.5.0-beta.1 (2025-06-11)
|
||||||
|
|
||||||
### Features Added
|
### Features Added
|
||||||
|
|
||||||
|
- Added more useful error message when the SDK encounters an x-ms-version mis-match issue.
|
||||||
|
|
||||||
### Breaking Changes
|
### Breaking Changes
|
||||||
|
|
||||||
### Bugs Fixed
|
- `QueueProperties.ApproximateMessageCount` is deprecated. The value is `-1` if the value exceeds `INT32_MAX`. Use `QueueProperties.ApproximateMessageCountLong` instead.
|
||||||
|
|
||||||
### Other Changes
|
|
||||||
|
|
||||||
## 12.4.0 (2024-09-17)
|
## 12.4.0 (2024-09-17)
|
||||||
|
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "azure/storage/queues/queue_options.hpp"
|
#include "azure/storage/queues/queue_options.hpp"
|
||||||
|
#include "azure/storage/queues/queue_responses.hpp"
|
||||||
|
|
||||||
#include <azure/core/credentials/credentials.hpp>
|
#include <azure/core/credentials/credentials.hpp>
|
||||||
#include <azure/storage/common/storage_credential.hpp>
|
#include <azure/storage/common/storage_credential.hpp>
|
||||||
|
|||||||
@ -20,6 +20,32 @@ namespace Azure { namespace Storage { namespace Queues {
|
|||||||
|
|
||||||
class QueueServiceClient;
|
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.
|
* @brief Response type for #Azure::Storage::Queues::QueueServiceClient::ListQueues.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -283,21 +283,23 @@ namespace Azure { namespace Storage { namespace Queues {
|
|||||||
*/
|
*/
|
||||||
bool Deleted = true;
|
bool Deleted = true;
|
||||||
};
|
};
|
||||||
/**
|
namespace _detail {
|
||||||
* @brief Response type for #Azure::Storage::Queues::QueueClient::GetProperties.
|
|
||||||
*/
|
|
||||||
struct QueueProperties final
|
|
||||||
{
|
|
||||||
/**
|
/**
|
||||||
* A set of name-value pairs associated with this queue.
|
* @brief Response type for #Azure::Storage::Queues::QueueClient::GetProperties.
|
||||||
*/
|
*/
|
||||||
Core::CaseInsensitiveMap Metadata;
|
struct QueueProperties final
|
||||||
/**
|
{
|
||||||
* 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.
|
* A set of name-value pairs associated with this queue.
|
||||||
*/
|
*/
|
||||||
std::int32_t ApproximateMessageCount = std::int32_t();
|
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.
|
* @brief Response type for #Azure::Storage::Queues::QueueClient::SetMetadata.
|
||||||
*/
|
*/
|
||||||
@ -554,7 +556,7 @@ namespace Azure { namespace Storage { namespace Queues {
|
|||||||
struct GetQueuePropertiesOptions final
|
struct GetQueuePropertiesOptions final
|
||||||
{
|
{
|
||||||
};
|
};
|
||||||
static Response<Models::QueueProperties> GetProperties(
|
static Response<Models::_detail::QueueProperties> GetProperties(
|
||||||
Core::Http::_internal::HttpPipeline& pipeline,
|
Core::Http::_internal::HttpPipeline& pipeline,
|
||||||
const Core::Url& url,
|
const Core::Url& url,
|
||||||
const GetQueuePropertiesOptions& options,
|
const GetQueuePropertiesOptions& options,
|
||||||
|
|||||||
@ -165,8 +165,22 @@ namespace Azure { namespace Storage { namespace Queues {
|
|||||||
{
|
{
|
||||||
(void)options;
|
(void)options;
|
||||||
_detail::QueueClient::GetQueuePropertiesOptions protocolLayerOptions;
|
_detail::QueueClient::GetQueuePropertiesOptions protocolLayerOptions;
|
||||||
return _detail::QueueClient::GetProperties(
|
auto ret = _detail::QueueClient::GetProperties(
|
||||||
*m_pipeline, m_queueUrl, protocolLayerOptions, context);
|
*m_pipeline, m_queueUrl, protocolLayerOptions, context);
|
||||||
|
Models::QueueProperties queueProperties;
|
||||||
|
queueProperties.Metadata = std::move(ret.Value.Metadata);
|
||||||
|
if (ret.Value.ApproximateMessageCount > static_cast<int64_t>(INT32_MAX))
|
||||||
|
{
|
||||||
|
queueProperties.ApproximateMessageCount = -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
queueProperties.ApproximateMessageCount
|
||||||
|
= static_cast<std::int32_t>(ret.Value.ApproximateMessageCount);
|
||||||
|
}
|
||||||
|
queueProperties.ApproximateMessageCountLong = ret.Value.ApproximateMessageCount;
|
||||||
|
return Azure::Response<Models::QueueProperties>(
|
||||||
|
std::move(queueProperties), std::move(ret.RawResponse));
|
||||||
}
|
}
|
||||||
|
|
||||||
Azure::Response<Models::SetQueueMetadataResult> QueueClient::SetMetadata(
|
Azure::Response<Models::SetQueueMetadataResult> QueueClient::SetMetadata(
|
||||||
|
|||||||
@ -698,7 +698,7 @@ namespace Azure { namespace Storage { namespace Queues {
|
|||||||
Models::DeleteQueueResult response;
|
Models::DeleteQueueResult response;
|
||||||
return Response<Models::DeleteQueueResult>(std::move(response), std::move(pRawResponse));
|
return Response<Models::DeleteQueueResult>(std::move(response), std::move(pRawResponse));
|
||||||
}
|
}
|
||||||
Response<Models::QueueProperties> QueueClient::GetProperties(
|
Response<Models::_detail::QueueProperties> QueueClient::GetProperties(
|
||||||
Core::Http::_internal::HttpPipeline& pipeline,
|
Core::Http::_internal::HttpPipeline& pipeline,
|
||||||
const Core::Url& url,
|
const Core::Url& url,
|
||||||
const GetQueuePropertiesOptions& options,
|
const GetQueuePropertiesOptions& options,
|
||||||
@ -714,7 +714,7 @@ namespace Azure { namespace Storage { namespace Queues {
|
|||||||
{
|
{
|
||||||
throw StorageException::CreateFromResponse(std::move(pRawResponse));
|
throw StorageException::CreateFromResponse(std::move(pRawResponse));
|
||||||
}
|
}
|
||||||
Models::QueueProperties response;
|
Models::_detail::QueueProperties response;
|
||||||
for (auto i = pRawResponse->GetHeaders().lower_bound("x-ms-meta-");
|
for (auto i = pRawResponse->GetHeaders().lower_bound("x-ms-meta-");
|
||||||
i != pRawResponse->GetHeaders().end() && i->first.substr(0, 10) == "x-ms-meta-";
|
i != pRawResponse->GetHeaders().end() && i->first.substr(0, 10) == "x-ms-meta-";
|
||||||
++i)
|
++i)
|
||||||
@ -722,8 +722,9 @@ namespace Azure { namespace Storage { namespace Queues {
|
|||||||
response.Metadata.emplace(i->first.substr(10), i->second);
|
response.Metadata.emplace(i->first.substr(10), i->second);
|
||||||
}
|
}
|
||||||
response.ApproximateMessageCount
|
response.ApproximateMessageCount
|
||||||
= std::stoi(pRawResponse->GetHeaders().at("x-ms-approximate-messages-count"));
|
= std::stoll(pRawResponse->GetHeaders().at("x-ms-approximate-messages-count"));
|
||||||
return Response<Models::QueueProperties>(std::move(response), std::move(pRawResponse));
|
return Response<Models::_detail::QueueProperties>(
|
||||||
|
std::move(response), std::move(pRawResponse));
|
||||||
}
|
}
|
||||||
Response<Models::SetQueueMetadataResult> QueueClient::SetMetadata(
|
Response<Models::SetQueueMetadataResult> QueueClient::SetMetadata(
|
||||||
Core::Http::_internal::HttpPipeline& pipeline,
|
Core::Http::_internal::HttpPipeline& pipeline,
|
||||||
|
|||||||
@ -278,6 +278,7 @@ directive:
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"x-ms-client-name": "QueueProperties",
|
"x-ms-client-name": "QueueProperties",
|
||||||
"x-ms-sealed": false,
|
"x-ms-sealed": false,
|
||||||
|
"x-namespace": "_detail",
|
||||||
"properties": {"__placeHolder": {"type": "integer"}}
|
"properties": {"__placeHolder": {"type": "integer"}}
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|||||||
@ -185,6 +185,39 @@ namespace Azure { namespace Storage { namespace Test {
|
|||||||
EXPECT_TRUE(properties.Metadata.empty());
|
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_)
|
TEST_F(QueueClientTest, AccessControlList_LIVEONLY_)
|
||||||
{
|
{
|
||||||
auto clientOptions = InitStorageClientOptions<Queues::QueueClientOptions>();
|
auto clientOptions = InitStorageClientOptions<Queues::QueueClientOptions>();
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user