diff --git a/sdk/storage/azure-storage-blobs/inc/azure/storage/blobs/blob_client.hpp b/sdk/storage/azure-storage-blobs/inc/azure/storage/blobs/blob_client.hpp index e174f8005..546639de7 100644 --- a/sdk/storage/azure-storage-blobs/inc/azure/storage/blobs/blob_client.hpp +++ b/sdk/storage/azure-storage-blobs/inc/azure/storage/blobs/blob_client.hpp @@ -16,6 +16,7 @@ #include "azure/storage/blobs/protocol/blob_rest_client.hpp" namespace Azure { namespace Storage { namespace Files { namespace DataLake { + class DataLakeFileSystemClient; class DataLakeDirectoryClient; class DataLakeFileClient; }}}} // namespace Azure::Storage::Files::DataLake @@ -353,8 +354,8 @@ namespace Azure { namespace Storage { namespace Blobs { explicit BlobClient( Azure::Core::Url blobUrl, std::shared_ptr pipeline, - Azure::Nullable customerProvidedKey, - Azure::Nullable encryptionScope) + Azure::Nullable customerProvidedKey = Azure::Nullable(), + Azure::Nullable encryptionScope = Azure::Nullable()) : m_blobUrl(std::move(blobUrl)), m_pipeline(std::move(pipeline)), m_customerProvidedKey(std::move(customerProvidedKey)), m_encryptionScope(std::move(encryptionScope)) @@ -362,6 +363,7 @@ namespace Azure { namespace Storage { namespace Blobs { } friend class BlobContainerClient; + friend class Files::DataLake::DataLakeFileSystemClient; friend class Files::DataLake::DataLakeDirectoryClient; friend class Files::DataLake::DataLakeFileClient; friend class BlobLeaseClient; diff --git a/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/datalake_utilities.hpp b/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/datalake_utilities.hpp index 636a6ff19..9eb8acc64 100644 --- a/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/datalake_utilities.hpp +++ b/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/datalake_utilities.hpp @@ -12,8 +12,16 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { namespace _detail { - std::string GetBlobUrlFromUrl(const std::string& url); - std::string GetDfsUrlFromUrl(const std::string& url); + Azure::Core::Url GetBlobUrlFromUrl(const Azure::Core::Url& url); + Azure::Core::Url GetDfsUrlFromUrl(const Azure::Core::Url& url); + inline std::string GetBlobUrlFromUrl(const std::string& url) + { + return GetBlobUrlFromUrl(Azure::Core::Url(url)).GetAbsoluteUrl(); + } + inline std::string GetDfsUrlFromUrl(const std::string& url) + { + return GetDfsUrlFromUrl(Azure::Core::Url(url)).GetAbsoluteUrl(); + } std::string SerializeMetadata(const Storage::Metadata& dataLakePropertiesMap); diff --git a/sdk/storage/azure-storage-files-datalake/src/datalake_directory_client.cpp b/sdk/storage/azure-storage-files-datalake/src/datalake_directory_client.cpp index ffc83c80a..7e22a5dc3 100644 --- a/sdk/storage/azure-storage-files-datalake/src/datalake_directory_client.cpp +++ b/sdk/storage/azure-storage-files-datalake/src/datalake_directory_client.cpp @@ -86,16 +86,23 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { const RenameFileOptions& options, const Azure::Core::Context& context) const { - Azure::Nullable destinationFileSystem = options.DestinationFileSystem; - if (!destinationFileSystem.HasValue() || destinationFileSystem.GetValue().empty()) + std::string destinationFileSystem; + if (options.DestinationFileSystem.HasValue()) { - const auto& currentPath = m_pathUrl.GetPath(); - std::string::const_iterator cur = currentPath.begin(); - destinationFileSystem = _detail::GetSubstringTillDelimiter('/', currentPath, cur); + destinationFileSystem = options.DestinationFileSystem.GetValue(); } + else + { + const std::string& currentPath = m_pathUrl.GetPath(); + destinationFileSystem = currentPath.substr(0, currentPath.find('/')); + } + + auto sourceDfsUrl = m_pathUrl; + sourceDfsUrl.AppendPath(_internal::UrlEncodePath(fileName)); + auto destinationDfsUrl = m_pathUrl; - destinationDfsUrl.SetPath( - destinationFileSystem.GetValue() + '/' + _internal::UrlEncodePath(destinationFilePath)); + destinationDfsUrl.SetPath(_internal::UrlEncodePath(destinationFileSystem)); + destinationDfsUrl.AppendPath(_internal::UrlEncodePath(destinationFilePath)); _detail::DataLakeRestClient::Path::CreateOptions protocolLayerOptions; protocolLayerOptions.Mode = _detail::PathRenameMode::Legacy; @@ -109,16 +116,14 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { protocolLayerOptions.SourceIfNoneMatch = options.SourceAccessConditions.IfNoneMatch; protocolLayerOptions.SourceIfModifiedSince = options.SourceAccessConditions.IfModifiedSince; protocolLayerOptions.SourceIfUnmodifiedSince = options.SourceAccessConditions.IfUnmodifiedSince; - protocolLayerOptions.RenameSource - = "/" + m_pathUrl.GetPath() + _internal::UrlEncodePath(fileName); + protocolLayerOptions.RenameSource = "/" + sourceDfsUrl.GetPath(); auto result = _detail::DataLakeRestClient::Path::Create( destinationDfsUrl, *m_pipeline, context, protocolLayerOptions); - // At this point, there is not more exception thrown, meaning the rename is successful. - // Initialize the file client. - auto blobClient = m_blobClient; - blobClient.m_blobUrl.SetPath(destinationDfsUrl.GetPath()); - auto renamedFileClient - = DataLakeFileClient(std::move(destinationDfsUrl), std::move(blobClient), m_pipeline); + + auto renamedBlobClient + = Blobs::BlobClient(_detail::GetBlobUrlFromUrl(destinationDfsUrl), m_pipeline); + auto renamedFileClient = DataLakeFileClient( + std::move(destinationDfsUrl), std::move(renamedBlobClient), m_pipeline); return Azure::Response( std::move(renamedFileClient), result.ExtractRawResponse()); } @@ -129,17 +134,23 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { const RenameSubdirectoryOptions& options, const Azure::Core::Context& context) const { - Azure::Nullable destinationFileSystem = options.DestinationFileSystem; - if (!destinationFileSystem.HasValue() || destinationFileSystem.GetValue().empty()) + std::string destinationFileSystem; + if (options.DestinationFileSystem.HasValue()) { - const auto& currentPath = m_pathUrl.GetPath(); - std::string::const_iterator cur = currentPath.begin(); - destinationFileSystem = _detail::GetSubstringTillDelimiter('/', currentPath, cur); + destinationFileSystem = options.DestinationFileSystem.GetValue(); } + else + { + const std::string& currentPath = m_pathUrl.GetPath(); + destinationFileSystem = currentPath.substr(0, currentPath.find('/')); + } + + auto sourceDfsUrl = m_pathUrl; + sourceDfsUrl.AppendPath(_internal::UrlEncodePath(subdirectoryName)); + auto destinationDfsUrl = m_pathUrl; - destinationDfsUrl.SetPath( - destinationFileSystem.GetValue() + '/' - + _internal::UrlEncodePath(destinationDirectoryPath)); + destinationDfsUrl.SetPath(_internal::UrlEncodePath(destinationFileSystem)); + destinationDfsUrl.AppendPath(_internal::UrlEncodePath(destinationDirectoryPath)); _detail::DataLakeRestClient::Path::CreateOptions protocolLayerOptions; protocolLayerOptions.Mode = _detail::PathRenameMode::Legacy; @@ -153,16 +164,14 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { protocolLayerOptions.SourceIfNoneMatch = options.SourceAccessConditions.IfNoneMatch; protocolLayerOptions.SourceIfModifiedSince = options.SourceAccessConditions.IfModifiedSince; protocolLayerOptions.SourceIfUnmodifiedSince = options.SourceAccessConditions.IfUnmodifiedSince; - protocolLayerOptions.RenameSource - = "/" + m_pathUrl.GetPath() + _internal::UrlEncodePath(subdirectoryName); + protocolLayerOptions.RenameSource = "/" + sourceDfsUrl.GetPath(); auto result = _detail::DataLakeRestClient::Path::Create( destinationDfsUrl, *m_pipeline, context, protocolLayerOptions); - // At this point, there is not more exception thrown, meaning the rename is successful. - // Initialize the directory client. - auto blobClient = m_blobClient; - blobClient.m_blobUrl.SetPath(destinationDfsUrl.GetPath()); - auto renamedDirectoryClient - = DataLakeDirectoryClient(std::move(destinationDfsUrl), std::move(blobClient), m_pipeline); + + auto renamedBlobClient + = Blobs::BlobClient(_detail::GetBlobUrlFromUrl(destinationDfsUrl), m_pipeline); + auto renamedDirectoryClient = DataLakeDirectoryClient( + std::move(destinationDfsUrl), std::move(renamedBlobClient), m_pipeline); return Azure::Response( std::move(renamedDirectoryClient), result.ExtractRawResponse()); } diff --git a/sdk/storage/azure-storage-files-datalake/src/datalake_file_system_client.cpp b/sdk/storage/azure-storage-files-datalake/src/datalake_file_system_client.cpp index ed1f3cf8c..e026a7a59 100644 --- a/sdk/storage/azure-storage-files-datalake/src/datalake_file_system_client.cpp +++ b/sdk/storage/azure-storage-files-datalake/src/datalake_file_system_client.cpp @@ -347,7 +347,46 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { const RenameFileOptions& options, const Azure::Core::Context& context) const { - return this->GetDirectoryClient("").RenameFile(fileName, destinationFilePath, options, context); + std::string destinationFileSystem; + if (options.DestinationFileSystem.HasValue()) + { + destinationFileSystem = options.DestinationFileSystem.GetValue(); + } + else + { + const std::string& currentPath = m_fileSystemUrl.GetPath(); + destinationFileSystem = currentPath.substr(0, currentPath.find('/')); + } + + auto sourceDfsUrl = m_fileSystemUrl; + sourceDfsUrl.AppendPath(_internal::UrlEncodePath(fileName)); + + auto destinationDfsUrl = m_fileSystemUrl; + destinationDfsUrl.SetPath(_internal::UrlEncodePath(destinationFileSystem)); + destinationDfsUrl.AppendPath(_internal::UrlEncodePath(destinationFilePath)); + + _detail::DataLakeRestClient::Path::CreateOptions protocolLayerOptions; + protocolLayerOptions.Mode = _detail::PathRenameMode::Legacy; + protocolLayerOptions.SourceLeaseId = options.SourceAccessConditions.LeaseId; + protocolLayerOptions.LeaseIdOptional = options.AccessConditions.LeaseId; + protocolLayerOptions.IfMatch = options.AccessConditions.IfMatch; + protocolLayerOptions.IfNoneMatch = options.AccessConditions.IfNoneMatch; + protocolLayerOptions.IfModifiedSince = options.AccessConditions.IfModifiedSince; + protocolLayerOptions.IfUnmodifiedSince = options.AccessConditions.IfUnmodifiedSince; + protocolLayerOptions.SourceIfMatch = options.SourceAccessConditions.IfMatch; + protocolLayerOptions.SourceIfNoneMatch = options.SourceAccessConditions.IfNoneMatch; + protocolLayerOptions.SourceIfModifiedSince = options.SourceAccessConditions.IfModifiedSince; + protocolLayerOptions.SourceIfUnmodifiedSince = options.SourceAccessConditions.IfUnmodifiedSince; + protocolLayerOptions.RenameSource = "/" + sourceDfsUrl.GetPath(); + auto result = _detail::DataLakeRestClient::Path::Create( + destinationDfsUrl, *m_pipeline, context, protocolLayerOptions); + + auto renamedBlobClient + = Blobs::BlobClient(_detail::GetBlobUrlFromUrl(destinationDfsUrl), m_pipeline); + auto renamedFileClient = DataLakeFileClient( + std::move(destinationDfsUrl), std::move(renamedBlobClient), m_pipeline); + return Azure::Response( + std::move(renamedFileClient), result.ExtractRawResponse()); } Azure::Response DataLakeFileSystemClient::RenameDirectory( @@ -356,8 +395,46 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { const RenameDirectoryOptions& options, const Azure::Core::Context& context) const { - return this->GetDirectoryClient("").RenameSubdirectory( - directoryName, destinationDirectoryPath, options, context); + std::string destinationFileSystem; + if (options.DestinationFileSystem.HasValue()) + { + destinationFileSystem = options.DestinationFileSystem.GetValue(); + } + else + { + const std::string& currentPath = m_fileSystemUrl.GetPath(); + destinationFileSystem = currentPath.substr(0, currentPath.find('/')); + } + + auto sourceDfsUrl = m_fileSystemUrl; + sourceDfsUrl.AppendPath(_internal::UrlEncodePath(directoryName)); + + auto destinationDfsUrl = m_fileSystemUrl; + destinationDfsUrl.SetPath(_internal::UrlEncodePath(destinationFileSystem)); + destinationDfsUrl.AppendPath(_internal::UrlEncodePath(destinationDirectoryPath)); + + _detail::DataLakeRestClient::Path::CreateOptions protocolLayerOptions; + protocolLayerOptions.Mode = _detail::PathRenameMode::Legacy; + protocolLayerOptions.SourceLeaseId = options.SourceAccessConditions.LeaseId; + protocolLayerOptions.LeaseIdOptional = options.AccessConditions.LeaseId; + protocolLayerOptions.IfMatch = options.AccessConditions.IfMatch; + protocolLayerOptions.IfNoneMatch = options.AccessConditions.IfNoneMatch; + protocolLayerOptions.IfModifiedSince = options.AccessConditions.IfModifiedSince; + protocolLayerOptions.IfUnmodifiedSince = options.AccessConditions.IfUnmodifiedSince; + protocolLayerOptions.SourceIfMatch = options.SourceAccessConditions.IfMatch; + protocolLayerOptions.SourceIfNoneMatch = options.SourceAccessConditions.IfNoneMatch; + protocolLayerOptions.SourceIfModifiedSince = options.SourceAccessConditions.IfModifiedSince; + protocolLayerOptions.SourceIfUnmodifiedSince = options.SourceAccessConditions.IfUnmodifiedSince; + protocolLayerOptions.RenameSource = "/" + sourceDfsUrl.GetPath(); + auto result = _detail::DataLakeRestClient::Path::Create( + destinationDfsUrl, *m_pipeline, context, protocolLayerOptions); + + auto renamedBlobClient + = Blobs::BlobClient(_detail::GetBlobUrlFromUrl(destinationDfsUrl), m_pipeline); + auto renamedDirectoryClient = DataLakeDirectoryClient( + std::move(destinationDfsUrl), std::move(renamedBlobClient), m_pipeline); + return Azure::Response( + std::move(renamedDirectoryClient), result.ExtractRawResponse()); } }}}} // namespace Azure::Storage::Files::DataLake diff --git a/sdk/storage/azure-storage-files-datalake/src/datalake_utilities.cpp b/sdk/storage/azure-storage-files-datalake/src/datalake_utilities.cpp index 4a3aaa497..c22d7466d 100644 --- a/sdk/storage/azure-storage-files-datalake/src/datalake_utilities.cpp +++ b/sdk/storage/azure-storage-files-datalake/src/datalake_utilities.cpp @@ -13,25 +13,31 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { nam const static std::string DfsEndPointIdentifier = ".dfs."; const static std::string BlobEndPointIdentifier = ".blob."; - std::string GetBlobUrlFromUrl(const std::string& url) + Azure::Core::Url GetBlobUrlFromUrl(const Azure::Core::Url& url) { - std::string result = url; - auto pos = result.find(DfsEndPointIdentifier); - if (pos != std::string::npos) + std::string host = url.GetHost(); + auto pos = host.rfind(DfsEndPointIdentifier); + if (pos == std::string::npos) { - result.replace(pos, DfsEndPointIdentifier.size(), BlobEndPointIdentifier); + return url; } + host.replace(pos, DfsEndPointIdentifier.size(), BlobEndPointIdentifier); + Azure::Core::Url result = url; + result.SetHost(host); return result; } - std::string GetDfsUrlFromUrl(const std::string& url) + Azure::Core::Url GetDfsUrlFromUrl(const Azure::Core::Url& url) { - std::string result = url; - auto pos = result.find(BlobEndPointIdentifier); - if (pos != std::string::npos) + std::string host = url.GetHost(); + auto pos = host.rfind(BlobEndPointIdentifier); + if (pos == std::string::npos) { - result.replace(pos, BlobEndPointIdentifier.size(), DfsEndPointIdentifier); + return url; } + host.replace(pos, BlobEndPointIdentifier.size(), DfsEndPointIdentifier); + Azure::Core::Url result = url; + result.SetHost(host); return result; } diff --git a/sdk/storage/azure-storage-files-datalake/test/datalake_directory_client_test.cpp b/sdk/storage/azure-storage-files-datalake/test/datalake_directory_client_test.cpp index 178ded4ff..31bee5543 100644 --- a/sdk/storage/azure-storage-files-datalake/test/datalake_directory_client_test.cpp +++ b/sdk/storage/azure-storage-files-datalake/test/datalake_directory_client_test.cpp @@ -131,114 +131,146 @@ namespace Azure { namespace Storage { namespace Test { } } + TEST_F(DataLakeDirectoryClientTest, RenameFile) + { + const std::string baseDirectoryName = RandomString(); + auto baseDirectoryClient = m_fileSystemClient->GetDirectoryClient(baseDirectoryName); + baseDirectoryClient.Create(); + + const std::string oldFilename = RandomString(); + auto oldFileClient = baseDirectoryClient.GetSubdirectoryClient(oldFilename); + oldFileClient.Create(); + const std::string newFilename = RandomString(); + auto newFileClient + = *baseDirectoryClient.RenameFile(oldFilename, baseDirectoryName + "/" + newFilename); + EXPECT_NO_THROW(newFileClient.GetProperties()); + EXPECT_NO_THROW(baseDirectoryClient.GetSubdirectoryClient(newFilename).GetProperties()); + EXPECT_THROW(oldFileClient.GetProperties(), StorageException); + + const std::string newFileSystemName = LowercaseRandomString(); + const std::string newFilename2 = RandomString(); + + auto newFileSystem = m_dataLakeServiceClient->GetFileSystemClient(newFileSystemName); + newFileSystem.Create(); + + Files::DataLake::RenameFileOptions options; + options.DestinationFileSystem = newFileSystemName; + auto newFileClient2 = *baseDirectoryClient.RenameFile(newFilename, newFilename2, options); + + EXPECT_NO_THROW(newFileClient2.GetProperties()); + EXPECT_NO_THROW(newFileSystem.GetFileClient(newFilename2).GetProperties()); + newFileSystem.Delete(); + EXPECT_THROW(newFileClient.GetProperties(), StorageException); + } + + TEST_F(DataLakeDirectoryClientTest, RenameFileAccessCondition) + { + const std::string baseDirectoryName = RandomString(); + auto baseDirectoryClient = m_fileSystemClient->GetDirectoryClient(baseDirectoryName); + baseDirectoryClient.Create(); + + const std::string oldFilename = RandomString(); + auto oldFileClient = baseDirectoryClient.GetSubdirectoryClient(oldFilename); + oldFileClient.Create(); + const std::string newFilename = RandomString(); + + Files::DataLake::RenameFileOptions options; + options.SourceAccessConditions.IfModifiedSince = oldFileClient.GetProperties()->LastModified; + EXPECT_THROW( + baseDirectoryClient.RenameFile(oldFilename, newFilename, options), StorageException); + + options = Files::DataLake::RenameFileOptions(); + options.SourceAccessConditions.IfUnmodifiedSince + = oldFileClient.GetProperties()->LastModified - std::chrono::minutes(5); + + EXPECT_THROW( + baseDirectoryClient.RenameFile(oldFilename, newFilename, options), StorageException); + + options = Files::DataLake::RenameFileOptions(); + options.SourceAccessConditions.IfMatch = DummyETag; + + EXPECT_THROW( + baseDirectoryClient.RenameFile(oldFilename, newFilename, options), StorageException); + + options = Files::DataLake::RenameFileOptions(); + options.SourceAccessConditions.IfNoneMatch = oldFileClient.GetProperties()->ETag; + + EXPECT_THROW( + baseDirectoryClient.RenameFile(oldFilename, newFilename, options), StorageException); + } + TEST_F(DataLakeDirectoryClientTest, RenameDirectory) { - { - // Normal create/rename/delete. - std::vector directoryClients; - for (int32_t i = 0; i < 5; ++i) - { - auto client = m_fileSystemClient->GetDirectoryClient(RandomString()); - EXPECT_NO_THROW(client.Create()); - directoryClients.emplace_back(std::move(client)); - } - std::vector newDirectoryClients; - for (auto& client : directoryClients) - { - auto newPath = RandomString(); - EXPECT_NO_THROW(newDirectoryClients.emplace_back( - client.RenameSubdirectory("", newPath).ExtractValue())); - } - for (const auto& client : directoryClients) - { - EXPECT_THROW(client.DeleteEmpty(), StorageException); - } - for (const auto& client : newDirectoryClients) - { - EXPECT_NO_THROW(client.DeleteEmpty()); - } - } - { - // Normal rename with last modified access condition. - std::vector directoryClient; - for (int32_t i = 0; i < 2; ++i) - { - auto client = m_fileSystemClient->GetDirectoryClient(RandomString()); - EXPECT_NO_THROW(client.Create()); - directoryClient.emplace_back(std::move(client)); - } - for (auto& client : directoryClient) - { - auto response = client.GetProperties(); - Files::DataLake::RenameDirectoryOptions options1; - options1.SourceAccessConditions.IfModifiedSince = response->LastModified; - EXPECT_TRUE(IsValidTime(response->LastModified)); - EXPECT_THROW(client.RenameSubdirectory("", RandomString(), options1), StorageException); - Files::DataLake::RenameDirectoryOptions options2; - options2.SourceAccessConditions.IfUnmodifiedSince = response->LastModified; - auto newPath = RandomString(); - EXPECT_NO_THROW( - client.RenameSubdirectory("", newPath, options2).ExtractValue().DeleteEmpty()); - } - } - { - // Normal rename with if match access condition. - std::vector directoryClient; - for (int32_t i = 0; i < 2; ++i) - { - auto client = m_fileSystemClient->GetDirectoryClient(RandomString()); - EXPECT_NO_THROW(client.Create()); - directoryClient.emplace_back(std::move(client)); - } - for (auto& client : directoryClient) - { - auto response = client.GetProperties(); - Files::DataLake::RenameDirectoryOptions options1; - options1.SourceAccessConditions.IfNoneMatch = response->ETag; - EXPECT_THROW(client.RenameSubdirectory("", RandomString(), options1), StorageException); - Files::DataLake::RenameDirectoryOptions options2; - options2.SourceAccessConditions.IfMatch = response->ETag; - auto newPath = RandomString(); - EXPECT_NO_THROW( - client.RenameSubdirectory("", newPath, options2).ExtractValue().DeleteEmpty()); - } - } - { - // Rename to a destination file system. - std::vector directoryClient; - for (int32_t i = 0; i < 2; ++i) - { - auto client = m_fileSystemClient->GetDirectoryClient(RandomString()); - EXPECT_NO_THROW(client.Create()); - directoryClient.emplace_back(std::move(client)); - } - { - // Rename to a non-existing file system will fail and source is not changed. - Files::DataLake::RenameDirectoryOptions options; - options.DestinationFileSystem = LowercaseRandomString(); - for (auto& client : directoryClient) - { - EXPECT_THROW(client.RenameSubdirectory("", RandomString(), options), StorageException); - EXPECT_NO_THROW(client.GetProperties()); - } - } - { - // Rename to an existing file system will succeed and changes URI. - auto newfileSystemName = LowercaseRandomString(10); - auto newfileSystemClient = std::make_shared( - Files::DataLake::DataLakeFileSystemClient::CreateFromConnectionString( - AdlsGen2ConnectionString(), newfileSystemName)); - newfileSystemClient->Create(); - Files::DataLake::RenameDirectoryOptions options; - options.DestinationFileSystem = newfileSystemName; - for (auto& client : directoryClient) - { - auto newPath = RandomString(); - EXPECT_NO_THROW( - client.RenameSubdirectory("", newPath, options).ExtractValue().DeleteEmpty()); - } - } - } + const std::string baseDirectoryName = RandomString(); + auto baseDirectoryClient = m_fileSystemClient->GetDirectoryClient(baseDirectoryName); + baseDirectoryClient.Create(); + + const std::string oldDirectoryName = RandomString(); + auto oldDirectoryClient = baseDirectoryClient.GetSubdirectoryClient(oldDirectoryName); + oldDirectoryClient.Create(); + const std::string newDirectoryName = RandomString(); + auto newDirectoryClient = *baseDirectoryClient.RenameSubdirectory( + oldDirectoryName, baseDirectoryName + "/" + newDirectoryName); + EXPECT_NO_THROW(newDirectoryClient.GetProperties()); + EXPECT_NO_THROW(baseDirectoryClient.GetSubdirectoryClient(newDirectoryName).GetProperties()); + EXPECT_THROW(oldDirectoryClient.GetProperties(), StorageException); + + const std::string newFileSystemName = LowercaseRandomString(); + const std::string newDirectoryName2 = RandomString(); + + auto newFileSystem = m_dataLakeServiceClient->GetFileSystemClient(newFileSystemName); + newFileSystem.Create(); + + Files::DataLake::RenameDirectoryOptions options; + options.DestinationFileSystem = newFileSystemName; + auto newDirectoryClient2 + = *baseDirectoryClient.RenameSubdirectory(newDirectoryName, newDirectoryName2, options); + + EXPECT_NO_THROW(newDirectoryClient2.GetProperties()); + EXPECT_NO_THROW(newFileSystem.GetDirectoryClient(newDirectoryName2).GetProperties()); + newFileSystem.Delete(); + EXPECT_THROW(newDirectoryClient.GetProperties(), StorageException); + } + + TEST_F(DataLakeDirectoryClientTest, RenameDirectoryAccessCondition) + { + const std::string baseDirectoryName = RandomString(); + auto baseDirectoryClient = m_fileSystemClient->GetDirectoryClient(baseDirectoryName); + baseDirectoryClient.Create(); + + const std::string oldDirectoryName = RandomString(); + auto oldDirectoryClient = baseDirectoryClient.GetSubdirectoryClient(oldDirectoryName); + oldDirectoryClient.Create(); + const std::string newDirectoryName = RandomString(); + + Files::DataLake::RenameDirectoryOptions options; + options.SourceAccessConditions.IfModifiedSince + = oldDirectoryClient.GetProperties()->LastModified; + EXPECT_THROW( + baseDirectoryClient.RenameSubdirectory(oldDirectoryName, newDirectoryName, options), + StorageException); + + options = Files::DataLake::RenameDirectoryOptions(); + options.SourceAccessConditions.IfUnmodifiedSince + = oldDirectoryClient.GetProperties()->LastModified - std::chrono::minutes(5); + + EXPECT_THROW( + baseDirectoryClient.RenameSubdirectory(oldDirectoryName, newDirectoryName, options), + StorageException); + + options = Files::DataLake::RenameDirectoryOptions(); + options.SourceAccessConditions.IfMatch = DummyETag; + + EXPECT_THROW( + baseDirectoryClient.RenameSubdirectory(oldDirectoryName, newDirectoryName, options), + StorageException); + + options = Files::DataLake::RenameDirectoryOptions(); + options.SourceAccessConditions.IfNoneMatch = oldDirectoryClient.GetProperties()->ETag; + + EXPECT_THROW( + baseDirectoryClient.RenameSubdirectory(oldDirectoryName, newDirectoryName, options), + StorageException); } TEST_F(DataLakeDirectoryClientTest, DirectoryMetadata) diff --git a/sdk/storage/azure-storage-files-datalake/test/datalake_file_client_test.cpp b/sdk/storage/azure-storage-files-datalake/test/datalake_file_client_test.cpp index 47788281d..ac7dd3fc6 100644 --- a/sdk/storage/azure-storage-files-datalake/test/datalake_file_client_test.cpp +++ b/sdk/storage/azure-storage-files-datalake/test/datalake_file_client_test.cpp @@ -130,90 +130,6 @@ namespace Azure { namespace Storage { namespace Test { } } - TEST_F(DataLakeFileClientTest, RenameFiles) - { - { - // Normal create/rename/delete. - auto fileName = RandomString(); - EXPECT_NO_THROW(m_fileSystemClient->GetFileClient(fileName).Create()); - std::shared_ptr ret; - EXPECT_NO_THROW( - ret = std::make_shared( - m_fileSystemClient->RenameFile(fileName, RandomString()).ExtractValue())); - EXPECT_THROW(m_fileSystemClient->GetFileClient(fileName).Delete(), StorageException); - EXPECT_NO_THROW(ret->Delete()); - } - { - // Normal rename with last modified access condition. - auto fileName = RandomString(); - auto fileClient = m_fileSystemClient->GetFileClient(fileName); - EXPECT_NO_THROW(fileClient.Create()); - auto response = fileClient.GetProperties(); - Files::DataLake::RenameFileOptions options1; - options1.SourceAccessConditions.IfModifiedSince = response->LastModified; - EXPECT_THROW( - m_fileSystemClient->RenameFile(fileName, RandomString(), options1), StorageException); - Files::DataLake::RenameFileOptions options2; - options2.SourceAccessConditions.IfUnmodifiedSince = response->LastModified; - std::shared_ptr ret; - EXPECT_NO_THROW( - ret = std::make_shared( - m_fileSystemClient->RenameFile(fileName, RandomString(), options2).ExtractValue())); - EXPECT_THROW(m_fileSystemClient->GetFileClient(fileName).Delete(), StorageException); - EXPECT_NO_THROW(ret->Delete()); - } - { - // Normal rename with if match access condition. - auto fileName = RandomString(); - auto fileClient = m_fileSystemClient->GetFileClient(fileName); - EXPECT_NO_THROW(fileClient.Create()); - auto response = fileClient.GetProperties(); - Files::DataLake::RenameFileOptions options1; - options1.SourceAccessConditions.IfNoneMatch = response->ETag; - EXPECT_THROW( - m_fileSystemClient->RenameFile(fileName, RandomString(), options1), StorageException); - Files::DataLake::RenameFileOptions options2; - options2.SourceAccessConditions.IfMatch = response->ETag; - std::shared_ptr ret; - EXPECT_NO_THROW( - ret = std::make_shared( - m_fileSystemClient->RenameFile(fileName, RandomString(), options2).ExtractValue())); - EXPECT_THROW(m_fileSystemClient->GetFileClient(fileName).Delete(), StorageException); - EXPECT_THROW(fileClient.GetProperties(), StorageException); - EXPECT_NO_THROW(ret->Delete()); - } - { - // Rename to a destination file system. - auto fileName = RandomString(); - auto fileClient = m_fileSystemClient->GetFileClient(fileName); - EXPECT_NO_THROW(fileClient.Create()); - { - // Rename to a non-existing file system will fail but will not change URI. - Files::DataLake::RenameFileOptions options; - options.DestinationFileSystem = LowercaseRandomString(); - EXPECT_THROW( - m_fileSystemClient->RenameFile(fileName, RandomString(), options), StorageException); - EXPECT_NO_THROW(fileClient.GetProperties()); - } - { - // Rename to an existing file system will succeed and changes URI. - auto newfileSystemName = LowercaseRandomString(10); - auto newfileSystemClient = std::make_shared( - Files::DataLake::DataLakeFileSystemClient::CreateFromConnectionString( - AdlsGen2ConnectionString(), newfileSystemName)); - newfileSystemClient->Create(); - Files::DataLake::RenameFileOptions options; - options.DestinationFileSystem = newfileSystemName; - std::shared_ptr ret; - EXPECT_NO_THROW( - ret = std::make_shared( - m_fileSystemClient->RenameFile(fileName, RandomString(), options).ExtractValue())); - EXPECT_THROW(fileClient.GetProperties(), StorageException); - EXPECT_NO_THROW(ret->Delete()); - } - } - } - TEST_F(DataLakeFileClientTest, FileMetadata) { auto metadata1 = RandomMetadata(); diff --git a/sdk/storage/azure-storage-files-datalake/test/datalake_file_system_client_test.cpp b/sdk/storage/azure-storage-files-datalake/test/datalake_file_system_client_test.cpp index aefc0cf41..09dd4ec5f 100644 --- a/sdk/storage/azure-storage-files-datalake/test/datalake_file_system_client_test.cpp +++ b/sdk/storage/azure-storage-files-datalake/test/datalake_file_system_client_test.cpp @@ -23,10 +23,11 @@ namespace Azure { namespace Storage { namespace Test { void DataLakeFileSystemClientTest::SetUpTestSuite() { + DataLakeServiceClientTest::SetUpTestSuite(); + m_fileSystemName = LowercaseRandomString(); m_fileSystemClient = std::make_shared( - Files::DataLake::DataLakeFileSystemClient::CreateFromConnectionString( - AdlsGen2ConnectionString(), m_fileSystemName)); + m_dataLakeServiceClient->GetFileSystemClient(m_fileSystemName)); m_fileSystemClient->Create(); m_directoryA = LowercaseRandomString(); @@ -48,7 +49,11 @@ namespace Azure { namespace Storage { namespace Test { } } - void DataLakeFileSystemClientTest::TearDownTestSuite() { m_fileSystemClient->Delete(); } + void DataLakeFileSystemClientTest::TearDownTestSuite() + { + m_fileSystemClient->Delete(); + DataLakeServiceClientTest::TearDownTestSuite(); + } std::vector DataLakeFileSystemClientTest::ListAllPaths( bool recursive, @@ -439,4 +444,69 @@ namespace Azure { namespace Storage { namespace Test { EXPECT_EQ(Files::DataLake::Models::PublicAccessType::Path, ret->AccessType); } } + + TEST_F(DataLakeFileSystemClientTest, RenameFile) + { + const std::string oldFilename = RandomString(); + const std::string newFilename = RandomString(); + + auto oldFileClient = m_fileSystemClient->GetFileClient(oldFilename); + oldFileClient.Create(); + + auto newFileClient = *m_fileSystemClient->RenameFile(oldFilename, newFilename); + + EXPECT_NO_THROW(newFileClient.GetProperties()); + EXPECT_NO_THROW(m_fileSystemClient->GetFileClient(newFilename).GetProperties()); + EXPECT_THROW(oldFileClient.GetProperties(), StorageException); + + const std::string newFileSystemName = LowercaseRandomString(); + const std::string newFilename2 = RandomString(); + + auto newFileSystem = m_dataLakeServiceClient->GetFileSystemClient(newFileSystemName); + newFileSystem.Create(); + + Files::DataLake::RenameFileOptions options; + options.DestinationFileSystem = newFileSystemName; + auto newFileClient2 = *m_fileSystemClient->RenameFile(newFilename, newFilename2, options); + + EXPECT_NO_THROW(newFileClient2.GetProperties()); + EXPECT_NO_THROW(newFileSystem.GetFileClient(newFilename2).GetProperties()); + newFileSystem.Delete(); + EXPECT_THROW(newFileClient.GetProperties(), StorageException); + } + + TEST_F(DataLakeFileSystemClientTest, RenameDirectory) + { + const std::string oldDirectoryName = RandomString(); + const std::string newDirectoryName = RandomString(); + + auto oldDirectoryClient = m_fileSystemClient->GetDirectoryClient(oldDirectoryName); + oldDirectoryClient.Create(); + oldDirectoryClient.GetFileClient(RandomString()).Create(); + oldDirectoryClient.GetSubdirectoryClient(RandomString()).Create(); + + auto newDirectoryClient + = *m_fileSystemClient->RenameDirectory(oldDirectoryName, newDirectoryName); + + EXPECT_NO_THROW(newDirectoryClient.GetProperties()); + EXPECT_NO_THROW(m_fileSystemClient->GetDirectoryClient(newDirectoryName).GetProperties()); + EXPECT_THROW(oldDirectoryClient.GetProperties(), StorageException); + + const std::string newFileSystemName = LowercaseRandomString(); + const std::string newDirectoryName2 = RandomString(); + + auto newFileSystem = m_dataLakeServiceClient->GetFileSystemClient(newFileSystemName); + newFileSystem.Create(); + + Files::DataLake::RenameDirectoryOptions options; + options.DestinationFileSystem = newFileSystemName; + auto newDirectoryClient2 + = *m_fileSystemClient->RenameDirectory(newDirectoryName, newDirectoryName2, options); + + EXPECT_NO_THROW(newDirectoryClient2.GetProperties()); + EXPECT_NO_THROW(newFileSystem.GetDirectoryClient(newDirectoryName2).GetProperties()); + newFileSystem.Delete(); + EXPECT_THROW(newDirectoryClient.GetProperties(), StorageException); + } + }}} // namespace Azure::Storage::Test diff --git a/sdk/storage/azure-storage-files-datalake/test/datalake_file_system_client_test.hpp b/sdk/storage/azure-storage-files-datalake/test/datalake_file_system_client_test.hpp index 4d49e0d19..3d4927ba8 100644 --- a/sdk/storage/azure-storage-files-datalake/test/datalake_file_system_client_test.hpp +++ b/sdk/storage/azure-storage-files-datalake/test/datalake_file_system_client_test.hpp @@ -3,11 +3,12 @@ #include +#include "datalake_service_client_test.hpp" #include "test_base.hpp" namespace Azure { namespace Storage { namespace Test { - class DataLakeFileSystemClientTest : public ::testing::Test { + class DataLakeFileSystemClientTest : public DataLakeServiceClientTest { protected: static void SetUpTestSuite(); static void TearDownTestSuite();