Source code for argus_api.helpers.tests
"""Test helpers for the API"""
import requests_mock
from faker import Faker
RANDOMIZE = Faker()
[docs]def response(url: str, status_code: int = 200, method: str = 'GET', json=None) -> callable:
"""Creates a decorator that can be used to mock the given URL
and intercept calls to it with a response of the given status code
and JSON.
:param str url: URL to intercept
:param int status_code: HTTP status to respond with
:param dict json: JSON body to respond with (optional)
"""
def decorator(function):
"""Mock {url}, respond with HTTP {status_code}""".format(url=url, status_code=status_code)
def mock_response(*args, **kwargs):
print(url)
with requests_mock.Mocker(real_http=True) as mock:
mock.register_uri(method.upper(), url, status_code=status_code, json=json)
return function(*args, **kwargs)
return mock_response
return decorator
[docs]def fake_response(response_definition, key=None):
"""Recursive method that traverses a dict response and generates
fake data for each key, faking a successful response
"""
from random import choice
def is_leaf(response_definition):
# If it ONLY has a type key, and nothing else,
# this is a leaf and we should generate fake data for it
if isinstance(response_definition, dict):
if ("type",) == tuple(response_definition.keys()):
return True
# If it has several keys, but no children that have a "type"
# key of their own, this is also a leaf
if not any(
filter(lambda x: "type" in x, [
value for key, value in response_definition.items()
if isinstance(value, dict)
])):
return True
# Lists count as leaves as well
if "type" in response_definition and response_definition["type"] == "list":
return True
return not response_definition
# If the definition only contains type, we can replace this
# object with fake data of that type
if is_leaf(response_definition) and response_definition:
if response_definition["type"] == 'str' and "enum" in response_definition:
return choice(response_definition["enum"])
elif response_definition["type"] == "list" and "items" in response_definition:
return [fake_response(response_definition["items"])]
elif response_definition["type"] == "dict":
if "items" in response_definition:
return fake_response(response_definition["items"])
return {}
else:
if key and \
(key.lower() in ("username", "email", "link", "url", "name", "responsecode") \
or "timestamp" in key.lower()):
return fake_data_for(key)
else:
return fake_data_for(response_definition["type"])
elif isinstance(response_definition, dict):
return {
key: fake_response(value, key)
for key, value in response_definition.items()
if isinstance(value, dict) and "type" in value
}
else:
return response_definition
[docs]def fake_data_for(python_type: str):
"""Generates fake data for a given type, where type can be any basic python type,
such as int, str, float, bool; but it also supports more specific types, such as
url, username, and email
:param str python_type: String representation of python type
:returns: Generated fake value
"""
from random import randint, uniform
python_type = python_type.lower()
if python_type == 'int':
return randint(0, 1000)
elif python_type == 'bool':
return bool(randint(0, 1))
elif python_type == 'float':
return uniform(0, 100)
elif python_type == 'None':
return None
elif python_type == "responsecode":
# Always return successful response since otherwise
# we wouldnt get a response anyway
return 200
elif python_type == 'username':
return RANDOMIZE.user_name()
elif "timestamp" in python_type:
return RANDOMIZE.unix_time()
else:
if hasattr(RANDOMIZE, python_type):
return getattr(RANDOMIZE, python_type)()
else:
return RANDOMIZE.sentence()