def test_not_active_backend(): app = Kutana() app.add_backend(Debug([], name="backend1", active=False)) async def test(): with patch('asyncio.ensure_future') as ensure_future: await app._on_start(None) ensure_future.assert_not_called asyncio.get_event_loop().run_until_complete(test())
def make_kutana(messages): app = Kutana() debug = Debug( messages=messages, on_complete=app.stop, ) app.add_backend(debug) return app, debug
def test_happy_path(): app = Kutana() # Simple echo plugin pl = Plugin("") @pl.on_messages() async def __(message, ctx): await ctx.reply(message.text) app.add_plugin(pl) # Simple debug backend debug = Debug( messages=[("message 1", 1), ("message 2", 2)], on_complete=app.stop, ) app.add_backend(debug) # Run application app.run() # Check replies assert debug.answers[1] == [("message 1", (), {})] assert debug.answers[2] == [("message 2", (), {})]
def main(): app = Kutana() # set_logger_level(logging.DEBUG) backend = Vkontakte(SHUF_SETTINGS['TOKEN']) app.add_backend(backend) app.config['settings'] = SHUF_SETTINGS app.config['prefixes'] = ('еш ', 'есб ', 'esb ', 'ешаф ', 'eshuf ' ) # ('шаф ', 'sb ', 'шб ', 'shuf ', 'shufbot ') app.config['inform_time'] = time(20, 50) # 12:00 app.config['votekick_time'] = 5 * 60 init_db(app) app.add_plugins(load_plugins(os.path.join(os.curdir, 'bot', 'plugins'))) return app
def test_incorrect_values(): app = Kutana() with pytest.raises(ValueError): app.add_backend(None) with pytest.raises(ValueError): app.set_storage('permanent', None) with pytest.raises(ValueError): app.add_plugin(None)
def test_storages(): app = Kutana() app.set_storage('permanent', MemoryStorage()) assert app.get_storage('default') assert app.get_storage('permanent') assert not app.get_storage('temporary')
def debug_controller(self, queue): if self.kutana is None: self.kutana = Kutana() self.controller = DebugController(*queue) self.kutana.add_controller(self.controller) self.plugin = Plugin() self.plugins = [self.plugin] try: yield self.plugin finally: for plugin in self.plugins: self.kutana.executor.register_plugins(plugin) self.kutana.run() self.assertEqual(self.target, self.controller.replies)
def debug_manager(self, queue): if self.app is None: self.app = Kutana() self.manager = DebugManager(*queue) self.app.add_manager(self.manager) self.plugin = Plugin() self.plugins = [self.plugin] try: yield self.plugin finally: for plugin in self.plugins: self.app.register_plugins([plugin]) self.app.run() self.assertEqual(self.target, self.manager.replies)
def setUpClass(cls): try: with open("configuration_test.json") as o: cls.conf = json.load(o) except FileNotFoundError: cls.conf = {} if "vk_token" not in cls.conf: cls.conf["vk_token"] = os.environ.get("TEST_TOKEN", "") if "vk_utoken" not in cls.conf: cls.conf["vk_utoken"] = os.environ.get("TEST_UTOKEN", "") cls.messages_to_delete = set() if not cls.conf["vk_token"] or not cls.conf["vk_utoken"]: raise unittest.SkipTest("No authorization found for this tests.") async def get_receiver_coroutine_function(self): actual_reci = await self.original_get_receiver_coroutine_function() empty_if_done = [1] async def reci(): if not empty_if_done: raise ExitException empty_if_done.pop(0) cls.ureq("messages.setActivity", type="typing", peer_id=-self.group_id) cls.messages_to_delete.add( str( cls.ureq("messages.send", message="echo message", peer_id=-self.group_id, attachment="photo-164328508_456239017," * 2))) return await actual_reci() return reci VKController.original_get_receiver_coroutine_function = VKController.get_receiver_coroutine_function VKController.get_receiver_coroutine_function = get_receiver_coroutine_function cls.kutana = Kutana() cls.kutana.add_controller( VKController(token=cls.conf["vk_token"], longpoll_settings={"message_typing_state": 1}))
async def test(): vk = VkontakteCallback("token") vk.start_server = noop vk._execute_loop = noop vk._update_group_data = noop vk.request = _request await vk.on_start(Kutana()) assert vk.updates_queue assert len(calls) == 0
class KutanaTest(unittest.TestCase): def setUp(self): self.app = None self.target = [] @contextmanager def debug_manager(self, queue): if self.app is None: self.app = Kutana() self.manager = DebugManager(*queue) self.app.add_manager(self.manager) self.plugin = Plugin() self.plugins = [self.plugin] try: yield self.plugin finally: for plugin in self.plugins: self.app.register_plugins([plugin]) self.app.run() self.assertEqual(self.target, self.manager.replies)
def test_get_backend(): app = Kutana() app.add_backend(Debug([], name="backend1")) app.add_backend(Debug([], name="backend2")) assert app.get_backend("backend1").name == "backend1" assert app.get_backend("backend2").name == "backend2" assert app.get_backend("backend3") is None
def make_kutana_no_run(backend_source=None): app = Kutana() app.storage = NaiveMemory() debug = Debug(messages=[]) if backend_source: debug.get_identity = lambda: backend_source app.add_backend(debug) async def _handle_update(update): ctx = await Context.create(app=app, config={"prefixes": (".", )}, update=update, backend=debug) return await app._handle_update(update, ctx) def handle_update(update): return app.get_loop().run_until_complete(_handle_update(update)) return app, debug, handle_update
def test_add_plugins(): added = [] app = Kutana() assert app.get_plugins() == [] app.add_plugin = lambda pl: added.append(pl) app.add_plugins(["a", "b", "c"]) assert added == ["a", "b", "c"]
def test_kutana_shutdown(): for exception in [Exception, KeyboardInterrupt]: app = Kutana() _shutdown = app._shutdown async def checker(): checker._called += 1 await _shutdown() checker._called = 0 app._main_loop = MagicMock(side_effect=exception) app._shutdown = checker app.run() assert checker._called == 1
def test_kutana_shutdown(): app = Kutana() async def trigger(): raise KeyboardInterrupt _shutdown = app._shutdown async def checker(): checker._called = True await _shutdown() checker._called = False app._main_loop = trigger app._shutdown = checker app.run() assert checker._called == True
def run(): """ This function runs kutana application using provided configuration and CLI options. Refer to its source to create more specific starter for your application. """ # Parse provided arguments args = parser.parse_args() # Setup logger if args.debug: logger.set_logger_level(logging.DEBUG) # Import configuration if not os.path.isfile(args.config): logger.logger.error(f"Couldn't open confiuration file: {args.config}") exit(1) with open(args.config) as fh: config = yaml.safe_load(fh) # Create application app = Kutana() # Update configuration app.config.update(config) # Setup i18n set_default_language(config.get("language", "en")) load_translations(args.translations) # Add each backend from config add_backends(app, config.get("backends")) # Add each storage from config add_storages(app, config.get("storages")) # Load and register plugins from provided path app.add_plugins(load_plugins(args.plugins)) # Run application app.run()
def test_load_plugins(self): loaded_plugins = load_plugins("test/test_plugins/") loaded_plugins.sort(key=lambda plugin: plugin.name) self.assertEqual(len(loaded_plugins), 3) self.assertEqual(loaded_plugins[0].name, "Memory") self.assertEqual(loaded_plugins[1].name, "My file") self.assertEqual(loaded_plugins[2].name, "My file twice") app = Kutana() app.register_plugins(loaded_plugins) loop = asyncio.get_event_loop() loop.run_until_complete(app.startup()) loop.run_until_complete(app.process(DebugManager(), "message")) self.assertEqual(loaded_plugins[0].memory, "message") self.assertEqual(loaded_plugins[1].my_file, ":)") self.assertEqual(loaded_plugins[2].my_file, ":):)")
from kutana import Kutana, VKController, load_plugins, load_configuration # Create engine kutana = Kutana() # Create VKController kutana.add_controller( VKController(token = "d6842a32a19fefc24f1ac19b17cba1c9243f4bf1ecdf426215d193d96135a111d0d537f6e2df8f1452482") ) # Load and register plugins kutana.executor.register_plugins(*load_plugins("/root/bot/example/")) # Run engine kutana.run()
def test_happy_path(mock_post): group_change_settings_update = { "type": "group_change_settings", "object": { "changes": { "screen_name": {"old_value": "", "new_value": "sdffff23f23"}, "title": {"old_value": "Спасибо", "new_value": "Спасибо 2"} } } } raw_updates = [ {}, {"type": "present"}, group_change_settings_update, MESSAGES["not_message"], MESSAGES["message"], MESSAGES[".echo"], MESSAGES[".echo chat"], MESSAGES[".echo wa"], ] answers = [] updated_longpoll = [] def acquire_updates(content_type=None): if not raw_updates: return {"updates": [], "ts": "100"} if updated_longpoll == [1]: return {"failed": 3} return {"updates": [raw_updates.pop(0)], "ts": "0"} mock_post.return_value.__aenter__.return_value.json = CoroutineMock( side_effect=acquire_updates ) class _VkontakteLongpoll(VkontakteLongpoll): async def _get_response(self, method, kwargs={}): if method == "groups.setLongPollSettings": return {"response": 1} if method == "groups.getById": return { "response": [ {"id": 1, "name": "group", "screen_name": "grp"}, ], } if method == "groups.getLongPollServer": updated_longpoll.append(1) return { "response": { "server": "s", "key": "k", "ts": "1", }, } if method == "execute": answers.extend(kwargs["code"].split("API.")[1:]) return { "response": [1] * kwargs["code"].count("API."), } print(method, kwargs) app = Kutana() vkontakte = _VkontakteLongpoll(token="token") app.add_backend(vkontakte) echo_plugin = Plugin("echo") @echo_plugin.on_commands(["echo", "ec"]) async def __(message, ctx): assert ctx.resolve_screen_name assert ctx.reply await ctx.reply(message.text, attachments=message.attachments) app.add_plugin(echo_plugin) app.get_loop().call_later( delay=vkontakte.api_request_pause * 4, callback=app.stop, ) app.run() assert vkontakte.group_name == "Спасибо 2" assert vkontakte.group_screen_name == "sdffff23f23" assert len(updated_longpoll) == 2 answers.sort() assert len(answers) == 3 assert '{"message": ".echo chat [michaelkrukov|Михаил]",' in answers[0] assert '{"message": ".echo wa",' in answers[1] assert 'attachment": ""' not in answers[1] assert '{"message": ".echo",' in answers[2]
import os from pathlib import Path from kutana import Kutana, load_plugins from kutana.backends import Telegram import dotenv env = dotenv.dotenv_values() if Path(".env").exists() else os.environ # Create application app = Kutana() # Add manager to application app.add_backend(Telegram(env.get("TELEGRAM_TOKEN"), proxy=env.get("PROXY"))) # Load and register plugins app.add_plugins(load_plugins("plugins/")) if __name__ == "__main__": # Run application app.run()
import json from kutana import Kutana, VKManager, load_plugins, TGManager # Load configuration with open("configuration.json") as fh: config = json.load(fh) # Create application app = Kutana() # Add manager to application app.add_manager(VKManager(config["vk_token"])) app.add_manager(TGManager(config["tg_token"])) # Load and register plugins app.register_plugins(load_plugins("plugins/")) if __name__ == "__main__": # Run application app.run()
def test_callback_setup(): calls = [] class _VkontakteCallback(VkontakteCallback): async def _execute_loop(self, loop): pass async def start_server(self): pass async def request(self, method, _timeout=None, **kwargs): return await self.raw_request(method, kwargs) async def _get_response(self, method, kwargs={}): calls.append([method, kwargs]) if method == "groups.getById": return { "response": [ { "id": 1, "name": "group", "screen_name": "grp" }, ], } if method == "groups.getCallbackServers": return { "response": { "items": [ { "url": self._address, "id": 1 }, { "url": "123", "title": "kutana@2" }, { "url": "abc", "title": "kutana@3" }, ] } } if method == "groups.deleteCallbackServer": return {"response": "ok"} if method == "groups.addCallbackServer": return {"response": {"server_id": "10"}} if method == "groups.setCallbackSettings": assert kwargs["server_id"] == "10" return {"response": "ok"} print(method, kwargs) app = Kutana() async def test(): vk = _VkontakteCallback("token", address="127.0.0.1:8080") await vk.on_start(app) assert vk.updates_queue assert len(calls) == 5 await vk.on_shutdown(app) app.get_loop().run_until_complete(test())
from ai_dungeon import config from ai_dungeon.storage.redis import RedisStorage from kutana import Kutana, load_plugins from kutana.backends import Vkontakte, Telegram import logging logging.basicConfig(level=logging.DEBUG) # Create application if config.REDIS_URL is not None: app = Kutana(storage=RedisStorage(config.REDIS_URL)) else: app = Kutana() # Add manager to application if config.TELEGRAM_TOKEN: app.add_backend(Telegram(token=config.TELEGRAM_TOKEN)) if config.VK_TOKEN: app.add_backend(Vkontakte(token=config.VK_TOKEN)) # Load and register plugins app.add_plugins(load_plugins("plugins/")) if __name__ == "__main__": # Run application app.run()
import json from kutana import Kutana, load_plugins from kutana.backends import Vkontakte # Import configuration with open("config.json") as fh: config = json.load(fh) # Create application app = Kutana() # Add manager to application app.add_backend(Vkontakte(token=config["vk_token"])) # Load and register plugins app.add_plugins(load_plugins("plugins/")) if __name__ == "__main__": # Run application app.run()
def test_same_plugins_and_backends(): app = Kutana() plugin = Plugin("") backend = Debug([]) app.add_plugin(plugin) with pytest.raises(RuntimeError): app.add_plugin(plugin) app.add_backend(backend) with pytest.raises(RuntimeError): app.add_backend(backend) assert app.get_backends() == [backend]
def test_get_loop(): app = Kutana() assert app._loop == app.get_loop()
import json from kutana import (Kutana, TGManager, VKManager, load_plugins) # Create engine app = Kutana() # Load configuration and available plugins with open("config.json", "r") as fh: config = json.load(fh) app.config["names"] = config["info"]["names"] # Register plugins app.register_plugins(load_plugins("plugins/")) # Add managers from configuration for manager_conf in config["managers"]: manager = None if manager_conf["type"] == "vkontakte": manager = VKManager elif manager_conf["type"] == "telegram": manager = TGManager if manager is None: raise ValueError("Unknown manager type: {}".format( manager_conf["type"])) kwargs = manager_conf
def test_add_backend(): app = Kutana() with pytest.raises(ValueError): app.add_backend(None)
def test_happy_path(): updates = [ MESSAGES["not_message"], MESSAGES["message"], MESSAGES[".echo"], MESSAGES[".echo chat"], MESSAGES["/echo@bot chat"], MESSAGES["/echo chat"], MESSAGES[".echo@bot chat"], MESSAGES["_image"], ] answers = [] class _Telegram(Telegram): async def _request(self, method, kwargs={}): if method == "getMe": return { "first_name": "te", "last_name": "st", "username": "******" } if method == "getUpdates": if not updates: return [] return [updates.pop(0)] if method == "sendMessage": answers.append(("msg", kwargs["text"])) return 1 if method == "sendPhoto": answers.append(("image", kwargs["photo"])) return 1 print(method, kwargs) app = Kutana() telegram = _Telegram(token="token") app.add_backend(telegram) echo_plugin = Plugin("echo") @echo_plugin.on_commands(["echo", "ec"]) async def _(message, ctx): await ctx.reply(message.text) @echo_plugin.on_attachments(["image"]) async def _(message, ctx): await ctx.reply(message.text, attachments=message.attachments[0]) app.add_plugin(echo_plugin) app.get_loop().call_later( delay=0.5, callback=app.stop, ) app.run() answers.sort() assert len(answers) == 5 assert answers[0][0] == "image" assert answers[1] == ("msg", ".echo") assert answers[2] == ("msg", ".echo chat") assert answers[3] == ("msg", "/echo chat") assert answers[4] == ("msg", "/echo chat")