[Storage Blobs Service] Add test cases for LastModifiedTime and ETag and lease id (#425)

* add test cases for LastModifiedTime and ETag and lease id
This commit is contained in:
JinmingHu 2020-08-11 10:40:59 +08:00 committed by GitHub
parent 8372d39cc1
commit 68643e3ee2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 267 additions and 9 deletions

View File

@ -555,7 +555,7 @@ namespace Azure { namespace Storage { namespace Blobs {
protocolLayerOptions.IfNoneMatch = options.AccessConditions.IfNoneMatch;
protocolLayerOptions.SourceLeaseId = options.SourceConditions.LeaseId;
protocolLayerOptions.SourceIfModifiedSince = options.SourceConditions.IfModifiedSince;
protocolLayerOptions.SourceIfUnmodifiedSince = options.AccessConditions.IfUnmodifiedSince;
protocolLayerOptions.SourceIfUnmodifiedSince = options.SourceConditions.IfUnmodifiedSince;
protocolLayerOptions.SourceIfMatch = options.SourceConditions.IfMatch;
protocolLayerOptions.SourceIfNoneMatch = options.SourceConditions.IfNoneMatch;
return BlobRestClient::Blob::StartCopyFromUri(

View File

@ -177,6 +177,12 @@ namespace Azure { namespace Storage { namespace Blobs {
protocolLayerOptions.Metadata = metadata;
protocolLayerOptions.LeaseId = options.AccessConditions.LeaseId;
protocolLayerOptions.IfModifiedSince = options.AccessConditions.IfModifiedSince;
if (options.AccessConditions.IfUnmodifiedSince.HasValue())
{
// Strangely enough, this operation doesn't support If-Unmodified-Since while it does support
// If-Modified-Since
throw std::runtime_error("this operation doesn't support unmodified since access condition.");
}
return BlobRestClient::Container::SetMetadata(
options.Context, *m_pipeline, m_containerUrl.ToString(), protocolLayerOptions);
}

View File

@ -90,4 +90,169 @@ namespace Azure { namespace Storage { namespace Test {
EXPECT_THROW(appendBlobClient.Delete(), StorageError);
}
TEST_F(AppendBlobClientTest, AccessConditionLastModifiedTime)
{
auto appendBlobClient = Azure::Storage::Blobs::AppendBlobClient::CreateFromConnectionString(
StandardStorageConnectionString(), m_containerName, RandomString());
appendBlobClient.Create();
enum class TimePoint
{
TimeBefore,
TimeAfter,
None,
};
enum class Condition
{
ModifiedSince,
UnmodifiedSince,
};
auto lastModifiedTime = FromRfc1123(appendBlobClient.GetProperties()->LastModified);
auto timeBeforeStr = ToRfc1123(lastModifiedTime - std::chrono::seconds(1));
auto timeAfterStr = ToRfc1123(lastModifiedTime + std::chrono::seconds(1));
for (auto condition : {Condition::ModifiedSince, Condition::UnmodifiedSince})
{
for (auto sinceTime : {TimePoint::TimeBefore, TimePoint::TimeAfter})
{
Blobs::GetBlobPropertiesOptions options;
if (condition == Condition::ModifiedSince)
{
options.AccessConditions.IfModifiedSince
= sinceTime == TimePoint::TimeBefore ? timeBeforeStr : timeAfterStr;
}
else if (condition == Condition::UnmodifiedSince)
{
options.AccessConditions.IfUnmodifiedSince
= sinceTime == TimePoint::TimeBefore ? timeBeforeStr : timeAfterStr;
}
bool shouldThrow
= (condition == Condition::ModifiedSince && sinceTime == TimePoint::TimeAfter)
|| (condition == Condition::UnmodifiedSince && sinceTime == TimePoint::TimeBefore);
if (shouldThrow)
{
EXPECT_THROW(appendBlobClient.GetProperties(options), StorageError);
}
else
{
EXPECT_NO_THROW(appendBlobClient.GetProperties(options));
}
}
}
}
TEST_F(AppendBlobClientTest, AccessConditionETag)
{
auto appendBlobClient = Azure::Storage::Blobs::AppendBlobClient::CreateFromConnectionString(
StandardStorageConnectionString(), m_containerName, RandomString());
Blobs::CreateAppendBlobOptions createOptions;
createOptions.AccessConditions.IfNoneMatch = "*";
EXPECT_NO_THROW(appendBlobClient.Create(createOptions));
EXPECT_THROW(appendBlobClient.Create(createOptions), StorageError);
std::string eTag = appendBlobClient.GetProperties()->ETag;
for (std::string match : {eTag, std::string(c_dummyETag), std::string()})
{
for (std::string noneMatch : {eTag, std::string(c_dummyETag), std::string()})
{
Blobs::GetBlobPropertiesOptions options;
if (!match.empty())
{
options.AccessConditions.IfMatch = match;
}
if (!noneMatch.empty())
{
options.AccessConditions.IfNoneMatch = noneMatch;
}
bool shouldThrow = (!match.empty() && match != eTag) || noneMatch == eTag;
if (shouldThrow)
{
EXPECT_THROW(appendBlobClient.GetProperties(options), StorageError);
}
else
{
EXPECT_NO_THROW(appendBlobClient.GetProperties(options));
}
}
}
}
TEST_F(AppendBlobClientTest, AccessConditionLeaseId)
{
auto appendBlobClient = Azure::Storage::Blobs::AppendBlobClient::CreateFromConnectionString(
StandardStorageConnectionString(), m_containerName, RandomString());
appendBlobClient.Create();
std::string leaseId = CreateUniqueLeaseId();
appendBlobClient.AcquireLease(leaseId, 30);
EXPECT_THROW(appendBlobClient.Delete(), StorageError);
Blobs::DeleteBlobOptions options;
options.AccessConditions.LeaseId = leaseId;
EXPECT_NO_THROW(appendBlobClient.Delete(options));
}
TEST_F(AppendBlobClientTest, SourceBlobAccessConditions)
{
auto sourceBlobClient = Azure::Storage::Blobs::AppendBlobClient::CreateFromConnectionString(
StandardStorageConnectionString(), m_containerName, RandomString());
sourceBlobClient.Create();
auto leaseResponse
= sourceBlobClient.AcquireLease(CreateUniqueLeaseId(), c_InfiniteLeaseDuration);
std::string leaseId = leaseResponse->LeaseId;
std::string eTag = leaseResponse->ETag;
auto lastModifiedTime = FromRfc1123(leaseResponse->LastModified);
auto timeBeforeStr = ToRfc1123(lastModifiedTime - std::chrono::seconds(1));
auto timeAfterStr = ToRfc1123(lastModifiedTime + std::chrono::seconds(1));
auto destBlobClient = Azure::Storage::Blobs::AppendBlobClient::CreateFromConnectionString(
StandardStorageConnectionString(), m_containerName, RandomString());
{
Blobs::StartCopyFromUriOptions options;
options.SourceConditions.LeaseId = CreateUniqueLeaseId();
/*
don't know why, the copy operation also succeeds even if the lease id doesn't match.
EXPECT_THROW(
destBlobClient.StartCopyFromUri(sourceBlobClient.GetUri(), options), StorageError);
*/
options.SourceConditions.LeaseId = leaseId;
EXPECT_NO_THROW(destBlobClient.StartCopyFromUri(sourceBlobClient.GetUri(), options));
}
sourceBlobClient.BreakLease();
{
Blobs::StartCopyFromUriOptions options;
options.SourceConditions.IfMatch = eTag;
EXPECT_NO_THROW(destBlobClient.StartCopyFromUri(sourceBlobClient.GetUri(), options));
options.SourceConditions.IfMatch = c_dummyETag;
EXPECT_THROW(
destBlobClient.StartCopyFromUri(sourceBlobClient.GetUri(), options), StorageError);
}
{
Blobs::StartCopyFromUriOptions options;
options.SourceConditions.IfNoneMatch = c_dummyETag;
EXPECT_NO_THROW(destBlobClient.StartCopyFromUri(sourceBlobClient.GetUri(), options));
options.SourceConditions.IfNoneMatch = eTag;
EXPECT_THROW(
destBlobClient.StartCopyFromUri(sourceBlobClient.GetUri(), options), StorageError);
}
{
Blobs::StartCopyFromUriOptions options;
options.SourceConditions.IfModifiedSince = timeBeforeStr;
EXPECT_NO_THROW(destBlobClient.StartCopyFromUri(sourceBlobClient.GetUri(), options));
options.SourceConditions.IfModifiedSince = timeAfterStr;
EXPECT_THROW(
destBlobClient.StartCopyFromUri(sourceBlobClient.GetUri(), options), StorageError);
}
{
Blobs::StartCopyFromUriOptions options;
options.SourceConditions.IfUnmodifiedSince = timeAfterStr;
EXPECT_NO_THROW(destBlobClient.StartCopyFromUri(sourceBlobClient.GetUri(), options));
options.SourceConditions.IfUnmodifiedSince = timeBeforeStr;
EXPECT_THROW(
destBlobClient.StartCopyFromUri(sourceBlobClient.GetUri(), options), StorageError);
}
}
}}} // namespace Azure::Storage::Test

View File

@ -553,4 +553,73 @@ namespace Azure { namespace Storage { namespace Test {
}
}
TEST_F(BlobContainerClientTest, AccessConditionLastModifiedTime)
{
auto containerClient = Azure::Storage::Blobs::BlobContainerClient::CreateFromConnectionString(
StandardStorageConnectionString(), LowercaseRandomString());
containerClient.Create();
enum class TimePoint
{
TimeBefore,
TimeAfter,
None,
};
enum class Condition
{
ModifiedSince,
UnmodifiedSince,
};
for (auto condition : {Condition::ModifiedSince, Condition::UnmodifiedSince})
{
for (auto sinceTime : {TimePoint::TimeBefore, TimePoint::TimeAfter})
{
auto lastModifiedTime = FromRfc1123(containerClient.GetProperties()->LastModified);
auto timeBeforeStr = ToRfc1123(lastModifiedTime - std::chrono::seconds(1));
auto timeAfterStr = ToRfc1123(lastModifiedTime + std::chrono::seconds(1));
Blobs::SetBlobContainerAccessPolicyOptions options;
options.AccessType = Blobs::PublicAccessType::Private;
if (condition == Condition::ModifiedSince)
{
options.AccessConditions.IfModifiedSince
= sinceTime == TimePoint::TimeBefore ? timeBeforeStr : timeAfterStr;
}
else if (condition == Condition::UnmodifiedSince)
{
options.AccessConditions.IfUnmodifiedSince
= sinceTime == TimePoint::TimeBefore ? timeBeforeStr : timeAfterStr;
}
bool shouldThrow
= (condition == Condition::ModifiedSince && sinceTime == TimePoint::TimeAfter)
|| (condition == Condition::UnmodifiedSince && sinceTime == TimePoint::TimeBefore);
if (shouldThrow)
{
EXPECT_THROW(containerClient.SetAccessPolicy(options), StorageError);
}
else
{
EXPECT_NO_THROW(containerClient.SetAccessPolicy(options));
}
}
}
containerClient.Delete();
}
TEST_F(BlobContainerClientTest, AccessConditionLeaseId)
{
auto containerClient = Azure::Storage::Blobs::BlobContainerClient::CreateFromConnectionString(
StandardStorageConnectionString(), LowercaseRandomString());
containerClient.Create();
std::string leaseId = CreateUniqueLeaseId();
containerClient.AcquireLease(leaseId, 30);
EXPECT_THROW(containerClient.Delete(), StorageError);
Blobs::DeleteBlobContainerOptions options;
options.AccessConditions.LeaseId = leaseId;
EXPECT_NO_THROW(containerClient.Delete(options));
}
}}} // namespace Azure::Storage::Test

View File

@ -218,10 +218,10 @@ namespace Azure { namespace Storage { namespace Test {
}
std::string ToIso8601(
const std::chrono::system_clock::time_point& time_point,
const std::chrono::system_clock::time_point& timePoint,
int numDecimalDigits)
{
std::time_t epoch_seconds = std::chrono::system_clock::to_time_t(time_point);
std::time_t epoch_seconds = std::chrono::system_clock::to_time_t(timePoint);
struct tm ct;
#ifdef _WIN32
gmtime_s(&ct, &epoch_seconds);
@ -235,8 +235,8 @@ namespace Azure { namespace Storage { namespace Test {
if (numDecimalDigits != 0)
{
time_str += ".";
auto time_point_second = std::chrono::time_point_cast<std::chrono::seconds>(time_point);
auto decimal_part = time_point - time_point_second;
auto time_point_second = std::chrono::time_point_cast<std::chrono::seconds>(timePoint);
auto decimal_part = timePoint - time_point_second;
uint64_t num_nanoseconds
= std::chrono::duration_cast<std::chrono::nanoseconds>(decimal_part).count();
std::string decimal_part_str = std::to_string(num_nanoseconds);
@ -248,9 +248,9 @@ namespace Azure { namespace Storage { namespace Test {
return time_str;
}
std::string ToRfc1123(const std::chrono::system_clock::time_point& time_point)
std::string ToRfc1123(const std::chrono::system_clock::time_point& timePoint)
{
std::time_t epoch_seconds = std::chrono::system_clock::to_time_t(time_point);
std::time_t epoch_seconds = std::chrono::system_clock::to_time_t(timePoint);
struct tm ct;
#ifdef _WIN32
gmtime_s(&ct, &epoch_seconds);
@ -263,4 +263,18 @@ namespace Azure { namespace Storage { namespace Test {
return ss.str();
}
std::chrono::system_clock::time_point FromRfc1123(const std::string& timeStr)
{
std::tm t;
std::stringstream ss(timeStr);
ss.imbue(std::locale("C"));
ss >> std::get_time(&t, "%a, %d %b %Y %H:%M:%S GMT");
#ifdef _WIN32
time_t tt = _mkgmtime(&t);
#else
time_t tt = timegm(&t);
#endif
return std::chrono::system_clock::from_time_t(tt);
}
}}} // namespace Azure::Storage::Test

View File

@ -38,6 +38,8 @@ namespace Azure { namespace Storage { namespace Test {
return x * 1024 * 1024 * 1024 * 1024;
}
constexpr static const char* c_dummyETag = "0x8D83B58BDF51D75";
std::string RandomString(size_t size = 10);
std::string LowercaseRandomString(size_t size = 10);
@ -64,8 +66,10 @@ namespace Azure { namespace Storage { namespace Test {
void DeleteFile(const std::string& filename);
std::string ToIso8601(
const std::chrono::system_clock::time_point& time_point,
const std::chrono::system_clock::time_point& timePoint,
int numDecimalDigits = 0);
std::string ToRfc1123(const std::chrono::system_clock::time_point& time_point);
std::string ToRfc1123(const std::chrono::system_clock::time_point& timePoint);
std::chrono::system_clock::time_point FromRfc1123(const std::string& timeStr);
}}} // namespace Azure::Storage::Test