Changeset View
Changeset View
Standalone View
Standalone View
swh/web/tests/api/test_apidoc.py
# Copyright (C) 2015-2019 The Software Heritage developers | # Copyright (C) 2015-2019 The Software Heritage developers | ||||
# See the AUTHORS file at the top-level directory of this distribution | # See the AUTHORS file at the top-level directory of this distribution | ||||
# License: GNU Affero General Public License version 3, or any later version | # License: GNU Affero General Public License version 3, or any later version | ||||
# See top-level LICENSE file for more information | # See top-level LICENSE file for more information | ||||
import pytest | import pytest | ||||
from rest_framework.response import Response | from rest_framework.response import Response | ||||
from swh.storage.exc import StorageDBError, StorageAPIError | from swh.storage.exc import StorageDBError, StorageAPIError | ||||
from swh.web.api.apidoc import api_doc, _parse_httpdomain_doc | from swh.web.api.apidoc import api_doc, _parse_httpdomain_doc | ||||
from swh.web.api.apiurls import api_route | from swh.web.api.apiurls import api_route | ||||
from swh.web.common.exc import BadInputExc, ForbiddenExc, NotFoundExc | from swh.web.common.exc import BadInputExc, ForbiddenExc, NotFoundExc | ||||
from swh.web.common.utils import reverse | from swh.web.common.utils import reverse | ||||
from swh.web.tests.django_asserts import assert_template_used | from swh.web.tests.django_asserts import assert_template_used, assert_contains | ||||
httpdomain_doc = """ | _httpdomain_doc = """ | ||||
.. http:get:: /api/1/revision/(sha1_git)/ | .. http:get:: /api/1/revision/(sha1_git)/ | ||||
Get information about a revision in the archive. | Get information about a revision in the archive. | ||||
Revisions are identified by **sha1** checksums, compatible with Git commit | Revisions are identified by **sha1** checksums, compatible with Git commit | ||||
identifiers. | identifiers. | ||||
See :func:`swh.model.identifiers.revision_identifier` in our data model | See :func:`swh.model.identifiers.revision_identifier` in our data model | ||||
module for details about how they are computed. | module for details about how they are computed. | ||||
:param string sha1_git: hexadecimal representation of the revision | :param string sha1_git: hexadecimal representation of the revision | ||||
**sha1_git** identifier | **sha1_git** identifier | ||||
:reqheader Accept: the requested response content type, | :reqheader Accept: the requested response content type, | ||||
either ``application/json`` (default) or ``application/yaml`` | either ``application/json`` (default) or ``application/yaml`` | ||||
:resheader Content-Type: this depends on :http:header:`Accept` header | :resheader Content-Type: this depends on :http:header:`Accept` header | ||||
of request | of request | ||||
:<json int n: sample input integer | |||||
:<json string s: sample input string | |||||
:<json array a: sample input array | |||||
:>json object author: information about the author of the revision | :>json object author: information about the author of the revision | ||||
:>json object committer: information about the committer of the revision | :>json object committer: information about the committer of the revision | ||||
:>json string committer_date: ISO representation of the commit date | :>json string committer_date: ISO representation of the commit date | ||||
(in UTC) | (in UTC) | ||||
:>json string date: ISO representation of the revision date (in UTC) | :>json string date: ISO representation of the revision date (in UTC) | ||||
:>json string directory: the unique identifier that revision points to | :>json string directory: the unique identifier that revision points to | ||||
:>json string directory_url: link to | :>json string directory_url: link to | ||||
:http:get:`/api/1/directory/(sha1_git)/[(path)/]` to get information | :http:get:`/api/1/directory/(sha1_git)/[(path)/]` to get information | ||||
Show All 18 Lines | .. http:get:: /api/1/revision/(sha1_git)/ | ||||
**Request:** | **Request:** | ||||
.. parsed-literal:: | .. parsed-literal:: | ||||
:swh_web_api:`revision/aafb16d69fd30ff58afdd69036a26047f3aebdc6/` | :swh_web_api:`revision/aafb16d69fd30ff58afdd69036a26047f3aebdc6/` | ||||
""" | """ | ||||
exception_http_code = { | _exception_http_code = { | ||||
BadInputExc: 400, | BadInputExc: 400, | ||||
ForbiddenExc: 403, | ForbiddenExc: 403, | ||||
NotFoundExc: 404, | NotFoundExc: 404, | ||||
Exception: 500, | Exception: 500, | ||||
StorageAPIError: 503, | StorageAPIError: 503, | ||||
StorageDBError: 503, | StorageDBError: 503, | ||||
} | } | ||||
Show All 31 Lines | |||||
@api_route(r'/test/error/(?P<exc_name>.+)/', 'api-1-test-error') | @api_route(r'/test/error/(?P<exc_name>.+)/', 'api-1-test-error') | ||||
@api_doc('/test/error/') | @api_doc('/test/error/') | ||||
def apidoc_test_error_route(request, exc_name): | def apidoc_test_error_route(request, exc_name): | ||||
""" | """ | ||||
Sample doc | Sample doc | ||||
""" | """ | ||||
for e in exception_http_code.keys(): | for e in _exception_http_code.keys(): | ||||
if e.__name__ == exc_name: | if e.__name__ == exc_name: | ||||
raise e('Error') | raise e('Error') | ||||
def test_apidoc_error(api_client): | def test_apidoc_error(api_client): | ||||
for exc, code in exception_http_code.items(): | for exc, code in _exception_http_code.items(): | ||||
url = reverse('api-1-test-error', | url = reverse('api-1-test-error', | ||||
url_args={'exc_name': exc.__name__}) | url_args={'exc_name': exc.__name__}) | ||||
rv = api_client.get(url) | rv = api_client.get(url) | ||||
assert rv.status_code == code, rv.data | assert rv.status_code == code, rv.data | ||||
@api_route(r'/some/full/(?P<myarg>[0-9]+)/(?P<myotherarg>[0-9]+)/', | @api_route(r'/some/full/(?P<myarg>[0-9]+)/(?P<myotherarg>[0-9]+)/', | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | |||||
def test_api_doc_parse_httpdomain(): | def test_api_doc_parse_httpdomain(): | ||||
doc_data = { | doc_data = { | ||||
'description': '', | 'description': '', | ||||
'urls': [], | 'urls': [], | ||||
'args': [], | 'args': [], | ||||
'params': [], | 'params': [], | ||||
'resheaders': [], | 'resheaders': [], | ||||
'reqheaders': [], | 'reqheaders': [], | ||||
'input_type': '', | |||||
'inputs': [], | |||||
'return_type': '', | 'return_type': '', | ||||
'returns': [], | 'returns': [], | ||||
'status_codes': [], | 'status_codes': [], | ||||
'examples': [] | 'examples': [] | ||||
} | } | ||||
_parse_httpdomain_doc(httpdomain_doc, doc_data) | _parse_httpdomain_doc(_httpdomain_doc, doc_data) | ||||
expected_urls = [{ | expected_urls = [{ | ||||
'rule': '/api/1/revision/ **\\(sha1_git\\)** /', | 'rule': '/api/1/revision/ **\\(sha1_git\\)** /', | ||||
'methods': ['GET', 'HEAD'] | 'methods': ['GET', 'HEAD'] | ||||
}] | }] | ||||
assert 'urls' in doc_data | assert 'urls' in doc_data | ||||
assert doc_data['urls'] == expected_urls | assert doc_data['urls'] == expected_urls | ||||
▲ Show 20 Lines • Show All 52 Lines • ▼ Show 20 Lines | expected_statuscodes = [ | ||||
'code': '404', | 'code': '404', | ||||
'doc': 'requested revision can not be found in the archive' | 'doc': 'requested revision can not be found in the archive' | ||||
} | } | ||||
] | ] | ||||
assert 'status_codes' in doc_data | assert 'status_codes' in doc_data | ||||
assert doc_data['status_codes'] == expected_statuscodes | assert doc_data['status_codes'] == expected_statuscodes | ||||
expected_input_type = 'object' | |||||
assert 'input_type' in doc_data | |||||
assert doc_data['input_type'] == expected_input_type | |||||
expected_inputs = [ | |||||
{ | |||||
'name': 'n', | |||||
'type': 'int', | |||||
'doc': 'sample input integer' | |||||
}, | |||||
{ | |||||
'name': 's', | |||||
'type': 'string', | |||||
'doc': 'sample input string' | |||||
}, | |||||
{ | |||||
'name': 'a', | |||||
'type': 'array', | |||||
'doc': 'sample input array' | |||||
}, | |||||
] | |||||
assert 'inputs' in doc_data | |||||
assert doc_data['inputs'] == expected_inputs | |||||
expected_return_type = 'object' | expected_return_type = 'object' | ||||
assert 'return_type' in doc_data | assert 'return_type' in doc_data | ||||
assert doc_data['return_type'] in expected_return_type | assert doc_data['return_type'] == expected_return_type | ||||
expected_returns = [ | expected_returns = [ | ||||
{ | { | ||||
'name': 'author', | 'name': 'author', | ||||
'type': 'object', | 'type': 'object', | ||||
'doc': 'information about the author of the revision' | 'doc': 'information about the author of the revision' | ||||
}, | }, | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | def test_api_doc_parse_httpdomain(): | ||||
assert doc_data['returns'] == expected_returns | assert doc_data['returns'] == expected_returns | ||||
expected_examples = [ | expected_examples = [ | ||||
'/api/1/revision/aafb16d69fd30ff58afdd69036a26047f3aebdc6/' | '/api/1/revision/aafb16d69fd30ff58afdd69036a26047f3aebdc6/' | ||||
] | ] | ||||
assert 'examples' in doc_data | assert 'examples' in doc_data | ||||
assert doc_data['examples'] == expected_examples | assert doc_data['examples'] == expected_examples | ||||
@api_route(r'/post/endpoint/', 'api-1-post-endpoint', | |||||
methods=['POST']) | |||||
@api_doc('/post/endpoint/') | |||||
def apidoc_test_post_endpoint(request): | |||||
""" | |||||
.. http:post:: /api/1/post/endpoint/ | |||||
Endpoint documentation | |||||
:<jsonarr string -: Input array of pids | |||||
:>jsonarr string type: swh object type | |||||
:>jsonarr string sha1_git: swh object sha1_git | |||||
:>jsonarr boolean found: whether the object was found or not | |||||
""" | |||||
pass | |||||
def test_apidoc_input_output_doc(client): | |||||
url = reverse('api-1-post-endpoint-doc') | |||||
rv = client.get(url, HTTP_ACCEPT='text/html') | |||||
assert rv.status_code == 200, rv.content | |||||
assert_template_used(rv, 'api/apidoc.html') | |||||
input_html_doc = ( | |||||
' <dl class="row">\n' | |||||
' <dt class="col col-md-2 text-right"> array </dt>\n' | |||||
' <dd class="col col-md-9">\n' | |||||
' <p>\n' | |||||
' \n' | |||||
' Input array of pids\n' | |||||
' \n' | |||||
' \n' | |||||
' </p>\n' | |||||
' </dd>\n' | |||||
' </dl>\n' | |||||
) | |||||
output_html_doc = ( | |||||
' <dl class="row">\n' | |||||
' <dt class="col col-md-2 text-right"> array </dt>\n' | |||||
' <dd class="col col-md-9">\n' | |||||
' <p>\n' | |||||
' \n' | |||||
' an array of objects containing the following keys:\n' | |||||
' \n' | |||||
' \n' | |||||
' <div class="swh-rst"><ul class="simple">\n' | |||||
'<li><p><strong>type (string)</strong>: swh object type</p></li>\n' | |||||
'<li><p><strong>sha1_git (string)</strong>: swh object sha1_git</p></li>\n' # noqa | |||||
'<li><p><strong>found (boolean)</strong>: whether the object was found or not</p></li>\n' # noqa | |||||
'</ul>\n' | |||||
'</div>\n' | |||||
' \n' | |||||
' </p>\n' | |||||
' </dd>\n' | |||||
' </dl>' | |||||
) | |||||
assert_contains(rv, input_html_doc) | |||||
assert_contains(rv, output_html_doc) |