Skip to content

Commit b2364d2

Browse files
authored
Add Slack connect API support + tests (#1089)
1 parent cbafdd1 commit b2364d2

File tree

6 files changed

+571
-79
lines changed

6 files changed

+571
-79
lines changed

integration_tests/env_variable_names.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,14 @@
3535
SLACK_SDK_TEST_INCOMING_WEBHOOK_CHANNEL_NAME = (
3636
"SLACK_SDK_TEST_INCOMING_WEBHOOK_CHANNEL_NAME"
3737
)
38+
39+
# For Slack Connect shared tests
40+
SLACK_SDK_TEST_CONNECT_INVITE_SENDER_BOT_TOKEN = (
41+
"SLACK_SDK_TEST_CONNECT_INVITE_SENDER_BOT_TOKEN"
42+
)
43+
SLACK_SDK_TEST_CONNECT_INVITE_RECEIVER_BOT_TOKEN = (
44+
"SLACK_SDK_TEST_CONNECT_INVITE_RECEIVER_BOT_TOKEN"
45+
)
46+
SLACK_SDK_TEST_CONNECT_INVITE_RECEIVER_BOT_USER_ID = (
47+
"SLACK_SDK_TEST_CONNECT_INVITE_RECEIVER_BOT_USER_ID"
48+
)
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
import logging
2+
import os
3+
import time
4+
from typing import Optional
5+
import unittest
6+
7+
from slack_sdk.web.slack_response import SlackResponse
8+
from slack_sdk.errors import SlackApiError
9+
from integration_tests.env_variable_names import (
10+
SLACK_SDK_TEST_CONNECT_INVITE_SENDER_BOT_TOKEN,
11+
SLACK_SDK_TEST_CONNECT_INVITE_RECEIVER_BOT_TOKEN,
12+
SLACK_SDK_TEST_CONNECT_INVITE_RECEIVER_BOT_USER_ID,
13+
)
14+
from integration_tests.helpers import async_test
15+
from slack_sdk.web import WebClient
16+
from slack_sdk.web.async_client import AsyncWebClient
17+
18+
19+
class TestWebClient(unittest.TestCase):
20+
"""Runs integration tests with Slack API for conversations.* endpoints
21+
To run, we use two workspace-level bot tokens,
22+
one for the inviting workspace(list and send invites) another for the recipient
23+
workspace (accept and approve) sent invites. Before being able to run this test suite,
24+
we also need to have manually created a slack connect shared channel and added
25+
these two bots as members first. See: https://api.slack.com/apis/connect
26+
27+
In addition to conversations.connect:* scopes, your sender bot token should have channels:manage scopes.
28+
"""
29+
30+
def setUp(self):
31+
self.logger = logging.getLogger(__name__)
32+
self.sender_bot_token = os.environ[
33+
SLACK_SDK_TEST_CONNECT_INVITE_SENDER_BOT_TOKEN
34+
]
35+
self.receiver_bot_token = os.environ[
36+
SLACK_SDK_TEST_CONNECT_INVITE_RECEIVER_BOT_TOKEN
37+
]
38+
self.sender_sync_client: WebClient = WebClient(token=self.sender_bot_token)
39+
self.sender_async_client: AsyncWebClient = AsyncWebClient(
40+
token=self.sender_bot_token
41+
)
42+
self.receiver_sync_client: WebClient = WebClient(token=self.receiver_bot_token)
43+
self.receiver_async_client: AsyncWebClient = AsyncWebClient(
44+
token=self.receiver_bot_token
45+
)
46+
47+
def tearDown(self):
48+
pass
49+
50+
def test_sync(self):
51+
sender = self.sender_sync_client
52+
receiver = self.receiver_sync_client
53+
channel_id: Optional[str] = None
54+
55+
try:
56+
# list senders pending connect invites
57+
connect_invites: SlackResponse = sender.conversations_listConnectInvites()
58+
self.assertIsNotNone(connect_invites["invites"])
59+
60+
# creates channel in sender workspace to share
61+
unique_channel_name = str(int(time.time())) + "-shared"
62+
new_channel: SlackResponse = sender.conversations_create(
63+
name=unique_channel_name
64+
)
65+
self.assertIsNotNone(new_channel["channel"])
66+
self.assertIsNotNone(new_channel["channel"]["id"])
67+
channel_id = new_channel["channel"]["id"]
68+
69+
# send an invite for sender's intended shared channel to receiver's bot user id
70+
invite: SlackResponse = sender.conversations_inviteShared(
71+
channel=new_channel["channel"]["id"],
72+
user_ids=os.environ[SLACK_SDK_TEST_CONNECT_INVITE_RECEIVER_BOT_USER_ID],
73+
)
74+
self.assertIsNotNone(invite["invite_id"])
75+
76+
# reciever accept conversations invite via invite id
77+
accepted: SlackResponse = receiver.conversations_acceptSharedInvite(
78+
channel_name=unique_channel_name,
79+
invite_id=invite["invite_id"],
80+
)
81+
self.assertIsNone(accepted["error"])
82+
83+
# receiver attempt to approve invite already accepted by an admin level token should fail
84+
self.assertRaises(
85+
SlackApiError,
86+
receiver.conversations_approveSharedInvite,
87+
invite_id=invite["invite_id"],
88+
)
89+
finally:
90+
if channel_id is not None:
91+
# clean up created channel
92+
delete_channel: SlackResponse = sender.conversations_archive(
93+
channel=new_channel["channel"]["id"]
94+
)
95+
self.assertIsNotNone(delete_channel)
96+
97+
@async_test
98+
async def test_async(self):
99+
sender = self.sender_async_client
100+
receiver = self.receiver_async_client
101+
channel_id: Optional[str] = None
102+
103+
try:
104+
# list senders pending connect invites
105+
connect_invites: SlackResponse = (
106+
await sender.conversations_listConnectInvites()
107+
)
108+
self.assertIsNotNone(connect_invites["invites"])
109+
110+
# creates channel in sender workspace to share
111+
unique_channel_name = str(int(time.time())) + "-shared"
112+
new_channel: SlackResponse = await sender.conversations_create(
113+
name=unique_channel_name
114+
)
115+
self.assertIsNotNone(new_channel["channel"])
116+
self.assertIsNotNone(new_channel["channel"]["id"])
117+
channel_id = new_channel["channel"]["id"]
118+
119+
# send an invite for sender's intended shared channel to receiver's bot user id
120+
invite: SlackResponse = await sender.conversations_inviteShared(
121+
channel=new_channel["channel"]["id"],
122+
user_ids=os.environ[SLACK_SDK_TEST_CONNECT_INVITE_RECEIVER_BOT_USER_ID],
123+
)
124+
self.assertIsNotNone(invite["invite_id"])
125+
126+
# reciever accept conversations invite via invite id
127+
accepted: SlackResponse = await receiver.conversations_acceptSharedInvite(
128+
channel_name=unique_channel_name,
129+
invite_id=invite["invite_id"],
130+
)
131+
self.assertIsNone(accepted["error"])
132+
133+
# receiver attempt to approve invite already accepted by an admin level token should fail
134+
with self.assertRaises(SlackApiError):
135+
await receiver.conversations_approveSharedInvite(
136+
invite_id=invite["invite_id"]
137+
)
138+
finally:
139+
if channel_id is not None:
140+
# clean up created channel
141+
delete_channel: SlackResponse = await sender.conversations_archive(
142+
channel=new_channel["channel"]["id"]
143+
)
144+
self.assertIsNotNone(delete_channel)

0 commit comments

Comments
 (0)