async def test_listen_break_loop(self):
     """Test that listening consumes from the socket."""
     connector = ConnectorSlack({"api-token": "abc123"}, opsdroid=OpsDroid())
     connector.receive_from_websocket = amock.CoroutineMock()
     connector.receive_from_websocket.side_effect = AttributeError
     await connector.listen()
     self.assertTrue(connector.receive_from_websocket.called)
    async def test_process_message(self):
        """Test processing a slack message."""
        connector = ConnectorSlack({"api-token": "abc123"}, opsdroid=OpsDroid())
        connector.lookup_username = amock.CoroutineMock()
        connector.lookup_username.return_value = {"name": "testuser"}
        connector.opsdroid = amock.CoroutineMock()
        connector.opsdroid.parse = amock.CoroutineMock()

        message = {   # https://api.slack.com/events/message
            "type": "message",
            "channel": "C2147483705",
            "user": "******",
            "text": "Hello, world!",
            "ts": "1355517523.000005",
            "edited": {
                "user": "******",
                "ts": "1355517536.000001"
            }
        }
        await connector.process_message(message)
        self.assertTrue(connector.opsdroid.parse.called)

        connector.opsdroid.parse.reset_mock()
        message["subtype"] = "bot_message"
        await connector.process_message(message)
        self.assertFalse(connector.opsdroid.parse.called)
        del message["subtype"]

        connector.opsdroid.parse.reset_mock()
        connector.lookup_username.side_effect = ValueError
        await connector.process_message(message)
        self.assertFalse(connector.opsdroid.parse.called)
 async def test_reconnect(self):
     connector = ConnectorSlack({"api-token": "abc123"}, opsdroid=OpsDroid())
     connector.connect = amock.CoroutineMock()
     with amock.patch('asyncio.sleep') as mocked_sleep:
         await connector.reconnect(10)
         self.assertTrue(connector.connect.called)
         self.assertTrue(mocked_sleep.called)
 async def test_keepalive_websocket_loop(self):
     """Test that listening consumes from the socket."""
     connector = ConnectorSlack({"api-token": "abc123"}, opsdroid=OpsDroid())
     connector.ping_websocket = amock.CoroutineMock()
     connector.ping_websocket.side_effect = Exception()
     with self.assertRaises(Exception):
         await connector.keepalive_websocket()
     self.assertTrue(connector.ping_websocket.called)
    async def test_reconnect_on_error(self):
        import aiohttp
        connector = ConnectorSlack({"api-token": "abc123"}, opsdroid=OpsDroid())
        connector.slacker.rtm.start = amock.CoroutineMock()
        connector.slacker.rtm.start.side_effect = aiohttp.ClientOSError()
        connector.reconnect = amock.CoroutineMock()

        await connector.connect()
        self.assertTrue(connector.reconnect.called)
 async def test_connect(self):
     connector = ConnectorSlack({"api-token": "abc123"}, opsdroid=OpsDroid())
     opsdroid = amock.CoroutineMock()
     opsdroid.eventloop = self.loop
     connector.slacker.rtm.start = amock.CoroutineMock()
     connector.keepalive_websocket = amock.CoroutineMock()
     with amock.patch('websockets.connect', new=amock.CoroutineMock()) \
             as mocked_websocket_connect:
         await connector.connect()
     self.assertTrue(connector.slacker.rtm.start.called)
     self.assertTrue(mocked_websocket_connect.called)
     self.assertTrue(connector.keepalive_websocket.called)
    async def test_ping_websocket(self):
        """Test pinging the websocket."""
        import websockets
        connector = ConnectorSlack({"api-token": "abc123"}, opsdroid=OpsDroid())
        with amock.patch('asyncio.sleep', new=amock.CoroutineMock()) \
                as mocked_sleep:
            connector.websocket = amock.CoroutineMock()
            connector.websocket.send = amock.CoroutineMock()
            await connector.ping_websocket()
            self.assertTrue(mocked_sleep.called)
            self.assertTrue(connector.websocket.send.called)

            connector.reconnect = amock.CoroutineMock()
            connector.websocket.send.side_effect = \
                websockets.exceptions.ConnectionClosed(500, "Mock Error")
            await connector.ping_websocket()
            self.assertTrue(connector.reconnect.called)
    async def test_receive_from_websocket(self):
        """Test receive_from_websocket receives and reconnects."""
        import websockets
        connector = ConnectorSlack({"api-token": "abc123"}, opsdroid=OpsDroid())

        connector.websocket = amock.CoroutineMock()
        connector.websocket.recv = amock.CoroutineMock()
        connector.websocket.recv.return_value = '[]'
        connector.process_message = amock.CoroutineMock()
        await connector.receive_from_websocket()
        self.assertTrue(connector.websocket.recv.called)
        self.assertTrue(connector.process_message.called)

        connector.websocket.recv.side_effect = \
            websockets.exceptions.ConnectionClosed(500, "Mock Error")
        connector.reconnect = amock.CoroutineMock()
        await connector.receive_from_websocket()
        self.assertTrue(connector.reconnect.called)
    async def test_react_invalid_name(self):

        connector = ConnectorSlack({"token": "abc123"}, opsdroid=self.od)
        connector.slack.api_call = amock.CoroutineMock(
            side_effect=slack.errors.SlackApiError("invalid_name",
                                                   "invalid_name"))
        prev_message = events.Message(
            text="test",
            user="******",
            target="room",
            connector=connector,
            raw_event={"ts": 0},
        )
        await prev_message.respond(events.Reaction("😀"))
        self.assertLogs("_LOGGER", "warning")
