def test_generate_config_if_none_exist(self): cdf_backup = Loader.create_default_config Loader.create_default_config = mock.Mock( return_value=os.path.abspath("tests/configs/minimal.yaml")) Loader.load_config_file(["file_which_does_not_exist"]) self.assertTrue(Loader.create_default_config.called) Loader.create_default_config = cdf_backup
def test_generate_config_if_none_exist(self): cdf_backup = Loader.create_default_config Loader.create_default_config = mock.Mock( return_value=os.path.abspath("tests/configs/minimal.yaml")) Loader.load_config_file(["file_which_does_not_exist"]) self.assertTrue(Loader.create_default_config.called) Loader.create_default_config = cdf_backup
def test_load_non_existant_config_file(self): cdf_backup = Loader.create_default_config Loader.create_default_config = mock.Mock( return_value=os.path.abspath("/tmp/my_nonexistant_config")) with mock.patch("sys.exit") as mock_sysexit: Loader.load_config_file(["file_which_does_not_exist"]) self.assertTrue(Loader.create_default_config.called) self.assertTrue(mock_sysexit.called) Loader.create_default_config = cdf_backup
def test_load_non_existant_config_file(self): cdf_backup = Loader.create_default_config Loader.create_default_config = mock.Mock( return_value=os.path.abspath("/tmp/my_nonexistant_config")) with mock.patch('sys.exit') as mock_sysexit: Loader.load_config_file(["file_which_does_not_exist"]) self.assertTrue(Loader.create_default_config.called) self.assertTrue(mock_sysexit.called) Loader.create_default_config = cdf_backup
def test_yaml_load_exploit(self): with mock.patch("sys.exit"): config = Loader.load_config_file( [os.path.abspath("tests/configs/include_exploit.yaml")]) self.assertIsNone(config) # If the command in exploit.yaml is echoed it will return 0 self.assertNotEqual(config, 0)
def test_yaml_load_exploit(self): with mock.patch('sys.exit'): config = Loader.load_config_file( [os.path.abspath("tests/configs/include_exploit.yaml")]) self.assertIsNone(config) # If the command in exploit.yaml is echoed it will return 0 self.assertNotEqual(config, 0)
async def reload(self): """Reload opsdroid.""" await self.unload() self.config = Loader.load_config_file([ "configuration.yaml", DEFAULT_CONFIG_PATH, "/etc/opsdroid/configuration.yaml" ]) self.load()
async def reload(self): """Reload opsdroid.""" await self.unload() self.config = Loader.load_config_file([ "configuration.yaml", DEFAULT_CONFIG_PATH, "/etc/opsdroid/configuration.yaml" ]) self.load()
def test_load_minimal_config_file_2(self): opsdroid, loader = self.setup() loader._install_module = mock.MagicMock() loader.import_module = mock.MagicMock() config = Loader.load_config_file( [os.path.abspath("tests/configs/minimal_2.yaml")]) modules = loader.load_modules_from_config(config) self.assertIsNotNone(modules["connectors"]) self.assertIsNone(modules["databases"]) self.assertIsNotNone(modules["skills"]) self.assertIsNotNone(config)
def test_load_minimal_config_file_2(self): opsdroid, loader = self.setup() loader._install_module = mock.MagicMock() loader.import_module = mock.MagicMock() config = Loader.load_config_file( [os.path.abspath("tests/configs/minimal_2.yaml")]) modules = loader.load_modules_from_config(config) self.assertIsNotNone(modules["connectors"]) self.assertIsNone(modules["databases"]) self.assertIsNotNone(modules["skills"]) self.assertIsNotNone(config)
def start(): """Start the opsdroid bot.""" check_dependencies() config = Loader.load_config_file([ "configuration.yaml", DEFAULT_CONFIG_PATH, "/etc/opsdroid/configuration.yaml" ]) configure_lang(config) configure_logging(config) welcome_message(config) with OpsDroid(config=config) as opsdroid: opsdroid.run()
def main(): """Opsdroid is a chat bot framework written in Python. It is designed to be extendable, scalable and simple. See https://opsdroid.github.io/ for more information. """ check_dependencies() config = Loader.load_config_file([ "configuration.yaml", DEFAULT_CONFIG_PATH, "/etc/opsdroid/configuration.yaml" ]) configure_lang(config) configure_logging(config) welcome_message(config) with OpsDroid(config=config) as opsdroid: opsdroid.load() opsdroid.run()
def main(): """Opsdroid is a chat bot framework written in Python. It is designed to be extendable, scalable and simple. See https://opsdroid.github.io/ for more information. """ check_dependencies() config = Loader.load_config_file([ "configuration.yaml", DEFAULT_CONFIG_PATH, "/etc/opsdroid/configuration.yaml" ]) configure_lang(config) configure_logging(config) welcome_message(config) with OpsDroid(config=config) as opsdroid: opsdroid.load() opsdroid.run()
def test_load_broken_config_file(self): with mock.patch("sys.exit") as patched_sysexit: Loader.load_config_file( [os.path.abspath("tests/configs/broken.yaml")]) self.assertTrue(patched_sysexit.called)
class OpsDroid(): """Root object for opsdroid.""" # pylint: disable=too-many-instance-attributes # All are reasonable in this case. instances = [] def __init__(self): """Start opsdroid.""" self.bot_name = 'opsdroid' self.sys_status = 0 self.connectors = [] self.connector_tasks = [] self.eventloop = asyncio.get_event_loop() for sig in (signal.SIGINT, signal.SIGTERM): self.eventloop.add_signal_handler(sig, self.call_stop) self.skills = [] self.memory = Memory() self.loader = Loader(self) self.config = {} self.stats = { "messages_parsed": 0, "webhooks_called": 0, "total_response_time": 0, "total_responses": 0, } self.web_server = None self.should_restart = False self.stored_path = [] def __enter__(self): """Add self to existing instances.""" self.stored_path = copy.copy(sys.path) if not self.__class__.instances: self.__class__.instances.append(weakref.proxy(self)) else: self.critical("opsdroid has already been started", 1) return self def __exit__(self, exc_type, exc_value, traceback): """Remove self from existing instances.""" sys.path = self.stored_path self.__class__.instances = [] asyncio.set_event_loop(asyncio.new_event_loop()) @property def default_connector(self): """Return the default connector.""" default_connector = None for connector in self.connectors: if "default" in connector.config and connector.config["default"]: default_connector = connector break if default_connector is None: default_connector = self.connectors[0] return default_connector def exit(self): """Exit application.""" _LOGGER.info("Exiting application with return code " + str(self.sys_status)) sys.exit(self.sys_status) def critical(self, error, code): """Exit due to unrecoverable error.""" self.sys_status = code _LOGGER.critical(error) print("Error:", error) self.exit() def restart(self): """Restart opsdroid.""" self.should_restart = True self.stop() def call_stop(self): """Signal handler to call disconnect and stop.""" future = asyncio.ensure_future(self.disconnect()) future.add_done_callback(self.stop) return future async def disconnect(self): """Disconnect all the connectors.""" for connector in self.connectors: await connector.disconnect(self) def stop(self, future=None): """Stop the event loop.""" pending = asyncio.Task.all_tasks() for task in pending: task.cancel() self.eventloop.stop() print('') # Prints a character return for return to shell _LOGGER.info("Keyboard interrupt, exiting.") def load(self): """Load configuration.""" self.config = self.loader.load_config_file([ "configuration.yaml", DEFAULT_CONFIG_PATH, "/etc/opsdroid/configuration.yaml" ]) def start_loop(self): """Start the event loop.""" connectors, databases, skills = \ self.loader.load_modules_from_config(self.config) _LOGGER.debug("Loaded %i skills", len(skills)) if databases is not None: self.start_databases(databases) self.setup_skills(skills) self.start_connector_tasks(connectors) self.eventloop.create_task(parse_crontab(self)) self.web_server.start() try: pending = asyncio.Task.all_tasks() self.eventloop.run_until_complete(asyncio.gather(*pending)) except RuntimeError as error: if str(error) != 'Event loop is closed': raise error finally: self.eventloop.close() def setup_skills(self, skills): """Call the setup function on the passed in skills.""" for skill in skills: try: skill["module"].setup(self) except AttributeError: pass def start_connector_tasks(self, connectors): """Start the connectors.""" for connector_module in connectors: for _, cls in connector_module["module"].__dict__.items(): if isinstance(cls, type) and \ issubclass(cls, Connector) and\ cls is not Connector: connector = cls(connector_module["config"]) self.connectors.append(connector) if connectors: for connector in self.connectors: self.eventloop.run_until_complete(connector.connect(self)) for connector in self.connectors: task = self.eventloop.create_task(connector.listen(self)) self.connector_tasks.append(task) else: self.critical("All connectors failed to load", 1) def start_databases(self, databases): """Start the databases.""" if not databases: _LOGGER.debug(databases) _LOGGER.warning("All databases failed to load") for database_module in databases: for name, cls in database_module["module"].__dict__.items(): if isinstance(cls, type) and \ issubclass(cls, Database) and \ cls is not Database: _LOGGER.debug("Adding database: %s", name) database = cls(database_module["config"]) self.memory.databases.append(database) self.eventloop.run_until_complete(database.connect(self)) async def parse(self, message): """Parse a string against all skills.""" self.stats["messages_parsed"] = self.stats["messages_parsed"] + 1 tasks = [] if message.text.strip() != "": _LOGGER.debug("Parsing input: %s", message.text) tasks.append( self.eventloop.create_task(parse_regex(self, message))) tasks.append( self.eventloop.create_task(parse_always(self, message))) if "parsers" in self.config: _LOGGER.debug("Processing parsers...") parsers = self.config["parsers"] dialogflow = [p for p in parsers if p["name"] == "dialogflow" or p["name"] == "apiai"] # Show deprecation message but parse message # Once it stops working remove this bit apiai = [p for p in parsers if p["name"] == "apiai"] if apiai: _LOGGER.warning("Api.ai is now called Dialogflow. This " "parser will stop working in the future " "please swap: 'name: apiai' for " "'name: dialogflow' in configuration.yaml") _LOGGER.debug("Checking dialogflow...") if len(dialogflow) == 1 and \ ("enabled" not in dialogflow[0] or dialogflow[0]["enabled"] is not False): _LOGGER.debug("Parsing with Dialogflow.") tasks.append( self.eventloop.create_task( parse_dialogflow(self, message, dialogflow[0]))) luisai = [p for p in parsers if p["name"] == "luisai"] _LOGGER.debug("Checking luisai...") if len(luisai) == 1 and \ ("enabled" not in luisai[0] or luisai[0]["enabled"] is not False): _LOGGER.debug("Parsing with luisai.") tasks.append( self.eventloop.create_task( parse_luisai(self, message, luisai[0]))) witai = [p for p in parsers if p["name"] == "witai"] _LOGGER.debug("Checking wit.ai...") if len(witai) == 1 and \ ("enabled" not in witai[0] or witai[0]["enabled"] is not False): _LOGGER.debug("Parsing with witai.") tasks.append( self.eventloop.create_task( parse_witai(self, message, witai[0]))) return tasks
def test_load_broken_config_file(self): with mock.patch('sys.exit') as patched_sysexit: Loader.load_config_file( [os.path.abspath("tests/configs/broken.yaml")]) self.assertTrue(patched_sysexit.called)