diff options
Diffstat (limited to '')
-rw-r--r-- | tests/cli_tests/test_cli_pubsub.py | 31 | ||||
-rw-r--r-- | tests/cli_tests/test_cli_start.py | 75 | ||||
-rw-r--r-- | tests/cli_tests/test_command_input.py | 55 | ||||
-rw-r--r-- | tests/cli_tests/test_completer.py | 51 | ||||
-rw-r--r-- | tests/cli_tests/test_config.py | 25 | ||||
-rw-r--r-- | tests/cli_tests/test_dsn.py | 53 | ||||
-rw-r--r-- | tests/cli_tests/test_history.py | 42 | ||||
-rw-r--r-- | tests/cli_tests/test_on_error.py | 12 | ||||
-rw-r--r-- | tests/cli_tests/test_pager.py | 117 | ||||
-rw-r--r-- | tests/cli_tests/test_self_implemented_command.py | 14 | ||||
-rw-r--r-- | tests/cli_tests/test_shell_pipeline.py | 11 | ||||
-rw-r--r-- | tests/cli_tests/test_string_execute.py | 39 | ||||
-rw-r--r-- | tests/cli_tests/test_transaction.py | 70 | ||||
-rw-r--r-- | tests/cli_tests/test_warning.py | 51 | ||||
-rw-r--r-- | tests/cli_tests/wrappager.py | 14 |
15 files changed, 660 insertions, 0 deletions
diff --git a/tests/cli_tests/test_cli_pubsub.py b/tests/cli_tests/test_cli_pubsub.py new file mode 100644 index 0000000..956e105 --- /dev/null +++ b/tests/cli_tests/test_cli_pubsub.py @@ -0,0 +1,31 @@ +def test_subscribe(cli, clean_redis): + cli.sendline("subscribe foo") + cli.expect("subscribe from") + cli.expect("foo") + cli.expect("1") + + clean_redis.publish("foo", "test message") + cli.expect("from") + cli.expect("foo") + cli.expect("test message") + + # unsubscribe, send ctrl-c + cli.send(chr(3)) + cli.expect("unsubscribe from") + cli.expect("0") + + +def test_subscribe_in_raw_mode(raw_cli, clean_redis): + raw_cli.sendline("subscribe foo") + raw_cli.expect("subscribe\r") + raw_cli.expect("foo\r") + raw_cli.expect("1\r") + + clean_redis.publish("foo", "test message") + raw_cli.expect("message\r") + raw_cli.expect("foo\r") + raw_cli.expect("test message") + + # unsubscribe, send ctrl-c + raw_cli.send(chr(3)) + raw_cli.expect("0\r") diff --git a/tests/cli_tests/test_cli_start.py b/tests/cli_tests/test_cli_start.py new file mode 100644 index 0000000..d33185a --- /dev/null +++ b/tests/cli_tests/test_cli_start.py @@ -0,0 +1,75 @@ +import pexpect +import pytest +from textwrap import dedent + + +def test_start_on_connection_error(): + cli = pexpect.spawn("iredis -p 12345", timeout=1) + cli.logfile_read = open("cli_test.log", "ab") + cli.expect(r"Error \d+ connecting to 127.0.0.1:12345. Connection refused.") + cli.close() + + +def test_short_help_option(config): + c = pexpect.spawn("iredis -h", timeout=2) + + c.expect("Show this message and exit.") + + c = pexpect.spawn("iredis -h 127.0.0.1") + c.expect("127.0.0.1:6379>") + + c.close() + + +@pytest.mark.skipif("int(os.environ['REDIS_VERSION']) != 5") +def test_server_version_in_starting_on5(): + c = pexpect.spawn("iredis", timeout=2) + c.expect("redis-server 5") + c.close() + + +@pytest.mark.skipif("int(os.environ['REDIS_VERSION']) != 6") +def test_server_version_in_starting_on6(): + c = pexpect.spawn("iredis", timeout=2) + c.expect("redis-server 6") + c.close() + + +def test_connection_using_url(clean_redis): + c = pexpect.spawn("iredis --url redis://localhost:6379/7", timeout=2) + c.logfile_read = open("cli_test.log", "ab") + c.expect(["iredis", "127.0.0.1:6379[7]>"]) + c.sendline("set current-db 7") + c.expect("OK") + c.close() + + +def test_connection_using_url_from_env(clean_redis, monkeypatch): + monkeypatch.setenv("IREDIS_URL", "redis://localhost:6379/7") + c = pexpect.spawn("iredis", timeout=2) + c.logfile_read = open("cli_test.log", "ab") + c.expect(["iredis", "localhost:6379[7]>"]) + c.sendline("set current-db 7") + c.expect("OK") + c.close() + + +@pytest.mark.xfail(reason="current test in github action, socket not supported.") +# https://github.community/t5/GitHub-Actions/Job-service-command/td-p/33901# +# https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idservices +def test_connect_via_socket(fake_redis_socket): + config_content = dedent( + """ + [main] + log_location = /tmp/iredis1.log + no_info=True + """ + ) + with open("/tmp/iredisrc", "w+") as etc_config: + etc_config.write(config_content) + + c = pexpect.spawn("iredis --iredisrc /tmp/iredisrc -s /tmp/test.sock", timeout=2) + c.logfile_read = open("cli_test.log", "ab") + c.expect("redis /tmp/test.sock") + + c.close() diff --git a/tests/cli_tests/test_command_input.py b/tests/cli_tests/test_command_input.py new file mode 100644 index 0000000..4f970f5 --- /dev/null +++ b/tests/cli_tests/test_command_input.py @@ -0,0 +1,55 @@ +import pytest + + +def test_wrong_select_db_index(cli): + cli.sendline("select 1") + cli.expect(["OK", "127.0.0.1"]) + + cli.sendline("select 128") + cli.expect(["DB index is out of range", "127.0.0.1:6379[1]>"]) + + cli.sendline("select abc") + cli.expect(["invalid DB index", "127.0.0.1:6379[1]>"]) + + cli.sendline("select 15") + cli.expect("OK") + + +def test_set_command_with_shash(clean_redis, cli): + cli.sendline("set a \\hello\\") # legal redis command + cli.expect("OK") + + cli.sendline("get a") + cli.expect(r"hello") + + +def test_enter_key_binding(clean_redis, cli): + cli.send("set") + cli.expect("set") + cli.send("\033[B") # down + cli.sendline() # enter + + cli.sendline(" a 'hello'") + cli.expect("OK") + + cli.sendline("get a") + cli.expect(r"hello") + + +@pytest.mark.skipif("int(os.environ['REDIS_VERSION']) < 6") +def test_auth_hidden_password_with_username(clean_redis, cli): + cli.send("auth default hello-world") + cli.expect("default") + cli.expect(r"\*{11}") + + +@pytest.mark.skipif("int(os.environ['REDIS_VERSION']) > 5") +def test_auth_hidden_password(clean_redis, cli): + cli.send("auth hello-world") + cli.expect("auth") + cli.expect(r"\*{11}") + + +def test_hello_command_is_not_supported(cli): + cli.sendline("hello 3") + cli.expect("IRedis currently not support RESP3") diff --git a/tests/cli_tests/test_completer.py b/tests/cli_tests/test_completer.py new file mode 100644 index 0000000..4ffd058 --- /dev/null +++ b/tests/cli_tests/test_completer.py @@ -0,0 +1,51 @@ +import pytest + + +def test_integer_type_completer(cli): + cli.expect("127.0.0.1") + cli.send("BITFIELD meykey GET ") + cli.expect(["i64", "u63", "u62"]) + cli.sendline("u4 #0") + cli.expect("127.0.0.1") + + cli.send("BITFIELD meykey GET ") + cli.expect(["u4", "i64", "u63", "u62"]) + + +def test_command_completion_when_a_command_is_another_command_substring( + cli, clean_redis +): + cli.expect("127.0.0.1") + cli.send("set") + cli.expect(["set", "setnx", "setex", "setbit", "setrange"]) + + cli.send("n") + cli.expect("setnx") + cli.send("x") + cli.expect("setnx") + cli.sendline("foo bar") + cli.expect(["1", "127.0.0.1"]) + + cli.send("setnx") + cli.expect("foo") + + +def test_command_completion_when_space_command(cli, clean_redis): + cli.expect("127.0.0.1") + + cli.send("command in") + cli.expect("command info") + + +@pytest.mark.skipif("int(os.environ['REDIS_VERSION']) < 6") +def test_username_completer(cli, iredis_client): + iredis_client.execute("acl setuser", "foo1") + iredis_client.execute("acl setuser", "bar2") + + cli.expect("127.0.0.1") + cli.sendline("acl users") + cli.expect("foo1") + + cli.send("acl deluser ") + cli.expect("foo1") + cli.expect("bar2") diff --git a/tests/cli_tests/test_config.py b/tests/cli_tests/test_config.py new file mode 100644 index 0000000..7d6839d --- /dev/null +++ b/tests/cli_tests/test_config.py @@ -0,0 +1,25 @@ +import pexpect +from textwrap import dedent +from pathlib import Path + + +def test_log_location_config(): + config_content = dedent( + """ + [main] + log_location = /tmp/iredis1.log + """ + ) + with open("/tmp/iredisrc", "w+") as etc_config: + etc_config.write(config_content) + + cli = pexpect.spawn("iredis -n 15 --iredisrc /tmp/iredisrc", timeout=1) + cli.expect("127.0.0.1") + cli.close() + + log = Path("/tmp/iredis1.log") + assert log.exists() + with open(log, "r") as logfile: + content = logfile.read() + + assert len(content) > 100 diff --git a/tests/cli_tests/test_dsn.py b/tests/cli_tests/test_dsn.py new file mode 100644 index 0000000..8c9528d --- /dev/null +++ b/tests/cli_tests/test_dsn.py @@ -0,0 +1,53 @@ +import os + +import pexpect +from textwrap import dedent +import pytest + + +def test_using_dsn(): + config_content = dedent( + """ + [alias_dsn] + local = redis://localhost:6379/15 + """ + ) + with open("/tmp/iredisrc", "w+") as etc_config: + etc_config.write(config_content) + + cli = pexpect.spawn("iredis --iredisrc /tmp/iredisrc --dsn local", timeout=1) + cli.logfile_read = open("cli_test.log", "ab") + cli.expect(["iredis", "localhost:6379[15]>"]) + cli.close() + + # overwrite with -n + cli = pexpect.spawn("iredis --iredisrc /tmp/iredisrc --dsn local -n 3", timeout=1) + cli.logfile_read = open("cli_test.log", "ab") + cli.expect(["iredis", "localhost:6379[3]>"]) + cli.close() + + # dsn not exists + cli = pexpect.spawn("iredis --iredisrc /tmp/iredisrc --dsn ghost-dsn", timeout=1) + cli.expect(["Could not find the specified DSN in the config file."]) + cli.close() + assert cli.status == 1 + + +@pytest.mark.skipif( + not os.path.exists("/tmp/redis/redis.sock"), reason="unix socket is not found" +) +def test_using_dsn_unix(): + config_content = dedent( + """ + [alias_dsn] + unix = unix:///tmp/redis/redis.sock?db=3 + """ + ) + with open("/tmp/iredisrc", "w+") as etc_config: + etc_config.write(config_content) + + cli = pexpect.spawn("iredis --iredisrc /tmp/iredisrc --dsn unix", timeout=2) + cli.logfile_read = open("cli_test.log", "ab") + cli.expect(["iredis", "redis /tmp/redis/redis.sock[3]>"]) + + cli.close() diff --git a/tests/cli_tests/test_history.py b/tests/cli_tests/test_history.py new file mode 100644 index 0000000..09e6c82 --- /dev/null +++ b/tests/cli_tests/test_history.py @@ -0,0 +1,42 @@ +import os +import pexpect +from pathlib import Path +from textwrap import dedent + + +def test_history_not_log_auth(cli): + cli.sendline("AUTH 123") + cli.expect(["Client sent AUTH, but no password is set", "127.0.0.1"]) + cli.sendline("set foo bar") + cli.expect("OK") + + with open(os.path.expanduser("~/.iredis_history"), "r") as history_file: + content = history_file.read() + + assert "set foo bar" in content + assert "AUTH" not in content + + +def test_history_create_and_writing_with_config(): + config_content = dedent( + """ + [main] + history_location = /tmp/iredis_history.txt + """ + ) + with open("/tmp/iredisrc", "w+") as etc_config: + etc_config.write(config_content) + + cli = pexpect.spawn("iredis -n 15 --iredisrc /tmp/iredisrc", timeout=2) + cli.expect("127.0.0.1") + cli.sendline("set hello world") + cli.expect("OK") + cli.close() + + log = Path("/tmp/iredis_history.txt") + assert log.exists() + + with open(log, "r") as logfile: + content = logfile.read() + + assert "set hello world" in content diff --git a/tests/cli_tests/test_on_error.py b/tests/cli_tests/test_on_error.py new file mode 100644 index 0000000..9ab8927 --- /dev/null +++ b/tests/cli_tests/test_on_error.py @@ -0,0 +1,12 @@ +def test_wrong_stream_type(clean_redis, cli): + clean_redis.lpush("mylist", "foo") + cli.sendline("xrange mylist 0 -1") + cli.expect("error") + cli.expect("Invalid stream ID specified as stream command argument") + + +def test_wrong_stream_type_in_raw_mode(clean_redis, raw_cli): + clean_redis.lpush("mylist", "foo") + raw_cli.sendline("xrange mylist 0 -1") + raw_cli.expect("ERROR") + raw_cli.expect("Invalid stream ID specified as stream command argument") diff --git a/tests/cli_tests/test_pager.py b/tests/cli_tests/test_pager.py new file mode 100644 index 0000000..38ced31 --- /dev/null +++ b/tests/cli_tests/test_pager.py @@ -0,0 +1,117 @@ +# noqa: F541 +import os +import sys +import pexpect +import pathlib +from contextlib import contextmanager +from textwrap import dedent + + +TEST_IREDISRC = "/tmp/.iredisrc.test" +TEST_PAGER_BOUNDARY = "---boundary---" +TEST_PAGER_BOUNDARY_NUMBER = "---88938347271---" + +env_pager = "{0} {1} {2}".format( + sys.executable, + os.path.join(pathlib.Path(__file__).parent, "wrappager.py"), + TEST_PAGER_BOUNDARY, +) +env_pager_numbers = "{0} {1} {2}".format( + sys.executable, + os.path.join(pathlib.Path(__file__).parent, "wrappager.py"), + TEST_PAGER_BOUNDARY_NUMBER, +) + + +@contextmanager +def pager_enabled_cli(): + env = os.environ + env["PAGER"] = env_pager + child = pexpect.spawn("iredis -n 15", timeout=3, env=env) + child.logfile_read = open("cli_test.log", "ab") + child.expect("127.0.0.1") + try: + yield child + finally: + child.close() + + +def test_using_pager_when_rows_too_high(clean_redis): + for index in range(100): + clean_redis.lpush("long-list", f"value-{index}") + with pager_enabled_cli() as child: + child.sendline("lrange long-list 0 -1") + child.expect(TEST_PAGER_BOUNDARY) + child.expect("value-1") + child.expect(TEST_PAGER_BOUNDARY) + + +def test_using_pager_works_for_help(): + with pager_enabled_cli() as child: + child.sendline("help set") + child.expect(TEST_PAGER_BOUNDARY) + child.expect("Set the string value of a key") + child.expect(TEST_PAGER_BOUNDARY) + + +def test_pager_works_for_peek(clean_redis): + for index in range(100): + clean_redis.lpush("long-list", f"value-{index}") + with pager_enabled_cli() as child: + child.sendline("peek long-list") + child.expect(TEST_PAGER_BOUNDARY) + child.expect("(quicklist)") + child.expect("value-1") + child.expect(TEST_PAGER_BOUNDARY) + + +def test_using_pager_from_config(clean_redis): + config_content = dedent( + f""" + [main] + log_location = /tmp/iredis1.log + pager = {env_pager_numbers} + """ + ) + + with open(TEST_IREDISRC, "w+") as test_iredisrc: + test_iredisrc.write(config_content) + + child = pexpect.spawn(f"iredis -n 15 --iredisrc {TEST_IREDISRC}", timeout=3) + child.logfile_read = open("cli_test.log", "ab") + child.expect("127.0.0.1") + for index in range(100): + clean_redis.lpush("long-list", f"value-{index}") + child.sendline("lrange long-list 0 -1") + child.expect(TEST_PAGER_BOUNDARY_NUMBER) + child.expect("value-1") + child.expect(TEST_PAGER_BOUNDARY_NUMBER) + child.close() + + +def test_using_pager_from_config_when_env_config_both_set(clean_redis): + config_content = dedent( + f""" + [main] + log_location = /tmp/iredis1.log + pager = {env_pager_numbers} + """ + ) + + with open(TEST_IREDISRC, "w+") as test_iredisrc: + test_iredisrc.write(config_content) + + env = os.environ + env["PAGER"] = env_pager + child = pexpect.spawn( + f"iredis -n 15 --iredisrc {TEST_IREDISRC}", timeout=3, env=env + ) + child.logfile_read = open("cli_test.log", "ab") + child.expect("127.0.0.1") + for index in range(100): + clean_redis.lpush("long-list", f"value-{index}") + child.sendline("lrange long-list 0 -1") + child.expect(TEST_PAGER_BOUNDARY_NUMBER) + child.expect("value-1") + child.expect(TEST_PAGER_BOUNDARY_NUMBER) + child.close() diff --git a/tests/cli_tests/test_self_implemented_command.py b/tests/cli_tests/test_self_implemented_command.py new file mode 100644 index 0000000..328d56b --- /dev/null +++ b/tests/cli_tests/test_self_implemented_command.py @@ -0,0 +1,14 @@ +""" +check ascii table: +http://ascii-table.com/ansi-escape-sequences.php +""" + + +def test_clear(cli): + cli.sendline("clear") + cli.expect("\\[2J") # clear screen + + +def test_exirt(cli): + cli.sendline("EXIT") + cli.expect("Goodbye!") diff --git a/tests/cli_tests/test_shell_pipeline.py b/tests/cli_tests/test_shell_pipeline.py new file mode 100644 index 0000000..4bacf8d --- /dev/null +++ b/tests/cli_tests/test_shell_pipeline.py @@ -0,0 +1,11 @@ +import pexpect + + +def test_running_disable_shell_pipeline(): + cli = pexpect.spawn("iredis -n 15 --no-shell", timeout=2) + cli.expect("127.0.0.1") + cli.sendline("set foo hello") + cli.expect("OK") + cli.sendline("get foo | grep w") + cli.expect(r"hello") + cli.close() diff --git a/tests/cli_tests/test_string_execute.py b/tests/cli_tests/test_string_execute.py new file mode 100644 index 0000000..310adab --- /dev/null +++ b/tests/cli_tests/test_string_execute.py @@ -0,0 +1,39 @@ +def test_set(cli): + cli.sendline("set foo bar") + cli.expect(["OK", "127.0.0.1"]) + + cli.sendline("set foo bar nx") + cli.expect(["(nil)", "127.0.0.1"]) + + cli.sendline("set foo bar xx") + cli.expect(["OK", "127.0.0.1"]) + + cli.sendline("set foo1 bar xx") + cli.expect(["(nil)", "127.0.0.1"]) + + +def test_get(cli): + cli.sendline("set foo bar") + cli.expect("OK") + + cli.sendline("get foo") + cli.expect('"bar"') + + +def test_delete_string(clean_redis, cli, config): + config.warning = True + cli.sendline("set foo bar") + cli.expect("OK") + cli.sendline("del foo") + cli.expect("Do you want to proceed") + cli.sendline("yes") + cli.expect("1") + + cli.sendline("get foo") + cli.expect("(nil)") + + +def test_on_dangerous_commands(cli, config): + config.warning = True + cli.sendline("keys *") + cli.expect("KEYS will hang redis server, use SCAN instead") diff --git a/tests/cli_tests/test_transaction.py b/tests/cli_tests/test_transaction.py new file mode 100644 index 0000000..b5c6b4e --- /dev/null +++ b/tests/cli_tests/test_transaction.py @@ -0,0 +1,70 @@ +import pytest +import pexpect + + +def test_trasaction_rprompt(clean_redis, cli): + cli.sendline("multi") + cli.expect(["OK", "transaction", "127.0.0.1"]) + + cli.sendline("get foo") + cli.expect(["QUEUED", "127.0.0.1", "transaction"]) + + cli.sendline("set hello world") + cli.expect(["QUEUED", "127.0.0.1", "transaction"]) + + cli.sendline("ping") + cli.expect(["QUEUED", "127.0.0.1", "transaction"]) + + cli.sendline("EXEC") + cli.expect("(nil)") + cli.expect("OK") + cli.expect("PONG") + cli.expect("127.0.0.1") + + with pytest.raises(pexpect.exceptions.TIMEOUT): + cli.expect("transaction") + + +def test_trasaction_syntax_error(cli): + cli.sendline("multi") + cli.sendline("get foo 1") + cli.expect(["wrong number of arguments for 'get' command", "transaction"]) + + cli.sendline("EXEC") + cli.expect("Transaction discarded because of previous errors.") + with pytest.raises(pexpect.exceptions.TIMEOUT): + cli.expect("transaction") + + +def test_trasaction_in_raw_mode(clean_redis, raw_cli): + clean_redis.set("foo", "bar") + + raw_cli.sendline("multi") + raw_cli.expect(["OK", "transaction", "127.0.0.1"]) + + raw_cli.sendline("get foo") + raw_cli.expect(["QUEUED", "127.0.0.1", "transaction"]) + + raw_cli.sendline("EXEC") + raw_cli.expect("bar") + raw_cli.expect("127.0.0.1") + + with pytest.raises(pexpect.exceptions.TIMEOUT): + raw_cli.expect("transaction") + + +def test_exec_return_nil_when_using_watch(clean_redis, cli): + cli.sendline("watch foo") + cli.expect("OK") + + cli.sendline("multi") + cli.expect("OK") + + cli.sendline("get bar") + cli.expect("QUEUED") + + # transaction will fail, return nil + clean_redis.set("foo", "hello!") + + cli.sendline("exec") + cli.expect("(nil)") diff --git a/tests/cli_tests/test_warning.py b/tests/cli_tests/test_warning.py new file mode 100644 index 0000000..402c51b --- /dev/null +++ b/tests/cli_tests/test_warning.py @@ -0,0 +1,51 @@ +from iredis.warning import is_dangerous + + +def test_is_dangerous(): + assert is_dangerous("KEYS") == ( + True, + "KEYS will hang redis server, use SCAN instead", + ) + + +def test_warning_for_dangerous_command(cli): + cli.sendline("config set save '900 1'") + cli.expect("Do you want to proceed?") + cli.sendline("yes") + + cli.sendline("config get save") + cli.expect("900 1") + + +def test_warnings_in_raw_mode(clean_redis, raw_cli): + clean_redis.set("foo", "bar") + raw_cli.sendline("keys *") + raw_cli.expect("Do you want to proceed?") + raw_cli.sendline("y") + raw_cli.expect("foo") + + +def test_warnings_in_raw_mode_canceled(clean_redis, raw_cli): + clean_redis.set("foo", "bar") + raw_cli.sendline("keys *") + raw_cli.expect("Do you want to proceed?") + raw_cli.sendline("n") + # the f should never appeared + raw_cli.expect("Canceled![^f]+127.0.0.1") + + +def test_warnings_confirmed(clean_redis, cli): + clean_redis.set("foo", "bar") + cli.sendline("keys *") + cli.expect("Do you want to proceed?") + cli.sendline("y") + cli.expect("foo") + + +def test_warnings_canceled(clean_redis, cli): + clean_redis.set("foo", "bar") + cli.sendline("keys *") + cli.expect("Do you want to proceed?") + cli.sendline("n") + # the f should never appeared + cli.expect("Canceled![^f]+127.0.0.1") diff --git a/tests/cli_tests/wrappager.py b/tests/cli_tests/wrappager.py new file mode 100644 index 0000000..dce86ce --- /dev/null +++ b/tests/cli_tests/wrappager.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python +import sys +import fileinput + + +def wrappager(boundary): + print(boundary) + for line in fileinput.input(files="-"): + sys.stdout.write(line) + print(boundary) + + +if __name__ == "__main__": + wrappager(sys.argv[1]) |