Example #10
0
    async def test_react_invalid_name(self):
        import slack

        connector = ConnectorSlack({"api-token": "abc123"})
        connector.slack.api_call = amock.CoroutineMock(
            side_effect=slack.errors.SlackApiError("invalid_name",
                                                   "invalid_name"))
        prev_message = Message("test",
                               "user",
                               "room",
                               connector,
                               raw_event={"ts": 0})
        with OpsDroid():
            await prev_message.respond(Reaction("😀"))
        self.assertLogs("_LOGGER", "warning")
 async def test_react(self):
     connector = ConnectorSlack({"api-token": "abc123"})
     connector.slacker.reactions.post = amock.CoroutineMock()
     prev_message = Message("test",
                            "user",
                            "room",
                            connector,
                            raw_event={"ts": 0})
     with OpsDroid() as opsdroid:
         await prev_message.respond(Reaction("😀"))
     self.assertTrue(connector.slacker.reactions.post)
     self.assertEqual(
         connector.slacker.reactions.post.call_args[1]["data"]["name"],
         ":grinning_face:",
     )
Example #12
0
    async def test_block_actions_interactivity(self):
        """Test the block_actions interactivity type in Slack interactions handler."""

        connector = ConnectorSlack({"token": "abc123"}, opsdroid=OpsDroid())
        connector.opsdroid = amock.CoroutineMock()
        connector.opsdroid.parse = amock.CoroutineMock()

        req_ob = {
            "type": "block_actions",
            "team": {"id": "T9TK3CUKW", "domain": "example"},
            "user": {
                "id": "UA8RXUSPL",
                "username": "******",
                "team_id": "T9TK3CUKW",
            },
            "channel": {"id": "CBR2V3XEX", "name": "review-updates"},
            "actions": [
                {
                    "action_id": "WaXA",
                    "block_id": "=qXel",
                    "text": {"type": "plain_text", "text": "View", "emoji": True},
                    "value": "click_me_123",
                    "type": "button",
                    "action_ts": "1548426417.840180",
                }
            ],
        }

        mock_request = amock.CoroutineMock()
        mock_request.post = amock.CoroutineMock()
        mock_request.post.return_value = {"payload": json.dumps(req_ob)}

        response = await connector.slack_interactions_handler(mock_request)
        self.assertTrue(connector.opsdroid.parse.called)
        self.assertEqual(type(response), aiohttp.web.Response)
        self.assertEqual(response.status, 200)
