class TestWebClient(unittest.TestCase):
    """Runs integration tests with real Slack API

    https://github.com/slackapi/python-slackclient/issues/560
    """

    def setUp(self):
        self.logger = logging.getLogger(__name__)
        self.bot_token = os.environ[SLACK_SDK_TEST_BOT_TOKEN]
        self.sync_client: WebClient = WebClient(token=self.bot_token, run_async=False, loop=asyncio.new_event_loop())
        self.async_client: WebClient = WebClient(token=self.bot_token, run_async=True)

    def tearDown(self):
        pass

    def test_issue_560_success(self):
        client = self.sync_client
        response = client.conversations_list(exclude_archived=1)
        self.assertIsNotNone(response)

        response = client.conversations_list(exclude_archived="true")
        self.assertIsNotNone(response)

    @pytest.mark.skipif(condition=is_not_specified(), reason="still unfixed")
    def test_issue_560_failure(self):
        client = self.sync_client
        response = client.conversations_list(exclude_archived=True)
        self.assertIsNotNone(response)

    @pytest.mark.skipif(condition=is_not_specified(), reason="still unfixed")
    @async_test
    async def test_issue_560_failure_async(self):
        client = self.async_client
        response = await client.conversations_list(exclude_archived=True)
        self.assertIsNotNone(response)
class TestWebClient(unittest.TestCase):
    """Runs integration tests with real Slack API"""
    def setUp(self):
        self.logger = logging.getLogger(__name__)
        self.org_admin_token = os.environ[
            SLACK_SDK_TEST_GRID_ORG_ADMIN_USER_TOKEN]
        self.sync_client: WebClient = WebClient(token=self.org_admin_token)
        self.sync_client.retry_handlers.append(
            RateLimitErrorRetryHandler(max_retry_count=2))
        self.async_client: AsyncWebClient = AsyncWebClient(
            token=self.org_admin_token)
        self.async_client.retry_handlers.append(
            AsyncRateLimitErrorRetryHandler(max_retry_count=2))

    def tearDown(self):
        pass

    @pytest.mark.skipif(condition=is_not_specified(),
                        reason="execution can take long")
    def test_sync(self):
        client = self.sync_client
        for response in client.admin_users_session_list(limit=1):
            self.assertIsNotNone(response.get("active_sessions"))

    @pytest.mark.skipif(condition=is_not_specified(),
                        reason="execution can take long")
    @async_test
    async def test_async(self):
        client = self.async_client
        async for response in await client.admin_users_session_list(limit=1):
            self.assertIsNotNone(response.get("active_sessions"))
class TestRTMClient(unittest.TestCase):
    """Runs integration tests with real Slack API

    https://github.com/slackapi/python-slackclient/issues/530
    """
    def setUp(self):
        self.logger = logging.getLogger(__name__)

    def tearDown(self):
        # Reset the decorators by @RTMClient.run_on
        RTMClient._callbacks = collections.defaultdict(list)

    @pytest.mark.skipif(condition=is_not_specified(), reason="still unfixed")
    def test_issue_530(self):
        try:
            rtm_client = RTMClient(token="I am not a token",
                                   run_async=False,
                                   loop=asyncio.new_event_loop())
            rtm_client.start()
            self.fail("Raising an error here was expected")
        except Exception as e:
            self.assertEqual(
                str(e),
                "The server responded with: {'ok': False, 'error': 'invalid_auth'}"
            )
        finally:
            if not rtm_client._stopped:
                rtm_client.stop()

    @pytest.mark.skipif(condition=is_not_specified(), reason="still unfixed")
    @async_test
    async def test_issue_530_async(self):
        try:
            rtm_client = RTMClient(token="I am not a token", run_async=True)
            await rtm_client.start()
            self.fail("Raising an error here was expected")
        except Exception as e:
            self.assertEqual(
                str(e),
                "The server responded with: {'ok': False, 'error': 'invalid_auth'}"
            )
        finally:
            if not rtm_client._stopped:
                rtm_client.stop()
