Skip to content

Commit

Permalink
Add more tests & apply black to test code
Browse files Browse the repository at this point in the history
  • Loading branch information
seratch committed Aug 4, 2020
1 parent ed80f3e commit eb89c44
Show file tree
Hide file tree
Showing 27 changed files with 1,036 additions and 329 deletions.
12 changes: 12 additions & 0 deletions scripts/run_tests.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/bin/bash
# Run all the tests or a single test
# all: ./scripts/run_tests.sh
# single: ./scripts/run_tests.sh tests/scenario_tests/test_app.py

script_dir=`dirname $0`
cd ${script_dir}/..

python setup.py install && \
pip install "black==19.10b0" && \
black slack_bolt/ tests/ && \
pytest $1
4 changes: 3 additions & 1 deletion slack_bolt/adapter/aws_lambda/lambda_s3_oauth_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
from slack_sdk.oauth.installation_store.amazon_s3 import AmazonS3InstallationStore
from slack_sdk.oauth.state_store.amazon_s3 import AmazonS3OAuthStateStore

from slack_bolt.util.utils import create_web_client


class LambdaS3OAuthFlow(OAuthFlow):
def __init__(
Expand Down Expand Up @@ -69,7 +71,7 @@ def __init__(
@property
def client(self) -> WebClient:
if self._client is None:
self._client = WebClient()
self._client = create_web_client()
return self._client

@property
Expand Down
37 changes: 27 additions & 10 deletions slack_bolt/app/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
from http.server import SimpleHTTPRequestHandler, HTTPServer
from typing import List, Union, Pattern, Callable, Dict, Optional

from slack_sdk.oauth import OAuthStateUtils
from slack_sdk.oauth.installation_store import InstallationStore, FileInstallationStore
from slack_sdk.oauth.state_store import OAuthStateStore, FileOAuthStateStore
from slack_sdk.web import WebClient

from slack_bolt.error import BoltError
from slack_bolt.listener.custom_listener import CustomListener
from slack_bolt.listener.listener import Listener
from slack_bolt.listener_matcher import CustomListenerMatcher
Expand All @@ -26,10 +32,7 @@
from slack_bolt.oauth import OAuthFlow
from slack_bolt.request import BoltRequest
from slack_bolt.response import BoltResponse
from slack_sdk.oauth import OAuthStateUtils
from slack_sdk.oauth.installation_store import InstallationStore, FileInstallationStore
from slack_sdk.oauth.state_store import OAuthStateStore, FileOAuthStateStore
from slack_sdk.web import WebClient
from slack_bolt.util.utils import create_web_client


class App:
Expand All @@ -41,9 +44,9 @@ def __init__(
# Set True when you run this app on a FaaS platform
process_before_response: bool = False,
# Basic Information > Credentials > Signing Secret
signing_secret: str = os.environ.get("SLACK_SIGNING_SECRET", None),
signing_secret: Optional[str] = None,
# for single-workspace apps
token: Optional[str] = os.environ.get("SLACK_BOT_TOKEN", None),
token: Optional[str] = None,
client: Optional[WebClient] = None,
# for multi-workspace apps
installation_store: Optional[InstallationStore] = None,
Expand All @@ -65,6 +68,14 @@ def __init__(
# No need to set (the value is used only in response to ssl_check requests)
verification_token: Optional[str] = None,
):
signing_secret = signing_secret or os.environ.get("SLACK_SIGNING_SECRET", None)
token = token or os.environ.get("SLACK_BOT_TOKEN", None)

if signing_secret is None or signing_secret == "":
raise BoltError(
"Signing secret not found, so could not initialize the Bolt app."
)

self._name: str = name or inspect.stack()[1].filename.split(os.path.sep)[-1]
self._signing_secret: str = signing_secret

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

self._installation_store: Optional[InstallationStore] = installation_store
self._oauth_state_store: Optional[OAuthStateStore] = oauth_state_store
Expand Down Expand Up @@ -135,7 +146,7 @@ def __init__(
)

self._oauth_flow = OAuthFlow(
client=WebClient(token=None),
client=create_web_client(),
logger=self._framework_logger,
# required storage implementations
installation_store=self._installation_store,
Expand Down Expand Up @@ -178,8 +189,14 @@ def _init_middleware_list(self):
SslCheck(verification_token=self._verification_token)
)
self._middleware_list.append(RequestVerification(self._signing_secret))
if self._oauth_flow is None and self._token:
self._middleware_list.append(SingleTeamAuthorization())

if self._oauth_flow is None:
if self._token:
self._middleware_list.append(SingleTeamAuthorization())
else:
raise BoltError(
"OAuthFlow not found, so could not initialize the Bolt app."
)
else:
self._middleware_list.append(
MultiTeamsAuthorization(
Expand Down
54 changes: 38 additions & 16 deletions slack_bolt/app/async_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@
from asyncio import Future
from typing import Optional, List, Union, Callable, Pattern, Dict, Awaitable

from slack_sdk.oauth import OAuthStateUtils
from slack_sdk.oauth.installation_store import FileInstallationStore
from slack_sdk.oauth.installation_store.async_installation_store import (
AsyncInstallationStore,
)
from slack_sdk.oauth.state_store import FileOAuthStateStore
from slack_sdk.oauth.state_store.async_state_store import AsyncOAuthStateStore
from slack_sdk.web.async_client import AsyncWebClient

from slack_bolt.error import BoltError
from slack_bolt.listener.async_listener import AsyncListener, AsyncCustomListener
from slack_bolt.listener_matcher import builtins as builtin_matchers
from slack_bolt.listener_matcher.async_listener_matcher import (
Expand All @@ -32,14 +42,7 @@
from slack_bolt.oauth.async_oauth_flow import AsyncOAuthFlow
from slack_bolt.request.async_request import AsyncBoltRequest
from slack_bolt.response import BoltResponse
from slack_sdk.oauth import OAuthStateUtils
from slack_sdk.oauth.installation_store import FileInstallationStore
from slack_sdk.oauth.installation_store.async_installation_store import (
AsyncInstallationStore,
)
from slack_sdk.oauth.state_store import FileOAuthStateStore
from slack_sdk.oauth.state_store.async_state_store import AsyncOAuthStateStore
from slack_sdk.web.async_client import AsyncWebClient
from slack_bolt.util.async_utils import create_async_web_client


class AsyncApp:
Expand All @@ -51,9 +54,9 @@ def __init__(
# Set True when you run this app on a FaaS platform
process_before_response: bool = False,
# Basic Information > Credentials > Signing Secret
signing_secret: str = os.environ.get("SLACK_SIGNING_SECRET", None),
signing_secret: Optional[str] = None,
# for single-workspace apps
token: Optional[str] = os.environ.get("SLACK_BOT_TOKEN", None),
token: Optional[str] = None,
client: Optional[AsyncWebClient] = None,
# for multi-workspace apps
installation_store: Optional[AsyncInstallationStore] = None,
Expand All @@ -74,6 +77,14 @@ def __init__(
# No need to set (the value is used only in response to ssl_check requests)
verification_token: Optional[str] = None,
):
signing_secret = signing_secret or os.environ.get("SLACK_SIGNING_SECRET", None)
token = token or os.environ.get("SLACK_BOT_TOKEN", None)

if signing_secret is None or signing_secret == "":
raise BoltError(
"Signing secret not found, so could not initialize the Bolt app."
)

self._name: str = name or inspect.stack()[1].filename.split(os.path.sep)[-1]
self._signing_secret: str = signing_secret

Expand Down Expand Up @@ -104,9 +115,8 @@ def __init__(
"As you gave client as well, the bot token will be unused."
)
else:
self._async_client = AsyncWebClient(
token=token
) # NOTE: the token here can be None
# NOTE: the token here can be None
self._async_client = create_async_web_client(token)

self._async_installation_store: Optional[
AsyncInstallationStore
Expand Down Expand Up @@ -154,7 +164,7 @@ def __init__(
)

self._async_oauth_flow = AsyncOAuthFlow(
client=AsyncWebClient(token=None),
client=create_async_web_client(),
logger=self._framework_logger,
# required storage implementations
installation_store=self._async_installation_store,
Expand Down Expand Up @@ -198,12 +208,18 @@ def _init_async_middleware_list(self):
self._async_middleware_list.append(
AsyncRequestVerification(self._signing_secret)
)
if self._async_oauth_flow is None and self._token:
self._async_middleware_list.append(AsyncSingleTeamAuthorization())
if self._async_oauth_flow is None:
if self._token:
self._async_middleware_list.append(AsyncSingleTeamAuthorization())
else:
raise BoltError(
"AsyncOAuthFlow not found, so could not initialize the Bolt app."
)
else:
self._async_middleware_list.append(
AsyncMultiTeamsAuthorization(self._async_installation_store)
)

self._async_middleware_list.append(AsyncIgnoringSelfEvents())
self._async_middleware_list.append(AsyncUrlVerification())
self._init_middleware_list_done = True
Expand Down Expand Up @@ -557,6 +573,12 @@ def _register_listener(
auto_acknowledgement: bool = False,
) -> Callable[..., None]:

if not inspect.iscoroutinefunction(func):
name = func.__name__
raise BoltError(
f"The listener function ({name}) is not a coroutine function."
)

listener_matchers = [
AsyncCustomListenerMatcher(app_name=self.name, func=f)
for f in (matchers or [])
Expand Down
19 changes: 12 additions & 7 deletions slack_bolt/listener_matcher/builtins.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import inspect
import sys

from ..error import BoltError

if sys.version_info.major == 3 and sys.version_info.minor <= 6:
from re import _pattern_type as Pattern
else:
Expand Down Expand Up @@ -89,7 +91,7 @@ def func(payload: dict) -> bool:

return build_listener_matcher(func, asyncio)

raise ValueError(
raise BoltError(
f"event ({constraints}: {type(constraints)}) must be any of str, Pattern, and dict"
)

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

raise ValueError(
raise BoltError(
f"shortcut ({constraints}: {type(constraints)}) must be any of str, Pattern, and dict"
)

Expand Down Expand Up @@ -179,10 +181,13 @@ def action(
if isinstance(constraints, (str, Pattern)):
return block_action(constraints, asyncio)
elif "type" in constraints:
if constraints["type"] == "block_actions":
action_type = constraints["type"]
if action_type == "block_actions":
return block_action(constraints["action_id"], asyncio)
else:
raise BoltError(f"type: {action_type} is unsupported")

raise ValueError(
raise BoltError(
f"action ({constraints}: {type(constraints)}) must be any of str, Pattern, and dict"
)

Expand Down Expand Up @@ -215,7 +220,7 @@ def view(
if constraints["type"] == "view_submission":
return view_submission(constraints["callback_id"], asyncio)

raise ValueError(
raise BoltError(
f"view ({constraints}: {type(constraints)}) must be any of str, Pattern, and dict"
)

Expand Down Expand Up @@ -250,7 +255,7 @@ def options(
elif "callback_id" in constraints:
return dialog_suggestion(constraints["callback_id"], asyncio)
else:
raise ValueError(
raise BoltError(
f"options ({constraints}: {type(constraints)}) must be any of str, Pattern, and dict"
)

Expand Down Expand Up @@ -310,6 +315,6 @@ def _matches(str_or_pattern: Union[str, Pattern], input: Optional[str]) -> bool:
pattern: Pattern = str_or_pattern
return pattern.search(input)
else:
raise ValueError(
raise BoltError(
f"{str_or_pattern} ({type(str_or_pattern)}) must be either str or Pattern"
)
6 changes: 4 additions & 2 deletions slack_bolt/oauth/async_oauth_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
from slack_sdk.web.async_client import AsyncWebClient
from slack_sdk.web.async_slack_response import AsyncSlackResponse

from slack_bolt.util.async_utils import create_async_web_client


class AsyncOAuthFlow:
installation_store: AsyncInstallationStore
Expand All @@ -46,7 +48,7 @@ class AsyncOAuthFlow:
@property
def client(self) -> AsyncWebClient:
if self._async_client is None:
self._async_client = AsyncWebClient()
self._async_client = create_async_web_client()
return self._async_client

@property
Expand Down Expand Up @@ -133,7 +135,7 @@ def sqlite3(
) -> "AsyncOAuthFlow":

return AsyncOAuthFlow(
client=AsyncWebClient(),
client=create_async_web_client(),
logger=logger,
installation_store=SQLite3InstallationStore(
database=database, client_id=client_id, logger=logger,
Expand Down
Empty file added slack_bolt/util/__init__.py
Empty file.
8 changes: 8 additions & 0 deletions slack_bolt/util/async_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from typing import Optional

from slack_sdk.web.async_client import AsyncWebClient


def create_async_web_client(token: Optional[str] = None) -> AsyncWebClient:
# TODO: add bolt info to user-agent
return AsyncWebClient(token=token)
8 changes: 8 additions & 0 deletions slack_bolt/util/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from typing import Optional

from slack_sdk import WebClient


def create_web_client(token: Optional[str] = None) -> WebClient:
# TODO: add bolt info to user-agent
return WebClient(token=token)
Loading

0 comments on commit eb89c44

Please sign in to comment.