Skip to content

Instantly share code, notes, and snippets.

@pinge
Last active February 4, 2016 00:04
Show Gist options
  • Save pinge/98bb86f597f62e1c51b4 to your computer and use it in GitHub Desktop.
Save pinge/98bb86f597f62e1c51b4 to your computer and use it in GitHub Desktop.
# -*- coding: utf-8 -*-
import json
import requests.models
from deepdiff import DeepDiff
def validate_status_code(response, status_code):
"""
validates status code based on the client library used to make the request.
currently supports:
- requests
@type response: requests.models.Response
@param response: the requests response instance
@type status_code: int
@param status_code: the status code expected in the response
@rtype: tuple(bool, dict)
@rparam: a tuple with the validation outcome (bool) and its details (dict: message, diff)
"""
if isinstance(response, requests.models.Response):
return (status_code == response.status_code, {
'message': """
=> [expected status code]
{:d}
=> [response status code]
{:d}
""".format(status_code, response.status_code)
})
else:
raise NotImplementedError("status code: '{}' http client response support is not implemented".format(str(type(response))))
def validate_presence_of(response, payload):
"""
validates partial response payload from the client library used to make the request.
http clients currently supported:
- requests
if no Content Type header is set in the response, the validation defaults to a simple string comparison because
RFC 822 says that text/plain should be used. from https://www.w3.org/Protocols/rfc1341/4_Content-Type.html:
| Default RFC 822 messages are typed by this protocol as plain text in the US-ASCII character set, which can be
| explicitly specified as "Content-type: text/plain; charset=us-ascii". If no Content-Type is specified, either
| by error or by an older user agent, this default is assumed.
@type response: requests.models.Response
@param response: the requests response instance
@type payload: dict, str
@param payload: the payload expected in response
"""
if not isinstance(response, requests.models.Response):
raise NotImplementedError("presence of: '{}' http client response support is not implemented".
format(str(type(response))))
content_type = response.headers.get('Content-Type', 'text/plain; charset=us-ascii')
if not content_type.startswith('application/json') and not content_type.startswith('text/plain'):
raise NotImplementedError("presence of: support for responses with Content Type '{}' not implemented".
format(str(type(response))))
if content_type.startswith('application/json'):
try:
json_response = json.loads(response.text)
json_payload_validation = __unicode_dict(payload)
diff = DeepDiff(json_payload_validation, json_response)
return ('dic_item_removed' not in diff and 'type_changes' not in diff and 'values_changed' not in diff,
{
'message': """
=> [expected payload]
{}
=> [response payload]
{}
=> [payload diff]
{}
""".format(json.dumps(json_payload_validation, indent=4), json.dumps(json_response, indent=4),
json.dumps(diff, indent=4)),
'payload': json_payload_validation,
'response': json_response,
'diff': diff
})
except ValueError:
return False, {'message': 'malformed JSON response:\n\n{}'.format(response.text)}
elif content_type.startswith('text/plain'):
return (response.text == payload, {
'message': """
=> [expected payload]
{}
=> [response payload]
{}
""".format(payload, response.text)
})
def __to_unicode(d):
"""
This private method is used as a helper to update every 'str' value in the dictionary 'd' to 'unicode'. This is
merely for convenience purposes, we can use this method to avoid being pedantic when declaring validation payloads
@type d: dict or list
@param d: the dictionary or the list to update
@rtype: dict
@rparam: the updated dictionary or list with every 'str' value cast to 'unicode'
"""
if isinstance(d, dict):
for k, v in d.iteritems():
if isinstance(v, dict) or isinstance(v, list):
__to_unicode(v)
elif isinstance(v, str):
d[k] = unicode(v)
elif isinstance(d, list):
for i, value in enumerate(d):
if isinstance(value, basestring):
d[i] = unicode(value)
elif isinstance(value, dict) or isinstance(value, list):
d[i] == __to_unicode(value)
return d
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment