bot tests: Allow raw responses in fixtures.

Previously, the responses set in bot test fixtures
where handled as JSON objects. This works fine for
most bot tests, because most of the APIs that bots
are calling return a JSON-formatted response object.
However, some, like Trello, do return raw data.
This hasn't been noticed so far, because the respective
Trello test needed internet access. Tests shouldn't
need internet access.
This commit makes that Trello test use a fixture. To
work properly, it also adds a way to make http_mock_config
parse the response object as raw data.
This can now be done by modifying the "is_raw_response"
property in a newly introduced "meta" object that can
be used to specify how a fixture should be handled.
This commit is contained in:
Robert Hönig 2018-06-04 18:22:22 +02:00 committed by Tim Abbott
parent e638cdd4a9
commit 60c3919deb
3 changed files with 37 additions and 12 deletions

View file

@ -0,0 +1,15 @@
{
"meta": {
"is_raw_response": true
},
"request": {
"api_url": "https://api.trello.com/1/members/TEST/",
"params": {
"key": "TEST",
"token": "TEST"
}
},
"response": "invalid key",
"response-headers": {
}
}

View file

@ -27,7 +27,8 @@ class TestTrelloBot(BotTestCase):
def test_bot_quit_with_invalid_config(self) -> None:
with self.mock_config_info(mock_config), self.assertRaises(StubBotHandler.BotQuitException):
TrelloHandler().initialize(StubBotHandler())
with self.mock_http_conversation('invalid_key'):
TrelloHandler().initialize(StubBotHandler())
def test_invalid_command(self) -> None:
with self.mock_config_info(mock_config), patch('requests.get'):

View file

@ -18,18 +18,21 @@ def mock_http_conversation(http_data):
http_data should be fixtures data formatted like the data
in zulip_bots/zulip_bots/bots/giphy/fixtures/test_normal.json
"""
def get_response(http_response, http_headers):
# type: (Dict[str, Any], Dict[str, Any]) -> Any
def get_response(http_response, http_headers, is_raw_response):
# type: (Dict[str, Any], Dict[str, Any], bool) -> Any
"""Creates a fake `requests` Response with a desired HTTP response and
response headers.
"""
mock_result = requests.Response()
mock_result._content = json.dumps(http_response).encode() # type: ignore # This modifies a "hidden" attribute.
if is_raw_response:
mock_result._content = http_response.encode() # type: ignore # This modifies a "hidden" attribute.
else:
mock_result._content = json.dumps(http_response).encode() # type: ignore # See above.
mock_result.status_code = http_headers.get('status', 200)
return mock_result
def assert_called_with_fields(mock_result, http_request, fields):
# type: (Any, Dict[str, Any], List[str]) -> None
def assert_called_with_fields(mock_result, http_request, fields, meta):
# type: (Any, Dict[str, Any], List[str], Dict[str, Any]) -> None
"""Calls `assert_called_with` on a mock object using an HTTP request.
Uses `fields` to determine which keys to look for in HTTP request and
to test; if a key is in `fields`, e.g., 'headers', it will be used in
@ -51,34 +54,40 @@ def mock_http_conversation(http_data):
print("ERROR: Failed to find 'request', 'response' or 'response-headers' fields in fixture")
raise
meta = http_data.get('meta', dict())
is_raw_response = meta.get('is_raw_response', False)
http_method = http_request.get('method', 'GET')
if http_method == 'GET':
with patch('requests.get') as mock_get:
mock_get.return_value = get_response(http_response, http_headers)
mock_get.return_value = get_response(http_response, http_headers, is_raw_response)
yield
assert_called_with_fields(
mock_get,
http_request,
['params', 'headers']
['params', 'headers'],
meta
)
elif http_method == 'PATCH':
with patch('requests.patch') as mock_patch:
mock_patch.return_value = get_response(http_response, http_headers)
mock_patch.return_value = get_response(http_response, http_headers, is_raw_response)
yield
assert_called_with_fields(
mock_patch,
http_request,
['params', 'headers', 'json', 'data']
['params', 'headers', 'json', 'data'],
meta
)
else:
with patch('requests.post') as mock_post:
mock_post.return_value = get_response(http_response, http_headers)
mock_post.return_value = get_response(http_response, http_headers, is_raw_response)
yield
assert_called_with_fields(
mock_post,
http_request,
['params', 'headers', 'json', 'data']
['params', 'headers', 'json', 'data'],
meta
)
@contextmanager