Example #13
0
 async def test_connect(self):
     connector = ConnectorSlack({"token": "abc123"}, opsdroid=OpsDroid())
     opsdroid = amock.CoroutineMock()
     opsdroid.eventloop = self.loop
     connector.slack_rtm._connect_and_read = amock.CoroutineMock()
     connector.slack.api_call = amock.CoroutineMock()
     connector.opsdroid.web_server = amock.CoroutineMock()
     connector.opsdroid.web_server.web_app = amock.CoroutineMock()
     connector.opsdroid.web_server.web_app.router = amock.CoroutineMock()
     connector.opsdroid.web_server.web_app.router.add_post = amock.CoroutineMock(
     )
     await connector.connect()
     self.assertTrue(connector.slack_rtm._connect_and_read.called)
     self.assertTrue(connector.slack.api_call.called)
     self.assertTrue(
         connector.opsdroid.web_server.web_app.router.add_post.called)
Example #14
0
 async def test_react(self):
     connector = ConnectorSlack({"token": "abc123"})
     connector.slack.api_call = amock.CoroutineMock()
     prev_message = Message(
         text="test",
         user="******",
         target="room",
         connector=connector,
         raw_event={"ts": 0},
     )
     with OpsDroid():
         await prev_message.respond(Reaction("😀"))
     self.assertTrue(connector.slack.api_call)
     self.assertEqual(
         connector.slack.api_call.call_args[1]["data"]["name"], "grinning_face"
     )
Example #15
0
    async def test_react_unknown_error(self):
        import slack

        connector = ConnectorSlack({"token": "abc123"})
        connector.slack.api_call = amock.CoroutineMock(
            side_effect=slack.errors.SlackApiError("unknown", "unknown")
        )
        with self.assertRaises(slack.errors.SlackApiError), OpsDroid():
            prev_message = Message(
                text="test",
                user="******",
                target="room",
                connector=connector,
                raw_event={"ts": 0},
            )
            await prev_message.respond(Reaction("😀"))
Example #16
0
 async def test_send_blocks(self):
     connector = ConnectorSlack({"token": "abc123"}, opsdroid=OpsDroid())
     connector.slack.api_call = amock.CoroutineMock()
     await connector.send(
         Blocks(
             [{
                 "type": "section",
                 "text": {
                     "type": "mrkdwn",
                     "text": "*Test*"
                 }
             }],
             "user",
             "room",
             connector,
         ))
     self.assertTrue(connector.slack.api_call.called)
 async def test_update_blocks(self):
     connector = ConnectorSlack({"token": "abc123"}, opsdroid=self.od)
     connector.slack.api_call = amock.CoroutineMock()
     await connector.send(
         slackevents.EditedBlocks(
             [{
                 "type": "section",
                 "text": {
                     "type": "mrkdwn",
                     "text": "*Test*"
                 }
             }],
             user="******",
             target="room",
             connector=connector,
             linked_event="1358878749.000002",
         ))
     self.assertTrue(connector.slack.api_call.called)
 async def test_send_pin_removed(self):
     connector = ConnectorSlack({"token": "abc123"}, opsdroid=self.od)
     connector.slack.api_call = amock.CoroutineMock()
     await connector.send(
         events.UnpinMessage(
             target="an-existing-room",
             linked_event=events.Message(
                 "An important message",
                 user="******",
                 user_id="U9S8JGF45",
                 target="an-existing-room",
                 connector=connector,
                 event_id="1582838099.000600",
             ),
         ))
     connector.slack.api_call.assert_called_once_with(
         "pins.remove",
         data={
             "channel": "an-existing-room",
             "timestamp": "1582838099.000600"
         },
     )
