Skip to content

Commit 052d62a

Browse files
authored
feat(storage): noncurrent and custom time OLM (#4871)
Support "noncurrent time" attributes in the Object Lifecycle Management conditions. Support "custom time" attributes in the Object Lifecycle Management conditions.
1 parent b26c708 commit 052d62a

4 files changed

Lines changed: 233 additions & 10 deletions

File tree

google/cloud/storage/internal/bucket_requests.cc

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,9 @@ StatusOr<LifecycleRule> LifecycleRuleParser::FromJson(
8585
auto const date = condition.value("createdBefore", "");
8686
absl::CivilDay day;
8787
if (!absl::ParseCivilTime(date, &day)) {
88-
return Status(StatusCode::kInvalidArgument,
89-
"Cannot parse " + date + " as a date");
88+
return Status(
89+
StatusCode::kInvalidArgument,
90+
"Cannot parse createdBefore value (" + date + ") as a date");
9091
}
9192
result.condition_.created_before.emplace(std::move(day));
9293
}
@@ -105,6 +106,34 @@ StatusOr<LifecycleRule> LifecycleRuleParser::FromJson(
105106
result.condition_.num_newer_versions.emplace(
106107
internal::ParseIntField(condition, "numNewerVersions"));
107108
}
109+
if (condition.count("daysSinceNoncurrentTime") != 0) {
110+
result.condition_.days_since_noncurrent_time.emplace(
111+
internal::ParseIntField(condition, "daysSinceNoncurrentTime"));
112+
}
113+
if (condition.count("noncurrentTimeBefore") != 0) {
114+
auto const date = condition.value("noncurrentTimeBefore", "");
115+
absl::CivilDay day;
116+
if (!absl::ParseCivilTime(date, &day)) {
117+
return Status(
118+
StatusCode::kInvalidArgument,
119+
"Cannot parse noncurrentTimeBefore value (" + date + ") as a date");
120+
}
121+
result.condition_.noncurrent_time_before.emplace(std::move(day));
122+
}
123+
if (condition.count("daysSinceCustomTime") != 0) {
124+
result.condition_.days_since_custom_time.emplace(
125+
internal::ParseIntField(condition, "daysSinceCustomTime"));
126+
}
127+
if (condition.count("customTimeBefore") != 0) {
128+
auto const date = condition.value("customTimeBefore", "");
129+
absl::CivilDay day;
130+
if (!absl::ParseCivilTime(date, &day)) {
131+
return Status(
132+
StatusCode::kInvalidArgument,
133+
"Cannot parse customTimeBefore value (" + date + ") as a date");
134+
}
135+
result.condition_.custom_time_before.emplace(std::move(day));
136+
}
108137
}
109138
return result;
110139
}

