Simplify testing framework. Run(...) now returns RespExpr instead of vector of RespExpr

This commit is contained in:
Roman Gershman 2022-04-22 10:31:39 +03:00
parent f1c5e4d702
commit ec64f4e9e1
14 changed files with 369 additions and 309 deletions

View file

@ -57,6 +57,9 @@ void RespMatcher::DescribeTo(std::ostream* os) const {
case RespExpr::INT64:
*os << exp_str_;
break;
case RespExpr::ARRAY:
*os << "array of length " << exp_int_;
break;
default:
*os << "TBD";
break;

View file

@ -50,10 +50,6 @@ class RespTypeMatcher {
RespExpr::Type type_;
};
inline ::testing::PolymorphicMatcher<RespMatcher> StrArg(std::string_view str) {
return ::testing::MakePolymorphicMatcher(RespMatcher(str));
}
inline ::testing::PolymorphicMatcher<RespMatcher> ErrArg(std::string_view str) {
return ::testing::MakePolymorphicMatcher(RespMatcher(str, RespExpr::ERROR));
}
@ -70,14 +66,10 @@ inline ::testing::PolymorphicMatcher<RespTypeMatcher> ArgType(RespExpr::Type t)
return ::testing::MakePolymorphicMatcher(RespTypeMatcher(t));
}
inline bool operator==(const RespExpr& left, const char* s) {
inline bool operator==(const RespExpr& left, std::string_view s) {
return left.type == RespExpr::STRING && ToSV(left.GetBuf()) == s;
}
void PrintTo(const RespExpr::Vec& vec, std::ostream* os);
MATCHER_P(RespEq, val, "") {
return ::testing::ExplainMatchResult(::testing::ElementsAre(StrArg(val)), arg, result_listener);
}
} // namespace facade

View file