Beispiel #4
0
class TestRTMClient(unittest.TestCase):
    """Runs integration tests with real Slack API

    https://github.com/slackapi/python-slackclient/issues/605
    """
    def setUp(self):
        self.logger = logging.getLogger(__name__)
        self.bot_token = os.environ[SLACK_SDK_TEST_CLASSIC_APP_BOT_TOKEN]
        self.channel_id = os.environ[SLACK_SDK_TEST_RTM_TEST_CHANNEL_ID]
        self.rtm_client = RTMClient(token=self.bot_token, run_async=False)

    def tearDown(self):
        # Reset the decorators by @RTMClient.run_on
        RTMClient._callbacks = collections.defaultdict(list)

    @pytest.mark.skipif(condition=is_not_specified(), reason="still unfixed")
    def test_issue_605(self):
        self.text = "This message was sent to verify issue #605"
        self.called = False

        @RTMClient.run_on(event="message")
        def process_messages(**payload):
            self.logger.info(payload)
            self.called = True

        def connect():
            self.logger.debug("Starting RTM Client...")
            self.rtm_client.start()

        t = threading.Thread(target=connect)
        t.setDaemon(True)
        try:
            t.start()
            self.assertFalse(self.called)

            time.sleep(3)

            self.web_client = WebClient(
                token=self.bot_token,
                run_async=False,
                loop=asyncio.new_event_loop(
                ),  # TODO: this doesn't work without this
            )
            new_message = self.web_client.chat_postMessage(
                channel=self.channel_id, text=self.text)
            self.assertFalse("error" in new_message)

            time.sleep(5)
            self.assertTrue(self.called)
        finally:
            t.join(.3)
Beispiel #5
0
class TestRTMClient(unittest.TestCase):
    """Runs integration tests with real Slack API

    https://github.com/slackapi/python-slackclient/issues/558
    """

    def setUp(self):
        self.logger = logging.getLogger(__name__)
        self.bot_token = os.environ[SLACK_SDK_TEST_CLASSIC_APP_BOT_TOKEN]

    def tearDown(self):
        # Reset the decorators by @RTMClient.run_on
        RTMClient._callbacks = collections.defaultdict(list)

    @pytest.mark.skipif(condition=is_not_specified(), reason="still unfixed")
    @async_test
    async def test_issue_558(self):
        channel_id = os.environ[SLACK_SDK_TEST_RTM_TEST_CHANNEL_ID]
        text = "This message was sent by <https://slack.dev/python-slackclient/|python-slackclient>! (test_issue_558)"

        self.message_count, self.reaction_count = 0, 0

        async def process_messages(**payload):
            self.logger.debug(payload)
            self.message_count += 1
            await asyncio.sleep(10)  # this blocks all handlers

        async def process_reactions(**payload):
            self.logger.debug(payload)
            self.reaction_count += 1

        rtm = RTMClient(token=self.bot_token, run_async=True)
        RTMClient.on(event='message', callback=process_messages)
        RTMClient.on(event='reaction_added', callback=process_reactions)

        web_client = WebClient(token=self.bot_token, run_async=True)
        message = await web_client.chat_postMessage(channel=channel_id, text=text)
        self.assertFalse("error" in message)
        ts = message["ts"]
        await asyncio.sleep(3)

        # intentionally not waiting here
        rtm.start()
        await asyncio.sleep(3)

        try:
            first_reaction = await web_client.reactions_add(channel=channel_id, timestamp=ts, name="eyes")
            self.assertFalse("error" in first_reaction)
            await asyncio.sleep(2)

            message = await web_client.chat_postMessage(channel=channel_id, text=text)
            self.assertFalse("error" in message)
            # start blocking here

            # This reaction_add event won't be handled due to a bug
            second_reaction = await web_client.reactions_add(channel=channel_id, timestamp=ts, name="tada")
            self.assertFalse("error" in second_reaction)
            await asyncio.sleep(2)

            self.assertEqual(self.message_count, 1)
            self.assertEqual(self.reaction_count, 2)  # fails
        finally:
            if not rtm._stopped:
                rtm.stop()
class TestRTMClient(unittest.TestCase):
    """Runs integration tests with real Slack API

    https://github.com/slackapi/python-slack-sdk/issues/611
    """
    def setUp(self):
        self.logger = logging.getLogger(__name__)
        self.bot_token = os.environ[SLACK_SDK_TEST_CLASSIC_APP_BOT_TOKEN]

    def tearDown(self):
        # Reset the decorators by @RTMClient.run_on
        RTMClient._callbacks = collections.defaultdict(list)

    @pytest.mark.skipif(condition=is_not_specified(),
                        reason="To avoid rate limited errors")
    @async_test
    async def test_issue_611(self):
        channel_id = os.environ[SLACK_SDK_TEST_RTM_TEST_CHANNEL_ID]
        text = "This message was sent by <https://slack.dev/python-slackclient/|python-slackclient>! (test_issue_611)"

        self.message_count, self.reaction_count = 0, 0

        async def process_messages(**payload):
            self.logger.info(payload)
            if "subtype" in payload["data"] and payload["data"][
                    "subtype"] == "message_replied":
                return  # skip

            self.message_count += 1
            raise Exception("something is wrong!"
                            )  # This causes the termination of the process

        async def process_reactions(**payload):
            self.logger.info(payload)
            self.reaction_count += 1

        rtm = RTMClient(token=self.bot_token, run_async=True)
        RTMClient.on(event='message', callback=process_messages)
        RTMClient.on(event='reaction_added', callback=process_reactions)

        web_client = WebClient(token=self.bot_token, run_async=True)
        message = await web_client.chat_postMessage(channel=channel_id,
                                                    text=text)
        ts = message["ts"]

        await asyncio.sleep(3)

        # intentionally not waiting here
        rtm.start()

        try:
            await asyncio.sleep(3)

            first_reaction = await web_client.reactions_add(channel=channel_id,
                                                            timestamp=ts,
                                                            name="eyes")
            self.assertFalse("error" in first_reaction)
            await asyncio.sleep(2)

            should_be_ignored = await web_client.chat_postMessage(
                channel=channel_id, text="Hello?", thread_ts=ts)
            self.assertFalse("error" in should_be_ignored)
            await asyncio.sleep(2)

            second_reaction = await web_client.reactions_add(
                channel=channel_id, timestamp=ts, name="tada")
            self.assertFalse("error" in second_reaction)
            await asyncio.sleep(2)

            self.assertEqual(self.message_count, 1)
            self.assertEqual(self.reaction_count, 2)
        finally:
            if not rtm._stopped:
                rtm.stop()
