maestral/tests/offline/test_cli.py
2023-02-01 21:42:40 +01:00

244 lines
7.4 KiB
Python

import logging
from click.testing import CliRunner
from maestral.main import Maestral
from maestral.cli import main
from maestral.autostart import AutoStart
from maestral.notify import level_number_to_name, level_name_to_number
from maestral.daemon import MaestralProxy, start_maestral_daemon_process, Start
from maestral.logging import scoped_logger
from maestral.utils.appdirs import get_log_path
TEST_TIMEOUT = 60
def test_help() -> None:
"""Test help output without args and with --help arg."""
runner = CliRunner()
result_no_arg = runner.invoke(main)
result_help_arg = runner.invoke(main, ["--help"])
assert result_no_arg.exit_code == 0, result_no_arg.output
assert result_no_arg.output.startswith("Usage: main [OPTIONS] COMMAND [ARGS]")
assert result_no_arg.output == result_help_arg.output
def test_invalid_config() -> None:
"""Test failure of commands that require an existing config file"""
for command in [
("stop",),
("pause",),
("resume",),
("auth", "status"),
("auth", "unlink"),
("sharelink", "create"),
("sharelink", "list"),
("sharelink", "revoke"),
("status",),
("filestatus",),
("activity",),
("history",),
("ls",),
("autostart",),
("excluded", "add"),
("excluded", "list"),
("excluded", "remove"),
("notify", "level"),
("notify", "snooze"),
("move-dir",),
("rebuild-index",),
("revs",),
("diff",),
("restore",),
("log", "level"),
("log", "clear"),
("log", "show"),
("config", "get", "path"),
("config", "set", "path"),
("config", "show"),
]:
runner = CliRunner()
result = runner.invoke(main, [*command, "-c", "non-existent-config"])
assert result.exit_code == 1, command
assert (
result.output == "! Configuration 'non-existent-config' does not exist. "
"Use 'maestral config-files' to list all configurations.\n"
)
def test_start_already_running(config_name: str) -> None:
res = start_maestral_daemon_process(config_name, timeout=TEST_TIMEOUT)
assert res is Start.Ok
runner = CliRunner()
result = runner.invoke(main, ["start", "-c", config_name])
assert result.exit_code == 0, result.output
assert "already running" in result.output
def test_stop(config_name: str) -> None:
res = start_maestral_daemon_process(config_name, timeout=TEST_TIMEOUT)
assert res is Start.Ok
runner = CliRunner()
result = runner.invoke(main, ["stop", "-c", config_name])
assert result.exit_code == 0, result.output
def test_filestatus(m: Maestral) -> None:
runner = CliRunner()
result = runner.invoke(main, ["filestatus", "/usr", "-c", m.config_name])
assert result.exit_code == 0, result.output
assert result.output == "unwatched\n"
result = runner.invoke(main, ["filestatus", "/invalid-dir", "-c", m.config_name])
# the exception will be already raised by click's argument check
assert result.exit_code == 2
assert isinstance(result.exception, SystemExit)
assert "'/invalid-dir' does not exist" in result.output
def test_autostart(m: Maestral) -> None:
autostart = AutoStart(m.config_name)
autostart.disable()
runner = CliRunner()
result = runner.invoke(main, ["autostart", "-c", m.config_name])
assert result.exit_code == 0, result.output
assert "disabled" in result.output
result = runner.invoke(main, ["autostart", "-Y", "-c", m.config_name])
if autostart.implementation:
if result.exit_code == 0:
assert "Enabled" in result.output
assert autostart.enabled
else:
# TODO: be more specific here
assert result.exception is not None
else:
assert "not supported" in result.output
assert not autostart.enabled
result = runner.invoke(main, ["autostart", "-N", "-c", m.config_name])
assert result.exit_code == 0, result.output
assert "Disabled" in result.output
assert not autostart.enabled
def test_excluded_list(m: Maestral) -> None:
runner = CliRunner()
result = runner.invoke(main, ["excluded", "list", "-c", m.config_name])
assert result.exit_code == 0, result.output
assert result.output == "No excluded files or folders.\n"
def test_notify_level(config_name: str) -> None:
start_maestral_daemon_process(config_name, timeout=TEST_TIMEOUT)
m = MaestralProxy(config_name)
runner = CliRunner()
result = runner.invoke(main, ["notify", "level", "-c", m.config_name])
level_name = level_number_to_name(m.notification_level)
assert result.exit_code == 0, result.output
assert level_name in result.output
level_name = "SYNCISSUE"
level_number = level_name_to_number(level_name)
result = runner.invoke(main, ["notify", "level", level_name, "-c", m.config_name])
assert result.exit_code == 0, result.output
assert level_name in result.output
assert m.notification_level == level_number
result = runner.invoke(main, ["notify", "level", "INVALID", "-c", m.config_name])
assert result.exit_code == 2
assert isinstance(result.exception, SystemExit)
def test_notify_snooze(config_name: str) -> None:
start_maestral_daemon_process(config_name, timeout=TEST_TIMEOUT)
m = MaestralProxy(config_name)
runner = CliRunner()
result = runner.invoke(main, ["notify", "snooze", "20", "-c", m.config_name])
assert result.exit_code == 0, result.output
assert 0 < m.notification_snooze <= 20
result = runner.invoke(main, ["notify", "snooze", "0", "-c", m.config_name])
assert result.exit_code == 0, result.output
assert m.notification_snooze == 0
def test_log_level(m: Maestral) -> None:
runner = CliRunner()
result = runner.invoke(main, ["log", "level", "-c", m.config_name])
level_name = logging.getLevelName(m.log_level)
assert result.exit_code == 0, result.output
assert level_name in result.output
result = runner.invoke(main, ["log", "level", "DEBUG", "-c", m.config_name])
assert result.exit_code == 0, result.output
assert "DEBUG" in result.output
result = runner.invoke(main, ["notify", "level", "INVALID", "-c", m.config_name])
assert result.exit_code == 2
assert isinstance(result.exception, SystemExit)
def test_log_show(m: Maestral) -> None:
# log a message
logger = scoped_logger("maestral", m.config_name)
logger.info("Hello from pytest!")
runner = CliRunner()
result = runner.invoke(main, ["log", "show", "-c", m.config_name])
assert result.exit_code == 0, result.output
assert "Hello from pytest!" in result.output
def test_log_clear(m: Maestral) -> None:
# log a message
logger = scoped_logger("maestral", m.config_name)
logger.info("Hello from pytest!")
runner = CliRunner()
result = runner.invoke(main, ["log", "show", "-c", m.config_name])
assert result.exit_code == 0, result.output
assert "Hello from pytest!" in result.output
# Stop connection helper to prevent spurious log messages.
m.manager._connection_helper_running = False
m.manager.connection_helper.join()
# clear the logs
result = runner.invoke(main, ["log", "clear", "-c", m.config_name])
assert result.exit_code == 0, result.output
logfile = get_log_path("maestral", f"{m.config_name}.log")
with open(logfile) as f:
log_content = f.read()
assert log_content == ""