Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor Slack calls into a class #83

Merged
merged 4 commits into from
Aug 5, 2019
Merged

Conversation

milesbxf
Copy link
Contributor

This refactors anything that calls slack_client.api_call into a new class at response.slack.SlackClient. There are a few benefits I think we get here:

  • We centralise all the logic around actually doing the api_call:
    • we can check for a {"ok": False} response and translate that into a Python exception. Previously, this has been inconsistently applied around the codebase, sometimes making it very difficult to debug Slack errors
    • similar to above, we can add logging in one place to log all Slack API calls for debugging
  • Whilst it's fairly straightforward to monkeypatch and mock out slack_client.api_call, our mock had to have lots of extra logic to handle each Slack API call (and record that it had been handled). This means our test code can now go from this:
    mock_slack = MagicMock(spec=SlackClient)
    slack_api_calls = {}
    def handle_slack_api_call(self, slack_api_name, *args, **kwargs):
        slack_api_calls[slack_api_name] = {"args": args, "kwargs": kwargs}
        if slack_api_name == "dialog.open":
            return {"ok": True, "ts": str(datetime.now().timestamp())}
    
    mock_slack.api_call.side_effect = handle_slack_api_call

    # ... run test

    assert 'dialog.open' in slack_api_calls

to this:

mock_slack = MagicMock(spec=SlackClient)

# ... run test
mock_slack.dialog_open.assert_called()

We moved the UI templates from response/ui to response - however the
package manifest was still looking for files to include from
response/ui/templates, so didn't actually package the templates.
Creates a new response.slack.client.SlackClient class we can use to
abstract calls to the Slack API, and replaces invocations in settings
with this
@milesbxf milesbxf requested a review from evnsio July 25, 2019 10:36
@@ -237,3 +186,6 @@ def get_env_var(setting, warn_only=False):
value = value.replace('"', '') # remove start/end quotes

return value

SLACK_TOKEN = get_env_var("SLACK_TOKEN")
SLACK_CLIENT = SlackClient(SLACK_TOKEN)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if there's a way to avoid having to define this here? It would ideal if it was defined inside response, so people don't need to add this to their settings file.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I've since been wondering this myself actually. We could create a global slack_client object in response.slack.client that is instantiated using settings.SLACK_TOKEN. I'll put that in this afternoon 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had a go at this. It's excruciatingly difficult to mock, because of the way Python imports things - I'm running into lots of the issues described in http://alexmarandon.com/articles/python_mock_gotchas/, and looks like we'd need to monkeypatch every single file that slack_client would be imported into.

Definitely agree that this isn't a great approach, but I'm not sure it's something we should spend lots of time solving right now

@milesbxf milesbxf merged commit b57a976 into release-0.1 Aug 5, 2019
@milesbxf milesbxf deleted the slack-client-refactor branch August 5, 2019 13:48
milesbxf added a commit that referenced this pull request Aug 14, 2019
* Include newly moved templates

We moved the UI templates from response/ui to response - however the
package manifest was still looking for files to include from
response/ui/templates, so didn't actually package the templates.

* Extract Slack uses in settings to a common client

Creates a new response.slack.client.SlackClient class we can use to
abstract calls to the Slack API, and replaces invocations in settings
with this

* Move some functions from slack_utils to slack.client

* Fix unit tests
@milesbxf milesbxf mentioned this pull request Aug 14, 2019
milesbxf added a commit that referenced this pull request Aug 15, 2019
* Include newly moved templates

We moved the UI templates from response/ui to response - however the
package manifest was still looking for files to include from
response/ui/templates, so didn't actually package the templates.

* Extract Slack uses in settings to a common client

Creates a new response.slack.client.SlackClient class we can use to
abstract calls to the Slack API, and replaces invocations in settings
with this

* Move some functions from slack_utils to slack.client

* Fix unit tests
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants