add missing properties in BlobClient::GetProperties (#1512)

* add missing properties in BlobClient::GetProperties

* changelog

* fix test case bug

* Add more properties in download blob result
This commit is contained in:
JinmingHu 2021-01-29 11:39:00 +08:00 committed by GitHub
parent 34fcca36ea
commit 5e2e84cdbc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 304 additions and 14 deletions

View File

@ -5,6 +5,7 @@
### New Features
- Added `RequestId` in API return types.
- Added some new properties in `GetBlobPropertiesResult` and `DownloadBlobResult`.
### Breaking Changes

View File

@ -1067,6 +1067,14 @@ namespace Azure { namespace Storage { namespace Blobs {
std::vector<ObjectReplicationPolicy>
ObjectReplicationSourceProperties; // only valid for replication source blob
Azure::Core::Nullable<int32_t> TagCount;
Azure::Core::Nullable<std::string> CopyId;
Azure::Core::Nullable<std::string> CopySource;
Azure::Core::Nullable<Models::CopyStatus> CopyStatus;
Azure::Core::Nullable<std::string> CopyStatusDescription;
Azure::Core::Nullable<std::string> CopyProgress;
Azure::Core::Nullable<Azure::Core::DateTime> CopyCompletedOn;
Azure::Core::Nullable<std::string> VersionId;
Azure::Core::Nullable<bool> IsCurrentVersion;
}; // struct DownloadBlobResult
struct GetBlobPropertiesResult
@ -1093,10 +1101,14 @@ namespace Azure { namespace Storage { namespace Blobs {
Azure::Core::Nullable<AccessTier> Tier;
Azure::Core::Nullable<bool> IsAccessTierInferred;
Azure::Core::Nullable<BlobArchiveStatus> ArchiveStatus;
Azure::Core::Nullable<Models::RehydratePriority> RehydratePriority;
Azure::Core::Nullable<Azure::Core::DateTime> AccessTierChangedOn;
Azure::Core::Nullable<std::string> CopyId;
Azure::Core::Nullable<std::string> CopySource;
Azure::Core::Nullable<Models::CopyStatus> CopyStatus;
Azure::Core::Nullable<std::string> CopyStatusDescription;
Azure::Core::Nullable<bool> IsIncrementalCopy;
Azure::Core::Nullable<std::string> IncrementalCopyDestinationSnapshot;
Azure::Core::Nullable<std::string> CopyProgress;
Azure::Core::Nullable<Azure::Core::DateTime> CopyCompletedOn;
Azure::Core::Nullable<std::string>
@ -1104,6 +1116,8 @@ namespace Azure { namespace Storage { namespace Blobs {
std::vector<ObjectReplicationPolicy>
ObjectReplicationSourceProperties; // only valid for replication source blob
Azure::Core::Nullable<int32_t> TagCount;
Azure::Core::Nullable<std::string> VersionId;
Azure::Core::Nullable<bool> IsCurrentVersion;
}; // struct GetBlobPropertiesResult
struct ListBlobsByHierarchySinglePageResult
@ -5101,6 +5115,51 @@ namespace Azure { namespace Storage { namespace Blobs {
{
response.TagCount = std::stoi(x_ms_tag_count__iterator->second);
}
auto x_ms_copy_id__iterator = httpResponse.GetHeaders().find("x-ms-copy-id");
if (x_ms_copy_id__iterator != httpResponse.GetHeaders().end())
{
response.CopyId = x_ms_copy_id__iterator->second;
}
auto x_ms_copy_source__iterator = httpResponse.GetHeaders().find("x-ms-copy-source");
if (x_ms_copy_source__iterator != httpResponse.GetHeaders().end())
{
response.CopySource = x_ms_copy_source__iterator->second;
}
auto x_ms_copy_status__iterator = httpResponse.GetHeaders().find("x-ms-copy-status");
if (x_ms_copy_status__iterator != httpResponse.GetHeaders().end())
{
response.CopyStatus = CopyStatus(x_ms_copy_status__iterator->second);
}
auto x_ms_copy_status_description__iterator
= httpResponse.GetHeaders().find("x-ms-copy-status-description");
if (x_ms_copy_status_description__iterator != httpResponse.GetHeaders().end())
{
response.CopyStatusDescription = x_ms_copy_status_description__iterator->second;
}
auto x_ms_copy_progress__iterator = httpResponse.GetHeaders().find("x-ms-copy-progress");
if (x_ms_copy_progress__iterator != httpResponse.GetHeaders().end())
{
response.CopyProgress = x_ms_copy_progress__iterator->second;
}
auto x_ms_copy_completion_time__iterator
= httpResponse.GetHeaders().find("x-ms-copy-completion-time");
if (x_ms_copy_completion_time__iterator != httpResponse.GetHeaders().end())
{
response.CopyCompletedOn = Azure::Core::DateTime::Parse(
x_ms_copy_completion_time__iterator->second,
Azure::Core::DateTime::DateFormat::Rfc1123);
}
auto x_ms_version_id__iterator = httpResponse.GetHeaders().find("x-ms-version-id");
if (x_ms_version_id__iterator != httpResponse.GetHeaders().end())
{
response.VersionId = x_ms_version_id__iterator->second;
}
auto x_ms_is_current_version__iterator
= httpResponse.GetHeaders().find("x-ms-is-current-version");
if (x_ms_is_current_version__iterator != httpResponse.GetHeaders().end())
{
response.IsCurrentVersion = x_ms_is_current_version__iterator->second == "true";
}
return Azure::Core::Response<DownloadBlobResult>(
std::move(response), std::move(pHttpResponse));
}
@ -5493,6 +5552,13 @@ namespace Azure { namespace Storage { namespace Blobs {
{
response.ArchiveStatus = BlobArchiveStatus(x_ms_archive_status__iterator->second);
}
auto x_ms_rehydrate_priority__iterator
= httpResponse.GetHeaders().find("x-ms-rehydrate-priority");
if (x_ms_rehydrate_priority__iterator != httpResponse.GetHeaders().end())
{
response.RehydratePriority
= RehydratePriority(x_ms_rehydrate_priority__iterator->second);
}
auto x_ms_access_tier_change_time__iterator
= httpResponse.GetHeaders().find("x-ms-access-tier-change-time");
if (x_ms_access_tier_change_time__iterator != httpResponse.GetHeaders().end())
@ -5516,6 +5582,25 @@ namespace Azure { namespace Storage { namespace Blobs {
{
response.CopyStatus = CopyStatus(x_ms_copy_status__iterator->second);
}
auto x_ms_copy_status_description__iterator
= httpResponse.GetHeaders().find("x-ms-copy-status-description");
if (x_ms_copy_status_description__iterator != httpResponse.GetHeaders().end())
{
response.CopyStatusDescription = x_ms_copy_status_description__iterator->second;
}
auto x_ms_incremental_copy__iterator
= httpResponse.GetHeaders().find("x-ms-incremental-copy");
if (x_ms_incremental_copy__iterator != httpResponse.GetHeaders().end())
{
response.IsIncrementalCopy = x_ms_incremental_copy__iterator->second == "true";
}
auto x_ms_copy_destination_snapshot__iterator
= httpResponse.GetHeaders().find("x-ms-copy-destination-snapshot");
if (x_ms_copy_destination_snapshot__iterator != httpResponse.GetHeaders().end())
{
response.IncrementalCopyDestinationSnapshot
= x_ms_copy_destination_snapshot__iterator->second;
}
auto x_ms_copy_progress__iterator = httpResponse.GetHeaders().find("x-ms-copy-progress");
if (x_ms_copy_progress__iterator != httpResponse.GetHeaders().end())
{
@ -5568,6 +5653,17 @@ namespace Azure { namespace Storage { namespace Blobs {
{
response.TagCount = std::stoi(x_ms_tag_count__iterator->second);
}
auto x_ms_version_id__iterator = httpResponse.GetHeaders().find("x-ms-version-id");
if (x_ms_version_id__iterator != httpResponse.GetHeaders().end())
{
response.VersionId = x_ms_version_id__iterator->second;
}
auto x_ms_is_current_version__iterator
= httpResponse.GetHeaders().find("x-ms-is-current-version");
if (x_ms_is_current_version__iterator != httpResponse.GetHeaders().end())
{
response.IsCurrentVersion = x_ms_is_current_version__iterator->second == "true";
}
return Azure::Core::Response<GetBlobPropertiesResult>(
std::move(response), std::move(pHttpResponse));
}

View File

@ -208,6 +208,15 @@ namespace Azure { namespace Storage { namespace Blobs {
downloadResponse->BodyStream = std::make_unique<ReliableStream>(
std::move(downloadResponse->BodyStream), reliableStreamOptions, retryFunction);
}
if (downloadResponse->BlobType == Models::BlobType::AppendBlob
&& !downloadResponse->IsSealed.HasValue())
{
downloadResponse->IsSealed = false;
}
if (downloadResponse->VersionId.HasValue() && !downloadResponse->IsCurrentVersion.HasValue())
{
downloadResponse->IsCurrentVersion = false;
}
return downloadResponse;
}
@ -463,8 +472,25 @@ namespace Azure { namespace Storage { namespace Blobs {
protocolLayerOptions.EncryptionKeySha256 = m_customerProvidedKey.GetValue().KeyHash;
protocolLayerOptions.EncryptionAlgorithm = m_customerProvidedKey.GetValue().Algorithm;
}
return Details::BlobRestClient::Blob::GetProperties(
auto response = Details::BlobRestClient::Blob::GetProperties(
options.Context, *m_pipeline, m_blobUrl, protocolLayerOptions);
if (response->Tier.HasValue() && !response->IsAccessTierInferred.HasValue())
{
response->IsAccessTierInferred = false;
}
if (response->VersionId.HasValue() && !response->IsCurrentVersion.HasValue())
{
response->IsCurrentVersion = false;
}
if (response->CopyStatus.HasValue() && !response->IsIncrementalCopy.HasValue())
{
response->IsIncrementalCopy = false;
}
if (response->BlobType == Models::BlobType::AppendBlob && !response->IsSealed.HasValue())
{
response->IsSealed = false;
}
return response;
}
Azure::Core::Response<Models::SetBlobHttpHeadersResult> BlobClient::SetHttpHeaders(

View File

@ -239,10 +239,18 @@ namespace Azure { namespace Storage { namespace Blobs {
options.Context, *m_pipeline, m_blobContainerUrl, protocolLayerOptions);
for (auto& i : response->Items)
{
if (i.Tier.HasValue() && !i.IsAccessTierInferred.HasValue())
{
i.IsAccessTierInferred = false;
}
if (i.VersionId.HasValue() && !i.IsCurrentVersion.HasValue())
{
i.IsCurrentVersion = false;
}
if (i.BlobType == Models::BlobType::AppendBlob && !i.IsSealed)
{
i.IsSealed = false;
}
}
return response;
}

View File

@ -276,16 +276,28 @@ namespace Azure { namespace Storage { namespace Test {
blobClient.AppendBlock(&blockContent);
auto downloadResult = blobClient.Download();
if (downloadResult->IsSealed.HasValue())
{
EXPECT_FALSE(downloadResult->IsSealed.GetValue());
}
EXPECT_TRUE(downloadResult->IsSealed.HasValue());
EXPECT_FALSE(downloadResult->IsSealed.GetValue());
auto getPropertiesResult = blobClient.GetProperties();
if (getPropertiesResult->IsSealed.HasValue())
EXPECT_TRUE(getPropertiesResult->IsSealed.HasValue());
EXPECT_FALSE(getPropertiesResult->IsSealed.GetValue());
Azure::Storage::Blobs::ListBlobsSinglePageOptions options;
options.Prefix = blobName;
do
{
EXPECT_FALSE(getPropertiesResult->IsSealed.GetValue());
}
auto res = m_blobContainerClient->ListBlobsSinglePage(options);
options.ContinuationToken = res->ContinuationToken;
for (const auto& blob : res->Items)
{
if (blob.Name == blobName)
{
EXPECT_TRUE(blob.IsSealed.HasValue());
EXPECT_FALSE(blob.IsSealed.GetValue());
}
}
} while (options.ContinuationToken.HasValue());
Blobs::SealAppendBlobOptions sealOptions;
sealOptions.AccessConditions.IfAppendPositionEqual = m_blobContent.size() + 1;
@ -306,8 +318,6 @@ namespace Azure { namespace Storage { namespace Test {
EXPECT_TRUE(getPropertiesResult->IsSealed.HasValue());
EXPECT_TRUE(getPropertiesResult->IsSealed.GetValue());
Azure::Storage::Blobs::ListBlobsSinglePageOptions options;
options.Prefix = blobName;
do
{
auto res = m_blobContainerClient->ListBlobsSinglePage(options);
@ -330,10 +340,7 @@ namespace Azure { namespace Storage { namespace Test {
getPropertiesResult = copyResult->PollUntilDone(std::chrono::seconds(1));
ASSERT_TRUE(getPropertiesResult->CopyStatus.HasValue());
EXPECT_EQ(getPropertiesResult->CopyStatus.GetValue(), Blobs::Models::CopyStatus::Success);
if (getPropertiesResult->IsSealed.HasValue())
{
EXPECT_FALSE(getPropertiesResult->IsSealed.GetValue());
}
EXPECT_FALSE(getPropertiesResult->IsSealed.GetValue());
copyOptions.ShouldSealDestination = true;
copyResult = blobClient2.StartCopyFromUri(blobClient.GetUrl() + GetSas(), copyOptions);

View File

@ -201,6 +201,22 @@ namespace Azure { namespace Storage { namespace Test {
{
EXPECT_TRUE(IsValidTime(properties.CopyCompletedOn.GetValue()));
}
ASSERT_TRUE(properties.IsIncrementalCopy.HasValue());
EXPECT_FALSE(properties.IsIncrementalCopy.GetValue());
EXPECT_FALSE(properties.IncrementalCopyDestinationSnapshot.HasValue());
auto downloadResult = blobClient.Download();
EXPECT_EQ(downloadResult->CopyId.GetValue(), res->CopyId);
EXPECT_FALSE(downloadResult->CopySource.GetValue().empty());
EXPECT_TRUE(
downloadResult->CopyStatus.GetValue() == Azure::Storage::Blobs::Models::CopyStatus::Pending
|| downloadResult->CopyStatus.GetValue()
== Azure::Storage::Blobs::Models::CopyStatus::Success);
EXPECT_FALSE(downloadResult->CopyProgress.GetValue().empty());
if (downloadResult->CopyStatus.GetValue() == Azure::Storage::Blobs::Models::CopyStatus::Success)
{
EXPECT_TRUE(IsValidTime(downloadResult->CopyCompletedOn.GetValue()));
}
}
TEST_F(BlockBlobClientTest, SnapShotVersions)
@ -249,6 +265,72 @@ namespace Azure { namespace Storage { namespace Test {
EXPECT_NO_THROW(m_blockBlobClient->GetProperties());
}
TEST_F(BlockBlobClientTest, IsCurrentVersion)
{
std::vector<uint8_t> emptyContent;
std::string blobName = RandomString();
auto blobClient = m_blobContainerClient->GetBlockBlobClient(blobName);
blobClient.UploadFrom(emptyContent.data(), emptyContent.size());
auto properties = *blobClient.GetProperties();
ASSERT_TRUE(properties.VersionId.HasValue());
ASSERT_TRUE(properties.IsCurrentVersion.HasValue());
EXPECT_TRUE(properties.IsCurrentVersion.GetValue());
auto downloadResponse = blobClient.Download();
ASSERT_TRUE(downloadResponse->VersionId.HasValue());
ASSERT_TRUE(downloadResponse->IsCurrentVersion.HasValue());
EXPECT_TRUE(downloadResponse->IsCurrentVersion.GetValue());
std::string version1 = properties.VersionId.GetValue();
blobClient.CreateSnapshot();
properties = *blobClient.GetProperties();
ASSERT_TRUE(properties.VersionId.HasValue());
ASSERT_TRUE(properties.IsCurrentVersion.HasValue());
EXPECT_TRUE(properties.IsCurrentVersion.GetValue());
std::string latestVersion = properties.VersionId.GetValue();
EXPECT_NE(version1, properties.VersionId.GetValue());
auto versionClient = blobClient.WithVersionId(version1);
properties = *versionClient.GetProperties();
ASSERT_TRUE(properties.VersionId.HasValue());
ASSERT_TRUE(properties.IsCurrentVersion.HasValue());
EXPECT_FALSE(properties.IsCurrentVersion.GetValue());
EXPECT_EQ(version1, properties.VersionId.GetValue());
downloadResponse = versionClient.Download();
ASSERT_TRUE(downloadResponse->VersionId.HasValue());
ASSERT_TRUE(downloadResponse->IsCurrentVersion.HasValue());
EXPECT_FALSE(downloadResponse->IsCurrentVersion.GetValue());
EXPECT_EQ(version1, downloadResponse->VersionId.GetValue());
Azure::Storage::Blobs::ListBlobsSinglePageOptions options;
options.Prefix = blobName;
options.Include = Blobs::Models::ListBlobsIncludeFlags::Versions;
do
{
auto res = m_blobContainerClient->ListBlobsSinglePage(options);
options.ContinuationToken = res->ContinuationToken;
for (const auto& blob : res->Items)
{
if (blob.Name == blobName)
{
ASSERT_TRUE(blob.VersionId.HasValue());
ASSERT_TRUE(blob.IsCurrentVersion.HasValue());
if (blob.VersionId.GetValue() == latestVersion)
{
EXPECT_TRUE(blob.IsCurrentVersion.GetValue());
}
else
{
EXPECT_FALSE(blob.IsCurrentVersion.GetValue());
}
}
}
} while (options.ContinuationToken.HasValue());
}
TEST_F(BlockBlobClientTest, Properties)
{
auto blockBlobClient = Azure::Storage::Blobs::BlockBlobClient::CreateFromConnectionString(
@ -845,4 +927,62 @@ namespace Azure { namespace Storage { namespace Test {
EXPECT_THROW(blobClient.WithSnapshot(s2).GetProperties(), StorageException);
}
TEST_F(BlockBlobClientTest, SetTier)
{
std::vector<uint8_t> emptyContent;
std::string blobName = RandomString();
auto blobClient = m_blobContainerClient->GetBlockBlobClient(blobName);
blobClient.UploadFrom(emptyContent.data(), emptyContent.size());
auto properties = *blobClient.GetProperties();
ASSERT_TRUE(properties.Tier.HasValue());
ASSERT_TRUE(properties.IsAccessTierInferred.HasValue());
EXPECT_TRUE(properties.IsAccessTierInferred.GetValue());
EXPECT_FALSE(properties.AccessTierChangedOn.HasValue());
Azure::Storage::Blobs::ListBlobsSinglePageOptions options;
options.Prefix = blobName;
do
{
auto res = m_blobContainerClient->ListBlobsSinglePage(options);
options.ContinuationToken = res->ContinuationToken;
for (const auto& blob : res->Items)
{
if (blob.Name == blobName)
{
ASSERT_TRUE(blob.Tier.HasValue());
ASSERT_TRUE(blob.IsAccessTierInferred.HasValue());
EXPECT_TRUE(blob.IsAccessTierInferred.GetValue());
}
}
} while (options.ContinuationToken.HasValue());
// choose a different tier
auto targetTier = properties.Tier.GetValue() == Blobs::Models::AccessTier::Hot
? Blobs::Models::AccessTier::Cool
: Blobs::Models::AccessTier::Hot;
blobClient.SetAccessTier(targetTier);
properties = *blobClient.GetProperties();
ASSERT_TRUE(properties.Tier.HasValue());
ASSERT_TRUE(properties.IsAccessTierInferred.HasValue());
EXPECT_FALSE(properties.IsAccessTierInferred.GetValue());
EXPECT_TRUE(properties.AccessTierChangedOn.HasValue());
do
{
auto res = m_blobContainerClient->ListBlobsSinglePage(options);
options.ContinuationToken = res->ContinuationToken;
for (const auto& blob : res->Items)
{
if (blob.Name == blobName)
{
ASSERT_TRUE(blob.Tier.HasValue());
ASSERT_TRUE(blob.IsAccessTierInferred.HasValue());
EXPECT_FALSE(blob.IsAccessTierInferred.GetValue());
}
}
} while (options.ContinuationToken.HasValue());
}
}}} // namespace Azure::Storage::Test

View File

@ -160,6 +160,18 @@ namespace Azure { namespace Storage { namespace Test {
auto getPropertiesResult = copyInfo->PollUntilDone(std::chrono::seconds(1));
ASSERT_TRUE(getPropertiesResult->CopyStatus.HasValue());
EXPECT_EQ(getPropertiesResult->CopyStatus.GetValue(), Blobs::Models::CopyStatus::Success);
ASSERT_TRUE(getPropertiesResult->CopyId.HasValue());
EXPECT_FALSE(getPropertiesResult->CopyId.GetValue().empty());
ASSERT_TRUE(getPropertiesResult->CopySource.HasValue());
EXPECT_FALSE(getPropertiesResult->CopySource.GetValue().empty());
ASSERT_TRUE(getPropertiesResult->IsIncrementalCopy.HasValue());
EXPECT_TRUE(getPropertiesResult->IsIncrementalCopy.GetValue());
ASSERT_TRUE(getPropertiesResult->IncrementalCopyDestinationSnapshot.HasValue());
EXPECT_FALSE(getPropertiesResult->IncrementalCopyDestinationSnapshot.GetValue().empty());
ASSERT_TRUE(getPropertiesResult->CopyCompletedOn.HasValue());
EXPECT_TRUE(IsValidTime(getPropertiesResult->CopyCompletedOn.GetValue()));
ASSERT_TRUE(getPropertiesResult->CopyProgress.HasValue());
EXPECT_FALSE(getPropertiesResult->CopyProgress.GetValue().empty());
}
TEST_F(PageBlobClientTest, Lease)