Refine rename functions in datalake (#1493)

* Refine rename functions in datalake

* Changed default mode to Legacy

* remove mode.

* Make rename return clients.

* Remove continuation token

* Resolve merge issue.
This commit is contained in:
Kan Tang 2021-01-28 01:21:59 -08:00 committed by GitHub
parent ec9d35ae8c
commit d99f3ab8e6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 241 additions and 233 deletions

View File

@ -34,6 +34,9 @@
- Changed all previous `LeaseDuration` members to a new type named `LeaseDurationType`.
- `startsOn` parameter for `GetUserDelegationKey` was changed to optional.
- Removed `PreviousContinuationToken` from `ListFileSystemsSinglePageResult`.
- Removed `Rename` from `DataLakeDirectoryClient` and `DataLakeFileClient`. Instead, added `RenameFile` and `RenameSubdirectory` to `DataLakeDirectoryClient` and added `RenameFile` and `RenameDirectory` to `DataLakeFileSystemClient`.
- Rename APIs now return the client of the resource it is renaming to.
- Removed `Mode` for rename operations' options, that originally controls the rename mode. Now it is fixed to legacy mode.
- Changed `SetAccessControlRecursive` to `SetAccessControlRecursiveListSinglePage`, to mark that it is a single page operation, and removed the `mode` parameter, separated the modify/delete functionality to two new APIs.
- Moved `SetAccessControlRecursiveListSinglePage` to `DataLakePathClient`.
- Changed `MaxRecord` to `MaxEntries`, `ForceFlag` to `ContinueOnFailure` to be more accurate names.

View File

@ -116,20 +116,34 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
}
/**
* @brief Renames a directory. By default, the destination is overwritten and
* @brief Renames a file. By default, the destination is overwritten and
* if the destination already exists and has a lease the lease is broken.
* @param destinationDirectoryPath The destinationPath this current directory is renaming to.
* @param options Optional parameters to rename a resource to the resource the destination
* directory points to.
* @return Azure::Core::Response<Models::RenameDataLakeDirectoryResult> containing the
* information returned when renaming the directory.
* @remark This operation will not change the URL this directory client points too, to use the
* new name, customer needs to initialize a new directory client with the new name/path.
* @param fileName The file that gets renamed.
* @param destinationFilePath The path of the file the source file is renaming to.
* @param options Optional parameters to rename a file.
* @return Azure::Core::Response<DataLakeFileClient> The client targets the renamed file.
* @remark This request is sent to dfs endpoint.
*/
Azure::Core::Response<Models::RenameDataLakeDirectoryResult> Rename(
Azure::Core::Response<DataLakeFileClient> RenameFile(
const std::string& fileName,
const std::string& destinationFilePath,
const RenameDataLakeFileOptions& options = RenameDataLakeFileOptions()) const;
/**
* @brief Renames a directory. By default, the destination is overwritten and
* if the destination already exists and has a lease the lease is broken.
* @param subdirectoryName The subdirectory that gets renamed.
* @param destinationDirectoryPath The destinationPath the source subdirectory is renaming to.
* @param options Optional parameters to rename a directory.
* @return Azure::Core::Response<DataLakeDirectoryClient> The client targets the renamed
* directory.
* @remark This request is sent to dfs endpoint.
*/
Azure::Core::Response<DataLakeDirectoryClient> RenameSubdirectory(
const std::string& subdirectoryName,
const std::string& destinationDirectoryPath,
const RenameDataLakeDirectoryOptions& options = RenameDataLakeDirectoryOptions()) const;
const RenameDataLakeSubdirectoryOptions& options
= RenameDataLakeSubdirectoryOptions()) const;
/**
* @brief Deletes the directory.

View File

@ -142,22 +142,6 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
return DataLakePathClient::CreateIfNotExists(Models::PathResourceType::File, options);
}
/**
* @brief Renames a file. By default, the destination is overwritten and
* if the destination already exists and has a lease the lease is broken.
* @param destinationFilePath The path of the file this file is renaming to.
* @param options Optional parameters to rename a resource to the resource the destination path
* points to.
* @return Azure::Core::Response<Models::RenameDataLakeDataLakeFileResult> containing the
* information returned when renaming the file.
* @remark This operation will not change the URL this file client points too, to use the
* new name, customer needs to initialize a new file client with the new name/path.
* @remark This request is sent to dfs endpoint.
*/
Azure::Core::Response<Models::RenameDataLakeFileResult> Rename(
const std::string& destinationFilePath,
const RenameDataLakeFileOptions& options = RenameDataLakeFileOptions()) const;
/**
* @brief Deletes the file.
* @param options Optional parameters to delete the file the path points to.

View File

@ -201,6 +201,35 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
const SetDataLakeFileSystemAccessPolicyOptions& options
= SetDataLakeFileSystemAccessPolicyOptions()) const;
/**
* @brief Renames a file. By default, the destination is overwritten and
* if the destination already exists and has a lease the lease is broken.
* @param fileName The file that gets renamed.
* @param destinationFilePath The path of the file the source file is renaming to.
* @param options Optional parameters to rename a file
* @return Azure::Core::Response<DataLakeFileClient> The client targets the renamed file.
* @remark This request is sent to dfs endpoint.
*/
Azure::Core::Response<DataLakeFileClient> RenameFile(
const std::string& fileName,
const std::string& destinationFilePath,
const RenameDataLakeFileOptions& options = RenameDataLakeFileOptions()) const;
/**
* @brief Renames a directory. By default, the destination is overwritten and
* if the destination already exists and has a lease the lease is broken.
* @param directoryName The directory that gets renamed.
* @param destinationDirectoryPath The destinationPath the source directory is renaming to.
* @param options Optional parameters to rename a directory.
* @return Azure::Core::Response<DataLakeDirectoryClient> The client targets the renamed
* directory.
* @remark This request is sent to dfs endpoint.
*/
Azure::Core::Response<DataLakeDirectoryClient> RenameDirectory(
const std::string& directoryName,
const std::string& destinationDirectoryPath,
const RenameDataLakeDirectoryOptions& options = RenameDataLakeDirectoryOptions()) const;
private:
Azure::Core::Http::Url m_dfsUrl;
Blobs::BlobContainerClient m_blobContainerClient;

