From 653d7dfecddac990e74c255c270d9b8a99633afb Mon Sep 17 00:00:00 2001 From: microzchang <110015819+microzchang@users.noreply.github.com> Date: Fri, 18 Aug 2023 16:31:05 +0800 Subject: [PATCH] Storage/File Share test coverage improvement (#4895) * add share tests * Add accessRights test * update tests * update test records * change --- sdk/storage/assets.json | 2 +- .../test/ut/share_client_test.cpp | 24 ++ .../test/ut/share_directory_client_test.cpp | 61 +++++ .../test/ut/share_file_client_test.cpp | 219 ++++++++++++++++++ .../test/ut/share_service_client_test.cpp | 25 ++ 5 files changed, 330 insertions(+), 1 deletion(-) diff --git a/sdk/storage/assets.json b/sdk/storage/assets.json index 91f9dd5f1..1567aa466 100644 --- a/sdk/storage/assets.json +++ b/sdk/storage/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "cpp", "TagPrefix": "cpp/storage", - "Tag": "cpp/storage_4491a2739b" + "Tag": "cpp/storage_f900b96a8c" } diff --git a/sdk/storage/azure-storage-files-shares/test/ut/share_client_test.cpp b/sdk/storage/azure-storage-files-shares/test/ut/share_client_test.cpp index 850f3a868..5e809aa2d 100644 --- a/sdk/storage/azure-storage-files-shares/test/ut/share_client_test.cpp +++ b/sdk/storage/azure-storage-files-shares/test/ut/share_client_test.cpp @@ -671,5 +671,29 @@ namespace Azure { namespace Storage { namespace Test { Files::Shares::Models::CreateSharePermissionResult created; EXPECT_NO_THROW(created = shareClient.CreatePermission(permission).Value); EXPECT_NO_THROW(shareClient.GetPermission(created.FilePermissionKey)); + + // OAuth Constructor + auto shareClient1 = Files::Shares::ShareClient( + m_shareClient->GetUrl(), + std::make_shared( + AadTenantId(), AadClientId(), AadClientSecret(), GetTokenCredentialOptions()), + options); + EXPECT_NO_THROW(shareClient1.GetPermission(created.FilePermissionKey)); + } + + TEST_F(FileShareClientTest, WithSnapshot) + { + const std::string timestamp1 = "2001-01-01T01:01:01.1111000Z"; + const std::string timestamp2 = "2022-02-02T02:02:02.2222000Z"; + + auto client1 = m_shareClient->WithSnapshot(timestamp1); + EXPECT_FALSE(client1.GetUrl().find("snapshot=" + timestamp1) == std::string::npos); + EXPECT_TRUE(client1.GetUrl().find("snapshot=" + timestamp2) == std::string::npos); + client1 = client1.WithSnapshot(timestamp2); + EXPECT_TRUE(client1.GetUrl().find("snapshot=" + timestamp1) == std::string::npos); + EXPECT_FALSE(client1.GetUrl().find("snapshot=" + timestamp2) == std::string::npos); + client1 = client1.WithSnapshot(""); + EXPECT_TRUE(client1.GetUrl().find("snapshot=" + timestamp1) == std::string::npos); + EXPECT_TRUE(client1.GetUrl().find("snapshot=" + timestamp2) == std::string::npos); } }}} // namespace Azure::Storage::Test diff --git a/sdk/storage/azure-storage-files-shares/test/ut/share_directory_client_test.cpp b/sdk/storage/azure-storage-files-shares/test/ut/share_directory_client_test.cpp index 047405960..c07ec1bf0 100644 --- a/sdk/storage/azure-storage-files-shares/test/ut/share_directory_client_test.cpp +++ b/sdk/storage/azure-storage-files-shares/test/ut/share_directory_client_test.cpp @@ -21,6 +21,43 @@ namespace Azure { namespace Storage { namespace Test { m_fileShareDirectoryClient->Create(); } + TEST_F(FileShareDirectoryClientTest, Constructors) + { + auto clientOptions = InitStorageClientOptions(); + { + auto directoryClient = Files::Shares::ShareDirectoryClient::CreateFromConnectionString( + StandardStorageConnectionString(), m_shareName, m_directoryName, clientOptions); + EXPECT_NO_THROW(directoryClient.GetProperties()); + } + { + auto credential + = _internal::ParseConnectionString(StandardStorageConnectionString()).KeyCredential; + Files::Shares::ShareDirectoryClient directoryClient( + m_fileShareDirectoryClient->GetUrl(), credential, clientOptions); + EXPECT_NO_THROW(directoryClient.GetProperties()); + } + { + auto sasStartsOn = std::chrono::system_clock::now() - std::chrono::minutes(5); + auto sasExpiresOn = std::chrono::system_clock::now() + std::chrono::minutes(60); + + auto keyCredential + = _internal::ParseConnectionString(StandardStorageConnectionString()).KeyCredential; + + Sas::ShareSasBuilder shareSasBuilder; + shareSasBuilder.Protocol = Sas::SasProtocol::HttpsAndHttp; + shareSasBuilder.StartsOn = sasStartsOn; + shareSasBuilder.ExpiresOn = sasExpiresOn; + shareSasBuilder.ShareName = m_shareName; + shareSasBuilder.Resource = Sas::ShareSasResource::Share; + shareSasBuilder.SetPermissions(Sas::ShareSasPermissions::All); + auto sasToken = shareSasBuilder.GenerateSasToken(*keyCredential); + + auto directoryClient = Files::Shares::ShareDirectoryClient( + m_fileShareDirectoryClient->GetUrl() + sasToken, clientOptions); + EXPECT_NO_THROW(directoryClient.GetProperties()); + } + } + TEST_F(FileShareDirectoryClientTest, CreateDeleteDirectories) { { @@ -1124,6 +1161,14 @@ namespace Azure { namespace Storage { namespace Test { // Delete EXPECT_NO_THROW(directoryClient.Delete()); + + // OAuth Constructor + auto directoryClient1 = Files::Shares::ShareDirectoryClient( + m_fileShareDirectoryClient->GetUrl(), + std::make_shared( + AadTenantId(), AadClientId(), AadClientSecret(), GetTokenCredentialOptions()), + options); + EXPECT_NO_THROW(directoryClient1.GetProperties()); } // cspell:ignore myshare mydirectory @@ -1144,4 +1189,20 @@ namespace Azure { namespace Storage { namespace Test { EXPECT_TRUE(directoryHandles[0].AccessRights.HasValue()); EXPECT_EQ(allAccessRights, directoryHandles[0].AccessRights.Value()); } + + TEST_F(FileShareDirectoryClientTest, WithShareSnapshot) + { + const std::string timestamp1 = "2001-01-01T01:01:01.1111000Z"; + const std::string timestamp2 = "2022-02-02T02:02:02.2222000Z"; + + auto client1 = m_fileShareDirectoryClient->WithShareSnapshot(timestamp1); + EXPECT_FALSE(client1.GetUrl().find("snapshot=" + timestamp1) == std::string::npos); + EXPECT_TRUE(client1.GetUrl().find("snapshot=" + timestamp2) == std::string::npos); + client1 = client1.WithShareSnapshot(timestamp2); + EXPECT_TRUE(client1.GetUrl().find("snapshot=" + timestamp1) == std::string::npos); + EXPECT_FALSE(client1.GetUrl().find("snapshot=" + timestamp2) == std::string::npos); + client1 = client1.WithShareSnapshot(""); + EXPECT_TRUE(client1.GetUrl().find("snapshot=" + timestamp1) == std::string::npos); + EXPECT_TRUE(client1.GetUrl().find("snapshot=" + timestamp2) == std::string::npos); + } }}} // namespace Azure::Storage::Test diff --git a/sdk/storage/azure-storage-files-shares/test/ut/share_file_client_test.cpp b/sdk/storage/azure-storage-files-shares/test/ut/share_file_client_test.cpp index d5e7636c4..eb503e727 100644 --- a/sdk/storage/azure-storage-files-shares/test/ut/share_file_client_test.cpp +++ b/sdk/storage/azure-storage-files-shares/test/ut/share_file_client_test.cpp @@ -74,6 +74,30 @@ namespace Azure { namespace Storage { namespace Test { } } + TEST_F(FileShareFileClientTest, CreateWithHttpHeaders) + { + auto fileName = RandomString(); + Files::Shares::ShareFileClient client = m_fileShareDirectoryClient->GetFileClient(fileName); + + std::vector emptyContent; + Azure::Core::Cryptography::Md5Hash instance; + auto md5 = instance.Final(emptyContent.data(), 0L); + + Files::Shares::Models::FileHttpHeaders httpHeaders; + httpHeaders.ContentType = "application/x-binary"; + httpHeaders.ContentLanguage = "en-US"; + httpHeaders.ContentDisposition = "attachment"; + httpHeaders.CacheControl = "no-cache"; + httpHeaders.ContentEncoding = "identity"; + httpHeaders.ContentHash.Algorithm = HashAlgorithm::Md5; + httpHeaders.ContentHash.Value = md5; + + Files::Shares::CreateFileOptions options; + options.HttpHeaders = httpHeaders; + + EXPECT_NO_THROW(client.Create(1024, options)); + } + TEST_F(FileShareFileClientTest, DownloadEmptyFile) { auto fileClient = m_fileShareDirectoryClient->GetFileClient(RandomString()); @@ -656,6 +680,19 @@ namespace Azure { namespace Storage { namespace Test { EXPECT_EQ(downloadOptions.Range.Value().Offset, result.ContentRange.Offset); EXPECT_EQ(static_cast(numOfChunks) * rangeSize, result.FileSize); } + + // Range download without Length + { + Files::Shares::DownloadFileOptions downloadOptions; + downloadOptions.Range = Core::Http::HttpRange(); + downloadOptions.Range.Value().Offset = static_cast(rangeSize) * (numOfChunks - 1); + Files::Shares::Models::DownloadFileResult result; + EXPECT_NO_THROW(result = fileClient.Download(downloadOptions).Value); + auto resultBuffer = result.BodyStream->ReadToEnd(Core::Context()); + EXPECT_EQ(rangeContent, resultBuffer); + EXPECT_EQ(downloadOptions.Range.Value().Offset, result.ContentRange.Offset); + EXPECT_EQ(static_cast(numOfChunks) * rangeSize, result.FileSize); + } } // last write time { @@ -703,6 +740,21 @@ namespace Azure { namespace Storage { namespace Test { uploadOptions.TransactionalContentHash = hash; memBodyStream.Rewind(); EXPECT_THROW(fileClient.UploadRange(0, memBodyStream, uploadOptions), StorageException); + + Files::Shares::DownloadFileOptions downloadOptions; + downloadOptions.Range = Core::Http::HttpRange(); + downloadOptions.Range.Value().Offset = 0; + downloadOptions.Range.Value().Length = rangeSize; + downloadOptions.RangeHashAlgorithm = HashAlgorithm::Md5; + Files::Shares::Models::DownloadFileResult result; + EXPECT_NO_THROW(result = fileClient.Download(downloadOptions).Value); + auto resultBuffer = result.BodyStream->ReadToEnd(Core::Context()); + EXPECT_EQ(rangeContent, resultBuffer); + EXPECT_EQ(downloadOptions.Range.Value().Length.Value(), result.ContentRange.Length.Value()); + EXPECT_EQ(downloadOptions.Range.Value().Offset, result.ContentRange.Offset); + EXPECT_EQ(static_cast(numOfChunks) * rangeSize, result.FileSize); + EXPECT_TRUE(result.TransactionalContentHash.HasValue()); + EXPECT_EQ(md5, result.TransactionalContentHash.Value().Value); } } @@ -736,6 +788,37 @@ namespace Azure { namespace Storage { namespace Test { } } + TEST_F(FileShareFileClientTest, CopyWithProperties) + { + size_t fileSize = 128; + std::vector fileContent = RandomBuffer(fileSize); + auto memBodyStream = Core::IO::MemoryBodyStream(fileContent); + { + // Simple copy works. + auto fileClient = m_shareClient->GetRootDirectoryClient().GetFileClient(RandomString() + "1"); + fileClient.Create(fileSize); + + auto sourceProperties = fileClient.GetProperties().Value; + + Files::Shares::StartFileCopyOptions options; + options.SmbProperties.Attributes = sourceProperties.SmbProperties.Attributes; + options.SmbProperties.CreatedOn = sourceProperties.SmbProperties.CreatedOn; + options.SmbProperties.ChangedOn = sourceProperties.SmbProperties.ChangedOn; + options.SmbProperties.LastWrittenOn = sourceProperties.SmbProperties.LastWrittenOn; + options.PermissionCopyMode = Files::Shares::Models::PermissionCopyMode::Override; + options.SmbProperties.PermissionKey = sourceProperties.SmbProperties.PermissionKey; + + auto destFileClient + = m_shareClient->GetRootDirectoryClient().GetFileClient(RandomString() + "2"); + auto copyOperation = destFileClient.StartCopy(fileClient.GetUrl(), options); + EXPECT_EQ( + copyOperation.GetRawResponse().GetStatusCode(), + Azure::Core::Http::HttpStatusCode::Accepted); + auto fileProperties = copyOperation.PollUntilDone(std::chrono::milliseconds(1000)).Value; + EXPECT_EQ(fileProperties.CopyStatus.Value(), Files::Shares::Models::CopyStatus::Success); + } + } + TEST_F(FileShareFileClientTest, RangeRelated) { size_t fileSize = 1024 * 3; @@ -764,6 +847,60 @@ namespace Azure { namespace Storage { namespace Test { EXPECT_EQ(static_cast(fileSize / 2) - 1024, result.Ranges[1].Length.Value()); } + TEST_F(FileShareFileClientTest, GetRangeListWithRange) + { + size_t rangeSize = 128; + std::vector rangeContent = RandomBuffer(rangeSize); + auto memBodyStream = Core::IO::MemoryBodyStream(rangeContent); + + auto fileClient = m_shareClient->GetRootDirectoryClient().GetFileClient(RandomString()); + fileClient.Create(rangeSize); + + EXPECT_NO_THROW(fileClient.UploadRange(0, memBodyStream)); + + // GetRangeList with Range + { + Files::Shares::GetFileRangeListOptions options; + options.Range = Core::Http::HttpRange(); + options.Range.Value().Offset = 0; + options.Range.Value().Length = 128; + Files::Shares::Models::GetFileRangeListResult result; + + EXPECT_NO_THROW(result = fileClient.GetRangeList(options).Value); + EXPECT_EQ(1U, result.Ranges.size()); + EXPECT_EQ(0, result.Ranges[0].Offset); + EXPECT_TRUE(result.Ranges[0].Length.HasValue()); + + options.Range.Value().Length.Reset(); + EXPECT_NO_THROW(result = fileClient.GetRangeList(options).Value); + EXPECT_EQ(1U, result.Ranges.size()); + EXPECT_EQ(0, result.Ranges[0].Offset); + EXPECT_TRUE(result.Ranges[0].Length.HasValue()); + } + + // GetRangeListDiff with Range + { + auto snapshot = m_shareClient->CreateSnapshot().Value.Snapshot; + EXPECT_NO_THROW(fileClient.ClearRange(64, 64)); + Files::Shares::GetFileRangeListOptions options; + options.Range = Core::Http::HttpRange(); + options.Range.Value().Offset = 64; + options.Range.Value().Length = 64; + Files::Shares::Models::GetFileRangeListResult result; + + EXPECT_NO_THROW(result = fileClient.GetRangeListDiff(snapshot, options).Value); + EXPECT_EQ(1U, result.Ranges.size()); + EXPECT_EQ(64, result.Ranges[0].Offset); + EXPECT_TRUE(result.Ranges[0].Length.HasValue()); + + options.Range.Value().Length.Reset(); + EXPECT_NO_THROW(result = fileClient.GetRangeListDiff(snapshot, options).Value); + EXPECT_EQ(1U, result.Ranges.size()); + EXPECT_EQ(64, result.Ranges[0].Offset); + EXPECT_TRUE(result.Ranges[0].Length.HasValue()); + } + } + TEST_F(FileShareFileClientTest, PreviousRangeWithSnapshot) { size_t fileSize = 1024 * 10; @@ -1084,6 +1221,40 @@ namespace Azure { namespace Storage { namespace Test { EXPECT_NO_THROW(containerClient.Delete()); } + TEST_F(FileShareFileClientTest, UploadFromWithOptions) + { + auto fileClient = m_shareClient->GetRootDirectoryClient().GetFileClient(RandomString()); + + size_t fileSize = 512; + std::vector content(RandomBuffer(fileSize)); + auto memBodyStream = Core::IO::MemoryBodyStream(content); + + Azure::Core::Cryptography::Md5Hash instance; + auto md5 = instance.Final(content.data(), fileSize); + + Files::Shares::UploadFileFromOptions options; + + options.SmbProperties.Attributes = Files::Shares::Models::FileAttributes::Hidden; + options.SmbProperties.CreatedOn = std::chrono::system_clock::now(); + options.SmbProperties.LastWrittenOn = std::chrono::system_clock::now(); + options.SmbProperties.PermissionKey = ""; + options.SmbProperties.ChangedOn = std::chrono::system_clock::now(); + options.HttpHeaders.ContentType = "application/x-binary"; + options.HttpHeaders.ContentLanguage = "en-US"; + options.HttpHeaders.ContentDisposition = "attachment"; + options.HttpHeaders.CacheControl = "no-cache"; + options.HttpHeaders.ContentEncoding = "identity"; + options.HttpHeaders.ContentHash.Value = md5; + + // UploadFrom buffer + EXPECT_NO_THROW(fileClient.UploadFrom(content.data(), fileSize, options)); + + // UploadFrom file + const std::string tempFilename = "file" + RandomString(); + WriteFile(tempFilename, content); + EXPECT_NO_THROW(fileClient.UploadFrom(tempFilename, options)); + } + TEST_F(FileShareFileClientTest, AllowTrailingDot) { const std::string fileName = RandomString(); @@ -1430,6 +1601,14 @@ namespace Azure { namespace Storage { namespace Test { // Delete EXPECT_NO_THROW(fileClient.Delete()); + + // OAuth Constructor + auto fileClient1 = Files::Shares::ShareFileClient( + m_fileClient->GetUrl(), + std::make_shared( + AadTenantId(), AadClientId(), AadClientSecret(), GetTokenCredentialOptions()), + options); + EXPECT_NO_THROW(fileClient1.GetProperties()); } TEST_F(FileShareFileClientTest, OAuthCopy_PLAYBACKONLY_) @@ -1496,4 +1675,44 @@ namespace Azure { namespace Storage { namespace Test { EXPECT_TRUE(fileHandles[0].AccessRights.HasValue()); EXPECT_EQ(allAccessRights, fileHandles[0].AccessRights.Value()); } + + TEST_F(FileShareFileClientTest, WithShareSnapshot) + { + const std::string timestamp1 = "2001-01-01T01:01:01.1111000Z"; + const std::string timestamp2 = "2022-02-02T02:02:02.2222000Z"; + + auto client1 = m_fileClient->WithShareSnapshot(timestamp1); + EXPECT_FALSE(client1.GetUrl().find("snapshot=" + timestamp1) == std::string::npos); + EXPECT_TRUE(client1.GetUrl().find("snapshot=" + timestamp2) == std::string::npos); + client1 = client1.WithShareSnapshot(timestamp2); + EXPECT_TRUE(client1.GetUrl().find("snapshot=" + timestamp1) == std::string::npos); + EXPECT_FALSE(client1.GetUrl().find("snapshot=" + timestamp2) == std::string::npos); + client1 = client1.WithShareSnapshot(""); + EXPECT_TRUE(client1.GetUrl().find("snapshot=" + timestamp1) == std::string::npos); + EXPECT_TRUE(client1.GetUrl().find("snapshot=" + timestamp2) == std::string::npos); + } + + TEST(ShareFileHandleAccessRightsTest, ShareFileHandleAccessRights) + { + Files::Shares::Models::ShareFileHandleAccessRights accessRightsA + = Files::Shares::Models::ShareFileHandleAccessRights::Read + | Files::Shares::Models::ShareFileHandleAccessRights::Write; + Files::Shares::Models::ShareFileHandleAccessRights accessRightsB + = Files::Shares::Models::ShareFileHandleAccessRights::Write + | Files::Shares::Models::ShareFileHandleAccessRights::Delete; + + Files::Shares::Models::ShareFileHandleAccessRights orAccessRights + = Files::Shares::Models::ShareFileHandleAccessRights::Read + | Files::Shares::Models::ShareFileHandleAccessRights::Write + | Files::Shares::Models::ShareFileHandleAccessRights::Delete; + Files::Shares::Models::ShareFileHandleAccessRights andAccessRights + = Files::Shares::Models::ShareFileHandleAccessRights::Write; + Files::Shares::Models::ShareFileHandleAccessRights xorAccessRights + = Files::Shares::Models::ShareFileHandleAccessRights::Read + | Files::Shares::Models::ShareFileHandleAccessRights::Delete; + + EXPECT_EQ(orAccessRights, accessRightsA | accessRightsB); + EXPECT_EQ(andAccessRights, accessRightsA & accessRightsB); + EXPECT_EQ(xorAccessRights, accessRightsA ^ accessRightsB); + } }}} // namespace Azure::Storage::Test diff --git a/sdk/storage/azure-storage-files-shares/test/ut/share_service_client_test.cpp b/sdk/storage/azure-storage-files-shares/test/ut/share_service_client_test.cpp index 8def59819..7655422a6 100644 --- a/sdk/storage/azure-storage-files-shares/test/ut/share_service_client_test.cpp +++ b/sdk/storage/azure-storage-files-shares/test/ut/share_service_client_test.cpp @@ -26,6 +26,31 @@ namespace Azure { namespace Storage { namespace Test { StandardStorageConnectionString(), options)); } + TEST_F(FileShareServiceClientTest, Constructors) + { + auto clientOptions = InitStorageClientOptions(); + { + auto sasStartsOn = std::chrono::system_clock::now() - std::chrono::minutes(5); + auto sasExpiresOn = std::chrono::system_clock::now() + std::chrono::minutes(60); + + auto keyCredential + = _internal::ParseConnectionString(StandardStorageConnectionString()).KeyCredential; + + Sas::AccountSasBuilder accountSasBuilder; + accountSasBuilder.Protocol = Sas::SasProtocol::HttpsAndHttp; + accountSasBuilder.StartsOn = sasStartsOn; + accountSasBuilder.ExpiresOn = sasExpiresOn; + accountSasBuilder.Services = Sas::AccountSasServices::Files; + accountSasBuilder.ResourceTypes = Sas::AccountSasResource::All; + accountSasBuilder.SetPermissions(Sas::AccountSasPermissions::Read); + auto sasToken = accountSasBuilder.GenerateSasToken(*keyCredential); + + auto serviceClient = Files::Shares::ShareServiceClient( + m_shareServiceClient->GetUrl() + sasToken, clientOptions); + EXPECT_NO_THROW(serviceClient.GetProperties()); + } + } + TEST_F(FileShareServiceClientTest, ListShares) { std::string prefix1 = LowercaseRandomString();