test(store): add string and key command tests

This commit is contained in:
dualfroz committed 2026-08-28 09:00:00 +02:00
1 parent 5de6afbb61
commit b0f3e152c7
1 file changed
+124
+124
View File
@@ -0,0 +1,124 @@
defmodule ExcacheTest do
use Excache.Test.ServerCase, async: false
test "PING and ECHO", %{conn: conn} do
assert {{:simple, "PONG"}, conn} = Client.command(conn, ["PING"])
assert {"hi", conn} = Client.command(conn, ["PING", "hi"])
assert {"hello world", _conn} = Client.command(conn, ["ECHO", "hello world"])
end
test "inline PING command over the socket", %{conn: conn} do
conn = Client.send_raw(conn, "PING\r\n")
assert {{:simple, "PONG"}, _conn} = Client.read(conn)
end
test "SET, GET, TYPE and missing key", %{conn: conn} do
assert {{:simple, "OK"}, conn} = Client.command(conn, ["SET", "greeting", "hello"])
assert {"hello", conn} = Client.command(conn, ["GET", "greeting"])
assert {{:simple, "string"}, conn} = Client.command(conn, ["TYPE", "greeting"])
assert {nil, conn} = Client.command(conn, ["GET", "absent"])
assert {{:simple, "none"}, _conn} = Client.command(conn, ["TYPE", "absent"])
end
test "SET with NX and XX", %{conn: conn} do
assert {{:simple, "OK"}, conn} = Client.command(conn, ["SET", "lock", "a", "NX"])
assert {nil, conn} = Client.command(conn, ["SET", "lock", "b", "NX"])
assert {"a", conn} = Client.command(conn, ["GET", "lock"])
assert {{:simple, "OK"}, conn} = Client.command(conn, ["SET", "lock", "c", "XX"])
assert {nil, _conn} = Client.command(conn, ["SET", "fresh", "z", "XX"])
end
test "INCR, DECR, INCRBY and non-integer error", %{conn: conn} do
assert {1, conn} = Client.command(conn, ["INCR", "counter"])
assert {3, conn} = Client.command(conn, ["INCRBY", "counter", "2"])
assert {2, conn} = Client.command(conn, ["DECR", "counter"])
assert {{:simple, "OK"}, conn} = Client.command(conn, ["SET", "word", "abc"])
assert {{:error, "ERR value is not an integer or out of range"}, _conn} =
Client.command(conn, ["INCR", "word"])
end
test "APPEND and GETSET", %{conn: conn} do
assert {5, conn} = Client.command(conn, ["APPEND", "buf", "hello"])
assert {11, conn} = Client.command(conn, ["APPEND", "buf", " world"])
assert {"hello world", conn} = Client.command(conn, ["GETSET", "buf", "fresh"])
assert {"fresh", _conn} = Client.command(conn, ["GET", "buf"])
end
test "MSET and MGET", %{conn: conn} do
assert {{:simple, "OK"}, conn} = Client.command(conn, ["MSET", "a", "1", "b", "2"])
assert {["1", "2", nil], _conn} = Client.command(conn, ["MGET", "a", "b", "missing"])
end
test "DEL, EXISTS, KEYS, DBSIZE and FLUSHDB", %{conn: conn} do
assert {{:simple, "OK"}, conn} = Client.command(conn, ["SET", "user:1", "ann"])
assert {{:simple, "OK"}, conn} = Client.command(conn, ["SET", "user:2", "ben"])
assert {2, conn} = Client.command(conn, ["EXISTS", "user:1", "user:2"])
assert {2, conn} = Client.command(conn, ["DBSIZE"])
{keys, conn} = Client.command(conn, ["KEYS", "user:*"])
assert Enum.sort(keys) == ["user:1", "user:2"]
assert {1, conn} = Client.command(conn, ["DEL", "user:1"])
assert {0, conn} = Client.command(conn, ["EXISTS", "user:1"])
assert {{:simple, "OK"}, conn} = Client.command(conn, ["FLUSHDB"])
assert {0, _conn} = Client.command(conn, ["DBSIZE"])
end
test "EXPIRE, TTL, PTTL and PERSIST", %{conn: conn} do
assert {{:simple, "OK"}, conn} = Client.command(conn, ["SET", "ephemeral", "v", "EX", "100"])
{ttl, conn} = Client.command(conn, ["TTL", "ephemeral"])
assert ttl > 0 and ttl <= 100
assert {1, conn} = Client.command(conn, ["PERSIST", "ephemeral"])
assert {-1, conn} = Client.command(conn, ["TTL", "ephemeral"])
assert {1, conn} = Client.command(conn, ["EXPIRE", "ephemeral", "50"])
{pttl, conn} = Client.command(conn, ["PTTL", "ephemeral"])
assert pttl > 40_000 and pttl <= 50_000
assert {-2, _conn} = Client.command(conn, ["TTL", "never-existed"])
end
test "PX expiry actually removes the key", %{conn: conn} do
assert {{:simple, "OK"}, conn} = Client.command(conn, ["SET", "blink", "v", "PX", "40"])
Process.sleep(120)
assert {nil, _conn} = Client.command(conn, ["GET", "blink"])
end
test "WRONGTYPE guard across data types", %{conn: conn} do
assert {3, conn} = Client.command(conn, ["RPUSH", "aList", "a", "b", "c"])
assert {{:error, "WRONGTYPE" <> _}, _conn} = Client.command(conn, ["GET", "aList"])
end
test "pub/sub delivers a published message", %{port: port, conn: subscriber} do
channel = "room:#{System.unique_integer([:positive])}"
assert {["subscribe", ^channel, 1], subscriber} =
Client.command(subscriber, ["SUBSCRIBE", channel])
publisher = Client.connect(port)
assert {1, _publisher} = Client.command(publisher, ["PUBLISH", channel, "ping"])
Client.close(publisher)
assert {["message", ^channel, "ping"], _subscriber} = Client.read(subscriber)
end
test "SAVE then restart reloads from disk", %{conn: conn} do
assert {{:simple, "OK"}, conn} = Client.command(conn, ["SET", "durable", "kept"])
assert {{:simple, "OK"}, conn} = Client.command(conn, ["SAVE"])
Excache.Store.flushdb()
assert {nil, conn} = Client.command(conn, ["GET", "durable"])
Excache.Store.restart()
assert {"kept", _conn} = Client.command(conn, ["GET", "durable"])
end
test "partial frames are buffered until complete", %{conn: conn} do
conn = Client.send_raw(conn, "*3\r\n$3\r\nSET\r\n$4\r\npart")
conn = Client.send_raw(conn, "\r\n$2\r\nok\r\n")
assert {{:simple, "OK"}, conn} = Client.read(conn)
assert {"ok", _conn} = Client.command(conn, ["GET", "part"])
end
end