diff --git a/apprise/plugins/slack.py b/apprise/plugins/slack.py index b929dfb4..50a872ee 100644 --- a/apprise/plugins/slack.py +++ b/apprise/plugins/slack.py @@ -603,16 +603,17 @@ class NotifySlack(NotifyBase): channel if channel[0] == '#' \ else '#{}'.format(channel) - # Store the valid and massaged payload that is recognizable by - # slack. This list is used for sending attachments later. - attach_channel_list.append(payload['channel']) - response = self._send(url, payload) if not response: # Handle any error has_error = True continue + # Store the valid channel or chat ID (for DMs) that will + # be accepted by Slack's attachment method later. + if response.get('channel'): + attach_channel_list.append(response.get('channel')) + self.logger.info( 'Sent Slack notification{}.'.format( ' to {}'.format(channel) @@ -635,21 +636,58 @@ class NotifySlack(NotifyBase): 'Posting Slack attachment {}'.format( attachment.url(privacy=True))) - # Prepare API Upload Payload - _payload = { + # Get the URL to which to upload the file. + # https://api.slack.com/methods/files.getUploadURLExternal + _params = { 'filename': attachment.name, - 'channels': ','.join(attach_channel_list) + 'length': len(attachment), } - - # Our URL - _url = self.api_url.format('files.upload') - - response = self._send(_url, _payload, attach=attachment) - if not (response and response.get('file') and - response['file'].get('url_private')): - # We failed to post our attachments, take an early exit + _url = self.api_url.format('files.getUploadURLExternal') + response = self._send( + _url, {}, http_method='get', params=_params + ) + if not ( + response and response.get('file_id') + and response.get('upload_url') + ): + self.logger.error('Could retrieve file upload URL.') + # We failed to get an upload URL, take an early exit return False + file_id = response.get('file_id') + upload_url = response.get('upload_url') + + # Upload file + response = self._send(upload_url, {}, attach=attachment) + + # Send file to channels + # https://api.slack.com/methods/files.completeUploadExternal + for channel_id in attach_channel_list: + _payload = { + 'files': [{ + "id": file_id, + "title": attachment.name, + }], + 'channel_id': channel_id + } + _url = self.api_url.format('files.completeUploadExternal') + response = self._send(_url, _payload) + # Expected response + # { + # "ok": true, + # "files": [ + # { + # "id": "F123ABC456", + # "title": "slack-test" + # } + # ] + # } + if not (response and response.get('files')): + self.logger.error('Failed to send file to channel.') + # We failed to send the file to the channel, + # take an early exit + return False + return not has_error def lookup_userid(self, email): @@ -808,7 +846,8 @@ class NotifySlack(NotifyBase): return user_id - def _send(self, url, payload, attach=None, **kwargs): + def _send(self, url, payload, attach=None, http_method='post', params=None, + **kwargs): """ Wrapper to the requests (post) object """ @@ -842,13 +881,15 @@ class NotifySlack(NotifyBase): if attach: files = {'file': (attach.name, open(attach.path, 'rb'))} - r = requests.post( + r = requests.request( + http_method, url, data=payload if attach else dumps(payload), headers=headers, files=files, verify=self.verify_certificate, timeout=self.request_timeout, + params=params if params else None, ) # Posts return a JSON string @@ -866,11 +907,22 @@ class NotifySlack(NotifyBase): # 'ok': False, # 'error': 'not_in_channel', # } - # - # The text 'ok' is returned if this is a Webhook request - # So the below captures that as well. - status_okay = (response and response.get('ok', False)) \ - if self.mode is SlackMode.BOT else r.content == b'ok' + status_okay = False + if self.mode is SlackMode.BOT: + status_okay = ( + (response and response.get('ok', False)) or + # Responses for file uploads look like this + # 'OK - ' + ( + r.content and + isinstance(r.content, bytes) and + b'OK' in r.content + ) + ) + elif r.content == b'ok': + # The text 'ok' is returned if this is a Webhook request + # So the below captures that as well. + status_okay = True if r.status_code != requests.codes.ok or not status_okay: # We had a problem @@ -879,9 +931,9 @@ class NotifySlack(NotifyBase): r.status_code, SLACK_HTTP_ERROR_MAP) self.logger.warning( - 'Failed to send {}to Slack: ' + 'Failed to send{} to Slack: ' '{}{}error={}.'.format( - attach.name if attach else '', + (' ' + attach.name) if attach else '', status_str, ', ' if status_str else '', r.status_code)) @@ -913,53 +965,15 @@ class NotifySlack(NotifyBase): # "username": "Apprise" # } - # File Attachment Responses look like this + # files.completeUploadExternal responses look like this: # { - # "file": { - # "channels": [], - # "comments_count": 0, - # "created": 1573617523, - # "display_as_bot": false, - # "editable": false, - # "external_type": "", - # "filetype": "png", - # "groups": [], - # "has_rich_preview": false, - # "id": "FQJJLDAHM", - # "image_exif_rotation": 1, - # "ims": [], - # "is_external": false, - # "is_public": false, - # "is_starred": false, - # "mimetype": "image/png", - # "mode": "hosted", - # "name": "apprise-test.png", - # "original_h": 640, - # "original_w": 640, - # "permalink": "https://{name}.slack.com/files/... - # "permalink_public": "https://slack-files.com/... - # "pretty_type": "PNG", - # "public_url_shared": false, - # "shares": {}, - # "size": 238810, - # "thumb_160": "https://files.slack.com/files-tmb/... - # "thumb_360": "https://files.slack.com/files-tmb/... - # "thumb_360_h": 360, - # "thumb_360_w": 360, - # "thumb_480": "https://files.slack.com/files-tmb/... - # "thumb_480_h": 480, - # "thumb_480_w": 480, - # "thumb_64": "https://files.slack.com/files-tmb/... - # "thumb_80": "https://files.slack.com/files-tmb/... - # "thumb_tiny": abcd... - # "timestamp": 1573617523, - # "title": "apprise-test", - # "url_private": "https://files.slack.com/files-pri/... - # "url_private_download": "https://files.slack.com/files-... - # "user": "UADKLLMJT", - # "username": "" - # }, - # "ok": true + # "ok": true, + # "files": [ + # { + # "id": "F123ABC456", + # "title": "slack-test" + # } + # ] # } except requests.RequestException as e: self.logger.warning( diff --git a/test/helpers/rest.py b/test/helpers/rest.py index 3581d902..c3ab5bcf 100644 --- a/test/helpers/rest.py +++ b/test/helpers/rest.py @@ -115,7 +115,8 @@ class AppriseURLTester: @mock.patch('requests.get') @mock.patch('requests.post') - def run(self, url, meta, mock_post, mock_get): + @mock.patch('requests.request') + def run(self, url, meta, mock_request, mock_post, mock_get): """ Run a specific test """ @@ -150,6 +151,7 @@ class AppriseURLTester: robj.content = u'' mock_get.return_value = robj mock_post.return_value = robj + mock_request.return_value = robj try: # We can now instantiate our object: @@ -276,8 +278,21 @@ class AppriseURLTester: @mock.patch('requests.put') @mock.patch('requests.delete') @mock.patch('requests.patch') - def __notify(self, url, obj, meta, asset, mock_patch, mock_del, mock_put, - mock_head, mock_post, mock_get): + @mock.patch('requests.request') + def __notify( + self, + url, + obj, + meta, + asset, + mock_request, + mock_patch, + mock_del, + mock_put, + mock_head, + mock_post, + mock_get + ): """ Perform notification testing against object specified """ @@ -342,6 +357,7 @@ class AppriseURLTester: mock_patch.return_value = robj mock_del.return_value = robj mock_put.return_value = robj + mock_request.return_value = robj if test_requests_exceptions is False: # Handle our default response @@ -351,6 +367,7 @@ class AppriseURLTester: mock_post.return_value.status_code = requests_response_code mock_get.return_value.status_code = requests_response_code mock_patch.return_value.status_code = requests_response_code + mock_request.return_value.status_code = requests_response_code # Handle our default text response mock_get.return_value.content = requests_response_content @@ -359,6 +376,7 @@ class AppriseURLTester: mock_put.return_value.content = requests_response_content mock_head.return_value.content = requests_response_content mock_patch.return_value.content = requests_response_content + mock_request.return_value.content = requests_response_content mock_get.return_value.text = requests_response_text mock_post.return_value.text = requests_response_text @@ -366,6 +384,7 @@ class AppriseURLTester: mock_del.return_value.text = requests_response_text mock_head.return_value.text = requests_response_text mock_patch.return_value.text = requests_response_text + mock_request.return_value.text = requests_response_text # Ensure there is no side effect set mock_post.side_effect = None @@ -374,6 +393,7 @@ class AppriseURLTester: mock_head.side_effect = None mock_get.side_effect = None mock_patch.side_effect = None + mock_request.side_effect = None else: # Handle exception testing; first we turn the boolean flag @@ -532,6 +552,7 @@ class AppriseURLTester: mock_put.side_effect = _exception mock_get.side_effect = _exception mock_patch.side_effect = _exception + mock_request.side_effect = _exception try: assert obj.notify( @@ -577,6 +598,7 @@ class AppriseURLTester: mock_head.side_effect = _exception mock_get.side_effect = _exception mock_patch.side_effect = _exception + mock_request.side_effect = _exception try: assert obj.notify( diff --git a/test/test_plugin_slack.py b/test/test_plugin_slack.py index 0ebf68b9..eaff0aff 100644 --- a/test/test_plugin_slack.py +++ b/test/test_plugin_slack.py @@ -131,10 +131,6 @@ apprise_url_tests = ( 'requests_response_text': { 'ok': True, 'message': '', - # support attachments - 'file': { - 'url_private': 'http://localhost/', - }, }, }), # Test blocks mode @@ -170,10 +166,6 @@ apprise_url_tests = ( 'requests_response_text': { 'ok': True, 'message': '', - # support attachments - 'file': { - 'url_private': 'http://localhost/', - }, }, # Our expected url(privacy=True) startswith() response: 'privacy_url': 'slack://test@x...4/nuxref/', @@ -184,10 +176,6 @@ apprise_url_tests = ( 'requests_response_text': { 'ok': True, 'message': '', - # support attachments - 'file': { - 'url_private': 'http://localhost/', - }, }, # We fail because of the empty channel #$ and #- 'notify_response': False, @@ -289,8 +277,8 @@ def test_plugin_slack_urls(): AppriseURLTester(tests=apprise_url_tests).run_all() -@mock.patch('requests.post') -def test_plugin_slack_oauth_access_token(mock_post): +@mock.patch('requests.request') +def test_plugin_slack_oauth_access_token(mock_request): """ NotifySlack() OAuth Access Token Tests @@ -303,11 +291,7 @@ def test_plugin_slack_oauth_access_token(mock_post): request.content = dumps({ 'ok': True, 'message': '', - - # Attachment support - 'file': { - 'url_private': 'http://localhost', - } + 'channel': 'C123456', }) request.status_code = requests.codes.ok @@ -319,8 +303,7 @@ def test_plugin_slack_oauth_access_token(mock_post): token = 'xoxb-1234-1234-abc124' # Prepare Mock - mock_post.return_value = request - + mock_request.return_value = request # Variation Initializations obj = NotifySlack(access_token=token, targets='#apprise') assert isinstance(obj, NotifySlack) is True @@ -330,7 +313,34 @@ def test_plugin_slack_oauth_access_token(mock_post): assert obj.send(body="test") is True # Test Valid Attachment - mock_post.reset_mock() + mock_request.reset_mock() + mock_request.side_effect = [ + request, + mock.Mock(**{ + 'content': dumps({ + "ok": True, + "upload_url": "https://files.slack.com/upload/v1/ABC123", + "file_id": "F123ABC456" + }), + 'status_code': requests.codes.ok + }), + mock.Mock(**{ + 'content': b'OK - 123', + 'status_code': requests.codes.ok + }), + mock.Mock(**{ + 'content': dumps({ + "ok": True, + "files": [ + { + "id": "F123ABC456", + "title": "slack-test" + } + ] + }), + 'status_code': requests.codes.ok + }), + ] path = os.path.join(TEST_VAR_DIR, 'apprise-test.gif') attach = AppriseAttachment(path) @@ -338,30 +348,42 @@ def test_plugin_slack_oauth_access_token(mock_post): body='body', title='title', notify_type=NotifyType.INFO, attach=attach) is True - assert mock_post.call_count == 2 - assert mock_post.call_args_list[0][0][0] == \ + assert mock_request.call_count == 4 + assert mock_request.call_args_list[0][0][0] == \ + 'post' + assert mock_request.call_args_list[0][0][1] == \ 'https://slack.com/api/chat.postMessage' - assert mock_post.call_args_list[1][0][0] == \ - 'https://slack.com/api/files.upload' + assert mock_request.call_args_list[1][0][0] == \ + 'get' + assert mock_request.call_args_list[1][0][1] == \ + 'https://slack.com/api/files.getUploadURLExternal' + assert mock_request.call_args_list[2][0][0] == \ + 'post' + assert mock_request.call_args_list[2][0][1] == \ + 'https://files.slack.com/upload/v1/ABC123' + assert mock_request.call_args_list[3][0][0] == \ + 'post' + assert mock_request.call_args_list[3][0][1] == \ + 'https://slack.com/api/files.completeUploadExternal' # Test a valid attachment that throws an Connection Error - mock_post.return_value = None - mock_post.side_effect = (request, requests.ConnectionError( + mock_request.return_value = None + mock_request.side_effect = (request, requests.ConnectionError( 0, 'requests.ConnectionError() not handled')) assert obj.notify( body='body', title='title', notify_type=NotifyType.INFO, attach=attach) is False # Test a valid attachment that throws an OSError - mock_post.return_value = None - mock_post.side_effect = (request, OSError(0, 'OSError')) + mock_request.return_value = None + mock_request.side_effect = (request, OSError(0, 'OSError')) assert obj.notify( body='body', title='title', notify_type=NotifyType.INFO, attach=attach) is False # Reset our mock object back to how it was - mock_post.return_value = request - mock_post.side_effect = None + mock_request.return_value = request + mock_request.side_effect = None # Test invalid attachment path = os.path.join(TEST_VAR_DIR, '/invalid/path/to/an/invalid/file.jpg') @@ -370,13 +392,16 @@ def test_plugin_slack_oauth_access_token(mock_post): attach=path) is False # Test case where expected return attachment payload is invalid - request.content = dumps({ - 'ok': True, - 'message': '', - - # Attachment support - 'file': None - }) + mock_request.reset_mock() + mock_request.side_effect = [ + request, + mock.Mock(**{ + 'content': dumps({ + "ok": False, + }), + 'status_code': requests.codes.internal_server_error + }), + ] path = os.path.join(TEST_VAR_DIR, 'apprise-test.gif') attach = AppriseAttachment(path) # We'll fail because of the bad 'file' response @@ -387,6 +412,9 @@ def test_plugin_slack_oauth_access_token(mock_post): # Slack requests pay close attention to the response to determine # if things go well... this is not a good JSON response: request.content = '{' + mock_request.reset_mock() + mock_request.return_value = request + mock_request.side_effect = None # As a result, we'll fail to send our notification assert obj.send(body="test", attach=attach) is False @@ -401,8 +429,8 @@ def test_plugin_slack_oauth_access_token(mock_post): assert obj.send(body="test", attach=attach) is False # Handle exceptions reading our attachment from disk (should it happen) - mock_post.side_effect = OSError("Attachment Error") - mock_post.return_value = None + mock_request.side_effect = OSError("Attachment Error") + mock_request.return_value = None # We'll fail now because of an internal exception assert obj.send(body="test") is False @@ -410,18 +438,18 @@ def test_plugin_slack_oauth_access_token(mock_post): # Test Email Lookup -@mock.patch('requests.post') -def test_plugin_slack_webhook_mode(mock_post): +@mock.patch('requests.request') +def test_plugin_slack_webhook_mode(mock_request): """ NotifySlack() Webhook Mode Tests """ # Prepare Mock - mock_post.return_value = requests.Request() - mock_post.return_value.status_code = requests.codes.ok - mock_post.return_value.content = b'ok' - mock_post.return_value.text = 'ok' + mock_request.return_value = requests.Request() + mock_request.return_value.status_code = requests.codes.ok + mock_request.return_value.content = b'ok' + mock_request.return_value.text = 'ok' # Initialize some generic (but valid) tokens token_a = 'A' * 9 @@ -455,9 +483,9 @@ def test_plugin_slack_webhook_mode(mock_post): body='body', title='title', notify_type=NotifyType.INFO) is True -@mock.patch('requests.post') +@mock.patch('requests.request') @mock.patch('requests.get') -def test_plugin_slack_send_by_email(mock_get, mock_post): +def test_plugin_slack_send_by_email(mock_get, mock_request): """ NotifySlack() Send by Email Tests @@ -477,7 +505,7 @@ def test_plugin_slack_send_by_email(mock_get, mock_post): request.status_code = requests.codes.ok # Prepare Mock - mock_post.return_value = request + mock_request.return_value = request mock_get.return_value = request # Variation Initializations @@ -486,7 +514,7 @@ def test_plugin_slack_send_by_email(mock_get, mock_post): assert isinstance(obj.url(), str) is True # No calls made yet - assert mock_post.call_count == 0 + assert mock_request.call_count == 0 assert mock_get.call_count == 0 # Send our notification @@ -496,18 +524,18 @@ def test_plugin_slack_send_by_email(mock_get, mock_post): # 2 calls were made, one to perform an email lookup, the second # was the notification itself assert mock_get.call_count == 1 - assert mock_post.call_count == 1 + assert mock_request.call_count == 1 assert mock_get.call_args_list[0][0][0] == \ 'https://slack.com/api/users.lookupByEmail' - assert mock_post.call_args_list[0][0][0] == \ + assert mock_request.call_args_list[0][0][1] == \ 'https://slack.com/api/chat.postMessage' # Reset our mock object - mock_post.reset_mock() + mock_request.reset_mock() mock_get.reset_mock() # Prepare Mock - mock_post.return_value = request + mock_request.return_value = request mock_get.return_value = request # Send our notification again (cached copy of user id associated with @@ -516,8 +544,8 @@ def test_plugin_slack_send_by_email(mock_get, mock_post): body='body', title='title', notify_type=NotifyType.INFO) is True assert mock_get.call_count == 0 - assert mock_post.call_count == 1 - assert mock_post.call_args_list[0][0][0] == \ + assert mock_request.call_count == 1 + assert mock_request.call_args_list[0][0][1] == \ 'https://slack.com/api/chat.postMessage' # @@ -529,11 +557,11 @@ def test_plugin_slack_send_by_email(mock_get, mock_post): }) # Reset our mock object - mock_post.reset_mock() + mock_request.reset_mock() mock_get.reset_mock() # Prepare Mock - mock_post.return_value = request + mock_request.return_value = request mock_get.return_value = request # Variation Initializations @@ -542,7 +570,7 @@ def test_plugin_slack_send_by_email(mock_get, mock_post): assert isinstance(obj.url(), str) is True # No calls made yet - assert mock_post.call_count == 0 + assert mock_request.call_count == 0 assert mock_get.call_count == 0 # Send our notification; it will fail because we failed to look up @@ -553,7 +581,7 @@ def test_plugin_slack_send_by_email(mock_get, mock_post): # We would have failed to look up the email, therefore we wouldn't have # even bothered to attempt to send the notification assert mock_get.call_count == 1 - assert mock_post.call_count == 0 + assert mock_request.call_count == 0 assert mock_get.call_args_list[0][0][0] == \ 'https://slack.com/api/users.lookupByEmail' @@ -563,11 +591,11 @@ def test_plugin_slack_send_by_email(mock_get, mock_post): request.content = '}' # Reset our mock object - mock_post.reset_mock() + mock_request.reset_mock() mock_get.reset_mock() # Prepare Mock - mock_post.return_value = request + mock_request.return_value = request mock_get.return_value = request # Variation Initializations @@ -576,7 +604,7 @@ def test_plugin_slack_send_by_email(mock_get, mock_post): assert isinstance(obj.url(), str) is True # No calls made yet - assert mock_post.call_count == 0 + assert mock_request.call_count == 0 assert mock_get.call_count == 0 # Send our notification; it will fail because we failed to look up @@ -587,7 +615,7 @@ def test_plugin_slack_send_by_email(mock_get, mock_post): # We would have failed to look up the email, therefore we wouldn't have # even bothered to attempt to send the notification assert mock_get.call_count == 1 - assert mock_post.call_count == 0 + assert mock_request.call_count == 0 assert mock_get.call_args_list[0][0][0] == \ 'https://slack.com/api/users.lookupByEmail' @@ -597,11 +625,11 @@ def test_plugin_slack_send_by_email(mock_get, mock_post): request.content = '}' # Reset our mock object - mock_post.reset_mock() + mock_request.reset_mock() mock_get.reset_mock() # Prepare Mock - mock_post.return_value = request + mock_request.return_value = request mock_get.return_value = request # Variation Initializations @@ -610,7 +638,7 @@ def test_plugin_slack_send_by_email(mock_get, mock_post): assert isinstance(obj.url(), str) is True # No calls made yet - assert mock_post.call_count == 0 + assert mock_request.call_count == 0 assert mock_get.call_count == 0 # Send our notification; it will fail because we failed to look up @@ -621,7 +649,7 @@ def test_plugin_slack_send_by_email(mock_get, mock_post): # We would have failed to look up the email, therefore we wouldn't have # even bothered to attempt to send the notification assert mock_get.call_count == 1 - assert mock_post.call_count == 0 + assert mock_request.call_count == 0 assert mock_get.call_args_list[0][0][0] == \ 'https://slack.com/api/users.lookupByEmail' @@ -640,11 +668,11 @@ def test_plugin_slack_send_by_email(mock_get, mock_post): request.status_code = requests.codes.ok # Reset our mock object - mock_post.reset_mock() + mock_request.reset_mock() mock_get.reset_mock() # Prepare Mock - mock_post.return_value = request + mock_request.return_value = request mock_get.side_effect = requests.ConnectionError( 0, 'requests.ConnectionError() not handled') @@ -654,7 +682,7 @@ def test_plugin_slack_send_by_email(mock_get, mock_post): assert isinstance(obj.url(), str) is True # No calls made yet - assert mock_post.call_count == 0 + assert mock_request.call_count == 0 assert mock_get.call_count == 0 # Send our notification; it will fail because we failed to look up @@ -665,14 +693,14 @@ def test_plugin_slack_send_by_email(mock_get, mock_post): # We would have failed to look up the email, therefore we wouldn't have # even bothered to attempt to send the notification assert mock_get.call_count == 1 - assert mock_post.call_count == 0 + assert mock_request.call_count == 0 assert mock_get.call_args_list[0][0][0] == \ 'https://slack.com/api/users.lookupByEmail' -@mock.patch('requests.post') +@mock.patch('requests.request') @mock.patch('requests.get') -def test_plugin_slack_markdown(mock_get, mock_post): +def test_plugin_slack_markdown(mock_get, mock_request): """ NotifySlack() Markdown tests @@ -683,7 +711,7 @@ def test_plugin_slack_markdown(mock_get, mock_post): request.status_code = requests.codes.ok # Prepare Mock - mock_post.return_value = request + mock_request.return_value = request mock_get.return_value = request # Variation Initializations @@ -712,12 +740,12 @@ def test_plugin_slack_markdown(mock_get, mock_post): # We would have failed to look up the email, therefore we wouldn't have # even bothered to attempt to send the notification assert mock_get.call_count == 0 - assert mock_post.call_count == 1 - assert mock_post.call_args_list[0][0][0] == \ + assert mock_request.call_count == 1 + assert mock_request.call_args_list[0][0][1] == \ 'https://hooks.slack.com/services/T1JJ3T3L2/A1BRTD4JD/' \ 'TIiajkdnlazkcOXrIdevi7FQ' - data = loads(mock_post.call_args_list[0][1]['data']) + data = loads(mock_request.call_args_list[0][1]['data']) assert data['attachments'][0]['text'] == \ "Here is a we want to support as part "\ "of it's\nmarkdown.\n\nThis one has arguments we want to preserve:"\ @@ -727,8 +755,8 @@ def test_plugin_slack_markdown(mock_get, mock_post): "\n\nChannel Testing\n\n" -@mock.patch('requests.post') -def test_plugin_slack_single_thread_reply(mock_post): +@mock.patch('requests.request') +def test_plugin_slack_single_thread_reply(mock_request): """ NotifySlack() Send Notification as a Reply @@ -748,7 +776,7 @@ def test_plugin_slack_single_thread_reply(mock_post): request.status_code = requests.codes.ok # Prepare Mock - mock_post.return_value = request + mock_request.return_value = request # Variation Initializations obj = NotifySlack(access_token=token, targets=[f'#general:{thread_id}']) @@ -756,22 +784,22 @@ def test_plugin_slack_single_thread_reply(mock_post): assert isinstance(obj.url(), str) is True # No calls made yet - assert mock_post.call_count == 0 + assert mock_request.call_count == 0 # Send our notification assert obj.notify( body='body', title='title', notify_type=NotifyType.INFO) is True # Post was made - assert mock_post.call_count == 1 - assert mock_post.call_args_list[0][0][0] == \ + assert mock_request.call_count == 1 + assert mock_request.call_args_list[0][0][1] == \ 'https://slack.com/api/chat.postMessage' - assert loads(mock_post.call_args_list[0][1]['data']).get("thread_ts") \ + assert loads(mock_request.call_args_list[0][1]['data']).get("thread_ts") \ == str(thread_id) -@mock.patch('requests.post') -def test_plugin_slack_multiple_thread_reply(mock_post): +@mock.patch('requests.request') +def test_plugin_slack_multiple_thread_reply(mock_request): """ NotifySlack() Send Notification to multiple channels as Reply @@ -791,7 +819,7 @@ def test_plugin_slack_multiple_thread_reply(mock_post): request.status_code = requests.codes.ok # Prepare Mock - mock_post.return_value = request + mock_request.return_value = request # Variation Initializations obj = NotifySlack(access_token=token, @@ -802,17 +830,17 @@ def test_plugin_slack_multiple_thread_reply(mock_post): assert isinstance(obj.url(), str) is True # No calls made yet - assert mock_post.call_count == 0 + assert mock_request.call_count == 0 # Send our notification assert obj.notify( body='body', title='title', notify_type=NotifyType.INFO) is True # Post was made - assert mock_post.call_count == 2 - assert mock_post.call_args_list[0][0][0] == \ + assert mock_request.call_count == 2 + assert mock_request.call_args_list[0][0][1] == \ 'https://slack.com/api/chat.postMessage' - assert loads(mock_post.call_args_list[0][1]['data']).get("thread_ts") \ + assert loads(mock_request.call_args_list[0][1]['data']).get("thread_ts") \ == str(thread_id_1) - assert loads(mock_post.call_args_list[1][1]['data']).get("thread_ts") \ + assert loads(mock_request.call_args_list[1][1]['data']).get("thread_ts") \ == str(thread_id_2)