Skip to content

Commit 1082724

Browse files
authored
fix: Support for additional flags in expireat, pexpire and pexpireat commands (#5007)
* fix: Support for additional flags in expireat, pexpire and pexpireat commands. * Replaced actual clock with Test clock in generic family tests.
1 parent befb36d commit 1082724

File tree

2 files changed

+216
-4
lines changed

2 files changed

+216
-4
lines changed

src/server/generic_family.cc

+4-4
Original file line numberDiff line numberDiff line change
@@ -1925,13 +1925,13 @@ void GenericFamily::Register(CommandRegistry* registry) {
19251925
<< CI{"TOUCH", CO::READONLY | CO::FAST, -2, 1, -1, acl::kTouch}.HFUNC(Exists)
19261926
<< CI{"EXPIRE", CO::WRITE | CO::FAST | CO::NO_AUTOJOURNAL, -3, 1, 1, acl::kExpire}.HFUNC(
19271927
Expire)
1928-
<< CI{"EXPIREAT", CO::WRITE | CO::FAST | CO::NO_AUTOJOURNAL, 3, 1, 1, acl::kExpireAt}.HFUNC(
1928+
<< CI{"EXPIREAT", CO::WRITE | CO::FAST | CO::NO_AUTOJOURNAL, -3, 1, 1, acl::kExpireAt}.HFUNC(
19291929
ExpireAt)
19301930
<< CI{"PERSIST", CO::WRITE | CO::FAST, 2, 1, 1, acl::kPersist}.HFUNC(Persist)
19311931
<< CI{"KEYS", CO::READONLY, 2, 0, 0, acl::kKeys}.HFUNC(Keys)
1932-
<< CI{"PEXPIREAT", CO::WRITE | CO::FAST | CO::NO_AUTOJOURNAL, 3, 1, 1, acl::kPExpireAt}.HFUNC(
1933-
PexpireAt)
1934-
<< CI{"PEXPIRE", CO::WRITE | CO::FAST | CO::NO_AUTOJOURNAL, 3, 1, 1, acl::kPExpire}.HFUNC(
1932+
<< CI{"PEXPIREAT", CO::WRITE | CO::FAST | CO::NO_AUTOJOURNAL, -3, 1, 1, acl::kPExpireAt}
1933+
.HFUNC(PexpireAt)
1934+
<< CI{"PEXPIRE", CO::WRITE | CO::FAST | CO::NO_AUTOJOURNAL, -3, 1, 1, acl::kPExpire}.HFUNC(
19351935
Pexpire)
19361936
<< CI{"FIELDEXPIRE", CO::WRITE | CO::FAST | CO::DENYOOM, -4, 1, 1, acl::kFieldExpire}.HFUNC(
19371937
FieldExpire)

src/server/generic_family_test.cc

+212
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,218 @@ TEST_F(GenericFamilyTest, ExpireOptions) {
145145
EXPECT_THAT(resp.GetInt(), 101);
146146
}
147147

148+
TEST_F(GenericFamilyTest, ExpireAtOptions) {
149+
auto test_time_ms = TEST_current_time_ms;
150+
auto time_s = (test_time_ms + 500) / 1000;
151+
auto test_time_s = time_s;
152+
153+
Run({"set", "key", "val"});
154+
// NX and XX are mutually exclusive
155+
auto resp = Run({"expireat", "key", "3600", "NX", "XX"});
156+
ASSERT_THAT(resp, ErrArg("NX and XX, GT or LT options at the same time are not compatible"));
157+
158+
// NX and GT are mutually exclusive
159+
resp = Run({"expireat", "key", "3600", "NX", "GT"});
160+
ASSERT_THAT(resp, ErrArg("NX and XX, GT or LT options at the same time are not compatible"));
161+
162+
// NX and LT are mutually exclusive
163+
resp = Run({"expireat", "key", "3600", "NX", "LT"});
164+
ASSERT_THAT(resp, ErrArg("NX and XX, GT or LT options at the same time are not compatible"));
165+
166+
// GT and LT are mutually exclusive
167+
resp = Run({"expireat", "key", "3600", "GT", "LT"});
168+
ASSERT_THAT(resp, ErrArg("GT and LT options at the same time are not compatible"));
169+
170+
// NX option should be added since there is no expiry
171+
test_time_s = time_s + 5;
172+
resp = Run({"expireat", "key", absl::StrCat(test_time_s), "NX"});
173+
EXPECT_THAT(resp, IntArg(1));
174+
EXPECT_EQ(test_time_s, CheckedInt({"EXPIRETIME", "key"}));
175+
176+
// running again with NX option, should not change expiry
177+
test_time_s = time_s + 9;
178+
resp = Run({"expireat", "key", absl::StrCat(test_time_s), "NX"});
179+
EXPECT_THAT(resp, IntArg(0));
180+
181+
// given a key with no expiry
182+
Run({"set", "key2", "val"});
183+
test_time_s = time_s + 9;
184+
resp = Run({"expireat", "key2", absl::StrCat(test_time_s), "XX"});
185+
// XX does not apply expiry since key has no existing expiry
186+
EXPECT_THAT(resp, IntArg(0));
187+
resp = Run({"ttl", "key2"});
188+
EXPECT_THAT(resp.GetInt(), -1);
189+
190+
// set expiry to 101
191+
test_time_s = time_s + 101;
192+
resp = Run({"expireat", "key", absl::StrCat(test_time_s)});
193+
EXPECT_THAT(resp, IntArg(1));
194+
195+
// GT should not apply expiry since new is not greater than the current one
196+
auto less_test_time_s = time_s + 99;
197+
resp = Run({"expireat", "key", absl::StrCat(less_test_time_s), "GT"});
198+
EXPECT_THAT(resp, IntArg(0));
199+
EXPECT_EQ(test_time_s, CheckedInt({"EXPIRETIME", "key"}));
200+
201+
// GT should apply expiry since new is greater than the current one
202+
test_time_s = time_s + 105;
203+
resp = Run({"expireat", "key", absl::StrCat(test_time_s), "GT"});
204+
EXPECT_THAT(resp, IntArg(1));
205+
EXPECT_EQ(test_time_s, CheckedInt({"EXPIRETIME", "key"}));
206+
207+
// LT should apply new expiry is smaller than current
208+
test_time_s = time_s + 101;
209+
resp = Run({"expireat", "key", absl::StrCat(test_time_s), "LT"});
210+
EXPECT_THAT(resp, IntArg(1));
211+
EXPECT_EQ(test_time_s, CheckedInt({"EXPIRETIME", "key"}));
212+
213+
// LT should not apply expiry since new is not lesser than the current one
214+
auto gt_test_time_s = time_s + 102;
215+
resp = Run({"expireat", "key", absl::StrCat(gt_test_time_s), "LT"});
216+
EXPECT_THAT(resp, IntArg(0));
217+
EXPECT_EQ(test_time_s, CheckedInt({"EXPIRETIME", "key"}));
218+
}
219+
220+
TEST_F(GenericFamilyTest, PExpireOptions) {
221+
// NX and XX are mutually exclusive
222+
Run({"set", "key", "val"});
223+
auto resp = Run({"pexpire", "key", "3600", "NX", "XX"});
224+
ASSERT_THAT(resp, ErrArg("NX and XX, GT or LT options at the same time are not compatible"));
225+
226+
// NX and GT are mutually exclusive
227+
resp = Run({"pexpire", "key", "3600", "NX", "GT"});
228+
ASSERT_THAT(resp, ErrArg("NX and XX, GT or LT options at the same time are not compatible"));
229+
230+
// NX and LT are mutually exclusive
231+
resp = Run({"pexpire", "key", "3600", "NX", "LT"});
232+
ASSERT_THAT(resp, ErrArg("NX and XX, GT or LT options at the same time are not compatible"));
233+
234+
// GT and LT are mutually exclusive
235+
resp = Run({"pexpire", "key", "3600", "GT", "LT"});
236+
ASSERT_THAT(resp, ErrArg("GT and LT options at the same time are not compatible"));
237+
238+
// NX option should be added since there is no expiry
239+
resp = Run({"pexpire", "key", "3600000", "NX"});
240+
EXPECT_THAT(resp, IntArg(1));
241+
resp = Run({"pttl", "key"});
242+
EXPECT_THAT(resp.GetInt(), 3600000);
243+
244+
// running again with NX option, should not change expiry
245+
resp = Run({"pexpire", "key", "42", "NX"});
246+
EXPECT_THAT(resp, IntArg(0));
247+
248+
// given a key with no expiry
249+
Run({"set", "key2", "val"});
250+
resp = Run({"pexpire", "key2", "404", "XX"});
251+
// XX does not apply expiry since key has no existing expiry
252+
EXPECT_THAT(resp, IntArg(0));
253+
resp = Run({"pttl", "key2"});
254+
EXPECT_THAT(resp.GetInt(), -1);
255+
256+
// set expiry to 101
257+
resp = Run({"pexpire", "key", "101000"});
258+
EXPECT_THAT(resp, IntArg(1));
259+
260+
// GT should not apply expiry since new is not greater than the current one
261+
resp = Run({"pexpire", "key", "100000", "GT"});
262+
EXPECT_THAT(resp, IntArg(0));
263+
resp = Run({"pttl", "key"});
264+
EXPECT_THAT(resp.GetInt(), 101000);
265+
266+
// GT should apply expiry since new is greater than the current one
267+
resp = Run({"pexpire", "key", "102000", "GT"});
268+
EXPECT_THAT(resp, IntArg(1));
269+
resp = Run({"pttl", "key"});
270+
EXPECT_THAT(resp.GetInt(), 102000);
271+
272+
// GT should not apply since expiry is smaller than current
273+
resp = Run({"pexpire", "key", "101000", "GT"});
274+
EXPECT_THAT(resp, IntArg(0));
275+
resp = Run({"pttl", "key"});
276+
EXPECT_THAT(resp.GetInt(), 102000);
277+
278+
// LT should apply new expiry is smaller than current
279+
resp = Run({"pexpire", "key", "101000", "LT"});
280+
EXPECT_THAT(resp, IntArg(1));
281+
resp = Run({"pttl", "key"});
282+
EXPECT_THAT(resp.GetInt(), 101000);
283+
284+
// LT should not apply since expiry is greater than current
285+
resp = Run({"pexpire", "key", "102000", "LT"});
286+
EXPECT_THAT(resp, IntArg(0));
287+
resp = Run({"pttl", "key"});
288+
EXPECT_THAT(resp.GetInt(), 101000);
289+
}
290+
291+
TEST_F(GenericFamilyTest, PExpireAtOptions) {
292+
auto test_time_ms = TEST_current_time_ms;
293+
Run({"set", "key", "val"});
294+
// NX and XX are mutually exclusive
295+
auto resp = Run({"pexpireat", "key", "3600", "NX", "XX"});
296+
ASSERT_THAT(resp, ErrArg("NX and XX, GT or LT options at the same time are not compatible"));
297+
298+
// NX and GT are mutually exclusive
299+
resp = Run({"pexpireat", "key", "3600", "NX", "GT"});
300+
ASSERT_THAT(resp, ErrArg("NX and XX, GT or LT options at the same time are not compatible"));
301+
302+
// NX and LT are mutually exclusive
303+
resp = Run({"pexpireat", "key", "3600", "NX", "LT"});
304+
ASSERT_THAT(resp, ErrArg("NX and XX, GT or LT options at the same time are not compatible"));
305+
306+
// GT and LT are mutually exclusive
307+
resp = Run({"pexpireat", "key", "3600", "GT", "LT"});
308+
ASSERT_THAT(resp, ErrArg("GT and LT options at the same time are not compatible"));
309+
310+
// NX option should be added since there is no expiry
311+
test_time_ms = TEST_current_time_ms + 3600;
312+
resp = Run({"pexpireat", "key", absl::StrCat(test_time_ms), "NX"});
313+
EXPECT_THAT(resp, IntArg(1));
314+
EXPECT_EQ(test_time_ms, CheckedInt({"PEXPIRETIME", "key"}));
315+
316+
// running again with NX option, should not change expiry
317+
test_time_ms = TEST_current_time_ms + 42000;
318+
resp = Run({"pexpireat", "key", absl::StrCat(test_time_ms), "NX"});
319+
EXPECT_THAT(resp, IntArg(0));
320+
321+
// given a key with no expiry
322+
Run({"set", "key2", "val"});
323+
test_time_ms = TEST_current_time_ms + 404;
324+
resp = Run({"pexpireat", "key2", absl::StrCat(test_time_ms), "XX"});
325+
// XX does not apply expiry since key has no existing expiry
326+
EXPECT_THAT(resp, IntArg(0));
327+
resp = Run({"ttl", "key2"});
328+
EXPECT_THAT(resp.GetInt(), -1);
329+
330+
// set expiry to 101
331+
test_time_ms = TEST_current_time_ms + 101;
332+
resp = Run({"pexpireat", "key", absl::StrCat(test_time_ms)});
333+
EXPECT_THAT(resp, IntArg(1));
334+
335+
// GT should not apply expiry since new is not greater than the current one
336+
auto less_test_time_ms = TEST_current_time_ms + 100;
337+
resp = Run({"pexpireat", "key", absl::StrCat(less_test_time_ms), "GT"});
338+
EXPECT_THAT(resp, IntArg(0));
339+
EXPECT_EQ(test_time_ms, CheckedInt({"PEXPIRETIME", "key"}));
340+
341+
// GT should apply expiry since new is greater than the current one
342+
test_time_ms = TEST_current_time_ms + 105;
343+
resp = Run({"pexpireat", "key", absl::StrCat(test_time_ms), "GT"});
344+
EXPECT_THAT(resp, IntArg(1));
345+
EXPECT_EQ(test_time_ms, CheckedInt({"PEXPIRETIME", "key"}));
346+
347+
// LT should apply new expiry is smaller than current
348+
test_time_ms = TEST_current_time_ms + 101;
349+
resp = Run({"pexpireat", "key", absl::StrCat(test_time_ms), "LT"});
350+
EXPECT_THAT(resp, IntArg(1));
351+
EXPECT_EQ(test_time_ms, CheckedInt({"PEXPIRETIME", "key"}));
352+
353+
// LT should not apply expiry since new is not lesser than the current one
354+
auto gt_test_time_ms = TEST_current_time_ms + 102;
355+
resp = Run({"pexpireat", "key", absl::StrCat(gt_test_time_ms), "LT"});
356+
EXPECT_THAT(resp, IntArg(0));
357+
EXPECT_EQ(test_time_ms, CheckedInt({"PEXPIRETIME", "key"}));
358+
}
359+
148360
TEST_F(GenericFamilyTest, Del) {
149361
for (size_t i = 0; i < 1000; ++i) {
150362
Run({"set", StrCat("foo", i), "1"});

0 commit comments

Comments
 (0)