class TestWebClient(unittest.TestCase):
    """Runs integration tests with real Slack API"""
    def setUp(self):
        if not hasattr(self, "logger"):
            self.logger = logging.getLogger(__name__)
            self.bot_token = os.environ[SLACK_SDK_TEST_BOT_TOKEN]
            self.async_client: WebClient = WebClient(token=self.bot_token,
                                                     run_async=True)
            self.sync_client: WebClient = WebClient(
                token=self.bot_token,
                run_async=False,
                loop=asyncio.new_event_loop(),  # TODO: remove this
            )
            self.channel_id = os.environ[SLACK_SDK_TEST_WEB_TEST_CHANNEL_ID]

    def tearDown(self):
        pass

    # -------------------------
    # api.test

    def test_api_test(self):
        response: SlackResponse = self.sync_client.api_test(foo="bar")
        self.assertEqual(response["args"]["foo"], "bar")

    @async_test
    async def test_api_test_async(self):
        response: SlackResponse = await self.async_client.api_test(foo="bar")
        self.assertEqual(response["args"]["foo"], "bar")

    # -------------------------
    # auth.test

    def test_auth_test(self):
        response: SlackResponse = self.sync_client.auth_test()
        self.verify_auth_test_response(response)

    @async_test
    async def test_auth_test_async(self):
        response: SlackResponse = await self.async_client.auth_test()
        self.verify_auth_test_response(response)

    def verify_auth_test_response(self, response):
        self.assertIsNotNone(response["url"])
        self.assertIsNotNone(response["user"])
        self.assertIsNotNone(response["user_id"])
        self.assertIsNotNone(response["team"])
        self.assertIsNotNone(response["team_id"])
        self.assertIsNotNone(response["bot_id"])

    # -------------------------
    # basic metadata retrieval

    def test_metadata_retrieval(self):
        client = self.sync_client
        auth = client.auth_test()
        self.assertIsNotNone(auth)
        bot = client.bots_info(bot=auth["bot_id"])
        self.assertIsNotNone(bot)

    @async_test
    async def test_metadata_retrieval_async(self):
        client = self.async_client
        auth = await client.auth_test()
        self.assertIsNotNone(auth)
        bot = await client.bots_info(bot=auth["bot_id"])
        self.assertIsNotNone(bot)

    # -------------------------
    # basic chat operations

    def test_basic_chat_operations(self):
        client = self.sync_client

        auth = client.auth_test()
        self.assertIsNotNone(auth)
        subdomain = auth["team"]

        channel = self.channel_id
        message = "This message was posted by <https://slack.dev/python-slackclient/|python-slackclient>! " + \
                  "(integration_tests/test_web_client.py #test_chat_operations)"
        new_message: SlackResponse = client.chat_postMessage(channel=channel,
                                                             text=message)
        self.assertEqual(new_message["message"]["text"], message)
        ts = new_message["ts"]

        permalink = client.chat_getPermalink(channel=channel, message_ts=ts)
        self.assertIsNotNone(permalink)
        self.assertRegex(
            permalink["permalink"],
            f"https://{subdomain}.slack.com/archives/{channel}/.+")

        new_reaction = client.reactions_add(channel=channel,
                                            timestamp=ts,
                                            name="eyes")
        self.assertIsNotNone(new_reaction)

        reactions = client.reactions_get(channel=channel, timestamp=ts)
        self.assertIsNotNone(reactions)

        reaction_removal = client.reactions_remove(channel=channel,
                                                   timestamp=ts,
                                                   name="eyes")
        self.assertIsNotNone(reaction_removal)

        thread_reply = client.chat_postMessage(channel=channel,
                                               thread_ts=ts,
                                               text="threading...")
        self.assertIsNotNone(thread_reply)

        modification = client.chat_update(channel=channel,
                                          ts=ts,
                                          text="Is this intentional?")
        self.assertIsNotNone(modification)

        reply_deletion = client.chat_delete(channel=channel,
                                            ts=thread_reply["ts"])
        self.assertIsNotNone(reply_deletion)
        message_deletion = client.chat_delete(channel=channel, ts=ts)
        self.assertIsNotNone(message_deletion)

    @async_test
    async def test_basic_chat_operations_async(self):
        client = self.async_client

        auth = await client.auth_test()
        self.assertIsNotNone(auth)
        subdomain = auth["team"]

        channel = self.channel_id
        message = "This message was posted by <https://slack.dev/python-slackclient/|python-slackclient>! " + \
                  "(integration_tests/test_web_client.py #test_chat_operations)"
        new_message: SlackResponse = await client.chat_postMessage(
            channel=channel, text=message)
        self.assertEqual(new_message["message"]["text"], message)
        ts = new_message["ts"]

        permalink = await client.chat_getPermalink(channel=channel,
                                                   message_ts=ts)
        self.assertIsNotNone(permalink)
        self.assertRegex(
            permalink["permalink"],
            f"https://{subdomain}.slack.com/archives/{channel}/.+")

        new_reaction = await client.reactions_add(channel=channel,
                                                  timestamp=ts,
                                                  name="eyes")
        self.assertIsNotNone(new_reaction)

        reactions = await client.reactions_get(channel=channel, timestamp=ts)
        self.assertIsNotNone(reactions)

        reaction_removal = await client.reactions_remove(channel=channel,
                                                         timestamp=ts,
                                                         name="eyes")
        self.assertIsNotNone(reaction_removal)

        thread_reply = await client.chat_postMessage(channel=channel,
                                                     thread_ts=ts,
                                                     text="threading...")
        self.assertIsNotNone(thread_reply)

        modification = await client.chat_update(channel=channel,
                                                ts=ts,
                                                text="Is this intentional?")
        self.assertIsNotNone(modification)

        reply_deletion = await client.chat_delete(channel=channel,
                                                  ts=thread_reply["ts"])
        self.assertIsNotNone(reply_deletion)
        message_deletion = await client.chat_delete(channel=channel, ts=ts)
        self.assertIsNotNone(message_deletion)

    # -------------------------
    # file operations

    def test_uploading_text_files(self):
        client = self.sync_client
        file, filename = __file__, os.path.basename(__file__)
        upload = client.files_upload(channels=self.channel_id,
                                     filename=filename,
                                     file=file)
        self.assertIsNotNone(upload)

        deletion = client.files_delete(file=upload["file"]["id"])
        self.assertIsNotNone(deletion)

    @async_test
    async def test_uploading_text_files_async(self):
        client = self.async_client
        file, filename = __file__, os.path.basename(__file__)
        upload = await client.files_upload(channels=self.channel_id,
                                           title="Good Old Slack Logo",
                                           filename=filename,
                                           file=file)
        self.assertIsNotNone(upload)

        deletion = await client.files_delete(file=upload["file"]["id"])
        self.assertIsNotNone(deletion)

    def test_uploading_binary_files(self):
        client = self.sync_client
        current_dir = os.path.dirname(__file__)
        file = f"{current_dir}/../../tests/data/slack_logo.png"
        upload = client.files_upload(channels=self.channel_id,
                                     title="Good Old Slack Logo",
                                     filename="slack_logo.png",
                                     file=file)
        self.assertIsNotNone(upload)

        deletion = client.files_delete(file=upload["file"]["id"])
        self.assertIsNotNone(deletion)

    def test_uploading_binary_files_as_content(self):
        client = self.sync_client
        current_dir = os.path.dirname(__file__)
        file = f"{current_dir}/../../tests/data/slack_logo.png"
        with open(file, 'rb') as f:
            content = f.read()
            upload = client.files_upload(channels=self.channel_id,
                                         title="Good Old Slack Logo",
                                         filename="slack_logo.png",
                                         content=content)
            self.assertIsNotNone(upload)

            deletion = client.files_delete(file=upload["file"]["id"])
            self.assertIsNotNone(deletion)

    @async_test
    async def test_uploading_binary_files_async(self):
        client = self.async_client
        current_dir = os.path.dirname(__file__)
        file = f"{current_dir}/../../tests/data/slack_logo.png"
        upload = await client.files_upload(channels=self.channel_id,
                                           title="Good Old Slack Logo",
                                           filename="slack_logo.png",
                                           file=file)
        self.assertIsNotNone(upload)

        deletion = client.files_delete(file=upload["file"]["id"])
        self.assertIsNotNone(deletion)

    def test_uploading_file_with_token_param(self):
        client = WebClient()
        current_dir = os.path.dirname(__file__)
        file = f"{current_dir}/../../tests/data/slack_logo.png"
        upload = client.files_upload(
            token=self.bot_token,
            channels=self.channel_id,
            title="Good Old Slack Logo",
            filename="slack_logo.png",
            file=file,
        )
        self.assertIsNotNone(upload)

        deletion = client.files_delete(
            token=self.bot_token,
            file=upload["file"]["id"],
        )
        self.assertIsNotNone(deletion)

    @async_test
    async def test_uploading_file_with_token_param_async(self):
        client = WebClient(run_async=True)
        current_dir = os.path.dirname(__file__)
        file = f"{current_dir}/../../tests/data/slack_logo.png"
        upload = await client.files_upload(
            token=self.bot_token,
            channels=self.channel_id,
            title="Good Old Slack Logo",
            filename="slack_logo.png",
            file=file,
        )
        self.assertIsNotNone(upload)

        deletion = client.files_delete(
            token=self.bot_token,
            file=upload["file"]["id"],
        )
        self.assertIsNotNone(deletion)

    # -------------------------
    # pagination

    def test_pagination_with_iterator(self):
        client = self.sync_client
        fetched_count = 0
        # SlackResponse is an iterator that fetches next if next_cursor is not ""
        for response in client.conversations_list(limit=1,
                                                  exclude_archived=1,
                                                  types="public_channel"):
            fetched_count += len(response["channels"])
            if fetched_count > 1:
                break

        self.assertGreater(fetched_count, 1)

    def test_pagination_with_iterator_use_sync_aiohttp(self):
        client: WebClient = WebClient(
            token=self.bot_token,
            run_async=False,
            use_sync_aiohttp=True,
            loop=asyncio.new_event_loop(),
        )
        fetched_count = 0
        # SlackResponse is an iterator that fetches next if next_cursor is not ""
        for response in client.conversations_list(limit=1,
                                                  exclude_archived=1,
                                                  types="public_channel"):
            fetched_count += len(response["channels"])
            if fetched_count > 1:
                break

        self.assertGreater(fetched_count, 1)

    @pytest.mark.skipif(condition=is_not_specified(), reason="still unfixed")
    @async_test
    async def test_pagination_with_iterator_async(self):
        client = self.async_client
        fetched_count = 0
        # SlackResponse is an iterator that fetches next if next_cursor is not ""
        for response in await client.conversations_list(
                limit=1, exclude_archived=1, types="public_channel"):
            fetched_count += len(response["channels"])
            if fetched_count > 1:
                break

        self.assertGreater(fetched_count, 1)