Example #19
0
    async def test_lookup_username(self):
        """Test that looking up a username works and that it caches."""
        connector = ConnectorSlack({"token": "abc123"}, opsdroid=OpsDroid())
        connector.slack.users_info = amock.CoroutineMock()
        mock_user = mock.Mock()
        mock_user.data = {"user": {"name": "testuser"}}
        connector.slack.users_info.return_value = mock_user

        self.assertEqual(len(connector.known_users), 0)

        await connector.lookup_username("testuser")
        self.assertTrue(len(connector.known_users), 1)
        self.assertTrue(connector.slack.users_info.called)

        connector.slack.users_info.reset_mock()
        await connector.lookup_username("testuser")
        self.assertEqual(len(connector.known_users), 1)
        self.assertFalse(connector.slack.users_info.called)

        with self.assertRaises(ValueError):
            mock_user.data = {"user": None}
            connector.slack.users_info.return_value = mock_user
            await connector.lookup_username("invaliduser")
    async def test_edit_message(self):
        connector = ConnectorSlack({"token": "abc123"}, opsdroid=self.od)
        connector.slack.api_call = amock.CoroutineMock()
        linked_event = "1582838099.000600"

        edited_message = events.EditedMessage(
            text="edited_message",
            user="******",
            target="room",
            connector=connector,
            linked_event=linked_event,
        )

        await connector.send(edited_message)
        connector.slack.api_call.assert_called_once_with(
            "chat.update",
            data={
                "channel": "room",
                "ts": "1582838099.000600",
                "text": "edited_message",
                "as_user": False,
            },
        )
Example #21
0
    async def test_process_message(self):
        """Test processing a slack message."""
        connector = ConnectorSlack({"token": "abc123"}, opsdroid=OpsDroid())
        connector.lookup_username = amock.CoroutineMock()
        connector.lookup_username.return_value = {"name": "testuser"}
        connector.opsdroid = amock.CoroutineMock()
        connector.opsdroid.parse = amock.CoroutineMock()

        message = {  # https://api.slack.com/events/message
            "type": "message",
            "channel": "C2147483705",
            "user": "******",
            "text": "Hello, world!",
            "ts": "1355517523.000005",
            "edited": {"user": "******", "ts": "1355517536.000001"},
        }
        await connector.process_message(data=message)
        self.assertTrue(connector.opsdroid.parse.called)

        connector.opsdroid.parse.reset_mock()
        message["bot_id"] = "abc"
        message["subtype"] = "bot_message"
        connector.bot_id = message["bot_id"]
        await connector.process_message(data=message)
        self.assertFalse(connector.opsdroid.parse.called)
        del message["bot_id"]
        del message["subtype"]
        connector.bot_id = None

        connector.opsdroid.parse.reset_mock()
        message["subtype"] = "message_changed"
        await connector.process_message(data=message)
        self.assertFalse(connector.opsdroid.parse.called)
        del message["subtype"]

        connector.opsdroid.parse.reset_mock()
        connector.lookup_username.side_effect = ValueError
        await connector.process_message(data=message)
        self.assertFalse(connector.opsdroid.parse.called)

        connector.opsdroid.parse.reset_mock()
        connector.lookup_username.side_effect = KeyError
        await connector.process_message(data=message)
        self.assertFalse(connector.opsdroid.parse.called)
Example #22
0
 async def test_replace_usernames(self):
     connector = ConnectorSlack({"token": "abc123"}, opsdroid=OpsDroid())
     connector.lookup_username = amock.CoroutineMock()
     connector.lookup_username.return_value = {"name": "user"}
     result = await connector.replace_usernames("Hello <@U023BECGF>!")
     self.assertEqual(result, "Hello user!")
Example #23
0
 def test_init(self):
     """Test that the connector is initialised properly."""
     connector = ConnectorSlack({"token": "abc123"}, opsdroid=OpsDroid())
     self.assertEqual("#general", connector.default_target)
     self.assertEqual("slack", connector.name)
     self.assertEqual(10, connector.timeout)
 async def test_react_unknown_error(self):
     import slacker
     connector = ConnectorSlack({"api-token": "abc123"})
     connector.slacker.reactions.post = amock.CoroutineMock(side_effect=slacker.Error('unknown'))
     with self.assertRaises(slacker.Error):
         await connector.react(Message("test", "user", "room", connector, {'ts': 0}), "😀")