@ -60,7 +60,7 @@ TEST_F(RedisParserTest, Inline) {
ASSERT_EQ(RedisParser::OK, Parse(kCmd1));
EXPECT_EQ(strlen(kCmd1), consumed_);
EXPECT_THAT(args_, ElementsAre(StrArg("KEY"), StrArg("VAL")));
EXPECT_THAT(args_, ElementsAre("KEY", "VAL"));
ASSERT_EQ(RedisParser::INPUT_PENDING, Parse("KEY"));
EXPECT_EQ(3, consumed_);
@ -70,7 +70,7 @@ TEST_F(RedisParserTest, Inline) {
EXPECT_EQ(4, consumed_);
ASSERT_EQ(RedisParser::OK, Parse(" \r\n "));
EXPECT_EQ(3, consumed_);
EXPECT_THAT(args_, ElementsAre(StrArg("KEY"), StrArg("FOO"), StrArg("BAR")));
EXPECT_THAT(args_, ElementsAre("KEY", "FOO", "BAR"));
ASSERT_EQ(RedisParser::INPUT_PENDING, Parse(" 1 2"));
EXPECT_EQ(4, consumed_);
@ -78,7 +78,7 @@ TEST_F(RedisParserTest, Inline) {
EXPECT_EQ(3, consumed_);
ASSERT_EQ(RedisParser::OK, Parse("\r\n"));
EXPECT_EQ(2, consumed_);
EXPECT_THAT(args_, ElementsAre(StrArg("1"), StrArg("2"), StrArg("45")));
EXPECT_THAT(args_, ElementsAre("1", "2", "45"));
// Empty queries return RESP_OK.
EXPECT_EQ(RedisParser::OK, Parse("\r\n"));
@ -101,7 +101,7 @@ TEST_F(RedisParserTest, Multi1) {
ASSERT_EQ(RedisParser::OK, Parse("PING\r\n"));
EXPECT_EQ(6, consumed_);
EXPECT_EQ(0, parser_.parselen_hint());
EXPECT_THAT(args_, ElementsAre(StrArg("PING")));
EXPECT_THAT(args_, ElementsAre("PING"));
}
TEST_F(RedisParserTest, Multi2) {
@ -140,7 +140,7 @@ TEST_F(RedisParserTest, ClientMode) {
EXPECT_THAT(args_, ElementsAre(IntArg(-1)));
ASSERT_EQ(RedisParser::OK, Parse("+OK\r\n"));
EXPECT_THAT(args_, RespEq("OK"));
EXPECT_EQ(args_[0], "OK");
ASSERT_EQ(RedisParser::OK, Parse("-ERR foo bar\r\n"));
EXPECT_THAT(args_, ElementsAre(ErrArg("ERR foo")));
@ -152,8 +152,8 @@ TEST_F(RedisParserTest, Hierarchy) {
const char* kThirdArg = "*2\r\n$3\r\n100\r\n$3\r\n200\r\n";
string resp = absl::StrCat("*3\r\n$3\r\n900\r\n$3\r\n800\r\n", kThirdArg);
ASSERT_EQ(RedisParser::OK, Parse(resp));
EXPECT_THAT(args_, ElementsAre(StrArg("900"), StrArg("800"), ArrArg(2)));
EXPECT_THAT(*get<RespVec*>(args_[2].u), ElementsAre(StrArg("100"), StrArg("200")));
EXPECT_THAT(args_, ElementsAre("900", "800", ArrArg(2)));
EXPECT_THAT(*get<RespVec*>(args_[2].u), ElementsAre("100", "200"));
}
TEST_F(RedisParserTest, InvalidMult1) {

View file

@ -35,6 +35,10 @@ class RespExpr {
return std::get<Buffer>(u);
}
const Vec& GetVec() const {
return *std::get<Vec*>(u);
}
static const char* TypeName(Type t);
};

View file

@ -1,4 +1,4 @@
// Copyright 2021, Roman Gershman. All rights reserved.
// Copyright 2022, Roman Gershman. All rights reserved.
// See LICENSE for licensing terms.
//
@ -79,17 +79,18 @@ TEST_F(DflyEngineTest, Sds) {
}
TEST_F(DflyEngineTest, Multi) {
RespVec resp = Run({"multi"});
ASSERT_THAT(resp, RespEq("OK"));
RespExpr resp = Run({"multi"});
ASSERT_EQ(resp, "OK");
resp = Run({"get", kKey1});
ASSERT_THAT(resp, RespEq("QUEUED"));
ASSERT_EQ(resp, "QUEUED");
resp = Run({"get", kKey4});
ASSERT_THAT(resp, RespEq("QUEUED"));
ASSERT_EQ(resp, "QUEUED");
resp = Run({"exec"});
ASSERT_THAT(resp, ElementsAre(ArgType(RespExpr::NIL), ArgType(RespExpr::NIL)));
ASSERT_THAT(resp, ArrLen(2));
ASSERT_THAT(resp.GetVec(), ElementsAre(ArgType(RespExpr::NIL), ArgType(RespExpr::NIL)));
atomic_bool tx_empty = true;
@ -100,7 +101,7 @@ TEST_F(DflyEngineTest, Multi) {
EXPECT_TRUE(tx_empty);
resp = Run({"get", kKey4});
ASSERT_THAT(resp, ElementsAre(ArgType(RespExpr::NIL)));
ASSERT_THAT(resp, ArgType(RespExpr::NIL));
ASSERT_FALSE(service_->IsLocked(0, kKey1));
ASSERT_FALSE(service_->IsLocked(0, kKey4));
@ -108,71 +109,76 @@ TEST_F(DflyEngineTest, Multi) {
}
TEST_F(DflyEngineTest, MultiEmpty) {
RespVec resp = Run({"multi"});
ASSERT_THAT(resp, RespEq("OK"));
RespExpr resp = Run({"multi"});
ASSERT_EQ(resp, "OK");
resp = Run({"exec"});
ASSERT_THAT(resp[0], ArrLen(0));
ASSERT_THAT(resp, ArrLen(0));
ASSERT_FALSE(service_->IsShardSetLocked());
Run({"multi"});
ASSERT_THAT(Run({"ping", "foo"}), RespEq("QUEUED"));
EXPECT_THAT(Run({"exec"}), ElementsAre("foo"));
ASSERT_EQ(Run({"ping", "foo"}), "QUEUED");
resp = Run({"exec"});
// one cell arrays are promoted to respexpr.
EXPECT_EQ(resp, "foo");
}
TEST_F(DflyEngineTest, MultiSeq) {
RespVec resp = Run({"multi"});
ASSERT_THAT(resp, RespEq("OK"));
RespExpr resp = Run({"multi"});
ASSERT_EQ(resp, "OK");
resp = Run({"set", kKey1, absl::StrCat(1)});
ASSERT_THAT(resp, RespEq("QUEUED"));
ASSERT_EQ(resp, "QUEUED");
resp = Run({"get", kKey1});
ASSERT_THAT(resp, RespEq("QUEUED"));
ASSERT_EQ(resp, "QUEUED");
resp = Run({"mget", kKey1, kKey4});
ASSERT_THAT(resp, RespEq("QUEUED"));
ASSERT_EQ(resp, "QUEUED");
resp = Run({"exec"});
ASSERT_FALSE(service_->IsLocked(0, kKey1));
ASSERT_FALSE(service_->IsLocked(0, kKey4));
ASSERT_FALSE(service_->IsShardSetLocked());
EXPECT_THAT(resp, ElementsAre(StrArg("OK"), StrArg("1"), ArrLen(2)));
const RespExpr::Vec& arr = *get<RespVec*>(resp[2].u);
ASSERT_THAT(arr, ElementsAre("1", ArgType(RespExpr::NIL)));
ASSERT_THAT(resp, ArrLen(3));
const auto& arr = resp.GetVec();
EXPECT_THAT(arr, ElementsAre("OK", "1", ArrLen(2)));
ASSERT_THAT(arr[2].GetVec(), ElementsAre("1", ArgType(RespExpr::NIL)));
}
TEST_F(DflyEngineTest, MultiConsistent) {
auto mset_fb = pp_->at(0)->LaunchFiber([&] {
for (size_t i = 1; i < 10; ++i) {
string base = StrCat(i * 900);
RespVec resp = Run({"mset", kKey1, base, kKey4, base});
ASSERT_THAT(resp, RespEq("OK"));
RespExpr resp = Run({"mset", kKey1, base, kKey4, base});
ASSERT_EQ(resp, "OK");
}
});
auto fb = pp_->at(1)->LaunchFiber([&] {
RespVec resp = Run({"multi"});
ASSERT_THAT(resp, RespEq("OK"));
RespExpr resp = Run({"multi"});
ASSERT_EQ(resp, "OK");
this_fiber::sleep_for(1ms);
resp = Run({"get", kKey1});
ASSERT_THAT(resp, RespEq("QUEUED"));
ASSERT_EQ(resp, "QUEUED");
resp = Run({"get", kKey4});
ASSERT_THAT(resp, RespEq("QUEUED"));
ASSERT_EQ(resp, "QUEUED");
resp = Run({"mget", kKey4, kKey1});
ASSERT_THAT(resp, RespEq("QUEUED"));
ASSERT_EQ(resp, "QUEUED");
resp = Run({"exec"});
EXPECT_THAT(resp, ElementsAre(ArgType(RespExpr::STRING), ArgType(RespExpr::STRING),
ASSERT_THAT(resp, ArrLen(3));
const RespVec& resp_arr = resp.GetVec();
ASSERT_THAT(resp_arr, ElementsAre(ArgType(RespExpr::STRING), ArgType(RespExpr::STRING),
ArgType(RespExpr::ARRAY)));
ASSERT_EQ(resp[0].GetBuf(), resp[1].GetBuf());
const RespVec& arr = *get<RespVec*>(resp[2].u);
EXPECT_THAT(arr, ElementsAre(ArgType(RespExpr::STRING), ArgType(RespExpr::STRING)));
EXPECT_EQ(arr[0].GetBuf(), arr[1].GetBuf());
EXPECT_EQ(arr[0].GetBuf(), resp[0].GetBuf());
ASSERT_EQ(resp_arr[0].GetBuf(), resp_arr[1].GetBuf());
const RespVec& sub_arr = resp_arr[2].GetVec();
EXPECT_THAT(sub_arr, ElementsAre(ArgType(RespExpr::STRING), ArgType(RespExpr::STRING)));
EXPECT_EQ(sub_arr[0].GetBuf(), sub_arr[1].GetBuf());
EXPECT_EQ(sub_arr[0].GetBuf(), resp_arr[0].GetBuf());
});
mset_fb.join();
@ -184,20 +190,21 @@ TEST_F(DflyEngineTest, MultiConsistent) {
TEST_F(DflyEngineTest, MultiWeirdCommands) {
Run({"multi"});
ASSERT_THAT(Run({"eval", "return 42", "0"}), RespEq("QUEUED"));
EXPECT_THAT(Run({"exec"}), ElementsAre(IntArg(42)));
ASSERT_EQ(Run({"eval", "return 42", "0"}), "QUEUED");
EXPECT_THAT(Run({"exec"}), IntArg(42));
}
TEST_F(DflyEngineTest, MultiRename) {
RespVec resp = Run({"multi"});
ASSERT_THAT(resp, RespEq("OK"));
RespExpr resp = Run({"multi"});
ASSERT_EQ(resp, "OK");
Run({"set", kKey1, "1"});
resp = Run({"rename", kKey1, kKey4});
ASSERT_THAT(resp, RespEq("QUEUED"));
ASSERT_EQ(resp, "QUEUED");
resp = Run({"exec"});
EXPECT_THAT(resp, ElementsAre(StrArg("OK"), StrArg("OK")));
ASSERT_THAT(resp, ArrLen(2));
EXPECT_THAT(resp.GetVec(), ElementsAre("OK", "OK"));
ASSERT_FALSE(service_->IsLocked(0, kKey1));
ASSERT_FALSE(service_->IsLocked(0, kKey4));
ASSERT_FALSE(service_->IsShardSetLocked());
@ -209,11 +216,11 @@ TEST_F(DflyEngineTest, MultiHop) {
auto p1_fb = pp_->at(1)->LaunchFiber([&] {
for (int i = 0; i < 100; ++i) {
auto resp = Run({"rename", kKey1, kKey2});
ASSERT_THAT(resp, RespEq("OK"));
ASSERT_EQ(resp, "OK");
EXPECT_EQ(2, GetDebugInfo("IO1").shards_count);
resp = Run({"rename", kKey2, kKey1});
ASSERT_THAT(resp, RespEq("OK"));
ASSERT_EQ(resp, "OK");
}
});
@ -233,7 +240,7 @@ TEST_F(DflyEngineTest, MultiHop) {
TEST_F(DflyEngineTest, FlushDb) {
Run({"mset", kKey1, "1", kKey4, "2"});
auto resp = Run({"flushdb"});
ASSERT_THAT(resp, RespEq("OK"));
ASSERT_EQ(resp, "OK");
auto fb0 = pp_->at(0)->LaunchFiber([&] {
for (unsigned i = 0; i < 100; ++i) {
@ -244,8 +251,7 @@ TEST_F(DflyEngineTest, FlushDb) {
pp_->at(1)->Await([&] {
for (unsigned i = 0; i < 100; ++i) {
Run({"mset", kKey1, "1", kKey4, "2"});
auto resp = Run({"exists", kKey1, kKey4});
int64_t ival = get<int64_t>(resp[0].u);
int64_t ival = CheckedInt({"exists", kKey1, kKey4});
ASSERT_TRUE(ival == 0 || ival == 2) << i << " " << ival;
}
});
@ -259,21 +265,21 @@ TEST_F(DflyEngineTest, FlushDb) {
TEST_F(DflyEngineTest, Eval) {
auto resp = Run({"incrby", "foo", "42"});
EXPECT_THAT(resp[0], IntArg(42));
EXPECT_THAT(resp, IntArg(42));
resp = Run({"eval", "return redis.call('get', 'foo')", "0"});
EXPECT_THAT(resp[0], ErrArg("undeclared"));
EXPECT_THAT(resp, ErrArg("undeclared"));
resp = Run({"eval", "return redis.call('get', 'foo')", "1", "bar"});
EXPECT_THAT(resp[0], ErrArg("undeclared"));
EXPECT_THAT(resp, ErrArg("undeclared"));
ASSERT_FALSE(service_->IsLocked(0, "foo"));
resp = Run({"eval", "return redis.call('get', 'foo')", "1", "foo"});
EXPECT_THAT(resp[0], StrArg("42"));
EXPECT_THAT(resp, "42");
resp = Run({"eval", "return redis.call('get', KEYS[1])", "1", "foo"});
EXPECT_THAT(resp[0], StrArg("42"));
EXPECT_THAT(resp, "42");
ASSERT_FALSE(service_->IsLocked(0, "foo"));
ASSERT_FALSE(service_->IsShardSetLocked());
@ -281,30 +287,31 @@ TEST_F(DflyEngineTest, Eval) {
TEST_F(DflyEngineTest, EvalResp) {
auto resp = Run({"eval", "return 43", "0"});
EXPECT_THAT(resp[0], IntArg(43));
EXPECT_THAT(resp, IntArg(43));
resp = Run({"eval", "return {5, 'foo', 17.5}", "0"});
EXPECT_THAT(resp, ElementsAre(IntArg(5), "foo", "17.5"));
ASSERT_THAT(resp, ArrLen(3));
EXPECT_THAT(resp.GetVec(), ElementsAre(IntArg(5), "foo", "17.5"));
}
TEST_F(DflyEngineTest, EvalSha) {
auto resp = Run({"script", "load", "return 5"});
EXPECT_THAT(resp, ElementsAre(ArgType(RespExpr::STRING)));
EXPECT_THAT(resp, ArgType(RespExpr::STRING));
string sha{ToSV(resp[0].GetBuf())};
string sha{ToSV(resp.GetBuf())};
resp = Run({"evalsha", sha, "0"});
EXPECT_THAT(resp[0], IntArg(5));
EXPECT_THAT(resp, IntArg(5));
resp = Run({"script", "load", " return 5 "});
EXPECT_THAT(resp, ElementsAre(StrArg(sha)));
EXPECT_EQ(resp, sha);
absl::AsciiStrToUpper(&sha);
resp = Run({"evalsha", sha, "0"});
EXPECT_THAT(resp[0], IntArg(5));
EXPECT_THAT(resp, IntArg(5));
resp = Run({"evalsha", "foobar", "0"});
EXPECT_THAT(resp[0], ErrArg("No matching"));
EXPECT_THAT(resp, ErrArg("No matching"));
}
TEST_F(DflyEngineTest, Memcache) {
@ -345,7 +352,7 @@ TEST_F(DflyEngineTest, LimitMemory) {
string blob(128, 'a');
for (size_t i = 0; i < 10000; ++i) {
auto resp = Run({"set", absl::StrCat(blob, i), blob});
ASSERT_THAT(resp, RespEq("OK"));
ASSERT_EQ(resp, "OK");
}
}

View file

@ -29,26 +29,26 @@ TEST_F(GenericFamilyTest, Expire) {
Run({"set", "key", "val"});
auto resp = Run({"expire", "key", "1"});
EXPECT_THAT(resp[0], IntArg(1));
EXPECT_THAT(resp, IntArg(1));
UpdateTime(expire_now_ + 1000);
resp = Run({"get", "key"});
EXPECT_THAT(resp, ElementsAre(ArgType(RespExpr::NIL)));
EXPECT_THAT(resp, ArgType(RespExpr::NIL));
Run({"set", "key", "val"});
resp = Run({"pexpireat", "key", absl::StrCat(expire_now_ + 2000)});
EXPECT_THAT(resp[0], IntArg(1));
EXPECT_THAT(resp, IntArg(1));
// override
resp = Run({"pexpireat", "key", absl::StrCat(expire_now_ + 3000)});
EXPECT_THAT(resp[0], IntArg(1));
EXPECT_THAT(resp, IntArg(1));
UpdateTime(expire_now_ + 2999);
resp = Run({"get", "key"});
EXPECT_THAT(resp[0], "val");
EXPECT_THAT(resp, "val");
UpdateTime(expire_now_ + 3000);
resp = Run({"get", "key"});
EXPECT_THAT(resp[0], ArgType(RespExpr::NIL));
EXPECT_THAT(resp, ArgType(RespExpr::NIL));
}
TEST_F(GenericFamilyTest, Del) {
@ -88,28 +88,28 @@ TEST_F(GenericFamilyTest, TTL) {
TEST_F(GenericFamilyTest, Exists) {
Run({"mset", "x", "0", "y", "1"});
auto resp = Run({"exists", "x", "y", "x"});
EXPECT_THAT(resp[0], IntArg(3));
EXPECT_THAT(resp, IntArg(3));
}
TEST_F(GenericFamilyTest, Rename) {
RespVec resp;
RespExpr resp;
string b_val(32, 'b');
string x_val(32, 'x');
resp = Run({"mset", "x", x_val, "b", b_val});
ASSERT_THAT(resp, RespEq("OK"));
ASSERT_EQ(resp, "OK");
ASSERT_EQ(2, last_cmd_dbg_info_.shards_count);
resp = Run({"rename", "z", "b"});
ASSERT_THAT(resp[0], ErrArg("no such key"));
ASSERT_THAT(resp, ErrArg("no such key"));
resp = Run({"rename", "x", "b"});
ASSERT_THAT(resp, RespEq("OK"));
ASSERT_EQ(resp, "OK");
int64_t val = CheckedInt({"get", "x"});
ASSERT_EQ(kint64min, val); // does not exist
ASSERT_THAT(Run({"get", "b"}), RespEq(x_val)); // swapped.
ASSERT_EQ(Run({"get", "b"}), x_val); // swapped.
EXPECT_EQ(CheckedInt({"exists", "x", "b"}), 1);
@ -118,7 +118,7 @@ TEST_F(GenericFamilyTest, Rename) {
for (size_t i = 0; i < 200; ++i) {
int j = i % 2;
auto resp = Run({"rename", keys[j], keys[1 - j]});
ASSERT_THAT(resp, RespEq("OK"));
ASSERT_EQ(resp, "OK");
}
});
@ -136,7 +136,7 @@ TEST_F(GenericFamilyTest, Rename) {
TEST_F(GenericFamilyTest, RenameNonString) {
EXPECT_EQ(1, CheckedInt({"lpush", "x", "elem"}));
auto resp = Run({"rename", "x", "b"});
ASSERT_THAT(resp, RespEq("OK"));
ASSERT_EQ(resp, "OK");
ASSERT_EQ(2, last_cmd_dbg_info_.shards_count);
EXPECT_EQ(0, CheckedInt({"del", "x"}));
@ -149,13 +149,13 @@ TEST_F(GenericFamilyTest, RenameBinary) {
Run({"set", kKey1, "bar"});
Run({"rename", kKey1, kKey2});
EXPECT_THAT(Run({"get", kKey1}), ElementsAre(ArgType(RespExpr::NIL)));
EXPECT_THAT(Run({"get", kKey2}), RespEq("bar"));
EXPECT_THAT(Run({"get", kKey1}), ArgType(RespExpr::NIL));
EXPECT_EQ(Run({"get", kKey2}), "bar");
}
using testing::AnyOf;
using testing::Each;
using testing::StartsWith;
using testing::AnyOf;
TEST_F(GenericFamilyTest, Scan) {
for (unsigned i = 0; i < 10; ++i)
@ -171,13 +171,13 @@ TEST_F(GenericFamilyTest, Scan) {
Run({"zadd", absl::StrCat("zset", i), "0", "bar"});
auto resp = Run({"scan", "0", "count", "20", "type", "string"});
EXPECT_EQ(2, resp.size());
auto vec = StrArray(resp[1]);
EXPECT_THAT(resp, ArrLen(2));
auto vec = StrArray(resp.GetVec()[1]);
EXPECT_GT(vec.size(), 10);
EXPECT_THAT(vec, Each(AnyOf(StartsWith("str"), StartsWith("key"))));
resp = Run({"scan", "0", "count", "20", "match", "zset*"});
vec = StrArray(resp[1]);
vec = StrArray(resp.GetVec()[1]);
EXPECT_EQ(10, vec.size());
EXPECT_THAT(vec, Each(StartsWith("zset")));
}

View file

@ -39,9 +39,9 @@ TEST_F(HSetFamilyTest, Hash) {
TEST_F(HSetFamilyTest, Basic) {
auto resp = Run({"hset", "x", "a"});
EXPECT_THAT(resp[0], ErrArg("wrong number"));
EXPECT_THAT(resp, ErrArg("wrong number"));
EXPECT_THAT(Run({"HSET", "hs", "key1", "val1", "key2"}), ElementsAre(ErrArg("wrong number")));
EXPECT_THAT(Run({"HSET", "hs", "key1", "val1", "key2"}), ErrArg("wrong number"));
EXPECT_EQ(1, CheckedInt({"hset", "x", "a", "b"}));
EXPECT_EQ(1, CheckedInt({"hlen", "x"}));
@ -57,7 +57,7 @@ TEST_F(HSetFamilyTest, Basic) {
EXPECT_EQ(2, CheckedInt({"hset", "y", "a", "c", "d", "e"}));
EXPECT_EQ(2, CheckedInt({"hdel", "y", "a", "d"}));
EXPECT_THAT(Run({"hdel", "nokey", "a"}), ElementsAre(IntArg(0)));
EXPECT_THAT(Run({"hdel", "nokey", "a"}), IntArg(0));
}
TEST_F(HSetFamilyTest, HSet) {
@ -72,37 +72,42 @@ TEST_F(HSetFamilyTest, HSet) {
TEST_F(HSetFamilyTest, Get) {
auto resp = Run({"hset", "x", "a", "1", "b", "2", "c", "3"});
EXPECT_THAT(resp[0], IntArg(3));
EXPECT_THAT(resp, IntArg(3));
resp = Run({"hmget", "unkwn", "a", "c"});
EXPECT_THAT(resp, ElementsAre(ArgType(RespExpr::NIL), ArgType(RespExpr::NIL)));
ASSERT_THAT(resp, ArgType(RespExpr::ARRAY));
EXPECT_THAT(resp.GetVec(), ElementsAre(ArgType(RespExpr::NIL), ArgType(RespExpr::NIL)));
resp = Run({"hkeys", "x"});
EXPECT_THAT(resp, UnorderedElementsAre("a", "b", "c"));
ASSERT_THAT(resp, ArgType(RespExpr::ARRAY));
EXPECT_THAT(resp.GetVec(), UnorderedElementsAre("a", "b", "c"));
resp = Run({"hvals", "x"});
EXPECT_THAT(resp, UnorderedElementsAre("1", "2", "3"));
ASSERT_THAT(resp, ArgType(RespExpr::ARRAY));
EXPECT_THAT(resp.GetVec(), UnorderedElementsAre("1", "2", "3"));
resp = Run({"hmget", "x", "a", "c", "d"});
EXPECT_THAT(resp, ElementsAre("1", "3", ArgType(RespExpr::NIL)));
ASSERT_THAT(resp, ArgType(RespExpr::ARRAY));
EXPECT_THAT(resp.GetVec(), ElementsAre("1", "3", ArgType(RespExpr::NIL)));
resp = Run({"hgetall", "x"});
EXPECT_THAT(resp, ElementsAre("a", "1", "b", "2", "c", "3"));
ASSERT_THAT(resp, ArgType(RespExpr::ARRAY));
EXPECT_THAT(resp.GetVec(), ElementsAre("a", "1", "b", "2", "c", "3"));
}
TEST_F(HSetFamilyTest, HSetNx) {
EXPECT_EQ(1, CheckedInt({"hsetnx", "key", "field", "val"}));
EXPECT_THAT(Run({"hget", "key", "field"}), RespEq("val"));
EXPECT_EQ(Run({"hget", "key", "field"}), "val");
EXPECT_EQ(0, CheckedInt({"hsetnx", "key", "field", "val2"}));
EXPECT_THAT(Run({"hget", "key", "field"}), RespEq("val"));
EXPECT_EQ(Run({"hget", "key", "field"}), "val");
EXPECT_EQ(1, CheckedInt({"hsetnx", "key", "field2", "val2"}));
EXPECT_THAT(Run({"hget", "key", "field2"}), RespEq("val2"));
EXPECT_EQ(Run({"hget", "key", "field2"}), "val2");
// check dict path
EXPECT_EQ(0, CheckedInt({"hsetnx", "key", "field2", string(512, 'a')}));
EXPECT_THAT(Run({"hget", "key", "field2"}), RespEq("val2"));
EXPECT_EQ(Run({"hget", "key", "field2"}), "val2");
}
TEST_F(HSetFamilyTest, HIncr) {
@ -110,7 +115,7 @@ TEST_F(HSetFamilyTest, HIncr) {
Run({"hset", "key", "a", " 1"});
auto resp = Run({"hincrby", "key", "a", "10"});
EXPECT_THAT(resp[0], ErrArg("hash value is not an integer"));
EXPECT_THAT(resp, ErrArg("hash value is not an integer"));
}
} // namespace dfly

View file

@ -38,46 +38,48 @@ const char kKey3[] = "c";
TEST_F(ListFamilyTest, Basic) {
auto resp = Run({"lpush", kKey1, "1"});
EXPECT_THAT(resp[0], IntArg(1));
EXPECT_THAT(resp, IntArg(1));
resp = Run({"lpush", kKey2, "2"});
ASSERT_THAT(resp[0], IntArg(1));
ASSERT_THAT(resp, IntArg(1));
resp = Run({"llen", kKey1});
ASSERT_THAT(resp[0], IntArg(1));
ASSERT_THAT(resp, IntArg(1));
}
TEST_F(ListFamilyTest, Expire) {
auto resp = Run({"lpush", kKey1, "1"});
EXPECT_THAT(resp[0], IntArg(1));
EXPECT_THAT(resp, IntArg(1));
resp = Run({"expire", kKey1, "1"});
EXPECT_THAT(resp[0], IntArg(1));
EXPECT_THAT(resp, IntArg(1));
UpdateTime(expire_now_ + 1000);
resp = Run({"lpush", kKey1, "1"});
EXPECT_THAT(resp[0], IntArg(1));
EXPECT_THAT(resp, IntArg(1));
}
TEST_F(ListFamilyTest, BLPopUnblocking) {
auto resp = Run({"lpush", kKey1, "1"});
EXPECT_THAT(resp[0], IntArg(1));
EXPECT_THAT(resp, IntArg(1));
resp = Run({"lpush", kKey2, "2"});
ASSERT_THAT(resp, ElementsAre(IntArg(1)));
ASSERT_THAT(resp, IntArg(1));
resp = Run({"blpop", kKey1, kKey2}); // missing "0" delimiter.
ASSERT_THAT(resp[0], ErrArg("timeout is not a float"));
ASSERT_THAT(resp, ErrArg("timeout is not a float"));
resp = Run({"blpop", kKey1, kKey2, "0"});
ASSERT_EQ(2, GetDebugInfo().shards_count);
EXPECT_THAT(resp, ElementsAre(kKey1, "1"));
ASSERT_THAT(resp, ArrLen(2));
EXPECT_THAT(resp.GetVec(), ElementsAre(kKey1, "1"));
resp = Run({"blpop", kKey1, kKey2, "0"});
EXPECT_THAT(resp, ElementsAre(kKey2, "2"));
ASSERT_THAT(resp, ArrLen(2));
EXPECT_THAT(resp.GetVec(), ElementsAre(kKey2, "2"));
Run({"set", "z", "1"});
resp = Run({"blpop", "z", "0"});
ASSERT_THAT(resp[0], ErrArg("WRONGTYPE "));
ASSERT_THAT(resp, ErrArg("WRONGTYPE "));
ASSERT_FALSE(IsLocked(0, "x"));
ASSERT_FALSE(IsLocked(0, "y"));
@ -85,7 +87,7 @@ TEST_F(ListFamilyTest, BLPopUnblocking) {
}
TEST_F(ListFamilyTest, BLPopBlocking) {
RespVec resp0, resp1;
RespExpr resp0, resp1;
// Run the fiber at creation.
auto fb0 = pp_->at(0)->LaunchFiber(fibers::launch::dispatch, [&] {
@ -110,16 +112,16 @@ TEST_F(ListFamilyTest, BLPopBlocking) {
int64_t epoch0 = GetDebugInfo("IO0").clock;
int64_t epoch1 = GetDebugInfo("IO1").clock;
ASSERT_LT(epoch0, epoch1);
EXPECT_THAT(resp0, ElementsAre("x", "1"));
ASSERT_THAT(resp0, ArrLen(2));
EXPECT_THAT(resp0.GetVec(), ElementsAre("x", "1"));
ASSERT_FALSE(IsLocked(0, "x"));
}
TEST_F(ListFamilyTest, BLPopMultiple) {
RespVec resp0, resp1;
RespExpr resp0, resp1;
resp0 = Run({"blpop", kKey1, kKey2, "0.01"}); // timeout
EXPECT_THAT(resp0, ElementsAre(ArgType(RespExpr::NIL_ARRAY)));
EXPECT_THAT(resp0, ArgType(RespExpr::NIL_ARRAY));
ASSERT_EQ(2, GetDebugInfo().shards_count);
ASSERT_FALSE(IsLocked(0, kKey1));
@ -131,65 +133,74 @@ TEST_F(ListFamilyTest, BLPopMultiple) {
pp_->at(1)->Await([&] { Run({"lpush", kKey1, "1", "2", "3"}); });
fb1.join();
EXPECT_THAT(resp0, ElementsAre(StrArg(kKey1), StrArg("3")));
ASSERT_THAT(resp0, ArrLen(2));
EXPECT_THAT(resp0.GetVec(), ElementsAre(kKey1, "3"));
ASSERT_FALSE(IsLocked(0, kKey1));
ASSERT_FALSE(IsLocked(0, kKey2));
ess_->RunBriefInParallel([](EngineShard* es) { ASSERT_FALSE(es->HasAwakedTransaction()); });
}
TEST_F(ListFamilyTest, BLPopTimeout) {
RespVec resp = Run({"blpop", kKey1, kKey2, kKey3, "0.01"});
EXPECT_THAT(resp[0], ArgType(RespExpr::NIL_ARRAY));
RespExpr resp = Run({"blpop", kKey1, kKey2, kKey3, "0.01"});
EXPECT_THAT(resp, ArgType(RespExpr::NIL_ARRAY));
EXPECT_EQ(3, GetDebugInfo().shards_count);
ASSERT_FALSE(service_->IsLocked(0, kKey1));
// Under Multi
resp = Run({"multi"});
ASSERT_THAT(resp, RespEq("OK"));
ASSERT_EQ(resp, "OK");
Run({"blpop", kKey1, "0"});
resp = Run({"exec"});
EXPECT_THAT(resp, ElementsAre(ArgType(RespExpr::NIL_ARRAY)));
EXPECT_THAT(resp, ArgType(RespExpr::NIL_ARRAY));
ASSERT_FALSE(service_->IsLocked(0, kKey1));
}
TEST_F(ListFamilyTest, LRem) {
auto resp = Run({"rpush", kKey1, "a", "b", "a", "c"});
ASSERT_THAT(resp, ElementsAre(IntArg(4)));
ASSERT_THAT(resp, IntArg(4));
resp = Run({"lrem", kKey1, "2", "a"});
ASSERT_THAT(resp, ElementsAre(IntArg(2)));
ASSERT_THAT(Run({"lrange", kKey1, "0", "1"}), ElementsAre("b", "c"));
ASSERT_THAT(resp, IntArg(2));
resp = Run({"lrange", kKey1, "0", "1"});
ASSERT_THAT(resp, ArrLen(2));
ASSERT_THAT(resp.GetVec(), ElementsAre("b", "c"));
}
TEST_F(ListFamilyTest, LTrim) {
Run({"rpush", kKey1, "a", "b", "c", "d"});
ASSERT_THAT(Run({"ltrim", kKey1, "-2", "-1"}), RespEq("OK"));
ASSERT_THAT(Run({"lrange", kKey1, "0", "1"}), ElementsAre("c", "d"));
ASSERT_THAT(Run({"ltrim", kKey1, "0", "0"}), RespEq("OK"));
ASSERT_THAT(Run({"lrange", kKey1, "0", "1"}), ElementsAre("c"));
ASSERT_EQ(Run({"ltrim", kKey1, "-2", "-1"}), "OK");
auto resp = Run({"lrange", kKey1, "0", "1"});
ASSERT_THAT(resp, ArrLen(2));
ASSERT_THAT(resp.GetVec(), ElementsAre("c", "d"));
ASSERT_EQ(Run({"ltrim", kKey1, "0", "0"}), "OK");
ASSERT_EQ(Run({"lrange", kKey1, "0", "1"}), "c");
}
TEST_F(ListFamilyTest, LRange) {
auto resp = Run({"lrange", kKey1, "0", "5"});
ASSERT_THAT(resp[0], ArrLen(0));
ASSERT_THAT(resp, ArrLen(0));
Run({"rpush", kKey1, "0", "1", "2"});
resp = Run({"lrange", kKey1, "-2", "-1"});
ASSERT_THAT(resp, ElementsAre("1", "2"));
ASSERT_THAT(resp, ArrLen(2));
ASSERT_THAT(resp.GetVec(), ElementsAre("1", "2"));
}
TEST_F(ListFamilyTest, Lset) {
Run({"rpush", kKey1, "0", "1", "2"});
ASSERT_THAT(Run({"lset", kKey1, "0", "bar"}), RespEq("OK"));
ASSERT_THAT(Run({"lpop", kKey1}), RespEq("bar"));
ASSERT_THAT(Run({"lset", kKey1, "-1", "foo"}), RespEq("OK"));
ASSERT_THAT(Run({"rpop", kKey1}), RespEq("foo"));
ASSERT_EQ(Run({"lset", kKey1, "0", "bar"}), "OK");
ASSERT_EQ(Run({"lpop", kKey1}), "bar");
ASSERT_EQ(Run({"lset", kKey1, "-1", "foo"}), "OK");
ASSERT_EQ(Run({"rpop", kKey1}), "foo");
Run({"rpush", kKey2, "a"});
ASSERT_THAT(Run({"lset", kKey2, "1", "foo"}), ElementsAre(ErrArg("index out of range")));
ASSERT_THAT(Run({"lset", kKey2, "1", "foo"}), ErrArg("index out of range"));
}
TEST_F(ListFamilyTest, BLPopSerialize) {
RespVec blpop_resp;
RespExpr blpop_resp;
auto pop_fb = pp_->at(0)->LaunchFiber(fibers::launch::dispatch, [&] {
blpop_resp = Run({"blpop", kKey1, kKey2, kKey3, "0"});
@ -202,11 +213,10 @@ TEST_F(ListFamilyTest, BLPopSerialize) {
LOG(INFO) << "Starting multi";
TxClock cl1, cl2;
unsigned key1_len1 = 0, key1_len2 = 0;
auto p1_fb = pp_->at(1)->LaunchFiber([&] {
auto resp = Run({"multi"}); // We use multi to assign ts to lpush.
ASSERT_THAT(resp, RespEq("OK"));
ASSERT_EQ(resp, "OK");
Run({"lpush", kKey1, "A"});
resp = Run({"exec"});
@ -214,20 +224,20 @@ TEST_F(ListFamilyTest, BLPopSerialize) {
// In any case it must be that between 2 invocations of lpush (wrapped in multi)
// blpop will be triggerred and it will empty the list again. Hence, in any case
// lpush kKey1 here and below should return 1.
EXPECT_THAT(resp, ElementsAre(IntArg(1)));
key1_len1 = get<int64_t>(resp[0].u);
ASSERT_THAT(resp, IntArg(1));
cl1 = GetDebugInfo("IO1").clock;
LOG(INFO) << "push1 ts: " << cl1;
});
auto p2_fb = pp_->at(2)->LaunchFiber([&] {
auto resp = Run({"multi"}); // We use multi to assign ts to lpush.
ASSERT_THAT(resp, RespEq("OK"));
ASSERT_EQ(resp, "OK");
Run({"lpush", kKey1, "B"});
Run({"lpush", kKey2, "C"});
resp = Run({"exec"});
EXPECT_THAT(resp, ElementsAre(IntArg(1), IntArg(1)));
key1_len2 = get<int64_t>(resp[0].u);
ASSERT_THAT(resp, ArrLen(2));
EXPECT_THAT(resp.GetVec(), ElementsAre(IntArg(1), IntArg(1)));
cl2 = GetDebugInfo("IO2").clock;
LOG(INFO) << "push2 ts: " << cl2;
});
@ -236,17 +246,19 @@ TEST_F(ListFamilyTest, BLPopSerialize) {
p2_fb.join();
pop_fb.join();
EXPECT_THAT(blpop_resp, ElementsAre(StrArg(kKey1), ArgType(RespExpr::STRING)));
ASSERT_THAT(blpop_resp, ArrLen(2));
auto resp_arr = blpop_resp.GetVec();
EXPECT_THAT(resp_arr, ElementsAre(kKey1, ArgType(RespExpr::STRING)));
if (cl2 < cl1) {
EXPECT_EQ(blpop_resp[1], "B");
EXPECT_EQ(resp_arr[1], "B");
} else {
EXPECT_EQ(blpop_resp[1], "A");
EXPECT_EQ(resp_arr[1], "A");
}
}
TEST_F(ListFamilyTest, WrongTypeDoesNotWake) {
RespVec blpop_resp;
RespExpr blpop_resp;
auto pop_fb = pp_->at(0)->LaunchFiber(fibers::launch::dispatch, [&] {
blpop_resp = Run({"blpop", kKey1, "0"});
@ -262,7 +274,7 @@ TEST_F(ListFamilyTest, WrongTypeDoesNotWake) {
Run({"set", kKey1, "foo"});
auto resp = Run({"exec"});
EXPECT_THAT(resp, ElementsAre(IntArg(1), "OK"));
EXPECT_THAT(resp.GetVec(), ElementsAre(IntArg(1), "OK"));
Run({"del", kKey1});
Run({"lpush", kKey1, "B"});
@ -270,11 +282,12 @@ TEST_F(ListFamilyTest, WrongTypeDoesNotWake) {
p1_fb.join();
pop_fb.join();
EXPECT_THAT(blpop_resp, ElementsAre(kKey1, "B"));
ASSERT_THAT(blpop_resp, ArrLen(2));
EXPECT_THAT(blpop_resp.GetVec(), ElementsAre(kKey1, "B"));
}
TEST_F(ListFamilyTest, BPopSameKeyTwice) {
RespVec blpop_resp;
RespExpr blpop_resp;
auto pop_fb = pp_->at(0)->LaunchFiber(fibers::launch::dispatch, [&] {
blpop_resp = Run({"blpop", kKey1, kKey2, kKey2, kKey1, "0"});
@ -288,7 +301,9 @@ TEST_F(ListFamilyTest, BPopSameKeyTwice) {
EXPECT_EQ(1, CheckedInt({"lpush", kKey1, "bar"}));
});
pop_fb.join();
EXPECT_THAT(blpop_resp, ElementsAre(kKey1, "bar"));
ASSERT_THAT(blpop_resp, ArrLen(2));
EXPECT_THAT(blpop_resp.GetVec(), ElementsAre(kKey1, "bar"));
pop_fb = pp_->at(0)->LaunchFiber(fibers::launch::dispatch, [&] {
blpop_resp = Run({"blpop", kKey1, kKey2, kKey2, kKey1, "0"});
@ -302,11 +317,13 @@ TEST_F(ListFamilyTest, BPopSameKeyTwice) {
EXPECT_EQ(1, CheckedInt({"lpush", kKey2, "bar"}));
});
pop_fb.join();
EXPECT_THAT(blpop_resp, ElementsAre(kKey2, "bar"));
ASSERT_THAT(blpop_resp, ArrLen(2));
EXPECT_THAT(blpop_resp.GetVec(), ElementsAre(kKey2, "bar"));
}
TEST_F(ListFamilyTest, BPopRename) {
RespVec blpop_resp;
RespExpr blpop_resp;
Run({"exists", kKey1, kKey2});
ASSERT_EQ(2, GetDebugInfo().shards_count);
@ -324,7 +341,9 @@ TEST_F(ListFamilyTest, BPopRename) {
Run({"rename", "a", kKey1});
});
pop_fb.join();
EXPECT_THAT(blpop_resp, ElementsAre(kKey1, "bar"));
ASSERT_THAT(blpop_resp, ArrLen(2));
EXPECT_THAT(blpop_resp.GetVec(), ElementsAre(kKey1, "bar"));
}
} // namespace dfly

View file

@ -83,11 +83,15 @@ TEST_F(RdbTest, LoadSmall6) {
auto ec = loader.Load(&fs);
CHECK(!ec);
auto resp = Run({"scan", "0"});
EXPECT_THAT(StrArray(resp[1]),
ASSERT_THAT(resp, ArrLen(2));
EXPECT_THAT(StrArray(resp.GetVec()[1]),
UnorderedElementsAre("list1", "hset_zl", "list2", "zset_sl", "intset", "set1",
"zset_zl", "hset_ht", "intkey", "strkey"));
resp = Run({"smembers", "intset"});
EXPECT_THAT(resp, UnorderedElementsAre("111", "222", "1234", "3333", "4444", "67899", "76554"));
ASSERT_THAT(resp, ArgType(RespExpr::ARRAY));
EXPECT_THAT(resp.GetVec(),
UnorderedElementsAre("111", "222", "1234", "3333", "4444", "67899", "76554"));
// TODO: when we implement PEXPIRETIME we will be able to do it directly.
int ttl = CheckedInt({"ttl", "set1"}); // should expire at 1747008000.

View file

@ -23,23 +23,23 @@ class SetFamilyTest : public BaseFamilyTest {
TEST_F(SetFamilyTest, SAdd) {
auto resp = Run({"sadd", "x", "1", "2", "3"});
EXPECT_THAT(resp[0], IntArg(3));
EXPECT_THAT(resp, IntArg(3));
resp = Run({"sadd", "x", "2", "3"});
EXPECT_THAT(resp[0], IntArg(0));
EXPECT_THAT(resp, IntArg(0));
Run({"set", "a", "foo"});
resp = Run({"sadd", "a", "b"});
EXPECT_THAT(resp[0], ErrArg("WRONGTYPE "));
EXPECT_THAT(resp, ErrArg("WRONGTYPE "));
resp = Run({"type", "x"});
EXPECT_THAT(resp, RespEq("set"));
EXPECT_EQ(resp, "set");
}
TEST_F(SetFamilyTest, IntConv) {
auto resp = Run({"sadd", "x", "134"});
EXPECT_THAT(resp[0], IntArg(1));
EXPECT_THAT(resp, IntArg(1));
resp = Run({"sadd", "x", "abc"});
EXPECT_THAT(resp[0], IntArg(1));
EXPECT_THAT(resp, IntArg(1));
resp = Run({"sadd", "x", "134"});
EXPECT_THAT(resp[0], IntArg(0));
EXPECT_THAT(resp, IntArg(0));
}
TEST_F(SetFamilyTest, SUnionStore) {
@ -47,25 +47,29 @@ TEST_F(SetFamilyTest, SUnionStore) {
Run({"sadd", "c", "10", "11"});
Run({"set", "a", "foo"});
resp = Run({"sunionstore", "a", "b", "c"});
EXPECT_THAT(resp[0], IntArg(5));
EXPECT_THAT(resp, IntArg(5));
resp = Run({"type", "a"});
ASSERT_THAT(resp, RespEq("set"));
ASSERT_EQ(resp, "set");
resp = Run({"smembers", "a"});
EXPECT_THAT(resp, UnorderedElementsAre("11", "10", "1", "2", "3"));
ASSERT_THAT(resp, ArgType(RespExpr::ARRAY));
EXPECT_THAT(resp.GetVec(), UnorderedElementsAre("11", "10", "1", "2", "3"));
}
TEST_F(SetFamilyTest, SDiff) {
auto resp = Run({"sadd", "b", "1", "2", "3"});
Run({"sadd", "c", "10", "11"});
Run({"set", "a", "foo"});
resp = Run({"sdiff", "b", "c"});
EXPECT_THAT(resp, UnorderedElementsAre("1", "2", "3"));
ASSERT_THAT(resp, ArgType(RespExpr::ARRAY));
EXPECT_THAT(resp.GetVec(), UnorderedElementsAre("1", "2", "3"));
resp = Run({"sdiffstore", "a", "b", "c"});
EXPECT_THAT(resp[0], IntArg(3));
EXPECT_THAT(resp, IntArg(3));
Run({"set", "str", "foo"});
EXPECT_THAT(Run({"sdiff", "b", "str"}), ElementsAre(ErrArg("WRONGTYPE ")));
EXPECT_THAT(Run({"sdiff", "b", "str"}), ErrArg("WRONGTYPE "));
Run({"sadd", "bar", "x", "a", "b", "c"});
Run({"sadd", "foo", "c"});
@ -77,50 +81,53 @@ TEST_F(SetFamilyTest, SInter) {
auto resp = Run({"sadd", "a", "1", "2", "3", "4"});
Run({"sadd", "b", "3", "5", "6", "2"});
resp = Run({"sinterstore", "d", "a", "b"});
EXPECT_THAT(resp[0], IntArg(2));
EXPECT_THAT(resp, IntArg(2));
resp = Run({"smembers", "d"});
EXPECT_THAT(resp, UnorderedElementsAre("3", "2"));
ASSERT_THAT(resp, ArgType(RespExpr::ARRAY));
EXPECT_THAT(resp.GetVec(), UnorderedElementsAre("3", "2"));
Run({"set", "y", ""});
resp = Run({"sinter", "x", "y"});
ASSERT_EQ(1, GetDebugInfo("IO0").shards_count);
EXPECT_THAT(resp, ElementsAre(ErrArg("WRONGTYPE Operation against a key")));
EXPECT_THAT(resp, ErrArg("WRONGTYPE Operation against a key"));
}
TEST_F(SetFamilyTest, SMove) {
auto resp = Run({"sadd", "a", "1", "2", "3", "4"});
Run({"sadd", "b", "3", "5", "6", "2"});
resp = Run({"smove", "a", "b", "1"});
EXPECT_THAT(resp[0], IntArg(1));
EXPECT_THAT(resp, IntArg(1));
Run({"sadd", "x", "a", "b", "c"});
Run({"sadd", "y", "c"});
EXPECT_THAT(Run({"smove", "x", "y", "c"}), ElementsAre(IntArg(1)));
EXPECT_THAT(Run({"smove", "x", "y", "c"}), IntArg(1));
}
TEST_F(SetFamilyTest, SPop) {
auto resp = Run({"sadd", "x", "1", "2", "3"});
resp = Run({"spop", "x", "3"});
EXPECT_THAT(resp, UnorderedElementsAre("1", "2", "3"));
ASSERT_THAT(resp, ArgType(RespExpr::ARRAY));
EXPECT_THAT(resp.GetVec(), UnorderedElementsAre("1", "2", "3"));
resp = Run({"type", "x"});
EXPECT_THAT(resp, RespEq("none"));
EXPECT_EQ(resp, "none");
Run({"sadd", "x", "1", "2", "3"});
resp = Run({"spop", "x", "2"});
EXPECT_THAT(resp, IsSubsetOf({"1", "2", "3"}));
EXPECT_EQ(2, resp.size());
ASSERT_THAT(resp, ArrLen(2));
EXPECT_THAT(resp.GetVec(), IsSubsetOf({"1", "2", "3"}));
resp = Run({"scard", "x"});
EXPECT_THAT(resp[0], IntArg(1));
EXPECT_THAT(resp, IntArg(1));
Run({"sadd", "y", "a", "b", "c"});
resp = Run({"spop", "y", "1"});
EXPECT_THAT(resp, IsSubsetOf({"a", "b", "c"}));
EXPECT_EQ(1, resp.size());
EXPECT_THAT(resp, ArgType(RespExpr::STRING));
EXPECT_THAT(resp, testing::AnyOf("a", "b", "c"));
resp = Run({"smembers", "y"});
EXPECT_THAT(resp, IsSubsetOf({"a", "b", "c"}));
EXPECT_EQ(2, resp.size());
ASSERT_THAT(resp, ArrLen(2));
EXPECT_THAT(resp.GetVec(), IsSubsetOf({"a", "b", "c"}));
}
} // namespace dfly

View file

@ -26,83 +26,98 @@ class StringFamilyTest : public BaseFamilyTest {
protected:
};
vector<int64_t> ToIntArr(const RespExpr& e) {
vector<int64_t> res;
CHECK_EQ(e.type, RespExpr::ARRAY);
const RespVec* vec = get<RespVec*>(e.u);
for (auto a : *vec) {
int64_t val;
std::string_view s = ToSV(a.GetBuf());
CHECK(absl::SimpleAtoi(s, &val)) << s;
res.push_back(val);
}
return res;
}
TEST_F(StringFamilyTest, SetGet) {
auto resp = Run({"set", "key", "val"});
EXPECT_THAT(resp, RespEq("OK"));
EXPECT_THAT(Run({"get", "key"}), RespEq("val"));
EXPECT_THAT(Run({"set", "key1", "1"}), RespEq("OK"));
EXPECT_THAT(Run({"get", "key1"}), RespEq("1"));
EXPECT_THAT(Run({"set", "key", "2"}), RespEq("OK"));
EXPECT_THAT(Run({"get", "key"}), RespEq("2"));
EXPECT_EQ(resp, "OK");
EXPECT_EQ(Run({"get", "key"}), "val");
EXPECT_EQ(Run({"set", "key1", "1"}), "OK");
EXPECT_EQ(Run({"get", "key1"}), "1");
EXPECT_EQ(Run({"set", "key", "2"}), "OK");
EXPECT_EQ(Run({"get", "key"}), "2");
}
TEST_F(StringFamilyTest, Incr) {
ASSERT_THAT(Run({"set", "key", "0"}), RespEq("OK"));
ASSERT_THAT(Run({"incr", "key"}), ElementsAre(IntArg(1)));
ASSERT_EQ(Run({"set", "key", "0"}), "OK");
ASSERT_THAT(Run({"incr", "key"}), IntArg(1));
ASSERT_THAT(Run({"set", "key1", "123456789"}), RespEq("OK"));
ASSERT_THAT(Run({"incrby", "key1", "0"}), ElementsAre(IntArg(123456789)));
ASSERT_EQ(Run({"set", "key1", "123456789"}), "OK");
ASSERT_THAT(Run({"incrby", "key1", "0"}), IntArg(123456789));
ASSERT_THAT(Run({"set", "key1", "-123456789"}), RespEq("OK"));
ASSERT_THAT(Run({"incrby", "key1", "0"}), ElementsAre(IntArg(-123456789)));
ASSERT_EQ(Run({"set", "key1", "-123456789"}), "OK");
ASSERT_THAT(Run({"incrby", "key1", "0"}), IntArg(-123456789));
ASSERT_THAT(Run({"set", "key1", " -123 "}), RespEq("OK"));
ASSERT_THAT(Run({"incrby", "key1", "1"}), ElementsAre(ErrArg("ERR value is not an integer")));
ASSERT_EQ(Run({"set", "key1", " -123 "}), "OK");
ASSERT_THAT(Run({"incrby", "key1", "1"}), ErrArg("ERR value is not an integer"));
ASSERT_THAT(Run({"incrby", "ne", "0"}), ElementsAre(IntArg(0)));
ASSERT_THAT(Run({"decrby", "a", "-9223372036854775808"}), ElementsAre(ErrArg("overflow")));
ASSERT_THAT(Run({"incrby", "ne", "0"}), IntArg(0));
ASSERT_THAT(Run({"decrby", "a", "-9223372036854775808"}), ErrArg("overflow"));
}
TEST_F(StringFamilyTest, Append) {
Run({"setex", "key", "100", "val"});
EXPECT_THAT(Run({"append", "key", "bar"}), ElementsAre(IntArg(6)));
EXPECT_THAT(Run({"ttl", "key"}), ElementsAre(IntArg(100)));
EXPECT_THAT(Run({"append", "key", "bar"}), IntArg(6));
EXPECT_THAT(Run({"ttl", "key"}), IntArg(100));
}
TEST_F(StringFamilyTest, Expire) {
ASSERT_THAT(Run({"set", "key", "val", "PX", "20"}), RespEq("OK"));
ASSERT_EQ(Run({"set", "key", "val", "PX", "20"}), "OK");
UpdateTime(expire_now_ + 10);
EXPECT_THAT(Run({"get", "key"}), RespEq("val"));
EXPECT_EQ(Run({"get", "key"}), "val");
UpdateTime(expire_now_ + 20);
EXPECT_THAT(Run({"get", "key"}), ElementsAre(ArgType(RespExpr::NIL)));
EXPECT_THAT(Run({"get", "key"}), ArgType(RespExpr::NIL));
ASSERT_THAT(Run({"set", "i", "1", "PX", "10"}), RespEq("OK"));
ASSERT_THAT(Run({"incr", "i"}), ElementsAre(IntArg(2)));
ASSERT_THAT(Run({"set", "i", "1", "PX", "10"}), "OK");
ASSERT_THAT(Run({"incr", "i"}), IntArg(2));
UpdateTime(expire_now_ + 30);
ASSERT_THAT(Run({"incr", "i"}), ElementsAre(IntArg(1)));
ASSERT_THAT(Run({"incr", "i"}), IntArg(1));
}
TEST_F(StringFamilyTest, Set) {
auto resp = Run({"set", "foo", "bar", "XX"});
EXPECT_THAT(resp, ElementsAre(ArgType(RespExpr::NIL)));
EXPECT_THAT(resp, ArgType(RespExpr::NIL));
resp = Run({"set", "foo", "bar", "NX"});
ASSERT_THAT(resp, RespEq("OK"));
ASSERT_THAT(resp, "OK");
resp = Run({"set", "foo", "bar", "NX"});
EXPECT_THAT(resp, ElementsAre(ArgType(RespExpr::NIL)));
EXPECT_THAT(resp, ArgType(RespExpr::NIL));
resp = Run({"set", "foo", "bar", "xx"});
ASSERT_THAT(resp, RespEq("OK"));
ASSERT_THAT(resp, "OK");
resp = Run({"set", "foo", "bar", "ex", "abc"});
ASSERT_THAT(resp, ElementsAre(ErrArg(kInvalidIntErr)));
ASSERT_THAT(resp, ErrArg(kInvalidIntErr));
resp = Run({"set", "foo", "bar", "ex", "-1"});
ASSERT_THAT(resp, ElementsAre(ErrArg("invalid expire time")));
ASSERT_THAT(resp, ErrArg("invalid expire time"));
resp = Run({"set", "foo", "bar", "ex", "1"});
ASSERT_THAT(resp, RespEq("OK"));
ASSERT_THAT(resp, "OK");
}
TEST_F(StringFamilyTest, MGetSet) {
Run({"mset", "z", "0"}); // single key
auto resp = Run({"mget", "z"}); // single key
EXPECT_THAT(resp, RespEq("0"));
EXPECT_THAT(resp, "0");
Run({"mset", "x", "0", "b", "0"});
@ -110,8 +125,8 @@ TEST_F(StringFamilyTest, MGetSet) {
auto mget_fb = pp_->at(0)->LaunchFiber([&] {
for (size_t i = 0; i < 1000; ++i) {
auto resp = Run({"mget", "b", "x"});
ASSERT_EQ(2, resp.size());
RespExpr resp = Run({"mget", "b", "x"});
ASSERT_EQ(RespExpr::ARRAY, resp.type);
auto ivec = ToIntArr(resp);
ASSERT_GE(ivec[1], ivec[0]);
@ -147,8 +162,8 @@ TEST_F(StringFamilyTest, MSetGet) {
auto mset_fb = pp_->at(0)->LaunchFiber([&] {
for (size_t i = 0; i < 1000; ++i) {
RespVec resp = Run({"mset", "x", StrCat(i), "b", StrCat(i)});
ASSERT_THAT(resp, RespEq("OK")) << i;
RespExpr resp = Run({"mset", "x", StrCat(i), "b", StrCat(i)});
ASSERT_EQ(resp, "OK") << i;
}
});
@ -187,7 +202,7 @@ TEST_F(StringFamilyTest, MSetDel) {
TEST_F(StringFamilyTest, IntKey) {
Run({"mset", "1", "1", "-1000", "-1000"});
auto resp = Run({"get", "1"});
ASSERT_THAT(resp, RespEq("1"));
ASSERT_THAT(resp, "1");
}
TEST_F(StringFamilyTest, SingleShard) {
@ -238,7 +253,7 @@ TEST_F(StringFamilyTest, MSetIncr) {
for (size_t i = 1; i < 1000; ++i) {
string base = StrCat(i * 900);
auto resp = Run({"mset", "b", base, "a", base, "c", base});
ASSERT_THAT(resp, RespEq("OK"));
ASSERT_EQ(resp, "OK");
}
});
@ -260,21 +275,21 @@ TEST_F(StringFamilyTest, MSetIncr) {
}
TEST_F(StringFamilyTest, SetEx) {
ASSERT_THAT(Run({"setex", "key", "1", "val"}), RespEq("OK"));
ASSERT_THAT(Run({"setex", "key", "10", "val"}), RespEq("OK"));
ASSERT_THAT(Run({"ttl", "key"}), ElementsAre(IntArg(10)));
ASSERT_THAT(Run({"setex", "key", "0", "val"}), ElementsAre(ErrArg("invalid expire time")));
ASSERT_EQ(Run({"setex", "key", "1", "val"}), "OK");
ASSERT_EQ(Run({"setex", "key", "10", "val"}), "OK");
ASSERT_THAT(Run({"ttl", "key"}), IntArg(10));
ASSERT_THAT(Run({"setex", "key", "0", "val"}), ErrArg("invalid expire time"));
}
TEST_F(StringFamilyTest, Range) {
Run({"set", "key1", "Hello World"});
EXPECT_THAT(Run({"getrange", "key1", "5", "3"}), RespEq(""));
EXPECT_EQ(Run({"getrange", "key1", "5", "3"}), "");
Run({"SETRANGE", "key1", "6", "Earth"});
EXPECT_THAT(Run({"get", "key1"}), RespEq("Hello Earth"));
EXPECT_EQ(Run({"get", "key1"}), "Hello Earth");
Run({"SETRANGE", "key2", "2", "Earth"});
EXPECT_THAT(Run({"get", "key2"}), RespEq(string_view("\000\000Earth", 7)));
EXPECT_EQ(Run({"get", "key2"}), string_view("\000\000Earth", 7));
Run({"SETRANGE", "key3", "0", ""});
EXPECT_EQ(0, CheckedInt({"exists", "key3"}));
@ -283,13 +298,13 @@ TEST_F(StringFamilyTest, Range) {
EXPECT_EQ(1, CheckedInt({"exists", "key3"}));
Run({"SET", "key3", "123"});
EXPECT_THAT(Run({"getrange", "key3", "2", "3"}), RespEq("3"));
EXPECT_THAT(Run({"getrange", "key3", "3", "3"}), RespEq(""));
EXPECT_THAT(Run({"getrange", "key3", "4", "5"}), RespEq(""));
EXPECT_EQ(Run({"getrange", "key3", "2", "3"}), "3");
EXPECT_EQ(Run({"getrange", "key3", "3", "3"}), "");
EXPECT_EQ(Run({"getrange", "key3", "4", "5"}), "");
Run({"SET", "num", "1234"});
EXPECT_THAT(Run({"getrange","num", "3", "5000"}), RespEq("4"));
EXPECT_THAT(Run({"getrange","num", "-5000", "10000"}), RespEq("1234"));
EXPECT_EQ(Run({"getrange","num", "3", "5000"}), "4");
EXPECT_EQ(Run({"getrange","num", "-5000", "10000"}), "1234");
}
} // namespace dfly

View file

@ -34,17 +34,6 @@ static vector<string> SplitLines(const std::string& src) {
return res;
}
vector<int64_t> ToIntArr(const RespVec& vec) {
vector<int64_t> res;
for (auto a : vec) {
int64_t val;
std::string_view s = ToSV(a.GetBuf());
CHECK(absl::SimpleAtoi(s, &val)) << s;
res.push_back(val);
}
return res;
}
BaseFamilyTest::TestConnWrapper::TestConnWrapper(Protocol proto)
: dummy_conn(new facade::Connection(proto, nullptr, nullptr, nullptr)),
@ -58,6 +47,8 @@ BaseFamilyTest::BaseFamilyTest() {
}
BaseFamilyTest::~BaseFamilyTest() {
for (auto* v : resp_vec_)
delete v;
}
void BaseFamilyTest::SetUpTestSuite() {
@ -100,7 +91,7 @@ void BaseFamilyTest::UpdateTime(uint64_t ms) {
ess_->RunBriefInParallel(cb);
}
RespVec BaseFamilyTest::Run(initializer_list<std::string_view> list) {
RespExpr BaseFamilyTest::Run(initializer_list<std::string_view> list) {
if (!ProactorBase::IsProactorThread()) {
return pp_->at(0)->Await([&] { return this->Run(list); });
}
@ -108,7 +99,7 @@ RespVec BaseFamilyTest::Run(initializer_list<std::string_view> list) {
return Run(GetId(), list);
}
RespVec BaseFamilyTest::Run(std::string_view id, std::initializer_list<std::string_view> list) {
RespExpr BaseFamilyTest::Run(std::string_view id, std::initializer_list<std::string_view> list) {
TestConnWrapper* conn = AddFindConn(Protocol::REDIS, id);
CmdArgVec args = conn->Args(list);
@ -126,8 +117,15 @@ RespVec BaseFamilyTest::Run(std::string_view id, std::initializer_list<std::stri
last_cmd_dbg_info_ = context.last_command_debug;
RespVec vec = conn->ParseResponse();
if (vec.size() == 1)
return vec.front();
RespVec* new_vec = new RespVec(vec);
resp_vec_.push_back(new_vec);
RespExpr e;
e.type = RespExpr::ARRAY;
e.u = new_vec;
return vec;
return e;
}
auto BaseFamilyTest::RunMC(MP::CmdType cmd_type, string_view key, string_view value, uint32_t flags,
@ -203,16 +201,16 @@ auto BaseFamilyTest::GetMC(MP::CmdType cmd_type, std::initializer_list<std::stri
}
int64_t BaseFamilyTest::CheckedInt(std::initializer_list<std::string_view> list) {
RespVec resp = Run(list);
CHECK_EQ(1u, resp.size());
if (resp.front().type == RespExpr::INT64) {
return get<int64_t>(resp.front().u);
RespExpr resp = Run(list);
if (resp.type == RespExpr::INT64) {
return get<int64_t>(resp.u);
}
if (resp.front().type == RespExpr::NIL) {
if (resp.type == RespExpr::NIL) {
return INT64_MIN;
}
CHECK_EQ(RespExpr::STRING, int(resp.front().type)) << list;
string_view sv = ToSV(resp.front().GetBuf());
CHECK_EQ(RespExpr::STRING, int(resp.type)) << list;
string_view sv = ToSV(resp.GetBuf());
int64_t res;
CHECK(absl::SimpleAtoi(sv, &res)) << "|" << sv << "|";
return res;

View file

@ -16,8 +16,6 @@
namespace dfly {
using namespace facade;
std::vector<int64_t> ToIntArr(const RespVec& vec);
class BaseFamilyTest : public ::testing::Test {
protected:
BaseFamilyTest();
@ -47,8 +45,8 @@ class BaseFamilyTest : public ::testing::Test {
RespVec ParseResponse();
};
RespVec Run(std::initializer_list<std::string_view> list);
RespVec Run(std::string_view id, std::initializer_list<std::string_view> list);
RespExpr Run(std::initializer_list<std::string_view> list);
RespExpr Run(std::string_view id, std::initializer_list<std::string_view> list);
using MCResponse = std::vector<std::string>;
MCResponse RunMC(MemcacheParser::CmdType cmd_type, std::string_view key, std::string_view value,
@ -82,6 +80,7 @@ class BaseFamilyTest : public ::testing::Test {
::boost::fibers::mutex mu_;
ConnectionContext::DebugInfo last_cmd_dbg_info_;
uint64_t expire_now_;
std::vector<RespVec*> resp_vec_;
};
} // namespace dfly

View file

@ -23,53 +23,56 @@ class ZSetFamilyTest : public BaseFamilyTest {
TEST_F(ZSetFamilyTest, Add) {
auto resp = Run({"zadd", "x", "1.1", "a"});
EXPECT_THAT(resp[0], IntArg(1));
EXPECT_THAT(resp, IntArg(1));
resp = Run({"zscore", "x", "a"});
EXPECT_THAT(resp[0], StrArg("1.1"));
EXPECT_THAT(resp, "1.1");
resp = Run({"zadd", "x", "2", "a"});
EXPECT_THAT(resp[0], IntArg(0));
EXPECT_THAT(resp, IntArg(0));
resp = Run({"zscore", "x", "a"});
EXPECT_THAT(resp[0], StrArg("2"));
EXPECT_THAT(resp, "2");
resp = Run({"zadd", "x", "ch", "3", "a"});
EXPECT_THAT(resp[0], IntArg(1));
EXPECT_THAT(resp, IntArg(1));
resp = Run({"zscore", "x", "a"});
EXPECT_THAT(resp[0], StrArg("3"));
EXPECT_EQ(resp, "3");
resp = Run({"zcard", "x"});
EXPECT_THAT(resp[0], IntArg(1));
EXPECT_THAT(resp, IntArg(1));
EXPECT_THAT(Run({"zadd", "x", "", "a"}), ElementsAre(ErrArg("not a valid float")));
EXPECT_THAT(Run({"zadd", "x", "", "a"}), ErrArg("not a valid float"));
EXPECT_THAT(Run({"zadd", "ztmp", "xx", "10", "member"}), ElementsAre(IntArg(0)));
EXPECT_THAT(Run({"zadd", "ztmp", "xx", "10", "member"}), IntArg(0));
const char kHighPrecision[] = "0.79028573343077946";
Run({"zadd", "zs", kHighPrecision, "a"});
EXPECT_THAT(Run({"zscore", "zs", "a"}), ElementsAre("0.7902857334307795"));
EXPECT_EQ(Run({"zscore", "zs", "a"}), "0.7902857334307795");
EXPECT_EQ(0.79028573343077946, 0.7902857334307795);
}
TEST_F(ZSetFamilyTest, ZRem) {
auto resp = Run({"zadd", "x", "1.1", "b", "2.1", "a"});
EXPECT_THAT(resp[0], IntArg(2));
EXPECT_THAT(resp, IntArg(2));
resp = Run({"zrem", "x", "b", "c"});
EXPECT_THAT(resp[0], IntArg(1));
EXPECT_THAT(resp, IntArg(1));
resp = Run({"zcard", "x"});
EXPECT_THAT(resp[0], IntArg(1));
EXPECT_THAT(Run({"zrange", "x", "0", "3", "byscore"}), ElementsAre("a"));
EXPECT_THAT(Run({"zrange", "x", "(-inf", "(+inf", "byscore"}), ElementsAre("a"));
EXPECT_THAT(resp, IntArg(1));
EXPECT_THAT(Run({"zrange", "x", "0", "3", "byscore"}), "a");
EXPECT_THAT(Run({"zrange", "x", "(-inf", "(+inf", "byscore"}), "a");
}
TEST_F(ZSetFamilyTest, ZRangeRank) {
Run({"zadd", "x", "1.1", "a", "2.1", "b"});
EXPECT_THAT(Run({"zrangebyscore", "x", "0", "(1.1"}), ElementsAre(ArrLen(0)));
EXPECT_THAT(Run({"zrangebyscore", "x", "-inf", "1.1"}), ElementsAre("a"));
EXPECT_THAT(Run({"zrevrangebyscore", "x", "-inf", "+inf"}), ElementsAre("b", "a"));
EXPECT_THAT(Run({"zrangebyscore", "x", "0", "(1.1"}), ArrLen(0));
EXPECT_THAT(Run({"zrangebyscore", "x", "-inf", "1.1"}), "a");
auto resp = Run({"zrevrangebyscore", "x", "-inf", "+inf"});
ASSERT_THAT(resp, ArgType(RespExpr::ARRAY));
ASSERT_THAT(resp.GetVec(), ElementsAre("b", "a"));
EXPECT_EQ(2, CheckedInt({"zcount", "x", "1.1", "2.1"}));
EXPECT_EQ(1, CheckedInt({"zcount", "x", "(1.1", "2.1"}));
@ -79,39 +82,38 @@ TEST_F(ZSetFamilyTest, ZRangeRank) {
EXPECT_EQ(1, CheckedInt({"zrank", "x", "b"}));
EXPECT_EQ(1, CheckedInt({"zrevrank", "x", "a"}));
EXPECT_EQ(0, CheckedInt({"zrevrank", "x", "b"}));
EXPECT_THAT(Run({"zrevrank", "x", "c"}), ElementsAre(ArgType(RespExpr::NIL)));
EXPECT_THAT(Run({"zrank", "y", "c"}), ElementsAre(ArgType(RespExpr::NIL)));
EXPECT_THAT(Run({"zrevrank", "x", "c"}), ArgType(RespExpr::NIL));
EXPECT_THAT(Run({"zrank", "y", "c"}), ArgType(RespExpr::NIL));
}
TEST_F(ZSetFamilyTest, ZRemRangeRank) {
Run({"zadd", "x", "1.1", "a", "2.1", "b"});
EXPECT_THAT(Run({"ZREMRANGEBYRANK", "y", "0", "1"}), ElementsAre(IntArg(0)));
EXPECT_THAT(Run({"ZREMRANGEBYRANK", "x", "0", "0"}), ElementsAre(IntArg(1)));
EXPECT_THAT(Run({"zrange", "x", "0", "5"}), ElementsAre("b"));
EXPECT_THAT(Run({"ZREMRANGEBYRANK", "x", "0", "1"}), ElementsAre(IntArg(1)));
EXPECT_THAT(Run({"type", "x"}), ElementsAre("none"));
EXPECT_THAT(Run({"ZREMRANGEBYRANK", "y", "0", "1"}), IntArg(0));
EXPECT_THAT(Run({"ZREMRANGEBYRANK", "x", "0", "0"}), IntArg(1));
EXPECT_EQ(Run({"zrange", "x", "0", "5"}), "b");
EXPECT_THAT(Run({"ZREMRANGEBYRANK", "x", "0", "1"}), IntArg(1));
EXPECT_EQ(Run({"type", "x"}), "none");
}
TEST_F(ZSetFamilyTest, ZRemRangeScore) {
Run({"zadd", "x", "1.1", "a", "2.1", "b"});
EXPECT_THAT(Run({"ZREMRANGEBYSCORE", "y", "0", "1"}), ElementsAre(IntArg(0)));
EXPECT_THAT(Run({"ZREMRANGEBYSCORE", "x", "-inf", "1.1"}), ElementsAre(IntArg(1)));
EXPECT_THAT(Run({"zrange", "x", "0", "5"}), ElementsAre("b"));
EXPECT_THAT(Run({"ZREMRANGEBYSCORE", "x", "(2.0", "+inf"}), ElementsAre(IntArg(1)));
EXPECT_THAT(Run({"type", "x"}), ElementsAre("none"));
EXPECT_THAT(Run({"zremrangebyscore", "x", "1", "NaN"}),
ElementsAre(ErrArg("min or max is not a float")));
EXPECT_THAT(Run({"ZREMRANGEBYSCORE", "y", "0", "1"}), IntArg(0));
EXPECT_THAT(Run({"ZREMRANGEBYSCORE", "x", "-inf", "1.1"}), IntArg(1));
EXPECT_EQ(Run({"zrange", "x", "0", "5"}), "b");
EXPECT_THAT(Run({"ZREMRANGEBYSCORE", "x", "(2.0", "+inf"}), IntArg(1));
EXPECT_EQ(Run({"type", "x"}), "none");
EXPECT_THAT(Run({"zremrangebyscore", "x", "1", "NaN"}), ErrArg("min or max is not a float"));
}
TEST_F(ZSetFamilyTest, IncrBy) {
auto resp = Run({"zadd", "key", "xx", "incr", "2.1", "member"});
EXPECT_THAT(resp[0], ArgType(RespExpr::NIL));
EXPECT_THAT(resp, ArgType(RespExpr::NIL));
resp = Run({"zadd", "key", "nx", "incr", "2.1", "member"});
EXPECT_THAT(resp[0], "2.1");
EXPECT_THAT(resp, "2.1");
resp = Run({"zadd", "key", "nx", "incr", "4.9", "member"});
EXPECT_THAT(resp[0], ArgType(RespExpr::NIL));
EXPECT_THAT(resp, ArgType(RespExpr::NIL));
}
TEST_F(ZSetFamilyTest, ByLex) {
@ -119,12 +121,17 @@ TEST_F(ZSetFamilyTest, ByLex) {
"zadd", "key", "0", "alpha", "0", "bar", "0", "cool", "0", "down",
"0", "elephant", "0", "foo", "0", "great", "0", "hill", "0", "omega",
});
auto resp = Run({"zrangebylex", "key", "-", "[cool"});
EXPECT_THAT(resp, ElementsAre("alpha", "bar", "cool"));
ASSERT_THAT(resp, ArgType(RespExpr::ARRAY));
EXPECT_THAT(resp.GetVec(), ElementsAre("alpha", "bar", "cool"));
EXPECT_EQ(3, CheckedInt({"ZLEXCOUNT", "key", "(foo", "+"}));
EXPECT_EQ(3, CheckedInt({"ZREMRANGEBYLEX", "key", "(foo", "+"}));
EXPECT_THAT(Run({"zrangebylex", "key", "[a", "+"}),
ElementsAre("alpha", "bar", "cool", "down", "elephant", "foo"));
resp = Run({"zrangebylex", "key", "[a", "+"});
ASSERT_THAT(resp, ArgType(RespExpr::ARRAY));
ASSERT_THAT(resp.GetVec(), ElementsAre("alpha", "bar", "cool", "down", "elephant", "foo"));
}
} // namespace dfly