async def test_thinking_sleep(self): opsdroid = amock.CoroutineMock() mock_connector_int = Connector({ 'name': 'shell', 'thinking-delay': 3, 'type': 'connector', 'module_path': 'opsdroid-modules.connector.shell' }, opsdroid=opsdroid) with amock.patch('asyncio.sleep') as mocksleep_int: message = events.Message("user", "default", mock_connector_int, "hi") with self.assertRaises(NotImplementedError): await message.respond("Hello there") self.assertTrue(mocksleep_int.called) # Test thinking-delay with a list mock_connector_list = Connector({ 'name': 'shell', 'thinking-delay': [1, 4], 'type': 'connector', 'module_path': 'opsdroid-modules.connector.shell' }, opsdroid=opsdroid) with amock.patch('asyncio.sleep') as mocksleep_list: message = events.Message("user", "default", mock_connector_list, "hi") with self.assertRaises(NotImplementedError): await message.respond("Hello there") self.assertTrue(mocksleep_list.called)
async def test_send_message_start_thread_is_true(self): connector = ConnectorSlack({"token": "abc123"}, opsdroid=self.od) connector.slack.api_call = amock.CoroutineMock() connector.start_thread = True event_id = "1582838099.000601" linked_event = events.Message(text="linked text", event_id=event_id, raw_event={}) message = events.Message( text="test", user="******", target="room", connector=connector, linked_event=linked_event, ) await connector.send(message) connector.slack.api_call.assert_called_once_with( "chat.postMessage", data={ "channel": "room", "text": "test", "as_user": False, "username": "******", "icon_emoji": ":robot_face:", "thread_ts": "1582838099.000601", }, )
async def run_skill(self, skill, config, event): """Execute a skill. Attempts to run the skill parsed and provides other arguments to the skill if necessary. Also handles the exception encountered if th e Args: skill: name of the skill to be run. config: The configuration the skill must be loaded in. event: Message/event to be parsed to the chat service. """ # pylint: disable=broad-except # We want to catch all exceptions coming from a skill module and not # halt the application. If a skill throws an exception it just doesn't # give a response to the user, so an error response should be given. try: if len(inspect.signature(skill).parameters.keys()) > 1: return await skill(self, config, event) else: return await skill(event) except Exception: _LOGGER.exception(_("Exception when running skill '%s'."), str(config["name"])) if event: await event.respond( events.Message(_("Whoops there has been an error."))) await event.respond( events.Message(_("Check the log for details.")))
async def twim_bot(opsdroid, config, message): """ React to a TWIM post. Check the contents of the message then put it in the opsdroid memory. """ if isinstance(message, events.EditedMessage): return # If the message starts with TWIM and it's a reply then we use the parent event. if isinstance(message, events.Reply): message = message.linked_event post = await process_twim_event(opsdroid, message.target, message) _LOGGER.debug(f"Processed TWIM event, got: {post}") content = list(post.values())[0] nick = content['nick'] try: await message.respond( events.Reaction(MAGIC_EMOJI + VARIATION_SELECTOR_16)) except MatrixException: _LOGGER.error("Failed to react to submission with magic emoji.") pass # Send the update to the echo room. if "echo" in message.connector.rooms: echo_event_id = await message.respond( events.Message(format_update(post), target="echo")) echo_event_id = echo_event_id.event_id content['echo_event_id'] = echo_event_id await add_post_to_memory(opsdroid, message.target, post)
async def test_send_reaction(self): message = events.Message( "hello", event_id="$11111", connector=self.connector, target="!test:localhost", ) reaction = events.Reaction("⭕") with OpsDroid() as _: with amock.patch( api_string.format("send_message_event")) as patched_send: patched_send.return_value = asyncio.Future() patched_send.return_value.set_result(None) await message.respond(reaction) content = { "m.relates_to": { "rel_type": "m.annotation", "event_id": "$11111", "key": reaction.emoji, } } assert patched_send.called_once_with("!test:localhost", "m.reaction", content)
async def test_send_reply(self): message = events.Message( "hello", event_id="$11111", connector=self.connector, target="!test:localhost", ) reply = events.Reply("reply") with OpsDroid() as _: with amock.patch( api_string.format("send_message_event")) as patched_send: patched_send.return_value = asyncio.Future() patched_send.return_value.set_result(None) await message.respond(reply) content = self.connector._get_formatted_message_body( reply.text, msgtype="m.text") content["m.relates_to"] = { "m.in_reply_to": { "event_id": message.event_id } } assert patched_send.called_once_with("!test:localhost", "m.room.message", content)
async def test_respond_failure(opsdroid, caplog): caplog.set_level(logging.DEBUG) connector = ConnectorTelegram(connector_config, opsdroid=opsdroid) response = amock.Mock() response.status = 500 with amock.patch( "aiohttp.ClientSession.post", new=amock.CoroutineMock()) as patched_request, amock.patch.object( connector, "build_url") as mocked_build_url: patched_request.return_value = asyncio.Future() patched_request.return_value.set_result(response) assert opsdroid.__class__.instances test_message = opsdroid_events.Message( text="This is a test", user="******", target={"id": 12404}, connector=connector, ) patched_request.return_value = asyncio.Future() patched_request.return_value.set_result(response) await test_message.respond("Response") assert patched_request.called assert mocked_build_url.called assert "Responding" in caplog.text assert "Unable to respond" in caplog.text
async def test_message(self): opsdroid = amock.CoroutineMock() mock_connector = Connector({}, opsdroid=opsdroid) raw_message = { 'text': 'Hello world', 'user': '******', 'room': 'default', 'timestamp': '01/01/2000 19:23:00', 'messageId': '101' } message = events.Message( "user", "default", mock_connector, "Hello world", raw_message) self.assertEqual(message.text, "Hello world") self.assertEqual(message.user, "user") self.assertEqual(message.room, "default") self.assertEqual( message.raw_event['timestamp'], '01/01/2000 19:23:00' ) self.assertEqual(message.raw_event['messageId'], '101') with self.assertRaises(NotImplementedError): await message.respond("Goodbye world") # Also try responding with just some empty Event with self.assertRaises(NotImplementedError): await message.respond(events.Event( message.user, message.room, message.connector))
async def test_message(self): with OpsDroid() as opsdroid: mock_connector = Connector({}, opsdroid=opsdroid) raw_message = { "text": "Hello world", "user_id": "user_id", "user": "******", "room": "default", "timestamp": "01/01/2000 19:23:00", "messageId": "101", } message = events.Message( text="Hello world", user_id="user_id", user="******", target="default", connector=mock_connector, raw_event=raw_message, ) self.assertEqual(message.text, "Hello world") self.assertEqual(message.user_id, "user_id") self.assertEqual(message.user, "user") self.assertEqual(message.target, "default") self.assertEqual(message.raw_event["timestamp"], "01/01/2000 19:23:00") self.assertEqual(message.raw_event["messageId"], "101") with self.assertRaises(TypeError): await message.respond("Goodbye world") # Also try responding with just some empty Event with self.assertRaises(TypeError): await message.respond( events.Event(message.user, message.target, message.connector))
async def test_message(self): with OpsDroid() as opsdroid: mock_connector = Connector({}, opsdroid=opsdroid) raw_message = { 'text': 'Hello world', 'user': '******', 'room': 'default', 'timestamp': '01/01/2000 19:23:00', 'messageId': '101' } message = events.Message("Hello world", "user", "default", mock_connector, raw_event=raw_message) self.assertEqual(message.text, "Hello world") self.assertEqual(message.user, "user") self.assertEqual(message.target, "default") self.assertEqual(message.raw_event['timestamp'], '01/01/2000 19:23:00') self.assertEqual(message.raw_event['messageId'], '101') with self.assertRaises(TypeError): await message.respond("Goodbye world") # Also try responding with just some empty Event with self.assertRaises(TypeError): await message.respond( events.Event(message.user, message.target, message.connector))
async def create_message(self, event, roomid): """Send a Message event.""" kwargs = dict( text=event["content"]["body"], user_id=event["sender"], user=await self.connector.get_nick(roomid, event["sender"]), target=roomid, connector=self.connector, event_id=event["event_id"], raw_event=event, ) if "m.relates_to" in event["content"]: relates_to = event["content"]["m.relates_to"] # Detect an edit. if relates_to.get("rel_type", "") == "m.replace": kwargs["text"] = event["content"]["m.new_content"]["body"] kwargs["linked_event"] = await self.create_event_from_eventid( relates_to["event_id"], roomid) return events.EditedMessage(**kwargs) # Detect a reply if relates_to.get("m.in_reply_to"): kwargs["text"] = trim_reply_fallback_text(kwargs["text"]) kwargs["linked_event"] = await self.create_event_from_eventid( relates_to["m.in_reply_to"]["event_id"], roomid) return events.Reply(**kwargs) return events.Message(**kwargs)
async def test_response_effects(self): """Responding to a message shouldn't change the message.""" opsdroid = amock.CoroutineMock() mock_connector = Connector({}, opsdroid=opsdroid) message_text = "Hello world" message = events.Message("user", "default", mock_connector, message_text) with self.assertRaises(NotImplementedError): await message.respond("Goodbye world") self.assertEqual(message_text, message.text)
async def test_response_effects(self): """Responding to a message shouldn't change the message.""" with OpsDroid() as opsdroid: mock_connector = Connector({}, opsdroid=opsdroid) message_text = "Hello world" message = events.Message(message_text, "user", "default", mock_connector) with self.assertRaises(TypeError): await message.respond("Goodbye world") self.assertEqual(message_text, message.text)
async def test_respond(self): connector = ConnectorSlack({"token": "abc123"}, opsdroid=self.od) connector.slack.api_call = amock.CoroutineMock() await connector.send( events.Message(text="test", user="******", target="room", connector=connector)) self.assertTrue(connector.slack.api_call.called)
async def create_message(self, event, roomid): """Send a Message event.""" return events.Message(event['content']['body'], await self.connector.get_nick(roomid, event['sender']), roomid, self.connector, event_id=event['event_id'], raw_event=event)
async def test_send_reaction_invalid_name(send_event): message = events.Message( text="linked text", target="room", event_id="1582838099.000601", raw_event={"ts": 0}, ) event = events.Reaction("NOT_EMOJI", target=message.target, linked_event=message) await send_event(("/reactions.add",), event)
async def run_skill(self, skill, config, message): """Execute a skill.""" # pylint: disable=broad-except # We want to catch all exceptions coming from a skill module and not # halt the application. If a skill throws an exception it just doesn't # give a response to the user, so an error response should be given. try: if len(inspect.signature(skill).parameters.keys()) > 1: await skill(self, config, message) else: await skill(message) except Exception: _LOGGER.exception(_("Exception when running skill '%s' "), str(config["name"])) if message: await message.respond( events.Message(_("Whoops there has been an error"))) await message.respond( events.Message(_("Check the log for details")))
async def create_message(self, event, roomid): """Send a Message event.""" return events.Message( event["content"]["body"], await self.connector.get_nick(roomid, event["sender"]), roomid, self.connector, event_id=event["event_id"], raw_event=event, )
async def test_send_message(send_event, connector): event = events.Message(text="test", user="******", target="room", connector=connector) payload, response = await send_event(CHAT_POST_MESSAGE, event) assert payload == { "channel": "room", "text": "test", "username": "******", "icon_emoji": ":robot_face:", } assert response["ok"]
async def test_parse_invalid_str(self): with OpsDroid() as opsdroid: mock_skill = await self.getMockSkill() opsdroid.skills.append(match_event("Message2")(mock_skill)) mock_connector = amock.CoroutineMock() message = events.Message("Hello World", "user", "default", mock_connector) with self.assertRaises(ValueError): await parse_event_type(opsdroid, message)
async def test_send_reaction_unknown_error(send_event): message = events.Message( text="linked text", target="room", event_id="1582838099.000601", raw_event={"ts": 0}, ) event = events.Reaction("NOT_EMOJI", target=message.target, linked_event=message) with pytest.raises(SlackApiError): _, response = await send_event(("/reactions.add",), event) assert not response["ok"]
async def test_send_message_event(opsdroid, caplog): caplog.set_level(logging.DEBUG) connector = ConnectorTwitch(connector_config, opsdroid=opsdroid) message_event = opsdroid_events.Message(text="Hello world!") connector.send_message = amock.CoroutineMock() await connector._send_message(message_event) assert connector.send_message.called assert "Hello world!" in caplog.text
async def test_parse_str_event(self): with OpsDroid() as opsdroid: opsdroid.run_skill = amock.CoroutineMock() mock_skill = await self.getMockSkill() opsdroid.skills.append(match_event("Message")(mock_skill)) mock_connector = amock.CoroutineMock() message = events.Message("Hello World", "user", "default", mock_connector) await opsdroid.parse(message) self.assertTrue(opsdroid.run_skill.called)
async def test_typing_delay(self): with OpsDroid() as opsdroid: mock_connector = Connector( { "name": "shell", "typing-delay": 0.3, "type": "connector", "module_path": "opsdroid-modules.connector.shell", }, opsdroid=opsdroid, ) with amock.patch( "opsdroid.events.Message._typing_delay") as logmock: with amock.patch("asyncio.sleep") as mocksleep: message = events.Message("hi", "user_id", "user", "default", mock_connector) with self.assertRaises(TypeError): await message.respond("Hello there") self.assertTrue(logmock.called) self.assertTrue(mocksleep.called) # Test thinking-delay with a list mock_connector_list = Connector( { "name": "shell", "typing-delay": [1, 4], "type": "connector", "module_path": "opsdroid-modules.connector.shell", }, opsdroid=opsdroid, ) with amock.patch("asyncio.sleep") as mocksleep_list: message = events.Message("hi", "user_id", "user", "default", mock_connector_list) with self.assertRaises(TypeError): await message.respond("Hello there") self.assertTrue(mocksleep_list.called)
async def test_send_message_inside_thread_is_true(connector, send_event): connector.start_thread = True linked_event = events.Message( text="linked text", event_id="1582838099.000601", raw_event={} ) event = events.Message( text="test", user="******", target="room", connector=connector, linked_event=linked_event, ) payload, response = await send_event(CHAT_POST_MESSAGE, event) assert payload == { "channel": "room", "text": "test", "username": "******", "icon_emoji": ":robot_face:", "thread_ts": "1582838099.000601", } assert response["ok"]
async def test_react(self): opsdroid = amock.CoroutineMock() mock_connector = Connector({ 'name': 'shell', 'thinking-delay': 2, 'type': 'connector', }, opsdroid=opsdroid) with amock.patch('asyncio.sleep') as mocksleep: message = events.Message("user", "default", mock_connector, "Hello world") reacted = await message.react("emoji") self.assertTrue(mocksleep.called) self.assertFalse(reacted)
async def add_item(self, message): await message.respond(events.Message("Adding item to agenda")) db = self.opsdroid.get_database("matrix") with db.memory_in_room(message.target): all_items = await self.opsdroid.memory.get("agenda_items") or [] all_items.append(message.regex.capturesdict()['item'][0]) with db.memory_in_room(message.target): await self.opsdroid.memory.put("agenda_items", all_items)
async def test_typing_delay(self): with OpsDroid() as opsdroid: mock_connector = Connector( { 'name': 'shell', 'typing-delay': 0.3, 'type': 'connector', 'module_path': 'opsdroid-modules.connector.shell' }, opsdroid=opsdroid) with amock.patch( 'opsdroid.events.Message._typing_delay') as logmock: with amock.patch('asyncio.sleep') as mocksleep: message = events.Message("hi", "user", "default", mock_connector) with self.assertRaises(TypeError): await message.respond("Hello there") self.assertTrue(logmock.called) self.assertTrue(mocksleep.called) # Test thinking-delay with a list mock_connector_list = Connector( { 'name': 'shell', 'typing-delay': [1, 4], 'type': 'connector', 'module_path': 'opsdroid-modules.connector.shell' }, opsdroid=opsdroid) with amock.patch('asyncio.sleep') as mocksleep_list: message = events.Message("hi", "user", "default", mock_connector_list) with self.assertRaises(TypeError): await message.respond("Hello there") self.assertTrue(mocksleep_list.called)
async def test_react(self): with OpsDroid() as opsdroid: mock_connector = Connector( {"name": "shell", "thinking-delay": 2, "type": "connector"}, opsdroid=opsdroid, ) with amock.patch("asyncio.sleep") as mocksleep: message = events.Message( "Hello world", "user", "default", mock_connector ) with self.assertRaises(TypeError): await message.respond(events.Reaction("emoji")) self.assertTrue(mocksleep.called)
async def test_parse_event_with_args(self): with OpsDroid() as opsdroid: opsdroid.run_skill = amock.CoroutineMock() mock_skill = await self.getMockSkill() opsdroid.skills.append( match_event(events.Message, value="click_me_123")(mock_skill) ) mock_connector = amock.CoroutineMock() message1 = events.Message("Hello World", "user", "default", mock_connector) message1.update_entity("value", "click_me_123") await opsdroid.parse(message1) self.assertTrue(opsdroid.run_skill.called) opsdroid.run_skill.reset_mock() message2 = events.Message("Hello World", "user", "default", mock_connector) message2.update_entity("value", "click_me_456") await opsdroid.parse(message2) self.assertFalse(opsdroid.run_skill.called)