Example #25
0
 async def test_listen_loop(self):
     """Test that listening consumes from the socket."""
     connector = ConnectorSlack({"token": "abc123"}, opsdroid=OpsDroid())
     connector.listening = False
     await connector.listen()
 async def test_react_invalid_name(self):
     import slacker
     connector = ConnectorSlack({"api-token": "abc123"})
     connector.slacker.reactions.post = amock.CoroutineMock(side_effect=slacker.Error('invalid_name'))
     await connector.react(Message("test", "user", "room", connector, {'ts': 0}), "😀")
     self.assertLogs('_LOGGER', 'warning')
Example #27
0
    async def test_respond_on_interactive_actions(self):
        """Test the respond method for interactive actions in Slack."""

        result = amock.Mock()
        result.json = amock.CoroutineMock()
        result.json.return_value = {"success": "payload sent."}

        payload = {
            "type":
            "message_action",
            "team": {
                "id": "TXXXXXX",
                "domain": "coverbands"
            },
            "user": {
                "id": "UXXXXXX",
                "name": "dreamweaver"
            },
            "response_url":
            "https://hooks.slack.com/app-actions/T0MJR11A4/21974584944/yk1S9ndf35Q1flupVG5JbpM6",
        }

        interactive_action = InteractiveAction(payload)
        with amock.patch("aiohttp.ClientSession.post") as patched_request:
            patched_request.return_value = asyncio.Future()
            patched_request.return_value.set_result(result)
            await interactive_action.respond("Respond called with response_url"
                                             )
            self.assertTrue(patched_request.called)

        payload = {
            "type": "view_closed",
            "team": {
                "id": "TXXXXXX",
                "domain": "coverbands"
            },
            "user": {
                "id": "UXXXXXX",
                "name": "dreamweaver"
            },
        }

        interactive_action = InteractiveAction(payload)
        with amock.patch("aiohttp.ClientSession.post") as patched_request:
            patched_request.return_value = asyncio.Future()
            patched_request.return_value.set_result(result)
            await interactive_action.respond(
                "Respond called without response_url")
            self.assertFalse(patched_request.called)

        with OpsDroid() as opsdroid:
            connector = ConnectorSlack({"token": "abc123"},
                                       opsdroid=OpsDroid())
            raw_message = {
                "text": "Hello world",
                "user_id": "user_id",
                "user": "******",
                "room": "default",
            }
            message = Message(
                text="Hello world",
                user_id="user_id",
                user="******",
                target="default",
                connector=connector,
                raw_event=raw_message,
            )
            opsdroid.send = amock.CoroutineMock()

            with amock.patch("aiohttp.ClientSession.post") as patched_request:
                patched_request.return_value = asyncio.Future()
                patched_request.return_value.set_result(result)
                await interactive_action.respond(message)
                self.assertTrue(opsdroid.send.called)
                self.assertFalse(patched_request.called)
