mostr-zulip-bot/zulip_bots/zulip_bots/tests/test_run.py
Anders Kaseorg e747d3b712 mypy: Enable no_implicit_reexport.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
2023-10-26 13:38:57 -07:00

155 lines
6.2 KiB
Python

#!/usr/bin/env python3
import os
import sys
import unittest
from pathlib import Path
from typing import Optional
from unittest import TestCase, mock
from unittest.mock import MagicMock, patch
import importlib_metadata as metadata
import zulip_bots.run
from zulip_bots.lib import extract_query_without_mention
class TestDefaultArguments(TestCase):
our_dir = os.path.dirname(__file__)
path_to_bot = os.path.abspath(os.path.join(our_dir, "../bots/giphy/giphy.py"))
packaged_bot_module = MagicMock(__version__="1.0.0")
packaged_bot_entrypoint = metadata.EntryPoint(
"packaged_bot", "module_name", "zulip_bots.registry"
)
@patch("sys.argv", ["zulip-run-bot", "giphy", "--config-file", "/foo/bar/baz.conf"])
@patch("zulip_bots.run.run_message_handler_for_bot")
def test_argument_parsing_with_bot_name(
self, mock_run_message_handler_for_bot: mock.Mock
) -> None:
with patch("zulip_bots.run.exit_gracefully_if_zulip_config_is_missing"):
zulip_bots.run.main()
mock_run_message_handler_for_bot.assert_called_with(
bot_name="giphy",
config_file="/foo/bar/baz.conf",
bot_config_file=None,
lib_module=mock.ANY,
bot_source="source",
quiet=False,
)
@patch("sys.argv", ["zulip-run-bot", path_to_bot, "--config-file", "/foo/bar/baz.conf"])
@patch("zulip_bots.run.run_message_handler_for_bot")
def test_argument_parsing_with_bot_path(
self, mock_run_message_handler_for_bot: mock.Mock
) -> None:
with patch("zulip_bots.run.exit_gracefully_if_zulip_config_is_missing"):
zulip_bots.run.main()
mock_run_message_handler_for_bot.assert_called_with(
bot_name="giphy",
config_file="/foo/bar/baz.conf",
bot_config_file=None,
lib_module=mock.ANY,
bot_source="source",
quiet=False,
)
@patch(
"sys.argv", ["zulip-run-bot", "packaged_bot", "--config-file", "/foo/bar/baz.conf", "-r"]
)
@patch("zulip_bots.run.run_message_handler_for_bot")
def test_argument_parsing_with_zulip_bot_registry(
self, mock_run_message_handler_for_bot: mock.Mock
) -> None:
with patch("zulip_bots.run.exit_gracefully_if_zulip_config_is_missing"), patch(
"zulip_bots.finder.metadata.EntryPoint.load",
return_value=self.packaged_bot_module,
), patch(
"zulip_bots.finder.metadata.entry_points",
return_value=(self.packaged_bot_entrypoint,),
):
zulip_bots.run.main()
mock_run_message_handler_for_bot.assert_called_with(
bot_name="packaged_bot",
config_file="/foo/bar/baz.conf",
bot_config_file=None,
lib_module=mock.ANY,
bot_source="packaged_bot: 1.0.0",
quiet=False,
)
def test_adding_bot_parent_dir_to_sys_path_when_bot_name_specified(self) -> None:
bot_name = "helloworld" # existing bot's name
expected_bot_dir_path = Path(
os.path.dirname(zulip_bots.run.__file__), "bots", bot_name
).as_posix()
self._test_adding_bot_parent_dir_to_sys_path(
bot_qualifier=bot_name, bot_dir_path=expected_bot_dir_path
)
@patch("os.path.isfile", return_value=True)
def test_adding_bot_parent_dir_to_sys_path_when_bot_path_specified(
self, mock_os_path_isfile: mock.Mock
) -> None:
bot_path = "/path/to/bot"
expected_bot_dir_path = Path("/path/to").as_posix()
self._test_adding_bot_parent_dir_to_sys_path(
bot_qualifier=bot_path, bot_dir_path=expected_bot_dir_path
)
def _test_adding_bot_parent_dir_to_sys_path(
self, bot_qualifier: str, bot_dir_path: str
) -> None:
with patch(
"sys.argv", ["zulip-run-bot", bot_qualifier, "--config-file", "/path/to/config"]
):
with patch("zulip_bots.finder.import_module_from_source", return_value=mock.Mock()):
with patch("zulip_bots.run.run_message_handler_for_bot"):
with patch("zulip_bots.run.exit_gracefully_if_zulip_config_is_missing"):
zulip_bots.run.main()
sys_path = [Path(path).as_posix() for path in sys.path]
self.assertIn(bot_dir_path, sys_path)
@patch("os.path.isfile", return_value=False)
def test_run_bot_by_module_name(self, mock_os_path_isfile: mock.Mock) -> None:
bot_module_name = "bot.module.name"
mock_bot_module = mock.Mock()
mock_bot_module.__name__ = bot_module_name
with patch(
"sys.argv", ["zulip-run-bot", "bot.module.name", "--config-file", "/path/to/config"]
):
with patch("zulip_bots.run.run_message_handler_for_bot"):
with patch("zulip_bots.run.exit_gracefully_if_zulip_config_is_missing"):
with patch(
"importlib.import_module", return_value=mock_bot_module
) as mock_import_module:
zulip_bots.run.main()
mock_import_module.assert_called_once_with(bot_module_name)
class TestBotLib(TestCase):
def test_extract_query_without_mention(self) -> None:
def test_message(name: str, message: str, expected_return: Optional[str]) -> None:
mock_client = mock.MagicMock()
mock_client.full_name = name
mock_message = {"content": message}
self.assertEqual(
expected_return, extract_query_without_mention(mock_message, mock_client)
)
test_message("xkcd", "@**xkcd**foo", "foo")
test_message("xkcd", "@**xkcd** foo", "foo")
test_message("xkcd", "@**xkcd** foo bar baz", "foo bar baz")
test_message("xkcd", "@**xkcd** foo bar baz", "foo bar baz")
test_message("xkcd", "@**xkcd** 123_) (/&%) +}}}l", "123_) (/&%) +}}}l")
test_message("brokenmention", "@**brokenmention* foo", None)
test_message("nomention", "foo", None)
test_message("Max Mustermann", "@**Max Mustermann** foo", "foo")
test_message(r"Max (Mustermann)#(*$&12]\]", r"@**Max (Mustermann)#(*$&12]\]** foo", "foo")
if __name__ == "__main__":
unittest.main()