Skip to content

Commit

Permalink
tests: Add 'store_samples' decorator
Browse files Browse the repository at this point in the history
We want to start including sample API requests and responses in our
documentation.  Given that these may get out of date over time, we
should really generate these things dynamically. Create a decorator that
will allow us to do just that.

Signed-off-by: Stephen Finucane <[email protected]>
  • Loading branch information
stephenfin committed Dec 22, 2018
1 parent 3b12675 commit 7274953
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ htmlcov/

# Sphinx stuff
/docs/_build
/docs/api/samples

# Selenium test artifacts
/selenium.log
Expand Down
93 changes: 93 additions & 0 deletions patchwork/tests/api/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# Patchwork - automated patch tracking system
# Copyright (C) 2018 Stephen Finucane <[email protected]>
#
# SPDX-License-Identifier: GPL-2.0-or-later

import functools
import json
import os

# docs/examples
OUT_DIR = os.path.join(
os.path.dirname(os.path.abspath(__file__)), os.pardir, os.pardir,
os.pardir, 'docs', 'api', 'samples')

_WRITTEN_FILES = {}


def _duplicate_sample(filename, func):
global _WRITTEN_FILES

# sanity check to make sure we're not writing to the same file
# twice
if filename in _WRITTEN_FILES:
# though if tests do this, we simply ignore subsequent
# writes
if _WRITTEN_FILES[filename] == func:
return True

raise Exception(
"Tests '{}' and '{}' write to the same file".format(
_WRITTEN_FILES[filename], func))

_WRITTEN_FILES[filename] = func

return False


def store_samples(filename):
"""Wrapper to store responses and requests generated in tests.
These can be used in documentation. Only the first response or request body
is saved per test.
"""

if not os.path.exists(OUT_DIR):
os.mkdir(OUT_DIR)

def inner(func):

def wrapper(self, *args, **kwargs):

def client_wrapper(orig_func, path, data=None, *orig_args,
**orig_kwargs):

req_filename = filename + '-req.json'
resp_filename = filename + '-resp.json'

# we don't have a request body for GET requests
if orig_func != _get and not _duplicate_sample(
req_filename, func):
with open(os.path.join(OUT_DIR, req_filename), 'w') as fh:
json.dump(data, fh, indent=4, separators=(',', ': '))

resp = orig_func(path, data, *orig_args, **orig_kwargs)

if not _duplicate_sample(resp_filename, func):
with open(os.path.join(OUT_DIR, resp_filename), 'w') as fh:
json.dump(resp.data, fh, indent=4,
separators=(',', ': '))

return resp

# replace client.* with our own implementations
_get = self.client.get
self.client.get = functools.partial(client_wrapper, _get)
_post = self.client.post
self.client.post = functools.partial(client_wrapper, _post)
_put = self.client.put
self.client.put = functools.partial(client_wrapper, _put)
_patch = self.client.patch
self.client.patch = functools.partial(client_wrapper, _patch)

func(self, *args, **kwargs)

# ...then reverse
self.client.patch = _patch
self.client.put = _put
self.client.post = _post
self.client.get = _get

return wrapper

return inner

0 comments on commit 7274953

Please sign in to comment.