Example #28
0
    async def test_block_actions_interactivity(self):
        """Test the block_actions interactivity type in Slack interactions handler."""

        connector = ConnectorSlack({"token": "abc123"}, opsdroid=OpsDroid())
        connector.opsdroid = amock.CoroutineMock()
        connector.opsdroid.parse = amock.CoroutineMock()

        req_ob = {
            "type":
            "block_actions",
            "team": {
                "id": "T9TK3CUKW",
                "domain": "example"
            },
            "user": {
                "id": "UA8RXUSPL",
                "username": "******",
                "team_id": "T9TK3CUKW",
            },
            "channel": {
                "id": "CBR2V3XEX",
                "name": "review-updates"
            },
            "actions": [
                {
                    "action_id": "WaXA",
                    "block_id": "=qXel",
                    "text": {
                        "type": "plain_text",
                        "text": "View",
                        "emoji": True
                    },
                    "value": "click_me_123",
                    "type": "button",
                    "action_ts": "1548426417.840180",
                },
                {
                    "type": "overflow",
                    "block_id": "B5XNP",
                    "action_id": "BnhtF",
                    "selected_option": {
                        "text": {
                            "type": "plain_text",
                            "text": "Option 1",
                            "emoji": True,
                        },
                        "value": "value-0",
                    },
                    "action_ts": "1576336883.317406",
                },
                {
                    "type": "datepicker",
                    "block_id": "CAwR",
                    "action_id": "VS+",
                    "selected_date": "2019-12-31",
                    "initial_date": "1990-04-28",
                    "action_ts": "1576337318.133466",
                },
                {
                    "type":
                    "multi_static_select",
                    "block_id":
                    "rOL",
                    "action_id":
                    "Cd9",
                    "selected_options": [
                        {
                            "text": {
                                "type": "plain_text",
                                "text": "Choice 1",
                                "emoji": True,
                            },
                            "value": "value-0",
                        },
                        {
                            "text": {
                                "type": "plain_text",
                                "text": "Choice 2",
                                "emoji": True,
                            },
                            "value": "value-1",
                        },
                    ],
                    "placeholder": {
                        "type": "plain_text",
                        "text": "Select items",
                        "emoji": True,
                    },
                    "action_ts":
                    "1576337351.609054",
                },
                {
                    "type": "static_select",
                    "block_id": "OGN1",
                    "action_id": "4jd",
                    "selected_option": {
                        "text": {
                            "type": "plain_text",
                            "text": "Choice 2",
                            "emoji": True,
                        },
                        "value": "value-1",
                    },
                    "placeholder": {
                        "type": "plain_text",
                        "text": "Select an item",
                        "emoji": True,
                    },
                    "action_ts": "1576337378.859991",
                },
            ],
        }

        mock_request = amock.CoroutineMock()
        mock_request.post = amock.CoroutineMock()
        mock_request.post.return_value = {"payload": json.dumps(req_ob)}

        response = await connector.slack_interactions_handler(mock_request)
        self.assertTrue(connector.opsdroid.parse.called)
        self.assertEqual(connector.opsdroid.parse.call_count,
                         len(req_ob["actions"]))
        self.assertEqual(type(response), aiohttp.web.Response)
        self.assertEqual(response.status, 200)
 async def test_join_room(self):
     connector = ConnectorSlack({"token": "abc123"}, opsdroid=self.od)
     connector.slack_user.api_call = amock.CoroutineMock()
     await connector.send(events.JoinRoom(target="an-existing-room"))
     connector.slack_user.api_call.assert_called_once_with(
         "conversations.join", data={"channel": "an-existing-room"})
 async def test_send_room_creation(self):
     connector = ConnectorSlack({"token": "abc123"}, opsdroid=self.od)
     connector.slack_user.api_call = amock.CoroutineMock()
     await connector.send(events.NewRoom(name="mynewroom"))
     connector.slack_user.api_call.assert_called_once_with(
         "conversations.create", data={"name": "mynewroom"})
Example #31
0
 async def test_replace_usernames(self):
     connector = ConnectorSlack({"api-token": "abc123"}, opsdroid=OpsDroid())
     connector.lookup_username = amock.CoroutineMock()
     connector.lookup_username.return_value = {"name": 'user'}
     result = await connector.replace_usernames("Hello <@U023BECGF>!")
     self.assertEqual(result, "Hello user!")
Example #32
0
 def test_missing_api_key(self):
     """Test that creating without an API key raises an error."""
     with self.assertRaises(KeyError):
         ConnectorSlack({}, opsdroid=OpsDroid())
 def test_init(self):
     """Test that the connector is initialised properly."""
     connector = ConnectorSlack({"api-token": "abc123"})
     self.assertEqual("#general", connector.default_room)
     self.assertEqual("slack", connector.name)
 async def test_respond(self):
     connector = ConnectorSlack({"api-token": "abc123"})
     connector.slacker.chat.post_message = amock.CoroutineMock()
     await connector.respond(Message("test", "user", "room", connector))
     self.assertTrue(connector.slacker.chat.post_message.called)
Example #35
0
 async def test_respond(self):
     connector = ConnectorSlack({"api-token": "abc123"},
                                opsdroid=OpsDroid())
     connector.slack.api_call = amock.CoroutineMock()
     await connector.send(Message("test", "user", "room", connector))
     self.assertTrue(connector.slack.api_call.called)