class TestRTMClient(unittest.TestCase):
    """Runs integration tests with real Slack API

    https://github.com/slackapi/python-slack-sdk/issues/569
    """
    def setUp(self):
        if not hasattr(self, "logger"):
            self.logger = logging.getLogger(__name__)
            self.channel_id = os.environ[SLACK_SDK_TEST_RTM_TEST_CHANNEL_ID]
            self.bot_token = os.environ[SLACK_SDK_TEST_CLASSIC_APP_BOT_TOKEN]

        if not hasattr(
                self,
                "cpu_monitor") or not TestRTMClient.cpu_monitor.is_alive():

            def run_cpu_monitor(self):
                self.logger.debug("Starting CPU monitor in another thread...")
                TestRTMClient.cpu_usage = 0
                while True:
                    p = psutil.Process(os.getpid())
                    current_cpu_usage: float = p.cpu_percent(interval=0.5)
                    self.logger.debug(current_cpu_usage)
                    if current_cpu_usage > TestRTMClient.cpu_usage:
                        TestRTMClient.cpu_usage = current_cpu_usage

            TestRTMClient.cpu_monitor = threading.Thread(
                target=run_cpu_monitor, args=[self])
            TestRTMClient.cpu_monitor.daemon = True
            TestRTMClient.cpu_monitor.start()

        self.rtm_client = None
        self.web_client = None

    def tearDown(self):
        # Reset the decorators by @RTMClient.run_on
        RTMClient._callbacks = collections.defaultdict(list)
        # Stop the Client
        if hasattr(self, "rtm_client") and not self.rtm_client._stopped:
            self.rtm_client.stop()

    @pytest.mark.skipif(condition=is_not_specified(),
                        reason="To avoid rate_limited errors")
    def test_cpu_usage(self):
        self.rtm_client = RTMClient(token=self.bot_token,
                                    run_async=False,
                                    loop=asyncio.new_event_loop())
        self.web_client = WebClient(token=self.bot_token)

        self.call_count = 0
        TestRTMClient.cpu_usage = 0

        @RTMClient.run_on(event="message")
        def send_reply(**payload):
            self.logger.debug(payload)
            event = payload["data"]
            if "text" in event:
                if not str(event["text"]).startswith("Current CPU usage:"):
                    web_client = payload["web_client"]
                    for i in range(0, 3):
                        new_message = web_client.chat_postMessage(
                            channel=event["channel"],
                            text=
                            f"Current CPU usage: {TestRTMClient.cpu_usage} % (test_cpu_usage)",
                        )
                        self.logger.debug(new_message)
                        self.call_count += 1

        def connect():
            self.logger.debug("Starting RTM Client...")
            self.rtm_client.start()

        rtm = threading.Thread(target=connect)
        rtm.daemon = True

        rtm.start()
        time.sleep(5)

        text = "This message was sent by <https://slack.dev/python-slackclient/|python-slackclient>! (test_cpu_usage)"
        new_message = self.web_client.chat_postMessage(channel=self.channel_id,
                                                       text=text)
        self.assertFalse("error" in new_message)

        time.sleep(5)
        self.assertLess(TestRTMClient.cpu_usage, 30,
                        "Too high CPU usage detected")
        self.assertEqual(self.call_count, 3, "The RTM handler failed")

    # >       self.assertLess(TestRTMClient.cpu_usage, 30, "Too high CPU usage detected")
    # E       AssertionError: 100.2 not less than 30 : Too high CPU usage detected
    #
    # integration_tests/rtm/test_rtm_client.py:160: AssertionError

    @async_test
    async def test_cpu_usage_async(self):
        self.rtm_client = RTMClient(token=self.bot_token, run_async=True)
        self.web_client = LegacyWebClient(token=self.bot_token, run_async=True)

        self.call_count = 0
        TestRTMClient.cpu_usage = 0

        @RTMClient.run_on(event="message")
        async def send_reply_async(**payload):
            self.logger.debug(payload)
            event = payload["data"]
            if "text" in event:
                if not str(event["text"]).startswith("Current CPU usage:"):
                    web_client = payload["web_client"]
                    for i in range(0, 3):
                        new_message = await web_client.chat_postMessage(
                            channel=event["channel"],
                            text=
                            f"Current CPU usage: {TestRTMClient.cpu_usage} % (test_cpu_usage_async)",
                        )
                        self.logger.debug(new_message)
                        self.call_count += 1

        # intentionally not waiting here
        self.rtm_client.start()

        await asyncio.sleep(5)

        text = "This message was sent by <https://slack.dev/python-slackclient/|python-slackclient>! (test_cpu_usage_async)"
        new_message = await self.web_client.chat_postMessage(
            channel=self.channel_id, text=text)
        self.assertFalse("error" in new_message)

        await asyncio.sleep(5)
        self.assertLess(TestRTMClient.cpu_usage, 30,
                        "Too high CPU usage detected")
        self.assertEqual(self.call_count, 3, "The RTM handler failed")
