refine impl of rename file/directory (#1991)
* fix bug: / was left out in rename source * refine impl of rename file/directory
This commit is contained in:
parent
88499ab1b6
commit
b9c5c978ee
@ -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<Azure::Core::Http::_internal::HttpPipeline> pipeline,
|
||||
Azure::Nullable<EncryptionKey> customerProvidedKey,
|
||||
Azure::Nullable<std::string> encryptionScope)
|
||||
Azure::Nullable<EncryptionKey> customerProvidedKey = Azure::Nullable<EncryptionKey>(),
|
||||
Azure::Nullable<std::string> encryptionScope = Azure::Nullable<std::string>())
|
||||
: 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;
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -86,16 +86,23 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
|
||||
const RenameFileOptions& options,
|
||||
const Azure::Core::Context& context) const
|
||||
{
|
||||
Azure::Nullable<std::string> 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<DataLakeFileClient>(
|
||||
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<std::string> 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<DataLakeDirectoryClient>(
|
||||
std::move(renamedDirectoryClient), result.ExtractRawResponse());
|
||||
}
|
||||
|
||||
@ -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<DataLakeFileClient>(
|
||||
std::move(renamedFileClient), result.ExtractRawResponse());
|
||||
}
|
||||
|
||||
Azure::Response<DataLakeDirectoryClient> 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<DataLakeDirectoryClient>(
|
||||
std::move(renamedDirectoryClient), result.ExtractRawResponse());
|
||||
}
|
||||
|
||||
}}}} // namespace Azure::Storage::Files::DataLake
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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<Files::DataLake::DataLakeDirectoryClient> 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<Files::DataLake::DataLakeDirectoryClient> 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<Files::DataLake::DataLakeDirectoryClient> 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<Files::DataLake::DataLakeDirectoryClient> 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<Files::DataLake::DataLakeDirectoryClient> 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>(
|
||||
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)
|
||||
|
||||
@ -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<Files::DataLake::DataLakeFileClient> ret;
|
||||
EXPECT_NO_THROW(
|
||||
ret = std::make_shared<Files::DataLake::DataLakeFileClient>(
|
||||
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<Files::DataLake::DataLakeFileClient> ret;
|
||||
EXPECT_NO_THROW(
|
||||
ret = std::make_shared<Files::DataLake::DataLakeFileClient>(
|
||||
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<Files::DataLake::DataLakeFileClient> ret;
|
||||
EXPECT_NO_THROW(
|
||||
ret = std::make_shared<Files::DataLake::DataLakeFileClient>(
|
||||
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>(
|
||||
Files::DataLake::DataLakeFileSystemClient::CreateFromConnectionString(
|
||||
AdlsGen2ConnectionString(), newfileSystemName));
|
||||
newfileSystemClient->Create();
|
||||
Files::DataLake::RenameFileOptions options;
|
||||
options.DestinationFileSystem = newfileSystemName;
|
||||
std::shared_ptr<Files::DataLake::DataLakeFileClient> ret;
|
||||
EXPECT_NO_THROW(
|
||||
ret = std::make_shared<Files::DataLake::DataLakeFileClient>(
|
||||
m_fileSystemClient->RenameFile(fileName, RandomString(), options).ExtractValue()));
|
||||
EXPECT_THROW(fileClient.GetProperties(), StorageException);
|
||||
EXPECT_NO_THROW(ret->Delete());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DataLakeFileClientTest, FileMetadata)
|
||||
{
|
||||
auto metadata1 = RandomMetadata();
|
||||
|
||||
@ -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>(
|
||||
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<Files::DataLake::Models::PathItem> 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
|
||||
|
||||
@ -3,11 +3,12 @@
|
||||
|
||||
#include <azure/storage/files/datalake.hpp>
|
||||
|
||||
#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();
|
||||
|
||||
Loading…
Reference in New Issue
Block a user