test: cover commandState and commandInfo
This commit is contained in:
1 parent
817b8077f3
commit
bdaf425fb3
1 file changed
+157
@@ -467,3 +467,160 @@ defmodule Excache.IntrospectionTest do
|
|||||||
Client.command(conn, ["LINSERT", "a", "BEFORE", "b"])
|
Client.command(conn, ["LINSERT", "a", "BEFORE", "b"])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "GETKEYS walks plain ranges" do
|
||||||
|
assert getkeys(["GET", "one"]) == ["one"]
|
||||||
|
assert getkeys(["MSET", "a", "1", "b", "2", "c", "3"]) == ["a", "b", "c"]
|
||||||
|
assert getkeys(["DEL", "a", "b", "c"]) == ["a", "b", "c"]
|
||||||
|
assert getkeys(["BLPOP", "left", "right", "0"]) == ["left", "right"]
|
||||||
|
assert getkeys(["BITOP", "AND", "dest", "src1", "src2"]) == ["dest", "src1", "src2"]
|
||||||
|
assert getkeys(["SMOVE", "from", "to", "member"]) == ["from", "to"]
|
||||||
|
assert getkeys(["EXPIRE", "solo", "10"]) == ["solo"]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "GETKEYS resolves the commands whose keys move" do
|
||||||
|
assert getkeys(["XREAD", "COUNT", "2", "STREAMS", "s1", "s2", "0", "0"]) == ["s1", "s2"]
|
||||||
|
|
||||||
|
assert getkeys([
|
||||||
|
"XREADGROUP",
|
||||||
|
"GROUP",
|
||||||
|
"g",
|
||||||
|
"c",
|
||||||
|
"STREAMS",
|
||||||
|
"stream",
|
||||||
|
">"
|
||||||
|
]) == ["stream"]
|
||||||
|
|
||||||
|
assert getkeys(["SINTERCARD", "2", "a", "b", "LIMIT", "1"]) == ["a", "b"]
|
||||||
|
assert getkeys(["BLMPOP", "0", "2", "a", "b", "LEFT"]) == ["a", "b"]
|
||||||
|
assert getkeys(["OBJECT", "ENCODING", "thing"]) == ["thing"]
|
||||||
|
assert getkeys(["MEMORY", "USAGE", "thing"]) == ["thing"]
|
||||||
|
assert getkeys(["XINFO", "STREAM", "events"]) == ["events"]
|
||||||
|
assert getkeys(["XGROUP", "CREATE", "events", "group", "$"]) == ["events"]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "GETKEYS refuses what it cannot answer" do
|
||||||
|
assert getkeys(["PING"]) == {:error, "ERR The command has no key arguments"}
|
||||||
|
assert getkeys(["MEMORY", "DOCTOR"]) == {:error, "ERR The command has no key arguments"}
|
||||||
|
assert getkeys(["NOSUCHCOMMAND", "a"]) == {:error, "ERR Invalid command specified"}
|
||||||
|
|
||||||
|
assert getkeys(["GET"]) ==
|
||||||
|
{:error, "ERR Invalid number of arguments specified for command"}
|
||||||
|
|
||||||
|
assert getkeys(["XREAD", "COUNT", "2", "s1", "0"]) ==
|
||||||
|
{:error, "ERR Invalid arguments specified for command"}
|
||||||
|
|
||||||
|
assert getkeys(["SINTERCARD", "3", "a", "b"]) ==
|
||||||
|
{:error, "ERR Invalid arguments specified for command"}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "DOCS answers with the group and arity taken from the same table" do
|
||||||
|
assert {[{:array, entries}], _state} =
|
||||||
|
Introspection.dispatch(
|
||||||
|
"COMMAND",
|
||||||
|
["DOCS", "zadd", "nosuchcommand"],
|
||||||
|
commandState()
|
||||||
|
)
|
||||||
|
|
||||||
|
assert entries == [
|
||||||
|
{:bulk, "zadd"},
|
||||||
|
{:array, [{:bulk, "group"}, {:bulk, "zset"}, {:bulk, "arity"}, {:integer, -4}]}
|
||||||
|
]
|
||||||
|
|
||||||
|
assert {[{:array, everything}], _state} =
|
||||||
|
Introspection.dispatch("COMMAND", ["DOCS"], commandState())
|
||||||
|
|
||||||
|
assert length(everything) == 2 * length(Enum.uniq(Command.known_commands()))
|
||||||
|
end
|
||||||
|
|
||||||
|
test "an unknown subcommand is named in the error" do
|
||||||
|
assert {[{:error, message}], _state} =
|
||||||
|
Introspection.dispatch("COMMAND", ["NOPE"], commandState())
|
||||||
|
|
||||||
|
assert message =~ "Unknown subcommand or wrong number of arguments for 'NOPE'"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "the extended dispatcher already routes COMMAND to this module" do
|
||||||
|
assert {[{:integer, count}], _state} =
|
||||||
|
Excache.Command.Extended.dispatch("COMMAND", ["COUNT"], commandState())
|
||||||
|
|
||||||
|
assert count == Catalog.count()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp commandState,
|
||||||
|
do: Map.put(Transaction.initial_state(), :subscriptions, MapSet.new())
|
||||||
|
|
||||||
|
defp commandInfo(name) do
|
||||||
|
assert {[{:array, [{:array, entry}]}], _state} =
|
||||||
|
Introspection.dispatch("COMMAND", ["INFO", name], commandState())
|
||||||
|
|
||||||
|
[
|
||||||
|
{:bulk, lowered},
|
||||||
|
{:integer, arity},
|
||||||
|
{:array, flags},
|
||||||
|
{:integer, first},
|
||||||
|
{:integer, last},
|
||||||
|
{:integer, step}
|
||||||
|
] = entry
|
||||||
|
|
||||||
|
{lowered, arity, Enum.map(flags, fn {:simple, flag} -> flag end), first, last, step}
|
||||||
|
end
|
||||||
|
|
||||||
|
defp getkeys(argv) do
|
||||||
|
case Introspection.dispatch("COMMAND", ["GETKEYS" | argv], commandState()) do
|
||||||
|
{[{:array, keys}], _state} -> Enum.map(keys, fn {:bulk, key} -> key end)
|
||||||
|
{[error], _state} -> error
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp clientField(conn, name) do
|
||||||
|
{text, _conn} = Client.command(conn, ["INFO", "clients"])
|
||||||
|
String.to_integer(fields(text)[name])
|
||||||
|
end
|
||||||
|
|
||||||
|
defp sections(text) do
|
||||||
|
for "# " <> title <- String.split(text, "\r\n"), do: title
|
||||||
|
end
|
||||||
|
|
||||||
|
defp fields(text) do
|
||||||
|
text
|
||||||
|
|> String.split("\r\n")
|
||||||
|
|> Enum.reject(fn line -> line == "" or String.starts_with?(line, "#") end)
|
||||||
|
|> Map.new(fn line ->
|
||||||
|
[key, value] = String.split(line, ":", parts: 2)
|
||||||
|
{key, value}
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp listLines(text) do
|
||||||
|
text
|
||||||
|
|> String.split("\n")
|
||||||
|
|> Enum.reject(&(&1 == ""))
|
||||||
|
|> Map.new(fn line ->
|
||||||
|
parsed =
|
||||||
|
Map.new(String.split(line, " "), fn pair ->
|
||||||
|
[key, value] = String.split(pair, "=", parts: 2)
|
||||||
|
{key, value}
|
||||||
|
end)
|
||||||
|
|
||||||
|
{String.to_integer(parsed["id"]), parsed}
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp blockingTask(port, args) do
|
||||||
|
Task.async(fn ->
|
||||||
|
client = Client.connect(port)
|
||||||
|
{reply, _client} = Client.command(client, args)
|
||||||
|
Client.close(client)
|
||||||
|
reply
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp awaitUntil(check, attempts \\ 200) do
|
||||||
|
cond do
|
||||||
|
check.() -> :ok
|
||||||
|
attempts == 0 -> flunk("condition never held")
|
||||||
|
true -> Process.sleep(10) && awaitUntil(check, attempts - 1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
Reference in new issue
Block a user