Beispiel #9
0
class TestRTMClient(unittest.TestCase):
    """Runs integration tests with real Slack API

    https://github.com/slackapi/python-slack-sdk/issues/701
    """
    def setUp(self):
        self.logger = logging.getLogger(__name__)
        self.bot_token = os.environ[SLACK_SDK_TEST_CLASSIC_APP_BOT_TOKEN]

    def tearDown(self):
        # Reset the decorators by @RTMClient.run_on
        RTMClient._callbacks = collections.defaultdict(list)

    # @pytest.mark.skipif(condition=is_not_specified(), reason="to avoid rate_limited errors")
    @pytest.mark.skip()
    def test_receiving_all_messages(self):
        self.rtm_client = RTMClient(token=self.bot_token,
                                    loop=asyncio.new_event_loop())
        self.web_client = WebClient(token=self.bot_token)

        self.call_count = 0

        @RTMClient.run_on(event="message")
        def send_reply(**payload):
            self.logger.debug(payload)
            web_client, data = payload["web_client"], payload["data"]
            web_client.reactions_add(channel=data["channel"],
                                     timestamp=data["ts"],
                                     name="eyes")
            self.call_count += 1

        def connect():
            self.logger.debug("Starting RTM Client...")
            self.rtm_client.start()

        rtm = threading.Thread(target=connect)
        rtm.daemon = True

        rtm.start()
        time.sleep(3)

        total_num = 10

        sender_completion = []

        def sent_bulk_message():
            for i in range(total_num):
                text = f"Sent by <https://slack.dev/python-slackclient/|python-slackclient>! ({i})"
                self.web_client.chat_postMessage(channel="#random", text=text)
                time.sleep(0.1)
            sender_completion.append(True)

        num_of_senders = 3
        senders = []
        for sender_num in range(num_of_senders):
            sender = threading.Thread(target=sent_bulk_message)
            sender.daemon = True
            sender.start()
            senders.append(sender)

        while len(sender_completion) < num_of_senders:
            time.sleep(1)

        expected_call_count = total_num * num_of_senders
        wait_seconds = 0
        max_wait = 20
        while self.call_count < expected_call_count and wait_seconds < max_wait:
            time.sleep(1)
            wait_seconds += 1

        self.assertEqual(total_num * num_of_senders, self.call_count,
                         "The RTM handler failed")

    @pytest.mark.skipif(condition=is_not_specified(),
                        reason="to avoid rate_limited errors")
    @async_test
    async def test_receiving_all_messages_async(self):
        self.rtm_client = RTMClient(token=self.bot_token, run_async=True)
        self.web_client = WebClient(token=self.bot_token, run_async=False)

        self.call_count = 0

        @RTMClient.run_on(event="message")
        async def send_reply(**payload):
            self.logger.debug(payload)
            web_client, data = payload["web_client"], payload["data"]
            await web_client.reactions_add(channel=data["channel"],
                                           timestamp=data["ts"],
                                           name="eyes")
            self.call_count += 1

        # intentionally not waiting here
        self.rtm_client.start()

        await asyncio.sleep(3)

        total_num = 10

        sender_completion = []

        def sent_bulk_message():
            for i in range(total_num):
                text = f"Sent by <https://slack.dev/python-slackclient/|python-slackclient>! ({i})"
                self.web_client.chat_postMessage(channel="#random", text=text)
                time.sleep(0.1)
            sender_completion.append(True)

        num_of_senders = 3
        senders = []
        for sender_num in range(num_of_senders):
            sender = threading.Thread(target=sent_bulk_message)
            sender.daemon = True
            sender.start()
            senders.append(sender)

        while len(sender_completion) < num_of_senders:
            await asyncio.sleep(1)

        expected_call_count = total_num * num_of_senders
        wait_seconds = 0
        max_wait = 20
        while self.call_count < expected_call_count and wait_seconds < max_wait:
            await asyncio.sleep(1)
            wait_seconds += 1

        self.assertEqual(total_num * num_of_senders, self.call_count,
                         "The RTM handler failed")
