#!/usr/bin/env python from __future__ import print_function from __future__ import absolute_import import os import sys import argparse import zulip_bots from six.moves import configparser from mock import MagicMock, patch from zulip_bots.lib import StateHandler from zulip_bots.lib import ExternalBotHandler from zulip_bots.provision import provision_bot from zulip_bots.run import import_module_from_source current_dir = os.path.dirname(os.path.abspath(__file__)) def parse_args(): usage = ''' zulip-bot-output Example: zulip-bot-output xkcd "1" The message need only be enclosed in quotes if empty or containing spaces. This tool can be used for testing bots by sending simple messages and capturing the response. (Internally, this program loads bot-related code from the library code and then feeds the message provided in the command to the library code to handle.) ''' parser = argparse.ArgumentParser(usage=usage) parser.add_argument('bot', action='store', help='the name or path an existing bot to run') parser.add_argument('message', action='store', help='the message content to send to the bot') parser.add_argument('--force', '-f', action='store_true', help='try running bot even if dependencies install fails') parser.add_argument('--provision', '-p', action='store_true', help='install dependencies for the bot') args = parser.parse_args() return args def main(): # type: () -> None args = parse_args() if os.path.isfile(args.bot): bot_path = os.path.abspath(args.bot) bot_name = os.path.splitext(os.path.basename(bot_path))[0] else: bot_path = os.path.abspath(os.path.join(current_dir, 'bots', args.bot, args.bot+'.py')) bot_name = args.bot bot_dir = os.path.dirname(bot_path) if args.provision: provision_bot(os.path.dirname(bot_path), args.force) lib_module = import_module_from_source(bot_path, bot_name) message = {'content': args.message, 'sender_email': 'foo_sender@zulip.com'} message_handler = lib_module.handler_class() with patch('zulip.Client') as mock_client: mock_bot_handler = ExternalBotHandler(mock_client, bot_dir) mock_bot_handler.send_reply = MagicMock() mock_bot_handler.send_message = MagicMock() mock_bot_handler.update_message = MagicMock() if hasattr(message_handler, 'initialize') and callable(message_handler.initialize): message_handler.initialize(mock_bot_handler) message_handler.handle_message( message=message, bot_handler=mock_bot_handler, state_handler=StateHandler() ) print("On sending {} bot the message \"{}\"".format(bot_name, args.message)) # send_reply and send_message have slightly arguments; the # following takes that into account. # send_reply(original_message, response) # send_message(response_message) if mock_bot_handler.send_reply.called: output_message = list(mock_bot_handler.send_reply.call_args)[0][1] elif mock_bot_handler.send_message.called: output_message = list(mock_bot_handler.send_message.call_args)[0][0] elif mock_bot_handler.update_message.called: output_message = list(mock_bot_handler.update_message.call_args)[0][0]['content'] print("the bot updates a message with the following text (in quotes):\n\"{}\"".format(output_message)) sys.exit() else: print("the bot sent no reply.") sys.exit() print("the bot gives the following output message (in quotes):\n\"{}\"".format(output_message)) if __name__ == '__main__': main()