google/cloud/storage/lifecycle_rule.cc

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,24 @@ std::ostream& operator<<(std::ostream& os, LifecycleRuleCondition const& rhs) {
9090
}
9191
if (rhs.num_newer_versions.has_value()) {
9292
os << sep << "num_newer_versions=" << *rhs.num_newer_versions;
93+
sep = ", ";
94+
}
95+
if (rhs.days_since_noncurrent_time.has_value()) {
96+
os << sep
97+
<< "days_since_noncurrent_time=" << *rhs.days_since_noncurrent_time;
98+
sep = ", ";
99+
}
100+
if (rhs.noncurrent_time_before.has_value()) {
101+
os << sep << "noncurrent_time_before=" << *rhs.noncurrent_time_before;
102+
sep = ", ";
103+
}
104+
if (rhs.days_since_custom_time.has_value()) {
105+
os << sep << "days_since_custom_time=" << *rhs.days_since_custom_time;
106+
sep = ", ";
107+
}
108+
if (rhs.custom_time_before.has_value()) {
109+
os << sep << "custom_time_before=" << *rhs.custom_time_before;
110+
sep = ", ";
93111
}
94112
return os << "}";
95113
}
@@ -98,15 +116,15 @@ void LifecycleRule::MergeConditions(LifecycleRuleCondition& result,
98116
LifecycleRuleCondition const& rhs) {
99117
if (rhs.age.has_value()) {
100118
if (result.age.has_value()) {
101-
*result.age = std::min(*result.age, *rhs.age);
119+
result.age = std::min(*result.age, *rhs.age);
102120
} else {
103121
auto tmp = *rhs.age;
104122
result.age.emplace(std::forward<std::int32_t>(tmp));
105123
}
106124
}
107125
if (rhs.created_before.has_value()) {
108126
if (result.created_before.has_value()) {
109-
*result.created_before =
127+
result.created_before =
110128
std::max(*result.created_before, *rhs.created_before);
111129
} else {
112130
result.created_before.emplace(std::move(*rhs.created_before));
@@ -141,13 +159,45 @@ void LifecycleRule::MergeConditions(LifecycleRuleCondition& result,
141159
}
142160
if (rhs.num_newer_versions.has_value()) {
143161
if (result.num_newer_versions.has_value()) {
144-
*result.num_newer_versions =
162+
result.num_newer_versions =
145163
std::max(*result.num_newer_versions, *rhs.num_newer_versions);
146164
} else {
147165
auto tmp = *rhs.num_newer_versions;
148166
result.num_newer_versions.emplace(std::forward<std::int32_t>(tmp));
149167
}
150168
}
169+
if (rhs.days_since_noncurrent_time.has_value()) {
170+
if (result.days_since_noncurrent_time.has_value()) {
171+
result.days_since_noncurrent_time = (std::max)(
172+
*result.days_since_noncurrent_time, *rhs.days_since_noncurrent_time);
173+
} else {
174+
result.days_since_noncurrent_time = *rhs.days_since_noncurrent_time;
175+
}
176+
}
177+
if (rhs.noncurrent_time_before.has_value()) {
178+
if (result.noncurrent_time_before.has_value()) {
179+
result.noncurrent_time_before = (std::min)(*result.noncurrent_time_before,
180+
*rhs.noncurrent_time_before);
181+
} else {
182+
result.noncurrent_time_before = *rhs.noncurrent_time_before;
183+
}
184+
}
185+
if (rhs.days_since_custom_time.has_value()) {
186+
if (result.days_since_custom_time.has_value()) {
187+
result.days_since_custom_time = (std::max)(*result.days_since_custom_time,
188+
*rhs.days_since_custom_time);
189+
} else {
190+
result.days_since_custom_time = *rhs.days_since_custom_time;
191+
}
192+
}
193+
if (rhs.custom_time_before.has_value()) {
194+
if (result.custom_time_before.has_value()) {
195+
result.custom_time_before =
196+
(std::min)(*result.custom_time_before, *rhs.custom_time_before);
197+
} else {
198+
result.custom_time_before = *rhs.custom_time_before;
199+
}
200+
}
151201
}
152202

153203
std::ostream& operator<<(std::ostream& os, LifecycleRule const& rhs) {

google/cloud/storage/lifecycle_rule.h

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,22 +83,34 @@ struct LifecycleRuleCondition {
8383
absl::optional<bool> is_live;
8484
absl::optional<std::vector<std::string>> matches_storage_class;
8585
absl::optional<std::int32_t> num_newer_versions;
86+
absl::optional<std::int32_t> days_since_noncurrent_time;
87+
absl::optional<absl::CivilDay> noncurrent_time_before;
88+
absl::optional<std::int32_t> days_since_custom_time;
89+
absl::optional<absl::CivilDay> custom_time_before;
8690
};
8791

8892
inline bool operator==(LifecycleRuleCondition const& lhs,
8993
LifecycleRuleCondition const& rhs) {
9094
return lhs.age == rhs.age && lhs.created_before == rhs.created_before &&
9195
lhs.is_live == rhs.is_live &&
9296
lhs.matches_storage_class == rhs.matches_storage_class &&
93-
lhs.num_newer_versions == rhs.num_newer_versions;
97+
lhs.num_newer_versions == rhs.num_newer_versions &&
98+
lhs.days_since_noncurrent_time == rhs.days_since_noncurrent_time &&
99+
lhs.noncurrent_time_before == rhs.noncurrent_time_before &&
100+
lhs.days_since_custom_time == rhs.days_since_custom_time &&
101+
lhs.custom_time_before == rhs.custom_time_before;
94102
}
95103

96104
inline bool operator<(LifecycleRuleCondition const& lhs,
97105
LifecycleRuleCondition const& rhs) {
98106
return std::tie(lhs.age, lhs.created_before, lhs.is_live,
99-
lhs.matches_storage_class, lhs.num_newer_versions) <
107+
lhs.matches_storage_class, lhs.num_newer_versions,
108+
lhs.days_since_noncurrent_time, lhs.noncurrent_time_before,
109+
lhs.days_since_custom_time, lhs.custom_time_before) <
100110
std::tie(rhs.age, rhs.created_before, rhs.is_live,
101-
rhs.matches_storage_class, rhs.num_newer_versions);
111+
rhs.matches_storage_class, rhs.num_newer_versions,
112+
rhs.days_since_noncurrent_time, rhs.noncurrent_time_before,
113+
rhs.days_since_custom_time, rhs.custom_time_before);
102114
}
103115

104116
inline bool operator!=(LifecycleRuleCondition const& lhs,
@@ -237,6 +249,30 @@ class LifecycleRule {
237249
result.num_newer_versions.emplace(std::move(days));
238250
return result;
239251
}
252+
253+
static LifecycleRuleCondition DaysSinceNoncurrentTime(std::int32_t days) {
254+
LifecycleRuleCondition result;
255+
result.days_since_noncurrent_time = days;
256+
return result;
257+
}
258+
259+
static LifecycleRuleCondition NoncurrentTimeBefore(absl::CivilDay date) {
260+
LifecycleRuleCondition result;
261+
result.noncurrent_time_before = date;
262+
return result;
263+
}
264+
265+
static LifecycleRuleCondition DaysSinceCustomTime(std::int32_t days) {
266+
LifecycleRuleCondition result;
267+
result.days_since_custom_time = days;
268+
return result;
269+
}
270+
271+
static LifecycleRuleCondition CustomTimeBefore(absl::CivilDay date) {
272+
LifecycleRuleCondition result;
273+
result.custom_time_before = date;
274+
return result;
275+
}
240276
//@}
241277

242278
/**

google/cloud/storage/lifecycle_rule_test.cc

Lines changed: 110 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,11 @@ LifecycleRule CreateLifecycleRuleForTest() {
3030
"createdBefore": "2018-07-23",
3131
"isLive": true,
3232
"matchesStorageClass": [ "STANDARD" ],
33-
"numNewerVersions": 7
33+
"numNewerVersions": 7,
34+
"daysSinceNoncurrentTime": 3,
35+
"noncurrentTimeBefore": "2020-07-22",
36+
"daysSinceCustomTime": 30,
37+
"customTimeBefore": "2020-07-23"
3438
},
3539
"action": {
3640
"type": "SetStorageClass",
@@ -239,6 +243,66 @@ TEST(LifecycleRuleTest, NumNewerVersions) {
239243
EXPECT_EQ(7, condition.num_newer_versions.value());
240244
}
241245

246+
/// @test Verify that LifecycleRule::DaysSinceNoncurrent() works as expected.
247+
TEST(LifecycleRuleTest, DaysSinceNoncurrentTime) {
248+
auto const c1 = LifecycleRule::DaysSinceNoncurrentTime(3);
249+
ASSERT_TRUE(c1.days_since_noncurrent_time.has_value());
250+
EXPECT_EQ(3, c1.days_since_noncurrent_time.value());
251+
EXPECT_EQ(c1, c1);
252+
auto const c2 = LifecycleRule::DaysSinceNoncurrentTime(4);
253+
EXPECT_NE(c1, c2);
254+
EXPECT_LT(c1, c2);
255+
auto const empty = LifecycleRuleCondition{};
256+
EXPECT_NE(c1, empty);
257+
}
258+
259+
/// @test Verify that LifecycleRule::NoncurrentTimeBefore() works as expected.
260+
TEST(LifecycleRuleTest, NoncurrentTimeBefore) {
261+
auto const c1 =
262+
LifecycleRule::NoncurrentTimeBefore(absl::CivilDay(2020, 7, 22));
263+
ASSERT_TRUE(c1.noncurrent_time_before.has_value());
264+
EXPECT_EQ(c1, c1);
265+
auto const c2 =
266+
LifecycleRule::NoncurrentTimeBefore(absl::CivilDay(2020, 7, 23));
267+
ASSERT_TRUE(c2.noncurrent_time_before.has_value());
268+
EXPECT_EQ(c2, c2);
269+
270+
EXPECT_NE(c1, c2);
271+
EXPECT_LT(c1, c2);
272+
273+
auto const empty = LifecycleRuleCondition{};
274+
EXPECT_NE(c1, empty);
275+
}
276+
277+
/// @test Verify that LifecycleRule::DaysSinceCustomTime() works as expected.
278+
TEST(LifecycleRuleTest, DaysSinceCustomTime) {
279+
auto const c1 = LifecycleRule::DaysSinceCustomTime(3);
280+
ASSERT_TRUE(c1.days_since_custom_time.has_value());
281+
EXPECT_EQ(3, c1.days_since_custom_time.value());
282+
EXPECT_EQ(c1, c1);
283+
auto const c2 = LifecycleRule::DaysSinceCustomTime(4);
284+
EXPECT_NE(c1, c2);
285+
EXPECT_LT(c1, c2);
286+
auto const empty = LifecycleRuleCondition{};
287+
EXPECT_NE(c1, empty);
288+
}
289+
290+
/// @test Verify that LifecycleRule::NoncurrentTimeBefore() works as expected.
291+
TEST(LifecycleRuleTest, CustomTimeBefore) {
292+
auto const c1 = LifecycleRule::CustomTimeBefore(absl::CivilDay(2020, 7, 23));
293+
ASSERT_TRUE(c1.custom_time_before.has_value());
294+
EXPECT_EQ(c1, c1);
295+
auto const c2 = LifecycleRule::CustomTimeBefore(absl::CivilDay(2020, 7, 24));
296+
ASSERT_TRUE(c2.custom_time_before.has_value());
297+
EXPECT_EQ(c2, c2);
298+
299+
EXPECT_NE(c1, c2);
300+
EXPECT_LT(c1, c2);
301+
302+
auto const empty = LifecycleRuleCondition{};
303+
EXPECT_NE(c1, empty);
304+
}
305+
242306
/// @test Verify that LifecycleRule::ConditionConjunction() works as expected.
243307
TEST(LifecycleRuleTest, ConditionConjunctionAge) {
244308
auto c1 = LifecycleRule::MaxAge(7);
@@ -317,6 +381,44 @@ TEST(LifecycleRuleTest, ConditionConjunctionNumNewerVersions) {
317381
EXPECT_EQ(42, *condition.num_newer_versions);
318382
}
319383

384+
/// @test Verify that LifecycleRule::ConditionConjunction() works as expected.
385+
TEST(LifecycleRuleTest, ConditionConjunctionDaysSinceNoncurrentTime) {
386+
auto const c1 = LifecycleRule::DaysSinceNoncurrentTime(7);
387+
auto const c2 = LifecycleRule::DaysSinceNoncurrentTime(42);
388+
auto const condition = LifecycleRule::ConditionConjunction(c1, c2);
389+
ASSERT_TRUE(condition.days_since_noncurrent_time.has_value());
390+
EXPECT_EQ(42, *condition.days_since_noncurrent_time);
391+
}
392+
393+
/// @test Verify that LifecycleRule::ConditionConjunction() works as expected.
394+
TEST(LifecycleRuleTest, ConditionConjunctionNoncurrentTimeBefore) {
395+
auto const c1 =
396+
LifecycleRule::NoncurrentTimeBefore(absl::CivilDay(2020, 7, 22));
397+
auto const c2 =
398+
LifecycleRule::NoncurrentTimeBefore(absl::CivilDay(2020, 7, 23));
399+
auto const condition = LifecycleRule::ConditionConjunction(c1, c2);
400+
ASSERT_TRUE(condition.noncurrent_time_before.has_value());
401+
EXPECT_EQ(absl::CivilDay(2020, 7, 22), *condition.noncurrent_time_before);
402+
}
403+
404+
/// @test Verify that LifecycleRule::ConditionConjunction() works as expected.
405+
TEST(LifecycleRuleTest, ConditionConjunctionDaysSinceCustomTime) {
406+
auto const c1 = LifecycleRule::DaysSinceCustomTime(7);
407+
auto const c2 = LifecycleRule::DaysSinceCustomTime(42);
408+
auto const condition = LifecycleRule::ConditionConjunction(c1, c2);
409+
ASSERT_TRUE(condition.days_since_custom_time.has_value());
410+
EXPECT_EQ(42, *condition.days_since_custom_time);
411+
}
412+
413+
/// @test Verify that LifecycleRule::ConditionConjunction() works as expected.
414+
TEST(LifecycleRuleTest, ConditionConjunctionCustomTimeBefore) {
415+
auto const c1 = LifecycleRule::CustomTimeBefore(absl::CivilDay(2020, 7, 23));
416+
auto const c2 = LifecycleRule::CustomTimeBefore(absl::CivilDay(2020, 7, 24));
417+
auto const condition = LifecycleRule::ConditionConjunction(c1, c2);
418+
ASSERT_TRUE(condition.custom_time_before.has_value());
419+
EXPECT_EQ(absl::CivilDay(2020, 7, 23), *condition.custom_time_before);
420+
}
421+
320422
/// @test Verify that LifecycleRule::ConditionConjunction() works as expected.
321423
TEST(LifecycleRuleTest, ConditionConjunctionMultiple) {
322424
auto c1 = LifecycleRule::NumNewerVersions(7);
@@ -348,7 +450,11 @@ TEST(LifecycleRuleTest, Parsing) {
348450
LifecycleRule::CreatedBefore(absl::CivilDay(2018, 7, 23)),
349451
LifecycleRule::IsLive(true),
350452
LifecycleRule::MatchesStorageClassStandard(),
351-
LifecycleRule::NumNewerVersions(7));
453+
LifecycleRule::NumNewerVersions(7),
454+
LifecycleRule::DaysSinceNoncurrentTime(3),
455+
LifecycleRule::NoncurrentTimeBefore(absl::CivilDay(2020, 7, 22)),
456+
LifecycleRule::DaysSinceCustomTime(30),
457+
LifecycleRule::CustomTimeBefore(absl::CivilDay(2020, 7, 23)));
352458
EXPECT_EQ(expected_condition, actual.condition());
353459

354460
LifecycleRuleAction expected_action =
@@ -364,6 +470,8 @@ TEST(LifecycleRuleTest, LifecycleRuleStream) {
364470
auto actual = os.str();
365471
EXPECT_THAT(actual, ::testing::HasSubstr("age=42"));
366472
EXPECT_THAT(actual, ::testing::HasSubstr("NEARLINE"));
473+
EXPECT_THAT(actual, ::testing::HasSubstr("days_since_custom_time="));
474+
EXPECT_THAT(actual, ::testing::HasSubstr("custom_time_before="));
367475
}
368476

369477
} // namespace

0 commit comments

Comments
 (0)