class TestWebClient(unittest.TestCase):
    """Runs integration tests with real Slack API

    https://github.com/slackapi/python-slackclient/issues/594
    """
    def setUp(self):
        self.logger = logging.getLogger(__name__)
        self.bot_token = os.environ[SLACK_SDK_TEST_BOT_TOKEN]
        self.sync_client: WebClient = WebClient(token=self.bot_token,
                                                run_async=False,
                                                loop=asyncio.new_event_loop())
        self.async_client: WebClient = WebClient(token=self.bot_token,
                                                 run_async=True)
        self.channel_id = os.environ[SLACK_SDK_TEST_WEB_TEST_CHANNEL_ID]
        self.user_id = os.environ[SLACK_SDK_TEST_WEB_TEST_USER_ID]

    def tearDown(self):
        pass

    @pytest.mark.skipif(condition=is_not_specified(), reason="still unfixed")
    def test_issue_594(self):
        client, logger = self.sync_client, self.logger
        external_url = "https://www.example.com/good-old-slack-logo"
        external_id = f"test-remote-file-{uuid4()}"
        current_dir = os.path.dirname(__file__)
        image = f"{current_dir}/../../tests/data/slack_logo.png"
        creation = client.files_remote_add(
            external_id=external_id,
            external_url=external_url,
            title="Good Old Slack Logo",
            indexable_file_contents="Good Old Slack Logo",
            preview_image=image)
        self.assertIsNotNone(creation)

        sharing = client.files_remote_share(channels=self.channel_id,
                                            external_id=external_id)
        self.assertIsNotNone(sharing)

        message = client.chat_postEphemeral(
            channel=self.channel_id,
            user="******",
            blocks=[{
                "type": "section",
                "text": {
                    "type":
                    "mrkdwn",
                    "text":
                    "This is a mrkdwn section block :ghost: *this is bold*, and ~this is crossed out~, and <https://google.com|this is a link>"
                }
            }, {
                "type": "file",
                "external_id": external_id,
                "source": "remote",
            }],
        )
        self.assertIsNotNone(message)

    def test_no_preview_image(self):
        client, logger = self.sync_client, self.logger
        external_url = "https://www.example.com/what-is-slack"
        external_id = f"test-remote-file-{uuid4()}"
        creation = client.files_remote_add(
            external_id=external_id,
            external_url=external_url,
            title="Slack (Wikipedia)",
            indexable_file_contents=
            "Slack is a proprietary business communication platform developed by Slack Technologies.",
        )
        self.assertIsNotNone(creation)

        sharing = client.files_remote_share(channels=self.channel_id,
                                            external_id=external_id)
        self.assertIsNotNone(sharing)

        message = client.chat_postEphemeral(
            channel=self.channel_id,
            user="******",
            blocks=[{
                "type": "section",
                "text": {
                    "type":
                    "mrkdwn",
                    "text":
                    "This is a mrkdwn section block :ghost: *this is bold*, and ~this is crossed out~, and <https://google.com|this is a link>"
                }
            }, {
                "type": "file",
                "external_id": external_id,
                "source": "remote",
            }],
        )
        self.assertIsNotNone(message)
