[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:
parent
8372d39cc1
commit
68643e3ee2
@ -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(
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user