From d77ecf7917e66b16a4acc7f379226336774aa3cb Mon Sep 17 00:00:00 2001 From: Kan Tang Date: Fri, 14 Aug 2020 13:01:51 +0800 Subject: [PATCH] Added support for share service (#450) --- .../inc/shares/protocol/share_rest_client.hpp | 126 +++++++++++----- sdk/storage/inc/shares/share_client.hpp | 89 ++++++++++++ sdk/storage/inc/shares/share_options.hpp | 83 +++++++++++ sdk/storage/inc/shares/share_responses.hpp | 8 ++ sdk/storage/src/shares/share_client.cpp | 86 +++++++++++ sdk/storage/test/shares/share_client_test.cpp | 134 +++++++++++++++++- sdk/storage/test/shares/share_client_test.hpp | 2 +- 7 files changed, 485 insertions(+), 43 deletions(-) diff --git a/sdk/storage/inc/shares/protocol/share_rest_client.hpp b/sdk/storage/inc/shares/protocol/share_rest_client.hpp index 1a66f6cce..eaad38e85 100644 --- a/sdk/storage/inc/shares/protocol/share_rest_client.hpp +++ b/sdk/storage/inc/shares/protocol/share_rest_client.hpp @@ -383,10 +383,10 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { std::string LastModified; std::string Etag; int32_t Quota; - int32_t ProvisionedIops; - int32_t ProvisionedIngressMBps; - int32_t ProvisionedEgressMBps; - std::string NextAllowedQuotaDowngradeTime; + Azure::Core::Nullable ProvisionedIops; + Azure::Core::Nullable ProvisionedIngressMBps; + Azure::Core::Nullable ProvisionedEgressMBps; + Azure::Core::Nullable NextAllowedQuotaDowngradeTime; std::string DeletedTime; int32_t RemainingRetentionDays; }; @@ -445,7 +445,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { // Stats for the share. struct ShareStats { - int32_t + int64_t ShareUsageBytes; // The approximate size of the data stored in bytes. Note that this value // may not include all recently created or recently resized files. }; @@ -759,14 +759,14 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { struct ShareGetPropertiesResponse { - std::string Metadata; + std::map Metadata; std::string ETag; std::string LastModified; int32_t Quota = int32_t(); - int32_t ProvisionedIops = int32_t(); - int32_t ProvisionedIngressMBps = int32_t(); - int32_t ProvisionedEgressMBps = int32_t(); - std::string NextAllowedQuotaDowngradeTime; + Azure::Core::Nullable ProvisionedIops; + Azure::Core::Nullable ProvisionedIngressMBps; + Azure::Core::Nullable ProvisionedEgressMBps; + Azure::Core::Nullable NextAllowedQuotaDowngradeTime; }; struct ShareDeleteResponse @@ -817,7 +817,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { struct ShareGetStatisticsResponse { - int32_t ShareUsageBytes = int32_t(); + int64_t ShareUsageBytes = int64_t(); std::string ETag; std::string LastModified; }; @@ -844,7 +844,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { struct DirectoryGetPropertiesResponse { - std::string Metadata; + std::map Metadata; std::string ETag; std::string LastModified; bool IsServerEncrypted = bool(); @@ -927,7 +927,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { std::unique_ptr BodyStream; std::string LastModified; - std::string Metadata; + std::map Metadata; int64_t ContentLength = int64_t(); FileShareHttpHeaders HttpHeaders; std::string ContentRange; @@ -957,7 +957,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { struct FileGetPropertiesResponse { std::string LastModified; - std::string Metadata; + std::map Metadata; std::string FileType; int64_t ContentLength = int64_t(); FileShareHttpHeaders HttpHeaders; @@ -2103,7 +2103,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { } for (const auto& pair : createOptions.Metadata) { - request.AddHeader(Details::c_HeaderMetadata + pair.first, pair.second); + request.AddHeader(Details::c_HeaderMetadata + ("-" + pair.first), pair.second); } if (createOptions.ShareQuota.HasValue()) { @@ -2225,7 +2225,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { } for (const auto& pair : createSnapshotOptions.Metadata) { - request.AddHeader(Details::c_HeaderMetadata + pair.first, pair.second); + request.AddHeader(Details::c_HeaderMetadata + ("-" + pair.first), pair.second); } request.AddHeader(Details::c_HeaderVersion, createSnapshotOptions.ApiVersionParameter); return CreateSnapshotParseResponse(context, pipeline.Send(context, request)); @@ -2259,6 +2259,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { auto body = Azure::Core::Http::MemoryBodyStream( reinterpret_cast(json_body.data()), json_body.length()); auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Put, url, &body); + request.AddHeader("Content-Length", std::to_string(body.Length())); request.AddQueryParameter(Details::c_QueryRestype, "share"); request.AddQueryParameter(Details::c_QueryComp, "filepermission"); if (createPermissionOptions.Timeout.HasValue()) @@ -2370,7 +2371,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { } for (const auto& pair : setMetadataOptions.Metadata) { - request.AddHeader(Details::c_HeaderMetadata + pair.first, pair.second); + request.AddHeader(Details::c_HeaderMetadata + ("-" + pair.first), pair.second); } request.AddHeader(Details::c_HeaderVersion, setMetadataOptions.ApiVersionParameter); return SetMetadataParseResponse(context, pipeline.Send(context, request)); @@ -2557,18 +2558,41 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { // Success ShareGetPropertiesResponse result; - result.Metadata = response.GetHeaders().at(Details::c_HeaderMetadata); + + for (auto i = response.GetHeaders().lower_bound(Details::c_HeaderMetadata); + i != response.GetHeaders().end() + && i->first.substr(0, 9) == Details::c_HeaderMetadata; + ++i) + { + result.Metadata.emplace(i->first.substr(10), i->second); + } result.ETag = response.GetHeaders().at(Details::c_HeaderETag); result.LastModified = response.GetHeaders().at(Details::c_HeaderLastModified); result.Quota = std::stoi(response.GetHeaders().at(Details::c_HeaderQuota)); - result.ProvisionedIops - = std::stoi(response.GetHeaders().at(Details::c_HeaderProvisionedIops)); - result.ProvisionedIngressMBps - = std::stoi(response.GetHeaders().at(Details::c_HeaderProvisionedIngressMBps)); - result.ProvisionedEgressMBps - = std::stoi(response.GetHeaders().at(Details::c_HeaderProvisionedEgressMBps)); - result.NextAllowedQuotaDowngradeTime - = response.GetHeaders().at(Details::c_HeaderNextAllowedQuotaDowngradeTime); + if (response.GetHeaders().find(Details::c_HeaderProvisionedIops) + != response.GetHeaders().end()) + { + result.ProvisionedIops + = std::stoi(response.GetHeaders().at(Details::c_HeaderProvisionedIops)); + } + if (response.GetHeaders().find(Details::c_HeaderProvisionedIngressMBps) + != response.GetHeaders().end()) + { + result.ProvisionedIngressMBps + = std::stoi(response.GetHeaders().at(Details::c_HeaderProvisionedIngressMBps)); + } + if (response.GetHeaders().find(Details::c_HeaderProvisionedEgressMBps) + != response.GetHeaders().end()) + { + result.ProvisionedEgressMBps + = std::stoi(response.GetHeaders().at(Details::c_HeaderProvisionedEgressMBps)); + } + if (response.GetHeaders().find(Details::c_HeaderNextAllowedQuotaDowngradeTime) + != response.GetHeaders().end()) + { + result.NextAllowedQuotaDowngradeTime + = response.GetHeaders().at(Details::c_HeaderNextAllowedQuotaDowngradeTime); + } return Azure::Core::Response( std::move(result), std::move(responsePtr)); } @@ -2982,10 +3006,8 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { writer.Write(XmlNode{XmlNodeType::StartTag, "Id"}); writer.Write(XmlNode{XmlNodeType::Text, nullptr, object.Id.data()}); writer.Write(XmlNode{XmlNodeType::EndTag}); - writer.Write(XmlNode{XmlNodeType::StartTag, "AccessPolicy"}); AccessPolicyToXml(writer, object.Policy); writer.Write(XmlNode{XmlNodeType::EndTag}); - writer.Write(XmlNode{XmlNodeType::EndTag}); }; static void SignedIdentifiersToXml( @@ -3074,7 +3096,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { if (path.size() == 2 && path[0] == XmlTagName::c_ShareStats && path[1] == XmlTagName::c_ShareUsageBytes) { - result.ShareUsageBytes = std::stoi(node.Value); + result.ShareUsageBytes = std::stoll(node.Value); } } } @@ -3157,7 +3179,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { } for (const auto& pair : createOptions.Metadata) { - request.AddHeader(Details::c_HeaderMetadata + pair.first, pair.second); + request.AddHeader(Details::c_HeaderMetadata + ("-" + pair.first), pair.second); } request.AddHeader(Details::c_HeaderVersion, createOptions.ApiVersionParameter); if (createOptions.FilePermission.HasValue()) @@ -3332,7 +3354,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { } for (const auto& pair : setMetadataOptions.Metadata) { - request.AddHeader(Details::c_HeaderMetadata + pair.first, pair.second); + request.AddHeader(Details::c_HeaderMetadata + ("-" + pair.first), pair.second); } request.AddHeader(Details::c_HeaderVersion, setMetadataOptions.ApiVersionParameter); return SetMetadataParseResponse(context, pipeline.Send(context, request)); @@ -3571,7 +3593,14 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { // Success. DirectoryGetPropertiesResponse result; - result.Metadata = response.GetHeaders().at(Details::c_HeaderMetadata); + + for (auto i = response.GetHeaders().lower_bound(Details::c_HeaderMetadata); + i != response.GetHeaders().end() + && i->first.substr(0, 9) == Details::c_HeaderMetadata; + ++i) + { + result.Metadata.emplace(i->first.substr(10), i->second); + } result.ETag = response.GetHeaders().at(Details::c_HeaderETag); result.LastModified = response.GetHeaders().at(Details::c_HeaderLastModified); result.IsServerEncrypted @@ -4389,7 +4418,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { } for (const auto& pair : createOptions.Metadata) { - request.AddHeader(Details::c_HeaderMetadata + pair.first, pair.second); + request.AddHeader(Details::c_HeaderMetadata + ("-" + pair.first), pair.second); } if (createOptions.FilePermission.HasValue()) { @@ -4696,7 +4725,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { } for (const auto& pair : setMetadataOptions.Metadata) { - request.AddHeader(Details::c_HeaderMetadata + pair.first, pair.second); + request.AddHeader(Details::c_HeaderMetadata + ("-" + pair.first), pair.second); } request.AddHeader(Details::c_HeaderVersion, setMetadataOptions.ApiVersionParameter); if (setMetadataOptions.LeaseIdOptional.HasValue()) @@ -5205,7 +5234,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { request.AddHeader(Details::c_HeaderVersion, startCopyOptions.ApiVersionParameter); for (const auto& pair : startCopyOptions.Metadata) { - request.AddHeader(Details::c_HeaderMetadata + pair.first, pair.second); + request.AddHeader(Details::c_HeaderMetadata + ("-" + pair.first), pair.second); } request.AddHeader(Details::c_HeaderCopySource, startCopyOptions.CopySource); if (startCopyOptions.FilePermission.HasValue()) @@ -5448,7 +5477,14 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { FileDownloadResponse result; result.BodyStream = response.GetBodyStream(); result.LastModified = response.GetHeaders().at(Details::c_HeaderLastModified); - result.Metadata = response.GetHeaders().at(Details::c_HeaderMetadata); + + for (auto i = response.GetHeaders().lower_bound(Details::c_HeaderMetadata); + i != response.GetHeaders().end() + && i->first.substr(0, 9) == Details::c_HeaderMetadata; + ++i) + { + result.Metadata.emplace(i->first.substr(10), i->second); + } result.ContentLength = std::stoll(response.GetHeaders().at(Details::c_HeaderContentLength)); result.HttpHeaders.ContentType = response.GetHeaders().at(Details::c_HeaderContentType); @@ -5500,7 +5536,14 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { FileDownloadResponse result; result.BodyStream = response.GetBodyStream(); result.LastModified = response.GetHeaders().at(Details::c_HeaderLastModified); - result.Metadata = response.GetHeaders().at(Details::c_HeaderMetadata); + + for (auto i = response.GetHeaders().lower_bound(Details::c_HeaderMetadata); + i != response.GetHeaders().end() + && i->first.substr(0, 9) == Details::c_HeaderMetadata; + ++i) + { + result.Metadata.emplace(i->first.substr(10), i->second); + } result.ContentLength = std::stoll(response.GetHeaders().at(Details::c_HeaderContentLength)); result.HttpHeaders.ContentType = response.GetHeaders().at(Details::c_HeaderContentType); @@ -5562,7 +5605,14 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { // Success. FileGetPropertiesResponse result; result.LastModified = response.GetHeaders().at(Details::c_HeaderLastModified); - result.Metadata = response.GetHeaders().at(Details::c_HeaderMetadata); + + for (auto i = response.GetHeaders().lower_bound(Details::c_HeaderMetadata); + i != response.GetHeaders().end() + && i->first.substr(0, 9) == Details::c_HeaderMetadata; + ++i) + { + result.Metadata.emplace(i->first.substr(10), i->second); + } result.FileType = response.GetHeaders().at(Details::c_HeaderFileType); result.ContentLength = std::stoll(response.GetHeaders().at(Details::c_HeaderContentLength)); diff --git a/sdk/storage/inc/shares/share_client.hpp b/sdk/storage/inc/shares/share_client.hpp index eedfbcaec..d4dc6979a 100644 --- a/sdk/storage/inc/shares/share_client.hpp +++ b/sdk/storage/inc/shares/share_client.hpp @@ -87,6 +87,95 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { Azure::Core::Response Delete( const DeleteShareOptions& options = DeleteShareOptions()) const; + /** + * @brief Creates a snapshot for the share. + * @param options Optional parameters to create the share snapshot. + * @return Azure::Core::Response Containing the information for ths snapshot. + */ + Azure::Core::Response CreateSnapshot( + const CreateShareSnapshotOptions& options = CreateShareSnapshotOptions()) const; + + /** + * @brief Gets the properties of the share. + * @param options Optional parameters to get the share properties. + * @return Azure::Core::Response Containing the information for ths share + * or one of its snapshot. + */ + Azure::Core::Response GetProperties( + const GetSharePropertiesOptions& options = GetSharePropertiesOptions()) const; + + /** + * @brief Sets the quota of the share. + * @param quota Specifies the maximum size of the share, in gigabytes. + * @param options Optional parameters to set the share quota. + * @return Azure::Core::Response The information containing the version + * and modified time of a share. + */ + Azure::Core::Response SetQuota( + int32_t quota, + const SetShareQuotaOptions& options = SetShareQuotaOptions()) const; + + /** + * @brief Sets the metadata to the share. + * @param metadata A name-value pair to associate with a file storage 'Share' object.. + * @param options Optional parameters to set the share metadata. + * @return Azure::Core::Response The information containing the version + * and modified time of a share. + */ + Azure::Core::Response SetMetadata( + std::map metadata, + const SetShareMetadataOptions& options = SetShareMetadataOptions()) const; + + /** + * @brief Gets the access policy of the share. + * @param options Optional parameters to get the share's access policy. + * @return Azure::Core::Response> The access policy of the + * share. + */ + Azure::Core::Response GetAccessPolicy( + const GetShareAccessPolicyOptions& options = GetShareAccessPolicyOptions()) const; + + /** + * @brief Sets the access policy of the share. + * @param accessPolicy Specifies the access policy to be set to the share. + * @param options Optional parameters to Set the share's access policy. + * @return Azure::Core::Response The information containing the version + * and modified time of a share. + */ + Azure::Core::Response SetAccessPolicy( + const std::vector& accessPolicy, + const SetShareAccessPolicyOptions& options = SetShareAccessPolicyOptions()) const; + + /** + * @brief Gets the stats of the share. + * @param options Optional parameters to get share's statistics. + * @return Azure::Core::Response The information containing the bytes used in + * by the share, the version and modified time of a share. + */ + Azure::Core::Response GetStatistics( + const GetShareStatsOptions& options = GetShareStatsOptions()) const; + + /** + * @brief Creates a permission on the share. + * @param permission Specifies the permission to be created on the share. + * @param options Optional parameters to create the share's permission. + * @return Azure::Core::Response The information containing the permission + * key of the permission. + */ + Azure::Core::Response CreatePermission( + const std::string& permission, + const CreateSharePermissionOptions& options = CreateSharePermissionOptions()) const; + + /** + * @brief Gets the permission of the share using the specific key. + * @param permissionKey The permission key of a permission. + * @param options Optional parameters to get share's permission. + * @return Azure::Core::Response The permission sting with specified key. + */ + Azure::Core::Response GetPermission( + const std::string& permissionKey, + const GetSharePermissionOptions& options = GetSharePermissionOptions()) const; + private: UriBuilder m_shareUri; std::shared_ptr m_pipeline; diff --git a/sdk/storage/inc/shares/share_options.hpp b/sdk/storage/inc/shares/share_options.hpp index e377c65de..fa00608e2 100644 --- a/sdk/storage/inc/shares/share_options.hpp +++ b/sdk/storage/inc/shares/share_options.hpp @@ -119,4 +119,87 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { Azure::Core::Nullable IncludeSnapshots; }; + struct CreateShareSnapshotOptions + { + /** + * @brief Context for cancelling long running operations. + */ + Azure::Core::Context Context; + + /** + * @brief The metadata to be set on the snapshot of the share. + */ + std::map Metadata; + }; + + struct GetSharePropertiesOptions + { + /** + * @brief Context for cancelling long running operations. + */ + Azure::Core::Context Context; + + /** + * @brief The snapshot parameter is an opaque DateTime value that, when present, specifies the + * share snapshot to query. + */ + Azure::Core::Nullable ShareSnapshot; + }; + + struct SetShareQuotaOptions + { + /** + * @brief Context for cancelling long running operations. + */ + Azure::Core::Context Context; + }; + + struct SetShareMetadataOptions + { + /** + * @brief Context for cancelling long running operations. + */ + Azure::Core::Context Context; + }; + + struct GetShareAccessPolicyOptions + { + /** + * @brief Context for cancelling long running operations. + */ + Azure::Core::Context Context; + }; + + struct SetShareAccessPolicyOptions + { + /** + * @brief Context for cancelling long running operations. + */ + Azure::Core::Context Context; + }; + + struct GetShareStatsOptions + { + /** + * @brief Context for cancelling long running operations. + */ + Azure::Core::Context Context; + }; + + struct CreateSharePermissionOptions + { + /** + * @brief Context for cancelling long running operations. + */ + Azure::Core::Context Context; + }; + + struct GetSharePermissionOptions + { + /** + * @brief Context for cancelling long running operations. + */ + Azure::Core::Context Context; + }; + }}}} // namespace Azure::Storage::Files::Shares diff --git a/sdk/storage/inc/shares/share_responses.hpp b/sdk/storage/inc/shares/share_responses.hpp index ee3e1904e..53902f9fa 100644 --- a/sdk/storage/inc/shares/share_responses.hpp +++ b/sdk/storage/inc/shares/share_responses.hpp @@ -15,5 +15,13 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { // ShareClient models: using ShareInfo = ShareCreateResponse; using ShareDeleteInfo = ShareDeleteResponse; + using ShareSnapshotInfo = ShareCreateSnapshotResponse; + using FileShareProperties = ShareGetPropertiesResponse; + using SetShareQuotaInfo = ShareSetQuotaResponse; + using SetShareMetadataInfo = ShareSetMetadataResponse; + using SetAccessPolicyInfo = ShareSetAccessPolicyResponse; + using ShareStatistics = ShareGetStatisticsResponse; + using SharePermissionInfo = ShareCreatePermissionResponse; + using GetShareAccessPolicyResult = ShareGetAccessPolicyResponse; }}}} // namespace Azure::Storage::Files::Shares diff --git a/sdk/storage/src/shares/share_client.cpp b/sdk/storage/src/shares/share_client.cpp index b0991aa18..6e88cbb47 100644 --- a/sdk/storage/src/shares/share_client.cpp +++ b/sdk/storage/src/shares/share_client.cpp @@ -132,4 +132,90 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { m_shareUri.ToString(), *m_pipeline, options.Context, protocolLayerOptions); } + Azure::Core::Response ShareClient::CreateSnapshot( + const CreateShareSnapshotOptions& options) const + { + auto protocolLayerOptions = ShareRestClient::Share::CreateSnapshotOptions(); + protocolLayerOptions.Metadata = options.Metadata; + return ShareRestClient::Share::CreateSnapshot( + m_shareUri.ToString(), *m_pipeline, options.Context, protocolLayerOptions); + } + + Azure::Core::Response ShareClient::GetProperties( + const GetSharePropertiesOptions& options) const + { + auto protocolLayerOptions = ShareRestClient::Share::GetPropertiesOptions(); + protocolLayerOptions.ShareSnapshot = options.ShareSnapshot; + return ShareRestClient::Share::GetProperties( + m_shareUri.ToString(), *m_pipeline, options.Context, protocolLayerOptions); + } + + Azure::Core::Response ShareClient::SetQuota( + int32_t quota, + const SetShareQuotaOptions& options) const + { + auto protocolLayerOptions = ShareRestClient::Share::SetQuotaOptions(); + protocolLayerOptions.ShareQuota = quota; + return ShareRestClient::Share::SetQuota( + m_shareUri.ToString(), *m_pipeline, options.Context, protocolLayerOptions); + } + + Azure::Core::Response ShareClient::SetMetadata( + std::map metadata, + const SetShareMetadataOptions& options) const + { + auto protocolLayerOptions = ShareRestClient::Share::SetMetadataOptions(); + protocolLayerOptions.Metadata = metadata; + return ShareRestClient::Share::SetMetadata( + m_shareUri.ToString(), *m_pipeline, options.Context, protocolLayerOptions); + } + + Azure::Core::Response ShareClient::GetAccessPolicy( + const GetShareAccessPolicyOptions& options) const + { + auto protocolLayerOptions = ShareRestClient::Share::GetAccessPolicyOptions(); + return ShareRestClient::Share::GetAccessPolicy( + m_shareUri.ToString(), *m_pipeline, options.Context, protocolLayerOptions); + } + + Azure::Core::Response ShareClient::SetAccessPolicy( + const std::vector& accessPolicy, + const SetShareAccessPolicyOptions& options) const + { + auto protocolLayerOptions = ShareRestClient::Share::SetAccessPolicyOptions(); + protocolLayerOptions.ShareAcl = accessPolicy; + return ShareRestClient::Share::SetAccessPolicy( + m_shareUri.ToString(), *m_pipeline, options.Context, protocolLayerOptions); + } + + Azure::Core::Response ShareClient::GetStatistics( + const GetShareStatsOptions& options) const + { + auto protocolLayerOptions = ShareRestClient::Share::GetStatisticsOptions(); + return ShareRestClient::Share::GetStatistics( + m_shareUri.ToString(), *m_pipeline, options.Context, protocolLayerOptions); + } + + Azure::Core::Response ShareClient::CreatePermission( + const std::string& permission, + const CreateSharePermissionOptions& options) const + { + auto protocolLayerOptions = ShareRestClient::Share::CreatePermissionOptions(); + protocolLayerOptions.Permission.Permission = permission; + return ShareRestClient::Share::CreatePermission( + m_shareUri.ToString(), *m_pipeline, options.Context, protocolLayerOptions); + } + + Azure::Core::Response ShareClient::GetPermission( + const std::string& permissionKey, + const GetSharePermissionOptions& options) const + { + auto protocolLayerOptions = ShareRestClient::Share::GetPermissionOptions(); + protocolLayerOptions.FilePermissionKeyRequired = permissionKey; + auto result = ShareRestClient::Share::GetPermission( + m_shareUri.ToString(), *m_pipeline, options.Context, protocolLayerOptions); + return Azure::Core::Response( + std::move(result->Permission), result.ExtractRawResponse()); + } + }}}} // namespace Azure::Storage::Files::Shares diff --git a/sdk/storage/test/shares/share_client_test.cpp b/sdk/storage/test/shares/share_client_test.cpp index 2cbb80b24..d3dec0cbe 100644 --- a/sdk/storage/test/shares/share_client_test.cpp +++ b/sdk/storage/test/shares/share_client_test.cpp @@ -5,17 +5,29 @@ #include +namespace Azure { namespace Storage { namespace Files { namespace Shares { + + bool operator==( + const Azure::Storage::Files::Shares::SignedIdentifier& lhs, + const Azure::Storage::Files::Shares::SignedIdentifier& rhs) + { + return lhs.Id == rhs.Id && lhs.Policy.Start == rhs.Policy.Start + && lhs.Policy.Expiry == rhs.Policy.Expiry && lhs.Policy.Permission == rhs.Policy.Permission; + } + +}}}} // namespace Azure::Storage::Files::Shares + namespace Azure { namespace Storage { namespace Test { std::shared_ptr FileShareClientTest::m_shareClient; - std::string FileShareClientTest::m_fileSystemName; + std::string FileShareClientTest::m_shareName; void FileShareClientTest::SetUpTestSuite() { - m_fileSystemName = LowercaseRandomString(); + m_shareName = LowercaseRandomString(); m_shareClient = std::make_shared( Files::Shares::ShareClient::CreateFromConnectionString( - StandardStorageConnectionString(), m_fileSystemName)); + StandardStorageConnectionString(), m_shareName)); m_shareClient->Create(); } @@ -35,7 +47,7 @@ namespace Azure { namespace Storage { namespace Test { return result; } - TEST_F(FileShareClientTest, CreateDeleteFileSystems) + TEST_F(FileShareClientTest, CreateDeleteShares) { { // Normal create/delete. @@ -54,4 +66,118 @@ namespace Azure { namespace Storage { namespace Test { } } + TEST_F(FileShareClientTest, ShareMetadata) + { + auto metadata1 = RandomMetadata(); + auto metadata2 = RandomMetadata(); + { + // Set/Get Metadata works + EXPECT_NO_THROW(m_shareClient->SetMetadata(metadata1)); + auto result = m_shareClient->GetProperties()->Metadata; + EXPECT_EQ(metadata1, result); + EXPECT_NO_THROW(m_shareClient->SetMetadata(metadata2)); + result = m_shareClient->GetProperties()->Metadata; + EXPECT_EQ(metadata2, result); + } + + { + // Create share with metadata works + auto client1 = Files::Shares::ShareClient::CreateFromConnectionString( + AdlsGen2ConnectionString(), LowercaseRandomString()); + auto client2 = Files::Shares::ShareClient::CreateFromConnectionString( + AdlsGen2ConnectionString(), LowercaseRandomString()); + Files::Shares::CreateShareOptions options1; + Files::Shares::CreateShareOptions options2; + options1.Metadata = metadata1; + options2.Metadata = metadata2; + + EXPECT_NO_THROW(client1.Create(options1)); + EXPECT_NO_THROW(client2.Create(options2)); + auto result = client1.GetProperties()->Metadata; + EXPECT_EQ(metadata1, result); + result = client2.GetProperties()->Metadata; + EXPECT_EQ(metadata2, result); + } + } + + TEST_F(FileShareClientTest, ShareQuota) + { + const int32_t quota32GB = 32; + const int32_t quota64GB = 64; + const int32_t quota5120GB = 5120; + + { + // Set quota /Get properties works + EXPECT_NO_THROW(m_shareClient->SetQuota(quota32GB)); + auto result = m_shareClient->GetProperties(); + EXPECT_EQ(quota32GB, result->Quota); + EXPECT_NO_THROW(m_shareClient->SetQuota(quota64GB)); + result = m_shareClient->GetProperties(); + EXPECT_EQ(quota64GB, result->Quota); + } + + { + // Create file system with quota works + auto client1 = Files::Shares::ShareClient::CreateFromConnectionString( + AdlsGen2ConnectionString(), LowercaseRandomString()); + auto client2 = Files::Shares::ShareClient::CreateFromConnectionString( + AdlsGen2ConnectionString(), LowercaseRandomString()); + Files::Shares::CreateShareOptions options1; + Files::Shares::CreateShareOptions options2; + options1.ShareQuota = quota32GB; + options2.ShareQuota = quota64GB; + + EXPECT_NO_THROW(client1.Create(options1)); + EXPECT_NO_THROW(client2.Create(options2)); + auto result = client1.GetProperties()->Quota; + EXPECT_EQ(quota32GB, result); + result = client2.GetProperties()->Quota; + EXPECT_EQ(quota64GB, result); + } + + { + // Limit/negative cases: + EXPECT_NO_THROW(m_shareClient->SetQuota(quota5120GB)); + auto result = m_shareClient->GetProperties()->Quota; + EXPECT_EQ(quota5120GB, result); + } + } + + TEST_F(FileShareClientTest, ShareAccessPolicy) + { + std::vector identifiers; + for (unsigned i = 0; i < 3; ++i) + { + Files::Shares::SignedIdentifier identifier; + identifier.Id = RandomString(64); + identifier.Policy.Start + = ToIso8601(std::chrono::system_clock::now() - std::chrono::minutes(10), 7); + identifier.Policy.Expiry + = ToIso8601(std::chrono::system_clock::now() - std::chrono::minutes(100), 7); + identifier.Policy.Permission = "r"; + identifiers.emplace_back(identifier); + } + + auto ret = m_shareClient->SetAccessPolicy(identifiers); + EXPECT_FALSE(ret->ETag.empty()); + EXPECT_FALSE(ret->LastModified.empty()); + + auto ret2 = m_shareClient->GetAccessPolicy(); + EXPECT_EQ(ret2->ETag, ret->ETag); + EXPECT_EQ(ret2->LastModified, ret->LastModified); + EXPECT_EQ(ret2->SignedIdentifiers, identifiers); + } + + TEST_F(FileShareClientTest, SharePermissions) + { + std::string permission = "O:S-1-5-21-2127521184-1604012920-1887927527-21560751G:S-1-5-21-" + "2127521184-1604012920-1887927527-513D:AI(A;;FA;;;SY)(A;;FA;;;BA)(A;;" + "0x1200a9;;;S-1-5-21-397955417-626881126-188441444-3053964)"; + + auto ret = m_shareClient->CreatePermission(permission); + EXPECT_FALSE(ret->FilePermissionKey.empty()); + + auto ret2 = m_shareClient->GetPermission(ret->FilePermissionKey).ExtractValue(); + EXPECT_EQ(ret2, permission); + } }}} // namespace Azure::Storage::Test diff --git a/sdk/storage/test/shares/share_client_test.hpp b/sdk/storage/test/shares/share_client_test.hpp index 2b59c28f0..8fca8bc2a 100644 --- a/sdk/storage/test/shares/share_client_test.hpp +++ b/sdk/storage/test/shares/share_client_test.hpp @@ -14,7 +14,7 @@ namespace Azure { namespace Storage { namespace Test { static Files::Shares::FileShareHttpHeaders GetInterestingHttpHeaders(); static std::shared_ptr m_shareClient; - static std::string m_fileSystemName; + static std::string m_shareName; }; }}} // namespace Azure::Storage::Test