Beispiel #11
0
class TestRTMClient(unittest.TestCase):
    """Runs integration tests with real Slack API

    https://github.com/slackapi/python-slack-sdk/issues/631
    """

    def setUp(self):
        if not hasattr(self, "logger"):
            self.logger = logging.getLogger(__name__)
            self.channel_id = os.environ[SLACK_SDK_TEST_RTM_TEST_CHANNEL_ID]
            self.bot_token = os.environ[SLACK_SDK_TEST_CLASSIC_APP_BOT_TOKEN]

    def tearDown(self):
        # Reset the decorators by @RTMClient.run_on
        RTMClient._callbacks = collections.defaultdict(list)
        # Stop the Client
        if hasattr(self, "rtm_client") and not self.rtm_client._stopped:
            self.rtm_client.stop()

    @pytest.mark.skipif(
        condition=is_not_specified(), reason="to avoid rate_limited errors"
    )
    def test_issue_631_sharing_event_loop(self):
        self.success = None
        self.text = "This message was sent to verify issue #631"

        self.rtm_client = RTMClient(
            token=self.bot_token,
            run_async=False,
            loop=asyncio.new_event_loop(),  # TODO: this doesn't work without this
        )

        # @RTMClient.run_on(event="message")
        # def send_reply(**payload):
        #     self.logger.debug(payload)
        #     data = payload['data']
        #     web_client = payload['web_client']
        #     web_client._event_loop = self.loop
        #     # Maybe you will also need the following line uncommented
        #     # web_client.run_async = True
        #
        #     if self.text in data['text']:
        #         channel_id = data['channel']
        #         thread_ts = data['ts']
        #         try:
        #             self.success = web_client.chat_postMessage(
        #                 channel=channel_id,
        #                 text="Thanks!",
        #                 thread_ts=thread_ts
        #             )
        #         except Exception as e:
        #             # slack.rtm.client:client.py:446 When calling '#send_reply()'
        #             # in the 'test_rtm_client' module the following error was raised: This event loop is already running
        #             self.logger.error(traceback.format_exc())
        #             raise e

        # Solution (1) for #631
        @RTMClient.run_on(event="message")
        def send_reply(**payload):
            self.logger.debug(payload)
            data = payload["data"]
            web_client = payload["web_client"]

            try:
                if "text" in data and self.text in data["text"]:
                    channel_id = data["channel"]
                    thread_ts = data["ts"]
                    self.success = web_client.chat_postMessage(
                        channel=channel_id, text="Thanks!", thread_ts=thread_ts
                    )
            except Exception as e:
                self.logger.error(traceback.format_exc())
                raise e

        def connect():
            self.logger.debug("Starting RTM Client...")
            self.rtm_client.start()

        t = threading.Thread(target=connect)
        t.daemon = True
        t.start()

        try:
            self.assertIsNone(self.success)
            time.sleep(5)

            self.web_client = WebClient(
                token=self.bot_token,
                run_async=False,
            )
            new_message = self.web_client.chat_postMessage(
                channel=self.channel_id, text=self.text
            )
            self.assertFalse("error" in new_message)

            time.sleep(5)
            self.assertIsNotNone(self.success)
        finally:
            t.join(0.3)

    # Solution (2) for #631
    @pytest.mark.skipif(
        condition=is_not_specified(), reason="this is just for reference"
    )
    @async_test
    async def test_issue_631_sharing_event_loop_async(self):
        self.success = None
        self.text = "This message was sent to verify issue #631"

        # To make run_async=True, the test method needs to be an async function + @async_test decorator
        self.rtm_client = RTMClient(token=self.bot_token, run_async=True)
        self.web_client = WebClient(token=self.bot_token, run_async=True)

        @RTMClient.run_on(event="message")
        async def send_reply(**payload):
            self.logger.debug(payload)
            data = payload["data"]
            web_client = payload["web_client"]

            try:
                if "text" in data and self.text in data["text"]:
                    channel_id = data["channel"]
                    thread_ts = data["ts"]
                    self.success = await web_client.chat_postMessage(
                        channel=channel_id, text="Thanks!", thread_ts=thread_ts
                    )
            except Exception as e:
                self.logger.error(traceback.format_exc())
                raise e

        # intentionally not waiting here
        self.rtm_client.start()

        self.assertIsNone(self.success)
        await asyncio.sleep(5)

        self.web_client = WebClient(
            token=self.bot_token,
            run_async=True,  # all need to be async here
        )
        new_message = await self.web_client.chat_postMessage(
            channel=self.channel_id, text=self.text
        )
        self.assertFalse("error" in new_message)

        await asyncio.sleep(5)
        self.assertIsNotNone(self.success)