2020-08-07 01:09:47 +02:00
from typing import Any , Dict
2020-06-11 00:54:34 +02:00
from unittest import mock
2016-07-23 07:51:30 +02:00
2020-08-07 01:09:47 +02:00
import orjson
2020-06-11 00:54:34 +02:00
import requests
2020-03-28 13:22:19 +01:00
2020-06-11 00:54:34 +02:00
from version import ZULIP_VERSION
from zerver . lib . actions import do_create_user
2018-10-11 14:11:52 +02:00
from zerver . lib . outgoing_webhook import (
GenericOutgoingWebhookService ,
SlackOutgoingWebhookService ,
2020-06-11 00:54:34 +02:00
do_rest_call ,
2018-10-11 14:11:52 +02:00
)
2017-05-25 19:48:36 +02:00
from zerver . lib . test_classes import ZulipTestCase
2018-11-10 16:43:59 +01:00
from zerver . lib . topic import TOPIC_NAME
2020-03-28 13:22:19 +01:00
from zerver . lib . users import add_service
2020-07-24 19:21:42 +02:00
from zerver . models import Recipient , Service , UserProfile , get_display_recipient
2016-07-23 08:13:33 +02:00
2019-01-09 15:29:17 +01:00
2017-11-05 11:49:43 +01:00
class ResponseMock :
2021-02-12 08:19:30 +01:00
def __init__ ( self , status_code : int , content : bytes = b " " ) - > None :
2016-07-23 08:13:33 +02:00
self . status_code = status_code
self . content = content
2020-08-07 01:09:47 +02:00
self . text = content . decode ( )
2016-07-23 08:13:33 +02:00
2021-02-12 08:19:30 +01:00
def request_exception_error (
http_method : Any , final_url : Any , data : Any , * * request_kwargs : Any
) - > Any :
2017-08-29 15:21:25 +02:00
raise requests . exceptions . RequestException ( " I ' m a generic exception :( " )
2016-07-23 08:13:33 +02:00
2021-02-12 08:19:30 +01:00
2017-11-05 10:51:25 +01:00
def timeout_error ( http_method : Any , final_url : Any , data : Any , * * request_kwargs : Any ) - > Any :
2017-08-16 13:30:47 +02:00
raise requests . exceptions . Timeout ( " Time is up! " )
2016-07-23 08:13:33 +02:00
2021-02-12 08:19:30 +01:00
2018-10-10 19:52:32 +02:00
def connection_error ( http_method : Any , final_url : Any , data : Any , * * request_kwargs : Any ) - > Any :
raise requests . exceptions . ConnectionError ( )
2021-02-12 08:19:30 +01:00
2016-07-23 08:13:33 +02:00
class DoRestCallTests ( ZulipTestCase ) :
2020-07-24 19:21:42 +02:00
def mock_event ( self , bot_user : UserProfile ) - > Dict [ str , Any ] :
return {
2017-08-29 15:21:25 +02:00
# In the tests there is no active queue processor, so retries don't get processed.
# Therefore, we need to emulate `retry_event` in the last stage when the maximum
# retries have been exceeded.
2021-02-12 08:20:45 +01:00
" failed_tries " : 3 ,
" message " : {
" display_recipient " : " Verona " ,
" stream_id " : 999 ,
TOPIC_NAME : " Foo " ,
" id " : " " ,
" type " : " stream " ,
2021-02-12 08:19:30 +01:00
} ,
2021-02-12 08:20:45 +01:00
" user_profile_id " : bot_user . id ,
" command " : " " ,
" service_name " : " " ,
2021-02-12 08:19:30 +01:00
}
2017-09-25 16:03:35 +02:00
2020-07-24 18:46:14 +02:00
def test_successful_request ( self ) - > None :
2021-02-12 08:20:45 +01:00
bot_user = self . example_user ( " outgoing_webhook_bot " )
2020-07-24 19:21:42 +02:00
mock_event = self . mock_event ( bot_user )
service_handler = GenericOutgoingWebhookService ( " token " , bot_user , " service " )
2021-02-12 08:20:45 +01:00
response = ResponseMock ( 200 , orjson . dumps ( dict ( content = " whatever " ) ) )
expect_200 = mock . patch ( " requests.request " , return_value = response )
2020-07-24 18:46:14 +02:00
2021-02-12 08:20:45 +01:00
expect_send_response = mock . patch ( " zerver.lib.outgoing_webhook.send_response_message " )
2020-07-24 18:46:14 +02:00
with expect_200 , expect_send_response as mock_send :
2021-02-12 08:20:45 +01:00
do_rest_call ( " " , None , mock_event , service_handler )
2020-07-24 18:24:28 +02:00
self . assertTrue ( mock_send . called )
2016-07-23 08:13:33 +02:00
2018-10-11 14:11:52 +02:00
for service_class in [ GenericOutgoingWebhookService , SlackOutgoingWebhookService ] :
2020-07-24 19:21:42 +02:00
handler = service_class ( " token " , bot_user , " service " )
2020-07-24 18:46:14 +02:00
with expect_200 :
2021-02-12 08:20:45 +01:00
do_rest_call ( " " , None , mock_event , handler )
2020-07-24 18:46:14 +02:00
# TODO: assert something interesting here?
2018-10-11 14:11:52 +02:00
2020-07-24 19:00:11 +02:00
def test_retry_request ( self ) - > None :
2021-02-12 08:20:45 +01:00
bot_user = self . example_user ( " outgoing_webhook_bot " )
2020-07-24 19:21:42 +02:00
mock_event = self . mock_event ( bot_user )
service_handler = GenericOutgoingWebhookService ( " token " , bot_user , " service " )
2017-11-03 13:12:59 +01:00
response = ResponseMock ( 500 )
2021-02-12 08:20:45 +01:00
with mock . patch ( " requests.request " , return_value = response ) , self . assertLogs (
2021-02-12 08:19:30 +01:00
level = " WARNING "
) as m :
2021-02-12 08:20:45 +01:00
final_response = do_rest_call ( " " , None , mock_event , service_handler )
2020-10-29 20:21:18 +01:00
assert final_response is not None
2017-08-29 15:21:25 +02:00
2021-02-12 08:19:30 +01:00
self . assertEqual (
m . output ,
[
2021-02-12 08:20:45 +01:00
f ' WARNING:root:Message http://zulip.testserver/#narrow/stream/999-Verona/topic/Foo/near/ triggered an outgoing webhook, returning status code 500. \n Content of response (in quotes): " { final_response . text } " '
2021-02-12 08:19:30 +01:00
] ,
)
2020-07-24 18:24:28 +02:00
bot_owner_notification = self . get_last_message ( )
2021-02-12 08:19:30 +01:00
self . assertEqual (
bot_owner_notification . content ,
2021-02-12 08:20:45 +01:00
""" [A message](http://zulip.testserver/#narrow/stream/999-Verona/topic/Foo/near/) triggered an outgoing webhook.
The webhook got a response with status code * 500 * . """ ,
2021-02-12 08:19:30 +01:00
)
2020-07-24 19:00:11 +02:00
2020-07-24 19:21:42 +02:00
assert bot_user . bot_owner is not None
2021-02-02 14:09:11 +01:00
self . assertEqual ( bot_owner_notification . recipient_id , bot_user . bot_owner . recipient_id )
2016-07-23 08:13:33 +02:00
2020-07-24 18:46:14 +02:00
def test_fail_request ( self ) - > None :
2021-02-12 08:20:45 +01:00
bot_user = self . example_user ( " outgoing_webhook_bot " )
2020-07-24 19:21:42 +02:00
mock_event = self . mock_event ( bot_user )
service_handler = GenericOutgoingWebhookService ( " token " , bot_user , " service " )
2017-11-03 13:12:59 +01:00
response = ResponseMock ( 400 )
2020-07-24 18:46:14 +02:00
expect_400 = mock . patch ( " requests.request " , return_value = response )
expect_fail = mock . patch ( " zerver.lib.outgoing_webhook.fail_with_message " )
2020-10-29 20:21:18 +01:00
with expect_400 , expect_fail as mock_fail , self . assertLogs ( level = " WARNING " ) as m :
2021-02-12 08:20:45 +01:00
final_response = do_rest_call ( " " , None , mock_event , service_handler )
2020-10-29 20:21:18 +01:00
assert final_response is not None
2021-02-12 08:19:30 +01:00
self . assertEqual (
m . output ,
[
2021-02-12 08:20:45 +01:00
f ' WARNING:root:Message http://zulip.testserver/#narrow/stream/999-Verona/topic/Foo/near/ triggered an outgoing webhook, returning status code 400. \n Content of response (in quotes): " { final_response . text } " '
2021-02-12 08:19:30 +01:00
] ,
)
2020-07-24 18:24:28 +02:00
2020-07-24 18:46:14 +02:00
self . assertTrue ( mock_fail . called )
2020-07-24 18:24:28 +02:00
bot_owner_notification = self . get_last_message ( )
2021-02-12 08:19:30 +01:00
self . assertEqual (
bot_owner_notification . content ,
2021-02-12 08:20:45 +01:00
""" [A message](http://zulip.testserver/#narrow/stream/999-Verona/topic/Foo/near/) triggered an outgoing webhook.
The webhook got a response with status code * 400 * . """ ,
2021-02-12 08:19:30 +01:00
)
2020-07-24 19:00:11 +02:00
2020-07-24 19:21:42 +02:00
assert bot_user . bot_owner is not None
2021-02-02 14:09:11 +01:00
self . assertEqual ( bot_owner_notification . recipient_id , bot_user . bot_owner . recipient_id )
2016-07-23 08:13:33 +02:00
2019-01-09 15:29:17 +01:00
def test_headers ( self ) - > None :
2021-02-12 08:20:45 +01:00
bot_user = self . example_user ( " outgoing_webhook_bot " )
2020-07-24 19:21:42 +02:00
mock_event = self . mock_event ( bot_user )
service_handler = GenericOutgoingWebhookService ( " token " , bot_user , " service " )
2021-02-12 08:20:45 +01:00
with mock . patch ( " requests.request " ) as mock_request , self . assertLogs ( level = " WARNING " ) as m :
final_response = do_rest_call ( " " , " payload-stub " , mock_event , service_handler )
2020-10-29 20:21:18 +01:00
assert final_response is not None
2021-02-12 08:19:30 +01:00
self . assertEqual (
m . output ,
[
2021-02-12 08:20:45 +01:00
f ' WARNING:root:Message http://zulip.testserver/#narrow/stream/999-Verona/topic/Foo/near/ triggered an outgoing webhook, returning status code { final_response . status_code } . \n Content of response (in quotes): " { final_response . text } " '
2021-02-12 08:19:30 +01:00
] ,
)
2019-01-09 15:29:17 +01:00
2020-07-24 18:24:28 +02:00
kwargs = mock_request . call_args [ 1 ]
2021-02-12 08:20:45 +01:00
self . assertEqual ( kwargs [ " data " ] , " payload-stub " )
2020-07-24 18:24:28 +02:00
2021-02-12 08:20:45 +01:00
user_agent = " ZulipOutgoingWebhook/ " + ZULIP_VERSION
2020-07-24 18:24:28 +02:00
headers = {
2021-02-12 08:20:45 +01:00
" content-type " : " application/json " ,
" User-Agent " : user_agent ,
2020-07-24 18:24:28 +02:00
}
2021-02-12 08:20:45 +01:00
self . assertEqual ( kwargs [ " headers " ] , headers )
2019-01-09 15:29:17 +01:00
2018-10-10 19:52:32 +02:00
def test_error_handling ( self ) - > None :
2021-02-12 08:20:45 +01:00
bot_user = self . example_user ( " outgoing_webhook_bot " )
2020-10-29 20:21:18 +01:00
mock_event = self . mock_event ( bot_user )
service_handler = GenericOutgoingWebhookService ( " token " , bot_user , " service " )
2021-02-12 08:20:45 +01:00
bot_user_email = self . example_user_map [ " outgoing_webhook_bot " ]
2020-10-29 20:21:18 +01:00
2018-10-10 19:52:32 +02:00
def helper ( side_effect : Any , error_text : str ) - > None :
2020-07-24 19:21:42 +02:00
2021-02-12 08:20:45 +01:00
with mock . patch ( " requests.request " , side_effect = side_effect ) :
do_rest_call ( " " , None , mock_event , service_handler )
2020-07-24 18:24:28 +02:00
bot_owner_notification = self . get_last_message ( )
self . assertIn ( error_text , bot_owner_notification . content )
2021-02-12 08:20:45 +01:00
self . assertIn ( " triggered " , bot_owner_notification . content )
2020-07-24 19:21:42 +02:00
assert bot_user . bot_owner is not None
2021-02-02 14:09:11 +01:00
self . assertEqual ( bot_owner_notification . recipient_id , bot_user . bot_owner . recipient_id )
2018-10-10 19:52:32 +02:00
2020-10-29 20:21:18 +01:00
with self . assertLogs ( level = " INFO " ) as i :
2021-02-12 08:20:45 +01:00
helper ( side_effect = timeout_error , error_text = " A timeout occurred. " )
helper ( side_effect = connection_error , error_text = " A connection error occurred. " )
2020-10-29 20:21:18 +01:00
log_output = [
f " INFO:root:Trigger event { mock_event [ ' command ' ] } on { mock_event [ ' service_name ' ] } timed out. Retrying " ,
f " WARNING:root:Maximum retries exceeded for trigger: { bot_user_email } event: { mock_event [ ' command ' ] } " ,
f " INFO:root:Trigger event { mock_event [ ' command ' ] } on { mock_event [ ' service_name ' ] } resulted in a connection error. Retrying " ,
2021-02-12 08:19:30 +01:00
f " WARNING:root:Maximum retries exceeded for trigger: { bot_user_email } event: { mock_event [ ' command ' ] } " ,
2020-10-29 20:21:18 +01:00
]
self . assertEqual ( i . output , log_output )
2016-07-23 08:13:33 +02:00
2020-07-24 18:46:14 +02:00
def test_request_exception ( self ) - > None :
2021-02-12 08:20:45 +01:00
bot_user = self . example_user ( " outgoing_webhook_bot " )
2020-07-24 19:21:42 +02:00
mock_event = self . mock_event ( bot_user )
service_handler = GenericOutgoingWebhookService ( " token " , bot_user , " service " )
2021-02-12 08:19:30 +01:00
expect_request_exception = mock . patch (
" requests.request " , side_effect = request_exception_error
)
2020-10-29 20:21:18 +01:00
expect_logging_exception = self . assertLogs ( level = " ERROR " )
2020-07-24 18:46:14 +02:00
expect_fail = mock . patch ( " zerver.lib.outgoing_webhook.fail_with_message " )
2020-10-29 20:21:18 +01:00
# Don't think that we should catch and assert whole log output(which is actually a very big error traceback).
# We are already asserting bot_owner_notification.content which verifies exception did occur.
2020-07-24 18:46:14 +02:00
with expect_request_exception , expect_logging_exception , expect_fail as mock_fail :
2021-02-12 08:20:45 +01:00
do_rest_call ( " " , None , mock_event , service_handler )
2020-07-24 18:46:14 +02:00
self . assertTrue ( mock_fail . called )
2017-08-29 15:21:25 +02:00
bot_owner_notification = self . get_last_message ( )
2021-02-12 08:19:30 +01:00
self . assertEqual (
bot_owner_notification . content ,
2021-02-12 08:20:45 +01:00
""" [A message](http://zulip.testserver/#narrow/stream/999-Verona/topic/Foo/near/) triggered an outgoing webhook.
2017-11-09 16:26:38 +01:00
When trying to send a request to the webhook service , an exception of type RequestException occurred :
2017-08-29 15:21:25 +02:00
` ` `
I ' m a generic exception :(
2021-02-12 08:20:45 +01:00
` ` ` """ ,
2021-02-12 08:19:30 +01:00
)
2020-07-24 19:21:42 +02:00
assert bot_user . bot_owner is not None
2021-02-02 14:09:11 +01:00
self . assertEqual ( bot_owner_notification . recipient_id , bot_user . bot_owner . recipient_id )
2017-11-03 13:38:49 +01:00
2021-02-12 08:19:30 +01:00
2017-11-03 13:38:49 +01:00
class TestOutgoingWebhookMessaging ( ZulipTestCase ) :
2020-03-28 12:25:37 +01:00
def create_outgoing_bot ( self , bot_owner : UserProfile ) - > UserProfile :
return self . create_test_bot (
2021-02-12 08:20:45 +01:00
" outgoing-webhook " ,
2020-03-28 12:25:37 +01:00
bot_owner ,
2021-02-12 08:20:45 +01:00
full_name = " Outgoing Webhook bot " ,
2020-03-28 12:25:37 +01:00
bot_type = UserProfile . OUTGOING_WEBHOOK_BOT ,
2021-02-12 08:20:45 +01:00
service_name = " foo-service " ,
2020-03-28 12:25:37 +01:00
)
2017-11-03 13:38:49 +01:00
2020-03-28 13:22:19 +01:00
def test_multiple_services ( self ) - > None :
bot_owner = self . example_user ( " othello " )
bot = do_create_user (
bot_owner = bot_owner ,
bot_type = UserProfile . OUTGOING_WEBHOOK_BOT ,
2021-02-12 08:20:45 +01:00
full_name = " Outgoing Webhook Bot " ,
email = " whatever " ,
2020-03-28 13:22:19 +01:00
realm = bot_owner . realm ,
password = None ,
2021-02-06 14:27:06 +01:00
acting_user = None ,
2020-03-28 13:22:19 +01:00
)
add_service (
2021-02-12 08:20:45 +01:00
" weather " ,
2020-03-28 13:22:19 +01:00
user_profile = bot ,
interface = Service . GENERIC ,
2021-02-12 08:20:45 +01:00
base_url = " weather_url " ,
token = " weather_token " ,
2020-03-28 13:22:19 +01:00
)
add_service (
2021-02-12 08:20:45 +01:00
" qotd " ,
2020-03-28 13:22:19 +01:00
user_profile = bot ,
interface = Service . GENERIC ,
2021-02-12 08:20:45 +01:00
base_url = " qotd_url " ,
token = " qotd_token " ,
2020-03-28 13:22:19 +01:00
)
sender = self . example_user ( " hamlet " )
2021-02-12 08:20:45 +01:00
with mock . patch ( " zerver.worker.queue_processors.do_rest_call " ) as m :
2020-03-28 13:22:19 +01:00
self . send_personal_message (
sender ,
bot ,
python: Use trailing commas consistently.
Automatically generated by the following script, based on the output
of lint with flake8-comma:
import re
import sys
last_filename = None
last_row = None
lines = []
for msg in sys.stdin:
m = re.match(
r"\x1b\[35mflake8 \|\x1b\[0m \x1b\[1;31m(.+):(\d+):(\d+): (\w+)", msg
)
if m:
filename, row_str, col_str, err = m.groups()
row, col = int(row_str), int(col_str)
if filename == last_filename:
assert last_row != row
else:
if last_filename is not None:
with open(last_filename, "w") as f:
f.writelines(lines)
with open(filename) as f:
lines = f.readlines()
last_filename = filename
last_row = row
line = lines[row - 1]
if err in ["C812", "C815"]:
lines[row - 1] = line[: col - 1] + "," + line[col - 1 :]
elif err in ["C819"]:
assert line[col - 2] == ","
lines[row - 1] = line[: col - 2] + line[col - 1 :].lstrip(" ")
if last_filename is not None:
with open(last_filename, "w") as f:
f.writelines(lines)
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-04-10 05:23:40 +02:00
content = " some content " ,
2020-03-28 13:22:19 +01:00
)
url_token_tups = set ( )
for item in m . call_args_list :
args = item [ 0 ]
base_url = args [ 0 ]
2020-08-07 01:09:47 +02:00
request_data = orjson . loads ( args [ 1 ] )
2021-02-12 08:20:45 +01:00
tup = ( base_url , request_data [ " token " ] )
2020-03-28 13:22:19 +01:00
url_token_tups . add ( tup )
2021-02-12 08:20:45 +01:00
message_data = request_data [ " message " ]
self . assertEqual ( message_data [ " content " ] , " some content " )
self . assertEqual ( message_data [ " sender_id " ] , sender . id )
2020-03-28 13:22:19 +01:00
self . assertEqual (
url_token_tups ,
{
2021-02-12 08:20:45 +01:00
( " weather_url " , " weather_token " ) ,
( " qotd_url " , " qotd_token " ) ,
python: Use trailing commas consistently.
Automatically generated by the following script, based on the output
of lint with flake8-comma:
import re
import sys
last_filename = None
last_row = None
lines = []
for msg in sys.stdin:
m = re.match(
r"\x1b\[35mflake8 \|\x1b\[0m \x1b\[1;31m(.+):(\d+):(\d+): (\w+)", msg
)
if m:
filename, row_str, col_str, err = m.groups()
row, col = int(row_str), int(col_str)
if filename == last_filename:
assert last_row != row
else:
if last_filename is not None:
with open(last_filename, "w") as f:
f.writelines(lines)
with open(filename) as f:
lines = f.readlines()
last_filename = filename
last_row = row
line = lines[row - 1]
if err in ["C812", "C815"]:
lines[row - 1] = line[: col - 1] + "," + line[col - 1 :]
elif err in ["C819"]:
assert line[col - 2] == ","
lines[row - 1] = line[: col - 2] + line[col - 1 :].lstrip(" ")
if last_filename is not None:
with open(last_filename, "w") as f:
f.writelines(lines)
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-04-10 05:23:40 +02:00
} ,
2020-03-28 13:22:19 +01:00
)
2021-02-12 08:19:30 +01:00
@mock.patch (
2021-02-12 08:20:45 +01:00
" requests.request " ,
2021-02-12 08:19:30 +01:00
return_value = ResponseMock (
200 , orjson . dumps ( { " response_string " : " Hidley ho, I ' m a webhook responding! " } )
) ,
)
2017-11-05 10:51:25 +01:00
def test_pm_to_outgoing_webhook_bot ( self , mock_requests_request : mock . Mock ) - > None :
2020-03-28 12:25:37 +01:00
bot_owner = self . example_user ( " othello " )
bot = self . create_outgoing_bot ( bot_owner )
2020-03-28 12:37:36 +01:00
sender = self . example_user ( " hamlet " )
2020-03-28 12:25:37 +01:00
2021-02-12 08:19:30 +01:00
self . send_personal_message ( sender , bot , content = " foo " )
2017-11-03 13:38:49 +01:00
last_message = self . get_last_message ( )
2018-10-10 01:36:31 +02:00
self . assertEqual ( last_message . content , " Hidley ho, I ' m a webhook responding! " )
2020-03-28 12:25:37 +01:00
self . assertEqual ( last_message . sender_id , bot . id )
2020-03-28 12:37:36 +01:00
self . assertEqual (
last_message . recipient . type_id ,
python: Use trailing commas consistently.
Automatically generated by the following script, based on the output
of lint with flake8-comma:
import re
import sys
last_filename = None
last_row = None
lines = []
for msg in sys.stdin:
m = re.match(
r"\x1b\[35mflake8 \|\x1b\[0m \x1b\[1;31m(.+):(\d+):(\d+): (\w+)", msg
)
if m:
filename, row_str, col_str, err = m.groups()
row, col = int(row_str), int(col_str)
if filename == last_filename:
assert last_row != row
else:
if last_filename is not None:
with open(last_filename, "w") as f:
f.writelines(lines)
with open(filename) as f:
lines = f.readlines()
last_filename = filename
last_row = row
line = lines[row - 1]
if err in ["C812", "C815"]:
lines[row - 1] = line[: col - 1] + "," + line[col - 1 :]
elif err in ["C819"]:
assert line[col - 2] == ","
lines[row - 1] = line[: col - 2] + line[col - 1 :].lstrip(" ")
if last_filename is not None:
with open(last_filename, "w") as f:
f.writelines(lines)
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-04-10 05:23:40 +02:00
sender . id ,
2020-03-28 12:37:36 +01:00
)
self . assertEqual (
last_message . recipient . type ,
python: Use trailing commas consistently.
Automatically generated by the following script, based on the output
of lint with flake8-comma:
import re
import sys
last_filename = None
last_row = None
lines = []
for msg in sys.stdin:
m = re.match(
r"\x1b\[35mflake8 \|\x1b\[0m \x1b\[1;31m(.+):(\d+):(\d+): (\w+)", msg
)
if m:
filename, row_str, col_str, err = m.groups()
row, col = int(row_str), int(col_str)
if filename == last_filename:
assert last_row != row
else:
if last_filename is not None:
with open(last_filename, "w") as f:
f.writelines(lines)
with open(filename) as f:
lines = f.readlines()
last_filename = filename
last_row = row
line = lines[row - 1]
if err in ["C812", "C815"]:
lines[row - 1] = line[: col - 1] + "," + line[col - 1 :]
elif err in ["C819"]:
assert line[col - 2] == ","
lines[row - 1] = line[: col - 2] + line[col - 1 :].lstrip(" ")
if last_filename is not None:
with open(last_filename, "w") as f:
f.writelines(lines)
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-04-10 05:23:40 +02:00
Recipient . PERSONAL ,
2020-03-28 12:37:36 +01:00
)
2017-11-03 13:38:49 +01:00
2021-02-12 08:19:30 +01:00
@mock.patch (
2021-02-12 08:20:45 +01:00
" requests.request " ,
2021-02-12 08:19:30 +01:00
return_value = ResponseMock (
200 , orjson . dumps ( { " response_string " : " Hidley ho, I ' m a webhook responding! " } )
) ,
)
2017-11-05 10:51:25 +01:00
def test_stream_message_to_outgoing_webhook_bot ( self , mock_requests_request : mock . Mock ) - > None :
2020-03-28 12:25:37 +01:00
bot_owner = self . example_user ( " othello " )
bot = self . create_outgoing_bot ( bot_owner )
2021-02-12 08:19:30 +01:00
self . send_stream_message (
bot_owner , " Denmark " , content = f " @** { bot . full_name } ** foo " , topic_name = " bar "
)
2017-11-03 13:38:49 +01:00
last_message = self . get_last_message ( )
2018-10-10 01:36:31 +02:00
self . assertEqual ( last_message . content , " Hidley ho, I ' m a webhook responding! " )
2020-03-28 12:25:37 +01:00
self . assertEqual ( last_message . sender_id , bot . id )
2018-11-10 16:11:12 +01:00
self . assertEqual ( last_message . topic_name ( ) , " bar " )
2017-11-03 13:38:49 +01:00
display_recipient = get_display_recipient ( last_message . recipient )
self . assertEqual ( display_recipient , " Denmark " )