# -*- coding: utf-8 -*-
+import re
from dataclasses import dataclass
from unittest import mock
import pika.channel
import pika.spec
+import pytest
from slixmpp import Message, JID
from distbot.bot.bot import Bot
+from distbot.bot.worker import Worker
@dataclass
return AMQPCallback(ch=channel, method=method, properties=props, body=body)
-def inject_callback(msg: str, sender: str, bot_nick: str):
+def get_amqp_callback_params(msg: str, sender: str, bot_nick: str) -> AMQPCallback:
# Message interface is used like a dict
# msg_mock = mock.MagicMock(spec=Message)
msg_mock = {
"type": "groupchat",
"body": msg,
}
- return AMQPCallback.from_message(msg=msg_mock, bot_nick=bot_nick).__dict__
+ return AMQPCallback.from_message(msg=msg_mock, bot_nick=bot_nick)
+
+class LocalMessageBroker:
+ def __init__(self):
+ self.recipients = []
+
+ def add_recipient(self, recipient: Worker):
+ self.recipients.append(recipient)
+
+ def route_message(self, msg: str, sender: str, bot_nick: str):
+ params = get_amqp_callback_params(msg, sender, bot_nick)
+ for recipient in self.recipients:
+ for binding_key in recipient.binding_keys:
+ if self.matches(binding_key, params.method.routing_key):
+ recipient.callback(**params.__dict__)
+ break
+
+ @staticmethod
+ def matches(binding_key, message_routing_key):
+ regex = binding_key.replace('.', '\\.').replace('*', '[^.]+').replace('#', '.*')
+ # fix .# leading to \..*
+ regex = re.sub(r"\\.\.\*$", ".*", regex)
+ return re.fullmatch(regex, message_routing_key) is not None
+
+
+@pytest.mark.parametrize("bind,msg_routing_key", [
+ ("nick.dice.#", "nick.dice"),
+ ("nick.dice.#", "nick.dice.2"),
+])
+def test_local_message_broker(bind, msg_routing_key):
+ assert LocalMessageBroker.matches(bind, msg_routing_key)
\ No newline at end of file
from distbot.bot import worker
from distbot.plugins import openai
+from bot_test_utils import LocalMessageBroker
@pytest.fixture(name="send_action")
@pytest.fixture
def bot_nick():
- return "doofibot"
\ No newline at end of file
+ return "doofibot"
+
+@pytest.fixture(scope="function")
+def message_broker():
+ lmb = LocalMessageBroker()
+ # TODO another fixture maybe
+ # from distbot.minijobber.run import PLUGIN_MODULES
+ # for plugin_bunch in PLUGIN_MODULES.values():
+ # for plugin in plugin_bunch:
+ # lmb.add_recipient(plugin(None))
+ return lmb
from distbot.common.action import Action
from distbot.plugins.basic import Dice, Choose
-from tests.test_integration.bot_test_utils import inject_callback
"""
Goal: have a parameterized pipeline of
2. [somehow] replicate matching of rabbitmq topic
3. invoke Worker-interface with the raw body? using Worker.callback(..)
-TODO: plugins.resolve(message).callback() for (2)
"""
@pytest.mark.parametrize(["dice_count"], argvalues=(
[None], [1], [3], [100]
))
-def test_dice(send_action, randomint, bot_nick, dice_count):
+def test_dice(send_action, randomint, bot_nick, dice_count, message_broker):
args = f" {dice_count}" if dice_count else ""
- Dice(None).callback(**inject_callback(msg=f"{bot_nick}: dice" + args, sender="you", bot_nick=bot_nick))
+ message_broker.add_recipient(Dice(None))
+ message_broker.route_message(msg=f"{bot_nick}: dice" + args, sender="you", bot_nick=bot_nick)
result = {
"None": "rolling a dice for you: ⚂ (3)",
[2, "do_something do_nothing"],
[3, """ "to do something" "to do nothing" """],
))
-def test_quoted_choose(send_action, mock_openai, randomchoice, bot_nick, i, choices, monkeypatch):
+def test_quoted_choose(send_action, mock_openai, randomchoice, bot_nick, i, choices, monkeypatch, message_broker):
with mock.patch.object(Choose, "weighted_choice") as mock_weighted_choice:
mock_weighted_choice.side_effect = lambda l: l[0][0] # first option wins
- Choose(None).callback(**inject_callback(msg=f"{bot_nick}: choose " + choices, sender="you", bot_nick=bot_nick))
+ message_broker.add_recipient(Choose(None))
+ message_broker.route_message(msg=f"{bot_nick}: choose " + choices, sender="you", bot_nick=bot_nick)
result = {
0: "you: Yes.",