def test_handle_webhook(self): # Create an initialized plugin so its listeners are registered driver = Driver() plugin = WebHookExample().initialize(driver, Settings()) # Construct a handler with it handler = EventHandler(driver, Settings(), plugins=[plugin]) # Mock the call_function of the plugin so we can make some asserts async def mock_call_function(function, event, groups): # This is the regexp that we're trying to trigger assert function.matcher.pattern == "ping" assert event.text == "hello!" assert groups == [] with mock.patch.object( plugin, "call_function", wraps=mock_call_function ) as mocked: asyncio.run( handler._handle_webhook( WebHookEvent( body={"text": "hello!"}, request_id="request_id", webhook_id="ping", ), ) ) # Assert the function was called, so we know the asserts succeeded. mocked.assert_called_once()
def test_environment(): assert Settings(MATTERMOST_URL="website.com").MATTERMOST_URL == "website.com" os.environ["MATTERMOST_URL"] = "test_site.org" os.environ["IGNORE_USERS"] = "me,someone_else" s = Settings(MATTERMOST_URL="website.com") assert s.MATTERMOST_URL == "test_site.org" # The environment variable should be parsed into a list. assert s.IGNORE_USERS == ["me", "someone_else"]
def test_constructor(): default = Settings() assert default.MATTERMOST_URL == "chat.com" assert default.SCHEME == "https" assert default.IGNORE_USERS == [] manual = Settings( MATTERMOST_URL="http://website.com", IGNORE_USERS=["me", "someone_else"] ) assert manual.MATTERMOST_URL == "website.com" assert manual.SCHEME == "http" assert manual.IGNORE_USERS == ["me", "someone_else"] # Test default scheme assert Settings(MATTERMOST_URL="website.com").SCHEME == "https"
def test_handle_post(self): # Create an initialized plugin so its listeners are registered driver = Driver() plugin = ExamplePlugin().initialize(driver) # Construct a handler with it handler = EventHandler(driver, Settings(), plugins=[plugin]) # Mock the call_function of the plugin so we can make some asserts async def mock_call_function(function, message, groups): # This is the regexp that we're trying to trigger assert function.matcher.pattern == "sleep ([0-9]+)" assert message.text == "sleep 5" # username should be stripped off assert groups == ["5"] # arguments should be matched and passed explicitly with mock.patch.object( plugin, "call_function", wraps=mock_call_function ) as mocked: # Transform the default message into a raw post event so we can pass it new_body = create_message(text="@my_username sleep 5").body.copy() new_body["data"]["post"] = json.dumps(new_body["data"]["post"]) new_body["data"]["mentions"] = json.dumps(new_body["data"]["mentions"]) asyncio.run(handler._handle_post(new_body)) # Assert the function was called, so we know the asserts succeeded. mocked.assert_called_once()
def test_handle_event(self, handle_post): handler = EventHandler(Driver(), Settings(), plugins=[]) # This event should trigger _handle_post asyncio.run(handler._handle_event(json.dumps(create_message().body))) # This event should not asyncio.run(handler._handle_event(json.dumps({"event": "some_other_event"}))) handle_post.assert_called_once_with(create_message().body)
def test_should_ignore(self): handler = EventHandler( Driver(), Settings(IGNORE_USERS=["ignore_me"]), plugins=[] ) # We shouldn't ignore a message from betty, since she is not listed assert not handler._should_ignore(create_message(sender_name="betty")) assert handler._should_ignore(create_message(sender_name="ignore_me")) # We ignore our own messages by default assert handler._should_ignore(create_message(sender_name="my_username")) # But shouldn't do so if this is explicitly requested handler = EventHandler( Driver(), Settings(IGNORE_USERS=["ignore_me"]), plugins=[], ignore_own_messages=False, ) assert not handler._should_ignore(create_message(sender_name="my_username"))
def driver(): return Bot( settings=Settings( MATTERMOST_URL="http://127.0.0.1", BOT_TOKEN="7arqwr6kzibc58zomct9ndfk1e", MATTERMOST_PORT=8065, SSL_VERIFY=False, WEBHOOK_HOST_ENABLED=True, WEBHOOK_HOST_URL="http://127.0.0.1", WEBHOOK_HOST_PORT=8579, ), plugins= [], # We only use this to send messages, not to reply to anything. ).driver
def test_start(self, threadpool): # Test server startup with a different port so it won't clash with the # integration tests server = WebHookServer(port=3281, url=Settings().WEBHOOK_HOST_URL) threadpool.start_webhook_server_thread(server) threadpool.start() time.sleep(0.5) assert server.running asyncio.set_event_loop(asyncio.new_event_loop()) # Run the other tests sequentially self.test_obtain_response(server) self.test_process_webhook(server) # Test shutdown procedure threadpool.stop() assert not server.running
def start_bot(request): lock = FileLock("./bot.lock") try: # We want to run the tests in multiple parallel processes, but launch at most # a single bot. lock.acquire(timeout=0.01) bot = Bot( settings=Settings( MATTERMOST_URL="http://127.0.0.1", BOT_TOKEN="e691u15hajdebcnqpfdceqihcc", MATTERMOST_PORT=8065, SSL_VERIFY=False, WEBHOOK_HOST_ENABLED=True, WEBHOOK_HOST_URL="http://127.0.0.1", WEBHOOK_HOST_PORT=8579, ), plugins=[TestPlugin(), ExamplePlugin(), WebHookExample()], ) def run_bot(): bot.run() # Start the bot now bot_process = Process(target=run_bot) bot_process.start() def stop_bot(): time.sleep(5) bot_process.terminate() lock.release() # Once all tests are finished, stop the bot request.addfinalizer(stop_bot) except TimeoutError: # If the lock times out, it means a bot is already running and we don't need # to do anything here. pass finally: time.sleep(5) # Give the bot some time to start up
def test_init(self, login): # Create some plugins and mock their initialize method so we can check calls plugins = [ExamplePlugin(), TestPlugin()] for plugin in plugins: plugin.initialize = mock.MagicMock() # Create a bot and verify that it gets initialized correctly bot = Bot( settings=Settings(MATTERMOST_URL="test_url.org", BOT_TOKEN="random_token"), plugins=plugins, ) assert bot.driver.options["url"] == "test_url.org" assert bot.driver.options["token"] == "random_token" assert bot.plugins == plugins login.assert_called_once() # Verify that all of the passed plugins were initialized for plugin in plugins: assert plugin.initialize.called_once_with(bot.driver)
def test_click_function(self): @click.command() @click.option("--arg1", type=str, default="nothing") @click.option("--arg2", type=str, default="nothing either") @click.option("-f", "--flag", is_flag=True) def wrapped(self, message, arg1, arg2, flag): return arg1, arg2, flag f = MessageFunction(wrapped, matcher=re.compile("")) # Verify that the arguments are passed and returned correctly assert f(create_message(), "--arg1=yes --arg2=no") == ("yes", "no", False) assert f(create_message(), "-f --arg2=no") == ("nothing", "no", True) # If an incorrect argument is passed, the error and help string should be returned. def mocked_reply(message, response): assert "no such option: --nonexistent-arg" in response assert f.docstring in response f.plugin = ExamplePlugin().initialize(Driver(), Settings()) with mock.patch.object(f.plugin.driver, "reply_to", wraps=mocked_reply) as mock_function: f(create_message(), "-f --arg2=no --nonexistent-arg") mock_function.assert_called_once()
def test_init(self): handler = EventHandler( Driver(), Settings(), plugins=[ExamplePlugin(), WebHookExample()] ) # Test the name matcher regexp assert handler._name_matcher.match("@my_username are you there?") assert not handler._name_matcher.match("@other_username are you there?") # Test that all listeners from the individual plugins are now registered on # the handler for plugin in handler.plugins: for pattern, listener in plugin.message_listeners.items(): assert listener in handler.message_listeners[pattern] for pattern, listener in plugin.webhook_listeners.items(): assert listener in handler.webhook_listeners[pattern] # And vice versa, check that any listeners on the handler come from the # registered plugins for pattern, listeners in handler.message_listeners.items(): for listener in listeners: assert any( [ pattern in plugin.message_listeners and listener in plugin.message_listeners[pattern] for plugin in handler.plugins ] ) for pattern, listeners in handler.webhook_listeners.items(): for listener in listeners: assert any( [ pattern in plugin.webhook_listeners and listener in plugin.webhook_listeners[pattern] for plugin in handler.plugins ] )
from mmpy_bot import Bot, ExamplePlugin, Settings, WebHookExample bot = Bot( # Either specify your settings here or use environment variables to override them. # See docker-compose.yml for an example you can use for local development. settings=Settings(), plugins=[ExamplePlugin(), WebHookExample()], # Add your own plugins here. ) bot.run()
def bot(): bot = Bot(plugins=[ExamplePlugin()], settings=Settings(DEBUG=True)) yield bot bot.stop() # if the bot was started, stop it