test: extend coverage of introspection_test
This commit is contained in:
1 parent
f5e950deb9
commit
817b8077f3
1 file changed
+154
@@ -313,3 +313,157 @@ defmodule Excache.IntrospectionTest do
|
||||
|
||||
Process.sleep(1_200)
|
||||
|
||||
assert {mine, conn} = Client.command(conn, ["CLIENT", "ID"])
|
||||
assert {text, _conn} = Client.command(conn, ["CLIENT", "LIST"])
|
||||
lines = listLines(text)
|
||||
|
||||
assert String.to_integer(lines[quietId]["idle"]) >= 1
|
||||
assert String.to_integer(lines[quietId]["age"]) >= 1
|
||||
assert lines[mine]["idle"] == "0"
|
||||
|
||||
Client.close(quiet)
|
||||
end
|
||||
|
||||
test "KILL by ID tears down another live connection", %{conn: conn, port: port} do
|
||||
victim = Client.connect(port)
|
||||
assert {victimId, victim} = Client.command(victim, ["CLIENT", "ID"])
|
||||
assert {{:simple, "PONG"}, victim} = Client.command(victim, ["PING"])
|
||||
|
||||
assert {1, conn} =
|
||||
Client.command(conn, ["CLIENT", "KILL", "ID", Integer.to_string(victimId)])
|
||||
|
||||
assert {:error, :closed} = :gen_tcp.recv(victim.socket, 0, 1_000)
|
||||
|
||||
assert {0, conn} =
|
||||
Client.command(conn, ["CLIENT", "KILL", "ID", Integer.to_string(victimId)])
|
||||
|
||||
assert {text, _conn} = Client.command(conn, ["CLIENT", "LIST"])
|
||||
refute Map.has_key?(listLines(text), victimId)
|
||||
end
|
||||
|
||||
test "KILL by address accepts the legacy single argument form", %{conn: conn, port: port} do
|
||||
victim = Client.connect(port)
|
||||
assert {victimId, victim} = Client.command(victim, ["CLIENT", "ID"])
|
||||
|
||||
assert {text, conn} = Client.command(conn, ["CLIENT", "LIST"])
|
||||
address = listLines(text)[victimId]["addr"]
|
||||
|
||||
assert {{:simple, "OK"}, conn} = Client.command(conn, ["CLIENT", "KILL", address])
|
||||
assert {:error, :closed} = :gen_tcp.recv(victim.socket, 0, 1_000)
|
||||
|
||||
assert {{:error, "ERR No such client address in the client list"}, _conn} =
|
||||
Client.command(conn, ["CLIENT", "KILL", address])
|
||||
end
|
||||
|
||||
test "KILL skips the caller unless SKIPME no is given", %{conn: conn, port: port} do
|
||||
assert {mine, conn} = Client.command(conn, ["CLIENT", "ID"])
|
||||
bystander = Client.connect(port)
|
||||
assert {_id, _bystander} = Client.command(bystander, ["CLIENT", "ID"])
|
||||
|
||||
assert {0, conn} = Client.command(conn, ["CLIENT", "KILL", "ID", Integer.to_string(mine)])
|
||||
assert {{:simple, "PONG"}, conn} = Client.command(conn, ["PING"])
|
||||
|
||||
assert {1, conn} =
|
||||
Client.command(conn, [
|
||||
"CLIENT",
|
||||
"KILL",
|
||||
"ID",
|
||||
Integer.to_string(mine),
|
||||
"SKIPME",
|
||||
"no"
|
||||
])
|
||||
|
||||
assert {:error, :closed} = :gen_tcp.recv(conn.socket, 0, 1_000)
|
||||
Client.close(bystander)
|
||||
end
|
||||
|
||||
test "KILL rejects filters it does not understand", %{conn: conn} do
|
||||
assert {{:error, "ERR syntax error"}, conn} =
|
||||
Client.command(conn, ["CLIENT", "KILL", "WHATEVER", "1"])
|
||||
|
||||
assert {{:error, "ERR syntax error"}, conn} =
|
||||
Client.command(conn, ["CLIENT", "KILL", "ID", "notanumber"])
|
||||
|
||||
assert {{:error, "ERR Unknown subcommand" <> _}, _conn} =
|
||||
Client.command(conn, ["CLIENT", "NOSUCHTHING"])
|
||||
end
|
||||
|
||||
test "HELP lists the supported subcommands", %{conn: conn} do
|
||||
assert {lines, _conn} = Client.command(conn, ["CLIENT", "HELP"])
|
||||
assert {:simple, "KILL <ip:port>"} in lines
|
||||
assert {:simple, "ID"} in lines
|
||||
end
|
||||
|
||||
test "CLIENT off a real connection reports that it needs one" do
|
||||
assert {[{:error, "ERR CLIENT is only available on a server connection"}], _state} =
|
||||
Introspection.dispatch("CLIENT", ["ID"], commandState())
|
||||
end
|
||||
end
|
||||
|
||||
describe "COMMAND" do
|
||||
test "the catalog covers exactly the commands the server dispatches" do
|
||||
known = MapSet.new(Command.known_commands())
|
||||
assert MapSet.new(Catalog.tableNames()) == known
|
||||
end
|
||||
|
||||
test "the full reply carries one six element entry per command" do
|
||||
assert {[{:array, entries}], _state} = Introspection.dispatch("COMMAND", [], commandState())
|
||||
|
||||
assert length(entries) == length(Enum.uniq(Command.known_commands()))
|
||||
|
||||
Enum.each(entries, fn {:array, entry} ->
|
||||
assert [{:bulk, name}, {:integer, arity}, {:array, flags}, first, last, step] = entry
|
||||
assert name == String.downcase(name)
|
||||
assert arity != 0
|
||||
assert Enum.all?(flags, &match?({:simple, _flag}, &1))
|
||||
assert match?({:integer, _value}, first)
|
||||
assert match?({:integer, _value}, last)
|
||||
assert match?({:integer, _value}, step)
|
||||
end)
|
||||
end
|
||||
|
||||
test "COUNT and LIST agree with the full reply" do
|
||||
assert {[{:integer, count}], _state} =
|
||||
Introspection.dispatch("COMMAND", ["COUNT"], commandState())
|
||||
|
||||
assert {[{:array, names}], _state} =
|
||||
Introspection.dispatch("COMMAND", ["LIST"], commandState())
|
||||
|
||||
assert count == length(names)
|
||||
assert count == length(Enum.uniq(Command.known_commands()))
|
||||
assert {:bulk, "append"} in names
|
||||
end
|
||||
|
||||
test "INFO gives the real arity and key positions per command" do
|
||||
assert commandInfo("GET") == {"get", 2, ["readonly", "fast"], 1, 1, 1}
|
||||
assert commandInfo("SET") == {"set", -3, ["write", "denyoom"], 1, 1, 1}
|
||||
assert commandInfo("MSET") == {"mset", -3, ["write", "denyoom"], 1, -1, 2}
|
||||
assert commandInfo("DEL") == {"del", -2, ["write"], 1, -1, 1}
|
||||
assert commandInfo("BLPOP") == {"blpop", -3, ["write", "noscript", "blocking"], 1, -2, 1}
|
||||
assert commandInfo("BITOP") == {"bitop", -4, ["write", "denyoom"], 2, -1, 1}
|
||||
assert commandInfo("SMOVE") == {"smove", 4, ["write", "fast"], 1, 2, 1}
|
||||
assert commandInfo("PING") == {"ping", -1, ["fast"], 0, 0, 0}
|
||||
|
||||
assert {"xread", -4, flags, 0, 0, 0} = commandInfo("XREAD")
|
||||
assert "movablekeys" in flags
|
||||
end
|
||||
|
||||
test "INFO is case insensitive and answers nil for what it does not have" do
|
||||
assert {[{:array, [entry, nil?]}], _state} =
|
||||
Introspection.dispatch("COMMAND", ["INFO", "get", "nosuchcommand"], commandState())
|
||||
|
||||
assert {:array, [{:bulk, "get"} | _rest]} = entry
|
||||
assert nil? == {:array, nil}
|
||||
end
|
||||
|
||||
test "the declared arity matches what the dispatcher actually accepts", %{conn: conn} do
|
||||
assert {{:error, "ERR wrong number of arguments for 'get' command"}, conn} =
|
||||
Client.command(conn, ["GET", "a", "b"])
|
||||
|
||||
assert {{:error, "ERR wrong number of arguments for 'smove' command"}, conn} =
|
||||
Client.command(conn, ["SMOVE", "a", "b"])
|
||||
|
||||
assert {{:error, "ERR wrong number of arguments for 'linsert' command"}, _conn} =
|
||||
Client.command(conn, ["LINSERT", "a", "BEFORE", "b"])
|
||||
end
|
||||
|
||||
Reference in new issue
Block a user