Page Menu
Home
Software Heritage
Search
Configure Global Search
Log In
Files
F9123612
test_apidoc.py
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
13 KB
Subscribers
None
test_apidoc.py
View Options
# Copyright (C) 2015-2019 The Software Heritage developers
# See the AUTHORS file at the top-level directory of this distribution
# License: GNU Affero General Public License version 3, or any later version
# See top-level LICENSE file for more information
import
textwrap
import
pytest
from
rest_framework.response
import
Response
from
swh.storage.exc
import
StorageDBError
,
StorageAPIError
from
swh.web.api.apidoc
import
api_doc
,
_parse_httpdomain_doc
from
swh.web.api.apiurls
import
api_route
from
swh.web.common.exc
import
BadInputExc
,
ForbiddenExc
,
NotFoundExc
from
swh.web.common.utils
import
reverse
,
prettify_html
from
swh.web.tests.django_asserts
import
assert_template_used
_httpdomain_doc
=
"""
.. http:get:: /api/1/revision/(sha1_git)/
Get information about a revision in the archive.
Revisions are identified by **sha1** checksums, compatible with Git commit
identifiers.
See :func:`swh.model.identifiers.revision_identifier` in our data model
module for details about how they are computed.
:param string sha1_git: hexadecimal representation of the revision
**sha1_git** identifier
:reqheader Accept: the requested response content type,
either ``application/json`` (default) or ``application/yaml``
:resheader Content-Type: this depends on :http:header:`Accept` header
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 committer: information about the committer of the revision
:>json string committer_date: ISO representation of the commit 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_url: link to
:http:get:`/api/1/directory/(sha1_git)/[(path)/]` to get information
about the directory associated to the revision
:>json string id: the revision unique identifier
:>json boolean merge: whether or not the revision corresponds to a merge
commit
:>json string message: the message associated to the revision
:>json array parents: the parents of the revision, i.e. the previous
revisions that head directly to it, each entry of that array contains
an unique parent revision identifier but also a link to
:http:get:`/api/1/revision/(sha1_git)/` to get more information
about it
:>json string type: the type of the revision
**Allowed HTTP Methods:** :http:method:`get`, :http:method:`head`
:statuscode 200: no error
:statuscode 400: an invalid **sha1_git** value has been provided
:statuscode 404: requested revision can not be found in the archive
**Request:**
.. parsed-literal::
:swh_web_api:`revision/aafb16d69fd30ff58afdd69036a26047f3aebdc6/`
"""
_exception_http_code
=
{
BadInputExc
:
400
,
ForbiddenExc
:
403
,
NotFoundExc
:
404
,
Exception
:
500
,
StorageAPIError
:
503
,
StorageDBError
:
503
,
}
def
test_apidoc_nodoc_failure
():
with
pytest
.
raises
(
Exception
):
@api_doc
(
'/my/nodoc/url/'
)
def
apidoc_nodoc_tester
(
request
,
arga
=
0
,
argb
=
0
):
return
Response
(
arga
+
argb
)
@api_route
(
r'/some/(?P<myarg>[0-9]+)/(?P<myotherarg>[0-9]+)/'
,
'api-1-some-doc-route'
)
@api_doc
(
'/some/doc/route/'
)
def
apidoc_route
(
request
,
myarg
,
myotherarg
,
akw
=
0
):
"""
Sample doc
"""
return
{
'result'
:
int
(
myarg
)
+
int
(
myotherarg
)
+
akw
}
def
test_apidoc_route_doc
(
client
):
url
=
reverse
(
'api-1-some-doc-route-doc'
)
rv
=
client
.
get
(
url
,
HTTP_ACCEPT
=
'text/html'
)
assert
rv
.
status_code
==
200
,
rv
.
content
assert_template_used
(
rv
,
'api/apidoc.html'
)
def
test_apidoc_route_fn
(
api_client
):
url
=
reverse
(
'api-1-some-doc-route'
,
url_args
=
{
'myarg'
:
1
,
'myotherarg'
:
1
})
rv
=
api_client
.
get
(
url
)
assert
rv
.
status_code
==
200
,
rv
.
data
@api_route
(
r'/test/error/(?P<exc_name>.+)/'
,
'api-1-test-error'
)
@api_doc
(
'/test/error/'
)
def
apidoc_test_error_route
(
request
,
exc_name
):
"""
Sample doc
"""
for
e
in
_exception_http_code
.
keys
():
if
e
.
__name__
==
exc_name
:
raise
e
(
'Error'
)
def
test_apidoc_error
(
api_client
):
for
exc
,
code
in
_exception_http_code
.
items
():
url
=
reverse
(
'api-1-test-error'
,
url_args
=
{
'exc_name'
:
exc
.
__name__
})
rv
=
api_client
.
get
(
url
)
assert
rv
.
status_code
==
code
,
rv
.
data
@api_route
(
r'/some/full/(?P<myarg>[0-9]+)/(?P<myotherarg>[0-9]+)/'
,
'api-1-some-complete-doc-route'
)
@api_doc
(
'/some/complete/doc/route/'
)
def
apidoc_full_stack
(
request
,
myarg
,
myotherarg
,
akw
=
0
):
"""
Sample doc
"""
return
{
'result'
:
int
(
myarg
)
+
int
(
myotherarg
)
+
akw
}
def
test_apidoc_full_stack_doc
(
client
):
url
=
reverse
(
'api-1-some-complete-doc-route-doc'
)
rv
=
client
.
get
(
url
,
HTTP_ACCEPT
=
'text/html'
)
assert
rv
.
status_code
==
200
,
rv
.
content
assert_template_used
(
rv
,
'api/apidoc.html'
)
def
test_apidoc_full_stack_fn
(
api_client
):
url
=
reverse
(
'api-1-some-complete-doc-route'
,
url_args
=
{
'myarg'
:
1
,
'myotherarg'
:
1
})
rv
=
api_client
.
get
(
url
)
assert
rv
.
status_code
==
200
,
rv
.
data
@api_route
(
r'/test/post/only/'
,
'api-1-test-post-only'
,
methods
=
[
'POST'
])
@api_doc
(
'/test/post/only/'
)
def
apidoc_test_post_only
(
request
,
exc_name
):
"""
Sample doc
"""
return
{
'result'
:
'some data'
}
def
test_apidoc_post_only
(
client
):
# a dedicated view accepting GET requests should have
# been created to display the HTML documentation
url
=
reverse
(
'api-1-test-post-only-doc'
)
rv
=
client
.
get
(
url
,
HTTP_ACCEPT
=
'text/html'
)
assert
rv
.
status_code
==
200
,
rv
.
content
assert_template_used
(
rv
,
'api/apidoc.html'
)
def
test_api_doc_parse_httpdomain
():
doc_data
=
{
'description'
:
''
,
'urls'
:
[],
'args'
:
[],
'params'
:
[],
'resheaders'
:
[],
'reqheaders'
:
[],
'input_type'
:
''
,
'inputs'
:
[],
'return_type'
:
''
,
'returns'
:
[],
'status_codes'
:
[],
'examples'
:
[]
}
_parse_httpdomain_doc
(
_httpdomain_doc
,
doc_data
)
expected_urls
=
[{
'rule'
:
'/api/1/revision/ **
\\
(sha1_git
\\
)** /'
,
'methods'
:
[
'GET'
,
'HEAD'
]
}]
assert
'urls'
in
doc_data
assert
doc_data
[
'urls'
]
==
expected_urls
expected_description
=
(
'Get information about a revision in the archive. '
'Revisions are identified by **sha1** checksums, '
'compatible with Git commit identifiers. See '
'**swh.model.identifiers.revision_identifier** in '
'our data model module for details about how they '
'are computed.'
)
assert
'description'
in
doc_data
assert
doc_data
[
'description'
]
==
expected_description
expected_args
=
[{
'name'
:
'sha1_git'
,
'type'
:
'string'
,
'doc'
:
(
'hexadecimal representation of the revision '
'**sha1_git** identifier'
)
}]
assert
'args'
in
doc_data
assert
doc_data
[
'args'
]
==
expected_args
expected_params
=
[]
assert
'params'
in
doc_data
assert
doc_data
[
'params'
]
==
expected_params
expected_reqheaders
=
[{
'doc'
:
(
'the requested response content type, either '
'``application/json`` (default) or ``application/yaml``'
),
'name'
:
'Accept'
}]
assert
'reqheaders'
in
doc_data
assert
doc_data
[
'reqheaders'
]
==
expected_reqheaders
expected_resheaders
=
[{
'doc'
:
'this depends on **Accept** header of request'
,
'name'
:
'Content-Type'
}]
assert
'resheaders'
in
doc_data
assert
doc_data
[
'resheaders'
]
==
expected_resheaders
expected_statuscodes
=
[
{
'code'
:
'200'
,
'doc'
:
'no error'
},
{
'code'
:
'400'
,
'doc'
:
'an invalid **sha1_git** value has been provided'
},
{
'code'
:
'404'
,
'doc'
:
'requested revision can not be found in the archive'
}
]
assert
'status_codes'
in
doc_data
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'
assert
'return_type'
in
doc_data
assert
doc_data
[
'return_type'
]
==
expected_return_type
expected_returns
=
[
{
'name'
:
'author'
,
'type'
:
'object'
,
'doc'
:
'information about the author of the revision'
},
{
'name'
:
'committer'
,
'type'
:
'object'
,
'doc'
:
'information about the committer of the revision'
},
{
'name'
:
'committer_date'
,
'type'
:
'string'
,
'doc'
:
'ISO representation of the commit date (in UTC)'
},
{
'name'
:
'date'
,
'type'
:
'string'
,
'doc'
:
'ISO representation of the revision date (in UTC)'
},
{
'name'
:
'directory'
,
'type'
:
'string'
,
'doc'
:
'the unique identifier that revision points to'
},
{
'name'
:
'directory_url'
,
'type'
:
'string'
,
'doc'
:
(
'link to `</api/1/directory/>`_ to get information about '
'the directory associated to the revision'
)
},
{
'name'
:
'id'
,
'type'
:
'string'
,
'doc'
:
'the revision unique identifier'
},
{
'name'
:
'merge'
,
'type'
:
'boolean'
,
'doc'
:
'whether or not the revision corresponds to a merge commit'
},
{
'name'
:
'message'
,
'type'
:
'string'
,
'doc'
:
'the message associated to the revision'
},
{
'name'
:
'parents'
,
'type'
:
'array'
,
'doc'
:
(
'the parents of the revision, i.e. the previous revisions '
'that head directly to it, each entry of that array '
'contains an unique parent revision identifier but also a '
'link to `</api/1/revision/>`_ to get more information '
'about it'
)
},
{
'name'
:
'type'
,
'type'
:
'string'
,
'doc'
:
'the type of the revision'
}
]
assert
'returns'
in
doc_data
assert
doc_data
[
'returns'
]
==
expected_returns
expected_examples
=
[
'/api/1/revision/aafb16d69fd30ff58afdd69036a26047f3aebdc6/'
]
assert
'examples'
in
doc_data
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
:>json object <swh_pid>: an object whose keys are input persistent
identifiers and values objects with the following keys:
* **known (bool)**: whether the object was found
"""
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
=
textwrap
.
indent
((
'<dl class="row">
\n
'
' <dt class="col col-md-2 text-right">
\n
'
' array
\n
'
' </dt>
\n
'
' <dd class="col col-md-9">
\n
'
' <p>
\n
'
' Input array of pids
\n
'
' </p>
\n
'
' </dd>
\n
'
'</dl>
\n
'
),
' '
*
7
)
output_html_doc
=
textwrap
.
indent
((
'<dl class="row">
\n
'
' <dt class="col col-md-2 text-right">
\n
'
' object
\n
'
' </dt>
\n
'
' <dd class="col col-md-9">
\n
'
' <p>
\n
'
' an object containing the following keys:
\n
'
' </p>
\n
'
' <div class="swh-rst">
\n
'
' <blockquote>
\n
'
' <ul>
\n
'
' <li>
\n
'
' <p>
\n
'
' <strong>
\n
'
' <swh_pid> (object)
\n
'
' </strong>
\n
'
' : an object whose keys are input persistent identifiers'
' and values objects with the following keys:
\n
'
' </p>
\n
'
' <blockquote>
\n
'
' <ul class="simple">
\n
'
' <li>
\n
'
' <p>
\n
'
' <strong>
\n
'
' known (bool)
\n
'
' </strong>
\n
'
' : whether the object was found
\n
'
' </p>
\n
'
' </li>
\n
'
' </ul>
\n
'
' </blockquote>
\n
'
' </li>
\n
'
' </ul>
\n
'
' </blockquote>
\n
'
' </div>
\n
'
' </dd>
\n
'
'</dl>
\n
'
),
' '
*
7
)
html
=
prettify_html
(
rv
.
content
)
assert
input_html_doc
in
html
assert
output_html_doc
in
html
File Metadata
Details
Attached
Mime Type
text/x-python
Expires
Sat, Jun 21, 5:47 PM (1 w, 5 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3344125
Attached To
rDWAPPS Web applications
Event Timeline
Log In to Comment