Skip to content

Commit eb89c44

Browse files
committed
Add more tests & apply black to test code
1 parent ed80f3e commit eb89c44

27 files changed

Lines changed: 1036 additions & 329 deletions

scripts/run_tests.sh

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#!/bin/bash
2+
# Run all the tests or a single test
3+
# all: ./scripts/run_tests.sh
4+
# single: ./scripts/run_tests.sh tests/scenario_tests/test_app.py
5+
6+
script_dir=`dirname $0`
7+
cd ${script_dir}/..
8+
9+
python setup.py install && \
10+
pip install "black==19.10b0" && \
11+
black slack_bolt/ tests/ && \
12+
pytest $1

slack_bolt/adapter/aws_lambda/lambda_s3_oauth_flow.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
from slack_sdk.oauth.installation_store.amazon_s3 import AmazonS3InstallationStore
1111
from slack_sdk.oauth.state_store.amazon_s3 import AmazonS3OAuthStateStore
1212

13+
from slack_bolt.util.utils import create_web_client
14+
1315

1416
class LambdaS3OAuthFlow(OAuthFlow):
1517
def __init__(
@@ -69,7 +71,7 @@ def __init__(
6971
@property
7072
def client(self) -> WebClient:
7173
if self._client is None:
72-
self._client = WebClient()
74+
self._client = create_web_client()
7375
return self._client
7476

7577
@property

slack_bolt/app/app.py

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@
77
from http.server import SimpleHTTPRequestHandler, HTTPServer
88
from typing import List, Union, Pattern, Callable, Dict, Optional
99

10+
from slack_sdk.oauth import OAuthStateUtils
11+
from slack_sdk.oauth.installation_store import InstallationStore, FileInstallationStore
12+
from slack_sdk.oauth.state_store import OAuthStateStore, FileOAuthStateStore
13+
from slack_sdk.web import WebClient
14+
15+
from slack_bolt.error import BoltError
1016
from slack_bolt.listener.custom_listener import CustomListener
1117
from slack_bolt.listener.listener import Listener
1218
from slack_bolt.listener_matcher import CustomListenerMatcher
@@ -26,10 +32,7 @@
2632
from slack_bolt.oauth import OAuthFlow
2733
from slack_bolt.request import BoltRequest
2834
from slack_bolt.response import BoltResponse
29-
from slack_sdk.oauth import OAuthStateUtils
30-
from slack_sdk.oauth.installation_store import InstallationStore, FileInstallationStore
31-
from slack_sdk.oauth.state_store import OAuthStateStore, FileOAuthStateStore
32-
from slack_sdk.web import WebClient
35+
from slack_bolt.util.utils import create_web_client
3336

3437

3538
class App:
@@ -41,9 +44,9 @@ def __init__(
4144
# Set True when you run this app on a FaaS platform
4245
process_before_response: bool = False,
4346
# Basic Information > Credentials > Signing Secret
44-
signing_secret: str = os.environ.get("SLACK_SIGNING_SECRET", None),
47+
signing_secret: Optional[str] = None,
4548
# for single-workspace apps
46-
token: Optional[str] = os.environ.get("SLACK_BOT_TOKEN", None),
49+
token: Optional[str] = None,
4750
client: Optional[WebClient] = None,
4851
# for multi-workspace apps
4952
installation_store: Optional[InstallationStore] = None,
@@ -65,6 +68,14 @@ def __init__(
6568
# No need to set (the value is used only in response to ssl_check requests)
6669
verification_token: Optional[str] = None,
6770
):
71+
signing_secret = signing_secret or os.environ.get("SLACK_SIGNING_SECRET", None)
72+
token = token or os.environ.get("SLACK_BOT_TOKEN", None)
73+
74+
if signing_secret is None or signing_secret == "":
75+
raise BoltError(
76+
"Signing secret not found, so could not initialize the Bolt app."
77+
)
78+
6879
self._name: str = name or inspect.stack()[1].filename.split(os.path.sep)[-1]
6980
self._signing_secret: str = signing_secret
7081

@@ -95,7 +106,7 @@ def __init__(
95106
"As you gave client as well, the bot token will be unused."
96107
)
97108
else:
98-
self._client = WebClient(token=token) # NOTE: the token here can be None
109+
self._client = create_web_client(token) # NOTE: the token here can be None
99110

100111
self._installation_store: Optional[InstallationStore] = installation_store
101112
self._oauth_state_store: Optional[OAuthStateStore] = oauth_state_store
@@ -135,7 +146,7 @@ def __init__(
135146
)
136147

137148
self._oauth_flow = OAuthFlow(
138-
client=WebClient(token=None),
149+
client=create_web_client(),
139150
logger=self._framework_logger,
140151
# required storage implementations
141152
installation_store=self._installation_store,
@@ -178,8 +189,14 @@ def _init_middleware_list(self):
178189
SslCheck(verification_token=self._verification_token)
179190
)
180191
self._middleware_list.append(RequestVerification(self._signing_secret))
181-
if self._oauth_flow is None and self._token:
182-
self._middleware_list.append(SingleTeamAuthorization())
192+
193+
if self._oauth_flow is None:
194+
if self._token:
195+
self._middleware_list.append(SingleTeamAuthorization())
196+
else:
197+
raise BoltError(
198+
"OAuthFlow not found, so could not initialize the Bolt app."
199+
)
183200
else:
184201
self._middleware_list.append(
185202
MultiTeamsAuthorization(

slack_bolt/app/async_app.py

Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,16 @@
66
from asyncio import Future
77
from typing import Optional, List, Union, Callable, Pattern, Dict, Awaitable
88

9+
from slack_sdk.oauth import OAuthStateUtils
10+
from slack_sdk.oauth.installation_store import FileInstallationStore
11+
from slack_sdk.oauth.installation_store.async_installation_store import (
12+
AsyncInstallationStore,
13+
)
14+
from slack_sdk.oauth.state_store import FileOAuthStateStore
15+
from slack_sdk.oauth.state_store.async_state_store import AsyncOAuthStateStore
16+
from slack_sdk.web.async_client import AsyncWebClient
17+
18+
from slack_bolt.error import BoltError
919
from slack_bolt.listener.async_listener import AsyncListener, AsyncCustomListener
1020
from slack_bolt.listener_matcher import builtins as builtin_matchers
1121
from slack_bolt.listener_matcher.async_listener_matcher import (
@@ -32,14 +42,7 @@
3242
from slack_bolt.oauth.async_oauth_flow import AsyncOAuthFlow
3343
from slack_bolt.request.async_request import AsyncBoltRequest
3444
from slack_bolt.response import BoltResponse
35-
from slack_sdk.oauth import OAuthStateUtils
36-
from slack_sdk.oauth.installation_store import FileInstallationStore
37-
from slack_sdk.oauth.installation_store.async_installation_store import (
38-
AsyncInstallationStore,
39-
)
40-
from slack_sdk.oauth.state_store import FileOAuthStateStore
41-
from slack_sdk.oauth.state_store.async_state_store import AsyncOAuthStateStore
42-
from slack_sdk.web.async_client import AsyncWebClient
45+
from slack_bolt.util.async_utils import create_async_web_client
4346

4447

4548
class AsyncApp:
@@ -51,9 +54,9 @@ def __init__(
5154
# Set True when you run this app on a FaaS platform
5255
process_before_response: bool = False,
5356
# Basic Information > Credentials > Signing Secret
54-
signing_secret: str = os.environ.get("SLACK_SIGNING_SECRET", None),
57+
signing_secret: Optional[str] = None,
5558
# for single-workspace apps
56-
token: Optional[str] = os.environ.get("SLACK_BOT_TOKEN", None),
59+
token: Optional[str] = None,
5760
client: Optional[AsyncWebClient] = None,
5861
# for multi-workspace apps
5962
installation_store: Optional[AsyncInstallationStore] = None,
@@ -74,6 +77,14 @@ def __init__(
7477
# No need to set (the value is used only in response to ssl_check requests)
7578
verification_token: Optional[str] = None,
7679
):
80+
signing_secret = signing_secret or os.environ.get("SLACK_SIGNING_SECRET", None)
81+
token = token or os.environ.get("SLACK_BOT_TOKEN", None)
82+
83+
if signing_secret is None or signing_secret == "":
84+
raise BoltError(
85+
"Signing secret not found, so could not initialize the Bolt app."
86+
)
87+
7788
self._name: str = name or inspect.stack()[1].filename.split(os.path.sep)[-1]
7889
self._signing_secret: str = signing_secret
7990

@@ -104,9 +115,8 @@ def __init__(
104115
"As you gave client as well, the bot token will be unused."
105116
)
106117
else:
107-
self._async_client = AsyncWebClient(
108-
token=token
109-
) # NOTE: the token here can be None
118+
# NOTE: the token here can be None
119+
self._async_client = create_async_web_client(token)
110120

111121
self._async_installation_store: Optional[
112122
AsyncInstallationStore
@@ -154,7 +164,7 @@ def __init__(
154164
)
155165

156166
self._async_oauth_flow = AsyncOAuthFlow(
157-
client=AsyncWebClient(token=None),
167+
client=create_async_web_client(),
158168
logger=self._framework_logger,
159169
# required storage implementations
160170
installation_store=self._async_installation_store,
@@ -198,12 +208,18 @@ def _init_async_middleware_list(self):
198208
self._async_middleware_list.append(
199209
AsyncRequestVerification(self._signing_secret)
200210
)
201-
if self._async_oauth_flow is None and self._token:
202-
self._async_middleware_list.append(AsyncSingleTeamAuthorization())
211+
if self._async_oauth_flow is None:
212+
if self._token:
213+
self._async_middleware_list.append(AsyncSingleTeamAuthorization())
214+
else:
215+
raise BoltError(
216+
"AsyncOAuthFlow not found, so could not initialize the Bolt app."
217+
)
203218
else:
204219
self._async_middleware_list.append(
205220
AsyncMultiTeamsAuthorization(self._async_installation_store)
206221
)
222+
207223
self._async_middleware_list.append(AsyncIgnoringSelfEvents())
208224
self._async_middleware_list.append(AsyncUrlVerification())
209225
self._init_middleware_list_done = True
@@ -557,6 +573,12 @@ def _register_listener(
557573
auto_acknowledgement: bool = False,
558574
) -> Callable[..., None]:
559575

576+
if not inspect.iscoroutinefunction(func):
577+
name = func.__name__
578+
raise BoltError(
579+
f"The listener function ({name}) is not a coroutine function."
580+
)
581+
560582
listener_matchers = [
561583
AsyncCustomListenerMatcher(app_name=self.name, func=f)
562584
for f in (matchers or [])

slack_bolt/listener_matcher/builtins.py

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import inspect
22
import sys
33

4+
from ..error import BoltError
5+
46
if sys.version_info.major == 3 and sys.version_info.minor <= 6:
57
from re import _pattern_type as Pattern
68
else:
@@ -89,7 +91,7 @@ def func(payload: dict) -> bool:
8991

9092
return build_listener_matcher(func, asyncio)
9193

92-
raise ValueError(
94+
raise BoltError(
9395
f"event ({constraints}: {type(constraints)}) must be any of str, Pattern, and dict"
9496
)
9597

@@ -135,7 +137,7 @@ def func(payload: dict) -> bool:
135137
elif constraints["type"] == "message_action":
136138
return message_shortcut(constraints["callback_id"], asyncio)
137139

138-
raise ValueError(
140+
raise BoltError(
139141
f"shortcut ({constraints}: {type(constraints)}) must be any of str, Pattern, and dict"
140142
)
141143

@@ -179,10 +181,13 @@ def action(
179181
if isinstance(constraints, (str, Pattern)):
180182
return block_action(constraints, asyncio)
181183
elif "type" in constraints:
182-
if constraints["type"] == "block_actions":
184+
action_type = constraints["type"]
185+
if action_type == "block_actions":
183186
return block_action(constraints["action_id"], asyncio)
187+
else:
188+
raise BoltError(f"type: {action_type} is unsupported")
184189

185-
raise ValueError(
190+
raise BoltError(
186191
f"action ({constraints}: {type(constraints)}) must be any of str, Pattern, and dict"
187192
)
188193

@@ -215,7 +220,7 @@ def view(
215220
if constraints["type"] == "view_submission":
216221
return view_submission(constraints["callback_id"], asyncio)
217222

218-
raise ValueError(
223+
raise BoltError(
219224
f"view ({constraints}: {type(constraints)}) must be any of str, Pattern, and dict"
220225
)
221226

@@ -250,7 +255,7 @@ def options(
250255
elif "callback_id" in constraints:
251256
return dialog_suggestion(constraints["callback_id"], asyncio)
252257
else:
253-
raise ValueError(
258+
raise BoltError(
254259
f"options ({constraints}: {type(constraints)}) must be any of str, Pattern, and dict"
255260
)
256261

@@ -310,6 +315,6 @@ def _matches(str_or_pattern: Union[str, Pattern], input: Optional[str]) -> bool:
310315
pattern: Pattern = str_or_pattern
311316
return pattern.search(input)
312317
else:
313-
raise ValueError(
318+
raise BoltError(
314319
f"{str_or_pattern} ({type(str_or_pattern)}) must be either str or Pattern"
315320
)

slack_bolt/oauth/async_oauth_flow.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
from slack_sdk.web.async_client import AsyncWebClient
2323
from slack_sdk.web.async_slack_response import AsyncSlackResponse
2424

25+
from slack_bolt.util.async_utils import create_async_web_client
26+
2527

2628
class AsyncOAuthFlow:
2729
installation_store: AsyncInstallationStore
@@ -46,7 +48,7 @@ class AsyncOAuthFlow:
4648
@property
4749
def client(self) -> AsyncWebClient:
4850
if self._async_client is None:
49-
self._async_client = AsyncWebClient()
51+
self._async_client = create_async_web_client()
5052
return self._async_client
5153

5254
@property
@@ -133,7 +135,7 @@ def sqlite3(
133135
) -> "AsyncOAuthFlow":
134136

135137
return AsyncOAuthFlow(
136-
client=AsyncWebClient(),
138+
client=create_async_web_client(),
137139
logger=logger,
138140
installation_store=SQLite3InstallationStore(
139141
database=database, client_id=client_id, logger=logger,

slack_bolt/util/__init__.py

Whitespace-only changes.

slack_bolt/util/async_utils.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from typing import Optional
2+
3+
from slack_sdk.web.async_client import AsyncWebClient
4+
5+
6+
def create_async_web_client(token: Optional[str] = None) -> AsyncWebClient:
7+
# TODO: add bolt info to user-agent
8+
return AsyncWebClient(token=token)

slack_bolt/util/utils.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from typing import Optional
2+
3+
from slack_sdk import WebClient
4+
5+
6+
def create_web_client(token: Optional[str] = None) -> WebClient:
7+
# TODO: add bolt info to user-agent
8+
return WebClient(token=token)

0 commit comments

Comments
 (0)