Some API changes to blob service (#2557)
This commit is contained in:
parent
a97970ea20
commit
bc16d4d812
@ -4,10 +4,20 @@
|
||||
|
||||
### Features Added
|
||||
|
||||
- Added lease ID access condition and tags access condition for `BlobClient::SetAccessTier()`.
|
||||
- Added source ETag access conditions and last-modified access conditions for `PageBlobClient::UploadPagesFromUri()`.
|
||||
- Added three new fields `IsServerEncrypted`, `EncryptionKeySha256` and `EncryptionScope` into `SetBlobMetadataResult`.
|
||||
- Added support for setting blob tags when creating or copying blobs.
|
||||
- Added new fields `AccessTierChangedOn`, `ArchiveStatus`, `RehydratePriority`, `CopyId`, `CopySource`, `CopyStatus`, `CopyStatusDescription`, `IsIncrementalCopy`, `IncrementalCopyDestinationSnapshot`, `CopyProgress`, `CopyCompletedOn`, `TagCount`, `Tags`, `DeletedOn` and `RemainingRetentionDays` into `BlobItemDetails`.
|
||||
- Added support for including blob tags when listing blobs.
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
### Bugs Fixed
|
||||
|
||||
- Fixed a bug where lease ID didn't work for `BlobContainerClient::GetAccessPolicy()`.
|
||||
- Fixed a bug where `BlobItemDetails::EncryptionKeySha256` was always null because it wasn't correctly parsed from xml.
|
||||
|
||||
### Other Changes
|
||||
|
||||
## 12.0.1 (2021-07-07)
|
||||
|
||||
@ -435,6 +435,12 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
* same blob.
|
||||
*/
|
||||
Azure::Nullable<Models::RehydratePriority> RehydratePriority;
|
||||
/**
|
||||
* @brief Optional conditions that must be met to perform this operation.
|
||||
*/
|
||||
struct : public LeaseAccessConditions, public TagAccessConditions
|
||||
{
|
||||
} AccessConditions;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -451,6 +457,11 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
*/
|
||||
Storage::Metadata Metadata;
|
||||
|
||||
/**
|
||||
* @brief The tags to set for this blob.
|
||||
*/
|
||||
std::map<std::string, std::string> Tags;
|
||||
|
||||
/**
|
||||
* @brief Optional conditions that must be met to perform this operation.
|
||||
*/
|
||||
@ -458,8 +469,15 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
|
||||
/**
|
||||
* @brief Optional conditions that the source must meet to perform this operation.
|
||||
*
|
||||
* @note Lease access condition only works for API versions before 2012-02-12.
|
||||
*/
|
||||
BlobAccessConditions SourceAccessConditions;
|
||||
struct : public Azure::ModifiedConditions,
|
||||
public Azure::MatchConditions,
|
||||
public LeaseAccessConditions,
|
||||
public TagAccessConditions
|
||||
{
|
||||
} SourceAccessConditions;
|
||||
|
||||
/**
|
||||
* @brief Specifies the tier to be set on the target blob.
|
||||
@ -698,6 +716,11 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
*/
|
||||
Storage::Metadata Metadata;
|
||||
|
||||
/**
|
||||
* @brief The tags to set for this blob.
|
||||
*/
|
||||
std::map<std::string, std::string> Tags;
|
||||
|
||||
/**
|
||||
* @brief Indicates the tier to be set on blob.
|
||||
*/
|
||||
@ -724,6 +747,11 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
*/
|
||||
Storage::Metadata Metadata;
|
||||
|
||||
/**
|
||||
* @brief The tags to set for this blob.
|
||||
*/
|
||||
std::map<std::string, std::string> Tags;
|
||||
|
||||
/**
|
||||
* @brief Indicates the tier to be set on blob.
|
||||
*/
|
||||
@ -816,6 +844,11 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
*/
|
||||
Storage::Metadata Metadata;
|
||||
|
||||
/**
|
||||
* @brief The tags to set for this blob.
|
||||
*/
|
||||
std::map<std::string, std::string> Tags;
|
||||
|
||||
/**
|
||||
* @brief Indicates the tier to be set on blob.
|
||||
*/
|
||||
@ -861,6 +894,11 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
*/
|
||||
Storage::Metadata Metadata;
|
||||
|
||||
/**
|
||||
* @brief The tags to set for this blob.
|
||||
*/
|
||||
std::map<std::string, std::string> Tags;
|
||||
|
||||
/**
|
||||
* @brief Optional conditions that must be met to perform this operation.
|
||||
*/
|
||||
@ -945,6 +983,11 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
*/
|
||||
Azure::Nullable<Models::AccessTier> AccessTier;
|
||||
|
||||
/**
|
||||
* @brief The tags to set for this blob.
|
||||
*/
|
||||
std::map<std::string, std::string> Tags;
|
||||
|
||||
/**
|
||||
* @brief Optional conditions that must be met to perform this operation.
|
||||
*/
|
||||
@ -985,6 +1028,13 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
* @brief Optional conditions that must be met to perform this operation.
|
||||
*/
|
||||
PageBlobAccessConditions AccessConditions;
|
||||
|
||||
/**
|
||||
* @brief Optional conditions that the source must meet to perform this operation.
|
||||
*/
|
||||
struct : public Azure::ModifiedConditions, public Azure::MatchConditions
|
||||
{
|
||||
} SourceAccessConditions;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -846,6 +846,18 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
* True if the access tier is not explicitly set on the blob.
|
||||
*/
|
||||
Azure::Nullable<bool> IsAccessTierInferred;
|
||||
/**
|
||||
* The date and time the tier was changed on the object.
|
||||
*/
|
||||
Azure::Nullable<Azure::DateTime> AccessTierChangedOn;
|
||||
/**
|
||||
* Indicates if the blob is being rehydrated.
|
||||
*/
|
||||
Azure::Nullable<Models::ArchiveStatus> ArchiveStatus;
|
||||
/**
|
||||
* Priority of rehydrate if the blob is being rehydrated.
|
||||
*/
|
||||
Azure::Nullable<Models::RehydratePriority> RehydratePriority;
|
||||
/**
|
||||
* The current lease status of the blob.
|
||||
*/
|
||||
@ -886,6 +898,66 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
* Only valid when Object Replication is enabled and current blob is the source.
|
||||
*/
|
||||
std::vector<ObjectReplicationPolicy> ObjectReplicationSourceProperties;
|
||||
/**
|
||||
* String identifier for the last attempted Copy Blob operation where this blob was the
|
||||
* destination. This value is null if this blob has never been the destination of a copy
|
||||
* operation, or if this blob has been modified after a concluded copy operation.
|
||||
*/
|
||||
Azure::Nullable<std::string> CopyId;
|
||||
/**
|
||||
* URL that specifies the source blob or file used in the last attempted copy operation where
|
||||
* this blob was the destination blob. This value is null if this blob has never been the
|
||||
* destination of a copy operation, or if this blob has been modified after a concluded copy
|
||||
* operation.
|
||||
*/
|
||||
Azure::Nullable<std::string> CopySource;
|
||||
/**
|
||||
* State of the copy operation identified by the copy ID. Possible values include success,
|
||||
* pending, aborted, failed etc. This value is null if this blob has never been the
|
||||
* destination of a copy operation, or if this blob has been modified after a concluded copy
|
||||
* operation.
|
||||
*/
|
||||
Azure::Nullable<Models::CopyStatus> CopyStatus;
|
||||
/**
|
||||
* Describes the cause of the last fatal or non-fatal copy operation failure. This is not null
|
||||
* only when copy status is failed or pending.
|
||||
*/
|
||||
Azure::Nullable<std::string> CopyStatusDescription;
|
||||
/**
|
||||
* True if the copy operation is incremental copy.
|
||||
*/
|
||||
Azure::Nullable<bool> IsIncrementalCopy;
|
||||
/**
|
||||
* Snapshot time of the last successful incremental copy snapshot for this blob.
|
||||
*/
|
||||
Azure::Nullable<std::string> IncrementalCopyDestinationSnapshot;
|
||||
/**
|
||||
* Contains the number of bytes copied and the total bytes in the source in the last attempted
|
||||
* copy operation where this blob was the destination blob.
|
||||
*/
|
||||
Azure::Nullable<std::string> CopyProgress;
|
||||
/**
|
||||
* Conclusion time of the last attempted copy operation where this blob was the destination
|
||||
* blob.
|
||||
*/
|
||||
Azure::Nullable<Azure::DateTime> CopyCompletedOn;
|
||||
/**
|
||||
* the number of tags stored on the blob.
|
||||
*/
|
||||
Azure::Nullable<int32_t> TagCount;
|
||||
/**
|
||||
* User-defined tags for this blob.
|
||||
*/
|
||||
std::map<std::string, std::string> Tags;
|
||||
/**
|
||||
* Data and time at which this blob was deleted. Only valid when this blob was deleted.
|
||||
*/
|
||||
Azure::Nullable<Azure::DateTime> DeletedOn;
|
||||
/**
|
||||
* Remaining days before this blob will be permanantely deleted. Only valid when this blob was
|
||||
* deleted.
|
||||
*/
|
||||
Azure::Nullable<int32_t> RemainingRetentionDays;
|
||||
}; // struct BlobItemDetails
|
||||
|
||||
/**
|
||||
@ -1921,6 +1993,10 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
* Uncommitted blobs should be included.
|
||||
*/
|
||||
UncomittedBlobs = 32,
|
||||
/**
|
||||
* Tags should be included.
|
||||
*/
|
||||
Tags = 64,
|
||||
}; // bitwise enum ListBlobsIncludeFlags
|
||||
|
||||
inline ListBlobsIncludeFlags operator|(ListBlobsIncludeFlags lhs, ListBlobsIncludeFlags rhs)
|
||||
@ -2082,6 +2158,16 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
*/
|
||||
struct SetBlobExpiryResult final
|
||||
{
|
||||
/**
|
||||
* The ETag contains a value that you can use to perform operations conditionally.
|
||||
*/
|
||||
Azure::ETag ETag;
|
||||
/**
|
||||
* The date and time the container was last modified. Any operation that modifies the blob,
|
||||
* including an update of the metadata or properties, changes the last-modified time of the
|
||||
* blob.
|
||||
*/
|
||||
Azure::DateTime LastModified;
|
||||
}; // struct SetBlobExpiryResult
|
||||
|
||||
/**
|
||||
@ -2122,10 +2208,23 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
*/
|
||||
Azure::DateTime LastModified;
|
||||
/**
|
||||
* The current sequence number for a page blob. This value is null for block blobs or append
|
||||
* blobs.
|
||||
* This value is always null, don't use it.
|
||||
*/
|
||||
Azure::Nullable<int64_t> SequenceNumber;
|
||||
/**
|
||||
* True if the blob data and metadata are completely encrypted using the specified algorithm.
|
||||
* Otherwise, the value is set to false (when the blob is unencrypted, or if only parts of the
|
||||
* blob/application metadata are encrypted).
|
||||
*/
|
||||
bool IsServerEncrypted = false;
|
||||
/**
|
||||
* The SHA-256 hash of the encryption key used to encrypt the blob data and metadata.
|
||||
*/
|
||||
Azure::Nullable<std::vector<uint8_t>> EncryptionKeySha256;
|
||||
/**
|
||||
* Name of the encryption scope used to encrypt the blob data and metadata.
|
||||
*/
|
||||
Azure::Nullable<std::string> EncryptionScope;
|
||||
}; // struct SetBlobMetadataResult
|
||||
|
||||
/**
|
||||
@ -2486,6 +2585,9 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
namespace _detail {
|
||||
struct GetBlobTagsResult final
|
||||
{
|
||||
/**
|
||||
* User-defined tags for this blob.
|
||||
*/
|
||||
std::map<std::string, std::string> Tags;
|
||||
}; // struct GetBlobTagsResult
|
||||
} // namespace _detail
|
||||
@ -2575,11 +2677,6 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
* blob.
|
||||
*/
|
||||
Azure::DateTime LastModified;
|
||||
/**
|
||||
* The current sequence number for a page blob. This value is null for block blobs or append
|
||||
* blobs.
|
||||
*/
|
||||
Azure::Nullable<int64_t> SequenceNumber;
|
||||
}; // struct ReleaseBlobLeaseResult
|
||||
} // namespace _detail
|
||||
|
||||
@ -2745,6 +2842,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
ListBlobsIncludeFlags::Snapshots,
|
||||
ListBlobsIncludeFlags::Versions,
|
||||
ListBlobsIncludeFlags::UncomittedBlobs,
|
||||
ListBlobsIncludeFlags::Tags,
|
||||
};
|
||||
const char* string_list[] = {
|
||||
"copy",
|
||||
@ -2753,6 +2851,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
"snapshots",
|
||||
"versions",
|
||||
"uncommittedblobs",
|
||||
"tags",
|
||||
};
|
||||
std::string ret;
|
||||
for (size_t i = 0; i < sizeof(value_list) / sizeof(ListBlobsIncludeFlags); ++i)
|
||||
@ -4986,6 +5085,10 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
}
|
||||
request.GetUrl().AppendQueryParameter("restype", "container");
|
||||
request.GetUrl().AppendQueryParameter("comp", "acl");
|
||||
if (options.LeaseId.HasValue())
|
||||
{
|
||||
request.SetHeader("x-ms-lease-id", options.LeaseId.Value());
|
||||
}
|
||||
auto pHttpResponse = pipeline.Send(request, context);
|
||||
Azure::Core::Http::RawResponse& httpResponse = *pHttpResponse;
|
||||
BlobContainerAccessPolicy response;
|
||||
@ -5687,15 +5790,32 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
k_BlobType,
|
||||
k_AccessTier,
|
||||
k_AccessTierInferred,
|
||||
k_AccessTierChangeTime,
|
||||
k_ArchiveStatus,
|
||||
k_RehydratePriority,
|
||||
k_LeaseStatus,
|
||||
k_LeaseState,
|
||||
k_LeaseDuration,
|
||||
k_ServerEncrypted,
|
||||
k_EncryptionKeySHA256,
|
||||
k_CustomerProvidedKeySha256,
|
||||
k_EncryptionScope,
|
||||
k_Sealed,
|
||||
k_xmsblobsequencenumber,
|
||||
k_CopyId,
|
||||
k_CopyStatus,
|
||||
k_CopySource,
|
||||
k_CopyProgress,
|
||||
k_CopyCompletionTime,
|
||||
k_CopyStatusDescription,
|
||||
k_IncrementalCopy,
|
||||
k_CopyDestinationSnapshot,
|
||||
k_DeletedTime,
|
||||
k_RemainingRetentionDays,
|
||||
k_TagCount,
|
||||
k_Metadata,
|
||||
k_OrMetadata,
|
||||
k_Tags,
|
||||
k_TagSet,
|
||||
k_Unknown,
|
||||
};
|
||||
std::vector<XmlTagName> path;
|
||||
@ -5803,6 +5923,18 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
{
|
||||
path.emplace_back(XmlTagName::k_AccessTierInferred);
|
||||
}
|
||||
else if (node.Name == "AccessTierChangeTime")
|
||||
{
|
||||
path.emplace_back(XmlTagName::k_AccessTierChangeTime);
|
||||
}
|
||||
else if (node.Name == "ArchiveStatus")
|
||||
{
|
||||
path.emplace_back(XmlTagName::k_ArchiveStatus);
|
||||
}
|
||||
else if (node.Name == "RehydratePriority")
|
||||
{
|
||||
path.emplace_back(XmlTagName::k_RehydratePriority);
|
||||
}
|
||||
else if (node.Name == "LeaseStatus")
|
||||
{
|
||||
path.emplace_back(XmlTagName::k_LeaseStatus);
|
||||
@ -5819,9 +5951,13 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
{
|
||||
path.emplace_back(XmlTagName::k_ServerEncrypted);
|
||||
}
|
||||
else if (node.Name == "EncryptionKeySHA256")
|
||||
else if (node.Name == "CustomerProvidedKeySha256")
|
||||
{
|
||||
path.emplace_back(XmlTagName::k_EncryptionKeySHA256);
|
||||
path.emplace_back(XmlTagName::k_CustomerProvidedKeySha256);
|
||||
}
|
||||
else if (node.Name == "EncryptionScope")
|
||||
{
|
||||
path.emplace_back(XmlTagName::k_EncryptionScope);
|
||||
}
|
||||
else if (node.Name == "Sealed")
|
||||
{
|
||||
@ -5831,6 +5967,50 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
{
|
||||
path.emplace_back(XmlTagName::k_xmsblobsequencenumber);
|
||||
}
|
||||
else if (node.Name == "CopyId")
|
||||
{
|
||||
path.emplace_back(XmlTagName::k_CopyId);
|
||||
}
|
||||
else if (node.Name == "CopyStatus")
|
||||
{
|
||||
path.emplace_back(XmlTagName::k_CopyStatus);
|
||||
}
|
||||
else if (node.Name == "CopySource")
|
||||
{
|
||||
path.emplace_back(XmlTagName::k_CopySource);
|
||||
}
|
||||
else if (node.Name == "CopyProgress")
|
||||
{
|
||||
path.emplace_back(XmlTagName::k_CopyProgress);
|
||||
}
|
||||
else if (node.Name == "CopyCompletionTime")
|
||||
{
|
||||
path.emplace_back(XmlTagName::k_CopyCompletionTime);
|
||||
}
|
||||
else if (node.Name == "CopyStatusDescription")
|
||||
{
|
||||
path.emplace_back(XmlTagName::k_CopyStatusDescription);
|
||||
}
|
||||
else if (node.Name == "IncrementalCopy")
|
||||
{
|
||||
path.emplace_back(XmlTagName::k_IncrementalCopy);
|
||||
}
|
||||
else if (node.Name == "CopyDestinationSnapshot")
|
||||
{
|
||||
path.emplace_back(XmlTagName::k_CopyDestinationSnapshot);
|
||||
}
|
||||
else if (node.Name == "DeletedTime")
|
||||
{
|
||||
path.emplace_back(XmlTagName::k_DeletedTime);
|
||||
}
|
||||
else if (node.Name == "RemainingRetentionDays")
|
||||
{
|
||||
path.emplace_back(XmlTagName::k_RemainingRetentionDays);
|
||||
}
|
||||
else if (node.Name == "TagCount")
|
||||
{
|
||||
path.emplace_back(XmlTagName::k_TagCount);
|
||||
}
|
||||
else if (node.Name == "Metadata")
|
||||
{
|
||||
path.emplace_back(XmlTagName::k_Metadata);
|
||||
@ -5839,6 +6019,14 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
{
|
||||
path.emplace_back(XmlTagName::k_OrMetadata);
|
||||
}
|
||||
else if (node.Name == "Tags")
|
||||
{
|
||||
path.emplace_back(XmlTagName::k_Tags);
|
||||
}
|
||||
else if (node.Name == "TagSet")
|
||||
{
|
||||
path.emplace_back(XmlTagName::k_TagSet);
|
||||
}
|
||||
else
|
||||
{
|
||||
path.emplace_back(XmlTagName::k_Unknown);
|
||||
@ -5854,6 +6042,13 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
= ObjectReplicationSourcePropertiesFromXml(reader);
|
||||
path.pop_back();
|
||||
}
|
||||
else if (
|
||||
path.size() == 2 && path[0] == XmlTagName::k_Tags
|
||||
&& path[1] == XmlTagName::k_TagSet)
|
||||
{
|
||||
ret.Details.Tags = TagsFromXml(reader);
|
||||
path.pop_back();
|
||||
}
|
||||
}
|
||||
else if (node.Type == _internal::XmlNodeType::Text)
|
||||
{
|
||||
@ -5972,6 +6167,25 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
{
|
||||
ret.Details.IsAccessTierInferred = node.Value == "true";
|
||||
}
|
||||
else if (
|
||||
path.size() == 2 && path[0] == XmlTagName::k_Properties
|
||||
&& path[1] == XmlTagName::k_AccessTierChangeTime)
|
||||
{
|
||||
ret.Details.AccessTierChangedOn
|
||||
= Azure::DateTime::Parse(node.Value, Azure::DateTime::DateFormat::Rfc1123);
|
||||
}
|
||||
else if (
|
||||
path.size() == 2 && path[0] == XmlTagName::k_Properties
|
||||
&& path[1] == XmlTagName::k_ArchiveStatus)
|
||||
{
|
||||
ret.Details.ArchiveStatus = ArchiveStatus(node.Value);
|
||||
}
|
||||
else if (
|
||||
path.size() == 2 && path[0] == XmlTagName::k_Properties
|
||||
&& path[1] == XmlTagName::k_RehydratePriority)
|
||||
{
|
||||
ret.Details.RehydratePriority = RehydratePriority(node.Value);
|
||||
}
|
||||
else if (
|
||||
path.size() == 2 && path[0] == XmlTagName::k_Properties
|
||||
&& path[1] == XmlTagName::k_LeaseStatus)
|
||||
@ -5998,10 +6212,16 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
}
|
||||
else if (
|
||||
path.size() == 2 && path[0] == XmlTagName::k_Properties
|
||||
&& path[1] == XmlTagName::k_EncryptionKeySHA256)
|
||||
&& path[1] == XmlTagName::k_CustomerProvidedKeySha256)
|
||||
{
|
||||
ret.Details.EncryptionKeySha256 = Azure::Core::Convert::Base64Decode(node.Value);
|
||||
}
|
||||
else if (
|
||||
path.size() == 2 && path[0] == XmlTagName::k_Properties
|
||||
&& path[1] == XmlTagName::k_EncryptionScope)
|
||||
{
|
||||
ret.Details.EncryptionScope = node.Value;
|
||||
}
|
||||
else if (
|
||||
path.size() == 2 && path[0] == XmlTagName::k_Properties
|
||||
&& path[1] == XmlTagName::k_Sealed)
|
||||
@ -6014,6 +6234,74 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
{
|
||||
ret.Details.SequenceNumber = std::stoll(node.Value);
|
||||
}
|
||||
else if (
|
||||
path.size() == 2 && path[0] == XmlTagName::k_Properties
|
||||
&& path[1] == XmlTagName::k_CopyId)
|
||||
{
|
||||
ret.Details.CopyId = node.Value;
|
||||
}
|
||||
else if (
|
||||
path.size() == 2 && path[0] == XmlTagName::k_Properties
|
||||
&& path[1] == XmlTagName::k_CopyStatus)
|
||||
{
|
||||
ret.Details.CopyStatus = CopyStatus(node.Value);
|
||||
}
|
||||
else if (
|
||||
path.size() == 2 && path[0] == XmlTagName::k_Properties
|
||||
&& path[1] == XmlTagName::k_CopySource)
|
||||
{
|
||||
ret.Details.CopySource = node.Value;
|
||||
}
|
||||
else if (
|
||||
path.size() == 2 && path[0] == XmlTagName::k_Properties
|
||||
&& path[1] == XmlTagName::k_CopyProgress)
|
||||
{
|
||||
ret.Details.CopyProgress = node.Value;
|
||||
}
|
||||
else if (
|
||||
path.size() == 2 && path[0] == XmlTagName::k_Properties
|
||||
&& path[1] == XmlTagName::k_CopyCompletionTime)
|
||||
{
|
||||
ret.Details.CopyCompletedOn
|
||||
= Azure::DateTime::Parse(node.Value, Azure::DateTime::DateFormat::Rfc1123);
|
||||
}
|
||||
else if (
|
||||
path.size() == 2 && path[0] == XmlTagName::k_Properties
|
||||
&& path[1] == XmlTagName::k_CopyStatusDescription)
|
||||
{
|
||||
ret.Details.CopyStatusDescription = node.Value;
|
||||
}
|
||||
else if (
|
||||
path.size() == 2 && path[0] == XmlTagName::k_Properties
|
||||
&& path[1] == XmlTagName::k_IncrementalCopy)
|
||||
{
|
||||
ret.Details.IsIncrementalCopy = node.Value == "true";
|
||||
}
|
||||
else if (
|
||||
path.size() == 2 && path[0] == XmlTagName::k_Properties
|
||||
&& path[1] == XmlTagName::k_CopyDestinationSnapshot)
|
||||
{
|
||||
ret.Details.IncrementalCopyDestinationSnapshot = node.Value;
|
||||
}
|
||||
else if (
|
||||
path.size() == 2 && path[0] == XmlTagName::k_Properties
|
||||
&& path[1] == XmlTagName::k_DeletedTime)
|
||||
{
|
||||
ret.Details.DeletedOn
|
||||
= Azure::DateTime::Parse(node.Value, Azure::DateTime::DateFormat::Rfc1123);
|
||||
}
|
||||
else if (
|
||||
path.size() == 2 && path[0] == XmlTagName::k_Properties
|
||||
&& path[1] == XmlTagName::k_RemainingRetentionDays)
|
||||
{
|
||||
ret.Details.RemainingRetentionDays = std::stoi(node.Value);
|
||||
}
|
||||
else if (
|
||||
path.size() == 2 && path[0] == XmlTagName::k_Properties
|
||||
&& path[1] == XmlTagName::k_TagCount)
|
||||
{
|
||||
ret.Details.TagCount = std::stoi(node.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
@ -6108,6 +6396,56 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
return ret;
|
||||
}
|
||||
|
||||
static std::map<std::string, std::string> TagsFromXml(_internal::XmlReader& reader)
|
||||
{
|
||||
std::map<std::string, std::string> ret;
|
||||
int depth = 0;
|
||||
std::string key;
|
||||
bool is_key = false;
|
||||
bool is_value = false;
|
||||
while (true)
|
||||
{
|
||||
auto node = reader.Read();
|
||||
if (node.Type == _internal::XmlNodeType::End)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (node.Type == _internal::XmlNodeType::StartTag)
|
||||
{
|
||||
++depth;
|
||||
if (node.Name == "Key")
|
||||
{
|
||||
is_key = true;
|
||||
}
|
||||
else if (node.Name == "Value")
|
||||
{
|
||||
is_value = true;
|
||||
}
|
||||
}
|
||||
else if (node.Type == _internal::XmlNodeType::EndTag)
|
||||
{
|
||||
if (depth-- == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (depth == 2 && node.Type == _internal::XmlNodeType::Text)
|
||||
{
|
||||
if (is_key)
|
||||
{
|
||||
key = node.Value;
|
||||
is_key = false;
|
||||
}
|
||||
else if (is_value)
|
||||
{
|
||||
ret.emplace(std::move(key), node.Value);
|
||||
is_value = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static std::vector<ObjectReplicationPolicy> ObjectReplicationSourcePropertiesFromXml(
|
||||
_internal::XmlReader& reader)
|
||||
{
|
||||
@ -6727,6 +7065,9 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
{
|
||||
throw StorageException::CreateFromResponse(std::move(pHttpResponse));
|
||||
}
|
||||
response.ETag = Azure::ETag(httpResponse.GetHeaders().at("etag"));
|
||||
response.LastModified = Azure::DateTime::Parse(
|
||||
httpResponse.GetHeaders().at("last-modified"), Azure::DateTime::DateFormat::Rfc1123);
|
||||
return Azure::Response<SetBlobExpiryResult>(
|
||||
std::move(response), std::move(pHttpResponse));
|
||||
}
|
||||
@ -7294,6 +7635,27 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
response.ETag = Azure::ETag(httpResponse.GetHeaders().at("etag"));
|
||||
response.LastModified = Azure::DateTime::Parse(
|
||||
httpResponse.GetHeaders().at("last-modified"), Azure::DateTime::DateFormat::Rfc1123);
|
||||
auto x_ms_blob_sequence_number__iterator
|
||||
= httpResponse.GetHeaders().find("x-ms-blob-sequence-number");
|
||||
if (x_ms_blob_sequence_number__iterator != httpResponse.GetHeaders().end())
|
||||
{
|
||||
response.SequenceNumber = std::stoll(x_ms_blob_sequence_number__iterator->second);
|
||||
}
|
||||
response.IsServerEncrypted
|
||||
= httpResponse.GetHeaders().at("x-ms-request-server-encrypted") == "true";
|
||||
auto x_ms_encryption_key_sha256__iterator
|
||||
= httpResponse.GetHeaders().find("x-ms-encryption-key-sha256");
|
||||
if (x_ms_encryption_key_sha256__iterator != httpResponse.GetHeaders().end())
|
||||
{
|
||||
response.EncryptionKeySha256
|
||||
= Azure::Core::Convert::Base64Decode(x_ms_encryption_key_sha256__iterator->second);
|
||||
}
|
||||
auto x_ms_encryption_scope__iterator
|
||||
= httpResponse.GetHeaders().find("x-ms-encryption-scope");
|
||||
if (x_ms_encryption_scope__iterator != httpResponse.GetHeaders().end())
|
||||
{
|
||||
response.EncryptionScope = x_ms_encryption_scope__iterator->second;
|
||||
}
|
||||
return Azure::Response<SetBlobMetadataResult>(
|
||||
std::move(response), std::move(pHttpResponse));
|
||||
}
|
||||
@ -7303,6 +7665,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
Azure::Nullable<int32_t> Timeout;
|
||||
Models::AccessTier AccessTier;
|
||||
Azure::Nullable<Models::RehydratePriority> RehydratePriority;
|
||||
Azure::Nullable<std::string> LeaseId;
|
||||
Azure::Nullable<std::string> IfTags;
|
||||
}; // struct SetBlobAccessTierOptions
|
||||
|
||||
@ -7326,6 +7689,10 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
request.SetHeader(
|
||||
"x-ms-rehydrate-priority", options.RehydratePriority.Value().ToString());
|
||||
}
|
||||
if (options.LeaseId.HasValue())
|
||||
{
|
||||
request.SetHeader("x-ms-lease-id", options.LeaseId.Value());
|
||||
}
|
||||
if (options.IfTags.HasValue())
|
||||
{
|
||||
request.SetHeader("x-ms-if-tags", options.IfTags.Value());
|
||||
@ -7366,9 +7733,9 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
{
|
||||
Azure::Nullable<int32_t> Timeout;
|
||||
Storage::Metadata Metadata;
|
||||
std::map<std::string, std::string> Tags;
|
||||
std::string SourceUri;
|
||||
Azure::Nullable<std::string> LeaseId;
|
||||
Azure::Nullable<std::string> SourceLeaseId;
|
||||
Azure::Nullable<Models::AccessTier> AccessTier;
|
||||
Azure::Nullable<Models::RehydratePriority> RehydratePriority;
|
||||
Azure::Nullable<Azure::DateTime> IfModifiedSince;
|
||||
@ -7381,6 +7748,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
Azure::ETag SourceIfMatch;
|
||||
Azure::ETag SourceIfNoneMatch;
|
||||
Azure::Nullable<std::string> SourceIfTags;
|
||||
Azure::Nullable<std::string> SourceLeaseId;
|
||||
Azure::Nullable<bool> ShouldSealDestination;
|
||||
}; // struct StartBlobCopyFromUriOptions
|
||||
|
||||
@ -7403,15 +7771,25 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
{
|
||||
request.SetHeader("x-ms-meta-" + pair.first, pair.second);
|
||||
}
|
||||
if (!options.Tags.empty())
|
||||
{
|
||||
std::string blobTagsValue;
|
||||
for (const auto& tag : options.Tags)
|
||||
{
|
||||
if (!blobTagsValue.empty())
|
||||
{
|
||||
blobTagsValue += "&";
|
||||
}
|
||||
blobTagsValue += _internal::UrlEncodeQueryParameter(tag.first) + "="
|
||||
+ _internal::UrlEncodeQueryParameter(tag.second);
|
||||
}
|
||||
request.SetHeader("x-ms-tags", std::move(blobTagsValue));
|
||||
}
|
||||
request.SetHeader("x-ms-copy-source", options.SourceUri);
|
||||
if (options.LeaseId.HasValue())
|
||||
{
|
||||
request.SetHeader("x-ms-lease-id", options.LeaseId.Value());
|
||||
}
|
||||
if (options.SourceLeaseId.HasValue())
|
||||
{
|
||||
request.SetHeader("x-ms-source-lease-id", options.SourceLeaseId.Value());
|
||||
}
|
||||
if (options.AccessTier.HasValue())
|
||||
{
|
||||
request.SetHeader("x-ms-access-tier", options.AccessTier.Value().ToString());
|
||||
@ -7476,6 +7854,10 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
{
|
||||
request.SetHeader("x-ms-source-if-tags", options.SourceIfTags.Value());
|
||||
}
|
||||
if (options.SourceLeaseId.HasValue())
|
||||
{
|
||||
request.SetHeader("x-ms-source-lease-id", options.SourceLeaseId.Value());
|
||||
}
|
||||
auto pHttpResponse = pipeline.Send(request, context);
|
||||
Azure::Core::Http::RawResponse& httpResponse = *pHttpResponse;
|
||||
Models::_detail::StartBlobCopyFromUriResult response;
|
||||
@ -8047,12 +8429,6 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
response.ETag = Azure::ETag(httpResponse.GetHeaders().at("etag"));
|
||||
response.LastModified = Azure::DateTime::Parse(
|
||||
httpResponse.GetHeaders().at("last-modified"), Azure::DateTime::DateFormat::Rfc1123);
|
||||
auto x_ms_blob_sequence_number__iterator
|
||||
= httpResponse.GetHeaders().find("x-ms-blob-sequence-number");
|
||||
if (x_ms_blob_sequence_number__iterator != httpResponse.GetHeaders().end())
|
||||
{
|
||||
response.SequenceNumber = std::stoll(x_ms_blob_sequence_number__iterator->second);
|
||||
}
|
||||
return Azure::Response<Models::_detail::ReleaseBlobLeaseResult>(
|
||||
std::move(response), std::move(pHttpResponse));
|
||||
}
|
||||
@ -8271,6 +8647,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
Azure::Nullable<ContentHash> TransactionalContentHash;
|
||||
BlobHttpHeaders HttpHeaders;
|
||||
Storage::Metadata Metadata;
|
||||
std::map<std::string, std::string> Tags;
|
||||
Azure::Nullable<std::string> LeaseId;
|
||||
Azure::Nullable<Models::AccessTier> AccessTier;
|
||||
Azure::Nullable<std::string> EncryptionKey;
|
||||
@ -8368,6 +8745,20 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
{
|
||||
request.SetHeader("x-ms-meta-" + pair.first, pair.second);
|
||||
}
|
||||
if (!options.Tags.empty())
|
||||
{
|
||||
std::string blobTagsValue;
|
||||
for (const auto& tag : options.Tags)
|
||||
{
|
||||
if (!blobTagsValue.empty())
|
||||
{
|
||||
blobTagsValue += "&";
|
||||
}
|
||||
blobTagsValue += _internal::UrlEncodeQueryParameter(tag.first) + "="
|
||||
+ _internal::UrlEncodeQueryParameter(tag.second);
|
||||
}
|
||||
request.SetHeader("x-ms-tags", std::move(blobTagsValue));
|
||||
}
|
||||
if (options.LeaseId.HasValue())
|
||||
{
|
||||
request.SetHeader("x-ms-lease-id", options.LeaseId.Value());
|
||||
@ -8741,6 +9132,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
std::vector<std::pair<BlockType, std::string>> BlockList;
|
||||
BlobHttpHeaders HttpHeaders;
|
||||
Storage::Metadata Metadata;
|
||||
std::map<std::string, std::string> Tags;
|
||||
Azure::Nullable<std::string> LeaseId;
|
||||
Azure::Nullable<std::string> EncryptionKey;
|
||||
Azure::Nullable<std::vector<uint8_t>> EncryptionKeySha256;
|
||||
@ -8811,6 +9203,20 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
{
|
||||
request.SetHeader("x-ms-meta-" + pair.first, pair.second);
|
||||
}
|
||||
if (!options.Tags.empty())
|
||||
{
|
||||
std::string blobTagsValue;
|
||||
for (const auto& tag : options.Tags)
|
||||
{
|
||||
if (!blobTagsValue.empty())
|
||||
{
|
||||
blobTagsValue += "&";
|
||||
}
|
||||
blobTagsValue += _internal::UrlEncodeQueryParameter(tag.first) + "="
|
||||
+ _internal::UrlEncodeQueryParameter(tag.second);
|
||||
}
|
||||
request.SetHeader("x-ms-tags", std::move(blobTagsValue));
|
||||
}
|
||||
if (options.LeaseId.HasValue())
|
||||
{
|
||||
request.SetHeader("x-ms-lease-id", options.LeaseId.Value());
|
||||
@ -9122,6 +9528,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
Azure::ETag IfMatch;
|
||||
Azure::ETag IfNoneMatch;
|
||||
Azure::Nullable<std::string> IfTags;
|
||||
std::map<std::string, std::string> Tags;
|
||||
}; // struct CreatePageBlobOptions
|
||||
|
||||
static Azure::Response<CreatePageBlobResult> Create(
|
||||
@ -9170,6 +9577,20 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
{
|
||||
request.SetHeader("x-ms-meta-" + pair.first, pair.second);
|
||||
}
|
||||
if (!options.Tags.empty())
|
||||
{
|
||||
std::string blobTagsValue;
|
||||
for (const auto& tag : options.Tags)
|
||||
{
|
||||
if (!blobTagsValue.empty())
|
||||
{
|
||||
blobTagsValue += "&";
|
||||
}
|
||||
blobTagsValue += _internal::UrlEncodeQueryParameter(tag.first) + "="
|
||||
+ _internal::UrlEncodeQueryParameter(tag.second);
|
||||
}
|
||||
request.SetHeader("x-ms-tags", std::move(blobTagsValue));
|
||||
}
|
||||
if (options.LeaseId.HasValue())
|
||||
{
|
||||
request.SetHeader("x-ms-lease-id", options.LeaseId.Value());
|
||||
@ -9467,6 +9888,10 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
Azure::ETag IfMatch;
|
||||
Azure::ETag IfNoneMatch;
|
||||
Azure::Nullable<std::string> IfTags;
|
||||
Azure::Nullable<Azure::DateTime> SourceIfModifiedSince;
|
||||
Azure::Nullable<Azure::DateTime> SourceIfUnmodifiedSince;
|
||||
Azure::ETag SourceIfMatch;
|
||||
Azure::ETag SourceIfNoneMatch;
|
||||
}; // struct UploadPageBlobPagesFromUriOptions
|
||||
|
||||
static Azure::Response<UploadPagesFromUriResult> UploadPagesFromUri(
|
||||
@ -9587,6 +10012,28 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
{
|
||||
request.SetHeader("x-ms-if-tags", options.IfTags.Value());
|
||||
}
|
||||
if (options.SourceIfModifiedSince.HasValue())
|
||||
{
|
||||
request.SetHeader(
|
||||
"x-ms-source-if-modified-since",
|
||||
options.SourceIfModifiedSince.Value().ToString(
|
||||
Azure::DateTime::DateFormat::Rfc1123));
|
||||
}
|
||||
if (options.SourceIfUnmodifiedSince.HasValue())
|
||||
{
|
||||
request.SetHeader(
|
||||
"x-ms-source-if-unmodified-since",
|
||||
options.SourceIfUnmodifiedSince.Value().ToString(
|
||||
Azure::DateTime::DateFormat::Rfc1123));
|
||||
}
|
||||
if (options.SourceIfMatch.HasValue() && !options.SourceIfMatch.ToString().empty())
|
||||
{
|
||||
request.SetHeader("x-ms-source-if-match", options.SourceIfMatch.ToString());
|
||||
}
|
||||
if (options.SourceIfNoneMatch.HasValue() && !options.SourceIfNoneMatch.ToString().empty())
|
||||
{
|
||||
request.SetHeader("x-ms-source-if-none-match", options.SourceIfNoneMatch.ToString());
|
||||
}
|
||||
auto pHttpResponse = pipeline.Send(request, context);
|
||||
Azure::Core::Http::RawResponse& httpResponse = *pHttpResponse;
|
||||
UploadPagesFromUriResult response;
|
||||
@ -10247,6 +10694,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
Azure::Nullable<int32_t> Timeout;
|
||||
BlobHttpHeaders HttpHeaders;
|
||||
Storage::Metadata Metadata;
|
||||
std::map<std::string, std::string> Tags;
|
||||
Azure::Nullable<std::string> LeaseId;
|
||||
Azure::Nullable<std::string> EncryptionKey;
|
||||
Azure::Nullable<std::vector<uint8_t>> EncryptionKeySha256;
|
||||
@ -10305,6 +10753,20 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
{
|
||||
request.SetHeader("x-ms-meta-" + pair.first, pair.second);
|
||||
}
|
||||
if (!options.Tags.empty())
|
||||
{
|
||||
std::string blobTagsValue;
|
||||
for (const auto& tag : options.Tags)
|
||||
{
|
||||
if (!blobTagsValue.empty())
|
||||
{
|
||||
blobTagsValue += "&";
|
||||
}
|
||||
blobTagsValue += _internal::UrlEncodeQueryParameter(tag.first) + "="
|
||||
+ _internal::UrlEncodeQueryParameter(tag.second);
|
||||
}
|
||||
request.SetHeader("x-ms-tags", std::move(blobTagsValue));
|
||||
}
|
||||
if (options.LeaseId.HasValue())
|
||||
{
|
||||
request.SetHeader("x-ms-lease-id", options.LeaseId.Value());
|
||||
|
||||
@ -79,6 +79,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
_detail::BlobRestClient::AppendBlob::CreateAppendBlobOptions protocolLayerOptions;
|
||||
protocolLayerOptions.HttpHeaders = options.HttpHeaders;
|
||||
protocolLayerOptions.Metadata = options.Metadata;
|
||||
protocolLayerOptions.Tags = options.Tags;
|
||||
protocolLayerOptions.LeaseId = options.AccessConditions.LeaseId;
|
||||
protocolLayerOptions.IfModifiedSince = options.AccessConditions.IfModifiedSince;
|
||||
protocolLayerOptions.IfUnmodifiedSince = options.AccessConditions.IfUnmodifiedSince;
|
||||
|
||||
@ -525,6 +525,8 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
_detail::BlobRestClient::Blob::SetBlobAccessTierOptions protocolLayerOptions;
|
||||
protocolLayerOptions.AccessTier = tier;
|
||||
protocolLayerOptions.RehydratePriority = options.RehydratePriority;
|
||||
protocolLayerOptions.LeaseId = options.AccessConditions.LeaseId;
|
||||
protocolLayerOptions.IfTags = options.AccessConditions.TagConditions;
|
||||
return _detail::BlobRestClient::Blob::SetAccessTier(
|
||||
*m_pipeline, m_blobUrl, protocolLayerOptions, context);
|
||||
}
|
||||
@ -536,6 +538,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
{
|
||||
_detail::BlobRestClient::Blob::StartBlobCopyFromUriOptions protocolLayerOptions;
|
||||
protocolLayerOptions.Metadata = options.Metadata;
|
||||
protocolLayerOptions.Tags = options.Tags;
|
||||
protocolLayerOptions.SourceUri = sourceUri;
|
||||
protocolLayerOptions.AccessTier = options.AccessTier;
|
||||
protocolLayerOptions.RehydratePriority = options.RehydratePriority;
|
||||
@ -545,12 +548,12 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
protocolLayerOptions.IfMatch = options.AccessConditions.IfMatch;
|
||||
protocolLayerOptions.IfNoneMatch = options.AccessConditions.IfNoneMatch;
|
||||
protocolLayerOptions.IfTags = options.AccessConditions.TagConditions;
|
||||
protocolLayerOptions.SourceLeaseId = options.SourceAccessConditions.LeaseId;
|
||||
protocolLayerOptions.SourceIfModifiedSince = options.SourceAccessConditions.IfModifiedSince;
|
||||
protocolLayerOptions.SourceIfUnmodifiedSince = options.SourceAccessConditions.IfUnmodifiedSince;
|
||||
protocolLayerOptions.SourceIfMatch = options.SourceAccessConditions.IfMatch;
|
||||
protocolLayerOptions.SourceIfNoneMatch = options.SourceAccessConditions.IfNoneMatch;
|
||||
protocolLayerOptions.ShouldSealDestination = options.ShouldSealDestination;
|
||||
protocolLayerOptions.SourceLeaseId = options.SourceAccessConditions.LeaseId;
|
||||
protocolLayerOptions.SourceIfTags = options.SourceAccessConditions.TagConditions;
|
||||
|
||||
auto response = _detail::BlobRestClient::Blob::StartCopyFromUri(
|
||||
|
||||
@ -261,6 +261,10 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
{
|
||||
i.Details.IsSealed = false;
|
||||
}
|
||||
if (i.Details.CopyStatus.HasValue() && !i.Details.IsIncrementalCopy.HasValue())
|
||||
{
|
||||
i.Details.IsIncrementalCopy = false;
|
||||
}
|
||||
}
|
||||
|
||||
ListBlobsPagedResponse pagedResponse;
|
||||
@ -310,6 +314,10 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
{
|
||||
i.Details.IsSealed = false;
|
||||
}
|
||||
if (i.Details.CopyStatus.HasValue() && !i.Details.IsIncrementalCopy.HasValue())
|
||||
{
|
||||
i.Details.IsIncrementalCopy = false;
|
||||
}
|
||||
}
|
||||
|
||||
ListBlobsByHierarchyPagedResponse pagedResponse;
|
||||
|
||||
@ -98,6 +98,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
protocolLayerOptions.TransactionalContentHash = options.TransactionalContentHash;
|
||||
protocolLayerOptions.HttpHeaders = options.HttpHeaders;
|
||||
protocolLayerOptions.Metadata = options.Metadata;
|
||||
protocolLayerOptions.Tags = options.Tags;
|
||||
protocolLayerOptions.AccessTier = options.AccessTier;
|
||||
protocolLayerOptions.LeaseId = options.AccessConditions.LeaseId;
|
||||
protocolLayerOptions.IfModifiedSince = options.AccessConditions.IfModifiedSince;
|
||||
@ -138,6 +139,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
UploadBlockBlobOptions uploadBlockBlobOptions;
|
||||
uploadBlockBlobOptions.HttpHeaders = options.HttpHeaders;
|
||||
uploadBlockBlobOptions.Metadata = options.Metadata;
|
||||
uploadBlockBlobOptions.Tags = options.Tags;
|
||||
uploadBlockBlobOptions.AccessTier = options.AccessTier;
|
||||
return Upload(contentStream, uploadBlockBlobOptions, context);
|
||||
}
|
||||
@ -187,6 +189,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
CommitBlockListOptions commitBlockListOptions;
|
||||
commitBlockListOptions.HttpHeaders = options.HttpHeaders;
|
||||
commitBlockListOptions.Metadata = options.Metadata;
|
||||
commitBlockListOptions.Tags = options.Tags;
|
||||
commitBlockListOptions.AccessTier = options.AccessTier;
|
||||
auto commitBlockListResponse = CommitBlockList(blockIds, commitBlockListOptions, context);
|
||||
|
||||
@ -219,6 +222,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
UploadBlockBlobOptions uploadBlockBlobOptions;
|
||||
uploadBlockBlobOptions.HttpHeaders = options.HttpHeaders;
|
||||
uploadBlockBlobOptions.Metadata = options.Metadata;
|
||||
uploadBlockBlobOptions.Tags = options.Tags;
|
||||
uploadBlockBlobOptions.AccessTier = options.AccessTier;
|
||||
return Upload(contentStream, uploadBlockBlobOptions, context);
|
||||
}
|
||||
@ -276,6 +280,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
CommitBlockListOptions commitBlockListOptions;
|
||||
commitBlockListOptions.HttpHeaders = options.HttpHeaders;
|
||||
commitBlockListOptions.Metadata = options.Metadata;
|
||||
commitBlockListOptions.Tags = options.Tags;
|
||||
commitBlockListOptions.AccessTier = options.AccessTier;
|
||||
auto commitBlockListResponse = CommitBlockList(blockIds, commitBlockListOptions, context);
|
||||
|
||||
@ -351,6 +356,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
}
|
||||
protocolLayerOptions.HttpHeaders = options.HttpHeaders;
|
||||
protocolLayerOptions.Metadata = options.Metadata;
|
||||
protocolLayerOptions.Tags = options.Tags;
|
||||
protocolLayerOptions.AccessTier = options.AccessTier;
|
||||
protocolLayerOptions.LeaseId = options.AccessConditions.LeaseId;
|
||||
protocolLayerOptions.IfModifiedSince = options.AccessConditions.IfModifiedSince;
|
||||
|
||||
@ -86,6 +86,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
protocolLayerOptions.HttpHeaders = options.HttpHeaders;
|
||||
protocolLayerOptions.Metadata = options.Metadata;
|
||||
protocolLayerOptions.AccessTier = options.AccessTier;
|
||||
protocolLayerOptions.Tags = options.Tags;
|
||||
protocolLayerOptions.LeaseId = options.AccessConditions.LeaseId;
|
||||
protocolLayerOptions.IfModifiedSince = options.AccessConditions.IfModifiedSince;
|
||||
protocolLayerOptions.IfUnmodifiedSince = options.AccessConditions.IfUnmodifiedSince;
|
||||
@ -174,6 +175,10 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
protocolLayerOptions.IfMatch = options.AccessConditions.IfMatch;
|
||||
protocolLayerOptions.IfNoneMatch = options.AccessConditions.IfNoneMatch;
|
||||
protocolLayerOptions.IfTags = options.AccessConditions.TagConditions;
|
||||
protocolLayerOptions.SourceIfModifiedSince = options.SourceAccessConditions.IfModifiedSince;
|
||||
protocolLayerOptions.SourceIfUnmodifiedSince = options.SourceAccessConditions.IfUnmodifiedSince;
|
||||
protocolLayerOptions.SourceIfMatch = options.SourceAccessConditions.IfMatch;
|
||||
protocolLayerOptions.SourceIfNoneMatch = options.SourceAccessConditions.IfNoneMatch;
|
||||
if (m_customerProvidedKey.HasValue())
|
||||
{
|
||||
protocolLayerOptions.EncryptionKey = m_customerProvidedKey.Value().Key;
|
||||
|
||||
@ -93,6 +93,19 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
EXPECT_THROW(appendBlobClient.Delete(), StorageException);
|
||||
}
|
||||
|
||||
TEST_F(AppendBlobClientTest, CreateWithTags)
|
||||
{
|
||||
auto appendBlobClient = Azure::Storage::Blobs::AppendBlobClient::CreateFromConnectionString(
|
||||
StandardStorageConnectionString(), m_containerName, RandomString());
|
||||
Blobs::CreateAppendBlobOptions options;
|
||||
options.Tags["key1"] = "value1";
|
||||
options.Tags["key2"] = "value2";
|
||||
options.Tags["key3 +-./:=_"] = "v1 +-./:=_";
|
||||
appendBlobClient.Create(options);
|
||||
|
||||
EXPECT_EQ(appendBlobClient.GetTags().Value, options.Tags);
|
||||
}
|
||||
|
||||
TEST_F(AppendBlobClientTest, AccessConditionLastModifiedTime)
|
||||
{
|
||||
auto appendBlobClient = Azure::Storage::Blobs::AppendBlobClient::CreateFromConnectionString(
|
||||
@ -201,31 +214,15 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
{
|
||||
auto sourceBlobClient = Azure::Storage::Blobs::AppendBlobClient::CreateFromConnectionString(
|
||||
StandardStorageConnectionString(), m_containerName, RandomString());
|
||||
sourceBlobClient.Create();
|
||||
Blobs::BlobLeaseClient sourceLeaseClient(
|
||||
sourceBlobClient, Blobs::BlobLeaseClient::CreateUniqueLeaseId());
|
||||
auto leaseResponse = sourceLeaseClient.Acquire(Blobs::BlobLeaseClient::InfiniteLeaseDuration);
|
||||
std::string leaseId = leaseResponse.Value.LeaseId;
|
||||
Azure::ETag eTag = leaseResponse.Value.ETag;
|
||||
auto lastModifiedTime = leaseResponse.Value.LastModified;
|
||||
auto createResponse = sourceBlobClient.Create();
|
||||
Azure::ETag eTag = createResponse.Value.ETag;
|
||||
auto lastModifiedTime = createResponse.Value.LastModified;
|
||||
auto timeBeforeStr = lastModifiedTime - std::chrono::seconds(1);
|
||||
auto timeAfterStr = lastModifiedTime + std::chrono::seconds(1);
|
||||
|
||||
auto destBlobClient = Azure::Storage::Blobs::AppendBlobClient::CreateFromConnectionString(
|
||||
StandardStorageConnectionString(), m_containerName, RandomString());
|
||||
|
||||
{
|
||||
Blobs::StartBlobCopyFromUriOptions options;
|
||||
options.SourceAccessConditions.LeaseId = Blobs::BlobLeaseClient::CreateUniqueLeaseId();
|
||||
/*
|
||||
don't know why, the copy operation also succeeds even if the lease ID doesn't match.
|
||||
EXPECT_THROW(
|
||||
destBlobClient.StartCopyFromUri(sourceBlobClient.GetUrl(), options), StorageException);
|
||||
*/
|
||||
options.SourceAccessConditions.LeaseId = leaseId;
|
||||
EXPECT_NO_THROW(destBlobClient.StartCopyFromUri(sourceBlobClient.GetUrl(), options));
|
||||
}
|
||||
sourceLeaseClient.Break();
|
||||
{
|
||||
Blobs::StartBlobCopyFromUriOptions options;
|
||||
options.SourceAccessConditions.IfMatch = eTag;
|
||||
@ -277,20 +274,9 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
EXPECT_TRUE(getPropertiesResult.Value.IsSealed.HasValue());
|
||||
EXPECT_FALSE(getPropertiesResult.Value.IsSealed.Value());
|
||||
|
||||
Azure::Storage::Blobs::ListBlobsOptions options;
|
||||
options.Prefix = blobName;
|
||||
for (auto pageResponse = m_blobContainerClient->ListBlobs(options); pageResponse.HasPage();
|
||||
pageResponse.MoveToNextPage())
|
||||
{
|
||||
for (const auto& blob : pageResponse.Blobs)
|
||||
{
|
||||
if (blob.Name == blobName)
|
||||
{
|
||||
EXPECT_TRUE(blob.Details.IsSealed.HasValue());
|
||||
EXPECT_FALSE(blob.Details.IsSealed.Value());
|
||||
}
|
||||
}
|
||||
}
|
||||
auto blobItem = GetBlobItem(blobName);
|
||||
EXPECT_TRUE(blobItem.Details.IsSealed.HasValue());
|
||||
EXPECT_FALSE(blobItem.Details.IsSealed.Value());
|
||||
|
||||
Blobs::SealAppendBlobOptions sealOptions;
|
||||
sealOptions.AccessConditions.IfAppendPositionEqual = m_blobContent.size() + 1;
|
||||
@ -310,18 +296,9 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
EXPECT_TRUE(getPropertiesResult.Value.IsSealed.HasValue());
|
||||
EXPECT_TRUE(getPropertiesResult.Value.IsSealed.Value());
|
||||
|
||||
for (auto pageResponse = m_blobContainerClient->ListBlobs(options); pageResponse.HasPage();
|
||||
pageResponse.MoveToNextPage())
|
||||
{
|
||||
for (const auto& blob : pageResponse.Blobs)
|
||||
{
|
||||
if (blob.Name == blobName)
|
||||
{
|
||||
EXPECT_TRUE(blob.Details.IsSealed.HasValue());
|
||||
EXPECT_TRUE(blob.Details.IsSealed.Value());
|
||||
}
|
||||
}
|
||||
}
|
||||
blobItem = GetBlobItem(blobName);
|
||||
EXPECT_TRUE(blobItem.Details.IsSealed.HasValue());
|
||||
EXPECT_TRUE(blobItem.Details.IsSealed.Value());
|
||||
|
||||
auto blobClient2 = m_blobContainerClient->GetAppendBlobClient(RandomString());
|
||||
|
||||
|
||||
@ -51,6 +51,27 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
*_internal::ParseConnectionString(StandardStorageConnectionString()).KeyCredential);
|
||||
}
|
||||
|
||||
Blobs::Models::BlobItem BlobContainerClientTest::GetBlobItem(
|
||||
const std::string& blobName,
|
||||
Blobs::Models::ListBlobsIncludeFlags include)
|
||||
{
|
||||
Blobs::ListBlobsOptions options;
|
||||
options.Prefix = blobName;
|
||||
options.Include = include;
|
||||
for (auto page = m_blobContainerClient->ListBlobs(options); page.HasPage();
|
||||
page.MoveToNextPage())
|
||||
{
|
||||
for (auto& blob : page.Blobs)
|
||||
{
|
||||
if (blob.Name == blobName)
|
||||
{
|
||||
return std::move(blob);
|
||||
}
|
||||
}
|
||||
}
|
||||
std::abort();
|
||||
}
|
||||
|
||||
TEST_F(BlobContainerClientTest, CreateDelete)
|
||||
{
|
||||
auto container_client = Azure::Storage::Blobs::BlobContainerClient::CreateFromConnectionString(
|
||||
@ -477,6 +498,23 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
createOptions.PreventEncryptionScopeOverride.Value());
|
||||
auto appendBlobClient = containerClient.GetAppendBlobClient(blobName);
|
||||
auto blobContentInfo = appendBlobClient.Create();
|
||||
{
|
||||
Blobs::ListBlobsOptions listOptions;
|
||||
listOptions.Prefix = blobName;
|
||||
for (auto page = containerClient.ListBlobs(listOptions); page.HasPage();
|
||||
page.MoveToNextPage())
|
||||
{
|
||||
for (auto& blob : page.Blobs)
|
||||
{
|
||||
if (blob.Name == blobName)
|
||||
{
|
||||
EXPECT_TRUE(blob.Details.IsServerEncrypted);
|
||||
EXPECT_TRUE(blob.Details.EncryptionScope.HasValue());
|
||||
EXPECT_EQ(blob.Details.EncryptionScope.Value(), TestEncryptionScope);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
appendBlobClient.Delete();
|
||||
EXPECT_TRUE(blobContentInfo.Value.EncryptionScope.HasValue());
|
||||
EXPECT_EQ(blobContentInfo.Value.EncryptionScope.Value(), TestEncryptionScope);
|
||||
@ -498,6 +536,10 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
auto blobContentInfo = appendBlobClient.Create();
|
||||
EXPECT_TRUE(blobContentInfo.Value.EncryptionScope.HasValue());
|
||||
EXPECT_EQ(blobContentInfo.Value.EncryptionScope.Value(), TestEncryptionScope);
|
||||
auto setMetadataRes = appendBlobClient.SetMetadata({});
|
||||
EXPECT_TRUE(setMetadataRes.Value.IsServerEncrypted);
|
||||
ASSERT_TRUE(setMetadataRes.Value.EncryptionScope.HasValue());
|
||||
EXPECT_EQ(setMetadataRes.Value.EncryptionScope.Value(), TestEncryptionScope);
|
||||
auto properties = appendBlobClient.GetProperties().Value;
|
||||
EXPECT_TRUE(properties.EncryptionScope.HasValue());
|
||||
EXPECT_EQ(properties.EncryptionScope.Value(), TestEncryptionScope);
|
||||
@ -569,13 +611,24 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
EXPECT_TRUE(blobContentInfo.EncryptionKeySha256.HasValue());
|
||||
EXPECT_EQ(
|
||||
blobContentInfo.EncryptionKeySha256.Value(), options.CustomerProvidedKey.Value().KeyHash);
|
||||
auto blobItem = GetBlobItem(appendBlobName);
|
||||
EXPECT_TRUE(blobItem.Details.IsServerEncrypted);
|
||||
EXPECT_TRUE(blobItem.Details.EncryptionKeySha256.HasValue());
|
||||
EXPECT_EQ(
|
||||
blobItem.Details.EncryptionKeySha256.Value(),
|
||||
options.CustomerProvidedKey.Value().KeyHash);
|
||||
|
||||
bodyStream.Rewind();
|
||||
EXPECT_NO_THROW(appendBlob.AppendBlock(bodyStream));
|
||||
EXPECT_NO_THROW(appendBlob.AppendBlockFromUri(copySourceBlob.GetUrl() + GetSas()));
|
||||
EXPECT_NO_THROW(appendBlob.Download());
|
||||
EXPECT_NO_THROW(appendBlob.GetProperties());
|
||||
EXPECT_NO_THROW(appendBlob.SetMetadata({}));
|
||||
auto setMetadataRes = appendBlob.SetMetadata({});
|
||||
EXPECT_TRUE(setMetadataRes.Value.IsServerEncrypted);
|
||||
ASSERT_TRUE(setMetadataRes.Value.EncryptionKeySha256.HasValue());
|
||||
EXPECT_EQ(
|
||||
setMetadataRes.Value.EncryptionKeySha256.Value(),
|
||||
options.CustomerProvidedKey.Value().KeyHash);
|
||||
EXPECT_NO_THROW(appendBlob.CreateSnapshot());
|
||||
|
||||
auto appendBlobClientWithoutEncryptionKey
|
||||
@ -681,16 +734,47 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
StandardStorageConnectionString(), LowercaseRandomString());
|
||||
containerClient.Create();
|
||||
|
||||
std::string leaseId = Blobs::BlobLeaseClient::CreateUniqueLeaseId();
|
||||
const std::string leaseId = Blobs::BlobLeaseClient::CreateUniqueLeaseId();
|
||||
const std::string dummyLeaseId = Blobs::BlobLeaseClient::CreateUniqueLeaseId();
|
||||
Blobs::BlobLeaseClient leaseClient(containerClient, leaseId);
|
||||
leaseClient.Acquire(std::chrono::seconds(30));
|
||||
EXPECT_THROW(containerClient.Delete(), StorageException);
|
||||
Blobs::DeleteBlobContainerOptions options;
|
||||
options.AccessConditions.LeaseId = leaseId;
|
||||
EXPECT_NO_THROW(containerClient.Delete(options));
|
||||
{
|
||||
Blobs::GetBlobContainerPropertiesOptions options;
|
||||
options.AccessConditions.LeaseId = dummyLeaseId;
|
||||
EXPECT_THROW(containerClient.GetProperties(options), StorageException);
|
||||
options.AccessConditions.LeaseId = leaseId;
|
||||
EXPECT_NO_THROW(containerClient.GetProperties(options));
|
||||
}
|
||||
{
|
||||
Blobs::SetBlobContainerMetadataOptions options;
|
||||
options.AccessConditions.LeaseId = dummyLeaseId;
|
||||
EXPECT_THROW(containerClient.SetMetadata({}, options), StorageException);
|
||||
options.AccessConditions.LeaseId = leaseId;
|
||||
EXPECT_NO_THROW(containerClient.SetMetadata({}, options));
|
||||
}
|
||||
{
|
||||
Blobs::GetBlobContainerAccessPolicyOptions options;
|
||||
options.AccessConditions.LeaseId = dummyLeaseId;
|
||||
EXPECT_THROW(containerClient.GetAccessPolicy(options), StorageException);
|
||||
options.AccessConditions.LeaseId = leaseId;
|
||||
EXPECT_NO_THROW(containerClient.GetAccessPolicy(options));
|
||||
}
|
||||
{
|
||||
Blobs::SetBlobContainerAccessPolicyOptions options;
|
||||
options.AccessConditions.LeaseId = dummyLeaseId;
|
||||
EXPECT_THROW(containerClient.SetAccessPolicy(options), StorageException);
|
||||
options.AccessConditions.LeaseId = leaseId;
|
||||
EXPECT_NO_THROW(containerClient.SetAccessPolicy(options));
|
||||
}
|
||||
{
|
||||
EXPECT_THROW(containerClient.Delete(), StorageException);
|
||||
Blobs::DeleteBlobContainerOptions options;
|
||||
options.AccessConditions.LeaseId = leaseId;
|
||||
EXPECT_NO_THROW(containerClient.Delete(options));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(BlobContainerClientTest, DISABLED_Tags)
|
||||
TEST_F(BlobContainerClientTest, Tags)
|
||||
{
|
||||
std::string blobName = RandomString();
|
||||
auto blobClient = Azure::Storage::Blobs::AppendBlobClient::CreateFromConnectionString(
|
||||
@ -710,6 +794,8 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
std::string v2 = RandomString();
|
||||
std::string c3 = "k" + RandomString();
|
||||
std::string v3 = RandomString();
|
||||
std::string c4 = "key3 +-./:=_";
|
||||
std::string v4 = "v1 +-./:=_";
|
||||
tags[c1] = v1;
|
||||
tags[c2] = v2;
|
||||
tags[c3] = v3;
|
||||
@ -722,11 +808,16 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
|
||||
properties = blobClient.GetProperties().Value;
|
||||
EXPECT_TRUE(properties.TagCount.HasValue());
|
||||
EXPECT_EQ(properties.TagCount.Value(), static_cast<int64_t>(tags.size()));
|
||||
EXPECT_EQ(properties.TagCount.Value(), static_cast<int32_t>(tags.size()));
|
||||
|
||||
downloadRet = blobClient.Download();
|
||||
EXPECT_TRUE(downloadRet.Value.Details.TagCount.HasValue());
|
||||
EXPECT_EQ(downloadRet.Value.Details.TagCount.Value(), static_cast<int64_t>(tags.size()));
|
||||
ASSERT_TRUE(downloadRet.Value.Details.TagCount.HasValue());
|
||||
EXPECT_EQ(downloadRet.Value.Details.TagCount.Value(), static_cast<int32_t>(tags.size()));
|
||||
|
||||
auto blobItem = GetBlobItem(blobName, Blobs::Models::ListBlobsIncludeFlags::Tags);
|
||||
ASSERT_TRUE(blobItem.Details.TagCount.HasValue());
|
||||
EXPECT_EQ(blobItem.Details.TagCount.Value(), static_cast<int32_t>(tags.size()));
|
||||
EXPECT_EQ(blobItem.Details.Tags, tags);
|
||||
|
||||
auto blobServiceClient = Azure::Storage::Blobs::BlobServiceClient::CreateFromConnectionString(
|
||||
StandardStorageConnectionString());
|
||||
@ -762,7 +853,7 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
EXPECT_EQ(findResults[0].BlobContainerName, m_containerName);
|
||||
}
|
||||
|
||||
TEST_F(BlobContainerClientTest, DISABLED_AccessConditionTags)
|
||||
TEST_F(BlobContainerClientTest, AccessConditionTags)
|
||||
{
|
||||
std::map<std::string, std::string> tags;
|
||||
std::string c1 = "k" + RandomString();
|
||||
@ -960,6 +1051,15 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
blockBlobClient.UploadFrom(contentData.data(), contentData.size());
|
||||
blockBlobClient.SetTags(tags);
|
||||
|
||||
{
|
||||
Blobs::SetBlobAccessTierOptions options;
|
||||
options.AccessConditions.TagConditions = successWhereExpression;
|
||||
EXPECT_NO_THROW(blockBlobClient.SetAccessTier(Blobs::Models::AccessTier::Hot, options));
|
||||
options.AccessConditions.TagConditions = failWhereExpression;
|
||||
EXPECT_THROW(
|
||||
blockBlobClient.SetAccessTier(Blobs::Models::AccessTier::Hot, options), StorageException);
|
||||
}
|
||||
|
||||
{
|
||||
Blobs::UploadBlockBlobOptions options;
|
||||
options.AccessConditions.TagConditions = failWhereExpression;
|
||||
|
||||
@ -13,6 +13,9 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
static void TearDownTestSuite();
|
||||
|
||||
static std::string GetSas();
|
||||
static Blobs::Models::BlobItem GetBlobItem(
|
||||
const std::string& blobName,
|
||||
Blobs::Models::ListBlobsIncludeFlags include = Blobs::Models::ListBlobsIncludeFlags::None);
|
||||
|
||||
static std::shared_ptr<Azure::Storage::Blobs::BlobContainerClient> m_blobContainerClient;
|
||||
static std::string m_containerName;
|
||||
|
||||
@ -105,19 +105,19 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
blobClient0.Delete(options);
|
||||
};
|
||||
|
||||
// auto verify_blob_tags = [&](const std::string& sas) {
|
||||
// blobClient0.Create();
|
||||
// std::map<std::string, std::string> tags = {{"tag_key1", "tag_value1"}};
|
||||
// blobClient0.SetTags(tags);
|
||||
// auto blobClient = Blobs::AppendBlobClient(blobUrl + sas);
|
||||
// EXPECT_NO_THROW(blobClient.GetTags());
|
||||
// blobClient0.Delete();
|
||||
//};
|
||||
auto verify_blob_tags = [&](const std::string& sas) {
|
||||
blobClient0.Create();
|
||||
std::map<std::string, std::string> tags = {{"tag_key1", "tag_value1"}};
|
||||
blobClient0.SetTags(tags);
|
||||
auto blobClient = Blobs::AppendBlobClient(blobUrl + sas);
|
||||
EXPECT_NO_THROW(blobClient.GetTags());
|
||||
blobClient0.Delete();
|
||||
};
|
||||
|
||||
// auto verify_blob_filter = [&](const std::string& sas) {
|
||||
// auto serviceClient = Blobs::BlobServiceClient(serviceUrl + sas);
|
||||
// EXPECT_NO_THROW(serviceClient.FindBlobsByTags("\"tag_key1\" = 'tag_value1'"));
|
||||
//};
|
||||
auto verify_blob_filter = [&](const std::string& sas) {
|
||||
auto serviceClient = Blobs::BlobServiceClient(serviceUrl + sas);
|
||||
EXPECT_NO_THROW(serviceClient.FindBlobsByTags("\"tag_key1\" = 'tag_value1'"));
|
||||
};
|
||||
|
||||
for (auto permissions : {
|
||||
Sas::AccountSasPermissions::All,
|
||||
@ -161,11 +161,11 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
}
|
||||
if ((permissions & Sas::AccountSasPermissions::Tags) == Sas::AccountSasPermissions::Tags)
|
||||
{
|
||||
// verify_blob_tags(sasToken);
|
||||
verify_blob_tags(sasToken);
|
||||
}
|
||||
if ((permissions & Sas::AccountSasPermissions::Filter) == Sas::AccountSasPermissions::Filter)
|
||||
{
|
||||
// verify_blob_filter(sasToken);
|
||||
verify_blob_filter(sasToken);
|
||||
}
|
||||
}
|
||||
|
||||
@ -210,8 +210,8 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
}
|
||||
if ((permissions & Sas::BlobSasPermissions::Tags) == Sas::BlobSasPermissions::Tags)
|
||||
{
|
||||
// verify_blob_tags(sasToken);
|
||||
// verify_blob_tags(sasToken2);
|
||||
verify_blob_tags(sasToken);
|
||||
verify_blob_tags(sasToken2);
|
||||
}
|
||||
}
|
||||
|
||||
@ -322,8 +322,8 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
if ((permissions & Sas::BlobContainerSasPermissions::Tags)
|
||||
== Sas::BlobContainerSasPermissions::Tags)
|
||||
{
|
||||
// verify_blob_tags(sasToken);
|
||||
// verify_blob_tags(sasToken2);
|
||||
verify_blob_tags(sasToken);
|
||||
verify_blob_tags(sasToken2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -77,6 +77,32 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
EXPECT_THROW(blockBlobClient.Delete(), StorageException);
|
||||
}
|
||||
|
||||
TEST_F(BlockBlobClientTest, SoftDelete)
|
||||
{
|
||||
const std::string blobName = RandomString();
|
||||
std::vector<uint8_t> emptyContent;
|
||||
auto blockBlobClient = Azure::Storage::Blobs::BlockBlobClient::CreateFromConnectionString(
|
||||
StandardStorageConnectionString(), m_containerName, blobName);
|
||||
auto blobContent = Azure::Core::IO::MemoryBodyStream(emptyContent.data(), emptyContent.size());
|
||||
blockBlobClient.Upload(blobContent);
|
||||
|
||||
auto blobItem = GetBlobItem(blobName);
|
||||
EXPECT_FALSE(blobItem.IsDeleted);
|
||||
EXPECT_FALSE(blobItem.Details.DeletedOn.HasValue());
|
||||
EXPECT_FALSE(blobItem.Details.RemainingRetentionDays.HasValue());
|
||||
|
||||
blockBlobClient.Delete();
|
||||
|
||||
/*
|
||||
// Soft delete doesn't work in storage account with versioning enabled.
|
||||
blobItem = GetBlobItem(blobName, Blobs::Models::ListBlobsIncludeFlags::Deleted);
|
||||
EXPECT_TRUE(blobItem.IsDeleted);
|
||||
ASSERT_TRUE(blobItem.Details.DeletedOn.HasValue());
|
||||
EXPECT_TRUE(IsValidTime(blobItem.Details.DeletedOn.Value()));
|
||||
EXPECT_TRUE(blobItem.Details.RemainingRetentionDays.HasValue());
|
||||
*/
|
||||
}
|
||||
|
||||
TEST_F(BlockBlobClientTest, UploadDownload)
|
||||
{
|
||||
auto res = m_blockBlobClient->Download();
|
||||
@ -108,6 +134,49 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
EXPECT_EQ(res.Value.BlobSize, static_cast<int64_t>(m_blobContent.size()));
|
||||
}
|
||||
|
||||
TEST_F(BlockBlobClientTest, UploadWithTags)
|
||||
{
|
||||
auto blockBlobClient = Azure::Storage::Blobs::BlockBlobClient::CreateFromConnectionString(
|
||||
StandardStorageConnectionString(), m_containerName, RandomString());
|
||||
std::map<std::string, std::string> tags;
|
||||
tags["key1"] = "value1";
|
||||
tags["key2"] = "value2";
|
||||
tags["key3 +-./:=_"] = "v1 +-./:=_";
|
||||
|
||||
std::vector<uint8_t> blobContent(100, 'a');
|
||||
{
|
||||
Blobs::UploadBlockBlobOptions options;
|
||||
options.Tags = tags;
|
||||
auto stream = Azure::Core::IO::MemoryBodyStream(blobContent.data(), blobContent.size());
|
||||
blockBlobClient.Upload(stream, options);
|
||||
EXPECT_EQ(blockBlobClient.GetTags().Value, tags);
|
||||
blockBlobClient.Delete();
|
||||
}
|
||||
|
||||
{
|
||||
Blobs::UploadBlockBlobFromOptions options;
|
||||
options.TransferOptions.SingleUploadThreshold = 0;
|
||||
options.TransferOptions.ChunkSize = blobContent.size() / 2;
|
||||
options.Tags = tags;
|
||||
|
||||
{
|
||||
blockBlobClient.UploadFrom(blobContent.data(), blobContent.size(), options);
|
||||
EXPECT_EQ(blockBlobClient.GetTags().Value, tags);
|
||||
blockBlobClient.Delete();
|
||||
}
|
||||
{
|
||||
const std::string tempFilename = RandomString();
|
||||
{
|
||||
Azure::Storage::_internal::FileWriter fileWriter(tempFilename);
|
||||
fileWriter.Write(blobContent.data(), blobContent.size(), 0);
|
||||
}
|
||||
blockBlobClient.UploadFrom(tempFilename, options);
|
||||
EXPECT_EQ(blockBlobClient.GetTags().Value, tags);
|
||||
blockBlobClient.Delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(BlockBlobClientTest, DownloadTransactionalHash)
|
||||
{
|
||||
const std::vector<uint8_t> dataPart1(static_cast<size_t>(4_MB + 1), 'a');
|
||||
@ -204,24 +273,7 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
EXPECT_TRUE(IsValidTime(res.Value.LastAccessedOn.Value()));
|
||||
}
|
||||
{
|
||||
Azure::DateTime lastAccessedOn;
|
||||
|
||||
Azure::Storage::Blobs::ListBlobsOptions options;
|
||||
options.Prefix = m_blobName;
|
||||
for (auto pageResult = m_blobContainerClient->ListBlobs(options); pageResult.HasPage();
|
||||
pageResult.MoveToNextPage())
|
||||
{
|
||||
for (const auto& blob : pageResult.Blobs)
|
||||
{
|
||||
if (blob.Name == m_blobName)
|
||||
{
|
||||
lastAccessedOn = blob.Details.LastAccessedOn.Value();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_TRUE(IsValidTime(lastAccessedOn));
|
||||
EXPECT_TRUE(IsValidTime(GetBlobItem(m_blobName).Details.LastAccessedOn.Value()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -256,36 +308,52 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
|
||||
TEST_F(BlockBlobClientTest, CopyFromUri)
|
||||
{
|
||||
auto blobClient = m_blobContainerClient->GetBlobClient(RandomString());
|
||||
const std::string blobName = RandomString();
|
||||
auto blobClient = m_blobContainerClient->GetBlobClient(blobName);
|
||||
auto res = blobClient.StartCopyFromUri(m_blockBlobClient->GetUrl());
|
||||
EXPECT_EQ(res.GetRawResponse().GetStatusCode(), Azure::Core::Http::HttpStatusCode::Accepted);
|
||||
res.PollUntilDone(std::chrono::seconds(1));
|
||||
auto properties = blobClient.GetProperties().Value;
|
||||
EXPECT_FALSE(properties.CopyId.Value().empty());
|
||||
EXPECT_FALSE(properties.CopySource.Value().empty());
|
||||
EXPECT_TRUE(
|
||||
properties.CopyStatus.Value() == Azure::Storage::Blobs::Models::CopyStatus::Pending
|
||||
|| properties.CopyStatus.Value() == Azure::Storage::Blobs::Models::CopyStatus::Success);
|
||||
properties.CopyStatus.Value() == Azure::Storage::Blobs::Models::CopyStatus::Success);
|
||||
EXPECT_FALSE(properties.CopyProgress.Value().empty());
|
||||
if (properties.CopyStatus.Value() == Azure::Storage::Blobs::Models::CopyStatus::Success)
|
||||
{
|
||||
EXPECT_TRUE(IsValidTime(properties.CopyCompletedOn.Value()));
|
||||
}
|
||||
EXPECT_TRUE(IsValidTime(properties.CopyCompletedOn.Value()));
|
||||
ASSERT_TRUE(properties.IsIncrementalCopy.HasValue());
|
||||
EXPECT_FALSE(properties.IsIncrementalCopy.Value());
|
||||
EXPECT_FALSE(properties.IncrementalCopyDestinationSnapshot.HasValue());
|
||||
|
||||
auto downloadResult = blobClient.Download();
|
||||
EXPECT_FALSE(downloadResult.Value.Details.CopyId.Value().empty());
|
||||
EXPECT_FALSE(downloadResult.Value.Details.CopySource.Value().empty());
|
||||
EXPECT_TRUE(
|
||||
downloadResult.Value.Details.CopyStatus.Value()
|
||||
== Azure::Storage::Blobs::Models::CopyStatus::Pending
|
||||
|| downloadResult.Value.Details.CopyStatus.Value()
|
||||
== Azure::Storage::Blobs::Models::CopyStatus::Success);
|
||||
== Azure::Storage::Blobs::Models::CopyStatus::Success);
|
||||
EXPECT_FALSE(downloadResult.Value.Details.CopyProgress.Value().empty());
|
||||
if (downloadResult.Value.Details.CopyStatus.Value()
|
||||
== Azure::Storage::Blobs::Models::CopyStatus::Success)
|
||||
{
|
||||
EXPECT_TRUE(IsValidTime(downloadResult.Value.Details.CopyCompletedOn.Value()));
|
||||
}
|
||||
EXPECT_TRUE(IsValidTime(downloadResult.Value.Details.CopyCompletedOn.Value()));
|
||||
|
||||
auto blobItem = GetBlobItem(blobName, Blobs::Models::ListBlobsIncludeFlags::Copy);
|
||||
EXPECT_FALSE(blobItem.Details.CopyId.Value().empty());
|
||||
EXPECT_FALSE(blobItem.Details.CopySource.Value().empty());
|
||||
EXPECT_TRUE(
|
||||
blobItem.Details.CopyStatus.Value() == Azure::Storage::Blobs::Models::CopyStatus::Success);
|
||||
EXPECT_FALSE(blobItem.Details.CopyProgress.Value().empty());
|
||||
EXPECT_TRUE(IsValidTime(blobItem.Details.CopyCompletedOn.Value()));
|
||||
ASSERT_TRUE(blobItem.Details.IsIncrementalCopy.HasValue());
|
||||
EXPECT_FALSE(blobItem.Details.IsIncrementalCopy.Value());
|
||||
EXPECT_FALSE(blobItem.Details.IncrementalCopyDestinationSnapshot.HasValue());
|
||||
}
|
||||
|
||||
TEST_F(BlockBlobClientTest, CopyWithTags)
|
||||
{
|
||||
auto blobClient = m_blobContainerClient->GetBlockBlobClient(RandomString());
|
||||
Blobs::StartBlobCopyFromUriOptions options;
|
||||
options.Tags["key1"] = "value1";
|
||||
options.Tags["key2"] = "value2";
|
||||
options.Tags["key3 +-./:=_"] = "v1 +-./:=_";
|
||||
blobClient.StartCopyFromUri(m_blockBlobClient->GetUrl(), options);
|
||||
EXPECT_EQ(blobClient.GetTags().Value, options.Tags);
|
||||
}
|
||||
|
||||
TEST_F(BlockBlobClientTest, SnapShotVersions)
|
||||
@ -373,28 +441,16 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
EXPECT_FALSE(downloadResponse.Value.Details.IsCurrentVersion.Value());
|
||||
EXPECT_EQ(version1, downloadResponse.Value.Details.VersionId.Value());
|
||||
|
||||
Azure::Storage::Blobs::ListBlobsOptions options;
|
||||
options.Prefix = blobName;
|
||||
options.Include = Blobs::Models::ListBlobsIncludeFlags::Versions;
|
||||
for (auto pageResult = m_blobContainerClient->ListBlobs(options); pageResult.HasPage();
|
||||
pageResult.MoveToNextPage())
|
||||
auto blobItem = GetBlobItem(blobName, Blobs::Models::ListBlobsIncludeFlags::Versions);
|
||||
ASSERT_TRUE(blobItem.VersionId.HasValue());
|
||||
ASSERT_TRUE(blobItem.IsCurrentVersion.HasValue());
|
||||
if (blobItem.VersionId.Value() == latestVersion)
|
||||
{
|
||||
for (const auto& blob : pageResult.Blobs)
|
||||
{
|
||||
if (blob.Name == blobName)
|
||||
{
|
||||
ASSERT_TRUE(blob.VersionId.HasValue());
|
||||
ASSERT_TRUE(blob.IsCurrentVersion.HasValue());
|
||||
if (blob.VersionId.Value() == latestVersion)
|
||||
{
|
||||
EXPECT_TRUE(blob.IsCurrentVersion.Value());
|
||||
}
|
||||
else
|
||||
{
|
||||
EXPECT_FALSE(blob.IsCurrentVersion.Value());
|
||||
}
|
||||
}
|
||||
}
|
||||
EXPECT_TRUE(blobItem.IsCurrentVersion.Value());
|
||||
}
|
||||
else
|
||||
{
|
||||
EXPECT_FALSE(blobItem.IsCurrentVersion.Value());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1023,21 +1079,11 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
EXPECT_TRUE(properties.IsAccessTierInferred.Value());
|
||||
EXPECT_FALSE(properties.AccessTierChangedOn.HasValue());
|
||||
|
||||
Azure::Storage::Blobs::ListBlobsOptions options;
|
||||
options.Prefix = blobName;
|
||||
for (auto pageResult = m_blobContainerClient->ListBlobs(options); pageResult.HasPage();
|
||||
pageResult.MoveToNextPage())
|
||||
{
|
||||
for (const auto& blob : pageResult.Blobs)
|
||||
{
|
||||
if (blob.Name == blobName)
|
||||
{
|
||||
ASSERT_TRUE(blob.Details.AccessTier.HasValue());
|
||||
ASSERT_TRUE(blob.Details.IsAccessTierInferred.HasValue());
|
||||
EXPECT_TRUE(blob.Details.IsAccessTierInferred.Value());
|
||||
}
|
||||
}
|
||||
}
|
||||
auto blobItem = GetBlobItem(blobName);
|
||||
ASSERT_TRUE(blobItem.Details.AccessTier.HasValue());
|
||||
ASSERT_TRUE(blobItem.Details.IsAccessTierInferred.HasValue());
|
||||
EXPECT_TRUE(blobItem.Details.IsAccessTierInferred.Value());
|
||||
EXPECT_FALSE(blobItem.Details.AccessTierChangedOn.HasValue());
|
||||
|
||||
// choose a different tier
|
||||
auto targetTier = properties.AccessTier.Value() == Blobs::Models::AccessTier::Hot
|
||||
@ -1051,19 +1097,48 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
EXPECT_FALSE(properties.IsAccessTierInferred.Value());
|
||||
EXPECT_TRUE(properties.AccessTierChangedOn.HasValue());
|
||||
|
||||
for (auto pageResult = m_blobContainerClient->ListBlobs(options); pageResult.HasPage();
|
||||
pageResult.MoveToNextPage())
|
||||
{
|
||||
for (const auto& blob : pageResult.Blobs)
|
||||
{
|
||||
if (blob.Name == blobName)
|
||||
{
|
||||
ASSERT_TRUE(blob.Details.AccessTier.HasValue());
|
||||
ASSERT_TRUE(blob.Details.IsAccessTierInferred.HasValue());
|
||||
EXPECT_FALSE(blob.Details.IsAccessTierInferred.Value());
|
||||
}
|
||||
}
|
||||
}
|
||||
blobItem = GetBlobItem(blobName);
|
||||
ASSERT_TRUE(blobItem.Details.AccessTier.HasValue());
|
||||
ASSERT_TRUE(blobItem.Details.IsAccessTierInferred.HasValue());
|
||||
EXPECT_FALSE(blobItem.Details.IsAccessTierInferred.Value());
|
||||
EXPECT_TRUE(blobItem.Details.AccessTierChangedOn.HasValue());
|
||||
|
||||
// set to archive, then rehydrate
|
||||
blobClient.SetAccessTier(Blobs::Models::AccessTier::Archive);
|
||||
blobClient.SetAccessTier(Blobs::Models::AccessTier::Hot);
|
||||
properties = blobClient.GetProperties().Value;
|
||||
ASSERT_TRUE(properties.ArchiveStatus.HasValue());
|
||||
EXPECT_EQ(
|
||||
properties.ArchiveStatus.Value(), Blobs::Models::ArchiveStatus::RehydratePendingToHot);
|
||||
ASSERT_TRUE(properties.RehydratePriority.HasValue());
|
||||
EXPECT_EQ(properties.RehydratePriority.Value(), Blobs::Models::RehydratePriority::Standard);
|
||||
|
||||
blobItem = GetBlobItem(blobName);
|
||||
ASSERT_TRUE(blobItem.Details.ArchiveStatus.HasValue());
|
||||
EXPECT_EQ(
|
||||
blobItem.Details.ArchiveStatus.Value(),
|
||||
Blobs::Models::ArchiveStatus::RehydratePendingToHot);
|
||||
ASSERT_TRUE(blobItem.Details.RehydratePriority.HasValue());
|
||||
EXPECT_EQ(
|
||||
blobItem.Details.RehydratePriority.Value(), Blobs::Models::RehydratePriority::Standard);
|
||||
}
|
||||
|
||||
TEST_F(BlockBlobClientTest, SetTierWithLeaseId)
|
||||
{
|
||||
std::vector<uint8_t> emptyContent;
|
||||
auto blobClient = Azure::Storage::Blobs::BlockBlobClient::CreateFromConnectionString(
|
||||
StandardStorageConnectionString(), m_containerName, RandomString());
|
||||
blobClient.UploadFrom(emptyContent.data(), emptyContent.size());
|
||||
|
||||
const std::string leaseId = Blobs::BlobLeaseClient::CreateUniqueLeaseId();
|
||||
Blobs::BlobLeaseClient leaseClient(blobClient, leaseId);
|
||||
leaseClient.Acquire(std::chrono::seconds(30));
|
||||
|
||||
EXPECT_THROW(blobClient.SetAccessTier(Blobs::Models::AccessTier::Cool), StorageException);
|
||||
|
||||
Blobs::SetBlobAccessTierOptions options;
|
||||
options.AccessConditions.LeaseId = leaseId;
|
||||
EXPECT_NO_THROW(blobClient.SetAccessTier(Blobs::Models::AccessTier::Cool, options));
|
||||
}
|
||||
|
||||
}}} // namespace Azure::Storage::Test
|
||||
|
||||
@ -62,6 +62,19 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
EXPECT_THROW(pageBlobClient.Delete(), StorageException);
|
||||
}
|
||||
|
||||
TEST_F(PageBlobClientTest, CreateWithTags)
|
||||
{
|
||||
auto pageBlobClient = Azure::Storage::Blobs::PageBlobClient::CreateFromConnectionString(
|
||||
StandardStorageConnectionString(), m_containerName, RandomString());
|
||||
Blobs::CreatePageBlobOptions options;
|
||||
options.Tags["key1"] = "value1";
|
||||
options.Tags["key2"] = "value2";
|
||||
options.Tags["key3 +-./:=_"] = "v1 +-./:=_";
|
||||
pageBlobClient.Create(512, options);
|
||||
|
||||
EXPECT_EQ(pageBlobClient.GetTags().Value, options.Tags);
|
||||
}
|
||||
|
||||
TEST_F(PageBlobClientTest, Resize)
|
||||
{
|
||||
auto pageBlobClient = Azure::Storage::Blobs::PageBlobClient::CreateFromConnectionString(
|
||||
@ -162,8 +175,9 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
|
||||
TEST_F(PageBlobClientTest, StartCopyIncremental)
|
||||
{
|
||||
const std::string blobName = RandomString();
|
||||
auto pageBlobClient = Azure::Storage::Blobs::PageBlobClient::CreateFromConnectionString(
|
||||
StandardStorageConnectionString(), m_containerName, RandomString());
|
||||
StandardStorageConnectionString(), m_containerName, blobName);
|
||||
std::string snapshot = m_pageBlobClient->CreateSnapshot().Value.Snapshot;
|
||||
Azure::Core::Url sourceUri(m_pageBlobClient->WithSnapshot(snapshot).GetUrl());
|
||||
auto copyInfo = pageBlobClient.StartCopyIncremental(AppendQueryParameters(sourceUri, GetSas()));
|
||||
@ -184,6 +198,12 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
EXPECT_TRUE(IsValidTime(getPropertiesResult.Value.CopyCompletedOn.Value()));
|
||||
ASSERT_TRUE(getPropertiesResult.Value.CopyProgress.HasValue());
|
||||
EXPECT_FALSE(getPropertiesResult.Value.CopyProgress.Value().empty());
|
||||
|
||||
auto blobItem = GetBlobItem(blobName, Blobs::Models::ListBlobsIncludeFlags::Copy);
|
||||
ASSERT_TRUE(blobItem.Details.IsIncrementalCopy.HasValue());
|
||||
EXPECT_TRUE(blobItem.Details.IsIncrementalCopy.Value());
|
||||
ASSERT_TRUE(blobItem.Details.IncrementalCopyDestinationSnapshot.HasValue());
|
||||
EXPECT_FALSE(blobItem.Details.IncrementalCopyDestinationSnapshot.Value().empty());
|
||||
}
|
||||
|
||||
TEST_F(PageBlobClientTest, Lease)
|
||||
@ -329,4 +349,56 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
EXPECT_EQ(downloadStream->ReadToEnd(Azure::Core::Context()), m_blobContent);
|
||||
}
|
||||
|
||||
TEST_F(PageBlobClientTest, SourceBlobAccessConditions)
|
||||
{
|
||||
auto sourceBlobClient = Azure::Storage::Blobs::PageBlobClient::CreateFromConnectionString(
|
||||
StandardStorageConnectionString(), m_containerName, RandomString());
|
||||
|
||||
const std::string url = sourceBlobClient.GetUrl() + GetSas();
|
||||
|
||||
const int64_t blobSize = 512;
|
||||
auto createResponse = sourceBlobClient.Create(blobSize);
|
||||
Azure::ETag eTag = createResponse.Value.ETag;
|
||||
auto lastModifiedTime = createResponse.Value.LastModified;
|
||||
auto timeBeforeStr = lastModifiedTime - std::chrono::seconds(1);
|
||||
auto timeAfterStr = lastModifiedTime + std::chrono::seconds(1);
|
||||
|
||||
auto destBlobClient = Azure::Storage::Blobs::PageBlobClient::CreateFromConnectionString(
|
||||
StandardStorageConnectionString(), m_containerName, RandomString());
|
||||
destBlobClient.Create(blobSize);
|
||||
|
||||
{
|
||||
Blobs::UploadPagesFromUriOptions options;
|
||||
options.SourceAccessConditions.IfMatch = eTag;
|
||||
EXPECT_NO_THROW(destBlobClient.UploadPagesFromUri(0, url, {0, blobSize}, options));
|
||||
options.SourceAccessConditions.IfMatch = DummyETag;
|
||||
EXPECT_THROW(
|
||||
destBlobClient.UploadPagesFromUri(0, url, {0, blobSize}, options), StorageException);
|
||||
}
|
||||
{
|
||||
Blobs::UploadPagesFromUriOptions options;
|
||||
options.SourceAccessConditions.IfNoneMatch = DummyETag;
|
||||
EXPECT_NO_THROW(destBlobClient.UploadPagesFromUri(0, url, {0, blobSize}, options));
|
||||
options.SourceAccessConditions.IfNoneMatch = eTag;
|
||||
EXPECT_THROW(
|
||||
destBlobClient.UploadPagesFromUri(0, url, {0, blobSize}, options), StorageException);
|
||||
}
|
||||
{
|
||||
Blobs::UploadPagesFromUriOptions options;
|
||||
options.SourceAccessConditions.IfModifiedSince = timeBeforeStr;
|
||||
EXPECT_NO_THROW(destBlobClient.UploadPagesFromUri(0, url, {0, blobSize}, options));
|
||||
options.SourceAccessConditions.IfModifiedSince = timeAfterStr;
|
||||
EXPECT_THROW(
|
||||
destBlobClient.UploadPagesFromUri(0, url, {0, blobSize}, options), StorageException);
|
||||
}
|
||||
{
|
||||
Blobs::UploadPagesFromUriOptions options;
|
||||
options.SourceAccessConditions.IfUnmodifiedSince = timeAfterStr;
|
||||
EXPECT_NO_THROW(destBlobClient.UploadPagesFromUri(0, url, {0, blobSize}, options));
|
||||
options.SourceAccessConditions.IfUnmodifiedSince = timeBeforeStr;
|
||||
EXPECT_THROW(
|
||||
destBlobClient.UploadPagesFromUri(0, url, {0, blobSize}, options), StorageException);
|
||||
}
|
||||
}
|
||||
|
||||
}}} // namespace Azure::Storage::Test
|
||||
|
||||
@ -12,6 +12,10 @@
|
||||
|
||||
## 12.0.1 (2021-07-07)
|
||||
|
||||
### New Features
|
||||
|
||||
- Added `ETag` and `LastModified` into `ScheduleFileDeletionResult`.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Fixed a bug where transactional MD5 hash was treated as blob MD5 hash when downloading partial blob.
|
||||
|
||||
@ -333,9 +333,11 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
{
|
||||
{
|
||||
auto client = m_fileSystemClient->GetFileClient(RandomString());
|
||||
EXPECT_NO_THROW(client.Create());
|
||||
EXPECT_NO_THROW(
|
||||
client.ScheduleDeletion(Files::DataLake::ScheduleFileExpiryOriginType::NeverExpire));
|
||||
auto createResponse = client.Create();
|
||||
auto scheduleDeletionResponse
|
||||
= client.ScheduleDeletion(Files::DataLake::ScheduleFileExpiryOriginType::NeverExpire);
|
||||
EXPECT_EQ(scheduleDeletionResponse.Value.ETag, createResponse.Value.ETag);
|
||||
EXPECT_EQ(scheduleDeletionResponse.Value.LastModified, createResponse.Value.LastModified);
|
||||
}
|
||||
{
|
||||
auto client = m_fileSystemClient->GetFileClient(RandomString());
|
||||
|
||||
Loading…
Reference in New Issue
Block a user