From e65f9b657459e5976bfeffec6a912316ba3987d3 Mon Sep 17 00:00:00 2001 From: Sarah Jiang Date: Wed, 23 Jun 2021 14:40:11 -0700 Subject: [PATCH 01/16] Adds unfurl optional fields to webhook clients --- slack_sdk/webhook/__init__.py | 2 +- slack_sdk/webhook/async_client.py | 4 ++++ slack_sdk/webhook/client.py | 4 ++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/slack_sdk/webhook/__init__.py b/slack_sdk/webhook/__init__.py index 201c2efdb..e1fc1eb2a 100644 --- a/slack_sdk/webhook/__init__.py +++ b/slack_sdk/webhook/__init__.py @@ -1,6 +1,6 @@ """You can use slack_sdk.webhook.WebhookClient for Incoming Webhooks and message responses using response_url in payloads. """ -# from .async_client import AsyncWebhookClient # noqa +from .async_client import AsyncWebhookClient # noqa from .client import WebhookClient # noqa from .webhook_response import WebhookResponse # noqa diff --git a/slack_sdk/webhook/async_client.py b/slack_sdk/webhook/async_client.py index 38a6e3530..995ccfa36 100644 --- a/slack_sdk/webhook/async_client.py +++ b/slack_sdk/webhook/async_client.py @@ -87,6 +87,8 @@ async def send( response_type: Optional[str] = None, replace_original: Optional[bool] = None, delete_original: Optional[bool] = None, + unfurl_links: Optional[bool] = None, + unfurl_media: Optional[bool] = None, headers: Optional[Dict[str, str]] = None, ) -> WebhookResponse: """Performs a Slack API request and returns the result. @@ -113,6 +115,8 @@ async def send( "response_type": response_type, "replace_original": replace_original, "delete_original": delete_original, + "unfurl_links": unfurl_links, + "unfurl_media": unfurl_media, }, headers=headers, ) diff --git a/slack_sdk/webhook/client.py b/slack_sdk/webhook/client.py index d07aa6c53..e9d67dd36 100644 --- a/slack_sdk/webhook/client.py +++ b/slack_sdk/webhook/client.py @@ -77,6 +77,8 @@ def send( response_type: Optional[str] = None, replace_original: Optional[bool] = None, delete_original: Optional[bool] = None, + unfurl_links: Optional[bool] = None, + unfurl_media: Optional[bool] = None, headers: Optional[Dict[str, str]] = None, ) -> WebhookResponse: """Performs a Slack API request and returns the result. @@ -104,6 +106,8 @@ def send( "response_type": response_type, "replace_original": replace_original, "delete_original": delete_original, + "unfurl_links": unfurl_links, + "unfurl_media": unfurl_media, }, headers=headers, ) From da827cdff3603e53cc42aa2591eef8a4b3179708 Mon Sep 17 00:00:00 2001 From: Sarah Jiang Date: Wed, 23 Jun 2021 14:45:58 -0700 Subject: [PATCH 02/16] Add reference comments --- slack_sdk/webhook/async_client.py | 2 ++ slack_sdk/webhook/client.py | 2 ++ 2 files changed, 4 insertions(+) diff --git a/slack_sdk/webhook/async_client.py b/slack_sdk/webhook/async_client.py index 995ccfa36..23edd728a 100644 --- a/slack_sdk/webhook/async_client.py +++ b/slack_sdk/webhook/async_client.py @@ -100,6 +100,8 @@ async def send( response_type: The type of message (either 'in_channel' or 'ephemeral') replace_original: True if you use this option for response_url requests delete_original: True if you use this option for response_url requests + unfurl_links: Option to indicate whether text url should unfurl + unfurl_media: Option to indicate whether media url should unfurl headers: Request headers to append only for this request Returns: diff --git a/slack_sdk/webhook/client.py b/slack_sdk/webhook/client.py index e9d67dd36..1c0772be5 100644 --- a/slack_sdk/webhook/client.py +++ b/slack_sdk/webhook/client.py @@ -91,6 +91,8 @@ def send( response_type: The type of message (either 'in_channel' or 'ephemeral') replace_original: True if you use this option for response_url requests delete_original: True if you use this option for response_url requests + unfurl_links: Option to indicate whether text url should unfurl + unfurl_media: Option to indicate whether media url should unfurl headers: Request headers to append only for this request Returns: From 75efbee4393c2cb2a5dd9bf30c899d7c4d12b053 Mon Sep 17 00:00:00 2001 From: Sarah Jiang Date: Wed, 23 Jun 2021 17:48:16 -0700 Subject: [PATCH 03/16] Integer 0|1 instead of string --- slack_sdk/web/internal_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slack_sdk/web/internal_utils.py b/slack_sdk/web/internal_utils.py index 39023fe63..a2a500eef 100644 --- a/slack_sdk/web/internal_utils.py +++ b/slack_sdk/web/internal_utils.py @@ -229,7 +229,7 @@ def _next_cursor_is_present(data) -> bool: def _to_0_or_1_if_bool(v: Any) -> Union[Any, str]: if isinstance(v, bool): - return "1" if v else "0" + return 1 if v else 0 return v From 47823593f653cfbba3466bb267c228a11fd2f129 Mon Sep 17 00:00:00 2001 From: Sarah Jiang Date: Wed, 23 Jun 2021 18:29:21 -0700 Subject: [PATCH 04/16] Revert import for async module --- slack_sdk/sj_test_script.py | 88 +++++++++++++++++++++++++++++++++++ slack_sdk/webhook/__init__.py | 2 +- 2 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 slack_sdk/sj_test_script.py diff --git a/slack_sdk/sj_test_script.py b/slack_sdk/sj_test_script.py new file mode 100644 index 000000000..07093452c --- /dev/null +++ b/slack_sdk/sj_test_script.py @@ -0,0 +1,88 @@ +import logging +import asyncio + +from slack_sdk.webhook import WebhookClient + +# from slack_sdk.webhook import AsyncWebhookClient + +url = ( + "https://hooks.slack.com/services/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" +) +webhook = WebhookClient(url) + +# way 1 with a simple text message and .send() +url = "" +message_with_url = f"hello webhook world\n{url}" + +# way 2 with a body and .send_dict() +text = message_with_url +dict = {"text": text, "unfurl_links": True, "unfurl_media": True} + + +async def main(): + response = await webhook.send( + text=message_with_url, unfurl_media=True, unfurl_links=False + ) + return response + + +if __name__ == "__main__": + log = logging.getLogger() + log.setLevel(logging.DEBUG) + log.addHandler(logging.StreamHandler()) + response = asyncio.run(main()) # way 1 + # response = webhook.send_dict(dict) # way 2 + log.debug(response.body) + assert response.status_code == 200 + assert response.body == "ok" + + +# Example Urls + +# These testing conditions are done so with +# the knowledge that repeated urls (w/in the +# same hour will not unfurl: + +# Test Conditions 0 +# Conditions: no additional args +# Expected: +# - When text based link is supplied -> no unfurl ✅ +# - When a text based link is supplied with same domain -> no unfirl ✅ +# - When a text based link is supplied -> no unfirl ✅ +# - When a text based link is supplied with different domain -> unfirl 🔴 + +# Test Conditions 1 +# Conditions: links = False, media = False +# Expected: +# - When link is supplied -> No unfurl +# - When media is supplied -> No unfurl +# Actual: +# - When link is supplied -> ❓ +# - When media is supplied -> ❓ + +# Test Conditions 2 +# Conditions: links = True, media = True +# Expected: +# - When link is supplied -> Unfurl +# - When media is supplied -> Unfurl +# Actual: +# - When link is supplied -> ❓ +# - When media is supplied -> ❓ + +# Test Conditions 3 +# Conditions: links = False, media = True +# Expected: +# - When link is supplied -> No unfurl +# - When media is supplied -> Unfurl +# Actual: +# - When link is supplied -> ❓ +# - When media is supplied -> ❓ + +# Test Conditions 4 +# Conditions: links = True, media = False +# Expected: +# - When link is supplied -> Unfurl +# - When media is supplied -> No unfurl +# Actual: +# - When link is supplied -> ❓ +# - When media is supplied -> ❓ diff --git a/slack_sdk/webhook/__init__.py b/slack_sdk/webhook/__init__.py index e1fc1eb2a..201c2efdb 100644 --- a/slack_sdk/webhook/__init__.py +++ b/slack_sdk/webhook/__init__.py @@ -1,6 +1,6 @@ """You can use slack_sdk.webhook.WebhookClient for Incoming Webhooks and message responses using response_url in payloads. """ -from .async_client import AsyncWebhookClient # noqa +# from .async_client import AsyncWebhookClient # noqa from .client import WebhookClient # noqa from .webhook_response import WebhookResponse # noqa From 5ad43b9fb5735b25ec621d33298d6443496887e8 Mon Sep 17 00:00:00 2001 From: Sarah Jiang Date: Wed, 23 Jun 2021 18:32:44 -0700 Subject: [PATCH 05/16] Removes test script + updates fxn return type --- slack_sdk/sj_test_script.py | 88 --------------------------------- slack_sdk/web/internal_utils.py | 2 +- 2 files changed, 1 insertion(+), 89 deletions(-) delete mode 100644 slack_sdk/sj_test_script.py diff --git a/slack_sdk/sj_test_script.py b/slack_sdk/sj_test_script.py deleted file mode 100644 index 07093452c..000000000 --- a/slack_sdk/sj_test_script.py +++ /dev/null @@ -1,88 +0,0 @@ -import logging -import asyncio - -from slack_sdk.webhook import WebhookClient - -# from slack_sdk.webhook import AsyncWebhookClient - -url = ( - "https://hooks.slack.com/services/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" -) -webhook = WebhookClient(url) - -# way 1 with a simple text message and .send() -url = "" -message_with_url = f"hello webhook world\n{url}" - -# way 2 with a body and .send_dict() -text = message_with_url -dict = {"text": text, "unfurl_links": True, "unfurl_media": True} - - -async def main(): - response = await webhook.send( - text=message_with_url, unfurl_media=True, unfurl_links=False - ) - return response - - -if __name__ == "__main__": - log = logging.getLogger() - log.setLevel(logging.DEBUG) - log.addHandler(logging.StreamHandler()) - response = asyncio.run(main()) # way 1 - # response = webhook.send_dict(dict) # way 2 - log.debug(response.body) - assert response.status_code == 200 - assert response.body == "ok" - - -# Example Urls - -# These testing conditions are done so with -# the knowledge that repeated urls (w/in the -# same hour will not unfurl: - -# Test Conditions 0 -# Conditions: no additional args -# Expected: -# - When text based link is supplied -> no unfurl ✅ -# - When a text based link is supplied with same domain -> no unfirl ✅ -# - When a text based link is supplied -> no unfirl ✅ -# - When a text based link is supplied with different domain -> unfirl 🔴 - -# Test Conditions 1 -# Conditions: links = False, media = False -# Expected: -# - When link is supplied -> No unfurl -# - When media is supplied -> No unfurl -# Actual: -# - When link is supplied -> ❓ -# - When media is supplied -> ❓ - -# Test Conditions 2 -# Conditions: links = True, media = True -# Expected: -# - When link is supplied -> Unfurl -# - When media is supplied -> Unfurl -# Actual: -# - When link is supplied -> ❓ -# - When media is supplied -> ❓ - -# Test Conditions 3 -# Conditions: links = False, media = True -# Expected: -# - When link is supplied -> No unfurl -# - When media is supplied -> Unfurl -# Actual: -# - When link is supplied -> ❓ -# - When media is supplied -> ❓ - -# Test Conditions 4 -# Conditions: links = True, media = False -# Expected: -# - When link is supplied -> Unfurl -# - When media is supplied -> No unfurl -# Actual: -# - When link is supplied -> ❓ -# - When media is supplied -> ❓ diff --git a/slack_sdk/web/internal_utils.py b/slack_sdk/web/internal_utils.py index a2a500eef..87848ad69 100644 --- a/slack_sdk/web/internal_utils.py +++ b/slack_sdk/web/internal_utils.py @@ -227,7 +227,7 @@ def _next_cursor_is_present(data) -> bool: return present -def _to_0_or_1_if_bool(v: Any) -> Union[Any, str]: +def _to_0_or_1_if_bool(v: Any) -> Union[Any, int]: if isinstance(v, bool): return 1 if v else 0 return v From 80f61c18bbfcf9f4056f9caa1d8a51b8f84003d3 Mon Sep 17 00:00:00 2001 From: Sarah Jiang Date: Thu, 24 Jun 2021 13:03:34 -0700 Subject: [PATCH 06/16] Add example integration test for comment --- integration_tests/webhook/test_webhook.py | 55 +++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/integration_tests/webhook/test_webhook.py b/integration_tests/webhook/test_webhook.py index 12f60d022..c93bd968d 100644 --- a/integration_tests/webhook/test_webhook.py +++ b/integration_tests/webhook/test_webhook.py @@ -1,5 +1,6 @@ import os import unittest +import time from integration_tests.env_variable_names import ( SLACK_SDK_TEST_INCOMING_WEBHOOK_URL, @@ -21,6 +22,22 @@ def setUp(self): def tearDown(self): pass + def __get_channel_id(self): + token = os.environ[SLACK_SDK_TEST_BOT_TOKEN] + channel_name = os.environ[SLACK_SDK_TEST_INCOMING_WEBHOOK_CHANNEL_NAME].replace( + "#", "" + ) + client = WebClient(token=token) + channel_id = None + for resp in client.conversations_list(limit=10): + for c in resp["channels"]: + if c["name"] == channel_name: + channel_id = c["id"] + break + if channel_id is not None: + break + return channel_id + def test_webhook(self): url = os.environ[SLACK_SDK_TEST_INCOMING_WEBHOOK_URL] webhook = WebhookClient(url) @@ -47,6 +64,44 @@ def test_webhook(self): actual_text = history["messages"][0]["text"] self.assertEqual("Hello!", actual_text) + def test_with_unfurls_off(self): + url = os.environ[SLACK_SDK_TEST_INCOMING_WEBHOOK_URL] + token = os.environ[SLACK_SDK_TEST_BOT_TOKEN] + webhook = WebhookClient(url) + client = WebClient(token=token) + # send message that does not unfurl + response = webhook.send( + text="", + unfurl_links=False, + unfurl_media=False, + ) + self.assertEqual(200, response.status_code) + self.assertEqual("ok", response.body) + # wait in order to allow Slack API to edit message with attachments + time.sleep(2) + history = client.conversations_history(channel=self.__get_channel_id(), limit=1) + self.assertIsNotNone(history) + self.assertTrue("attachments" not in history["messages"][0]) + + def test_with_unfurls_on(self): + url = os.environ[SLACK_SDK_TEST_INCOMING_WEBHOOK_URL] + token = os.environ[SLACK_SDK_TEST_BOT_TOKEN] + webhook = WebhookClient(url) + client = WebClient(token=token) + # send message that does unfurl + response = webhook.send( + text="", + unfurl_links=True, + unfurl_media=True, + ) + self.assertEqual(200, response.status_code) + self.assertEqual("ok", response.body) + # wait in order to allow Slack API to edit message with attachments + time.sleep(2) + history = client.conversations_history(channel=self.__get_channel_id(), limit=1) + self.assertIsNotNone(history) + self.assertTrue("attachments" in history["messages"][0]) + def test_with_blocks(self): url = os.environ[SLACK_SDK_TEST_INCOMING_WEBHOOK_URL] webhook = WebhookClient(url) From 12f07c64d912e0427f286e4615ee327a2ba1e8e1 Mon Sep 17 00:00:00 2001 From: Sarah Jiang Date: Thu, 24 Jun 2021 13:08:41 -0700 Subject: [PATCH 07/16] Remove repetetive logic --- integration_tests/webhook/test_webhook.py | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/integration_tests/webhook/test_webhook.py b/integration_tests/webhook/test_webhook.py index c93bd968d..ef90b1f2f 100644 --- a/integration_tests/webhook/test_webhook.py +++ b/integration_tests/webhook/test_webhook.py @@ -46,20 +46,8 @@ def test_webhook(self): self.assertEqual("ok", response.body) token = os.environ[SLACK_SDK_TEST_BOT_TOKEN] - channel_name = os.environ[SLACK_SDK_TEST_INCOMING_WEBHOOK_CHANNEL_NAME].replace( - "#", "" - ) client = WebClient(token=token) - channel_id = None - for resp in client.conversations_list(limit=10): - for c in resp["channels"]: - if c["name"] == channel_name: - channel_id = c["id"] - break - if channel_id is not None: - break - - history = client.conversations_history(channel=channel_id, limit=1) + history = client.conversations_history(channel=self.__get_channel_id(), limit=1) self.assertIsNotNone(history) actual_text = history["messages"][0]["text"] self.assertEqual("Hello!", actual_text) From 52c44f8c19899ce37c451166b8839c46b660742f Mon Sep 17 00:00:00 2001 From: Sarah Jiang Date: Thu, 24 Jun 2021 13:47:18 -0700 Subject: [PATCH 08/16] Remove boolean conversion and revert web util --- slack_sdk/web/internal_utils.py | 2 +- slack_sdk/webhook/internal_utils.py | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/slack_sdk/web/internal_utils.py b/slack_sdk/web/internal_utils.py index 87848ad69..3ef717145 100644 --- a/slack_sdk/web/internal_utils.py +++ b/slack_sdk/web/internal_utils.py @@ -229,7 +229,7 @@ def _next_cursor_is_present(data) -> bool: def _to_0_or_1_if_bool(v: Any) -> Union[Any, int]: if isinstance(v, bool): - return 1 if v else 0 + return "1" if v else "0" return v diff --git a/slack_sdk/webhook/internal_utils.py b/slack_sdk/webhook/internal_utils.py index 37def28e7..1dd94deeb 100644 --- a/slack_sdk/webhook/internal_utils.py +++ b/slack_sdk/webhook/internal_utils.py @@ -4,7 +4,6 @@ from slack_sdk.web.internal_utils import ( _parse_web_class_objects, get_user_agent, - convert_bool_to_0_or_1, ) from .webhook_response import WebhookResponse @@ -12,7 +11,6 @@ def _build_body(original_body: Optional[Dict[str, Any]]) -> Optional[Dict[str, Any]]: if original_body: body = {k: v for k, v in original_body.items() if v is not None} - body = convert_bool_to_0_or_1(body) _parse_web_class_objects(body) return body return None From 326ca992a0c531a17cc218d93b0162b179f34d52 Mon Sep 17 00:00:00 2001 From: Sarah Jiang Date: Thu, 24 Jun 2021 13:54:50 -0700 Subject: [PATCH 09/16] Revert type --- slack_sdk/web/internal_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slack_sdk/web/internal_utils.py b/slack_sdk/web/internal_utils.py index 3ef717145..39023fe63 100644 --- a/slack_sdk/web/internal_utils.py +++ b/slack_sdk/web/internal_utils.py @@ -227,7 +227,7 @@ def _next_cursor_is_present(data) -> bool: return present -def _to_0_or_1_if_bool(v: Any) -> Union[Any, int]: +def _to_0_or_1_if_bool(v: Any) -> Union[Any, str]: if isinstance(v, bool): return "1" if v else "0" return v From 9d32daa60276d5a2a0f4f6ed0c31a6de2f53d147 Mon Sep 17 00:00:00 2001 From: Sarah Jiang Date: Mon, 28 Jun 2021 09:29:37 -0700 Subject: [PATCH 10/16] Cleanup comments --- integration_tests/webhook/test_webhook.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/integration_tests/webhook/test_webhook.py b/integration_tests/webhook/test_webhook.py index ef90b1f2f..b345144a6 100644 --- a/integration_tests/webhook/test_webhook.py +++ b/integration_tests/webhook/test_webhook.py @@ -65,13 +65,16 @@ def test_with_unfurls_off(self): ) self.assertEqual(200, response.status_code) self.assertEqual("ok", response.body) - # wait in order to allow Slack API to edit message with attachments + # wait to allow Slack API to edit message with attachments time.sleep(2) history = client.conversations_history(channel=self.__get_channel_id(), limit=1) self.assertIsNotNone(history) self.assertTrue("attachments" not in history["messages"][0]) def test_with_unfurls_on(self): + # Slack API rate limits unfurls of unique links so test will + # fail when repeated. For testing, either use a different URL + # for text option or delete existing attachments in webhook channel. url = os.environ[SLACK_SDK_TEST_INCOMING_WEBHOOK_URL] token = os.environ[SLACK_SDK_TEST_BOT_TOKEN] webhook = WebhookClient(url) @@ -84,7 +87,7 @@ def test_with_unfurls_on(self): ) self.assertEqual(200, response.status_code) self.assertEqual("ok", response.body) - # wait in order to allow Slack API to edit message with attachments + # wait to allow Slack API to edit message with attachments time.sleep(2) history = client.conversations_history(channel=self.__get_channel_id(), limit=1) self.assertIsNotNone(history) From ac4f8a40a88f5afe01e0b416a2ad4077cb173664 Mon Sep 17 00:00:00 2001 From: Sarah Jiang Date: Mon, 28 Jun 2021 09:35:23 -0700 Subject: [PATCH 11/16] Add setup --- integration_tests/webhook/test_webhook.py | 38 +++++++++++------------ 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/integration_tests/webhook/test_webhook.py b/integration_tests/webhook/test_webhook.py index b345144a6..19e2f071a 100644 --- a/integration_tests/webhook/test_webhook.py +++ b/integration_tests/webhook/test_webhook.py @@ -17,27 +17,25 @@ class TestWebhook(unittest.TestCase): def setUp(self): - pass + if not hasattr(self, "channel_id"): + token = os.environ[SLACK_SDK_TEST_BOT_TOKEN] + channel_name = os.environ[ + SLACK_SDK_TEST_INCOMING_WEBHOOK_CHANNEL_NAME + ].replace("#", "") + client = WebClient(token=token) + self.channel_id = None + for resp in client.conversations_list(limit=10): + for c in resp["channels"]: + if c["name"] == channel_name: + self.channel_id = c["id"] + break + if self.channel_id is not None: + break + return self.channel_id def tearDown(self): pass - def __get_channel_id(self): - token = os.environ[SLACK_SDK_TEST_BOT_TOKEN] - channel_name = os.environ[SLACK_SDK_TEST_INCOMING_WEBHOOK_CHANNEL_NAME].replace( - "#", "" - ) - client = WebClient(token=token) - channel_id = None - for resp in client.conversations_list(limit=10): - for c in resp["channels"]: - if c["name"] == channel_name: - channel_id = c["id"] - break - if channel_id is not None: - break - return channel_id - def test_webhook(self): url = os.environ[SLACK_SDK_TEST_INCOMING_WEBHOOK_URL] webhook = WebhookClient(url) @@ -47,7 +45,7 @@ def test_webhook(self): token = os.environ[SLACK_SDK_TEST_BOT_TOKEN] client = WebClient(token=token) - history = client.conversations_history(channel=self.__get_channel_id(), limit=1) + history = client.conversations_history(channel=self.channel_id, limit=1) self.assertIsNotNone(history) actual_text = history["messages"][0]["text"] self.assertEqual("Hello!", actual_text) @@ -67,7 +65,7 @@ def test_with_unfurls_off(self): self.assertEqual("ok", response.body) # wait to allow Slack API to edit message with attachments time.sleep(2) - history = client.conversations_history(channel=self.__get_channel_id(), limit=1) + history = client.conversations_history(channel=self.channel_id, limit=1) self.assertIsNotNone(history) self.assertTrue("attachments" not in history["messages"][0]) @@ -89,7 +87,7 @@ def test_with_unfurls_on(self): self.assertEqual("ok", response.body) # wait to allow Slack API to edit message with attachments time.sleep(2) - history = client.conversations_history(channel=self.__get_channel_id(), limit=1) + history = client.conversations_history(channel=self.channel_id, limit=1) self.assertIsNotNone(history) self.assertTrue("attachments" in history["messages"][0]) From d8389f47ddf1c2997bbd7296a7f1f49c371958b0 Mon Sep 17 00:00:00 2001 From: Sarah Jiang Date: Mon, 28 Jun 2021 13:06:49 -0700 Subject: [PATCH 12/16] Add async webhook integration test --- .../webhook/test_async_webhook.py | 76 +++++++++++++++---- integration_tests/webhook/test_webhook.py | 1 - 2 files changed, 61 insertions(+), 16 deletions(-) diff --git a/integration_tests/webhook/test_async_webhook.py b/integration_tests/webhook/test_async_webhook.py index e46092bb2..e81c96b44 100644 --- a/integration_tests/webhook/test_async_webhook.py +++ b/integration_tests/webhook/test_async_webhook.py @@ -1,5 +1,6 @@ import os import unittest +import time from integration_tests.env_variable_names import ( SLACK_SDK_TEST_INCOMING_WEBHOOK_URL, @@ -16,8 +17,22 @@ class TestAsyncWebhook(unittest.TestCase): - def setUp(self): - pass + @async_test + async def setUp(self): + if not hasattr(self, "channel_id"): + token = os.environ[SLACK_SDK_TEST_BOT_TOKEN] + channel_name = os.environ[ + SLACK_SDK_TEST_INCOMING_WEBHOOK_CHANNEL_NAME + ].replace("#", "") + client = AsyncWebClient(token=token) + self.channel_id = None + async for resp in await client.conversations_list(limit=10): + for c in resp["channels"]: + if c["name"] == channel_name: + self.channel_id = c["id"] + break + if self.channel_id is not None: + break def tearDown(self): pass @@ -31,24 +46,55 @@ async def test_webhook(self): self.assertEqual("ok", response.body) token = os.environ[SLACK_SDK_TEST_BOT_TOKEN] - channel_name = os.environ[SLACK_SDK_TEST_INCOMING_WEBHOOK_CHANNEL_NAME].replace( - "#", "" - ) client = AsyncWebClient(token=token) - channel_id = None - async for resp in await client.conversations_list(limit=10): - for c in resp["channels"]: - if c["name"] == channel_name: - channel_id = c["id"] - break - if channel_id is not None: - break - - history = await client.conversations_history(channel=channel_id, limit=1) + history = await client.conversations_history(channel=self.channel_id, limit=1) self.assertIsNotNone(history) actual_text = history["messages"][0]["text"] self.assertEqual("Hello!", actual_text) + @async_test + async def test_with_unfurls_off(self): + url = os.environ[SLACK_SDK_TEST_INCOMING_WEBHOOK_URL] + token = os.environ[SLACK_SDK_TEST_BOT_TOKEN] + webhook = AsyncWebhookClient(url) + client = AsyncWebClient(token=token) + # send message that does not unfurl + response = await webhook.send( + text="", + unfurl_links=False, + unfurl_media=False, + ) + self.assertEqual(200, response.status_code) + self.assertEqual("ok", response.body) + # wait to allow Slack API to edit message with attachments + time.sleep(2) + history = await client.conversations_history(channel=self.channel_id, limit=1) + self.assertIsNotNone(history) + self.assertTrue("attachments" not in history["messages"][0]) + + @async_test + async def test_with_unfurls_on(self): + # Slack API rate limits unfurls of unique links so test will + # fail when repeated. For testing, either use a different URL + # for text option or delete existing attachments in webhook channel. + url = os.environ[SLACK_SDK_TEST_INCOMING_WEBHOOK_URL] + token = os.environ[SLACK_SDK_TEST_BOT_TOKEN] + webhook = AsyncWebhookClient(url) + client = AsyncWebClient(token=token) + # send message that does unfurl + response = await webhook.send( + text="", + unfurl_links=True, + unfurl_media=True, + ) + self.assertEqual(200, response.status_code) + self.assertEqual("ok", response.body) + # wait to allow Slack API to edit message with attachments + time.sleep(2) + history = await client.conversations_history(channel=self.channel_id, limit=1) + self.assertIsNotNone(history) + self.assertTrue("attachments" in history["messages"][0]) + @async_test async def test_with_blocks(self): url = os.environ[SLACK_SDK_TEST_INCOMING_WEBHOOK_URL] diff --git a/integration_tests/webhook/test_webhook.py b/integration_tests/webhook/test_webhook.py index 19e2f071a..2b4d0cbd4 100644 --- a/integration_tests/webhook/test_webhook.py +++ b/integration_tests/webhook/test_webhook.py @@ -31,7 +31,6 @@ def setUp(self): break if self.channel_id is not None: break - return self.channel_id def tearDown(self): pass From da137801a1f658ee1d89453dc53ac5acc19eaed2 Mon Sep 17 00:00:00 2001 From: Sarah Jiang Date: Mon, 28 Jun 2021 13:11:08 -0700 Subject: [PATCH 13/16] Use async test case class --- integration_tests/webhook/test_async_webhook.py | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/integration_tests/webhook/test_async_webhook.py b/integration_tests/webhook/test_async_webhook.py index e81c96b44..19b6789e2 100644 --- a/integration_tests/webhook/test_async_webhook.py +++ b/integration_tests/webhook/test_async_webhook.py @@ -7,7 +7,6 @@ SLACK_SDK_TEST_INCOMING_WEBHOOK_CHANNEL_NAME, SLACK_SDK_TEST_BOT_TOKEN, ) -from integration_tests.helpers import async_test from slack_sdk.web.async_client import AsyncWebClient from slack_sdk.webhook.async_client import AsyncWebhookClient from slack_sdk.models.attachments import Attachment, AttachmentField @@ -16,9 +15,8 @@ from slack_sdk.models.blocks.basic_components import MarkdownTextObject, PlainTextObject -class TestAsyncWebhook(unittest.TestCase): - @async_test - async def setUp(self): +class TestAsyncWebhook(unittest.IsolatedAsyncioTestCase): + async def asyncSetUp(self): if not hasattr(self, "channel_id"): token = os.environ[SLACK_SDK_TEST_BOT_TOKEN] channel_name = os.environ[ @@ -37,7 +35,6 @@ async def setUp(self): def tearDown(self): pass - @async_test async def test_webhook(self): url = os.environ[SLACK_SDK_TEST_INCOMING_WEBHOOK_URL] webhook = AsyncWebhookClient(url) @@ -52,7 +49,6 @@ async def test_webhook(self): actual_text = history["messages"][0]["text"] self.assertEqual("Hello!", actual_text) - @async_test async def test_with_unfurls_off(self): url = os.environ[SLACK_SDK_TEST_INCOMING_WEBHOOK_URL] token = os.environ[SLACK_SDK_TEST_BOT_TOKEN] @@ -72,7 +68,6 @@ async def test_with_unfurls_off(self): self.assertIsNotNone(history) self.assertTrue("attachments" not in history["messages"][0]) - @async_test async def test_with_unfurls_on(self): # Slack API rate limits unfurls of unique links so test will # fail when repeated. For testing, either use a different URL @@ -95,7 +90,6 @@ async def test_with_unfurls_on(self): self.assertIsNotNone(history) self.assertTrue("attachments" in history["messages"][0]) - @async_test async def test_with_blocks(self): url = os.environ[SLACK_SDK_TEST_INCOMING_WEBHOOK_URL] webhook = AsyncWebhookClient(url) @@ -136,7 +130,6 @@ async def test_with_blocks(self): self.assertEqual(200, response.status_code) self.assertEqual("ok", response.body) - @async_test async def test_with_blocks_dict(self): url = os.environ[SLACK_SDK_TEST_INCOMING_WEBHOOK_URL] webhook = AsyncWebhookClient(url) @@ -205,7 +198,6 @@ async def test_with_blocks_dict(self): self.assertEqual(200, response.status_code) self.assertEqual("ok", response.body) - @async_test async def test_with_attachments(self): url = os.environ[SLACK_SDK_TEST_INCOMING_WEBHOOK_URL] webhook = AsyncWebhookClient(url) @@ -239,7 +231,6 @@ async def test_with_attachments(self): self.assertEqual(200, response.status_code) self.assertEqual("ok", response.body) - @async_test async def test_with_attachments_dict(self): url = os.environ[SLACK_SDK_TEST_INCOMING_WEBHOOK_URL] webhook = AsyncWebhookClient(url) From 693b27bbceed6546116399d715d80ffbb34d2903 Mon Sep 17 00:00:00 2001 From: Sarah Jiang Date: Mon, 28 Jun 2021 13:27:03 -0700 Subject: [PATCH 14/16] Add unit tests --- tests/webhook/test_async_webhook.py | 22 +++++++++++----------- tests/webhook/test_webhook.py | 10 ++++++++++ 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/tests/webhook/test_async_webhook.py b/tests/webhook/test_async_webhook.py index 4d1368d2b..a4ac0677e 100644 --- a/tests/webhook/test_async_webhook.py +++ b/tests/webhook/test_async_webhook.py @@ -1,8 +1,5 @@ -import asyncio import unittest -import aiohttp - from slack.web.classes.attachments import Attachment, AttachmentField from slack.web.classes.blocks import SectionBlock, ImageBlock from slack.webhook import AsyncWebhookClient, WebhookResponse @@ -13,14 +10,13 @@ ) -class TestAsyncWebhook(unittest.TestCase): +class TestAsyncWebhook(unittest.IsolatedAsyncioTestCase): def setUp(self): setup_mock_web_api_server(self) def tearDown(self): cleanup_mock_web_api_server(self) - @async_test async def test_send(self): client = AsyncWebhookClient("http://localhost:8888") @@ -31,7 +27,16 @@ async def test_send(self): resp = await client.send(text="hello!", response_type="in_channel") self.assertEqual("ok", resp.body) - @async_test + async def test_send_with_url_unfurl_opts_issue_1045(self): + client = AsyncWebhookClient("http://localhost:8888") + resp: WebhookResponse = await client.send( + text="", + unfurl_links=False, + unfurl_media=False, + ) + self.assertEqual(200, resp.status_code) + self.assertEqual("ok", resp.body) + async def test_send_blocks(self): client = AsyncWebhookClient("http://localhost:8888") @@ -83,7 +88,6 @@ async def test_send_blocks(self): ) self.assertEqual("ok", resp.body) - @async_test async def test_send_attachments(self): client = AsyncWebhookClient("http://localhost:8888") @@ -153,20 +157,17 @@ async def test_send_attachments(self): ) self.assertEqual("ok", resp.body) - @async_test async def test_send_dict(self): client = AsyncWebhookClient("http://localhost:8888") resp: WebhookResponse = await client.send_dict({"text": "hello!"}) self.assertEqual(200, resp.status_code) self.assertEqual("ok", resp.body) - @async_test async def test_timeout_issue_712(self): client = AsyncWebhookClient(url="http://localhost:8888/timeout", timeout=1) with self.assertRaises(Exception): await client.send_dict({"text": "hello!"}) - @async_test async def test_proxy_issue_714(self): client = AsyncWebhookClient( url="http://localhost:8888", proxy="http://invalid-host:9999" @@ -174,7 +175,6 @@ async def test_proxy_issue_714(self): with self.assertRaises(Exception): await client.send_dict({"text": "hello!"}) - @async_test async def test_user_agent_customization_issue_769(self): client = AsyncWebhookClient( url="http://localhost:8888/user-agent-this_is-test", diff --git a/tests/webhook/test_webhook.py b/tests/webhook/test_webhook.py index efcfa6fca..b54485904 100644 --- a/tests/webhook/test_webhook.py +++ b/tests/webhook/test_webhook.py @@ -28,6 +28,16 @@ def test_send(self): resp = client.send(text="hello!", response_type="in_channel") self.assertEqual("ok", resp.body) + def test_send_with_url_unfurl_opts_issue_1045(self): + client = WebhookClient("http://localhost:8888") + resp: WebhookResponse = client.send( + text="", + unfurl_links=False, + unfurl_media=False, + ) + self.assertEqual(200, resp.status_code) + self.assertEqual("ok", resp.body) + def test_send_blocks(self): client = WebhookClient("http://localhost:8888") From 784bee9b7eba8ca998959aef74661f65f81ad578 Mon Sep 17 00:00:00 2001 From: Sarah Jiang Date: Mon, 28 Jun 2021 13:27:51 -0700 Subject: [PATCH 15/16] Remove dep --- tests/webhook/test_async_webhook.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/webhook/test_async_webhook.py b/tests/webhook/test_async_webhook.py index a4ac0677e..138377728 100644 --- a/tests/webhook/test_async_webhook.py +++ b/tests/webhook/test_async_webhook.py @@ -3,7 +3,6 @@ from slack.web.classes.attachments import Attachment, AttachmentField from slack.web.classes.blocks import SectionBlock, ImageBlock from slack.webhook import AsyncWebhookClient, WebhookResponse -from tests.helpers import async_test from tests.webhook.mock_web_api_server import ( cleanup_mock_web_api_server, setup_mock_web_api_server, From d410e8d230619e1511369b1dacf9ab330a4915aa Mon Sep 17 00:00:00 2001 From: Sarah Jiang Date: Mon, 28 Jun 2021 14:03:49 -0700 Subject: [PATCH 16/16] Remove async class --- integration_tests/webhook/test_async_webhook.py | 13 +++++++++++-- tests/webhook/test_async_webhook.py | 11 ++++++++++- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/integration_tests/webhook/test_async_webhook.py b/integration_tests/webhook/test_async_webhook.py index 19b6789e2..09aa2e882 100644 --- a/integration_tests/webhook/test_async_webhook.py +++ b/integration_tests/webhook/test_async_webhook.py @@ -1,4 +1,5 @@ import os +from tests.helpers import async_test import unittest import time @@ -15,8 +16,9 @@ from slack_sdk.models.blocks.basic_components import MarkdownTextObject, PlainTextObject -class TestAsyncWebhook(unittest.IsolatedAsyncioTestCase): - async def asyncSetUp(self): +class TestAsyncWebhook(unittest.TestCase): + @async_test + async def setUp(self): if not hasattr(self, "channel_id"): token = os.environ[SLACK_SDK_TEST_BOT_TOKEN] channel_name = os.environ[ @@ -35,6 +37,7 @@ async def asyncSetUp(self): def tearDown(self): pass + @async_test async def test_webhook(self): url = os.environ[SLACK_SDK_TEST_INCOMING_WEBHOOK_URL] webhook = AsyncWebhookClient(url) @@ -49,6 +52,7 @@ async def test_webhook(self): actual_text = history["messages"][0]["text"] self.assertEqual("Hello!", actual_text) + @async_test async def test_with_unfurls_off(self): url = os.environ[SLACK_SDK_TEST_INCOMING_WEBHOOK_URL] token = os.environ[SLACK_SDK_TEST_BOT_TOKEN] @@ -68,6 +72,7 @@ async def test_with_unfurls_off(self): self.assertIsNotNone(history) self.assertTrue("attachments" not in history["messages"][0]) + @async_test async def test_with_unfurls_on(self): # Slack API rate limits unfurls of unique links so test will # fail when repeated. For testing, either use a different URL @@ -90,6 +95,7 @@ async def test_with_unfurls_on(self): self.assertIsNotNone(history) self.assertTrue("attachments" in history["messages"][0]) + @async_test async def test_with_blocks(self): url = os.environ[SLACK_SDK_TEST_INCOMING_WEBHOOK_URL] webhook = AsyncWebhookClient(url) @@ -130,6 +136,7 @@ async def test_with_blocks(self): self.assertEqual(200, response.status_code) self.assertEqual("ok", response.body) + @async_test async def test_with_blocks_dict(self): url = os.environ[SLACK_SDK_TEST_INCOMING_WEBHOOK_URL] webhook = AsyncWebhookClient(url) @@ -198,6 +205,7 @@ async def test_with_blocks_dict(self): self.assertEqual(200, response.status_code) self.assertEqual("ok", response.body) + @async_test async def test_with_attachments(self): url = os.environ[SLACK_SDK_TEST_INCOMING_WEBHOOK_URL] webhook = AsyncWebhookClient(url) @@ -231,6 +239,7 @@ async def test_with_attachments(self): self.assertEqual(200, response.status_code) self.assertEqual("ok", response.body) + @async_test async def test_with_attachments_dict(self): url = os.environ[SLACK_SDK_TEST_INCOMING_WEBHOOK_URL] webhook = AsyncWebhookClient(url) diff --git a/tests/webhook/test_async_webhook.py b/tests/webhook/test_async_webhook.py index 138377728..9ec27f6f0 100644 --- a/tests/webhook/test_async_webhook.py +++ b/tests/webhook/test_async_webhook.py @@ -1,3 +1,4 @@ +from tests.helpers import async_test import unittest from slack.web.classes.attachments import Attachment, AttachmentField @@ -9,13 +10,14 @@ ) -class TestAsyncWebhook(unittest.IsolatedAsyncioTestCase): +class TestAsyncWebhook(unittest.TestCase): def setUp(self): setup_mock_web_api_server(self) def tearDown(self): cleanup_mock_web_api_server(self) + @async_test async def test_send(self): client = AsyncWebhookClient("http://localhost:8888") @@ -26,6 +28,7 @@ async def test_send(self): resp = await client.send(text="hello!", response_type="in_channel") self.assertEqual("ok", resp.body) + @async_test async def test_send_with_url_unfurl_opts_issue_1045(self): client = AsyncWebhookClient("http://localhost:8888") resp: WebhookResponse = await client.send( @@ -36,6 +39,7 @@ async def test_send_with_url_unfurl_opts_issue_1045(self): self.assertEqual(200, resp.status_code) self.assertEqual("ok", resp.body) + @async_test async def test_send_blocks(self): client = AsyncWebhookClient("http://localhost:8888") @@ -87,6 +91,7 @@ async def test_send_blocks(self): ) self.assertEqual("ok", resp.body) + @async_test async def test_send_attachments(self): client = AsyncWebhookClient("http://localhost:8888") @@ -156,17 +161,20 @@ async def test_send_attachments(self): ) self.assertEqual("ok", resp.body) + @async_test async def test_send_dict(self): client = AsyncWebhookClient("http://localhost:8888") resp: WebhookResponse = await client.send_dict({"text": "hello!"}) self.assertEqual(200, resp.status_code) self.assertEqual("ok", resp.body) + @async_test async def test_timeout_issue_712(self): client = AsyncWebhookClient(url="http://localhost:8888/timeout", timeout=1) with self.assertRaises(Exception): await client.send_dict({"text": "hello!"}) + @async_test async def test_proxy_issue_714(self): client = AsyncWebhookClient( url="http://localhost:8888", proxy="http://invalid-host:9999" @@ -174,6 +182,7 @@ async def test_proxy_issue_714(self): with self.assertRaises(Exception): await client.send_dict({"text": "hello!"}) + @async_test async def test_user_agent_customization_issue_769(self): client = AsyncWebhookClient( url="http://localhost:8888/user-agent-this_is-test",