async def test_respond(self): connector = ConnectorSlack({"api-token": "abc123"}, opsdroid=OpsDroid()) connector.slacker.chat.post_message = amock.CoroutineMock() await connector.send(Message("test", "user", "room", connector)) self.assertTrue(connector.slacker.chat.post_message.called)
def test_respond(self): connector = Connector({}, opsdroid=OpsDroid()) with self.assertRaises(TypeError): self.loop.run_until_complete(connector.send(Message("")))
async def test_disconnect(self): connector = Connector({}, opsdroid=OpsDroid()) res = await connector.disconnect() assert res is None
async def test_listen(self): """Test that listen does nothing.""" connector = ConnectorWebsocket({}, opsdroid=OpsDroid()) await connector.listen()
def test_init(self): config = {"example_item": "test"} connector = Connector(config, opsdroid=OpsDroid()) self.assertEqual(None, connector.default_target) self.assertEqual("", connector.name) self.assertEqual("test", connector.config["example_item"])
async def test_respond_user_role(self): existing_power_levels = { "ban": 50, "events": { "m.room.name": 100, "m.room.power_levels": 100 }, "events_default": 0, "invite": 50, "kick": 50, "notifications": { "room": 20 }, "redact": 50, "state_default": 50, "users": { "@example:localhost": 100 }, "users_default": 0, } role_events = [ ( events.UserRole(75, target="!test:localhost", user_id="@test:localhost"), 75, ), ( events.UserRole("mod", target="!test:localhost", user_id="@test:localhost"), 50, ), ( events.UserRole("admin", target="!test:localhost", user_id="@test:localhost"), 100, ), ] for event, pl in role_events: with OpsDroid() as opsdroid, amock.patch( api_string.format("send_state_event")) as patched_send: with amock.patch(api_string.format( "get_power_levels")) as patched_power_levels: opsdroid.connectors = [self.connector] patched_power_levels.return_value = asyncio.Future() patched_power_levels.return_value.set_result( existing_power_levels) patched_send.return_value = asyncio.Future() patched_send.return_value.set_result({}) await self.connector.send(event) modified_power_levels = deepcopy(existing_power_levels) modified_power_levels["users"]["@test:localhost"] = pl assert patched_send.called_once_with( "!test:localhost", "m.room.power_levels", existing_power_levels, state_key=None, )
def test_property(self): connector = ConnectorWebsocket({}, opsdroid=OpsDroid()) self.assertEqual("websocket", connector.name)
async def test_train_rasanlu(self): with OpsDroid() as opsdroid: opsdroid.config["parsers"] = [{"name": "rasanlu"}] with amock.patch("opsdroid.parsers.rasanlu.train_rasanlu"): await opsdroid.train_parsers({})
def test_multiple_opsdroids(self): with OpsDroid() as opsdroid: opsdroid.__class__.critical = mock.MagicMock() with OpsDroid() as opsdroid2, self.assertRaises(SystemExit): opsdroid2.exit() self.assertEqual(len(opsdroid.__class__.critical.mock_calls), 1)
def test_default_target(self): with OpsDroid() as opsdroid: mock_connector = Connector({}, opsdroid=opsdroid) self.assertEqual(None, mock_connector.default_target)
def test_is_running(self): with OpsDroid() as opsdroid: self.assertFalse(opsdroid.is_running()) opsdroid._running = True self.assertTrue(opsdroid.is_running())
async def test_train_rasanlu(self): with OpsDroid() as opsdroid: opsdroid.config["parsers"] = {"rasanlu": {"enabled": True}} with amock.patch("opsdroid.parsers.rasanlu.train_rasanlu"): await opsdroid.train_parsers({})
async def test_listen_loop(self): """Test that listening consumes from the socket.""" connector = ConnectorSlack({"api-token": "abc123"}, opsdroid=OpsDroid()) connector.listening = False await connector.listen()
def test_missing_api_key(self): """Test that creating without an API key raises an error.""" with self.assertRaises(KeyError): ConnectorSlack({}, opsdroid=OpsDroid())
async def test_web(self): """Create a web object and check the config.""" with OpsDroid() as opsdroid: app = web.Web(opsdroid) self.assertEqual(app.config, {})
def test_core(self): with OpsDroid() as opsdroid: self.assertIsInstance(opsdroid, OpsDroid)
async def test_connect(self): with amock.patch( api_string.format("login")) as patched_login, amock.patch( api_string.format("join_room") ) as patched_join_room, amock.patch( api_string.format("create_filter") ) as patched_filter, amock.patch( api_string.format("sync")) as patched_sync, amock.patch( api_string.format("get_display_name") ) as patched_get_nick, amock.patch( api_string.format("set_display_name") ) as patch_set_nick, amock.patch( "aiohttp.ClientSession") as patch_cs, OpsDroid() as _: # Skip actually creating a client session patch_cs.return_value = amock.MagicMock() patched_login.return_value = asyncio.Future() patched_login.return_value.set_result( {"access_token": "arbitrary string1"}) patched_join_room.return_value = asyncio.Future() patched_join_room.return_value.set_result( {"room_id": "!aroomid:localhost"}) patched_filter.return_value = asyncio.Future() patched_filter.return_value.set_result( {"filter_id": "arbitrary string"}) patched_sync.return_value = asyncio.Future() patched_sync.return_value.set_result( {"next_batch": "arbitrary string2"}) await self.connector.connect() assert "!aroomid:localhost" in self.connector.room_ids.values() assert self.connector.connection.token == "arbitrary string1" assert self.connector.filter_id == "arbitrary string" assert self.connector.connection.sync_token == "arbitrary string2" self.connector.nick = "Rabbit Hole" patched_get_nick.return_value = asyncio.Future() patched_get_nick.return_value.set_result("Rabbit Hole") await self.connector.connect() assert patched_get_nick.called assert not patch_set_nick.called patched_get_nick.return_value = asyncio.Future() patched_get_nick.return_value.set_result("Neo") self.connector.mxid = "@morpheus:matrix.org" await self.connector.connect() assert patched_get_nick.called patch_set_nick.assert_called_once_with("@morpheus:matrix.org", "Rabbit Hole")
def test_exit(self): with OpsDroid() as opsdroid, self.assertRaises(SystemExit): opsdroid.eventloop = mock.Mock() opsdroid.eventloop.is_running.return_value = True opsdroid.exit() self.assertTrue(opsdroid.eventloop.stop.called)
def test_init(self): connector = ConnectorWebsocket({}, opsdroid=OpsDroid()) self.assertEqual(None, connector.default_room) self.assertEqual("websocket", connector.name)
def test_critical(self): with OpsDroid() as opsdroid, self.assertRaises(SystemExit): opsdroid.critical("An error", 1)
async def test_lookup_username(self): """Test lookup up the username.""" connector = ConnectorWebsocket({}, opsdroid=OpsDroid()) self.assertEqual("websocket", connector.name)
def test_stop(self): with OpsDroid() as opsdroid: self.assertFalse(opsdroid.eventloop.is_closed()) opsdroid.stop() self.assertFalse(opsdroid.eventloop.is_running())
async def test_parse_witai_entities(self): with OpsDroid() as opsdroid: opsdroid.config["parsers"] = [{ "name": "witai", "access-token": "test", "min-score": 0.3 }] mock_skill = await self.getMockSkill() opsdroid.skills.append(match_witai("get_weather")(mock_skill)) mock_connector = amock.CoroutineMock() message = Message( text="what is the weather in london", user="******", target="default", connector=mock_connector, ) with amock.patch.object(witai, "call_witai") as mocked_call_witai: mocked_call_witai.return_value = { "msg_id": "0fI07qSgCwM79NEjs", "_text": "what is the weather in london", "entities": { "intent": [{ "confidence": 0.99897986426571, "value": "get_weather" }], "location": [{ "confidence": 0.93009, "value": "london", "resolved": { "values": [ { "name": "London", "grain": "locality", "type": "resolved", "timezone": "Europe/London", "coords": { "lat": 51.508529663086, "long": -0.12574000656605, }, "external": { "geonames": "2643743", "wikidata": "Q84", "wikipedia": "London", }, }, { "name": "London", "grain": "locality", "type": "resolved", "timezone": "America/New_York", "coords": { "lat": 39.886451721191, "long": -83.448249816895, }, "external": { "geonames": "4517009", "wikidata": "Q1001456", "wikipedia": "London, Ohio", }, }, { "name": "London", "grain": "locality", "type": "resolved", "timezone": "America/Toronto", "coords": { "lat": 42.983390808105, "long": -81.233039855957, }, "external": { "geonames": "6058560", "wikidata": "Q22647924", }, }, ] }, }], }, } [skill ] = await witai.parse_witai(opsdroid, opsdroid.skills, message, opsdroid.config["parsers"][0]) self.assertEqual(len(skill["message"].entities.keys()), 1) self.assertTrue("location" in skill["message"].entities.keys()) self.assertEqual(skill["message"].entities["location"]["value"], "london")
def test_restart(self): with OpsDroid() as opsdroid: opsdroid.eventloop.create_task(asyncio.sleep(1)) self.assertFalse(opsdroid.should_restart) opsdroid.restart() self.assertTrue(opsdroid.should_restart)
def test_listen(self): connector = Connector({}, opsdroid=OpsDroid()) with self.assertRaises(NotImplementedError): self.loop.run_until_complete(connector.listen())
def test_load_config(self): with OpsDroid() as opsdroid: opsdroid.loader = mock.Mock() opsdroid.load() self.assertTrue(opsdroid.loader.load_config_file.called)
def test_unsupported_event(self): connector = Connector({}, opsdroid=OpsDroid()) with self.assertRaises(TypeError): self.loop.run_until_complete(connector.send(Reaction("emoji")))
class TestEventCreatorAsync(asynctest.TestCase): def setUp(self): configure_lang({}) self.od = OpsDroid() self.od.__enter__() self.connector = ConnectorSlack({"token": "abc123"}, opsdroid=self.od) self.event_creator = slackevents.SlackEventCreator( self.connector, self.connector.slack_rtm) def tearDown(self): slack.RTMClient._callbacks = collections.defaultdict(list) del self.connector del self.event_creator self.od.__exit__(None, None, None) del self.od @property def message_event(self): return { "text": "Hello World", "user": "******", "team": "T9T6EKEEB", "source_team": "T9T6EKEEB", "user_team": "T9T6EKEEB", "channel": "C9S8JGM2R", "event_ts": "1582838099.000600", "ts": "1582838099.000600", } async def test_create_message(self): with amock.patch( "opsdroid.connector.slack.ConnectorSlack.lookup_username" ) as lookup, amock.patch("opsdroid.core.OpsDroid.parse") as parse: lookup.return_value = asyncio.Future() lookup.return_value.set_result({"name": "testuser"}) await self.connector.slack_rtm._dispatch_event( "message", self.message_event) (called_event, ), _ = parse.call_args self.assertTrue(isinstance(called_event, events.Message)) self.assertTrue(called_event.text == self.message_event["text"]) self.assertTrue(called_event.user == "testuser") self.assertTrue(called_event.user_id == self.message_event["user"]) self.assertTrue( called_event.target == self.message_event["channel"]) self.assertTrue(called_event.event_id == self.message_event["ts"]) self.assertTrue(called_event.raw_event == self.message_event) lookup.assert_called_with("U9S8JGF45") async def test_create_message_no_user(self): with amock.patch( "opsdroid.connector.slack.events.SlackEventCreator._get_user_name" ) as getuser, amock.patch("opsdroid.core.OpsDroid.parse") as parse: getuser.return_value = asyncio.Future() getuser.return_value.set_result(None) await self.connector.slack_rtm._dispatch_event( "message", self.message_event) parse.assert_not_called() @property def bot_message_event(self): return { "subtype": "bot_message", "text": "Hello", "username": "******", "bot_id": "BDATLJZKQ", "team": "T9T6EKEEB", "bot_profile": { "id": "BDATLJZKQ", "deleted": False, "name": "rss", "updated": 1539016312, "app_id": "A0F81R7U7", "team_id": "T9T6EKEEB", }, "channel": "C9S8JGM2R", "event_ts": "1582841283.001700", "ts": "1582841283.001700", } async def test_create_message_from_bot(self): # Skip this test until we have implemented bot user name lookup return with amock.patch("opsdroid.core.OpsDroid.parse") as parse: await self.connector.slack_rtm._dispatch_event( "message", self.bot_message_event) (called_event, ), _ = parse.call_args self.assertTrue(isinstance(called_event, events.Message)) self.assertTrue( called_event.text == self.bot_message_event["text"]) self.assertTrue(called_event.user == "testuser") self.assertTrue( called_event.user_id == self.bot_message_event["user"]) self.assertTrue( called_event.target == self.bot_message_event["channel"]) self.assertTrue( called_event.event_id == self.bot_message_event["ts"]) self.assertTrue(called_event.raw_event == self.bot_message_event) async def test_ignore_own_bot_message(self): self.connector.bot_id = self.bot_message_event["bot_id"] with amock.patch("opsdroid.core.OpsDroid.parse") as parse: await self.connector.slack_rtm._dispatch_event( "message", self.bot_message_event) self.assertFalse(parse.called) self.connector.bot_id = None @property def channel_created_event(self): return { "channel": { "id": "CUM24109W", "is_channel": True, "name": "test100", "name_normalized": "test100", "created": 1582843467, "creator": "U9S8JGF45", "is_shared": False, "is_org_shared": False, }, "event_ts": "1582843467.006500", } async def test_create_channel_created_event(self): with amock.patch( "opsdroid.connector.slack.ConnectorSlack.lookup_username" ) as lookup, amock.patch("opsdroid.core.OpsDroid.parse") as parse: lookup.return_value = asyncio.Future() lookup.return_value.set_result({"name": "testuser"}) await self.connector.slack_rtm._dispatch_event( "channel_created", self.channel_created_event) (called_event, ), _ = parse.call_args self.assertTrue(isinstance(called_event, events.NewRoom)) self.assertTrue(called_event.user_id == self.channel_created_event["channel"]["creator"]) self.assertTrue(called_event.user == "testuser") self.assertTrue(called_event.target == self.channel_created_event["channel"]["id"]) self.assertTrue(called_event.connector == self.connector) self.assertTrue(called_event.event_id == self.channel_created_event["event_ts"]) self.assertTrue(called_event.name == self.channel_created_event["channel"]["name"]) lookup.assert_called_with("U9S8JGF45") @property def channel_archive_event(self): return { "channel": "CULJAHTUL", "user": "******", "is_moved": 0, "event_ts": "1582843733.007500", } async def test_create_channel_archive_event(self): with amock.patch( "opsdroid.connector.slack.ConnectorSlack.lookup_username" ) as lookup, amock.patch("opsdroid.core.OpsDroid.parse") as parse: lookup.return_value = asyncio.Future() lookup.return_value.set_result({"name": "testuser"}) await self.connector.slack_rtm._dispatch_event( "channel_archive", self.channel_archive_event) (called_event, ), _ = parse.call_args self.assertTrue( isinstance(called_event, slackevents.ChannelArchived)) self.assertTrue( called_event.target == self.channel_archive_event["channel"]) self.assertTrue(called_event.connector == self.connector) self.assertTrue(called_event.event_id == self.channel_archive_event["event_ts"]) @property def channel_unarchive_event(self): return { "channel": "CULJAHTUL", "user": "******", "event_ts": "1582843808.007700", } async def test_create_channel_unarchive_event(self): with amock.patch( "opsdroid.connector.slack.ConnectorSlack.lookup_username" ) as lookup, amock.patch("opsdroid.core.OpsDroid.parse") as parse: lookup.return_value = asyncio.Future() lookup.return_value.set_result({"name": "testuser"}) await self.connector.slack_rtm._dispatch_event( "channel_unarchive", self.channel_unarchive_event) (called_event, ), _ = parse.call_args self.assertTrue( isinstance(called_event, slackevents.ChannelUnarchived)) self.assertTrue( called_event.target == self.channel_unarchive_event["channel"]) self.assertTrue(called_event.connector == self.connector) self.assertTrue(called_event.event_id == self.channel_unarchive_event["event_ts"]) @property def join_event(self): return { "user": { "id": "UV6E5JA5T", "team_id": "T9T6EKEEB", "name": "slack1", "deleted": False, "color": "99a949", "real_name": "test4", "tz": "Europe/London", "tz_label": "Greenwich Mean Time", "tz_offset": 0, "profile": { "title": "", "phone": "", "skype": "", "real_name": "test4", "real_name_normalized": "test4", "display_name": "test4", "display_name_normalized": "test4", "fields": None, "status_text": "", "status_emoji": "", "status_expiration": 0, "avatar_hash": "gaa2e6c047a5", "status_text_canonical": "", "team": "T9T6EKEEB", }, "is_admin": False, "is_owner": False, "is_primary_owner": False, "is_restricted": False, "is_ultra_restricted": False, "is_bot": False, "is_app_user": False, "updated": 1583879206, "presence": "away", }, "cache_ts": 1583879206, "event_ts": "1583879207.001200", } async def test_user_join(self): with amock.patch( "opsdroid.connector.slack.ConnectorSlack.lookup_username" ) as lookup, amock.patch("opsdroid.core.OpsDroid.parse") as parse: lookup.return_value = asyncio.Future() lookup.return_value.set_result({"name": "testuser"}) await self.connector.slack_rtm._dispatch_event( "team_join", self.join_event) lookup.assert_called_with("UV6E5JA5T") (called_event, ), _ = parse.call_args assert isinstance(called_event, events.JoinGroup) self.assertTrue(called_event.user == "testuser") self.assertTrue( called_event.user_id == self.join_event["user"]["id"]) self.assertTrue( called_event.target == self.join_event["user"]["team_id"]) self.assertTrue( called_event.event_id == self.join_event["event_ts"]) self.assertTrue(called_event.raw_event == self.join_event) @property def edit_event(self): return { "subtype": "message_changed", "hidden": True, "message": { "type": "message", "text": "Hello World", "user": "******", "team": "T9T6EKEEB", "edited": { "user": "******", "ts": "1582842709.000000" }, "ts": "1582842695.003200", "source_team": "T9T6EKEEB", "user_team": "T9T6EKEEB", }, "channel": "C9S8JGM2R", "previous_message": { "type": "message", "text": "Hi", "user": "******", "ts": "1582842695.003200", "team": "T9T6EKEEB", }, "event_ts": "1582842709.003300", "ts": "1582842709.003300", } async def test_create_message_from_edit(self): with amock.patch( "opsdroid.connector.slack.ConnectorSlack.lookup_username" ) as lookup, amock.patch("opsdroid.core.OpsDroid.parse") as parse: lookup.return_value = asyncio.Future() lookup.return_value.set_result({"name": "testuser"}) await self.connector.slack_rtm._dispatch_event( "message", self.edit_event) assert parse.called is False # lookup.assert_called_once_with("U9S8JGF45") async def test_create_event_fails(self): # The create_event method of the event creator is redundant in slack because the RTM is # doing the heavy lifting on that. Check that it fails loudly if it gets called. with self.assertRaises(NotImplementedError): await self.event_creator.create_event(self.message_event, "hello") async def test_get_user_name(self): # Check that username lookup works with a username with amock.patch( "opsdroid.connector.slack.ConnectorSlack.lookup_username" ) as lookup: lookup.return_value = asyncio.Future() lookup.return_value.set_result({"name": "testuser"}) username = await self.event_creator._get_user_name( self.message_event) assert username == "testuser" async def test_get_user_name_fails(self): # Check that username lookup works without a username userless_event = self.message_event del userless_event["user"] user_info = await self.event_creator._get_user_name(userless_event) assert user_info is None @property def channel_name_event(self): return { "type": "channel_rename", "channel": { "id": "C02ELGNBH", "name": "new_name", "created": 1360782804 }, "event_ts": "1582842709.003300", "ts": "1582842709.003300", } async def test_channel_rename(self): with amock.patch( "opsdroid.connector.slack.ConnectorSlack.lookup_username" ) as lookup, amock.patch("opsdroid.core.OpsDroid.parse") as parse: await self.connector.slack_rtm._dispatch_event( "channel_rename", self.channel_name_event) (called_event, ), _ = parse.call_args assert isinstance(called_event, events.RoomName) assert called_event.name == self.channel_name_event["channel"][ "name"] assert called_event.target == self.channel_name_event["channel"][ "id"] assert called_event.connector == self.connector assert called_event.event_id == self.channel_name_event["event_ts"] lookup.assert_not_called() @property def pin_added_event(self): return { "type": "pin_added", "user": "******", "channel_id": "C02ELGNBH", "item": self.message_event, "event_ts": "1582842709.003301", } async def test_pin_message(self): with amock.patch( "opsdroid.connector.slack.ConnectorSlack.lookup_username" ) as lookup, amock.patch("opsdroid.core.OpsDroid.parse") as parse: await self.connector.slack_rtm._dispatch_event( "pin_added", self.pin_added_event) (called_event, ), _ = parse.call_args assert isinstance(called_event, events.PinMessage) assert called_event.target == self.pin_added_event["channel_id"] assert called_event.connector == self.connector assert called_event.event_id == self.pin_added_event["event_ts"] assert called_event.linked_event == self.message_event lookup.assert_not_called() @property def pin_removed_event(self): return { "type": "pin_removed", "user": "******", "channel_id": "C02ELGNBH", "item": self.message_event, "event_ts": "1582842709.003302", } async def test_unpin_message(self): with amock.patch( "opsdroid.connector.slack.ConnectorSlack.lookup_username" ) as lookup, amock.patch("opsdroid.core.OpsDroid.parse") as parse: await self.connector.slack_rtm._dispatch_event( "pin_removed", self.pin_removed_event) (called_event, ), _ = parse.call_args assert isinstance(called_event, events.UnpinMessage) assert called_event.target == self.pin_removed_event["channel_id"] assert called_event.connector == self.connector assert called_event.event_id == self.pin_removed_event["event_ts"] assert called_event.linked_event == self.message_event lookup.assert_not_called() @property def topic_changed_event(self): return { "subtype": "channel_topic", "user": "******", "text": "<@U9S8JGF45> set the channel topic: New topic", "topic": "New topic", "team": "T9T6EKEEB", "channel": "CUTKP9FDG", "event_ts": "1587296471.000100", "ts": "1587296471.000100", } async def test_topic_change(self): with amock.patch( "opsdroid.connector.slack.ConnectorSlack.lookup_username" ) as lookup, amock.patch("opsdroid.core.OpsDroid.parse") as parse: await self.connector.slack_rtm._dispatch_event( "message", self.topic_changed_event) (called_event, ), _ = parse.call_args assert isinstance(called_event, events.RoomDescription) assert called_event.target == self.topic_changed_event["channel"] assert called_event.connector == self.connector assert called_event.event_id == self.topic_changed_event[ "event_ts"] assert called_event.description == self.topic_changed_event[ "topic"] lookup.assert_not_called()
async def test_parse_sapcai_with_entities(self): with OpsDroid() as opsdroid: opsdroid.config["parsers"] = [{"name": "sapcai", "token": "test"}] mock_skill = await self.getMockSkill() mock_skill.config = {"name": "greetings"} opsdroid.skills.append(match_sapcai("weather")(mock_skill)) mock_connector = amock.CoroutineMock() message = Message( text="whats the weather in london", user="******", target="default", connector=mock_connector, ) with amock.patch.object(sapcai, "call_sapcai") as mocked_call_sapcai: mocked_call_sapcai.return_value = { "results": { "uuid": "f058ad85-d089-40e1-a910-a76990d36180", "intents": [{ "slug": "weather", "confidence": 0.97, "description": "weather", }], "entities": { "location": [{ "formatted": "London, UK", "lat": 51.5073509, "lng": -0.1277583, "type": "locality", "place": "ChIJdd4hrwug2EcRmSrV3Vo6llI", "raw": "london", "confidence": 0.99, "country": "gb", }] }, "language": "en", "processing_language": "en", "version": "1903.6.2", "timestamp": "2019-06-02T12:22:57.216286+00:00", "status": 200, "source": "whats the weather in london", "act": "wh-query", "type": "desc:desc", "sentiment": "neutral", }, "message": "Requests rendered with success", } [skill ] = await sapcai.parse_sapcai(opsdroid, opsdroid.skills, message, opsdroid.config["parsers"][0]) self.assertEqual(len(skill["message"].entities.keys()), 1) self.assertTrue("location" in skill["message"].entities.keys()) self.assertEqual(skill["message"].entities["location"]["value"], "london")
def test_init(self): """Test that the connector is initialised properly.""" connector = ConnectorSlack({"api-token": "abc123"}, opsdroid=OpsDroid()) self.assertEqual("#general", connector.default_target) self.assertEqual("slack", connector.name)