Added 2020-02-10 features. (#692)
* Added 2020-02-10 features. * Resolved comments.
This commit is contained in:
parent
453545afd6
commit
1b351de2d8
@ -137,6 +137,27 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
|
||||
bool Recursive,
|
||||
const DeleteDirectoryOptions& options = DeleteDirectoryOptions()) const;
|
||||
|
||||
/**
|
||||
* @brief Sets POSIX access control rights on files and directories under given directory
|
||||
* recursively.
|
||||
* @param mode Mode PathSetAccessControlRecursiveMode::Set sets POSIX access control rights on
|
||||
* files and directories, PathSetAccessControlRecursiveMode::Modify modifies one or more POSIX
|
||||
* access control rights that pre-exist on files and directories,
|
||||
* PathSetAccessControlRecursiveMode::Remove removes one or more POSIX access control rights
|
||||
* that were present earlier on files and directories
|
||||
* @param acls Sets POSIX access control rights on files and directories. Each access control
|
||||
* entry (ACE) consists of a scope, a type, a user or group identifier, and permissions.
|
||||
* @param options Optional parameters to set an access control recursively to the resource the
|
||||
* directory points to.
|
||||
* @return Azure::Core::Response<SetDirectoryAccessControlRecursiveResult>
|
||||
* @remark This request is sent to dfs endpoint.
|
||||
*/
|
||||
Azure::Core::Response<SetDirectoryAccessControlRecursiveResult> SetAccessControlRecursive(
|
||||
PathSetAccessControlRecursiveMode mode,
|
||||
std::vector<Acl> acls,
|
||||
const SetDirectoryAccessControlRecursiveOptions& options
|
||||
= SetDirectoryAccessControlRecursiveOptions()) const;
|
||||
|
||||
private:
|
||||
explicit DirectoryClient(
|
||||
Azure::Core::Http::Url dfsUri,
|
||||
|
||||
@ -647,6 +647,43 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
|
||||
PathAccessConditions AccessConditions;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Optional parameters for PathClient::SetAccessControlRecursive
|
||||
*/
|
||||
struct SetDirectoryAccessControlRecursiveOptions
|
||||
{
|
||||
/**
|
||||
* @brief Context for cancelling long running operations.
|
||||
*/
|
||||
Azure::Core::Context Context;
|
||||
|
||||
/**
|
||||
* @brief When performing setAccessControlRecursive on a directory, the number of paths that
|
||||
* are processed with each invocation is limited. If the number of paths to be processed
|
||||
* 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 setAccessControlRecursive operation to continue the
|
||||
* setAccessControlRecursive operation on the directory.
|
||||
*/
|
||||
Azure::Core::Nullable<std::string> Continuation;
|
||||
|
||||
/**
|
||||
* @brief It specifies the maximum number of files or directories on which the acl change will
|
||||
* be applied. If omitted or greater than 2,000, the request will process up to 2,000
|
||||
* items.
|
||||
*/
|
||||
Azure::Core::Nullable<int32_t> MaxRecords;
|
||||
|
||||
/**
|
||||
* @brief Optional. Valid for "SetAccessControlRecursive" operation. If set to false, the
|
||||
* operation will terminate quickly on encountering user errors (4XX). If true, the operation
|
||||
* will ignore user errors and proceed with the operation on other sub-entities of the
|
||||
* directory. Continuation token will only be returned when forceFlag is true in case of user
|
||||
* errors. If not set the default value is false for this.
|
||||
*/
|
||||
Azure::Core::Nullable<bool> ForceFlag;
|
||||
};
|
||||
|
||||
using CreateFileOptions = CreatePathOptions;
|
||||
using CreateDirectoryOptions = CreatePathOptions;
|
||||
|
||||
|
||||
@ -183,7 +183,7 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
|
||||
Azure::Core::Nullable<std::string> Continuation;
|
||||
};
|
||||
|
||||
using DirectorySetAccessControlRecursiveInfo = PathSetAccessControlRecursiveResult;
|
||||
using SetDirectoryAccessControlRecursiveResult = PathSetAccessControlRecursiveResult;
|
||||
using CreateDirectoryResult = CreatePathResult;
|
||||
using DeleteDirectoryResult = PathDeleteResult;
|
||||
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
namespace Azure { namespace Storage { namespace Files { namespace DataLake {
|
||||
|
||||
namespace Details {
|
||||
constexpr static const char* c_DefaultServiceApiVersion = "2019-12-12";
|
||||
constexpr static const char* c_DefaultServiceApiVersion = "2020-02-10";
|
||||
constexpr static const char* c_PathDnsSuffixDefault = "dfs.core.windows.net";
|
||||
constexpr static const char* c_QueryFileSystemResource = "resource";
|
||||
constexpr static const char* c_QueryTimeout = "timeout";
|
||||
@ -31,6 +31,7 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
|
||||
constexpr static const char* c_QueryRecursiveRequired = "recursive";
|
||||
constexpr static const char* c_QueryContinuation = "continuation";
|
||||
constexpr static const char* c_QueryPathSetAccessControlRecursiveMode = "mode";
|
||||
constexpr static const char* c_QueryForceFlag = "forceflag";
|
||||
constexpr static const char* c_QueryDirectory = "directory";
|
||||
constexpr static const char* c_QueryPrefix = "prefix";
|
||||
constexpr static const char* c_QueryMaxResults = "maxresults";
|
||||
@ -45,6 +46,7 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
|
||||
constexpr static const char* c_QueryMaxRecords = "maxrecords";
|
||||
constexpr static const char* c_QueryPathGetPropertiesAction = "action";
|
||||
constexpr static const char* c_QueryAction = "action";
|
||||
constexpr static const char* c_QueryComp = "comp";
|
||||
constexpr static const char* c_HeaderApiVersionParameter = "x-ms-version";
|
||||
constexpr static const char* c_HeaderClientRequestId = "x-ms-client-request-id";
|
||||
constexpr static const char* c_HeaderIfMatch = "if-match";
|
||||
@ -68,6 +70,7 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
|
||||
constexpr static const char* c_HeaderContentType = "x-ms-content-type";
|
||||
constexpr static const char* c_HeaderTransactionalContentMd5 = "content-md5";
|
||||
constexpr static const char* c_HeaderContentMd5 = "x-ms-content-md5";
|
||||
constexpr static const char* c_HeaderContentCrc64 = "x-ms-content-crc64";
|
||||
constexpr static const char* c_HeaderUmask = "x-ms-umask";
|
||||
constexpr static const char* c_HeaderPermissions = "x-ms-permissions";
|
||||
constexpr static const char* c_HeaderRenameSource = "x-ms-rename-source";
|
||||
@ -75,6 +78,8 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
|
||||
constexpr static const char* c_HeaderGroup = "x-ms-group";
|
||||
constexpr static const char* c_HeaderAcl = "x-ms-acl";
|
||||
constexpr static const char* c_HeaderContentLength = "content-length";
|
||||
constexpr static const char* c_HeaderPathExpiryOptions = "x-ms-expiry-option";
|
||||
constexpr static const char* c_HeaderPathExpiryTime = "x-ms-expiry-time";
|
||||
constexpr static const char* c_HeaderDate = "date";
|
||||
constexpr static const char* c_HeaderXMsRequestId = "x-ms-request-id";
|
||||
constexpr static const char* c_HeaderXMsClientRequestId = "x-ms-client-request-id";
|
||||
@ -103,6 +108,9 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
|
||||
constexpr static const char* c_HeaderXMsGroup = "x-ms-group";
|
||||
constexpr static const char* c_HeaderXMsPermissions = "x-ms-permissions";
|
||||
constexpr static const char* c_HeaderXMsAcl = "x-ms-acl";
|
||||
constexpr static const char* c_HeaderXMsContentCrc64 = "x-ms-content-crc64";
|
||||
constexpr static const char* c_HeaderXMsRequestServerEncrypted
|
||||
= "x-ms-request-server-encrypted";
|
||||
} // namespace Details
|
||||
struct DataLakeHttpHeaders
|
||||
{
|
||||
@ -159,6 +167,54 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
|
||||
+ " to PathSetAccessControlRecursiveMode");
|
||||
}
|
||||
|
||||
// Required. Indicates mode of the expiry time
|
||||
enum class PathExpiryOptions
|
||||
{
|
||||
NeverExpire,
|
||||
RelativeToCreation,
|
||||
RelativeToNow,
|
||||
Absolute,
|
||||
Unknown
|
||||
};
|
||||
|
||||
inline std::string PathExpiryOptionsToString(const PathExpiryOptions& pathExpiryOptions)
|
||||
{
|
||||
switch (pathExpiryOptions)
|
||||
{
|
||||
case PathExpiryOptions::NeverExpire:
|
||||
return "NeverExpire";
|
||||
case PathExpiryOptions::RelativeToCreation:
|
||||
return "RelativeToCreation";
|
||||
case PathExpiryOptions::RelativeToNow:
|
||||
return "RelativeToNow";
|
||||
case PathExpiryOptions::Absolute:
|
||||
return "Absolute";
|
||||
default:
|
||||
return std::string();
|
||||
}
|
||||
}
|
||||
|
||||
inline PathExpiryOptions PathExpiryOptionsFromString(const std::string& pathExpiryOptions)
|
||||
{
|
||||
if (pathExpiryOptions == "NeverExpire")
|
||||
{
|
||||
return PathExpiryOptions::NeverExpire;
|
||||
}
|
||||
if (pathExpiryOptions == "RelativeToCreation")
|
||||
{
|
||||
return PathExpiryOptions::RelativeToCreation;
|
||||
}
|
||||
if (pathExpiryOptions == "RelativeToNow")
|
||||
{
|
||||
return PathExpiryOptions::RelativeToNow;
|
||||
}
|
||||
if (pathExpiryOptions == "Absolute")
|
||||
{
|
||||
return PathExpiryOptions::Absolute;
|
||||
}
|
||||
throw std::runtime_error("Cannot convert " + pathExpiryOptions + " to PathExpiryOptions");
|
||||
}
|
||||
|
||||
struct AclFailedEntry
|
||||
{
|
||||
std::string Name;
|
||||
@ -185,9 +241,9 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
|
||||
static SetAccessControlRecursiveResponse CreateFromJson(const nlohmann::json& node)
|
||||
{
|
||||
SetAccessControlRecursiveResponse result;
|
||||
result.DirectoriesSuccessful = std::stoi(node["directoriesSuccessful"].get<std::string>());
|
||||
result.FilesSuccessful = std::stoi(node["filesSuccessful"].get<std::string>());
|
||||
result.FailureCount = std::stoi(node["failureCount"].get<std::string>());
|
||||
result.DirectoriesSuccessful = node["directoriesSuccessful"].get<int32_t>();
|
||||
result.FilesSuccessful = node["filesSuccessful"].get<int32_t>();
|
||||
result.FailureCount = node["failureCount"].get<int32_t>();
|
||||
for (const auto& element : node["failedEntries"])
|
||||
{
|
||||
result.FailedEntries.emplace_back(AclFailedEntry::CreateFromJson(element));
|
||||
@ -481,7 +537,7 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
|
||||
throw std::runtime_error("Cannot convert " + pathLeaseAction + " to PathLeaseAction");
|
||||
}
|
||||
|
||||
// Lease state of the blob.
|
||||
// Lease state of the resource.
|
||||
enum class LeaseStateType
|
||||
{
|
||||
Available,
|
||||
@ -536,7 +592,7 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
|
||||
throw std::runtime_error("Cannot convert " + leaseStateType + " to LeaseStateType");
|
||||
}
|
||||
|
||||
// The current lease status of the blob.
|
||||
// The lease status of the resource.
|
||||
enum class LeaseStatusType
|
||||
{
|
||||
Locked,
|
||||
@ -652,6 +708,8 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
|
||||
|
||||
struct FileSystemListPathsResult
|
||||
{
|
||||
Azure::Core::Nullable<std::string> ETag;
|
||||
Azure::Core::Nullable<std::string> LastModified;
|
||||
Azure::Core::Nullable<std::string> Continuation;
|
||||
std::vector<Path> Paths;
|
||||
|
||||
@ -674,8 +732,8 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
|
||||
|
||||
struct PathUpdateResult
|
||||
{
|
||||
std::string ETag;
|
||||
std::string LastModified;
|
||||
Azure::Core::Nullable<std::string> ETag;
|
||||
Azure::Core::Nullable<std::string> LastModified;
|
||||
Azure::Core::Nullable<std::string> AcceptRanges;
|
||||
DataLakeHttpHeaders HttpHeaders;
|
||||
int64_t ContentLength = int64_t();
|
||||
@ -789,6 +847,16 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
|
||||
|
||||
struct PathAppendDataResult
|
||||
{
|
||||
Azure::Core::Nullable<std::string> ETag;
|
||||
Azure::Core::Nullable<std::string> ContentMD5;
|
||||
Azure::Core::Nullable<std::string> XMsContentCrc64;
|
||||
bool IsServerEncrypted = bool();
|
||||
};
|
||||
|
||||
struct PathSetExpiryResult
|
||||
{
|
||||
std::string ETag;
|
||||
std::string LastModified;
|
||||
};
|
||||
|
||||
class DataLakeRestClient {
|
||||
@ -1290,6 +1358,15 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
|
||||
? FileSystemListPathsResult()
|
||||
: FileSystemListPathsResult::FileSystemListPathsResultFromPathList(
|
||||
PathList::CreateFromJson(nlohmann::json::parse(bodyBuffer)));
|
||||
if (response.GetHeaders().find(Details::c_HeaderETag) != response.GetHeaders().end())
|
||||
{
|
||||
result.ETag = response.GetHeaders().at(Details::c_HeaderETag);
|
||||
}
|
||||
if (response.GetHeaders().find(Details::c_HeaderLastModified)
|
||||
!= response.GetHeaders().end())
|
||||
{
|
||||
result.LastModified = response.GetHeaders().at(Details::c_HeaderLastModified);
|
||||
}
|
||||
if (response.GetHeaders().find(Details::c_HeaderXMsContinuation)
|
||||
!= response.GetHeaders().end())
|
||||
{
|
||||
@ -1361,7 +1438,7 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
|
||||
// active and matches this ID.
|
||||
Azure::Core::Nullable<std::string>
|
||||
SourceLeaseId; // A lease ID for the source path. If specified, the source path must
|
||||
// have an active lease and the leaase ID must match.
|
||||
// have an active lease and the lease ID must match.
|
||||
Azure::Core::Nullable<std::string>
|
||||
Properties; // Optional. User-defined properties to be stored with the filesystem, in
|
||||
// the format of a comma-separated list of name and value pairs "n1=v1,
|
||||
@ -1576,6 +1653,13 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
|
||||
// modifies one or more POSIX access control rights that pre-exist on files and
|
||||
// directories, "remove" removes one or more POSIX access control rights that
|
||||
// were present earlier on files and directories
|
||||
Azure::Core::Nullable<bool>
|
||||
ForceFlag; // Optional. Valid for "SetAccessControlRecursive" operation. If set to
|
||||
// false, the operation will terminate quickly on encountering user errors
|
||||
// (4XX). If true, the operation will ignore user errors and proceed with the
|
||||
// operation on other sub-entities of the directory. Continuation token will
|
||||
// only be returned when forceFlag is true in case of user errors. If not set
|
||||
// the default value is false for this.
|
||||
Azure::Core::Nullable<int64_t>
|
||||
Position; // This parameter allows the caller to upload data in parallel and control the
|
||||
// order in which it is appended to the file. It is required when uploading
|
||||
@ -1701,6 +1785,11 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
|
||||
request.GetUrl().AppendQuery(
|
||||
Details::c_QueryPathSetAccessControlRecursiveMode,
|
||||
PathSetAccessControlRecursiveModeToString(updateOptions.Mode));
|
||||
if (updateOptions.ForceFlag.HasValue())
|
||||
{
|
||||
request.GetUrl().AppendQuery(
|
||||
Details::c_QueryForceFlag, (updateOptions.ForceFlag.GetValue() ? "true" : "false"));
|
||||
}
|
||||
if (updateOptions.Position.HasValue())
|
||||
{
|
||||
request.GetUrl().AppendQuery(
|
||||
@ -2324,6 +2413,13 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
|
||||
// modifies one or more POSIX access control rights that pre-exist on files and
|
||||
// directories, "remove" removes one or more POSIX access control rights that
|
||||
// were present earlier on files and directories
|
||||
Azure::Core::Nullable<bool>
|
||||
ForceFlag; // Optional. Valid for "SetAccessControlRecursive" operation. If set to
|
||||
// false, the operation will terminate quickly on encountering user errors
|
||||
// (4XX). If true, the operation will ignore user errors and proceed with the
|
||||
// operation on other sub-entities of the directory. Continuation token will
|
||||
// only be returned when forceFlag is true in case of user errors. If not set
|
||||
// the default value is false for this.
|
||||
Azure::Core::Nullable<int32_t>
|
||||
MaxRecords; // Optional. It specifies the maximum number of files or directories on
|
||||
// which the acl change will be applied. If omitted or greater than 2,000,
|
||||
@ -2365,6 +2461,12 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
|
||||
request.GetUrl().AppendQuery(
|
||||
Details::c_QueryPathSetAccessControlRecursiveMode,
|
||||
PathSetAccessControlRecursiveModeToString(setAccessControlRecursiveOptions.Mode));
|
||||
if (setAccessControlRecursiveOptions.ForceFlag.HasValue())
|
||||
{
|
||||
request.GetUrl().AppendQuery(
|
||||
Details::c_QueryForceFlag,
|
||||
(setAccessControlRecursiveOptions.ForceFlag.GetValue() ? "true" : "false"));
|
||||
}
|
||||
if (setAccessControlRecursiveOptions.MaxRecords.HasValue())
|
||||
{
|
||||
request.GetUrl().AppendQuery(
|
||||
@ -2585,6 +2687,8 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
|
||||
Azure::Core::Nullable<std::string>
|
||||
TransactionalContentMd5; // Specify the transactional md5 for the body, to be validated
|
||||
// by the service.
|
||||
Azure::Core::Nullable<std::string> ContentCrc64; // Specify the transactional crc64 for the
|
||||
// body, to be validated by the service.
|
||||
Azure::Core::Nullable<std::string>
|
||||
LeaseIdOptional; // If specified, the operation only succeeds if the resource's lease is
|
||||
// active and matches this ID.
|
||||
@ -2629,6 +2733,11 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
|
||||
Details::c_HeaderTransactionalContentMd5,
|
||||
appendDataOptions.TransactionalContentMd5.GetValue());
|
||||
}
|
||||
if (appendDataOptions.ContentCrc64.HasValue())
|
||||
{
|
||||
request.AddHeader(
|
||||
Details::c_HeaderContentCrc64, appendDataOptions.ContentCrc64.GetValue());
|
||||
}
|
||||
if (appendDataOptions.LeaseIdOptional.HasValue())
|
||||
{
|
||||
request.AddHeader(
|
||||
@ -2644,6 +2753,55 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
|
||||
return AppendDataParseResult(context, pipeline.Send(context, request));
|
||||
}
|
||||
|
||||
struct SetExpiryOptions
|
||||
{
|
||||
Azure::Core::Nullable<int32_t>
|
||||
Timeout; // The timeout parameter is expressed in seconds. For more information, see <a
|
||||
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
|
||||
// Timeouts for Blob Service Operations.</a>
|
||||
std::string ApiVersionParameter
|
||||
= Details::c_DefaultServiceApiVersion; // Specifies the version of the operation to use
|
||||
// for this request.
|
||||
Azure::Core::Nullable<std::string>
|
||||
ClientRequestId; // Provides a client-generated, opaque value with a 1 KB character
|
||||
// limit that is recorded in the analytics logs when storage analytics
|
||||
// logging is enabled.
|
||||
PathExpiryOptions XMsExpiryOption; // Required. Indicates mode of the expiry time
|
||||
Azure::Core::Nullable<std::string> PathExpiryTime; // The time to set the blob to expiry
|
||||
};
|
||||
|
||||
static Azure::Core::Response<PathSetExpiryResult> SetExpiry(
|
||||
const Azure::Core::Http::Url& url,
|
||||
Azure::Core::Http::HttpPipeline& pipeline,
|
||||
const Azure::Core::Context& context,
|
||||
const SetExpiryOptions& setExpiryOptions)
|
||||
{
|
||||
Azure::Core::Http::Request request(Azure::Core::Http::HttpMethod::Put, url);
|
||||
request.AddHeader(Details::c_HeaderContentLength, "0");
|
||||
request.GetUrl().AppendQuery(Details::c_QueryComp, "expiry");
|
||||
if (setExpiryOptions.Timeout.HasValue())
|
||||
{
|
||||
request.GetUrl().AppendQuery(
|
||||
Details::c_QueryTimeout, std::to_string(setExpiryOptions.Timeout.GetValue()));
|
||||
}
|
||||
request.AddHeader(
|
||||
Details::c_HeaderApiVersionParameter, setExpiryOptions.ApiVersionParameter);
|
||||
if (setExpiryOptions.ClientRequestId.HasValue())
|
||||
{
|
||||
request.AddHeader(
|
||||
Details::c_HeaderClientRequestId, setExpiryOptions.ClientRequestId.GetValue());
|
||||
}
|
||||
request.AddHeader(
|
||||
Details::c_HeaderPathExpiryOptions,
|
||||
PathExpiryOptionsToString(setExpiryOptions.XMsExpiryOption));
|
||||
if (setExpiryOptions.PathExpiryTime.HasValue())
|
||||
{
|
||||
request.AddHeader(
|
||||
Details::c_HeaderPathExpiryTime, setExpiryOptions.PathExpiryTime.GetValue());
|
||||
}
|
||||
return SetExpiryParseResult(context, pipeline.Send(context, request));
|
||||
}
|
||||
|
||||
private:
|
||||
static Azure::Core::Response<PathCreateResult> CreateParseResult(
|
||||
const Azure::Core::Context& context,
|
||||
@ -2698,8 +2856,15 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
|
||||
: PathUpdateResult::PathUpdateResultFromSetAccessControlRecursiveResponse(
|
||||
SetAccessControlRecursiveResponse::CreateFromJson(
|
||||
nlohmann::json::parse(bodyBuffer)));
|
||||
result.ETag = response.GetHeaders().at(Details::c_HeaderETag);
|
||||
result.LastModified = response.GetHeaders().at(Details::c_HeaderLastModified);
|
||||
if (response.GetHeaders().find(Details::c_HeaderETag) != response.GetHeaders().end())
|
||||
{
|
||||
result.ETag = response.GetHeaders().at(Details::c_HeaderETag);
|
||||
}
|
||||
if (response.GetHeaders().find(Details::c_HeaderLastModified)
|
||||
!= response.GetHeaders().end())
|
||||
{
|
||||
result.LastModified = response.GetHeaders().at(Details::c_HeaderLastModified);
|
||||
}
|
||||
if (response.GetHeaders().find(Details::c_HeaderAcceptRanges)
|
||||
!= response.GetHeaders().end())
|
||||
{
|
||||
@ -3182,6 +3347,22 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
|
||||
{
|
||||
// Append data to file control response.
|
||||
PathAppendDataResult result;
|
||||
if (response.GetHeaders().find(Details::c_HeaderETag) != response.GetHeaders().end())
|
||||
{
|
||||
result.ETag = response.GetHeaders().at(Details::c_HeaderETag);
|
||||
}
|
||||
if (response.GetHeaders().find(Details::c_HeaderContentMD5)
|
||||
!= response.GetHeaders().end())
|
||||
{
|
||||
result.ContentMD5 = response.GetHeaders().at(Details::c_HeaderContentMD5);
|
||||
}
|
||||
if (response.GetHeaders().find(Details::c_HeaderXMsContentCrc64)
|
||||
!= response.GetHeaders().end())
|
||||
{
|
||||
result.XMsContentCrc64 = response.GetHeaders().at(Details::c_HeaderXMsContentCrc64);
|
||||
}
|
||||
result.IsServerEncrypted
|
||||
= response.GetHeaders().at(Details::c_HeaderXMsRequestServerEncrypted) == "true";
|
||||
return Azure::Core::Response<PathAppendDataResult>(
|
||||
std::move(result), std::move(responsePtr));
|
||||
}
|
||||
@ -3191,6 +3372,27 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
|
||||
throw Azure::Storage::StorageError::CreateFromResponse(std::move(responsePtr));
|
||||
}
|
||||
}
|
||||
|
||||
static Azure::Core::Response<PathSetExpiryResult> SetExpiryParseResult(
|
||||
const Azure::Core::Context& context,
|
||||
std::unique_ptr<Azure::Core::Http::RawResponse> responsePtr)
|
||||
{
|
||||
/* const */ auto& response = *responsePtr;
|
||||
if (response.GetStatusCode() == Azure::Core::Http::HttpStatusCode::Ok)
|
||||
{
|
||||
// The blob expiry was set successfully.
|
||||
PathSetExpiryResult result;
|
||||
result.ETag = response.GetHeaders().at(Details::c_HeaderETag);
|
||||
result.LastModified = response.GetHeaders().at(Details::c_HeaderLastModified);
|
||||
return Azure::Core::Response<PathSetExpiryResult>(
|
||||
std::move(result), std::move(responsePtr));
|
||||
}
|
||||
else
|
||||
{
|
||||
unused(context);
|
||||
throw Azure::Storage::StorageError::CreateFromResponse(std::move(responsePtr));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}; // class DataLakeRestClient
|
||||
|
||||
@ -196,4 +196,21 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
|
||||
return DataLakeRestClient::Path::Delete(
|
||||
m_dfsUri, *m_pipeline, options.Context, protocolLayerOptions);
|
||||
}
|
||||
|
||||
Azure::Core::Response<SetDirectoryAccessControlRecursiveResult>
|
||||
DirectoryClient::SetAccessControlRecursive(
|
||||
PathSetAccessControlRecursiveMode mode,
|
||||
std::vector<Acl> acls,
|
||||
const SetDirectoryAccessControlRecursiveOptions& options) const
|
||||
{
|
||||
DataLakeRestClient::Path::SetAccessControlRecursiveOptions protocolLayerOptions;
|
||||
protocolLayerOptions.Mode = mode;
|
||||
protocolLayerOptions.Continuation = options.Continuation;
|
||||
protocolLayerOptions.MaxRecords = options.MaxRecords;
|
||||
protocolLayerOptions.ForceFlag = options.ForceFlag;
|
||||
protocolLayerOptions.Acl = Acl::SerializeAcls(acls);
|
||||
return DataLakeRestClient::Path::SetAccessControlRecursive(
|
||||
m_dfsUri, *m_pipeline, options.Context, protocolLayerOptions);
|
||||
}
|
||||
|
||||
}}}} // namespace Azure::Storage::Files::DataLake
|
||||
|
||||
@ -105,8 +105,8 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
|
||||
{
|
||||
auto parsedConnectionString = Azure::Storage::Details::ParseConnectionString(connectionString);
|
||||
auto fileUri = std::move(parsedConnectionString.DataLakeServiceUri);
|
||||
fileUri.AppendPath(fileSystemName, true);
|
||||
fileUri.AppendPath(filePath, true);
|
||||
fileUri.AppendPath(fileSystemName);
|
||||
fileUri.AppendPath(filePath);
|
||||
|
||||
if (parsedConnectionString.KeyCredential)
|
||||
{
|
||||
|
||||
@ -295,4 +295,42 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DataLakeDirectoryClientTest, DirectorySetAccessControlRecursive)
|
||||
{
|
||||
// Setup directories.
|
||||
auto rootDirectoryName = LowercaseRandomString();
|
||||
auto directoryName1 = LowercaseRandomString();
|
||||
auto directoryName2 = LowercaseRandomString();
|
||||
auto rootDirectoryClient = m_fileSystemClient->GetDirectoryClient(rootDirectoryName);
|
||||
rootDirectoryClient.Create();
|
||||
auto directoryClient1
|
||||
= m_fileSystemClient->GetDirectoryClient(rootDirectoryName + "/" + directoryName1);
|
||||
directoryClient1.Create();
|
||||
auto directoryClient2
|
||||
= m_fileSystemClient->GetDirectoryClient(rootDirectoryName + "/" + directoryName2);
|
||||
directoryClient2.Create();
|
||||
|
||||
{
|
||||
// Set/Get Acls recursive works.
|
||||
std::vector<Files::DataLake::Acl> acls = GetValidAcls();
|
||||
EXPECT_NO_THROW(directoryClient1.SetAccessControl(acls));
|
||||
EXPECT_NO_THROW(rootDirectoryClient.SetAccessControlRecursive(
|
||||
Files::DataLake::PathSetAccessControlRecursiveMode::Modify, acls));
|
||||
std::vector<Files::DataLake::Acl> resultAcls1;
|
||||
std::vector<Files::DataLake::Acl> resultAcls2;
|
||||
EXPECT_NO_THROW(resultAcls1 = directoryClient1.GetAccessControls()->Acls);
|
||||
EXPECT_NO_THROW(resultAcls2 = directoryClient2.GetAccessControls()->Acls);
|
||||
for (const auto& acl : resultAcls2)
|
||||
{
|
||||
auto iter = std::find_if(
|
||||
resultAcls1.begin(), resultAcls1.end(), [&acl](const Files::DataLake::Acl& targetAcl) {
|
||||
return (targetAcl.Type == acl.Type) && (targetAcl.Id == acl.Id)
|
||||
&& (targetAcl.Scope == acl.Scope);
|
||||
});
|
||||
EXPECT_TRUE(iter != resultAcls1.end());
|
||||
EXPECT_EQ(iter->Permissions, acl.Permissions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}}} // namespace Azure::Storage::Test
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -218,6 +218,65 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
|
||||
const ListFilesAndDirectoriesSegmentOptions& options
|
||||
= ListFilesAndDirectoriesSegmentOptions()) const;
|
||||
|
||||
/**
|
||||
* @brief Acquires a lease on the share.
|
||||
*
|
||||
* @param proposedLeaseId Proposed lease ID, in a GUID string format.
|
||||
* @param duration Specifies the duration of the lease, in seconds, or
|
||||
* Azure::Storage::c_InfiniteLeaseDuration for a lease that never expires. A non-infinite lease
|
||||
* can be between 15 and 60 seconds. A lease duration cannot be changed using renew or change.
|
||||
* @param options Optional parameters to execute this function.
|
||||
* @return Azure::Core::Response<AcquireShareLeaseResult> describing the lease.
|
||||
*/
|
||||
Azure::Core::Response<AcquireShareLeaseResult> AcquireLease(
|
||||
const std::string& proposedLeaseId,
|
||||
int32_t duration,
|
||||
const AcquireShareLeaseOptions& options = AcquireShareLeaseOptions()) const;
|
||||
|
||||
/**
|
||||
* @brief Releases the share's previously-acquired lease.
|
||||
*
|
||||
* @param leaseId ID of the previously-acquired lease.
|
||||
* @param options Optional parameters to execute this function.
|
||||
* @return Azure::Core::Response<ReleaseShareLeaseResult> describing the updated lease status.
|
||||
*/
|
||||
Azure::Core::Response<ReleaseShareLeaseResult> ReleaseLease(
|
||||
const std::string& leaseId,
|
||||
const ReleaseShareLeaseOptions& options = ReleaseShareLeaseOptions()) const;
|
||||
|
||||
/**
|
||||
* @brief Changes the lease of an active lease.
|
||||
*
|
||||
* @param leaseId ID of the previously-acquired lease.
|
||||
* @param proposedLeaseId Proposed lease ID, in a GUID string format.
|
||||
* @param options Optional parameters to execute this function.
|
||||
* @return Azure::Core::Response<ChangeShareLeaseResult> describing the changed lease.
|
||||
*/
|
||||
Azure::Core::Response<ChangeShareLeaseResult> ChangeLease(
|
||||
const std::string& leaseId,
|
||||
const std::string& proposedLeaseId,
|
||||
const ChangeShareLeaseOptions& options = ChangeShareLeaseOptions()) const;
|
||||
|
||||
/**
|
||||
* @brief Breaks the previously-acquired lease.
|
||||
*
|
||||
* @param options Optional parameters to execute this function.
|
||||
* @return Azure::Core::Response<BreakShareLeaseResult> describing the broken lease.
|
||||
*/
|
||||
Azure::Core::Response<BreakShareLeaseResult> BreakLease(
|
||||
const BreakShareLeaseOptions& options = BreakShareLeaseOptions()) const;
|
||||
|
||||
/**
|
||||
* @brief Renew the previously-acquired lease.
|
||||
*
|
||||
* @param leaseId ID of the previously-acquired lease.
|
||||
* @param options Optional parameters to execute this function.
|
||||
* @return Azure::Core::Response<BreakShareLeaseResult> describing the renewed lease.
|
||||
*/
|
||||
Azure::Core::Response<RenewShareLeaseResult> RenewLease(
|
||||
const std::string& leaseId,
|
||||
const RenewShareLeaseOptions& options = RenewShareLeaseOptions()) const;
|
||||
|
||||
private:
|
||||
Azure::Core::Http::Url m_shareUri;
|
||||
std::shared_ptr<Azure::Core::Http::HttpPipeline> m_pipeline;
|
||||
|
||||
@ -209,6 +209,70 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
|
||||
Azure::Core::Context Context;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Optional parameters for ShareClient::AcquireLease.
|
||||
*/
|
||||
struct AcquireShareLeaseOptions
|
||||
{
|
||||
/**
|
||||
* @brief Context for cancelling long running operations.
|
||||
*/
|
||||
Azure::Core::Context Context;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Optional parameters for ShareClient::ChangeLease.
|
||||
*/
|
||||
struct ChangeShareLeaseOptions
|
||||
{
|
||||
/**
|
||||
* @brief Context for cancelling long running operations.
|
||||
*/
|
||||
Azure::Core::Context Context;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Optional parameters for ShareClient::ReleaseLease.
|
||||
*/
|
||||
struct ReleaseShareLeaseOptions
|
||||
{
|
||||
/**
|
||||
* @brief Context for cancelling long running operations.
|
||||
*/
|
||||
Azure::Core::Context Context;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Optional parameters for ShareClient::BreakLease.
|
||||
*/
|
||||
struct BreakShareLeaseOptions
|
||||
{
|
||||
/**
|
||||
* @brief Context for cancelling long running operations.
|
||||
*/
|
||||
Azure::Core::Context Context;
|
||||
|
||||
/**
|
||||
* @brief Proposed duration the lease should continue before it is broken, in seconds,
|
||||
* between 0 and 60. This break period is only used if it is shorter than the time remaining on
|
||||
* the lease. If longer, the time remaining on the lease is used. A new lease will not be
|
||||
* available before the break period has expired, but the lease may be held for longer than the
|
||||
* break period.
|
||||
*/
|
||||
Azure::Core::Nullable<int32_t> BreakPeriod;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Optional parameters for ShareClient::BreakLease.
|
||||
*/
|
||||
struct RenewShareLeaseOptions
|
||||
{
|
||||
/**
|
||||
* @brief Context for cancelling long running operations.
|
||||
*/
|
||||
Azure::Core::Context Context;
|
||||
};
|
||||
|
||||
struct CreateDirectoryOptions
|
||||
{
|
||||
/**
|
||||
@ -640,6 +704,12 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
|
||||
*/
|
||||
Azure::Core::Nullable<int64_t> Length;
|
||||
|
||||
/**
|
||||
* @brief The previous snapshot parameter is an opaque DateTime value that, when present,
|
||||
* specifies the previous snapshot.
|
||||
*/
|
||||
Azure::Core::Nullable<std::string> PrevShareSnapshot;
|
||||
|
||||
/**
|
||||
* @brief The operation will only succeed if the access condition is met.
|
||||
*/
|
||||
|
||||
@ -27,6 +27,11 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
|
||||
using CreateSharePermissionResult = ShareCreatePermissionResult;
|
||||
using GetShareAccessPolicyResult = ShareGetAccessPolicyResult;
|
||||
using GetSharePermissionResult = ShareGetPermissionResult;
|
||||
using AcquireShareLeaseResult = ShareAcquireLeaseResult;
|
||||
using RenewShareLeaseResult = ShareRenewLeaseResult;
|
||||
using ReleaseShareLeaseResult = ShareReleaseLeaseResult;
|
||||
using BreakShareLeaseResult = ShareBreakLeaseResult;
|
||||
using ChangeShareLeaseResult = ShareChangeLeaseResult;
|
||||
|
||||
// DirectoryClient models:
|
||||
using CreateDirectoryResult = DirectoryCreateResult;
|
||||
|
||||
@ -274,4 +274,57 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
|
||||
std::move(ret), result.ExtractRawResponse());
|
||||
}
|
||||
|
||||
Azure::Core::Response<AcquireShareLeaseResult> ShareClient::AcquireLease(
|
||||
const std::string& proposedLeaseId,
|
||||
int32_t duration,
|
||||
const AcquireShareLeaseOptions& options) const
|
||||
{
|
||||
ShareRestClient::Share::AcquireLeaseOptions protocolLayerOptions;
|
||||
protocolLayerOptions.ProposedLeaseIdOptional = proposedLeaseId;
|
||||
protocolLayerOptions.LeaseDuration = duration;
|
||||
return ShareRestClient::Share::AcquireLease(
|
||||
m_shareUri, *m_pipeline, options.Context, protocolLayerOptions);
|
||||
}
|
||||
|
||||
Azure::Core::Response<ChangeShareLeaseResult> ShareClient::ChangeLease(
|
||||
const std::string& leaseId,
|
||||
const std::string& proposedLeaseId,
|
||||
const ChangeShareLeaseOptions& options) const
|
||||
{
|
||||
ShareRestClient::Share::ChangeLeaseOptions protocolLayerOptions;
|
||||
protocolLayerOptions.LeaseIdRequired = leaseId;
|
||||
protocolLayerOptions.ProposedLeaseIdOptional = proposedLeaseId;
|
||||
return ShareRestClient::Share::ChangeLease(
|
||||
m_shareUri, *m_pipeline, options.Context, protocolLayerOptions);
|
||||
}
|
||||
|
||||
Azure::Core::Response<ReleaseShareLeaseResult> ShareClient::ReleaseLease(
|
||||
const std::string& leaseId,
|
||||
const ReleaseShareLeaseOptions& options) const
|
||||
{
|
||||
ShareRestClient::Share::ReleaseLeaseOptions protocolLayerOptions;
|
||||
protocolLayerOptions.LeaseIdRequired = leaseId;
|
||||
return ShareRestClient::Share::ReleaseLease(
|
||||
m_shareUri, *m_pipeline, options.Context, protocolLayerOptions);
|
||||
}
|
||||
|
||||
Azure::Core::Response<BreakShareLeaseResult> ShareClient::BreakLease(
|
||||
const BreakShareLeaseOptions& options) const
|
||||
{
|
||||
ShareRestClient::Share::BreakLeaseOptions protocolLayerOptions;
|
||||
protocolLayerOptions.LeaseBreakPeriod = options.BreakPeriod;
|
||||
return ShareRestClient::Share::BreakLease(
|
||||
m_shareUri, *m_pipeline, options.Context, protocolLayerOptions);
|
||||
}
|
||||
|
||||
Azure::Core::Response<RenewShareLeaseResult> ShareClient::RenewLease(
|
||||
const std::string& leaseId,
|
||||
const RenewShareLeaseOptions& options) const
|
||||
{
|
||||
ShareRestClient::Share::RenewLeaseOptions protocolLayerOptions;
|
||||
protocolLayerOptions.LeaseIdRequired = leaseId;
|
||||
return ShareRestClient::Share::RenewLease(
|
||||
m_shareUri, *m_pipeline, options.Context, protocolLayerOptions);
|
||||
}
|
||||
|
||||
}}}} // namespace Azure::Storage::Files::Shares
|
||||
|
||||
@ -476,6 +476,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
|
||||
}
|
||||
}
|
||||
|
||||
protocolLayerOptions.PrevShareSnapshot = options.PrevShareSnapshot;
|
||||
protocolLayerOptions.LeaseIdOptional = options.AccessConditions.LeaseId;
|
||||
return ShareRestClient::File::GetRangeList(
|
||||
m_shareFileUri, *m_pipeline, options.Context, protocolLayerOptions);
|
||||
|
||||
@ -31,7 +31,12 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
m_shareClient->Create();
|
||||
}
|
||||
|
||||
void FileShareClientTest::TearDownTestSuite() { m_shareClient->Delete(); }
|
||||
void FileShareClientTest::TearDownTestSuite()
|
||||
{
|
||||
auto deleteOptions = Files::Shares::DeleteShareOptions();
|
||||
deleteOptions.IncludeSnapshots = true;
|
||||
m_shareClient->Delete(deleteOptions);
|
||||
}
|
||||
|
||||
Files::Shares::FileShareHttpHeaders FileShareClientTest::GetInterestingHttpHeaders()
|
||||
{
|
||||
@ -182,4 +187,115 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
auto ret2 = m_shareClient->GetPermission(ret->FilePermissionKey);
|
||||
EXPECT_EQ(expectedPermission, ret2->Permission);
|
||||
}
|
||||
|
||||
TEST_F(FileShareClientTest, Lease)
|
||||
{
|
||||
std::string leaseId1 = CreateUniqueLeaseId();
|
||||
int32_t leaseDuration = 20;
|
||||
auto aLease = *m_shareClient->AcquireLease(leaseId1, leaseDuration);
|
||||
EXPECT_FALSE(aLease.ETag.empty());
|
||||
EXPECT_FALSE(aLease.LastModified.empty());
|
||||
EXPECT_EQ(aLease.LeaseId, leaseId1);
|
||||
aLease = *m_shareClient->AcquireLease(leaseId1, leaseDuration);
|
||||
EXPECT_FALSE(aLease.ETag.empty());
|
||||
EXPECT_FALSE(aLease.LastModified.empty());
|
||||
EXPECT_EQ(aLease.LeaseId, leaseId1);
|
||||
|
||||
auto properties = *m_shareClient->GetProperties();
|
||||
EXPECT_EQ(properties.LeaseState.GetValue(), Files::Shares::LeaseStateType::Leased);
|
||||
EXPECT_EQ(properties.LeaseStatus.GetValue(), Files::Shares::LeaseStatusType::Locked);
|
||||
EXPECT_EQ(Files::Shares::LeaseDurationType::Fixed, properties.LeaseDuration.GetValue());
|
||||
|
||||
auto rLease = *m_shareClient->RenewLease(leaseId1);
|
||||
EXPECT_FALSE(rLease.ETag.empty());
|
||||
EXPECT_FALSE(rLease.LastModified.empty());
|
||||
EXPECT_EQ(rLease.LeaseId, leaseId1);
|
||||
|
||||
std::string leaseId2 = CreateUniqueLeaseId();
|
||||
EXPECT_NE(leaseId1, leaseId2);
|
||||
auto cLease = *m_shareClient->ChangeLease(leaseId1, leaseId2);
|
||||
EXPECT_FALSE(cLease.ETag.empty());
|
||||
EXPECT_FALSE(cLease.LastModified.empty());
|
||||
EXPECT_EQ(cLease.LeaseId, leaseId2);
|
||||
|
||||
auto blobInfo = *m_shareClient->ReleaseLease(leaseId2);
|
||||
EXPECT_FALSE(blobInfo.ETag.empty());
|
||||
EXPECT_FALSE(blobInfo.LastModified.empty());
|
||||
|
||||
aLease = *m_shareClient->AcquireLease(CreateUniqueLeaseId(), c_InfiniteLeaseDuration);
|
||||
properties = *m_shareClient->GetProperties();
|
||||
EXPECT_EQ(Files::Shares::LeaseDurationType::Infinite, properties.LeaseDuration.GetValue());
|
||||
auto brokenLease = *m_shareClient->BreakLease();
|
||||
EXPECT_FALSE(brokenLease.ETag.empty());
|
||||
EXPECT_FALSE(brokenLease.LastModified.empty());
|
||||
EXPECT_EQ(brokenLease.LeaseTime, 0);
|
||||
|
||||
aLease = *m_shareClient->AcquireLease(CreateUniqueLeaseId(), leaseDuration);
|
||||
brokenLease = *m_shareClient->BreakLease();
|
||||
EXPECT_FALSE(brokenLease.ETag.empty());
|
||||
EXPECT_FALSE(brokenLease.LastModified.empty());
|
||||
EXPECT_NE(brokenLease.LeaseTime, 0);
|
||||
|
||||
Files::Shares::BreakShareLeaseOptions options;
|
||||
options.BreakPeriod = 0;
|
||||
m_shareClient->BreakLease(options);
|
||||
}
|
||||
|
||||
TEST_F(FileShareClientTest, SnapshotLease)
|
||||
{
|
||||
std::string leaseId1 = CreateUniqueLeaseId();
|
||||
int32_t leaseDuration = 20;
|
||||
auto snapshotResult = m_shareClient->CreateSnapshot();
|
||||
auto shareSnapshot = m_shareClient->WithSnapshot(snapshotResult->Snapshot);
|
||||
auto aLease = *shareSnapshot.AcquireLease(leaseId1, leaseDuration);
|
||||
EXPECT_FALSE(aLease.ETag.empty());
|
||||
EXPECT_FALSE(aLease.LastModified.empty());
|
||||
EXPECT_EQ(aLease.LeaseId, leaseId1);
|
||||
aLease = *shareSnapshot.AcquireLease(leaseId1, leaseDuration);
|
||||
EXPECT_FALSE(aLease.ETag.empty());
|
||||
EXPECT_FALSE(aLease.LastModified.empty());
|
||||
EXPECT_EQ(aLease.LeaseId, leaseId1);
|
||||
|
||||
auto properties = *shareSnapshot.GetProperties();
|
||||
EXPECT_EQ(properties.LeaseState.GetValue(), Files::Shares::LeaseStateType::Leased);
|
||||
EXPECT_EQ(properties.LeaseStatus.GetValue(), Files::Shares::LeaseStatusType::Locked);
|
||||
EXPECT_EQ(Files::Shares::LeaseDurationType::Fixed, properties.LeaseDuration.GetValue());
|
||||
|
||||
auto rLease = *shareSnapshot.RenewLease(leaseId1);
|
||||
EXPECT_FALSE(rLease.ETag.empty());
|
||||
EXPECT_FALSE(rLease.LastModified.empty());
|
||||
EXPECT_EQ(rLease.LeaseId, leaseId1);
|
||||
|
||||
std::string leaseId2 = CreateUniqueLeaseId();
|
||||
EXPECT_NE(leaseId1, leaseId2);
|
||||
auto cLease = *shareSnapshot.ChangeLease(leaseId1, leaseId2);
|
||||
EXPECT_FALSE(cLease.ETag.empty());
|
||||
EXPECT_FALSE(cLease.LastModified.empty());
|
||||
EXPECT_EQ(cLease.LeaseId, leaseId2);
|
||||
|
||||
auto blobInfo = *shareSnapshot.ReleaseLease(leaseId2);
|
||||
EXPECT_FALSE(blobInfo.ETag.empty());
|
||||
EXPECT_FALSE(blobInfo.LastModified.empty());
|
||||
|
||||
aLease = *shareSnapshot.AcquireLease(CreateUniqueLeaseId(), c_InfiniteLeaseDuration);
|
||||
properties = *shareSnapshot.GetProperties();
|
||||
EXPECT_EQ(Files::Shares::LeaseDurationType::Infinite, properties.LeaseDuration.GetValue());
|
||||
auto brokenLease = *shareSnapshot.BreakLease();
|
||||
EXPECT_FALSE(brokenLease.ETag.empty());
|
||||
EXPECT_FALSE(brokenLease.LastModified.empty());
|
||||
EXPECT_EQ(brokenLease.LeaseTime, 0);
|
||||
|
||||
aLease = *shareSnapshot.AcquireLease(CreateUniqueLeaseId(), leaseDuration);
|
||||
brokenLease = *shareSnapshot.BreakLease();
|
||||
EXPECT_FALSE(brokenLease.ETag.empty());
|
||||
EXPECT_FALSE(brokenLease.LastModified.empty());
|
||||
EXPECT_NE(brokenLease.LeaseTime, 0);
|
||||
|
||||
Files::Shares::BreakShareLeaseOptions options;
|
||||
options.BreakPeriod = 0;
|
||||
shareSnapshot.BreakLease(options);
|
||||
|
||||
EXPECT_THROW(m_shareClient->Delete(), StorageError);
|
||||
}
|
||||
|
||||
}}} // namespace Azure::Storage::Test
|
||||
|
||||
@ -615,11 +615,51 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
EXPECT_NO_THROW(fileClient.ClearRange(512, 512));
|
||||
Files::Shares::GetFileRangeListResult result;
|
||||
EXPECT_NO_THROW(result = fileClient.GetRangeList().ExtractValue());
|
||||
EXPECT_EQ(2U, result.RangeList.size());
|
||||
result.RangeList[0].Start = 0;
|
||||
result.RangeList[0].End = 511;
|
||||
result.RangeList[1].Start = 1024;
|
||||
result.RangeList[1].End = fileSize / 2;
|
||||
EXPECT_EQ(2U, result.Ranges.size());
|
||||
EXPECT_EQ(0, result.Ranges[0].Start);
|
||||
EXPECT_EQ(511, result.Ranges[0].End);
|
||||
EXPECT_EQ(1024, result.Ranges[1].Start);
|
||||
EXPECT_EQ(static_cast<int32_t>(fileSize / 2) - 1, result.Ranges[1].End);
|
||||
}
|
||||
|
||||
TEST_F(FileShareFileClientTest, DISABLED_PreviousRangeWithSnapshot)
|
||||
{
|
||||
size_t fileSize = 1 * 1024 * 1024;
|
||||
auto fileContent = RandomBuffer(fileSize);
|
||||
auto memBodyStream = Core::Http::MemoryBodyStream(fileContent);
|
||||
auto halfContent
|
||||
= std::vector<uint8_t>(fileContent.begin(), fileContent.begin() + fileSize / 2);
|
||||
halfContent.resize(fileSize);
|
||||
auto fileClient = m_shareClient->GetFileClient(LowercaseRandomString(10));
|
||||
fileClient.Create(fileSize);
|
||||
EXPECT_NO_THROW(fileClient.UploadRange(0, &memBodyStream));
|
||||
EXPECT_NO_THROW(fileClient.ClearRange(fileSize / 2, fileSize / 2));
|
||||
std::vector<uint8_t> downloadContent(static_cast<std::size_t>(fileSize), '\x00');
|
||||
EXPECT_NO_THROW(
|
||||
fileClient.DownloadTo(downloadContent.data(), static_cast<std::size_t>(fileSize)));
|
||||
EXPECT_EQ(halfContent, downloadContent);
|
||||
|
||||
auto snapshot1 = m_shareClient->CreateSnapshot()->Snapshot;
|
||||
EXPECT_NO_THROW(fileClient.ClearRange(500, 2048));
|
||||
auto snapshot2 = m_shareClient->CreateSnapshot()->Snapshot;
|
||||
Files::Shares::GetFileRangeListResult result;
|
||||
Files::Shares::GetFileRangeListOptions options;
|
||||
options.PrevShareSnapshot = snapshot1;
|
||||
EXPECT_NO_THROW(result = fileClient.GetRangeList(options).ExtractValue());
|
||||
EXPECT_EQ(2U, result.Ranges.size());
|
||||
EXPECT_EQ(0, result.Ranges[0].Start);
|
||||
EXPECT_EQ(511, result.Ranges[0].End);
|
||||
EXPECT_EQ(1024, result.Ranges[1].Start);
|
||||
EXPECT_EQ(static_cast<int32_t>(fileSize / 2) - 1, result.Ranges[1].End);
|
||||
EXPECT_NO_THROW(fileClient.ClearRange(3096, 2048));
|
||||
auto snapshot3 = m_shareClient->CreateSnapshot()->Snapshot;
|
||||
options.PrevShareSnapshot = snapshot1;
|
||||
EXPECT_NO_THROW(result = fileClient.GetRangeList(options).ExtractValue());
|
||||
EXPECT_EQ(2U, result.Ranges.size());
|
||||
EXPECT_EQ(0, result.Ranges[0].Start);
|
||||
EXPECT_EQ(511, result.Ranges[0].End);
|
||||
EXPECT_EQ(1024, result.Ranges[1].Start);
|
||||
EXPECT_EQ(static_cast<int32_t>(fileSize / 2) - 1, result.Ranges[1].End);
|
||||
}
|
||||
|
||||
}}} // namespace Azure::Storage::Test
|
||||
|
||||
@ -186,8 +186,14 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
downloadedProperties.HourMetrics.RetentionPolicy.Enabled,
|
||||
properties.HourMetrics.RetentionPolicy.Enabled);
|
||||
EXPECT_EQ(
|
||||
downloadedProperties.HourMetrics.RetentionPolicy.Days,
|
||||
properties.HourMetrics.RetentionPolicy.Days);
|
||||
downloadedProperties.HourMetrics.RetentionPolicy.Days.HasValue(),
|
||||
properties.HourMetrics.RetentionPolicy.Days.HasValue());
|
||||
if (properties.HourMetrics.RetentionPolicy.Days.HasValue())
|
||||
{
|
||||
EXPECT_EQ(
|
||||
downloadedProperties.HourMetrics.RetentionPolicy.Days.GetValue(),
|
||||
properties.HourMetrics.RetentionPolicy.Days.GetValue());
|
||||
}
|
||||
|
||||
EXPECT_EQ(downloadedProperties.MinuteMetrics.Version, properties.MinuteMetrics.Version);
|
||||
EXPECT_EQ(downloadedProperties.MinuteMetrics.Enabled, properties.MinuteMetrics.Enabled);
|
||||
@ -196,8 +202,14 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
downloadedProperties.MinuteMetrics.RetentionPolicy.Enabled,
|
||||
properties.MinuteMetrics.RetentionPolicy.Enabled);
|
||||
EXPECT_EQ(
|
||||
downloadedProperties.MinuteMetrics.RetentionPolicy.Days,
|
||||
properties.MinuteMetrics.RetentionPolicy.Days);
|
||||
downloadedProperties.MinuteMetrics.RetentionPolicy.Days.HasValue(),
|
||||
properties.MinuteMetrics.RetentionPolicy.Days.HasValue());
|
||||
if (properties.MinuteMetrics.RetentionPolicy.Days.HasValue())
|
||||
{
|
||||
EXPECT_EQ(
|
||||
downloadedProperties.MinuteMetrics.RetentionPolicy.Days.GetValue(),
|
||||
properties.MinuteMetrics.RetentionPolicy.Days.GetValue());
|
||||
}
|
||||
|
||||
EXPECT_EQ(downloadedProperties.Cors.size(), properties.Cors.size());
|
||||
for (const auto& cors : downloadedProperties.Cors)
|
||||
@ -218,4 +230,99 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
m_fileShareServiceClient->SetProperties(originalProperties);
|
||||
}
|
||||
|
||||
TEST_F(FileShareServiceClientTest, DISABLED_SetPremiumFileProperties)
|
||||
{
|
||||
auto premiumFileShareServiceClient = std::make_shared<Files::Shares::ServiceClient>(
|
||||
Files::Shares::ServiceClient::CreateFromConnectionString(PremiumFileConnectionString()));
|
||||
auto properties = *premiumFileShareServiceClient->GetProperties();
|
||||
auto originalProperties = properties;
|
||||
|
||||
properties.HourMetrics.Enabled = true;
|
||||
properties.HourMetrics.RetentionPolicy.Enabled = true;
|
||||
properties.HourMetrics.RetentionPolicy.Days = 4;
|
||||
properties.HourMetrics.IncludeAPIs = true;
|
||||
|
||||
properties.MinuteMetrics.Enabled = true;
|
||||
properties.MinuteMetrics.RetentionPolicy.Enabled = true;
|
||||
properties.MinuteMetrics.RetentionPolicy.Days = 3;
|
||||
properties.MinuteMetrics.IncludeAPIs = true;
|
||||
|
||||
Files::Shares::CorsRule corsRule;
|
||||
corsRule.AllowedOrigins = "http://www.example1.com";
|
||||
corsRule.AllowedMethods = "GET,PUT";
|
||||
corsRule.AllowedHeaders = "x-ms-header1,x-ms-header2";
|
||||
corsRule.ExposedHeaders = "x-ms-header3";
|
||||
corsRule.MaxAgeInSeconds = 10;
|
||||
properties.Cors.emplace_back(corsRule);
|
||||
|
||||
corsRule.AllowedOrigins = "http://www.example2.com";
|
||||
corsRule.AllowedMethods = "DELETE";
|
||||
corsRule.AllowedHeaders = "x-ms-header1";
|
||||
corsRule.ExposedHeaders = "x-ms-header2,x-ms-header3";
|
||||
corsRule.MaxAgeInSeconds = 20;
|
||||
properties.Cors.emplace_back(corsRule);
|
||||
|
||||
auto protocolSettings = Files::Shares::ShareProtocolSettings();
|
||||
protocolSettings.Settings.Multichannel.Enabled = true;
|
||||
properties.Protocol = protocolSettings;
|
||||
|
||||
EXPECT_NO_THROW(premiumFileShareServiceClient->SetProperties(properties));
|
||||
// It takes some time before the new properties comes into effect.
|
||||
using namespace std::chrono_literals;
|
||||
std::this_thread::sleep_for(10s);
|
||||
auto downloadedProperties = *premiumFileShareServiceClient->GetProperties();
|
||||
|
||||
EXPECT_EQ(downloadedProperties.HourMetrics.Version, properties.HourMetrics.Version);
|
||||
EXPECT_EQ(downloadedProperties.HourMetrics.Enabled, properties.HourMetrics.Enabled);
|
||||
EXPECT_EQ(downloadedProperties.HourMetrics.IncludeAPIs, properties.HourMetrics.IncludeAPIs);
|
||||
EXPECT_EQ(
|
||||
downloadedProperties.HourMetrics.RetentionPolicy.Enabled,
|
||||
properties.HourMetrics.RetentionPolicy.Enabled);
|
||||
EXPECT_EQ(
|
||||
downloadedProperties.HourMetrics.RetentionPolicy.Days.HasValue(),
|
||||
properties.HourMetrics.RetentionPolicy.Days.HasValue());
|
||||
if (properties.HourMetrics.RetentionPolicy.Days.HasValue())
|
||||
{
|
||||
EXPECT_EQ(
|
||||
downloadedProperties.HourMetrics.RetentionPolicy.Days.GetValue(),
|
||||
properties.HourMetrics.RetentionPolicy.Days.GetValue());
|
||||
}
|
||||
|
||||
EXPECT_EQ(downloadedProperties.MinuteMetrics.Version, properties.MinuteMetrics.Version);
|
||||
EXPECT_EQ(downloadedProperties.MinuteMetrics.Enabled, properties.MinuteMetrics.Enabled);
|
||||
EXPECT_EQ(downloadedProperties.MinuteMetrics.IncludeAPIs, properties.MinuteMetrics.IncludeAPIs);
|
||||
EXPECT_EQ(
|
||||
downloadedProperties.MinuteMetrics.RetentionPolicy.Enabled,
|
||||
properties.MinuteMetrics.RetentionPolicy.Enabled);
|
||||
EXPECT_EQ(
|
||||
downloadedProperties.MinuteMetrics.RetentionPolicy.Days.HasValue(),
|
||||
properties.MinuteMetrics.RetentionPolicy.Days.HasValue());
|
||||
if (properties.MinuteMetrics.RetentionPolicy.Days.HasValue())
|
||||
{
|
||||
EXPECT_EQ(
|
||||
downloadedProperties.MinuteMetrics.RetentionPolicy.Days.GetValue(),
|
||||
properties.MinuteMetrics.RetentionPolicy.Days.GetValue());
|
||||
}
|
||||
|
||||
EXPECT_EQ(downloadedProperties.Cors.size(), properties.Cors.size());
|
||||
for (const auto& cors : downloadedProperties.Cors)
|
||||
{
|
||||
auto iter = std::find_if(
|
||||
properties.Cors.begin(),
|
||||
properties.Cors.end(),
|
||||
[&cors](const Files::Shares::CorsRule& rule) {
|
||||
return rule.AllowedOrigins == cors.AllowedOrigins;
|
||||
});
|
||||
EXPECT_EQ(iter->AllowedMethods, cors.AllowedMethods);
|
||||
EXPECT_EQ(iter->AllowedHeaders, cors.AllowedHeaders);
|
||||
EXPECT_EQ(iter->ExposedHeaders, cors.ExposedHeaders);
|
||||
EXPECT_EQ(iter->MaxAgeInSeconds, cors.MaxAgeInSeconds);
|
||||
EXPECT_NE(properties.Cors.end(), iter);
|
||||
}
|
||||
|
||||
EXPECT_EQ(true, properties.Protocol.GetValue().Settings.Multichannel.Enabled);
|
||||
|
||||
premiumFileShareServiceClient->SetProperties(originalProperties);
|
||||
}
|
||||
|
||||
}}} // namespace Azure::Storage::Test
|
||||
|
||||
Loading…
Reference in New Issue
Block a user