mirror of https://github.com/zulip/zulip.git
management: Support sending custom headers when testing a webhook.
this commit adds an option to specify custom headers when using the `./manage.py send_webhook_fixture_message` tool.
This commit is contained in:
parent
e859ab7545
commit
99c3e2ecdc
|
@ -217,6 +217,16 @@ Using either method will create a message in Zulip:
|
|||
|
||||
<img class="screenshot" src="/static/images/api/helloworld-webhook.png" />
|
||||
|
||||
Some webhooks require custom HTTP headers, which can be passed using
|
||||
`./manage.py send_webhook_fixture_message --custom-headers`. For
|
||||
example:
|
||||
|
||||
--custom-headers='{"X-Custom-Header": "value"}'
|
||||
|
||||
The format is a JSON dictionary, so make sure that the header names do
|
||||
not contain any spaces in them and that you use the precise quoting
|
||||
approach shown above.
|
||||
|
||||
## Step 4: Create tests
|
||||
|
||||
Every webhook integration should have a corresponding test file:
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
import os
|
||||
|
||||
import ujson
|
||||
from typing import Union, Dict
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.management.base import CommandParser
|
||||
from django.test import Client
|
||||
|
@ -18,6 +18,14 @@ Example:
|
|||
--fixture=zerver/webhooks/integration/fixtures/name.json \
|
||||
'--url=/api/v1/external/integration?stream=stream_name&api_key=api_key'
|
||||
|
||||
To pass custom headers along with the webhook message use the --custom-headers
|
||||
command line option.
|
||||
Example:
|
||||
--custom-headers='{"X-Custom-Header": "value"}'
|
||||
|
||||
The format is a JSON dictionary, so make sure that the header names do
|
||||
not contain any spaces in them and that you use the precise quoting
|
||||
approach shown above.
|
||||
"""
|
||||
|
||||
def add_arguments(self, parser: CommandParser) -> None:
|
||||
|
@ -33,8 +41,30 @@ Example:
|
|||
help='The url on your Zulip server that you want '
|
||||
'to post the fixture to')
|
||||
|
||||
parser.add_argument('-H', '--custom-headers',
|
||||
dest='custom-headers',
|
||||
type=str,
|
||||
help='The headers you want to provide along with '
|
||||
'your mock request to Zulip.')
|
||||
|
||||
self.add_realm_args(parser, help="Specify which realm/subdomain to connect to; default is zulip")
|
||||
|
||||
def parse_headers(self, custom_headers: Union[None, str]) -> Union[None, Dict[str, str]]:
|
||||
headers = {}
|
||||
if not custom_headers:
|
||||
return None
|
||||
try:
|
||||
custom_headers_dict = ujson.loads(custom_headers)
|
||||
for header in custom_headers_dict:
|
||||
if len(header.split(" ")) > 1:
|
||||
raise ValueError("custom header '%s' contains a space." % (header))
|
||||
headers["HTTP_" + header.upper().replace("-", "_")] = str(custom_headers_dict[header])
|
||||
return headers
|
||||
except ValueError as ve:
|
||||
print('Encountered an error while attempting to parse custom headers: %s' % (ve))
|
||||
print('Note: all strings must be enclosed within "" instead of \'\'')
|
||||
exit(1)
|
||||
|
||||
def handle(self, **options: str) -> None:
|
||||
if options['fixture'] is None or options['url'] is None:
|
||||
self.print_help('./manage.py', 'send_webhook_fixture_message')
|
||||
|
@ -46,14 +76,19 @@ Example:
|
|||
print('Fixture {} does not exist'.format(options['fixture']))
|
||||
exit(1)
|
||||
|
||||
headers = self.parse_headers(options['custom-headers'])
|
||||
json = self._get_fixture_as_json(full_fixture_path)
|
||||
realm = self.get_realm(options)
|
||||
if realm is None:
|
||||
realm = get_realm("zulip")
|
||||
|
||||
client = Client()
|
||||
result = client.post(options['url'], json, content_type="application/json",
|
||||
HTTP_HOST=realm.host)
|
||||
if headers:
|
||||
result = client.post(options['url'], json, content_type="application/json",
|
||||
HTTP_HOST=realm.host, **headers)
|
||||
else:
|
||||
result = client.post(options['url'], json, content_type="application/json",
|
||||
HTTP_HOST=realm.host)
|
||||
if result.status_code != 200:
|
||||
print('Error status %s: %s' % (result.status_code, result.content))
|
||||
exit(1)
|
||||
|
|
|
@ -18,6 +18,7 @@ from zerver.lib.test_helpers import stdout_suppressed
|
|||
from zerver.lib.test_runner import slow
|
||||
from zerver.models import Recipient, get_user_profile_by_email, get_stream
|
||||
|
||||
from zerver.management.commands.send_webhook_fixture_message import Command
|
||||
from zerver.lib.test_helpers import most_recent_message
|
||||
from zerver.models import get_realm, UserProfile, Realm
|
||||
from confirmation.models import RealmCreationKey, generate_realm_creation_url
|
||||
|
@ -213,6 +214,29 @@ class TestSendWebhookFixtureMessage(TestCase):
|
|||
client.post.assert_called_once_with(self.url, {}, content_type="application/json",
|
||||
HTTP_HOST="zulip.testserver")
|
||||
|
||||
@patch('zerver.management.commands.send_webhook_fixture_message.Command._get_fixture_as_json')
|
||||
@patch('zerver.management.commands.send_webhook_fixture_message.Command._does_fixture_path_exist')
|
||||
@patch('zerver.management.commands.send_webhook_fixture_message.Command.parse_headers')
|
||||
def test_check_post_request_with_improper_custom_header(self,
|
||||
parse_headers_mock: MagicMock,
|
||||
does_fixture_path_exist_mock: MagicMock,
|
||||
get_fixture_as_json_mock: MagicMock) -> None:
|
||||
does_fixture_path_exist_mock.return_value = True
|
||||
get_fixture_as_json_mock.return_value = "{}"
|
||||
|
||||
improper_headers = '{"X-Custom - Headers": "some_val"}'
|
||||
with self.assertRaises(SystemExit) as se:
|
||||
call_command(self.COMMAND_NAME, fixture=self.fixture_path, url=self.url, custom_headers=improper_headers)
|
||||
|
||||
parse_headers_mock.assert_called_once_with(improper_headers)
|
||||
|
||||
def test_parse_headers_method(self) -> None:
|
||||
command = Command()
|
||||
self.assertEqual(command.parse_headers(None), None)
|
||||
self.assertEqual(command.parse_headers('{"X-Custom-Header": "value"}'), {"HTTP_X_CUSTOM_HEADER": "value"})
|
||||
with self.assertRaises(SystemExit):
|
||||
command.parse_headers('{"X-Custom - Headers": "some_val"}')
|
||||
|
||||
class TestGenerateRealmCreationLink(ZulipTestCase):
|
||||
COMMAND_NAME = "generate_realm_creation_link"
|
||||
|
||||
|
|
Loading…
Reference in New Issue