View File

@ -258,6 +258,36 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
FileSystemAccessConditions AccessConditions;
};
/**
* @brief Optional parameters for DataLakeFileSystemClient::RenameDirectory
* @remark Some optional parameter is mandatory in certain combination.
* More details:
* https://docs.microsoft.com/en-us/rest/api/storageservices/datalakestoragegen2/path/create
*/
struct RenameDataLakeDirectoryOptions
{
/**
* @brief Context for cancelling long running operations.
*/
Azure::Core::Context Context;
/**
* @brief If not specified, the source's file system is used. Otherwise, rename to destination
* file system.
*/
Azure::Core::Nullable<std::string> DestinationFileSystem;
/**
* @brief Specify the access condition for the path.
*/
PathAccessConditions AccessConditions;
/**
* @brief The access condition for source path.
*/
PathAccessConditions SourceAccessConditions;
};
/**
* @brief Optional parameters for PathClient::Append
*/
@ -585,13 +615,6 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
*/
Azure::Core::Context Context;
/**
* @brief This parameter determines the behavior of the rename operation. The value must be
* PathRenameMode::Legacy or PathRenameMode::Posix, and the default value will be
* PathRenameMode::Posix.
*/
Models::PathRenameMode Mode = Models::PathRenameMode::Posix;
/**
* @brief If not specified, the source's file system is used. Otherwise, rename to destination
* file system.
@ -625,51 +648,7 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
PathAccessConditions AccessConditions;
};
/**
* @brief Optional parameters for PathClient::Create
* @remark Some optional parameter is mandatory in certain combination.
* More details:
* https://docs.microsoft.com/en-us/rest/api/storageservices/datalakestoragegen2/path/create
*/
struct RenameDataLakeDirectoryOptions
{
/**
* @brief Context for cancelling long running operations.
*/
Azure::Core::Context Context;
/**
* @brief When renaming a directory, the number of paths that are renamed with each
* invocation is limited. If the number of paths to be renamed exceeds this limit,
* a continuation token is returned in this response header. When a continuation token
* is returned in the response, it must be specified in a subsequent invocation of the
* rename operation to continue renaming the directory.
*/
Azure::Core::Nullable<std::string> ContinuationToken;
/**
* @brief This parameter determines the behavior of the rename operation. The value must be
* PathRenameMode::Legacy or PathRenameMode::Posix, and the default value will be
* PathRenameMode::Posix.
*/
Models::PathRenameMode Mode = Models::PathRenameMode::Posix;
/**
* @brief If not specified, the source's file system is used. Otherwise, rename to destination
* file system.
*/
Azure::Core::Nullable<std::string> DestinationFileSystem;
/**
* @brief Specify the access condition for the path.
*/
PathAccessConditions AccessConditions;
/**
* @brief The access condition for source path.
*/
PathAccessConditions SourceAccessConditions;
};
using RenameDataLakeSubdirectoryOptions = RenameDataLakeDirectoryOptions;
/**
* @brief Optional parameters for DirectoryClient::Delete

View File

@ -227,11 +227,6 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { nam
std::string RequestId;
};
struct RenameDataLakeFileResult
{
std::string RequestId;
};
struct DeleteDataLakeFileResult
{
bool Deleted = true;

View File

@ -333,7 +333,6 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
Azure::Core::Nullable<std::string> ETag;
Azure::Core::Nullable<Core::DateTime> LastModified;
std::string RequestId;
Azure::Core::Nullable<std::string> ContinuationToken;
Azure::Core::Nullable<int64_t> ContentLength;
};
@ -1183,11 +1182,6 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
Core::DateTime::DateFormat::Rfc1123);
}
result.RequestId = response.GetHeaders().at(Details::HeaderRequestId);
if (response.GetHeaders().find(Details::HeaderContinuationToken)
!= response.GetHeaders().end())
{
result.ContinuationToken = response.GetHeaders().at(Details::HeaderContinuationToken);
}
if (response.GetHeaders().find(Details::HeaderContentLength)
!= response.GetHeaders().end())
{

View File

@ -147,9 +147,10 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
return DataLakeDirectoryClient(std::move(builder), std::move(blobClient), m_pipeline);
}
Azure::Core::Response<Models::RenameDataLakeDirectoryResult> DataLakeDirectoryClient::Rename(
const std::string& destinationPath,
const RenameDataLakeDirectoryOptions& options) const
Azure::Core::Response<DataLakeFileClient> DataLakeDirectoryClient::RenameFile(
const std::string& fileName,
const std::string& destinationFilePath,
const RenameDataLakeFileOptions& options) const
{
Azure::Core::Nullable<std::string> destinationFileSystem = options.DestinationFileSystem;
if (!destinationFileSystem.HasValue() || destinationFileSystem.GetValue().empty())
@ -159,11 +160,12 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
destinationFileSystem = Details::GetSubstringTillDelimiter('/', currentPath, cur);
}
auto destinationDfsUri = m_dfsUrl;
destinationDfsUri.SetPath(destinationFileSystem.GetValue() + '/' + destinationPath);
destinationDfsUri.SetPath(
destinationFileSystem.GetValue() + '/'
+ Storage::Details::UrlEncodePath(destinationFilePath));
Details::DataLakeRestClient::Path::CreateOptions protocolLayerOptions;
protocolLayerOptions.ContinuationToken = options.ContinuationToken;
protocolLayerOptions.Mode = options.Mode;
protocolLayerOptions.Mode = Models::PathRenameMode::Legacy;
protocolLayerOptions.SourceLeaseId = options.SourceAccessConditions.LeaseId;
protocolLayerOptions.LeaseIdOptional = options.AccessConditions.LeaseId;
protocolLayerOptions.IfMatch = options.AccessConditions.IfMatch;
@ -174,15 +176,65 @@ 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_dfsUrl.GetPath();
protocolLayerOptions.RenameSource
= "/" + m_dfsUrl.GetPath() + Storage::Details::UrlEncodePath(fileName);
auto result = Details::DataLakeRestClient::Path::Create(
destinationDfsUri, *m_pipeline, options.Context, protocolLayerOptions);
// At this point, there is not more exception thrown, meaning the rename is successful.
Models::RenameDataLakeDirectoryResult ret;
ret.ContinuationToken = std::move(result->ContinuationToken);
ret.RequestId = std::move(result->RequestId);
return Azure::Core::Response<Models::RenameDataLakeDirectoryResult>(
std::move(ret), result.ExtractRawResponse());
// Initialize the file client.
auto blobClient = m_blobClient;
blobClient.m_blobUrl.SetPath(destinationDfsUri.GetPath());
auto blockBlobClient = blobClient.AsBlockBlobClient();
auto renamedFileClient = DataLakeFileClient(
std::move(destinationDfsUri),
std::move(blobClient),
std::move(blockBlobClient),
m_pipeline);
return Azure::Core::Response<DataLakeFileClient>(
std::move(renamedFileClient), result.ExtractRawResponse());
}
Azure::Core::Response<DataLakeDirectoryClient> DataLakeDirectoryClient::RenameSubdirectory(
const std::string& subdirectoryName,
const std::string& destinationDirectoryPath,
const RenameDataLakeSubdirectoryOptions& options) const
{
Azure::Core::Nullable<std::string> destinationFileSystem = options.DestinationFileSystem;
if (!destinationFileSystem.HasValue() || destinationFileSystem.GetValue().empty())
{
const auto& currentPath = m_dfsUrl.GetPath();
std::string::const_iterator cur = currentPath.begin();
destinationFileSystem = Details::GetSubstringTillDelimiter('/', currentPath, cur);
}
auto destinationDfsUri = m_dfsUrl;
destinationDfsUri.SetPath(
destinationFileSystem.GetValue() + '/'
+ Storage::Details::UrlEncodePath(destinationDirectoryPath));
Details::DataLakeRestClient::Path::CreateOptions protocolLayerOptions;
protocolLayerOptions.Mode = Models::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
= "/" + m_dfsUrl.GetPath() + Storage::Details::UrlEncodePath(subdirectoryName);
auto result = Details::DataLakeRestClient::Path::Create(
destinationDfsUri, *m_pipeline, options.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(destinationDfsUri.GetPath());
auto renamedDirectoryClient
= DataLakeDirectoryClient(std::move(destinationDfsUri), std::move(blobClient), m_pipeline);
return Azure::Core::Response<DataLakeDirectoryClient>(
std::move(renamedDirectoryClient), result.ExtractRawResponse());
}
Azure::Core::Response<Models::DeleteDataLakeDirectoryResult> DataLakeDirectoryClient::Delete(

View File

@ -250,42 +250,6 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
m_dfsUrl, *m_pipeline, options.Context, protocolLayerOptions);
}
Azure::Core::Response<Models::RenameDataLakeFileResult> DataLakeFileClient::Rename(
const std::string& destinationPath,
const RenameDataLakeFileOptions& options) const
{
Azure::Core::Nullable<std::string> destinationFileSystem = options.DestinationFileSystem;
if (!destinationFileSystem.HasValue() || destinationFileSystem.GetValue().empty())
{
const auto& currentPath = m_dfsUrl.GetPath();
std::string::const_iterator cur = currentPath.begin();
destinationFileSystem = Details::GetSubstringTillDelimiter('/', currentPath, cur);
}
auto destinationDfsUri = m_dfsUrl;
destinationDfsUri.SetPath(destinationFileSystem.GetValue() + '/' + destinationPath);
Details::DataLakeRestClient::Path::CreateOptions protocolLayerOptions;
protocolLayerOptions.Mode = options.Mode;
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 = "/" + m_dfsUrl.GetPath();
auto result = Details::DataLakeRestClient::Path::Create(
destinationDfsUri, *m_pipeline, options.Context, protocolLayerOptions);
// At this point, there is not more exception thrown, meaning the rename is successful.
Models::RenameDataLakeFileResult ret;
ret.RequestId = std::move(result->RequestId);
return Azure::Core::Response<Models::RenameDataLakeFileResult>(
std::move(ret), result.ExtractRawResponse());
}
Azure::Core::Response<Models::DeleteDataLakeFileResult> DataLakeFileClient::Delete(
const DeleteDataLakeFileOptions& options) const
{

View File

@ -395,4 +395,21 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
std::move(ret), result.ExtractRawResponse());
}
Azure::Core::Response<DataLakeFileClient> DataLakeFileSystemClient::RenameFile(
const std::string& fileName,
const std::string& destinationFilePath,
const RenameDataLakeFileOptions& options) const
{
return this->GetDirectoryClient("").RenameFile(fileName, destinationFilePath, options);
}
Azure::Core::Response<DataLakeDirectoryClient> DataLakeFileSystemClient::RenameDirectory(
const std::string& directoryName,
const std::string& destinationDirectoryPath,
const RenameDataLakeDirectoryOptions& options) const
{
return this->GetDirectoryClient("").RenameSubdirectory(
directoryName, destinationDirectoryPath, options);
}
}}}} // namespace Azure::Storage::Files::DataLake

View File

@ -140,20 +140,20 @@ namespace Azure { namespace Storage { namespace Test {
EXPECT_NO_THROW(client.Create());
directoryClients.emplace_back(std::move(client));
}
std::vector<std::string> newPaths;
std::vector<Files::DataLake::DataLakeDirectoryClient> newDirectoryClients;
for (auto& client : directoryClients)
{
auto newPath = RandomString();
EXPECT_NO_THROW(client.Rename(newPath));
newPaths.push_back(newPath);
EXPECT_NO_THROW(newDirectoryClients.emplace_back(
client.RenameSubdirectory("", newPath).ExtractValue()));
}
for (const auto& client : directoryClients)
{
EXPECT_THROW(client.Delete(false), StorageException);
}
for (const auto& newPath : newPaths)
for (const auto& client : newDirectoryClients)
{
EXPECT_NO_THROW(m_fileSystemClient->GetDirectoryClient(newPath).Delete(false));
EXPECT_NO_THROW(client.Delete(false));
}
}
{
@ -171,12 +171,12 @@ namespace Azure { namespace Storage { namespace Test {
Files::DataLake::RenameDataLakeDirectoryOptions options1;
options1.SourceAccessConditions.IfModifiedSince = response->LastModified;
EXPECT_TRUE(IsValidTime(response->LastModified));
EXPECT_THROW(client.Rename(RandomString(), options1), StorageException);
EXPECT_THROW(client.RenameSubdirectory("", RandomString(), options1), StorageException);
Files::DataLake::RenameDataLakeDirectoryOptions options2;
options2.SourceAccessConditions.IfUnmodifiedSince = response->LastModified;
auto newPath = RandomString();
EXPECT_NO_THROW(client.Rename(newPath, options2));
EXPECT_NO_THROW(m_fileSystemClient->GetDirectoryClient(newPath).Delete(false));
EXPECT_NO_THROW(
client.RenameSubdirectory("", newPath, options2).ExtractValue().Delete(false));
}
}
{
@ -193,12 +193,12 @@ namespace Azure { namespace Storage { namespace Test {
auto response = client.GetProperties();
Files::DataLake::RenameDataLakeDirectoryOptions options1;
options1.SourceAccessConditions.IfNoneMatch = response->ETag;
EXPECT_THROW(client.Rename(RandomString(), options1), StorageException);
EXPECT_THROW(client.RenameSubdirectory("", RandomString(), options1), StorageException);
Files::DataLake::RenameDataLakeDirectoryOptions options2;
options2.SourceAccessConditions.IfMatch = response->ETag;
auto newPath = RandomString();
EXPECT_NO_THROW(client.Rename(newPath, options2));
EXPECT_NO_THROW(m_fileSystemClient->GetDirectoryClient(newPath).Delete(false));
EXPECT_NO_THROW(
client.RenameSubdirectory("", newPath, options2).ExtractValue().Delete(false));
}
}
{
@ -216,7 +216,7 @@ namespace Azure { namespace Storage { namespace Test {
options.DestinationFileSystem = LowercaseRandomString();
for (auto& client : directoryClient)
{
EXPECT_THROW(client.Rename(RandomString(), options), StorageException);
EXPECT_THROW(client.RenameSubdirectory("", RandomString(), options), StorageException);
EXPECT_NO_THROW(client.GetProperties());
}
}
@ -232,8 +232,8 @@ namespace Azure { namespace Storage { namespace Test {
for (auto& client : directoryClient)
{
auto newPath = RandomString();
EXPECT_NO_THROW(client.Rename(newPath, options));
EXPECT_NO_THROW(newfileSystemClient->GetDirectoryClient(newPath).Delete(false));
EXPECT_NO_THROW(
client.RenameSubdirectory("", newPath, options).ExtractValue().Delete(false));
}
}
}

View File

@ -132,91 +132,66 @@ namespace Azure { namespace Storage { namespace Test {
{
{
// Normal create/rename/delete.
std::vector<Files::DataLake::DataLakeFileClient> fileClients;
for (int32_t i = 0; i < 5; ++i)
{
auto client = m_fileSystemClient->GetFileClient(RandomString());
EXPECT_NO_THROW(client.Create());
fileClients.emplace_back(std::move(client));
}
std::vector<std::string> newPaths;
for (auto& client : fileClients)
{
auto newPath = RandomString();
EXPECT_NO_THROW(client.Rename(newPath));
newPaths.push_back(newPath);
}
for (const auto& client : fileClients)
{
EXPECT_THROW(client.Delete(), StorageException);
}
for (const auto& newPath : newPaths)
{
EXPECT_NO_THROW(m_fileSystemClient->GetDirectoryClient(newPath).Delete(false));
}
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.
std::vector<Files::DataLake::DataLakeFileClient> fileClient;
for (int32_t i = 0; i < 2; ++i)
{
auto client = m_fileSystemClient->GetFileClient(RandomString());
EXPECT_NO_THROW(client.Create());
fileClient.emplace_back(std::move(client));
}
for (auto& client : fileClient)
{
auto response = client.GetProperties();
Files::DataLake::RenameDataLakeFileOptions options1;
options1.SourceAccessConditions.IfModifiedSince = response->LastModified;
EXPECT_THROW(client.Rename(RandomString(), options1), StorageException);
Files::DataLake::RenameDataLakeFileOptions options2;
options2.SourceAccessConditions.IfUnmodifiedSince = response->LastModified;
auto newPath = RandomString();
EXPECT_NO_THROW(client.Rename(newPath, options2));
EXPECT_NO_THROW(m_fileSystemClient->GetDirectoryClient(newPath).Delete(false));
}
auto fileName = RandomString();
auto fileClient = m_fileSystemClient->GetFileClient(fileName);
EXPECT_NO_THROW(fileClient.Create());
auto response = fileClient.GetProperties();
Files::DataLake::RenameDataLakeFileOptions options1;
options1.SourceAccessConditions.IfModifiedSince = response->LastModified;
EXPECT_THROW(
m_fileSystemClient->RenameFile(fileName, RandomString(), options1), StorageException);
Files::DataLake::RenameDataLakeFileOptions 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.
std::vector<Files::DataLake::DataLakeFileClient> fileClient;
for (int32_t i = 0; i < 2; ++i)
{
auto client = m_fileSystemClient->GetFileClient(RandomString());
EXPECT_NO_THROW(client.Create());
fileClient.emplace_back(std::move(client));
}
for (auto& client : fileClient)
{
auto response = client.GetProperties();
Files::DataLake::RenameDataLakeFileOptions options1;
options1.SourceAccessConditions.IfNoneMatch = response->ETag;
EXPECT_THROW(client.Rename(RandomString(), options1), StorageException);
Files::DataLake::RenameDataLakeFileOptions options2;
options2.SourceAccessConditions.IfMatch = response->ETag;
auto newPath = RandomString();
EXPECT_NO_THROW(client.Rename(newPath, options2));
EXPECT_NO_THROW(m_fileSystemClient->GetDirectoryClient(newPath).Delete(false));
}
auto fileName = RandomString();
auto fileClient = m_fileSystemClient->GetFileClient(fileName);
EXPECT_NO_THROW(fileClient.Create());
auto response = fileClient.GetProperties();
Files::DataLake::RenameDataLakeFileOptions options1;
options1.SourceAccessConditions.IfNoneMatch = response->ETag;
EXPECT_THROW(
m_fileSystemClient->RenameFile(fileName, RandomString(), options1), StorageException);
Files::DataLake::RenameDataLakeFileOptions 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.
std::vector<Files::DataLake::DataLakeFileClient> fileClient;
for (int32_t i = 0; i < 2; ++i)
{
auto client = m_fileSystemClient->GetFileClient(RandomString());
EXPECT_NO_THROW(client.Create());
fileClient.emplace_back(std::move(client));
}
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::RenameDataLakeFileOptions options;
options.DestinationFileSystem = LowercaseRandomString();
for (auto& client : fileClient)
{
EXPECT_THROW(client.Rename(RandomString(), options), StorageException);
EXPECT_NO_THROW(client.GetProperties());
}
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.
@ -227,12 +202,12 @@ namespace Azure { namespace Storage { namespace Test {
newfileSystemClient->Create();
Files::DataLake::RenameDataLakeFileOptions options;
options.DestinationFileSystem = newfileSystemName;
for (auto& client : fileClient)
{
auto newPath = RandomString();
EXPECT_NO_THROW(client.Rename(newPath, options));
EXPECT_NO_THROW(newfileSystemClient->GetDirectoryClient(newPath).Delete(false));
}
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());
}
}
}
@ -570,7 +545,8 @@ namespace Azure { namespace Storage { namespace Test {
TEST_F(DataLakeFileClientTest, ConstructorsWorks)
{
{
// Create from connection string validates static creator function and shared key constructor.
// Create from connection string validates static creator function and shared key
// constructor.
auto fileName = RandomString(10);
auto connectionStringClient
= Azure::Storage::Files::DataLake::DataLakeFileClient::CreateFromConnectionString(

View File

@ -123,9 +123,10 @@ namespace Azure { namespace Storage { namespace Test {
std::string newFilename = RandomString();
auto newFileClient0 = directory2Client0.GetFileClient(newFilename);
newFileClient0.Create();
auto fileClient = Files::DataLake::DataLakeFileClient(
Files::DataLake::Details::GetDfsUrlFromUrl(newFileClient0.GetUrl()) + sas);
EXPECT_NO_THROW(fileClient.Rename(directory1Name + "/" + directory2Name + "/" + fileName));
auto directoryClient = Files::DataLake::DataLakeDirectoryClient(
Files::DataLake::Details::GetDfsUrlFromUrl(directory2Client0.GetUrl()) + sas);
EXPECT_NO_THROW(directoryClient.RenameFile(
newFilename, directory1Name + "/" + directory2Name + "/" + fileName));
};
auto verify_file_execute = [&](const std::string& sas) {