summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Finucane <stephen@that.guru>2018-10-28 14:40:31 +0000
committerStephen Finucane <stephen@that.guru>2018-12-22 16:13:26 +0000
commit7274953d3523f179b3fdd4a164632c595be75bd2 (patch)
tree1ae4e0a4bc7be8c646b22bf484bcb21ec99b0f66
parent3b12675c88ce81800df9e0921f299cf2a082b2aa (diff)
downloadpatchwork-7274953d3523f179b3fdd4a164632c595be75bd2.tar
patchwork-7274953d3523f179b3fdd4a164632c595be75bd2.tar.gz
tests: Add 'store_samples' decorator
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 <stephen@that.guru>
-rw-r--r--.gitignore1
-rw-r--r--patchwork/tests/api/utils.py93
2 files changed, 94 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index a33d102..1282bc9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -44,6 +44,7 @@ htmlcov/
# Sphinx stuff
/docs/_build
+/docs/api/samples
# Selenium test artifacts
/selenium.log
diff --git a/patchwork/tests/api/utils.py b/patchwork/tests/api/utils.py
new file mode 100644
index 0000000..1097bb0
--- /dev/null
+++ b/patchwork/tests/api/utils.py
@@ -0,0 +1,93 @@
+# Patchwork - automated patch tracking system
+# Copyright (C) 2018 Stephen Finucane <stephen@that.guru>
+#
+# 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