resolve conflict
This commit is contained in:
commit
62420e0f40
88
README.rst
88
README.rst
|
@ -1,5 +1,8 @@
|
||||||
Sanic
|
.. image:: https://raw.githubusercontent.com/huge-success/sanic-assets/master/png/sanic-framework-logo-400x97.png
|
||||||
=====
|
:alt: Sanic | Build fast. Run fast.
|
||||||
|
|
||||||
|
Sanic | Build fast. Run fast.
|
||||||
|
=============================
|
||||||
|
|
||||||
.. start-badges
|
.. start-badges
|
||||||
|
|
||||||
|
@ -13,8 +16,10 @@ Sanic
|
||||||
* - Package
|
* - Package
|
||||||
- | |PyPI| |PyPI version| |Wheel| |Supported implementations| |Code style black|
|
- | |PyPI| |PyPI version| |Wheel| |Supported implementations| |Code style black|
|
||||||
* - Support
|
* - Support
|
||||||
- |Join the chat at https://gitter.im/sanic-python/Lobby|
|
- | |Forums| |Join the chat at https://gitter.im/sanic-python/Lobby|
|
||||||
|
|
||||||
|
.. |Forums| image:: https://img.shields.io/badge/forums-community-ff0068.svg
|
||||||
|
:target: https://community.sanicframework.org/
|
||||||
.. |Join the chat at https://gitter.im/sanic-python/Lobby| image:: https://badges.gitter.im/sanic-python/Lobby.svg
|
.. |Join the chat at https://gitter.im/sanic-python/Lobby| image:: https://badges.gitter.im/sanic-python/Lobby.svg
|
||||||
:target: https://gitter.im/sanic-python/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
|
:target: https://gitter.im/sanic-python/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
|
||||||
.. |Codecov| image:: https://codecov.io/gh/huge-success/sanic/branch/master/graph/badge.svg
|
.. |Codecov| image:: https://codecov.io/gh/huge-success/sanic/branch/master/graph/badge.svg
|
||||||
|
@ -40,24 +45,26 @@ Sanic
|
||||||
|
|
||||||
.. end-badges
|
.. end-badges
|
||||||
|
|
||||||
Sanic is a Flask-like Python 3.5+ web server that's written to go fast. It's based on the work done by the amazing folks at magicstack, and was inspired by `this article <https://magic.io/blog/uvloop-blazing-fast-python-networking/>`_.
|
Sanic is a Python web server and web framework that's written to go fast. It allows usage the `async` and `await` syntax added in Python 3.5, which makes your code non-blocking and speedy.
|
||||||
|
|
||||||
On top of being Flask-like, Sanic supports async request handlers. This means you can use the new shiny async/await syntax from Python 3.5, making your code non-blocking and speedy.
|
`Source code on GitHub <https://github.com/huge-success/sanic/>`_ | `Help and discussion board <https://community.sanicframework.org/>`_.
|
||||||
|
|
||||||
Sanic is developed `on GitHub <https://github.com/huge-success/sanic/>`_. We also have `a community discussion board <https://community.sanicframework.org/>`_. Contributions are welcome!
|
The project is maintained by the community, for the community **Contributions are welcome!**
|
||||||
|
|
||||||
If you have a project that utilizes Sanic make sure to comment on the `issue <https://github.com/huge-success/sanic/issues/396>`_ that we use to track those projects!
|
The goal of the project is to provide a simple way to get up and running a highly performant HTTP server that is easy to build, to expand, and ultimately to scale.
|
||||||
|
|
||||||
Installation
|
Installation
|
||||||
------------
|
------------
|
||||||
|
|
||||||
- ``pip3 install sanic``
|
``pip3 install sanic``
|
||||||
|
|
||||||
To install sanic without uvloop or ujson using bash, you can provide either or both of these environmental variables
|
Sanic makes use of ``uvloop`` and ``ujson`` to help with performance. If you do not want to use those packages, simply add an environmental variable ``SANIC_NO_UVLOOP=true`` or ``SANIC_NO_UJSON=true`` at install time.
|
||||||
using any truthy string like `'y', 'yes', 't', 'true', 'on', '1'` and setting the ``SANIC_NO_X`` (``X`` = ``UVLOOP``/``UJSON``)
|
|
||||||
to true will stop that features installation.
|
|
||||||
|
|
||||||
- ``SANIC_NO_UVLOOP=true SANIC_NO_UJSON=true pip install sanic``
|
.. code:: shell
|
||||||
|
|
||||||
|
$ export SANIC_NO_UVLOOP=true
|
||||||
|
$ export SANIC_NO_UJSON=true
|
||||||
|
$ pip3 install sanic
|
||||||
|
|
||||||
|
|
||||||
Hello World Example
|
Hello World Example
|
||||||
|
@ -77,6 +84,27 @@ Hello World Example
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
app.run(host='0.0.0.0', port=8000)
|
app.run(host='0.0.0.0', port=8000)
|
||||||
|
|
||||||
|
Sanic can now be easily run using ``python3 hello.py``.
|
||||||
|
|
||||||
|
.. code::
|
||||||
|
|
||||||
|
[2018-12-30 11:37:41 +0200] [13564] [INFO] Goin' Fast @ http://0.0.0.0:8000
|
||||||
|
[2018-12-30 11:37:41 +0200] [13564] [INFO] Starting worker [13564]
|
||||||
|
|
||||||
|
And, we can verify it is working: ``curl localhost:8000 -i``
|
||||||
|
|
||||||
|
.. code::
|
||||||
|
|
||||||
|
HTTP/1.1 200 OK
|
||||||
|
Connection: keep-alive
|
||||||
|
Keep-Alive: 5
|
||||||
|
Content-Length: 17
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{"hello":"world"}
|
||||||
|
|
||||||
|
**Now, let's go build something fast!**
|
||||||
|
|
||||||
|
|
||||||
Documentation
|
Documentation
|
||||||
-------------
|
-------------
|
||||||
|
@ -89,37 +117,7 @@ Questions and Discussion
|
||||||
|
|
||||||
`Ask a question or join the conversation <https://community.sanicframework.org/>`_.
|
`Ask a question or join the conversation <https://community.sanicframework.org/>`_.
|
||||||
|
|
||||||
|
Contribution
|
||||||
|
------------
|
||||||
|
|
||||||
Examples
|
We are always happy to have new contributions. We have `marked issues good for anyone looking to get started <https://github.com/huge-success/sanic/issues?q=is%3Aopen+is%3Aissue+label%3Abeginner>`_, and welcome `questions on the forums <https://community.sanicframework.org/>`_. Please take a look at our `Contribution guidelines <https://github.com/huge-success/sanic/blob/master/CONTRIBUTING.md>`_.
|
||||||
--------
|
|
||||||
`Non-Core examples <https://github.com/huge-success/sanic/wiki/Examples/>`_. Examples of plugins and Sanic that are outside the scope of Sanic core.
|
|
||||||
|
|
||||||
`Extensions <https://github.com/huge-success/sanic/wiki/Extensions/>`_. Sanic extensions created by the community.
|
|
||||||
|
|
||||||
`Projects <https://github.com/huge-success/sanic/wiki/Projects/>`_. Sanic in production use.
|
|
||||||
|
|
||||||
|
|
||||||
Final Thoughts
|
|
||||||
--------------
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
▄▄▄▄▄
|
|
||||||
▀▀▀██████▄▄▄ _______________
|
|
||||||
▄▄▄▄▄ █████████▄ / \
|
|
||||||
▀▀▀▀█████▌ ▀▐▄ ▀▐█ | Gotta go fast! |
|
|
||||||
▀▀█████▄▄ ▀██████▄██ | _________________/
|
|
||||||
▀▄▄▄▄▄ ▀▀█▄▀█════█▀ |/
|
|
||||||
▀▀▀▄ ▀▀███ ▀ ▄▄
|
|
||||||
▄███▀▀██▄████████▄ ▄▀▀▀▀▀▀█▌
|
|
||||||
██▀▄▄▄██▀▄███▀ ▀▀████ ▄██
|
|
||||||
▄▀▀▀▄██▄▀▀▌████▒▒▒▒▒▒███ ▌▄▄▀
|
|
||||||
▌ ▐▀████▐███▒▒▒▒▒▐██▌
|
|
||||||
▀▄▄▄▄▀ ▀▀████▒▒▒▒▄██▀
|
|
||||||
▀▀█████████▀
|
|
||||||
▄▄██▀██████▀█
|
|
||||||
▄██▀ ▀▀▀ █
|
|
||||||
▄█ ▐▌
|
|
||||||
▄▄▄▄█▌ ▀█▄▄▄▄▀▀▄
|
|
||||||
▌ ▐ ▀▀▄▄▄▀
|
|
||||||
▀▀▄▄▀
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ directory with a virtual environment already set up, then run:
|
||||||
|
|
||||||
.. code:: bash
|
.. code:: bash
|
||||||
|
|
||||||
pip3 install -e . '[.dev]'
|
pip3 install -e '.[dev]'
|
||||||
|
|
||||||
Dependency Changes
|
Dependency Changes
|
||||||
------------------
|
------------------
|
||||||
|
@ -35,7 +35,7 @@ the document that explains the way ``sanic`` manages dependencies inside the ``s
|
||||||
| extras_require['test'] | for ``sanic`` | |
|
| extras_require['test'] | for ``sanic`` | |
|
||||||
+------------------------+-----------------------------------------------+--------------------------------+
|
+------------------------+-----------------------------------------------+--------------------------------+
|
||||||
| extras_require['dev'] | Additional Development requirements to add | ``pip3 install -e '.[dev]'`` |
|
| extras_require['dev'] | Additional Development requirements to add | ``pip3 install -e '.[dev]'`` |
|
||||||
| | contributing | |
|
| | for contributing | |
|
||||||
+------------------------+-----------------------------------------------+--------------------------------+
|
+------------------------+-----------------------------------------------+--------------------------------+
|
||||||
| extras_require['docs'] | Dependencies required to enable building and | ``pip3 install -e '.[docs]'`` |
|
| extras_require['docs'] | Dependencies required to enable building and | ``pip3 install -e '.[docs]'`` |
|
||||||
| | enhancing sanic documentation | |
|
| | enhancing sanic documentation | |
|
||||||
|
|
10
sanic/app.py
10
sanic/app.py
|
@ -13,7 +13,7 @@ from traceback import format_exc
|
||||||
from urllib.parse import urlencode, urlunparse
|
from urllib.parse import urlencode, urlunparse
|
||||||
|
|
||||||
from sanic import reloader_helpers
|
from sanic import reloader_helpers
|
||||||
from sanic.config import Config
|
from sanic.config import BASE_LOGO, Config
|
||||||
from sanic.constants import HTTP_METHODS
|
from sanic.constants import HTTP_METHODS
|
||||||
from sanic.exceptions import SanicException, ServerError, URLBuildError
|
from sanic.exceptions import SanicException, ServerError, URLBuildError
|
||||||
from sanic.handlers import ErrorHandler
|
from sanic.handlers import ErrorHandler
|
||||||
|
@ -1256,10 +1256,14 @@ class Sanic:
|
||||||
logger.setLevel(logging.DEBUG)
|
logger.setLevel(logging.DEBUG)
|
||||||
|
|
||||||
if (
|
if (
|
||||||
self.config.LOGO is not None
|
self.config.LOGO
|
||||||
and os.environ.get("SANIC_SERVER_RUNNING") != "true"
|
and os.environ.get("SANIC_SERVER_RUNNING") != "true"
|
||||||
):
|
):
|
||||||
logger.debug(self.config.LOGO)
|
logger.debug(
|
||||||
|
self.config.LOGO
|
||||||
|
if isinstance(self.config.LOGO, str)
|
||||||
|
else BASE_LOGO
|
||||||
|
)
|
||||||
|
|
||||||
if run_async:
|
if run_async:
|
||||||
server_settings["run_async"] = True
|
server_settings["run_async"] = True
|
||||||
|
|
|
@ -6,32 +6,18 @@ from sanic.helpers import import_string
|
||||||
|
|
||||||
|
|
||||||
SANIC_PREFIX = "SANIC_"
|
SANIC_PREFIX = "SANIC_"
|
||||||
|
BASE_LOGO = """
|
||||||
|
|
||||||
|
Sanic
|
||||||
|
Build Fast. Run Fast.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
class Config(dict):
|
class Config(dict):
|
||||||
def __init__(self, defaults=None, load_env=True, keep_alive=True):
|
def __init__(self, defaults=None, load_env=True, keep_alive=True):
|
||||||
super().__init__(defaults or {})
|
super().__init__(defaults or {})
|
||||||
self.LOGO = """
|
self.LOGO = BASE_LOGO
|
||||||
▄▄▄▄▄
|
|
||||||
▀▀▀██████▄▄▄ _______________
|
|
||||||
▄▄▄▄▄ █████████▄ / \\
|
|
||||||
▀▀▀▀█████▌ ▀▐▄ ▀▐█ | Gotta go fast! |
|
|
||||||
▀▀█████▄▄ ▀██████▄██ | _________________/
|
|
||||||
▀▄▄▄▄▄ ▀▀█▄▀█════█▀ |/
|
|
||||||
▀▀▀▄ ▀▀███ ▀ ▄▄
|
|
||||||
▄███▀▀██▄████████▄ ▄▀▀▀▀▀▀█▌
|
|
||||||
██▀▄▄▄██▀▄███▀ ▀▀████ ▄██
|
|
||||||
▄▀▀▀▄██▄▀▀▌████▒▒▒▒▒▒███ ▌▄▄▀
|
|
||||||
▌ ▐▀████▐███▒▒▒▒▒▐██▌
|
|
||||||
▀▄▄▄▄▀ ▀▀████▒▒▒▒▄██▀
|
|
||||||
▀▀█████████▀
|
|
||||||
▄▄██▀██████▀█
|
|
||||||
▄██▀ ▀▀▀ █
|
|
||||||
▄█ ▐▌
|
|
||||||
▄▄▄▄█▌ ▀█▄▄▄▄▀▀▄
|
|
||||||
▌ ▐ ▀▀▄▄▄▀
|
|
||||||
▀▀▄▄▀
|
|
||||||
"""
|
|
||||||
self.REQUEST_MAX_SIZE = 100000000 # 100 megabytes
|
self.REQUEST_MAX_SIZE = 100000000 # 100 megabytes
|
||||||
self.REQUEST_BUFFER_QUEUE_SIZE = 100
|
self.REQUEST_BUFFER_QUEUE_SIZE = 100
|
||||||
self.REQUEST_TIMEOUT = 60 # 60 seconds
|
self.REQUEST_TIMEOUT = 60 # 60 seconds
|
||||||
|
|
|
@ -3,7 +3,7 @@ import pytest
|
||||||
|
|
||||||
from sanic import Sanic
|
from sanic import Sanic
|
||||||
|
|
||||||
if sys.platform in ['win32', 'cygwin']:
|
if sys.platform in ["win32", "cygwin"]:
|
||||||
collect_ignore = ["test_worker.py"]
|
collect_ignore = ["test_worker.py"]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -9,10 +9,15 @@ import ujson as json
|
||||||
loop = uvloop.new_event_loop()
|
loop = uvloop.new_event_loop()
|
||||||
asyncio.set_event_loop(loop)
|
asyncio.set_event_loop(loop)
|
||||||
|
|
||||||
|
|
||||||
async def handle(request):
|
async def handle(request):
|
||||||
return web.Response(body=json.dumps({"test":True}).encode('utf-8'), content_type='application/json')
|
return web.Response(
|
||||||
|
body=json.dumps({"test": True}).encode("utf-8"),
|
||||||
|
content_type="application/json",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
app = web.Application(loop=loop)
|
app = web.Application(loop=loop)
|
||||||
app.router.add_route('GET', '/', handle)
|
app.router.add_route("GET", "/", handle)
|
||||||
|
|
||||||
web.run_app(app, port=sys.argv[1], access_log=None)
|
web.run_app(app, port=sys.argv[1], access_log=None)
|
||||||
|
|
|
@ -4,8 +4,9 @@ from bottle import route, run
|
||||||
import ujson
|
import ujson
|
||||||
|
|
||||||
|
|
||||||
@route('/')
|
@route("/")
|
||||||
def index():
|
def index():
|
||||||
return ujson.dumps({'test': True})
|
return ujson.dumps({"test": True})
|
||||||
|
|
||||||
|
|
||||||
app = bottle.default_app()
|
app = bottle.default_app()
|
||||||
|
|
|
@ -3,9 +3,11 @@
|
||||||
import falcon
|
import falcon
|
||||||
import ujson as json
|
import ujson as json
|
||||||
|
|
||||||
|
|
||||||
class TestResource:
|
class TestResource:
|
||||||
def on_get(self, req, resp):
|
def on_get(self, req, resp):
|
||||||
resp.body = json.dumps({"test": True})
|
resp.body = json.dumps({"test": True})
|
||||||
|
|
||||||
|
|
||||||
app = falcon.API()
|
app = falcon.API()
|
||||||
app.add_route('/', TestResource())
|
app.add_route("/", TestResource())
|
||||||
|
|
|
@ -13,8 +13,14 @@ kyk = Kyoukai("example_app")
|
||||||
logger = logging.getLogger("Kyoukai")
|
logger = logging.getLogger("Kyoukai")
|
||||||
logger.setLevel(logging.ERROR)
|
logger.setLevel(logging.ERROR)
|
||||||
|
|
||||||
|
|
||||||
@kyk.route("/")
|
@kyk.route("/")
|
||||||
async def index(ctx: HTTPRequestContext):
|
async def index(ctx: HTTPRequestContext):
|
||||||
return ujson.dumps({"test":True}), 200, {"Content-Type": "application/json"}
|
return (
|
||||||
|
ujson.dumps({"test": True}),
|
||||||
|
200,
|
||||||
|
{"Content-Type": "application/json"},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
kyk.run()
|
kyk.run()
|
|
@ -3,8 +3,10 @@ import sys
|
||||||
import os
|
import os
|
||||||
import inspect
|
import inspect
|
||||||
|
|
||||||
currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
|
currentdir = os.path.dirname(
|
||||||
sys.path.insert(0, currentdir + '/../../../')
|
os.path.abspath(inspect.getfile(inspect.currentframe()))
|
||||||
|
)
|
||||||
|
sys.path.insert(0, currentdir + "/../../../")
|
||||||
|
|
||||||
import timeit
|
import timeit
|
||||||
|
|
||||||
|
@ -16,7 +18,11 @@ print("Running New 100,000 times")
|
||||||
times = 0
|
times = 0
|
||||||
total_time = 0
|
total_time = 0
|
||||||
for n in range(6):
|
for n in range(6):
|
||||||
time = timeit.timeit('json({ "test":True }).output()', setup='from sanic.response import json', number=100000)
|
time = timeit.timeit(
|
||||||
|
'json({ "test":True }).output()',
|
||||||
|
setup="from sanic.response import json",
|
||||||
|
number=100000,
|
||||||
|
)
|
||||||
print("Took {} seconds".format(time))
|
print("Took {} seconds".format(time))
|
||||||
total_time += time
|
total_time += time
|
||||||
times += 1
|
times += 1
|
||||||
|
@ -26,7 +32,11 @@ print("Running Old 100,000 times")
|
||||||
times = 0
|
times = 0
|
||||||
total_time = 0
|
total_time = 0
|
||||||
for n in range(6):
|
for n in range(6):
|
||||||
time = timeit.timeit('json({ "test":True }).output_old()', setup='from sanic.response import json', number=100000)
|
time = timeit.timeit(
|
||||||
|
'json({ "test":True }).output_old()',
|
||||||
|
setup="from sanic.response import json",
|
||||||
|
number=100000,
|
||||||
|
)
|
||||||
print("Took {} seconds".format(time))
|
print("Took {} seconds".format(time))
|
||||||
total_time += time
|
total_time += time
|
||||||
times += 1
|
times += 1
|
||||||
|
|
|
@ -2,8 +2,10 @@ import sys
|
||||||
import os
|
import os
|
||||||
import inspect
|
import inspect
|
||||||
|
|
||||||
currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
|
currentdir = os.path.dirname(
|
||||||
sys.path.insert(0, currentdir + '/../../../')
|
os.path.abspath(inspect.getfile(inspect.currentframe()))
|
||||||
|
)
|
||||||
|
sys.path.insert(0, currentdir + "/../../../")
|
||||||
|
|
||||||
from sanic import Sanic
|
from sanic import Sanic
|
||||||
from sanic.response import json
|
from sanic.response import json
|
||||||
|
@ -15,5 +17,6 @@ app = Sanic("test")
|
||||||
async def test(request):
|
async def test(request):
|
||||||
return json({"test": True})
|
return json({"test": True})
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
|
if __name__ == "__main__":
|
||||||
app.run(host="0.0.0.0", port=sys.argv[1])
|
app.run(host="0.0.0.0", port=sys.argv[1])
|
||||||
|
|
|
@ -2,8 +2,10 @@ import sys
|
||||||
import os
|
import os
|
||||||
import inspect
|
import inspect
|
||||||
|
|
||||||
currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
|
currentdir = os.path.dirname(
|
||||||
sys.path.insert(0, currentdir + '/../../../')
|
os.path.abspath(inspect.getfile(inspect.currentframe()))
|
||||||
|
)
|
||||||
|
sys.path.insert(0, currentdir + "/../../../")
|
||||||
|
|
||||||
from sanic import Sanic
|
from sanic import Sanic
|
||||||
from sanic.response import json, text
|
from sanic.response import json, text
|
||||||
|
@ -17,7 +19,7 @@ async def test(request):
|
||||||
return json({"test": True})
|
return json({"test": True})
|
||||||
|
|
||||||
|
|
||||||
@app.route("/sync", methods=['GET', 'POST'])
|
@app.route("/sync", methods=["GET", "POST"])
|
||||||
def test(request):
|
def test(request):
|
||||||
return json({"test": True})
|
return json({"test": True})
|
||||||
|
|
||||||
|
@ -44,7 +46,14 @@ def post_json(request):
|
||||||
|
|
||||||
@app.route("/query_string")
|
@app.route("/query_string")
|
||||||
def query_string(request):
|
def query_string(request):
|
||||||
return json({"parsed": True, "args": request.args, "url": request.url, "query_string": request.query_string})
|
return json(
|
||||||
|
{
|
||||||
|
"parsed": True,
|
||||||
|
"args": request.args,
|
||||||
|
"url": request.url,
|
||||||
|
"query_string": request.query_string,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
@ -52,7 +61,6 @@ import sys
|
||||||
app.run(host="0.0.0.0", port=sys.argv[1])
|
app.run(host="0.0.0.0", port=sys.argv[1])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# import asyncio_redis
|
# import asyncio_redis
|
||||||
# import asyncpg
|
# import asyncpg
|
||||||
# async def setup(sanic, loop):
|
# async def setup(sanic, loop):
|
||||||
|
|
|
@ -5,14 +5,14 @@ from tornado import ioloop, web
|
||||||
|
|
||||||
class MainHandler(web.RequestHandler):
|
class MainHandler(web.RequestHandler):
|
||||||
def get(self):
|
def get(self):
|
||||||
self.write(ujson.dumps({'test': True}))
|
self.write(ujson.dumps({"test": True}))
|
||||||
|
|
||||||
|
|
||||||
app = web.Application([
|
app = web.Application(
|
||||||
(r'/', MainHandler)
|
[(r"/", MainHandler)],
|
||||||
], debug=False,
|
debug=False,
|
||||||
compress_response=False,
|
compress_response=False,
|
||||||
static_hash_cache=True
|
static_hash_cache=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
app.listen(8000)
|
app.listen(8000)
|
||||||
|
|
|
@ -12,16 +12,17 @@ from wheezy.web.middleware import path_routing_middleware_factory
|
||||||
|
|
||||||
import ujson
|
import ujson
|
||||||
|
|
||||||
class WelcomeHandler(BaseHandler):
|
|
||||||
|
|
||||||
|
class WelcomeHandler(BaseHandler):
|
||||||
def get(self):
|
def get(self):
|
||||||
response = HTTPResponse(content_type='application/json; charset=UTF-8')
|
response = HTTPResponse(content_type="application/json; charset=UTF-8")
|
||||||
response.write(ujson.dumps({"test":True}))
|
response.write(ujson.dumps({"test": True}))
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
all_urls = [
|
all_urls = [
|
||||||
url('', WelcomeHandler, name='default'),
|
url("", WelcomeHandler, name="default"),
|
||||||
# url('', welcome, name='welcome')
|
# url('', welcome, name='welcome')
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -29,18 +30,19 @@ options = {}
|
||||||
main = WSGIApplication(
|
main = WSGIApplication(
|
||||||
middleware=[
|
middleware=[
|
||||||
bootstrap_defaults(url_mapping=all_urls),
|
bootstrap_defaults(url_mapping=all_urls),
|
||||||
path_routing_middleware_factory
|
path_routing_middleware_factory,
|
||||||
],
|
],
|
||||||
options=options
|
options=options,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == "__main__":
|
||||||
import sys
|
import sys
|
||||||
from wsgiref.simple_server import make_server
|
from wsgiref.simple_server import make_server
|
||||||
|
|
||||||
try:
|
try:
|
||||||
print('Visit http://localhost:{}/'.format(sys.argv[-1]))
|
print("Visit http://localhost:{}/".format(sys.argv[-1]))
|
||||||
make_server('', int(sys.argv[-1]), main).serve_forever()
|
make_server("", int(sys.argv[-1]), main).serve_forever()
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
pass
|
pass
|
||||||
print('\nThanks!')
|
print("\nThanks!")
|
||||||
|
|
|
@ -8,14 +8,13 @@ from sanic.response import text
|
||||||
|
|
||||||
|
|
||||||
def test_app_loop_running(app):
|
def test_app_loop_running(app):
|
||||||
|
@app.get("/test")
|
||||||
@app.get('/test')
|
|
||||||
async def handler(request):
|
async def handler(request):
|
||||||
assert isinstance(app.loop, asyncio.AbstractEventLoop)
|
assert isinstance(app.loop, asyncio.AbstractEventLoop)
|
||||||
return text('pass')
|
return text("pass")
|
||||||
|
|
||||||
request, response = app.test_client.get('/test')
|
request, response = app.test_client.get("/test")
|
||||||
assert response.text == 'pass'
|
assert response.text == "pass"
|
||||||
|
|
||||||
|
|
||||||
def test_app_loop_not_running(app):
|
def test_app_loop_not_running(app):
|
||||||
|
@ -23,105 +22,117 @@ def test_app_loop_not_running(app):
|
||||||
app.loop
|
app.loop
|
||||||
|
|
||||||
assert str(excinfo.value) == (
|
assert str(excinfo.value) == (
|
||||||
'Loop can only be retrieved after the app has started '
|
"Loop can only be retrieved after the app has started "
|
||||||
'running. Not supported with `create_server` function'
|
"running. Not supported with `create_server` function"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_app_run_raise_type_error(app):
|
def test_app_run_raise_type_error(app):
|
||||||
|
|
||||||
with pytest.raises(TypeError) as excinfo:
|
with pytest.raises(TypeError) as excinfo:
|
||||||
app.run(loop='loop')
|
app.run(loop="loop")
|
||||||
|
|
||||||
assert str(excinfo.value) == (
|
assert str(excinfo.value) == (
|
||||||
'loop is not a valid argument. To use an existing loop, '
|
"loop is not a valid argument. To use an existing loop, "
|
||||||
'change to create_server().\nSee more: '
|
"change to create_server().\nSee more: "
|
||||||
'https://sanic.readthedocs.io/en/latest/sanic/deploying.html'
|
"https://sanic.readthedocs.io/en/latest/sanic/deploying.html"
|
||||||
'#asynchronous-support'
|
"#asynchronous-support"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_app_route_raise_value_error(app):
|
def test_app_route_raise_value_error(app):
|
||||||
|
|
||||||
with pytest.raises(ValueError) as excinfo:
|
with pytest.raises(ValueError) as excinfo:
|
||||||
@app.route('/test')
|
|
||||||
async def handler():
|
|
||||||
return text('test')
|
|
||||||
|
|
||||||
assert str(excinfo.value) == 'Required parameter `request` missing in the handler() route?'
|
@app.route("/test")
|
||||||
|
async def handler():
|
||||||
|
return text("test")
|
||||||
|
|
||||||
|
assert (
|
||||||
|
str(excinfo.value)
|
||||||
|
== "Required parameter `request` missing in the handler() route?"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_app_handle_request_handler_is_none(app, monkeypatch):
|
def test_app_handle_request_handler_is_none(app, monkeypatch):
|
||||||
|
|
||||||
def mockreturn(*args, **kwargs):
|
def mockreturn(*args, **kwargs):
|
||||||
return None, [], {}, ''
|
return None, [], {}, ""
|
||||||
|
|
||||||
# Not sure how to make app.router.get() return None, so use mock here.
|
# Not sure how to make app.router.get() return None, so use mock here.
|
||||||
monkeypatch.setattr(app.router, 'get', mockreturn)
|
monkeypatch.setattr(app.router, "get", mockreturn)
|
||||||
|
|
||||||
@app.get('/test')
|
@app.get("/test")
|
||||||
def handler(request):
|
def handler(request):
|
||||||
return text('test')
|
return text("test")
|
||||||
|
|
||||||
request, response = app.test_client.get('/test')
|
request, response = app.test_client.get("/test")
|
||||||
|
|
||||||
assert response.text == 'Error: \'None\' was returned while requesting a handler from the router'
|
assert (
|
||||||
|
response.text
|
||||||
|
== "Error: 'None' was returned while requesting a handler from the router"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('websocket_enabled', [True, False])
|
@pytest.mark.parametrize("websocket_enabled", [True, False])
|
||||||
@pytest.mark.parametrize('enable', [True, False])
|
@pytest.mark.parametrize("enable", [True, False])
|
||||||
def test_app_enable_websocket(app, websocket_enabled, enable):
|
def test_app_enable_websocket(app, websocket_enabled, enable):
|
||||||
app.websocket_enabled = websocket_enabled
|
app.websocket_enabled = websocket_enabled
|
||||||
app.enable_websocket(enable=enable)
|
app.enable_websocket(enable=enable)
|
||||||
|
|
||||||
assert app.websocket_enabled == enable
|
assert app.websocket_enabled == enable
|
||||||
|
|
||||||
@app.websocket('/ws')
|
@app.websocket("/ws")
|
||||||
async def handler(request, ws):
|
async def handler(request, ws):
|
||||||
await ws.send('test')
|
await ws.send("test")
|
||||||
|
|
||||||
assert app.websocket_enabled == True
|
assert app.websocket_enabled == True
|
||||||
|
|
||||||
|
|
||||||
def test_handle_request_with_nested_exception(app, monkeypatch):
|
def test_handle_request_with_nested_exception(app, monkeypatch):
|
||||||
|
|
||||||
err_msg = 'Mock Exception'
|
err_msg = "Mock Exception"
|
||||||
|
|
||||||
# Not sure how to raise an exception in app.error_handler.response(), use mock here
|
# Not sure how to raise an exception in app.error_handler.response(), use mock here
|
||||||
def mock_error_handler_response(*args, **kwargs):
|
def mock_error_handler_response(*args, **kwargs):
|
||||||
raise Exception(err_msg)
|
raise Exception(err_msg)
|
||||||
|
|
||||||
monkeypatch.setattr(app.error_handler, 'response', mock_error_handler_response)
|
monkeypatch.setattr(
|
||||||
|
app.error_handler, "response", mock_error_handler_response
|
||||||
|
)
|
||||||
|
|
||||||
@app.get('/')
|
@app.get("/")
|
||||||
def handler(request):
|
def handler(request):
|
||||||
raise Exception
|
raise Exception
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
request, response = app.test_client.get('/')
|
request, response = app.test_client.get("/")
|
||||||
assert response.status == 500
|
assert response.status == 500
|
||||||
assert response.text == 'An error occurred while handling an error'
|
assert response.text == "An error occurred while handling an error"
|
||||||
|
|
||||||
|
|
||||||
def test_handle_request_with_nested_exception_debug(app, monkeypatch):
|
def test_handle_request_with_nested_exception_debug(app, monkeypatch):
|
||||||
|
|
||||||
err_msg = 'Mock Exception'
|
err_msg = "Mock Exception"
|
||||||
|
|
||||||
# Not sure how to raise an exception in app.error_handler.response(), use mock here
|
# Not sure how to raise an exception in app.error_handler.response(), use mock here
|
||||||
def mock_error_handler_response(*args, **kwargs):
|
def mock_error_handler_response(*args, **kwargs):
|
||||||
raise Exception(err_msg)
|
raise Exception(err_msg)
|
||||||
|
|
||||||
monkeypatch.setattr(app.error_handler, 'response', mock_error_handler_response)
|
monkeypatch.setattr(
|
||||||
|
app.error_handler, "response", mock_error_handler_response
|
||||||
|
)
|
||||||
|
|
||||||
@app.get('/')
|
@app.get("/")
|
||||||
def handler(request):
|
def handler(request):
|
||||||
raise Exception
|
raise Exception
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
request, response = app.test_client.get('/', debug=True)
|
request, response = app.test_client.get("/", debug=True)
|
||||||
assert response.status == 500
|
assert response.status == 500
|
||||||
assert response.text.startswith(
|
assert response.text.startswith(
|
||||||
'Error while handling error: {}\nStack: Traceback (most recent call last):\n'.format(err_msg)
|
"Error while handling error: {}\nStack: Traceback (most recent call last):\n".format(
|
||||||
|
err_msg
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -129,21 +140,23 @@ def test_handle_request_with_nested_sanic_exception(app, monkeypatch, caplog):
|
||||||
|
|
||||||
# Not sure how to raise an exception in app.error_handler.response(), use mock here
|
# Not sure how to raise an exception in app.error_handler.response(), use mock here
|
||||||
def mock_error_handler_response(*args, **kwargs):
|
def mock_error_handler_response(*args, **kwargs):
|
||||||
raise SanicException('Mock SanicException')
|
raise SanicException("Mock SanicException")
|
||||||
|
|
||||||
monkeypatch.setattr(app.error_handler, 'response', mock_error_handler_response)
|
monkeypatch.setattr(
|
||||||
|
app.error_handler, "response", mock_error_handler_response
|
||||||
|
)
|
||||||
|
|
||||||
@app.get('/')
|
@app.get("/")
|
||||||
def handler(request):
|
def handler(request):
|
||||||
raise Exception
|
raise Exception
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
with caplog.at_level(logging.ERROR):
|
with caplog.at_level(logging.ERROR):
|
||||||
request, response = app.test_client.get('/')
|
request, response = app.test_client.get("/")
|
||||||
assert response.status == 500
|
assert response.status == 500
|
||||||
assert response.text == 'Error: Mock SanicException'
|
assert response.text == "Error: Mock SanicException"
|
||||||
assert caplog.record_tuples[0] == (
|
assert caplog.record_tuples[0] == (
|
||||||
'sanic.root',
|
"sanic.root",
|
||||||
logging.ERROR,
|
logging.ERROR,
|
||||||
"Exception occurred while handling uri: 'http://127.0.0.1:42101/'"
|
"Exception occurred while handling uri: 'http://127.0.0.1:42101/'",
|
||||||
)
|
)
|
||||||
|
|
|
@ -4,17 +4,18 @@ import asyncio
|
||||||
def test_bad_request_response(app):
|
def test_bad_request_response(app):
|
||||||
lines = []
|
lines = []
|
||||||
|
|
||||||
@app.listener('after_server_start')
|
@app.listener("after_server_start")
|
||||||
async def _request(sanic, loop):
|
async def _request(sanic, loop):
|
||||||
connect = asyncio.open_connection('127.0.0.1', 42101)
|
connect = asyncio.open_connection("127.0.0.1", 42101)
|
||||||
reader, writer = await connect
|
reader, writer = await connect
|
||||||
writer.write(b'not http')
|
writer.write(b"not http")
|
||||||
while True:
|
while True:
|
||||||
line = await reader.readline()
|
line = await reader.readline()
|
||||||
if not line:
|
if not line:
|
||||||
break
|
break
|
||||||
lines.append(line)
|
lines.append(line)
|
||||||
app.stop()
|
app.stop()
|
||||||
app.run(host='127.0.0.1', port=42101, debug=False)
|
|
||||||
assert lines[0] == b'HTTP/1.1 400 Bad Request\r\n'
|
app.run(host="127.0.0.1", port=42101, debug=False)
|
||||||
assert lines[-1] == b'Error: Bad Request'
|
assert lines[0] == b"HTTP/1.1 400 Bad Request\r\n"
|
||||||
|
assert lines[-1] == b"Error: Bad Request"
|
||||||
|
|
|
@ -17,12 +17,13 @@ from sanic.views import CompositionView
|
||||||
# GET
|
# GET
|
||||||
# ------------------------------------------------------------ #
|
# ------------------------------------------------------------ #
|
||||||
|
|
||||||
@pytest.fixture(scope='module')
|
|
||||||
|
@pytest.fixture(scope="module")
|
||||||
def static_file_directory():
|
def static_file_directory():
|
||||||
"""The static directory to serve"""
|
"""The static directory to serve"""
|
||||||
current_file = inspect.getfile(inspect.currentframe())
|
current_file = inspect.getfile(inspect.currentframe())
|
||||||
current_directory = os.path.dirname(os.path.abspath(current_file))
|
current_directory = os.path.dirname(os.path.abspath(current_file))
|
||||||
static_directory = os.path.join(current_directory, 'static')
|
static_directory = os.path.join(current_directory, "static")
|
||||||
return static_directory
|
return static_directory
|
||||||
|
|
||||||
|
|
||||||
|
@ -32,21 +33,23 @@ def get_file_path(static_file_directory, file_name):
|
||||||
|
|
||||||
def get_file_content(static_file_directory, file_name):
|
def get_file_content(static_file_directory, file_name):
|
||||||
"""The content of the static file to check"""
|
"""The content of the static file to check"""
|
||||||
with open(get_file_path(static_file_directory, file_name), 'rb') as file:
|
with open(get_file_path(static_file_directory, file_name), "rb") as file:
|
||||||
return file.read()
|
return file.read()
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('method', HTTP_METHODS)
|
@pytest.mark.parametrize("method", HTTP_METHODS)
|
||||||
def test_versioned_routes_get(app, method):
|
def test_versioned_routes_get(app, method):
|
||||||
bp = Blueprint('test_text')
|
bp = Blueprint("test_text")
|
||||||
|
|
||||||
method = method.lower()
|
method = method.lower()
|
||||||
|
|
||||||
func = getattr(bp, method)
|
func = getattr(bp, method)
|
||||||
if callable(func):
|
if callable(func):
|
||||||
@func('/{}'.format(method), version=1)
|
|
||||||
|
@func("/{}".format(method), version=1)
|
||||||
def handler(request):
|
def handler(request):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
else:
|
else:
|
||||||
print(func)
|
print(func)
|
||||||
raise Exception("{} is not callable".format(func))
|
raise Exception("{} is not callable".format(func))
|
||||||
|
@ -55,245 +58,231 @@ def test_versioned_routes_get(app, method):
|
||||||
|
|
||||||
client_method = getattr(app.test_client, method)
|
client_method = getattr(app.test_client, method)
|
||||||
|
|
||||||
request, response = client_method('/v1/{}'.format(method))
|
request, response = client_method("/v1/{}".format(method))
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
|
|
||||||
|
|
||||||
def test_bp(app):
|
def test_bp(app):
|
||||||
bp = Blueprint('test_text')
|
bp = Blueprint("test_text")
|
||||||
|
|
||||||
@bp.route('/')
|
@bp.route("/")
|
||||||
def handler(request):
|
def handler(request):
|
||||||
return text('Hello')
|
return text("Hello")
|
||||||
|
|
||||||
app.blueprint(bp)
|
app.blueprint(bp)
|
||||||
request, response = app.test_client.get('/')
|
request, response = app.test_client.get("/")
|
||||||
assert app.is_request_stream is False
|
assert app.is_request_stream is False
|
||||||
|
|
||||||
assert response.text == 'Hello'
|
assert response.text == "Hello"
|
||||||
|
|
||||||
|
|
||||||
def test_bp_strict_slash(app):
|
def test_bp_strict_slash(app):
|
||||||
bp = Blueprint('test_text')
|
bp = Blueprint("test_text")
|
||||||
|
|
||||||
@bp.get('/get', strict_slashes=True)
|
@bp.get("/get", strict_slashes=True)
|
||||||
def get_handler(request):
|
def get_handler(request):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
@bp.post('/post/', strict_slashes=True)
|
@bp.post("/post/", strict_slashes=True)
|
||||||
def post_handler(request):
|
def post_handler(request):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
app.blueprint(bp)
|
app.blueprint(bp)
|
||||||
|
|
||||||
request, response = app.test_client.get('/get')
|
request, response = app.test_client.get("/get")
|
||||||
assert response.text == 'OK'
|
assert response.text == "OK"
|
||||||
assert response.json is None
|
assert response.json is None
|
||||||
|
|
||||||
request, response = app.test_client.get('/get/')
|
request, response = app.test_client.get("/get/")
|
||||||
assert response.status == 404
|
assert response.status == 404
|
||||||
|
|
||||||
request, response = app.test_client.post('/post/')
|
request, response = app.test_client.post("/post/")
|
||||||
assert response.text == 'OK'
|
assert response.text == "OK"
|
||||||
|
|
||||||
request, response = app.test_client.post('/post')
|
request, response = app.test_client.post("/post")
|
||||||
assert response.status == 404
|
assert response.status == 404
|
||||||
|
|
||||||
|
|
||||||
def test_bp_strict_slash_default_value(app):
|
def test_bp_strict_slash_default_value(app):
|
||||||
bp = Blueprint('test_text', strict_slashes=True)
|
bp = Blueprint("test_text", strict_slashes=True)
|
||||||
|
|
||||||
@bp.get('/get')
|
@bp.get("/get")
|
||||||
def get_handler(request):
|
def get_handler(request):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
@bp.post('/post/')
|
@bp.post("/post/")
|
||||||
def post_handler(request):
|
def post_handler(request):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
app.blueprint(bp)
|
app.blueprint(bp)
|
||||||
|
|
||||||
request, response = app.test_client.get('/get/')
|
request, response = app.test_client.get("/get/")
|
||||||
assert response.status == 404
|
assert response.status == 404
|
||||||
|
|
||||||
request, response = app.test_client.post('/post')
|
request, response = app.test_client.post("/post")
|
||||||
assert response.status == 404
|
assert response.status == 404
|
||||||
|
|
||||||
|
|
||||||
def test_bp_strict_slash_without_passing_default_value(app):
|
def test_bp_strict_slash_without_passing_default_value(app):
|
||||||
bp = Blueprint('test_text')
|
bp = Blueprint("test_text")
|
||||||
|
|
||||||
@bp.get('/get')
|
@bp.get("/get")
|
||||||
def get_handler(request):
|
def get_handler(request):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
@bp.post('/post/')
|
@bp.post("/post/")
|
||||||
def post_handler(request):
|
def post_handler(request):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
app.blueprint(bp)
|
app.blueprint(bp)
|
||||||
|
|
||||||
request, response = app.test_client.get('/get/')
|
request, response = app.test_client.get("/get/")
|
||||||
assert response.text == 'OK'
|
assert response.text == "OK"
|
||||||
|
|
||||||
request, response = app.test_client.post('/post')
|
request, response = app.test_client.post("/post")
|
||||||
assert response.text == 'OK'
|
assert response.text == "OK"
|
||||||
|
|
||||||
|
|
||||||
def test_bp_strict_slash_default_value_can_be_overwritten(app):
|
def test_bp_strict_slash_default_value_can_be_overwritten(app):
|
||||||
bp = Blueprint('test_text', strict_slashes=True)
|
bp = Blueprint("test_text", strict_slashes=True)
|
||||||
|
|
||||||
@bp.get('/get', strict_slashes=False)
|
@bp.get("/get", strict_slashes=False)
|
||||||
def get_handler(request):
|
def get_handler(request):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
@bp.post('/post/', strict_slashes=False)
|
@bp.post("/post/", strict_slashes=False)
|
||||||
def post_handler(request):
|
def post_handler(request):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
app.blueprint(bp)
|
app.blueprint(bp)
|
||||||
|
|
||||||
request, response = app.test_client.get('/get/')
|
request, response = app.test_client.get("/get/")
|
||||||
assert response.text == 'OK'
|
assert response.text == "OK"
|
||||||
|
|
||||||
request, response = app.test_client.post('/post')
|
request, response = app.test_client.post("/post")
|
||||||
assert response.text == 'OK'
|
assert response.text == "OK"
|
||||||
|
|
||||||
|
|
||||||
def test_bp_with_url_prefix(app):
|
def test_bp_with_url_prefix(app):
|
||||||
bp = Blueprint('test_text', url_prefix='/test1')
|
bp = Blueprint("test_text", url_prefix="/test1")
|
||||||
|
|
||||||
@bp.route('/')
|
@bp.route("/")
|
||||||
def handler(request):
|
def handler(request):
|
||||||
return text('Hello')
|
return text("Hello")
|
||||||
|
|
||||||
app.blueprint(bp)
|
app.blueprint(bp)
|
||||||
request, response = app.test_client.get('/test1/')
|
request, response = app.test_client.get("/test1/")
|
||||||
|
|
||||||
assert response.text == 'Hello'
|
assert response.text == "Hello"
|
||||||
|
|
||||||
|
|
||||||
def test_several_bp_with_url_prefix(app):
|
def test_several_bp_with_url_prefix(app):
|
||||||
bp = Blueprint('test_text', url_prefix='/test1')
|
bp = Blueprint("test_text", url_prefix="/test1")
|
||||||
bp2 = Blueprint('test_text2', url_prefix='/test2')
|
bp2 = Blueprint("test_text2", url_prefix="/test2")
|
||||||
|
|
||||||
@bp.route('/')
|
@bp.route("/")
|
||||||
def handler(request):
|
def handler(request):
|
||||||
return text('Hello')
|
return text("Hello")
|
||||||
|
|
||||||
@bp2.route('/')
|
@bp2.route("/")
|
||||||
def handler2(request):
|
def handler2(request):
|
||||||
return text('Hello2')
|
return text("Hello2")
|
||||||
|
|
||||||
app.blueprint(bp)
|
app.blueprint(bp)
|
||||||
app.blueprint(bp2)
|
app.blueprint(bp2)
|
||||||
request, response = app.test_client.get('/test1/')
|
request, response = app.test_client.get("/test1/")
|
||||||
assert response.text == 'Hello'
|
assert response.text == "Hello"
|
||||||
|
|
||||||
request, response = app.test_client.get('/test2/')
|
request, response = app.test_client.get("/test2/")
|
||||||
assert response.text == 'Hello2'
|
assert response.text == "Hello2"
|
||||||
|
|
||||||
|
|
||||||
def test_bp_with_host(app):
|
def test_bp_with_host(app):
|
||||||
bp = Blueprint('test_bp_host', url_prefix='/test1', host="example.com")
|
bp = Blueprint("test_bp_host", url_prefix="/test1", host="example.com")
|
||||||
|
|
||||||
@bp.route('/')
|
@bp.route("/")
|
||||||
def handler1(request):
|
def handler1(request):
|
||||||
return text('Hello')
|
return text("Hello")
|
||||||
|
|
||||||
@bp.route('/', host="sub.example.com")
|
@bp.route("/", host="sub.example.com")
|
||||||
def handler2(request):
|
def handler2(request):
|
||||||
return text('Hello subdomain!')
|
return text("Hello subdomain!")
|
||||||
|
|
||||||
app.blueprint(bp)
|
app.blueprint(bp)
|
||||||
headers = {"Host": "example.com"}
|
headers = {"Host": "example.com"}
|
||||||
request, response = app.test_client.get(
|
request, response = app.test_client.get("/test1/", headers=headers)
|
||||||
'/test1/',
|
assert response.text == "Hello"
|
||||||
headers=headers)
|
|
||||||
assert response.text == 'Hello'
|
|
||||||
|
|
||||||
headers = {"Host": "sub.example.com"}
|
headers = {"Host": "sub.example.com"}
|
||||||
request, response = app.test_client.get(
|
request, response = app.test_client.get("/test1/", headers=headers)
|
||||||
'/test1/',
|
|
||||||
headers=headers)
|
|
||||||
|
|
||||||
assert response.text == 'Hello subdomain!'
|
assert response.text == "Hello subdomain!"
|
||||||
|
|
||||||
|
|
||||||
def test_several_bp_with_host(app):
|
def test_several_bp_with_host(app):
|
||||||
bp = Blueprint('test_text',
|
bp = Blueprint("test_text", url_prefix="/test", host="example.com")
|
||||||
url_prefix='/test',
|
bp2 = Blueprint("test_text2", url_prefix="/test", host="sub.example.com")
|
||||||
host="example.com")
|
|
||||||
bp2 = Blueprint('test_text2',
|
|
||||||
url_prefix='/test',
|
|
||||||
host="sub.example.com")
|
|
||||||
|
|
||||||
@bp.route('/')
|
@bp.route("/")
|
||||||
def handler(request):
|
def handler(request):
|
||||||
return text('Hello')
|
return text("Hello")
|
||||||
|
|
||||||
@bp2.route('/')
|
@bp2.route("/")
|
||||||
def handler1(request):
|
def handler1(request):
|
||||||
return text('Hello2')
|
return text("Hello2")
|
||||||
|
|
||||||
@bp2.route('/other/')
|
@bp2.route("/other/")
|
||||||
def handler2(request):
|
def handler2(request):
|
||||||
return text('Hello3')
|
return text("Hello3")
|
||||||
|
|
||||||
app.blueprint(bp)
|
app.blueprint(bp)
|
||||||
app.blueprint(bp2)
|
app.blueprint(bp2)
|
||||||
|
|
||||||
assert bp.host == "example.com"
|
assert bp.host == "example.com"
|
||||||
headers = {"Host": "example.com"}
|
headers = {"Host": "example.com"}
|
||||||
request, response = app.test_client.get(
|
request, response = app.test_client.get("/test/", headers=headers)
|
||||||
'/test/',
|
assert response.text == "Hello"
|
||||||
headers=headers)
|
|
||||||
assert response.text == 'Hello'
|
|
||||||
|
|
||||||
assert bp2.host == "sub.example.com"
|
assert bp2.host == "sub.example.com"
|
||||||
headers = {"Host": "sub.example.com"}
|
headers = {"Host": "sub.example.com"}
|
||||||
request, response = app.test_client.get(
|
request, response = app.test_client.get("/test/", headers=headers)
|
||||||
'/test/',
|
|
||||||
headers=headers)
|
|
||||||
|
|
||||||
assert response.text == 'Hello2'
|
assert response.text == "Hello2"
|
||||||
request, response = app.test_client.get(
|
request, response = app.test_client.get("/test/other/", headers=headers)
|
||||||
'/test/other/',
|
assert response.text == "Hello3"
|
||||||
headers=headers)
|
|
||||||
assert response.text == 'Hello3'
|
|
||||||
|
|
||||||
|
|
||||||
def test_bp_middleware(app):
|
def test_bp_middleware(app):
|
||||||
blueprint = Blueprint('test_middleware')
|
blueprint = Blueprint("test_middleware")
|
||||||
|
|
||||||
@blueprint.middleware('response')
|
@blueprint.middleware("response")
|
||||||
async def process_response(request, response):
|
async def process_response(request, response):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
@app.route('/')
|
@app.route("/")
|
||||||
async def handler(request):
|
async def handler(request):
|
||||||
return text('FAIL')
|
return text("FAIL")
|
||||||
|
|
||||||
app.blueprint(blueprint)
|
app.blueprint(blueprint)
|
||||||
|
|
||||||
request, response = app.test_client.get('/')
|
request, response = app.test_client.get("/")
|
||||||
|
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == 'OK'
|
assert response.text == "OK"
|
||||||
|
|
||||||
|
|
||||||
def test_bp_exception_handler(app):
|
def test_bp_exception_handler(app):
|
||||||
blueprint = Blueprint('test_middleware')
|
blueprint = Blueprint("test_middleware")
|
||||||
|
|
||||||
@blueprint.route('/1')
|
@blueprint.route("/1")
|
||||||
def handler_1(request):
|
def handler_1(request):
|
||||||
raise InvalidUsage("OK")
|
raise InvalidUsage("OK")
|
||||||
|
|
||||||
@blueprint.route('/2')
|
@blueprint.route("/2")
|
||||||
def handler_2(request):
|
def handler_2(request):
|
||||||
raise ServerError("OK")
|
raise ServerError("OK")
|
||||||
|
|
||||||
@blueprint.route('/3')
|
@blueprint.route("/3")
|
||||||
def handler_3(request):
|
def handler_3(request):
|
||||||
raise NotFound("OK")
|
raise NotFound("OK")
|
||||||
|
|
||||||
|
@ -303,131 +292,131 @@ def test_bp_exception_handler(app):
|
||||||
|
|
||||||
app.blueprint(blueprint)
|
app.blueprint(blueprint)
|
||||||
|
|
||||||
request, response = app.test_client.get('/1')
|
request, response = app.test_client.get("/1")
|
||||||
assert response.status == 400
|
assert response.status == 400
|
||||||
|
|
||||||
request, response = app.test_client.get('/2')
|
request, response = app.test_client.get("/2")
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == 'OK'
|
assert response.text == "OK"
|
||||||
|
|
||||||
request, response = app.test_client.get('/3')
|
request, response = app.test_client.get("/3")
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
|
|
||||||
|
|
||||||
def test_bp_listeners(app):
|
def test_bp_listeners(app):
|
||||||
blueprint = Blueprint('test_middleware')
|
blueprint = Blueprint("test_middleware")
|
||||||
|
|
||||||
order = []
|
order = []
|
||||||
|
|
||||||
@blueprint.listener('before_server_start')
|
@blueprint.listener("before_server_start")
|
||||||
def handler_1(sanic, loop):
|
def handler_1(sanic, loop):
|
||||||
order.append(1)
|
order.append(1)
|
||||||
|
|
||||||
@blueprint.listener('after_server_start')
|
@blueprint.listener("after_server_start")
|
||||||
def handler_2(sanic, loop):
|
def handler_2(sanic, loop):
|
||||||
order.append(2)
|
order.append(2)
|
||||||
|
|
||||||
@blueprint.listener('after_server_start')
|
@blueprint.listener("after_server_start")
|
||||||
def handler_3(sanic, loop):
|
def handler_3(sanic, loop):
|
||||||
order.append(3)
|
order.append(3)
|
||||||
|
|
||||||
@blueprint.listener('before_server_stop')
|
@blueprint.listener("before_server_stop")
|
||||||
def handler_4(sanic, loop):
|
def handler_4(sanic, loop):
|
||||||
order.append(5)
|
order.append(5)
|
||||||
|
|
||||||
@blueprint.listener('before_server_stop')
|
@blueprint.listener("before_server_stop")
|
||||||
def handler_5(sanic, loop):
|
def handler_5(sanic, loop):
|
||||||
order.append(4)
|
order.append(4)
|
||||||
|
|
||||||
@blueprint.listener('after_server_stop')
|
@blueprint.listener("after_server_stop")
|
||||||
def handler_6(sanic, loop):
|
def handler_6(sanic, loop):
|
||||||
order.append(6)
|
order.append(6)
|
||||||
|
|
||||||
app.blueprint(blueprint)
|
app.blueprint(blueprint)
|
||||||
|
|
||||||
request, response = app.test_client.get('/')
|
request, response = app.test_client.get("/")
|
||||||
|
|
||||||
assert order == [1, 2, 3, 4, 5, 6]
|
assert order == [1, 2, 3, 4, 5, 6]
|
||||||
|
|
||||||
|
|
||||||
def test_bp_static(app):
|
def test_bp_static(app):
|
||||||
current_file = inspect.getfile(inspect.currentframe())
|
current_file = inspect.getfile(inspect.currentframe())
|
||||||
with open(current_file, 'rb') as file:
|
with open(current_file, "rb") as file:
|
||||||
current_file_contents = file.read()
|
current_file_contents = file.read()
|
||||||
|
|
||||||
blueprint = Blueprint('test_static')
|
blueprint = Blueprint("test_static")
|
||||||
|
|
||||||
blueprint.static('/testing.file', current_file)
|
blueprint.static("/testing.file", current_file)
|
||||||
|
|
||||||
app.blueprint(blueprint)
|
app.blueprint(blueprint)
|
||||||
|
|
||||||
request, response = app.test_client.get('/testing.file')
|
request, response = app.test_client.get("/testing.file")
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.body == current_file_contents
|
assert response.body == current_file_contents
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('file_name', ['test.html'])
|
@pytest.mark.parametrize("file_name", ["test.html"])
|
||||||
def test_bp_static_content_type(app, file_name):
|
def test_bp_static_content_type(app, file_name):
|
||||||
# This is done here, since no other test loads a file here
|
# This is done here, since no other test loads a file here
|
||||||
current_file = inspect.getfile(inspect.currentframe())
|
current_file = inspect.getfile(inspect.currentframe())
|
||||||
current_directory = os.path.dirname(os.path.abspath(current_file))
|
current_directory = os.path.dirname(os.path.abspath(current_file))
|
||||||
static_directory = os.path.join(current_directory, 'static')
|
static_directory = os.path.join(current_directory, "static")
|
||||||
|
|
||||||
blueprint = Blueprint('test_static')
|
blueprint = Blueprint("test_static")
|
||||||
blueprint.static(
|
blueprint.static(
|
||||||
'/testing.file',
|
"/testing.file",
|
||||||
get_file_path(static_directory, file_name),
|
get_file_path(static_directory, file_name),
|
||||||
content_type='text/html; charset=utf-8'
|
content_type="text/html; charset=utf-8",
|
||||||
)
|
)
|
||||||
|
|
||||||
app.blueprint(blueprint)
|
app.blueprint(blueprint)
|
||||||
|
|
||||||
request, response = app.test_client.get('/testing.file')
|
request, response = app.test_client.get("/testing.file")
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.body == get_file_content(static_directory, file_name)
|
assert response.body == get_file_content(static_directory, file_name)
|
||||||
assert response.headers['Content-Type'] == 'text/html; charset=utf-8'
|
assert response.headers["Content-Type"] == "text/html; charset=utf-8"
|
||||||
|
|
||||||
|
|
||||||
def test_bp_shorthand(app):
|
def test_bp_shorthand(app):
|
||||||
blueprint = Blueprint('test_shorhand_routes')
|
blueprint = Blueprint("test_shorhand_routes")
|
||||||
ev = asyncio.Event()
|
ev = asyncio.Event()
|
||||||
|
|
||||||
@blueprint.get('/get')
|
@blueprint.get("/get")
|
||||||
def handler(request):
|
def handler(request):
|
||||||
assert request.stream is None
|
assert request.stream is None
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
@blueprint.put('/put')
|
@blueprint.put("/put")
|
||||||
def put_handler(request):
|
def put_handler(request):
|
||||||
assert request.stream is None
|
assert request.stream is None
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
@blueprint.post('/post')
|
@blueprint.post("/post")
|
||||||
def post_handler(request):
|
def post_handler(request):
|
||||||
assert request.stream is None
|
assert request.stream is None
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
@blueprint.head('/head')
|
@blueprint.head("/head")
|
||||||
def head_handler(request):
|
def head_handler(request):
|
||||||
assert request.stream is None
|
assert request.stream is None
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
@blueprint.options('/options')
|
@blueprint.options("/options")
|
||||||
def options_handler(request):
|
def options_handler(request):
|
||||||
assert request.stream is None
|
assert request.stream is None
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
@blueprint.patch('/patch')
|
@blueprint.patch("/patch")
|
||||||
def patch_handler(request):
|
def patch_handler(request):
|
||||||
assert request.stream is None
|
assert request.stream is None
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
@blueprint.delete('/delete')
|
@blueprint.delete("/delete")
|
||||||
def delete_handler(request):
|
def delete_handler(request):
|
||||||
assert request.stream is None
|
assert request.stream is None
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
@blueprint.websocket('/ws/', strict_slashes=True)
|
@blueprint.websocket("/ws/", strict_slashes=True)
|
||||||
async def websocket_handler(request, ws):
|
async def websocket_handler(request, ws):
|
||||||
assert request.stream is None
|
assert request.stream is None
|
||||||
ev.set()
|
ev.set()
|
||||||
|
@ -436,137 +425,146 @@ def test_bp_shorthand(app):
|
||||||
|
|
||||||
assert app.is_request_stream is False
|
assert app.is_request_stream is False
|
||||||
|
|
||||||
request, response = app.test_client.get('/get')
|
request, response = app.test_client.get("/get")
|
||||||
assert response.text == 'OK'
|
assert response.text == "OK"
|
||||||
|
|
||||||
request, response = app.test_client.post('/get')
|
request, response = app.test_client.post("/get")
|
||||||
assert response.status == 405
|
assert response.status == 405
|
||||||
|
|
||||||
request, response = app.test_client.put('/put')
|
request, response = app.test_client.put("/put")
|
||||||
assert response.text == 'OK'
|
assert response.text == "OK"
|
||||||
|
|
||||||
request, response = app.test_client.get('/post')
|
request, response = app.test_client.get("/post")
|
||||||
assert response.status == 405
|
assert response.status == 405
|
||||||
|
|
||||||
request, response = app.test_client.post('/post')
|
request, response = app.test_client.post("/post")
|
||||||
assert response.text == 'OK'
|
assert response.text == "OK"
|
||||||
|
|
||||||
request, response = app.test_client.get('/post')
|
request, response = app.test_client.get("/post")
|
||||||
assert response.status == 405
|
assert response.status == 405
|
||||||
|
|
||||||
request, response = app.test_client.head('/head')
|
request, response = app.test_client.head("/head")
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
|
|
||||||
request, response = app.test_client.get('/head')
|
request, response = app.test_client.get("/head")
|
||||||
assert response.status == 405
|
assert response.status == 405
|
||||||
|
|
||||||
request, response = app.test_client.options('/options')
|
request, response = app.test_client.options("/options")
|
||||||
assert response.text == 'OK'
|
assert response.text == "OK"
|
||||||
|
|
||||||
request, response = app.test_client.get('/options')
|
request, response = app.test_client.get("/options")
|
||||||
assert response.status == 405
|
assert response.status == 405
|
||||||
|
|
||||||
request, response = app.test_client.patch('/patch')
|
request, response = app.test_client.patch("/patch")
|
||||||
assert response.text == 'OK'
|
assert response.text == "OK"
|
||||||
|
|
||||||
request, response = app.test_client.get('/patch')
|
request, response = app.test_client.get("/patch")
|
||||||
assert response.status == 405
|
assert response.status == 405
|
||||||
|
|
||||||
request, response = app.test_client.delete('/delete')
|
request, response = app.test_client.delete("/delete")
|
||||||
assert response.text == 'OK'
|
assert response.text == "OK"
|
||||||
|
|
||||||
request, response = app.test_client.get('/delete')
|
request, response = app.test_client.get("/delete")
|
||||||
assert response.status == 405
|
assert response.status == 405
|
||||||
|
|
||||||
request, response = app.test_client.get('/ws/', headers={
|
request, response = app.test_client.get(
|
||||||
'Upgrade': 'websocket',
|
"/ws/",
|
||||||
'Connection': 'upgrade',
|
headers={
|
||||||
'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==',
|
"Upgrade": "websocket",
|
||||||
'Sec-WebSocket-Version': '13'})
|
"Connection": "upgrade",
|
||||||
|
"Sec-WebSocket-Key": "dGhlIHNhbXBsZSBub25jZQ==",
|
||||||
|
"Sec-WebSocket-Version": "13",
|
||||||
|
},
|
||||||
|
)
|
||||||
assert response.status == 101
|
assert response.status == 101
|
||||||
assert ev.is_set()
|
assert ev.is_set()
|
||||||
|
|
||||||
|
|
||||||
def test_bp_group(app):
|
def test_bp_group(app):
|
||||||
deep_0 = Blueprint('deep_0', url_prefix='/deep')
|
deep_0 = Blueprint("deep_0", url_prefix="/deep")
|
||||||
deep_1 = Blueprint('deep_1', url_prefix='/deep1')
|
deep_1 = Blueprint("deep_1", url_prefix="/deep1")
|
||||||
|
|
||||||
@deep_0.route('/')
|
@deep_0.route("/")
|
||||||
def handler(request):
|
def handler(request):
|
||||||
return text('D0_OK')
|
return text("D0_OK")
|
||||||
|
|
||||||
@deep_1.route('/bottom')
|
@deep_1.route("/bottom")
|
||||||
def bottom_handler(request):
|
def bottom_handler(request):
|
||||||
return text('D1B_OK')
|
return text("D1B_OK")
|
||||||
|
|
||||||
mid_0 = Blueprint.group(deep_0, deep_1, url_prefix='/mid')
|
mid_0 = Blueprint.group(deep_0, deep_1, url_prefix="/mid")
|
||||||
mid_1 = Blueprint('mid_tier', url_prefix='/mid1')
|
mid_1 = Blueprint("mid_tier", url_prefix="/mid1")
|
||||||
|
|
||||||
@mid_1.route('/')
|
@mid_1.route("/")
|
||||||
def handler1(request):
|
def handler1(request):
|
||||||
return text('M1_OK')
|
return text("M1_OK")
|
||||||
|
|
||||||
top = Blueprint.group(mid_0, mid_1)
|
top = Blueprint.group(mid_0, mid_1)
|
||||||
|
|
||||||
app.blueprint(top)
|
app.blueprint(top)
|
||||||
|
|
||||||
@app.route('/')
|
@app.route("/")
|
||||||
def handler2(request):
|
def handler2(request):
|
||||||
return text('TOP_OK')
|
return text("TOP_OK")
|
||||||
|
|
||||||
request, response = app.test_client.get('/')
|
request, response = app.test_client.get("/")
|
||||||
assert response.text == 'TOP_OK'
|
assert response.text == "TOP_OK"
|
||||||
|
|
||||||
request, response = app.test_client.get('/mid1')
|
request, response = app.test_client.get("/mid1")
|
||||||
assert response.text == 'M1_OK'
|
assert response.text == "M1_OK"
|
||||||
|
|
||||||
request, response = app.test_client.get('/mid/deep')
|
request, response = app.test_client.get("/mid/deep")
|
||||||
assert response.text == 'D0_OK'
|
assert response.text == "D0_OK"
|
||||||
|
|
||||||
request, response = app.test_client.get('/mid/deep1/bottom')
|
request, response = app.test_client.get("/mid/deep1/bottom")
|
||||||
assert response.text == 'D1B_OK'
|
assert response.text == "D1B_OK"
|
||||||
|
|
||||||
|
|
||||||
def test_bp_group_with_default_url_prefix(app):
|
def test_bp_group_with_default_url_prefix(app):
|
||||||
from sanic.response import json
|
from sanic.response import json
|
||||||
bp_resources = Blueprint('bp_resources')
|
|
||||||
|
|
||||||
@bp_resources.get('/')
|
bp_resources = Blueprint("bp_resources")
|
||||||
|
|
||||||
|
@bp_resources.get("/")
|
||||||
def list_resources_handler(request):
|
def list_resources_handler(request):
|
||||||
resource = {}
|
resource = {}
|
||||||
return json([resource])
|
return json([resource])
|
||||||
|
|
||||||
bp_resource = Blueprint('bp_resource', url_prefix='/<resource_id>')
|
bp_resource = Blueprint("bp_resource", url_prefix="/<resource_id>")
|
||||||
|
|
||||||
@bp_resource.get('/')
|
@bp_resource.get("/")
|
||||||
def get_resource_hander(request, resource_id):
|
def get_resource_hander(request, resource_id):
|
||||||
resource = {'resource_id': resource_id}
|
resource = {"resource_id": resource_id}
|
||||||
return json(resource)
|
return json(resource)
|
||||||
|
|
||||||
bp_resources_group = Blueprint.group(bp_resources, bp_resource,
|
bp_resources_group = Blueprint.group(
|
||||||
url_prefix='/resources')
|
bp_resources, bp_resource, url_prefix="/resources"
|
||||||
bp_api_v1 = Blueprint('bp_api_v1')
|
)
|
||||||
|
bp_api_v1 = Blueprint("bp_api_v1")
|
||||||
|
|
||||||
@bp_api_v1.get('/info')
|
@bp_api_v1.get("/info")
|
||||||
def api_v1_info(request):
|
def api_v1_info(request):
|
||||||
return text('api_version: v1')
|
return text("api_version: v1")
|
||||||
|
|
||||||
bp_api_v1_group = Blueprint.group(bp_api_v1, bp_resources_group,
|
bp_api_v1_group = Blueprint.group(
|
||||||
url_prefix='/v1')
|
bp_api_v1, bp_resources_group, url_prefix="/v1"
|
||||||
bp_api_group = Blueprint.group(bp_api_v1_group, url_prefix='/api')
|
)
|
||||||
|
bp_api_group = Blueprint.group(bp_api_v1_group, url_prefix="/api")
|
||||||
app.blueprint(bp_api_group)
|
app.blueprint(bp_api_group)
|
||||||
|
|
||||||
request, response = app.test_client.get('/api/v1/info')
|
request, response = app.test_client.get("/api/v1/info")
|
||||||
assert response.text == 'api_version: v1'
|
assert response.text == "api_version: v1"
|
||||||
|
|
||||||
request, response = app.test_client.get('/api/v1/resources')
|
request, response = app.test_client.get("/api/v1/resources")
|
||||||
assert response.json == [{}]
|
assert response.json == [{}]
|
||||||
|
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
|
|
||||||
resource_id = str(uuid4())
|
resource_id = str(uuid4())
|
||||||
request, response = app.test_client.get(
|
request, response = app.test_client.get(
|
||||||
'/api/v1/resources/{0}'.format(resource_id))
|
"/api/v1/resources/{0}".format(resource_id)
|
||||||
assert response.json == {'resource_id': resource_id}
|
)
|
||||||
|
assert response.json == {"resource_id": resource_id}
|
||||||
|
|
||||||
|
|
||||||
def test_blueprint_middleware_with_args(app: Sanic):
|
def test_blueprint_middleware_with_args(app: Sanic):
|
||||||
|
@ -588,19 +586,22 @@ def test_blueprint_middleware_with_args(app: Sanic):
|
||||||
|
|
||||||
app.blueprint(bp)
|
app.blueprint(bp)
|
||||||
|
|
||||||
_, response = app.test_client.get("/wa", headers={"content-type": "application/json"})
|
_, response = app.test_client.get(
|
||||||
|
"/wa", headers={"content-type": "application/json"}
|
||||||
|
)
|
||||||
assert response.text == "value"
|
assert response.text == "value"
|
||||||
|
|
||||||
_, response = app.test_client.get("/wa", headers={"content-type": "plain/text"})
|
_, response = app.test_client.get(
|
||||||
|
"/wa", headers={"content-type": "plain/text"}
|
||||||
|
)
|
||||||
assert response.json.get("test") == "value"
|
assert response.json.get("test") == "value"
|
||||||
d = {}
|
d = {}
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('file_name',
|
@pytest.mark.parametrize("file_name", ["test.file"])
|
||||||
['test.file'])
|
|
||||||
def test_static_blueprint_name(app: Sanic, static_file_directory, file_name):
|
def test_static_blueprint_name(app: Sanic, static_file_directory, file_name):
|
||||||
current_file = inspect.getfile(inspect.currentframe())
|
current_file = inspect.getfile(inspect.currentframe())
|
||||||
with open(current_file, 'rb') as file:
|
with open(current_file, "rb") as file:
|
||||||
current_file_contents = file.read()
|
current_file_contents = file.read()
|
||||||
|
|
||||||
bp = Blueprint(name="static", url_prefix="/static", strict_slashes=False)
|
bp = Blueprint(name="static", url_prefix="/static", strict_slashes=False)
|
||||||
|
@ -609,11 +610,12 @@ def test_static_blueprint_name(app: Sanic, static_file_directory, file_name):
|
||||||
"/test.file/",
|
"/test.file/",
|
||||||
get_file_path(static_file_directory, file_name),
|
get_file_path(static_file_directory, file_name),
|
||||||
name="static.testing",
|
name="static.testing",
|
||||||
strict_slashes=True)
|
strict_slashes=True,
|
||||||
|
)
|
||||||
|
|
||||||
app.blueprint(bp)
|
app.blueprint(bp)
|
||||||
|
|
||||||
uri = app.url_for('static', name='static.testing')
|
uri = app.url_for("static", name="static.testing")
|
||||||
assert uri == "/static/test.file"
|
assert uri == "/static/test.file"
|
||||||
|
|
||||||
_, response = app.test_client.get("/static/test.file")
|
_, response = app.test_client.get("/static/test.file")
|
||||||
|
@ -627,9 +629,7 @@ def test_route_handler_add(app: Sanic):
|
||||||
view = CompositionView()
|
view = CompositionView()
|
||||||
|
|
||||||
async def get_handler(request):
|
async def get_handler(request):
|
||||||
return json({
|
return json({"response": "OK"})
|
||||||
"response": "OK"
|
|
||||||
})
|
|
||||||
|
|
||||||
view.add(["GET"], get_handler, stream=False)
|
view.add(["GET"], get_handler, stream=False)
|
||||||
|
|
||||||
|
@ -637,10 +637,7 @@ def test_route_handler_add(app: Sanic):
|
||||||
return text("OK")
|
return text("OK")
|
||||||
|
|
||||||
bp = Blueprint(name="handler", url_prefix="/handler")
|
bp = Blueprint(name="handler", url_prefix="/handler")
|
||||||
bp.add_route(
|
bp.add_route(default_handler, uri="/default/", strict_slashes=True)
|
||||||
default_handler,
|
|
||||||
uri="/default/",
|
|
||||||
strict_slashes=True)
|
|
||||||
|
|
||||||
bp.add_route(view, uri="/view", name="test")
|
bp.add_route(view, uri="/view", name="test")
|
||||||
|
|
||||||
|
@ -665,18 +662,21 @@ def test_websocket_route(app: Sanic):
|
||||||
|
|
||||||
app.blueprint(bp)
|
app.blueprint(bp)
|
||||||
|
|
||||||
_, response = app.test_client.get("/ws/test", headers={
|
_, response = app.test_client.get(
|
||||||
'Upgrade': 'websocket',
|
"/ws/test",
|
||||||
'Connection': 'upgrade',
|
headers={
|
||||||
'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==',
|
"Upgrade": "websocket",
|
||||||
'Sec-WebSocket-Version': '13'
|
"Connection": "upgrade",
|
||||||
})
|
"Sec-WebSocket-Key": "dGhlIHNhbXBsZSBub25jZQ==",
|
||||||
|
"Sec-WebSocket-Version": "13",
|
||||||
|
},
|
||||||
|
)
|
||||||
assert response.status == 101
|
assert response.status == 101
|
||||||
assert event.is_set()
|
assert event.is_set()
|
||||||
|
|
||||||
|
|
||||||
def test_duplicate_blueprint(app):
|
def test_duplicate_blueprint(app):
|
||||||
bp_name = 'bp'
|
bp_name = "bp"
|
||||||
bp = Blueprint(bp_name)
|
bp = Blueprint(bp_name)
|
||||||
bp1 = Blueprint(bp_name)
|
bp1 = Blueprint(bp_name)
|
||||||
|
|
||||||
|
@ -687,13 +687,13 @@ def test_duplicate_blueprint(app):
|
||||||
|
|
||||||
assert str(excinfo.value) == (
|
assert str(excinfo.value) == (
|
||||||
'A blueprint with the name "{}" is already registered. '
|
'A blueprint with the name "{}" is already registered. '
|
||||||
'Blueprint names must be unique.'
|
"Blueprint names must be unique."
|
||||||
).format(bp_name)
|
).format(bp_name)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('debug', [True, False, None])
|
@pytest.mark.parametrize("debug", [True, False, None])
|
||||||
def test_register_blueprint(app, debug):
|
def test_register_blueprint(app, debug):
|
||||||
bp = Blueprint('bp')
|
bp = Blueprint("bp")
|
||||||
|
|
||||||
app.debug = debug
|
app.debug = debug
|
||||||
with pytest.warns(DeprecationWarning) as record:
|
with pytest.warns(DeprecationWarning) as record:
|
||||||
|
|
|
@ -13,7 +13,7 @@ from sanic.exceptions import PyFileError
|
||||||
def temp_path():
|
def temp_path():
|
||||||
""" a simple cross platform replacement for NamedTemporaryFile """
|
""" a simple cross platform replacement for NamedTemporaryFile """
|
||||||
with TemporaryDirectory() as td:
|
with TemporaryDirectory() as td:
|
||||||
yield Path(td, 'file')
|
yield Path(td, "file")
|
||||||
|
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
|
@ -23,9 +23,9 @@ class Config:
|
||||||
|
|
||||||
def test_load_from_object(app):
|
def test_load_from_object(app):
|
||||||
app.config.from_object(Config)
|
app.config.from_object(Config)
|
||||||
assert 'CONFIG_VALUE' in app.config
|
assert "CONFIG_VALUE" in app.config
|
||||||
assert app.config.CONFIG_VALUE == 'should be used'
|
assert app.config.CONFIG_VALUE == "should be used"
|
||||||
assert 'not_for_config' not in app.config
|
assert "not_for_config" not in app.config
|
||||||
|
|
||||||
|
|
||||||
def test_load_from_object_string(app):
|
def test_load_from_object_string(app):
|
||||||
|
@ -50,13 +50,13 @@ def test_auto_load_env():
|
||||||
def test_dont_load_env():
|
def test_dont_load_env():
|
||||||
environ["SANIC_TEST_ANSWER"] = "42"
|
environ["SANIC_TEST_ANSWER"] = "42"
|
||||||
app = Sanic(load_env=False)
|
app = Sanic(load_env=False)
|
||||||
assert getattr(app.config, 'TEST_ANSWER', None) is None
|
assert getattr(app.config, "TEST_ANSWER", None) is None
|
||||||
del environ["SANIC_TEST_ANSWER"]
|
del environ["SANIC_TEST_ANSWER"]
|
||||||
|
|
||||||
|
|
||||||
def test_load_env_prefix():
|
def test_load_env_prefix():
|
||||||
environ["MYAPP_TEST_ANSWER"] = "42"
|
environ["MYAPP_TEST_ANSWER"] = "42"
|
||||||
app = Sanic(load_env='MYAPP_')
|
app = Sanic(load_env="MYAPP_")
|
||||||
assert app.config.TEST_ANSWER == 42
|
assert app.config.TEST_ANSWER == 42
|
||||||
del environ["MYAPP_TEST_ANSWER"]
|
del environ["MYAPP_TEST_ANSWER"]
|
||||||
|
|
||||||
|
@ -76,43 +76,47 @@ def test_load_env_prefix_string_value():
|
||||||
|
|
||||||
|
|
||||||
def test_load_from_file(app):
|
def test_load_from_file(app):
|
||||||
config = dedent("""
|
config = dedent(
|
||||||
|
"""
|
||||||
VALUE = 'some value'
|
VALUE = 'some value'
|
||||||
condition = 1 == 1
|
condition = 1 == 1
|
||||||
if condition:
|
if condition:
|
||||||
CONDITIONAL = 'should be set'
|
CONDITIONAL = 'should be set'
|
||||||
""")
|
"""
|
||||||
|
)
|
||||||
with temp_path() as config_path:
|
with temp_path() as config_path:
|
||||||
config_path.write_text(config)
|
config_path.write_text(config)
|
||||||
app.config.from_pyfile(str(config_path))
|
app.config.from_pyfile(str(config_path))
|
||||||
assert 'VALUE' in app.config
|
assert "VALUE" in app.config
|
||||||
assert app.config.VALUE == 'some value'
|
assert app.config.VALUE == "some value"
|
||||||
assert 'CONDITIONAL' in app.config
|
assert "CONDITIONAL" in app.config
|
||||||
assert app.config.CONDITIONAL == 'should be set'
|
assert app.config.CONDITIONAL == "should be set"
|
||||||
assert 'condition' not in app.config
|
assert "condition" not in app.config
|
||||||
|
|
||||||
|
|
||||||
def test_load_from_missing_file(app):
|
def test_load_from_missing_file(app):
|
||||||
with pytest.raises(IOError):
|
with pytest.raises(IOError):
|
||||||
app.config.from_pyfile('non-existent file')
|
app.config.from_pyfile("non-existent file")
|
||||||
|
|
||||||
|
|
||||||
def test_load_from_envvar(app):
|
def test_load_from_envvar(app):
|
||||||
config = "VALUE = 'some value'"
|
config = "VALUE = 'some value'"
|
||||||
with temp_path() as config_path:
|
with temp_path() as config_path:
|
||||||
config_path.write_text(config)
|
config_path.write_text(config)
|
||||||
environ['APP_CONFIG'] = str(config_path)
|
environ["APP_CONFIG"] = str(config_path)
|
||||||
app.config.from_envvar('APP_CONFIG')
|
app.config.from_envvar("APP_CONFIG")
|
||||||
assert 'VALUE' in app.config
|
assert "VALUE" in app.config
|
||||||
assert app.config.VALUE == 'some value'
|
assert app.config.VALUE == "some value"
|
||||||
|
|
||||||
|
|
||||||
def test_load_from_missing_envvar(app):
|
def test_load_from_missing_envvar(app):
|
||||||
with pytest.raises(RuntimeError) as e:
|
with pytest.raises(RuntimeError) as e:
|
||||||
app.config.from_envvar('non-existent variable')
|
app.config.from_envvar("non-existent variable")
|
||||||
assert str(e.value) == ("The environment variable 'non-existent "
|
assert str(e.value) == (
|
||||||
"variable' is not set and thus configuration "
|
"The environment variable 'non-existent "
|
||||||
"could not be loaded.")
|
"variable' is not set and thus configuration "
|
||||||
|
"could not be loaded."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_load_config_from_file_invalid_syntax(app):
|
def test_load_config_from_file_invalid_syntax(app):
|
||||||
|
|
|
@ -8,109 +8,99 @@ from sanic.cookies import Cookie
|
||||||
# GET
|
# GET
|
||||||
# ------------------------------------------------------------ #
|
# ------------------------------------------------------------ #
|
||||||
|
|
||||||
|
|
||||||
def test_cookies(app):
|
def test_cookies(app):
|
||||||
|
@app.route("/")
|
||||||
@app.route('/')
|
|
||||||
def handler(request):
|
def handler(request):
|
||||||
response = text('Cookies are: {}'.format(request.cookies['test']))
|
response = text("Cookies are: {}".format(request.cookies["test"]))
|
||||||
response.cookies['right_back'] = 'at you'
|
response.cookies["right_back"] = "at you"
|
||||||
return response
|
return response
|
||||||
|
|
||||||
request, response = app.test_client.get('/', cookies={"test": "working!"})
|
request, response = app.test_client.get("/", cookies={"test": "working!"})
|
||||||
response_cookies = SimpleCookie()
|
response_cookies = SimpleCookie()
|
||||||
response_cookies.load(response.headers.get('Set-Cookie', {}))
|
response_cookies.load(response.headers.get("Set-Cookie", {}))
|
||||||
|
|
||||||
assert response.text == 'Cookies are: working!'
|
assert response.text == "Cookies are: working!"
|
||||||
assert response_cookies['right_back'].value == 'at you'
|
assert response_cookies["right_back"].value == "at you"
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("httponly,expected", [
|
@pytest.mark.parametrize("httponly,expected", [(False, False), (True, True)])
|
||||||
(False, False),
|
|
||||||
(True, True),
|
|
||||||
])
|
|
||||||
def test_false_cookies_encoded(app, httponly, expected):
|
def test_false_cookies_encoded(app, httponly, expected):
|
||||||
|
@app.route("/")
|
||||||
@app.route('/')
|
|
||||||
def handler(request):
|
def handler(request):
|
||||||
response = text('hello cookies')
|
response = text("hello cookies")
|
||||||
response.cookies['hello'] = 'world'
|
response.cookies["hello"] = "world"
|
||||||
response.cookies['hello']['httponly'] = httponly
|
response.cookies["hello"]["httponly"] = httponly
|
||||||
return text(response.cookies['hello'].encode('utf8'))
|
return text(response.cookies["hello"].encode("utf8"))
|
||||||
|
|
||||||
request, response = app.test_client.get('/')
|
request, response = app.test_client.get("/")
|
||||||
|
|
||||||
assert ('HttpOnly' in response.text) == expected
|
assert ("HttpOnly" in response.text) == expected
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("httponly,expected", [
|
@pytest.mark.parametrize("httponly,expected", [(False, False), (True, True)])
|
||||||
(False, False),
|
|
||||||
(True, True),
|
|
||||||
])
|
|
||||||
def test_false_cookies(app, httponly, expected):
|
def test_false_cookies(app, httponly, expected):
|
||||||
|
@app.route("/")
|
||||||
@app.route('/')
|
|
||||||
def handler(request):
|
def handler(request):
|
||||||
response = text('hello cookies')
|
response = text("hello cookies")
|
||||||
response.cookies['right_back'] = 'at you'
|
response.cookies["right_back"] = "at you"
|
||||||
response.cookies['right_back']['httponly'] = httponly
|
response.cookies["right_back"]["httponly"] = httponly
|
||||||
return response
|
return response
|
||||||
|
|
||||||
request, response = app.test_client.get('/')
|
request, response = app.test_client.get("/")
|
||||||
response_cookies = SimpleCookie()
|
response_cookies = SimpleCookie()
|
||||||
response_cookies.load(response.headers.get('Set-Cookie', {}))
|
response_cookies.load(response.headers.get("Set-Cookie", {}))
|
||||||
|
|
||||||
assert ('HttpOnly' in response_cookies['right_back'].output()) == expected
|
assert ("HttpOnly" in response_cookies["right_back"].output()) == expected
|
||||||
|
|
||||||
|
|
||||||
def test_http2_cookies(app):
|
def test_http2_cookies(app):
|
||||||
|
@app.route("/")
|
||||||
@app.route('/')
|
|
||||||
async def handler(request):
|
async def handler(request):
|
||||||
response = text('Cookies are: {}'.format(request.cookies['test']))
|
response = text("Cookies are: {}".format(request.cookies["test"]))
|
||||||
return response
|
return response
|
||||||
|
|
||||||
headers = {'cookie': 'test=working!'}
|
headers = {"cookie": "test=working!"}
|
||||||
request, response = app.test_client.get('/', headers=headers)
|
request, response = app.test_client.get("/", headers=headers)
|
||||||
|
|
||||||
assert response.text == 'Cookies are: working!'
|
assert response.text == "Cookies are: working!"
|
||||||
|
|
||||||
|
|
||||||
def test_cookie_options(app):
|
def test_cookie_options(app):
|
||||||
|
@app.route("/")
|
||||||
@app.route('/')
|
|
||||||
def handler(request):
|
def handler(request):
|
||||||
response = text("OK")
|
response = text("OK")
|
||||||
response.cookies['test'] = 'at you'
|
response.cookies["test"] = "at you"
|
||||||
response.cookies['test']['httponly'] = True
|
response.cookies["test"]["httponly"] = True
|
||||||
response.cookies['test']['expires'] = (datetime.now() +
|
response.cookies["test"]["expires"] = datetime.now() + timedelta(
|
||||||
timedelta(seconds=10))
|
seconds=10
|
||||||
|
)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
request, response = app.test_client.get('/')
|
request, response = app.test_client.get("/")
|
||||||
response_cookies = SimpleCookie()
|
response_cookies = SimpleCookie()
|
||||||
response_cookies.load(response.headers.get('Set-Cookie', {}))
|
response_cookies.load(response.headers.get("Set-Cookie", {}))
|
||||||
|
|
||||||
assert response_cookies['test'].value == 'at you'
|
assert response_cookies["test"].value == "at you"
|
||||||
assert response_cookies['test']['httponly'] is True
|
assert response_cookies["test"]["httponly"] is True
|
||||||
|
|
||||||
|
|
||||||
def test_cookie_deletion(app):
|
def test_cookie_deletion(app):
|
||||||
|
@app.route("/")
|
||||||
@app.route('/')
|
|
||||||
def handler(request):
|
def handler(request):
|
||||||
response = text("OK")
|
response = text("OK")
|
||||||
del response.cookies['i_want_to_die']
|
del response.cookies["i_want_to_die"]
|
||||||
response.cookies['i_never_existed'] = 'testing'
|
response.cookies["i_never_existed"] = "testing"
|
||||||
del response.cookies['i_never_existed']
|
del response.cookies["i_never_existed"]
|
||||||
return response
|
return response
|
||||||
|
|
||||||
request, response = app.test_client.get('/')
|
request, response = app.test_client.get("/")
|
||||||
response_cookies = SimpleCookie()
|
response_cookies = SimpleCookie()
|
||||||
response_cookies.load(response.headers.get('Set-Cookie', {}))
|
response_cookies.load(response.headers.get("Set-Cookie", {}))
|
||||||
|
|
||||||
assert int(response_cookies['i_want_to_die']['max-age']) == 0
|
assert int(response_cookies["i_want_to_die"]["max-age"]) == 0
|
||||||
with pytest.raises(KeyError):
|
with pytest.raises(KeyError):
|
||||||
response.cookies['i_never_existed']
|
response.cookies["i_never_existed"]
|
||||||
|
|
||||||
|
|
||||||
def test_cookie_reserved_cookie():
|
def test_cookie_reserved_cookie():
|
||||||
|
@ -134,58 +124,58 @@ def test_cookie_set_unknown_property():
|
||||||
|
|
||||||
def test_cookie_set_same_key(app):
|
def test_cookie_set_same_key(app):
|
||||||
|
|
||||||
cookies = {'test': 'wait'}
|
cookies = {"test": "wait"}
|
||||||
|
|
||||||
@app.get('/')
|
@app.get("/")
|
||||||
def handler(request):
|
def handler(request):
|
||||||
response = text('pass')
|
response = text("pass")
|
||||||
response.cookies['test'] = 'modified'
|
response.cookies["test"] = "modified"
|
||||||
response.cookies['test'] = 'pass'
|
response.cookies["test"] = "pass"
|
||||||
return response
|
return response
|
||||||
|
|
||||||
request, response = app.test_client.get('/', cookies=cookies)
|
request, response = app.test_client.get("/", cookies=cookies)
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.cookies['test'].value == 'pass'
|
assert response.cookies["test"].value == "pass"
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('max_age', ['0', 30, '30'])
|
@pytest.mark.parametrize("max_age", ["0", 30, "30"])
|
||||||
def test_cookie_max_age(app, max_age):
|
def test_cookie_max_age(app, max_age):
|
||||||
cookies = {'test': 'wait'}
|
cookies = {"test": "wait"}
|
||||||
|
|
||||||
@app.get('/')
|
@app.get("/")
|
||||||
def handler(request):
|
def handler(request):
|
||||||
response = text('pass')
|
response = text("pass")
|
||||||
response.cookies['test'] = 'pass'
|
response.cookies["test"] = "pass"
|
||||||
response.cookies['test']['max-age'] = max_age
|
response.cookies["test"]["max-age"] = max_age
|
||||||
return response
|
return response
|
||||||
|
|
||||||
request, response = app.test_client.get('/', cookies=cookies)
|
request, response = app.test_client.get("/", cookies=cookies)
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
|
|
||||||
assert response.cookies['test'].value == 'pass'
|
assert response.cookies["test"].value == "pass"
|
||||||
assert response.cookies['test']['max-age'] == str(max_age)
|
assert response.cookies["test"]["max-age"] == str(max_age)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('expires', [
|
@pytest.mark.parametrize(
|
||||||
datetime.now() + timedelta(seconds=60),
|
"expires",
|
||||||
'Fri, 21-Dec-2018 15:30:00 GMT'
|
[datetime.now() + timedelta(seconds=60), "Fri, 21-Dec-2018 15:30:00 GMT"],
|
||||||
])
|
)
|
||||||
def test_cookie_expires(app, expires):
|
def test_cookie_expires(app, expires):
|
||||||
cookies = {'test': 'wait'}
|
cookies = {"test": "wait"}
|
||||||
|
|
||||||
@app.get('/')
|
@app.get("/")
|
||||||
def handler(request):
|
def handler(request):
|
||||||
response = text('pass')
|
response = text("pass")
|
||||||
response.cookies['test'] = 'pass'
|
response.cookies["test"] = "pass"
|
||||||
response.cookies['test']['expires'] = expires
|
response.cookies["test"]["expires"] = expires
|
||||||
return response
|
return response
|
||||||
|
|
||||||
request, response = app.test_client.get('/', cookies=cookies)
|
request, response = app.test_client.get("/", cookies=cookies)
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
|
|
||||||
assert response.cookies['test'].value == 'pass'
|
assert response.cookies["test"].value == "pass"
|
||||||
|
|
||||||
if isinstance(expires, datetime):
|
if isinstance(expires, datetime):
|
||||||
expires = expires.strftime("%a, %d-%b-%Y %T GMT")
|
expires = expires.strftime("%a, %d-%b-%Y %T GMT")
|
||||||
|
|
||||||
assert response.cookies['test']['expires'] == expires
|
assert response.cookies["test"]["expires"] == expires
|
||||||
|
|
|
@ -13,26 +13,26 @@ def test_create_task(app):
|
||||||
|
|
||||||
app.add_task(coro)
|
app.add_task(coro)
|
||||||
|
|
||||||
@app.route('/early')
|
@app.route("/early")
|
||||||
def not_set(request):
|
def not_set(request):
|
||||||
return text(e.is_set())
|
return text(e.is_set())
|
||||||
|
|
||||||
@app.route('/late')
|
@app.route("/late")
|
||||||
async def set(request):
|
async def set(request):
|
||||||
await asyncio.sleep(0.1)
|
await asyncio.sleep(0.1)
|
||||||
return text(e.is_set())
|
return text(e.is_set())
|
||||||
|
|
||||||
request, response = app.test_client.get('/early')
|
request, response = app.test_client.get("/early")
|
||||||
assert response.body == b'False'
|
assert response.body == b"False"
|
||||||
|
|
||||||
request, response = app.test_client.get('/late')
|
request, response = app.test_client.get("/late")
|
||||||
assert response.body == b'True'
|
assert response.body == b"True"
|
||||||
|
|
||||||
|
|
||||||
def test_create_task_with_app_arg(app):
|
def test_create_task_with_app_arg(app):
|
||||||
q = Queue()
|
q = Queue()
|
||||||
|
|
||||||
@app.route('/')
|
@app.route("/")
|
||||||
def not_set(request):
|
def not_set(request):
|
||||||
return "hello"
|
return "hello"
|
||||||
|
|
||||||
|
@ -41,5 +41,5 @@ def test_create_task_with_app_arg(app):
|
||||||
|
|
||||||
app.add_task(coro)
|
app.add_task(coro)
|
||||||
|
|
||||||
request, response = app.test_client.get('/')
|
request, response = app.test_client.get("/")
|
||||||
assert q.get() == 'test_create_task_with_app_arg'
|
assert q.get() == "test_create_task_with_app_arg"
|
||||||
|
|
|
@ -3,26 +3,19 @@ from sanic.response import text
|
||||||
|
|
||||||
|
|
||||||
class CustomHttpProtocol(HttpProtocol):
|
class CustomHttpProtocol(HttpProtocol):
|
||||||
|
|
||||||
def write_response(self, response):
|
def write_response(self, response):
|
||||||
if isinstance(response, str):
|
if isinstance(response, str):
|
||||||
response = text(response)
|
response = text(response)
|
||||||
self.transport.write(
|
self.transport.write(response.output(self.request.version))
|
||||||
response.output(self.request.version)
|
|
||||||
)
|
|
||||||
self.transport.close()
|
self.transport.close()
|
||||||
|
|
||||||
|
|
||||||
def test_use_custom_protocol(app):
|
def test_use_custom_protocol(app):
|
||||||
|
@app.route("/1")
|
||||||
@app.route('/1')
|
|
||||||
async def handler_1(request):
|
async def handler_1(request):
|
||||||
return 'OK'
|
return "OK"
|
||||||
|
|
||||||
server_kwargs = {
|
server_kwargs = {"protocol": CustomHttpProtocol}
|
||||||
'protocol': CustomHttpProtocol
|
request, response = app.test_client.get("/1", server_kwargs=server_kwargs)
|
||||||
}
|
|
||||||
request, response = app.test_client.get(
|
|
||||||
'/1', server_kwargs=server_kwargs)
|
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == 'OK'
|
assert response.text == "OK"
|
||||||
|
|
|
@ -3,39 +3,41 @@ from sanic.router import RouteExists
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("method,attr, expected", [
|
@pytest.mark.parametrize(
|
||||||
("get", "text", "OK1 test"),
|
"method,attr, expected",
|
||||||
("post", "text", "OK2 test"),
|
[
|
||||||
("put", "text", "OK2 test"),
|
("get", "text", "OK1 test"),
|
||||||
("delete", "status", 405),
|
("post", "text", "OK2 test"),
|
||||||
])
|
("put", "text", "OK2 test"),
|
||||||
|
("delete", "status", 405),
|
||||||
|
],
|
||||||
|
)
|
||||||
def test_overload_dynamic_routes(app, method, attr, expected):
|
def test_overload_dynamic_routes(app, method, attr, expected):
|
||||||
|
@app.route("/overload/<param>", methods=["GET"])
|
||||||
@app.route('/overload/<param>', methods=['GET'])
|
|
||||||
async def handler1(request, param):
|
async def handler1(request, param):
|
||||||
return text('OK1 ' + param)
|
return text("OK1 " + param)
|
||||||
|
|
||||||
@app.route('/overload/<param>', methods=['POST', 'PUT'])
|
@app.route("/overload/<param>", methods=["POST", "PUT"])
|
||||||
async def handler2(request, param):
|
async def handler2(request, param):
|
||||||
return text('OK2 ' + param)
|
return text("OK2 " + param)
|
||||||
|
|
||||||
request, response = getattr(app.test_client, method)('/overload/test')
|
request, response = getattr(app.test_client, method)("/overload/test")
|
||||||
assert getattr(response, attr) == expected
|
assert getattr(response, attr) == expected
|
||||||
|
|
||||||
|
|
||||||
def test_overload_dynamic_routes_exist(app):
|
def test_overload_dynamic_routes_exist(app):
|
||||||
|
@app.route("/overload/<param>", methods=["GET"])
|
||||||
@app.route('/overload/<param>', methods=['GET'])
|
|
||||||
async def handler1(request, param):
|
async def handler1(request, param):
|
||||||
return text('OK1 ' + param)
|
return text("OK1 " + param)
|
||||||
|
|
||||||
@app.route('/overload/<param>', methods=['POST', 'PUT'])
|
@app.route("/overload/<param>", methods=["POST", "PUT"])
|
||||||
async def handler2(request, param):
|
async def handler2(request, param):
|
||||||
return text('OK2 ' + param)
|
return text("OK2 " + param)
|
||||||
|
|
||||||
# if this doesn't raise an error, than at least the below should happen:
|
# if this doesn't raise an error, than at least the below should happen:
|
||||||
# assert response.text == 'Duplicated'
|
# assert response.text == 'Duplicated'
|
||||||
with pytest.raises(RouteExists):
|
with pytest.raises(RouteExists):
|
||||||
@app.route('/overload/<param>', methods=['PUT', 'DELETE'])
|
|
||||||
|
@app.route("/overload/<param>", methods=["PUT", "DELETE"])
|
||||||
async def handler3(request):
|
async def handler3(request):
|
||||||
return text('Duplicated')
|
return text("Duplicated")
|
||||||
|
|
|
@ -11,72 +11,74 @@ class SanicExceptionTestException(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope='module')
|
@pytest.fixture(scope="module")
|
||||||
def exception_app():
|
def exception_app():
|
||||||
app = Sanic('test_exceptions')
|
app = Sanic("test_exceptions")
|
||||||
|
|
||||||
@app.route('/')
|
@app.route("/")
|
||||||
def handler(request):
|
def handler(request):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
@app.route('/error')
|
@app.route("/error")
|
||||||
def handler_error(request):
|
def handler_error(request):
|
||||||
raise ServerError("OK")
|
raise ServerError("OK")
|
||||||
|
|
||||||
@app.route('/404')
|
@app.route("/404")
|
||||||
def handler_404(request):
|
def handler_404(request):
|
||||||
raise NotFound("OK")
|
raise NotFound("OK")
|
||||||
|
|
||||||
@app.route('/403')
|
@app.route("/403")
|
||||||
def handler_403(request):
|
def handler_403(request):
|
||||||
raise Forbidden("Forbidden")
|
raise Forbidden("Forbidden")
|
||||||
|
|
||||||
@app.route('/401')
|
@app.route("/401")
|
||||||
def handler_401(request):
|
def handler_401(request):
|
||||||
raise Unauthorized("Unauthorized")
|
raise Unauthorized("Unauthorized")
|
||||||
|
|
||||||
@app.route('/401/basic')
|
@app.route("/401/basic")
|
||||||
def handler_401_basic(request):
|
def handler_401_basic(request):
|
||||||
raise Unauthorized("Unauthorized", scheme="Basic", realm="Sanic")
|
raise Unauthorized("Unauthorized", scheme="Basic", realm="Sanic")
|
||||||
|
|
||||||
@app.route('/401/digest')
|
@app.route("/401/digest")
|
||||||
def handler_401_digest(request):
|
def handler_401_digest(request):
|
||||||
raise Unauthorized("Unauthorized",
|
raise Unauthorized(
|
||||||
scheme="Digest",
|
"Unauthorized",
|
||||||
realm="Sanic",
|
scheme="Digest",
|
||||||
qop="auth, auth-int",
|
realm="Sanic",
|
||||||
algorithm="MD5",
|
qop="auth, auth-int",
|
||||||
nonce="abcdef",
|
algorithm="MD5",
|
||||||
opaque="zyxwvu")
|
nonce="abcdef",
|
||||||
|
opaque="zyxwvu",
|
||||||
|
)
|
||||||
|
|
||||||
@app.route('/401/bearer')
|
@app.route("/401/bearer")
|
||||||
def handler_401_bearer(request):
|
def handler_401_bearer(request):
|
||||||
raise Unauthorized("Unauthorized", scheme="Bearer")
|
raise Unauthorized("Unauthorized", scheme="Bearer")
|
||||||
|
|
||||||
@app.route('/invalid')
|
@app.route("/invalid")
|
||||||
def handler_invalid(request):
|
def handler_invalid(request):
|
||||||
raise InvalidUsage("OK")
|
raise InvalidUsage("OK")
|
||||||
|
|
||||||
@app.route('/abort/401')
|
@app.route("/abort/401")
|
||||||
def handler_401_error(request):
|
def handler_401_error(request):
|
||||||
abort(401)
|
abort(401)
|
||||||
|
|
||||||
@app.route('/abort')
|
@app.route("/abort")
|
||||||
def handler_500_error(request):
|
def handler_500_error(request):
|
||||||
abort(500)
|
abort(500)
|
||||||
return text("OK")
|
return text("OK")
|
||||||
|
|
||||||
@app.route('/abort/message')
|
@app.route("/abort/message")
|
||||||
def handler_abort_message(request):
|
def handler_abort_message(request):
|
||||||
abort(500, message='Abort')
|
abort(500, message="Abort")
|
||||||
|
|
||||||
@app.route('/divide_by_zero')
|
@app.route("/divide_by_zero")
|
||||||
def handle_unhandled_exception(request):
|
def handle_unhandled_exception(request):
|
||||||
1 / 0
|
1 / 0
|
||||||
|
|
||||||
@app.route('/error_in_error_handler_handler')
|
@app.route("/error_in_error_handler_handler")
|
||||||
def custom_error_handler(request):
|
def custom_error_handler(request):
|
||||||
raise SanicExceptionTestException('Dummy message!')
|
raise SanicExceptionTestException("Dummy message!")
|
||||||
|
|
||||||
@app.exception(SanicExceptionTestException)
|
@app.exception(SanicExceptionTestException)
|
||||||
def error_in_error_handler_handler(request, exception):
|
def error_in_error_handler_handler(request, exception):
|
||||||
|
@ -86,126 +88,127 @@ def exception_app():
|
||||||
|
|
||||||
|
|
||||||
def test_catch_exception_list(app):
|
def test_catch_exception_list(app):
|
||||||
|
|
||||||
@app.exception([SanicExceptionTestException, NotFound])
|
@app.exception([SanicExceptionTestException, NotFound])
|
||||||
def exception_list(request, exception):
|
def exception_list(request, exception):
|
||||||
return text("ok")
|
return text("ok")
|
||||||
|
|
||||||
@app.route('/')
|
@app.route("/")
|
||||||
def exception(request):
|
def exception(request):
|
||||||
raise SanicExceptionTestException("You won't see me")
|
raise SanicExceptionTestException("You won't see me")
|
||||||
|
|
||||||
request, response = app.test_client.get('/random')
|
request, response = app.test_client.get("/random")
|
||||||
assert response.text == 'ok'
|
assert response.text == "ok"
|
||||||
|
|
||||||
request, response = app.test_client.get('/')
|
request, response = app.test_client.get("/")
|
||||||
assert response.text == 'ok'
|
assert response.text == "ok"
|
||||||
|
|
||||||
|
|
||||||
def test_no_exception(exception_app):
|
def test_no_exception(exception_app):
|
||||||
"""Test that a route works without an exception"""
|
"""Test that a route works without an exception"""
|
||||||
request, response = exception_app.test_client.get('/')
|
request, response = exception_app.test_client.get("/")
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == 'OK'
|
assert response.text == "OK"
|
||||||
|
|
||||||
|
|
||||||
def test_server_error_exception(exception_app):
|
def test_server_error_exception(exception_app):
|
||||||
"""Test the built-in ServerError exception works"""
|
"""Test the built-in ServerError exception works"""
|
||||||
request, response = exception_app.test_client.get('/error')
|
request, response = exception_app.test_client.get("/error")
|
||||||
assert response.status == 500
|
assert response.status == 500
|
||||||
|
|
||||||
|
|
||||||
def test_invalid_usage_exception(exception_app):
|
def test_invalid_usage_exception(exception_app):
|
||||||
"""Test the built-in InvalidUsage exception works"""
|
"""Test the built-in InvalidUsage exception works"""
|
||||||
request, response = exception_app.test_client.get('/invalid')
|
request, response = exception_app.test_client.get("/invalid")
|
||||||
assert response.status == 400
|
assert response.status == 400
|
||||||
|
|
||||||
|
|
||||||
def test_not_found_exception(exception_app):
|
def test_not_found_exception(exception_app):
|
||||||
"""Test the built-in NotFound exception works"""
|
"""Test the built-in NotFound exception works"""
|
||||||
request, response = exception_app.test_client.get('/404')
|
request, response = exception_app.test_client.get("/404")
|
||||||
assert response.status == 404
|
assert response.status == 404
|
||||||
|
|
||||||
|
|
||||||
def test_forbidden_exception(exception_app):
|
def test_forbidden_exception(exception_app):
|
||||||
"""Test the built-in Forbidden exception"""
|
"""Test the built-in Forbidden exception"""
|
||||||
request, response = exception_app.test_client.get('/403')
|
request, response = exception_app.test_client.get("/403")
|
||||||
assert response.status == 403
|
assert response.status == 403
|
||||||
|
|
||||||
|
|
||||||
def test_unauthorized_exception(exception_app):
|
def test_unauthorized_exception(exception_app):
|
||||||
"""Test the built-in Unauthorized exception"""
|
"""Test the built-in Unauthorized exception"""
|
||||||
request, response = exception_app.test_client.get('/401')
|
request, response = exception_app.test_client.get("/401")
|
||||||
assert response.status == 401
|
assert response.status == 401
|
||||||
|
|
||||||
request, response = exception_app.test_client.get('/401/basic')
|
request, response = exception_app.test_client.get("/401/basic")
|
||||||
assert response.status == 401
|
assert response.status == 401
|
||||||
assert response.headers.get('WWW-Authenticate') is not None
|
assert response.headers.get("WWW-Authenticate") is not None
|
||||||
assert response.headers.get('WWW-Authenticate') == 'Basic realm="Sanic"'
|
assert response.headers.get("WWW-Authenticate") == 'Basic realm="Sanic"'
|
||||||
|
|
||||||
request, response = exception_app.test_client.get('/401/digest')
|
request, response = exception_app.test_client.get("/401/digest")
|
||||||
assert response.status == 401
|
assert response.status == 401
|
||||||
|
|
||||||
auth_header = response.headers.get('WWW-Authenticate')
|
auth_header = response.headers.get("WWW-Authenticate")
|
||||||
assert auth_header is not None
|
assert auth_header is not None
|
||||||
assert auth_header.startswith('Digest')
|
assert auth_header.startswith("Digest")
|
||||||
assert 'qop="auth, auth-int"' in auth_header
|
assert 'qop="auth, auth-int"' in auth_header
|
||||||
assert 'algorithm="MD5"' in auth_header
|
assert 'algorithm="MD5"' in auth_header
|
||||||
assert 'nonce="abcdef"' in auth_header
|
assert 'nonce="abcdef"' in auth_header
|
||||||
assert 'opaque="zyxwvu"' in auth_header
|
assert 'opaque="zyxwvu"' in auth_header
|
||||||
|
|
||||||
request, response = exception_app.test_client.get('/401/bearer')
|
request, response = exception_app.test_client.get("/401/bearer")
|
||||||
assert response.status == 401
|
assert response.status == 401
|
||||||
assert response.headers.get('WWW-Authenticate') == "Bearer"
|
assert response.headers.get("WWW-Authenticate") == "Bearer"
|
||||||
|
|
||||||
|
|
||||||
def test_handled_unhandled_exception(exception_app):
|
def test_handled_unhandled_exception(exception_app):
|
||||||
"""Test that an exception not built into sanic is handled"""
|
"""Test that an exception not built into sanic is handled"""
|
||||||
request, response = exception_app.test_client.get('/divide_by_zero')
|
request, response = exception_app.test_client.get("/divide_by_zero")
|
||||||
assert response.status == 500
|
assert response.status == 500
|
||||||
soup = BeautifulSoup(response.body, 'html.parser')
|
soup = BeautifulSoup(response.body, "html.parser")
|
||||||
assert soup.h1.text == 'Internal Server Error'
|
assert soup.h1.text == "Internal Server Error"
|
||||||
|
|
||||||
message = " ".join(soup.p.text.split())
|
message = " ".join(soup.p.text.split())
|
||||||
assert message == (
|
assert message == (
|
||||||
"The server encountered an internal error and "
|
"The server encountered an internal error and "
|
||||||
"cannot complete your request.")
|
"cannot complete your request."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_exception_in_exception_handler(exception_app):
|
def test_exception_in_exception_handler(exception_app):
|
||||||
"""Test that an exception thrown in an error handler is handled"""
|
"""Test that an exception thrown in an error handler is handled"""
|
||||||
request, response = exception_app.test_client.get(
|
request, response = exception_app.test_client.get(
|
||||||
'/error_in_error_handler_handler')
|
"/error_in_error_handler_handler"
|
||||||
|
)
|
||||||
assert response.status == 500
|
assert response.status == 500
|
||||||
assert response.body == b'An error occurred while handling an error'
|
assert response.body == b"An error occurred while handling an error"
|
||||||
|
|
||||||
|
|
||||||
def test_exception_in_exception_handler_debug_off(exception_app):
|
def test_exception_in_exception_handler_debug_off(exception_app):
|
||||||
"""Test that an exception thrown in an error handler is handled"""
|
"""Test that an exception thrown in an error handler is handled"""
|
||||||
request, response = exception_app.test_client.get(
|
request, response = exception_app.test_client.get(
|
||||||
'/error_in_error_handler_handler',
|
"/error_in_error_handler_handler", debug=False
|
||||||
debug=False)
|
)
|
||||||
assert response.status == 500
|
assert response.status == 500
|
||||||
assert response.body == b'An error occurred while handling an error'
|
assert response.body == b"An error occurred while handling an error"
|
||||||
|
|
||||||
|
|
||||||
def test_exception_in_exception_handler_debug_on(exception_app):
|
def test_exception_in_exception_handler_debug_on(exception_app):
|
||||||
"""Test that an exception thrown in an error handler is handled"""
|
"""Test that an exception thrown in an error handler is handled"""
|
||||||
request, response = exception_app.test_client.get(
|
request, response = exception_app.test_client.get(
|
||||||
'/error_in_error_handler_handler',
|
"/error_in_error_handler_handler", debug=True
|
||||||
debug=True)
|
)
|
||||||
assert response.status == 500
|
assert response.status == 500
|
||||||
assert response.body.startswith(b'Exception raised in exception ')
|
assert response.body.startswith(b"Exception raised in exception ")
|
||||||
|
|
||||||
|
|
||||||
def test_abort(exception_app):
|
def test_abort(exception_app):
|
||||||
"""Test the abort function"""
|
"""Test the abort function"""
|
||||||
request, response = exception_app.test_client.get('/abort/401')
|
request, response = exception_app.test_client.get("/abort/401")
|
||||||
assert response.status == 401
|
assert response.status == 401
|
||||||
|
|
||||||
request, response = exception_app.test_client.get('/abort')
|
request, response = exception_app.test_client.get("/abort")
|
||||||
assert response.status == 500
|
assert response.status == 500
|
||||||
|
|
||||||
request, response = exception_app.test_client.get('/abort/message')
|
request, response = exception_app.test_client.get("/abort/message")
|
||||||
assert response.status == 500
|
assert response.status == 500
|
||||||
assert response.text == 'Error: Abort'
|
assert response.text == "Error: Abort"
|
||||||
|
|
|
@ -4,38 +4,39 @@ from sanic.exceptions import InvalidUsage, ServerError, NotFound
|
||||||
from sanic.handlers import ErrorHandler
|
from sanic.handlers import ErrorHandler
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
|
|
||||||
exception_handler_app = Sanic('test_exception_handler')
|
exception_handler_app = Sanic("test_exception_handler")
|
||||||
|
|
||||||
|
|
||||||
@exception_handler_app.route('/1')
|
@exception_handler_app.route("/1")
|
||||||
def handler_1(request):
|
def handler_1(request):
|
||||||
raise InvalidUsage("OK")
|
raise InvalidUsage("OK")
|
||||||
|
|
||||||
|
|
||||||
@exception_handler_app.route('/2')
|
@exception_handler_app.route("/2")
|
||||||
def handler_2(request):
|
def handler_2(request):
|
||||||
raise ServerError("OK")
|
raise ServerError("OK")
|
||||||
|
|
||||||
|
|
||||||
@exception_handler_app.route('/3')
|
@exception_handler_app.route("/3")
|
||||||
def handler_3(request):
|
def handler_3(request):
|
||||||
raise NotFound("OK")
|
raise NotFound("OK")
|
||||||
|
|
||||||
|
|
||||||
@exception_handler_app.route('/4')
|
@exception_handler_app.route("/4")
|
||||||
def handler_4(request):
|
def handler_4(request):
|
||||||
foo = bar # noqa -- F821 undefined name 'bar' is done to throw exception
|
foo = bar # noqa -- F821 undefined name 'bar' is done to throw exception
|
||||||
return text(foo)
|
return text(foo)
|
||||||
|
|
||||||
|
|
||||||
@exception_handler_app.route('/5')
|
@exception_handler_app.route("/5")
|
||||||
def handler_5(request):
|
def handler_5(request):
|
||||||
class CustomServerError(ServerError):
|
class CustomServerError(ServerError):
|
||||||
pass
|
pass
|
||||||
raise CustomServerError('Custom server error')
|
|
||||||
|
raise CustomServerError("Custom server error")
|
||||||
|
|
||||||
|
|
||||||
@exception_handler_app.route('/6/<arg:int>')
|
@exception_handler_app.route("/6/<arg:int>")
|
||||||
def handler_6(request, arg):
|
def handler_6(request, arg):
|
||||||
try:
|
try:
|
||||||
foo = 1 / arg
|
foo = 1 / arg
|
||||||
|
@ -50,67 +51,67 @@ def handler_exception(request, exception):
|
||||||
|
|
||||||
|
|
||||||
def test_invalid_usage_exception_handler():
|
def test_invalid_usage_exception_handler():
|
||||||
request, response = exception_handler_app.test_client.get('/1')
|
request, response = exception_handler_app.test_client.get("/1")
|
||||||
assert response.status == 400
|
assert response.status == 400
|
||||||
|
|
||||||
|
|
||||||
def test_server_error_exception_handler():
|
def test_server_error_exception_handler():
|
||||||
request, response = exception_handler_app.test_client.get('/2')
|
request, response = exception_handler_app.test_client.get("/2")
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == 'OK'
|
assert response.text == "OK"
|
||||||
|
|
||||||
|
|
||||||
def test_not_found_exception_handler():
|
def test_not_found_exception_handler():
|
||||||
request, response = exception_handler_app.test_client.get('/3')
|
request, response = exception_handler_app.test_client.get("/3")
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
|
|
||||||
|
|
||||||
def test_text_exception__handler():
|
def test_text_exception__handler():
|
||||||
request, response = exception_handler_app.test_client.get('/random')
|
request, response = exception_handler_app.test_client.get("/random")
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == 'OK'
|
assert response.text == "OK"
|
||||||
|
|
||||||
|
|
||||||
def test_html_traceback_output_in_debug_mode():
|
def test_html_traceback_output_in_debug_mode():
|
||||||
request, response = exception_handler_app.test_client.get(
|
request, response = exception_handler_app.test_client.get("/4", debug=True)
|
||||||
'/4', debug=True)
|
|
||||||
assert response.status == 500
|
assert response.status == 500
|
||||||
soup = BeautifulSoup(response.body, 'html.parser')
|
soup = BeautifulSoup(response.body, "html.parser")
|
||||||
html = str(soup)
|
html = str(soup)
|
||||||
|
|
||||||
assert 'response = handler(request, *args, **kwargs)' in html
|
assert "response = handler(request, *args, **kwargs)" in html
|
||||||
assert 'handler_4' in html
|
assert "handler_4" in html
|
||||||
assert 'foo = bar' in html
|
assert "foo = bar" in html
|
||||||
|
|
||||||
summary_text = " ".join(soup.select('.summary')[0].text.split())
|
summary_text = " ".join(soup.select(".summary")[0].text.split())
|
||||||
assert (
|
assert (
|
||||||
"NameError: name 'bar' "
|
"NameError: name 'bar' " "is not defined while handling path /4"
|
||||||
"is not defined while handling path /4") == summary_text
|
) == summary_text
|
||||||
|
|
||||||
|
|
||||||
def test_inherited_exception_handler():
|
def test_inherited_exception_handler():
|
||||||
request, response = exception_handler_app.test_client.get('/5')
|
request, response = exception_handler_app.test_client.get("/5")
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
|
|
||||||
|
|
||||||
def test_chained_exception_handler():
|
def test_chained_exception_handler():
|
||||||
request, response = exception_handler_app.test_client.get(
|
request, response = exception_handler_app.test_client.get(
|
||||||
'/6/0', debug=True)
|
"/6/0", debug=True
|
||||||
|
)
|
||||||
assert response.status == 500
|
assert response.status == 500
|
||||||
|
|
||||||
soup = BeautifulSoup(response.body, 'html.parser')
|
soup = BeautifulSoup(response.body, "html.parser")
|
||||||
html = str(soup)
|
html = str(soup)
|
||||||
|
|
||||||
assert 'response = handler(request, *args, **kwargs)' in html
|
assert "response = handler(request, *args, **kwargs)" in html
|
||||||
assert 'handler_6' in html
|
assert "handler_6" in html
|
||||||
assert 'foo = 1 / arg' in html
|
assert "foo = 1 / arg" in html
|
||||||
assert 'ValueError' in html
|
assert "ValueError" in html
|
||||||
assert 'The above exception was the direct cause' in html
|
assert "The above exception was the direct cause" in html
|
||||||
|
|
||||||
summary_text = " ".join(soup.select('.summary')[0].text.split())
|
summary_text = " ".join(soup.select(".summary")[0].text.split())
|
||||||
assert (
|
assert (
|
||||||
"ZeroDivisionError: division by zero "
|
"ZeroDivisionError: division by zero " "while handling path /6/0"
|
||||||
"while handling path /6/0") == summary_text
|
) == summary_text
|
||||||
|
|
||||||
|
|
||||||
def test_exception_handler_lookup():
|
def test_exception_handler_lookup():
|
||||||
|
@ -132,6 +133,7 @@ def test_exception_handler_lookup():
|
||||||
try:
|
try:
|
||||||
ModuleNotFoundError
|
ModuleNotFoundError
|
||||||
except Exception:
|
except Exception:
|
||||||
|
|
||||||
class ModuleNotFoundError(ImportError):
|
class ModuleNotFoundError(ImportError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -143,12 +145,12 @@ def test_exception_handler_lookup():
|
||||||
assert handler.lookup(ImportError()) == import_error_handler
|
assert handler.lookup(ImportError()) == import_error_handler
|
||||||
assert handler.lookup(ModuleNotFoundError()) == import_error_handler
|
assert handler.lookup(ModuleNotFoundError()) == import_error_handler
|
||||||
assert handler.lookup(CustomError()) == custom_error_handler
|
assert handler.lookup(CustomError()) == custom_error_handler
|
||||||
assert handler.lookup(ServerError('Error')) == server_error_handler
|
assert handler.lookup(ServerError("Error")) == server_error_handler
|
||||||
assert handler.lookup(CustomServerError('Error')) == server_error_handler
|
assert handler.lookup(CustomServerError("Error")) == server_error_handler
|
||||||
|
|
||||||
# once again to ensure there is no caching bug
|
# once again to ensure there is no caching bug
|
||||||
assert handler.lookup(ImportError()) == import_error_handler
|
assert handler.lookup(ImportError()) == import_error_handler
|
||||||
assert handler.lookup(ModuleNotFoundError()) == import_error_handler
|
assert handler.lookup(ModuleNotFoundError()) == import_error_handler
|
||||||
assert handler.lookup(CustomError()) == custom_error_handler
|
assert handler.lookup(CustomError()) == custom_error_handler
|
||||||
assert handler.lookup(ServerError('Error')) == server_error_handler
|
assert handler.lookup(ServerError("Error")) == server_error_handler
|
||||||
assert handler.lookup(CustomServerError('Error')) == server_error_handler
|
assert handler.lookup(CustomServerError("Error")) == server_error_handler
|
||||||
|
|
|
@ -42,35 +42,19 @@ def test_is_hop_by_hop_header():
|
||||||
|
|
||||||
def test_remove_entity_headers():
|
def test_remove_entity_headers():
|
||||||
tests = (
|
tests = (
|
||||||
(
|
({}, {}),
|
||||||
{},
|
({"Allow": "GET, POST, HEAD"}, {}),
|
||||||
{}
|
|
||||||
),
|
|
||||||
(
|
|
||||||
{
|
|
||||||
"Allow": "GET, POST, HEAD",
|
|
||||||
},
|
|
||||||
{}
|
|
||||||
),
|
|
||||||
(
|
(
|
||||||
{
|
{
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
"Expires": "Wed, 21 Oct 2015 07:28:00 GMT",
|
"Expires": "Wed, 21 Oct 2015 07:28:00 GMT",
|
||||||
"Foo": "Bar"
|
"Foo": "Bar",
|
||||||
},
|
|
||||||
{
|
|
||||||
"Expires": "Wed, 21 Oct 2015 07:28:00 GMT",
|
|
||||||
"Foo": "Bar"
|
|
||||||
},
|
},
|
||||||
|
{"Expires": "Wed, 21 Oct 2015 07:28:00 GMT", "Foo": "Bar"},
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
{
|
{"Allow": "GET, POST, HEAD", "Content-Location": "/test"},
|
||||||
"Allow": "GET, POST, HEAD",
|
{"Content-Location": "/test"},
|
||||||
"Content-Location": "/test"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Content-Location": "/test"
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -16,12 +16,14 @@ class ReuseableTCPConnector(TCPConnector):
|
||||||
self.old_proto = None
|
self.old_proto = None
|
||||||
|
|
||||||
async def connect(self, req, *args, **kwargs):
|
async def connect(self, req, *args, **kwargs):
|
||||||
new_conn = await super(ReuseableTCPConnector, self)\
|
new_conn = await super(ReuseableTCPConnector, self).connect(
|
||||||
.connect(req, *args, **kwargs)
|
req, *args, **kwargs
|
||||||
|
)
|
||||||
if self.old_proto is not None:
|
if self.old_proto is not None:
|
||||||
if self.old_proto != new_conn._protocol:
|
if self.old_proto != new_conn._protocol:
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
"We got a new connection, wanted the same one!")
|
"We got a new connection, wanted the same one!"
|
||||||
|
)
|
||||||
print(new_conn.__dict__)
|
print(new_conn.__dict__)
|
||||||
self.old_proto = new_conn._protocol
|
self.old_proto = new_conn._protocol
|
||||||
return new_conn
|
return new_conn
|
||||||
|
@ -40,31 +42,39 @@ class ReuseableSanicTestClient(SanicTestClient):
|
||||||
# Copied from SanicTestClient, but with some changes to reuse the
|
# Copied from SanicTestClient, but with some changes to reuse the
|
||||||
# same loop for the same app.
|
# same loop for the same app.
|
||||||
def _sanic_endpoint_test(
|
def _sanic_endpoint_test(
|
||||||
self, method='get', uri='/', gather_request=True,
|
self,
|
||||||
debug=False, server_kwargs={},
|
method="get",
|
||||||
*request_args, **request_kwargs):
|
uri="/",
|
||||||
|
gather_request=True,
|
||||||
|
debug=False,
|
||||||
|
server_kwargs={},
|
||||||
|
*request_args,
|
||||||
|
**request_kwargs
|
||||||
|
):
|
||||||
loop = self._loop
|
loop = self._loop
|
||||||
results = [None, None]
|
results = [None, None]
|
||||||
exceptions = []
|
exceptions = []
|
||||||
do_kill_server = request_kwargs.pop('end_server', False)
|
do_kill_server = request_kwargs.pop("end_server", False)
|
||||||
if gather_request:
|
if gather_request:
|
||||||
|
|
||||||
def _collect_request(request):
|
def _collect_request(request):
|
||||||
if results[0] is None:
|
if results[0] is None:
|
||||||
results[0] = request
|
results[0] = request
|
||||||
|
|
||||||
self.app.request_middleware.appendleft(_collect_request)
|
self.app.request_middleware.appendleft(_collect_request)
|
||||||
|
|
||||||
@self.app.listener('after_server_start')
|
@self.app.listener("after_server_start")
|
||||||
async def _collect_response(loop):
|
async def _collect_response(loop):
|
||||||
try:
|
try:
|
||||||
if do_kill_server:
|
if do_kill_server:
|
||||||
request_kwargs['end_session'] = True
|
request_kwargs["end_session"] = True
|
||||||
response = await self._local_request(
|
response = await self._local_request(
|
||||||
method, uri, *request_args,
|
method, uri, *request_args, **request_kwargs
|
||||||
**request_kwargs)
|
)
|
||||||
results[-1] = response
|
results[-1] = response
|
||||||
except Exception as e2:
|
except Exception as e2:
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
traceback.print_tb(e2.__traceback__)
|
traceback.print_tb(e2.__traceback__)
|
||||||
exceptions.append(e2)
|
exceptions.append(e2)
|
||||||
# Don't stop here! self.app.stop()
|
# Don't stop here! self.app.stop()
|
||||||
|
@ -72,23 +82,25 @@ class ReuseableSanicTestClient(SanicTestClient):
|
||||||
if self._server is not None:
|
if self._server is not None:
|
||||||
_server = self._server
|
_server = self._server
|
||||||
else:
|
else:
|
||||||
_server_co = self.app.create_server(host=HOST, debug=debug,
|
_server_co = self.app.create_server(
|
||||||
port=PORT, **server_kwargs)
|
host=HOST, debug=debug, port=PORT, **server_kwargs
|
||||||
|
)
|
||||||
|
|
||||||
server.trigger_events(
|
server.trigger_events(
|
||||||
self.app.listeners['before_server_start'], loop)
|
self.app.listeners["before_server_start"], loop
|
||||||
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
loop._stopping = False
|
loop._stopping = False
|
||||||
http_server = loop.run_until_complete(_server_co)
|
http_server = loop.run_until_complete(_server_co)
|
||||||
except Exception as e1:
|
except Exception as e1:
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
traceback.print_tb(e1.__traceback__)
|
traceback.print_tb(e1.__traceback__)
|
||||||
raise e1
|
raise e1
|
||||||
self._server = _server = http_server
|
self._server = _server = http_server
|
||||||
server.trigger_events(
|
server.trigger_events(self.app.listeners["after_server_start"], loop)
|
||||||
self.app.listeners['after_server_start'], loop)
|
self.app.listeners["after_server_start"].pop()
|
||||||
self.app.listeners['after_server_start'].pop()
|
|
||||||
|
|
||||||
if do_kill_server:
|
if do_kill_server:
|
||||||
try:
|
try:
|
||||||
|
@ -98,11 +110,11 @@ class ReuseableSanicTestClient(SanicTestClient):
|
||||||
self.app.stop()
|
self.app.stop()
|
||||||
except Exception as e3:
|
except Exception as e3:
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
traceback.print_tb(e3.__traceback__)
|
traceback.print_tb(e3.__traceback__)
|
||||||
exceptions.append(e3)
|
exceptions.append(e3)
|
||||||
if exceptions:
|
if exceptions:
|
||||||
raise ValueError(
|
raise ValueError("Exception during request: {}".format(exceptions))
|
||||||
"Exception during request: {}".format(exceptions))
|
|
||||||
|
|
||||||
if gather_request:
|
if gather_request:
|
||||||
self.app.request_middleware.pop()
|
self.app.request_middleware.pop()
|
||||||
|
@ -112,28 +124,32 @@ class ReuseableSanicTestClient(SanicTestClient):
|
||||||
except Exception:
|
except Exception:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"Request and response object expected, got ({})".format(
|
"Request and response object expected, got ({})".format(
|
||||||
results))
|
results
|
||||||
|
)
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
return results[-1]
|
return results[-1]
|
||||||
except Exception:
|
except Exception:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"Request object expected, got ({})".format(results))
|
"Request object expected, got ({})".format(results)
|
||||||
|
)
|
||||||
|
|
||||||
# Copied from SanicTestClient, but with some changes to reuse the
|
# Copied from SanicTestClient, but with some changes to reuse the
|
||||||
# same TCPConnection and the sane ClientSession more than once.
|
# same TCPConnection and the sane ClientSession more than once.
|
||||||
# Note, you cannot use the same session if you are in a _different_
|
# Note, you cannot use the same session if you are in a _different_
|
||||||
# loop, so the changes above are required too.
|
# loop, so the changes above are required too.
|
||||||
async def _local_request(self, method, uri, cookies=None, *args,
|
async def _local_request(self, method, uri, cookies=None, *args, **kwargs):
|
||||||
**kwargs):
|
request_keepalive = kwargs.pop(
|
||||||
request_keepalive = kwargs.pop('request_keepalive',
|
"request_keepalive", Config.KEEP_ALIVE_TIMEOUT
|
||||||
Config.KEEP_ALIVE_TIMEOUT)
|
)
|
||||||
if uri.startswith(('http:', 'https:', 'ftp:', 'ftps://' '//')):
|
if uri.startswith(("http:", "https:", "ftp:", "ftps://" "//")):
|
||||||
url = uri
|
url = uri
|
||||||
else:
|
else:
|
||||||
url = 'http://{host}:{port}{uri}'.format(
|
url = "http://{host}:{port}{uri}".format(
|
||||||
host=HOST, port=self.port, uri=uri)
|
host=HOST, port=self.port, uri=uri
|
||||||
do_kill_session = kwargs.pop('end_session', False)
|
)
|
||||||
|
do_kill_session = kwargs.pop("end_session", False)
|
||||||
if self._session:
|
if self._session:
|
||||||
session = self._session
|
session = self._session
|
||||||
else:
|
else:
|
||||||
|
@ -143,16 +159,17 @@ class ReuseableSanicTestClient(SanicTestClient):
|
||||||
conn = ReuseableTCPConnector(
|
conn = ReuseableTCPConnector(
|
||||||
verify_ssl=False,
|
verify_ssl=False,
|
||||||
loop=self._loop,
|
loop=self._loop,
|
||||||
keepalive_timeout=request_keepalive
|
keepalive_timeout=request_keepalive,
|
||||||
)
|
)
|
||||||
self._tcp_connector = conn
|
self._tcp_connector = conn
|
||||||
session = aiohttp.ClientSession(cookies=cookies,
|
session = aiohttp.ClientSession(
|
||||||
connector=conn,
|
cookies=cookies, connector=conn, loop=self._loop
|
||||||
loop=self._loop)
|
)
|
||||||
self._session = session
|
self._session = session
|
||||||
|
|
||||||
async with getattr(session, method.lower())(
|
async with getattr(session, method.lower())(
|
||||||
url, *args, **kwargs) as response:
|
url, *args, **kwargs
|
||||||
|
) as response:
|
||||||
try:
|
try:
|
||||||
response.text = await response.text()
|
response.text = await response.text()
|
||||||
except UnicodeDecodeError:
|
except UnicodeDecodeError:
|
||||||
|
@ -160,9 +177,11 @@ class ReuseableSanicTestClient(SanicTestClient):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
response.json = await response.json()
|
response.json = await response.json()
|
||||||
except (JSONDecodeError,
|
except (
|
||||||
UnicodeDecodeError,
|
JSONDecodeError,
|
||||||
aiohttp.ClientResponseError):
|
UnicodeDecodeError,
|
||||||
|
aiohttp.ClientResponseError,
|
||||||
|
):
|
||||||
response.json = None
|
response.json = None
|
||||||
|
|
||||||
response.body = await response.read()
|
response.body = await response.read()
|
||||||
|
@ -174,24 +193,24 @@ class ReuseableSanicTestClient(SanicTestClient):
|
||||||
|
|
||||||
Config.KEEP_ALIVE_TIMEOUT = 2
|
Config.KEEP_ALIVE_TIMEOUT = 2
|
||||||
Config.KEEP_ALIVE = True
|
Config.KEEP_ALIVE = True
|
||||||
keep_alive_timeout_app_reuse = Sanic('test_ka_timeout_reuse')
|
keep_alive_timeout_app_reuse = Sanic("test_ka_timeout_reuse")
|
||||||
keep_alive_app_client_timeout = Sanic('test_ka_client_timeout')
|
keep_alive_app_client_timeout = Sanic("test_ka_client_timeout")
|
||||||
keep_alive_app_server_timeout = Sanic('test_ka_server_timeout')
|
keep_alive_app_server_timeout = Sanic("test_ka_server_timeout")
|
||||||
|
|
||||||
|
|
||||||
@keep_alive_timeout_app_reuse.route('/1')
|
@keep_alive_timeout_app_reuse.route("/1")
|
||||||
async def handler1(request):
|
async def handler1(request):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
|
|
||||||
@keep_alive_app_client_timeout.route('/1')
|
@keep_alive_app_client_timeout.route("/1")
|
||||||
async def handler2(request):
|
async def handler2(request):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
|
|
||||||
@keep_alive_app_server_timeout.route('/1')
|
@keep_alive_app_server_timeout.route("/1")
|
||||||
async def handler3(request):
|
async def handler3(request):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
|
|
||||||
def test_keep_alive_timeout_reuse():
|
def test_keep_alive_timeout_reuse():
|
||||||
|
@ -201,16 +220,14 @@ def test_keep_alive_timeout_reuse():
|
||||||
loop = asyncio.new_event_loop()
|
loop = asyncio.new_event_loop()
|
||||||
asyncio.set_event_loop(loop)
|
asyncio.set_event_loop(loop)
|
||||||
client = ReuseableSanicTestClient(keep_alive_timeout_app_reuse, loop)
|
client = ReuseableSanicTestClient(keep_alive_timeout_app_reuse, loop)
|
||||||
headers = {
|
headers = {"Connection": "keep-alive"}
|
||||||
'Connection': 'keep-alive'
|
request, response = client.get("/1", headers=headers)
|
||||||
}
|
|
||||||
request, response = client.get('/1', headers=headers)
|
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == 'OK'
|
assert response.text == "OK"
|
||||||
loop.run_until_complete(aio_sleep(1))
|
loop.run_until_complete(aio_sleep(1))
|
||||||
request, response = client.get('/1', end_server=True)
|
request, response = client.get("/1", end_server=True)
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == 'OK'
|
assert response.text == "OK"
|
||||||
|
|
||||||
|
|
||||||
def test_keep_alive_client_timeout():
|
def test_keep_alive_client_timeout():
|
||||||
|
@ -218,20 +235,17 @@ def test_keep_alive_client_timeout():
|
||||||
keep-alive timeout, client will try to create a new connection here."""
|
keep-alive timeout, client will try to create a new connection here."""
|
||||||
loop = asyncio.new_event_loop()
|
loop = asyncio.new_event_loop()
|
||||||
asyncio.set_event_loop(loop)
|
asyncio.set_event_loop(loop)
|
||||||
client = ReuseableSanicTestClient(keep_alive_app_client_timeout,
|
client = ReuseableSanicTestClient(keep_alive_app_client_timeout, loop)
|
||||||
loop)
|
headers = {"Connection": "keep-alive"}
|
||||||
headers = {
|
request, response = client.get("/1", headers=headers, request_keepalive=1)
|
||||||
'Connection': 'keep-alive'
|
|
||||||
}
|
|
||||||
request, response = client.get('/1', headers=headers,
|
|
||||||
request_keepalive=1)
|
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == 'OK'
|
assert response.text == "OK"
|
||||||
loop.run_until_complete(aio_sleep(2))
|
loop.run_until_complete(aio_sleep(2))
|
||||||
exception = None
|
exception = None
|
||||||
try:
|
try:
|
||||||
request, response = client.get('/1', end_server=True,
|
request, response = client.get(
|
||||||
request_keepalive=1)
|
"/1", end_server=True, request_keepalive=1
|
||||||
|
)
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
exception = e
|
exception = e
|
||||||
assert exception is not None
|
assert exception is not None
|
||||||
|
@ -246,23 +260,22 @@ def test_keep_alive_server_timeout():
|
||||||
broken server connection."""
|
broken server connection."""
|
||||||
loop = asyncio.new_event_loop()
|
loop = asyncio.new_event_loop()
|
||||||
asyncio.set_event_loop(loop)
|
asyncio.set_event_loop(loop)
|
||||||
client = ReuseableSanicTestClient(keep_alive_app_server_timeout,
|
client = ReuseableSanicTestClient(keep_alive_app_server_timeout, loop)
|
||||||
loop)
|
headers = {"Connection": "keep-alive"}
|
||||||
headers = {
|
request, response = client.get("/1", headers=headers, request_keepalive=60)
|
||||||
'Connection': 'keep-alive'
|
|
||||||
}
|
|
||||||
request, response = client.get('/1', headers=headers,
|
|
||||||
request_keepalive=60)
|
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == 'OK'
|
assert response.text == "OK"
|
||||||
loop.run_until_complete(aio_sleep(3))
|
loop.run_until_complete(aio_sleep(3))
|
||||||
exception = None
|
exception = None
|
||||||
try:
|
try:
|
||||||
request, response = client.get('/1', request_keepalive=60,
|
request, response = client.get(
|
||||||
end_server=True)
|
"/1", request_keepalive=60, end_server=True
|
||||||
|
)
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
exception = e
|
exception = e
|
||||||
assert exception is not None
|
assert exception is not None
|
||||||
assert isinstance(exception, ValueError)
|
assert isinstance(exception, ValueError)
|
||||||
assert "Connection reset" in exception.args[0] or \
|
assert (
|
||||||
"got a new connection" in exception.args[0]
|
"Connection reset" in exception.args[0]
|
||||||
|
or "got a new connection" in exception.args[0]
|
||||||
|
)
|
||||||
|
|
|
@ -14,9 +14,9 @@ from sanic import Sanic
|
||||||
from sanic.log import logger
|
from sanic.log import logger
|
||||||
|
|
||||||
|
|
||||||
logging_format = '''module: %(module)s; \
|
logging_format = """module: %(module)s; \
|
||||||
function: %(funcName)s(); \
|
function: %(funcName)s(); \
|
||||||
message: %(message)s'''
|
message: %(message)s"""
|
||||||
|
|
||||||
|
|
||||||
def reset_logging():
|
def reset_logging():
|
||||||
|
@ -29,19 +29,17 @@ def test_log(app):
|
||||||
for handler in logging.root.handlers[:]:
|
for handler in logging.root.handlers[:]:
|
||||||
logging.root.removeHandler(handler)
|
logging.root.removeHandler(handler)
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
format=logging_format,
|
format=logging_format, level=logging.DEBUG, stream=log_stream
|
||||||
level=logging.DEBUG,
|
|
||||||
stream=log_stream
|
|
||||||
)
|
)
|
||||||
log = logging.getLogger()
|
log = logging.getLogger()
|
||||||
rand_string = str(uuid.uuid4())
|
rand_string = str(uuid.uuid4())
|
||||||
|
|
||||||
@app.route('/')
|
@app.route("/")
|
||||||
def handler(request):
|
def handler(request):
|
||||||
log.info(rand_string)
|
log.info(rand_string)
|
||||||
return text('hello')
|
return text("hello")
|
||||||
|
|
||||||
request, response = app.test_client.get('/')
|
request, response = app.test_client.get("/")
|
||||||
log_text = log_stream.getvalue()
|
log_text = log_stream.getvalue()
|
||||||
assert rand_string in log_text
|
assert rand_string in log_text
|
||||||
|
|
||||||
|
@ -50,59 +48,80 @@ def test_logging_defaults():
|
||||||
# reset_logging()
|
# reset_logging()
|
||||||
app = Sanic("test_logging")
|
app = Sanic("test_logging")
|
||||||
|
|
||||||
for fmt in [h.formatter for h in logging.getLogger('sanic.root').handlers]:
|
for fmt in [h.formatter for h in logging.getLogger("sanic.root").handlers]:
|
||||||
assert fmt._fmt == LOGGING_CONFIG_DEFAULTS['formatters']['generic']['format']
|
assert (
|
||||||
|
fmt._fmt
|
||||||
|
== LOGGING_CONFIG_DEFAULTS["formatters"]["generic"]["format"]
|
||||||
|
)
|
||||||
|
|
||||||
for fmt in [h.formatter for h in logging.getLogger('sanic.error').handlers]:
|
for fmt in [
|
||||||
assert fmt._fmt == LOGGING_CONFIG_DEFAULTS['formatters']['generic']['format']
|
h.formatter for h in logging.getLogger("sanic.error").handlers
|
||||||
|
]:
|
||||||
|
assert (
|
||||||
|
fmt._fmt
|
||||||
|
== LOGGING_CONFIG_DEFAULTS["formatters"]["generic"]["format"]
|
||||||
|
)
|
||||||
|
|
||||||
for fmt in [h.formatter for h in logging.getLogger('sanic.access').handlers]:
|
for fmt in [
|
||||||
assert fmt._fmt == LOGGING_CONFIG_DEFAULTS['formatters']['access']['format']
|
h.formatter for h in logging.getLogger("sanic.access").handlers
|
||||||
|
]:
|
||||||
|
assert (
|
||||||
|
fmt._fmt
|
||||||
|
== LOGGING_CONFIG_DEFAULTS["formatters"]["access"]["format"]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_logging_pass_customer_logconfig():
|
def test_logging_pass_customer_logconfig():
|
||||||
# reset_logging()
|
# reset_logging()
|
||||||
|
|
||||||
modified_config = LOGGING_CONFIG_DEFAULTS
|
modified_config = LOGGING_CONFIG_DEFAULTS
|
||||||
modified_config['formatters']['generic']['format'] = '%(asctime)s - (%(name)s)[%(levelname)s]: %(message)s'
|
modified_config["formatters"]["generic"][
|
||||||
modified_config['formatters']['access']['format'] = '%(asctime)s - (%(name)s)[%(levelname)s]: %(message)s'
|
"format"
|
||||||
|
] = "%(asctime)s - (%(name)s)[%(levelname)s]: %(message)s"
|
||||||
|
modified_config["formatters"]["access"][
|
||||||
|
"format"
|
||||||
|
] = "%(asctime)s - (%(name)s)[%(levelname)s]: %(message)s"
|
||||||
|
|
||||||
app = Sanic("test_logging", log_config=modified_config)
|
app = Sanic("test_logging", log_config=modified_config)
|
||||||
|
|
||||||
for fmt in [h.formatter for h in logging.getLogger('sanic.root').handlers]:
|
for fmt in [h.formatter for h in logging.getLogger("sanic.root").handlers]:
|
||||||
assert fmt._fmt == modified_config['formatters']['generic']['format']
|
assert fmt._fmt == modified_config["formatters"]["generic"]["format"]
|
||||||
|
|
||||||
for fmt in [h.formatter for h in logging.getLogger('sanic.error').handlers]:
|
for fmt in [
|
||||||
assert fmt._fmt == modified_config['formatters']['generic']['format']
|
h.formatter for h in logging.getLogger("sanic.error").handlers
|
||||||
|
]:
|
||||||
|
assert fmt._fmt == modified_config["formatters"]["generic"]["format"]
|
||||||
|
|
||||||
for fmt in [h.formatter for h in logging.getLogger('sanic.access').handlers]:
|
for fmt in [
|
||||||
assert fmt._fmt == modified_config['formatters']['access']['format']
|
h.formatter for h in logging.getLogger("sanic.access").handlers
|
||||||
|
]:
|
||||||
|
assert fmt._fmt == modified_config["formatters"]["access"]["format"]
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('debug', (True, False, ))
|
@pytest.mark.parametrize("debug", (True, False))
|
||||||
def test_log_connection_lost(app, debug, monkeypatch):
|
def test_log_connection_lost(app, debug, monkeypatch):
|
||||||
""" Should not log Connection lost exception on non debug """
|
""" Should not log Connection lost exception on non debug """
|
||||||
stream = StringIO()
|
stream = StringIO()
|
||||||
root = logging.getLogger('sanic.root')
|
root = logging.getLogger("sanic.root")
|
||||||
root.addHandler(logging.StreamHandler(stream))
|
root.addHandler(logging.StreamHandler(stream))
|
||||||
monkeypatch.setattr(sanic.server, 'logger', root)
|
monkeypatch.setattr(sanic.server, "logger", root)
|
||||||
|
|
||||||
@app.route('/conn_lost')
|
@app.route("/conn_lost")
|
||||||
async def conn_lost(request):
|
async def conn_lost(request):
|
||||||
response = text('Ok')
|
response = text("Ok")
|
||||||
response.output = Mock(side_effect=RuntimeError)
|
response.output = Mock(side_effect=RuntimeError)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
# catch ValueError: Exception during request
|
# catch ValueError: Exception during request
|
||||||
app.test_client.get('/conn_lost', debug=debug)
|
app.test_client.get("/conn_lost", debug=debug)
|
||||||
|
|
||||||
log = stream.getvalue()
|
log = stream.getvalue()
|
||||||
|
|
||||||
if debug:
|
if debug:
|
||||||
assert 'Connection lost before response written @' in log
|
assert "Connection lost before response written @" in log
|
||||||
else:
|
else:
|
||||||
assert 'Connection lost before response written @' not in log
|
assert "Connection lost before response written @" not in log
|
||||||
|
|
||||||
|
|
||||||
def test_logger(caplog):
|
def test_logger(caplog):
|
||||||
|
@ -110,26 +129,38 @@ def test_logger(caplog):
|
||||||
|
|
||||||
app = Sanic()
|
app = Sanic()
|
||||||
|
|
||||||
@app.get('/')
|
@app.get("/")
|
||||||
def log_info(request):
|
def log_info(request):
|
||||||
logger.info(rand_string)
|
logger.info(rand_string)
|
||||||
return text('hello')
|
return text("hello")
|
||||||
|
|
||||||
with caplog.at_level(logging.INFO):
|
with caplog.at_level(logging.INFO):
|
||||||
request, response = app.test_client.get('/')
|
request, response = app.test_client.get("/")
|
||||||
|
|
||||||
assert caplog.record_tuples[0] == ('sanic.root', logging.INFO, 'Goin\' Fast @ http://127.0.0.1:42101')
|
assert caplog.record_tuples[0] == (
|
||||||
assert caplog.record_tuples[1] == ('sanic.root', logging.INFO, 'http://127.0.0.1:42101/')
|
"sanic.root",
|
||||||
assert caplog.record_tuples[2] == ('sanic.root', logging.INFO, rand_string)
|
logging.INFO,
|
||||||
assert caplog.record_tuples[-1] == ('sanic.root', logging.INFO, 'Server Stopped')
|
"Goin' Fast @ http://127.0.0.1:42101",
|
||||||
|
)
|
||||||
|
assert caplog.record_tuples[1] == (
|
||||||
|
"sanic.root",
|
||||||
|
logging.INFO,
|
||||||
|
"http://127.0.0.1:42101/",
|
||||||
|
)
|
||||||
|
assert caplog.record_tuples[2] == ("sanic.root", logging.INFO, rand_string)
|
||||||
|
assert caplog.record_tuples[-1] == (
|
||||||
|
"sanic.root",
|
||||||
|
logging.INFO,
|
||||||
|
"Server Stopped",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_logging_modified_root_logger_config():
|
def test_logging_modified_root_logger_config():
|
||||||
# reset_logging()
|
# reset_logging()
|
||||||
|
|
||||||
modified_config = LOGGING_CONFIG_DEFAULTS
|
modified_config = LOGGING_CONFIG_DEFAULTS
|
||||||
modified_config['loggers']['sanic.root']['level'] = 'DEBUG'
|
modified_config["loggers"]["sanic.root"]["level"] = "DEBUG"
|
||||||
|
|
||||||
app = Sanic("test_logging", log_config=modified_config)
|
app = Sanic("test_logging", log_config=modified_config)
|
||||||
|
|
||||||
assert logging.getLogger('sanic.root').getEffectiveLevel() == logging.DEBUG
|
assert logging.getLogger("sanic.root").getEffectiveLevel() == logging.DEBUG
|
||||||
|
|
84
tests/test_logo.py
Normal file
84
tests/test_logo.py
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
import logging
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
from sanic.config import BASE_LOGO
|
||||||
|
|
||||||
|
try:
|
||||||
|
import uvloop # noqa
|
||||||
|
ROW = 0
|
||||||
|
except BaseException:
|
||||||
|
ROW = 1
|
||||||
|
|
||||||
|
|
||||||
|
def test_logo_base(app, caplog):
|
||||||
|
server = app.create_server(debug=True)
|
||||||
|
loop = asyncio.new_event_loop()
|
||||||
|
asyncio.set_event_loop(loop)
|
||||||
|
loop._stopping = False
|
||||||
|
|
||||||
|
with caplog.at_level(logging.DEBUG):
|
||||||
|
_server = loop.run_until_complete(server)
|
||||||
|
|
||||||
|
_server.close()
|
||||||
|
loop.run_until_complete(_server.wait_closed())
|
||||||
|
app.stop()
|
||||||
|
|
||||||
|
assert caplog.record_tuples[ROW][1] == logging.DEBUG
|
||||||
|
assert caplog.record_tuples[ROW][2] == BASE_LOGO
|
||||||
|
|
||||||
|
|
||||||
|
def test_logo_false(app, caplog):
|
||||||
|
app.config.LOGO = False
|
||||||
|
|
||||||
|
server = app.create_server(debug=True)
|
||||||
|
loop = asyncio.new_event_loop()
|
||||||
|
asyncio.set_event_loop(loop)
|
||||||
|
loop._stopping = False
|
||||||
|
|
||||||
|
with caplog.at_level(logging.DEBUG):
|
||||||
|
_server = loop.run_until_complete(server)
|
||||||
|
|
||||||
|
_server.close()
|
||||||
|
loop.run_until_complete(_server.wait_closed())
|
||||||
|
app.stop()
|
||||||
|
|
||||||
|
assert caplog.record_tuples[ROW][1] == logging.INFO
|
||||||
|
assert caplog.record_tuples[ROW][2] == "Goin' Fast @ http://127.0.0.1:8000"
|
||||||
|
|
||||||
|
|
||||||
|
def test_logo_true(app, caplog):
|
||||||
|
app.config.LOGO = True
|
||||||
|
|
||||||
|
server = app.create_server(debug=True)
|
||||||
|
loop = asyncio.new_event_loop()
|
||||||
|
asyncio.set_event_loop(loop)
|
||||||
|
loop._stopping = False
|
||||||
|
|
||||||
|
with caplog.at_level(logging.DEBUG):
|
||||||
|
_server = loop.run_until_complete(server)
|
||||||
|
|
||||||
|
_server.close()
|
||||||
|
loop.run_until_complete(_server.wait_closed())
|
||||||
|
app.stop()
|
||||||
|
|
||||||
|
assert caplog.record_tuples[ROW][1] == logging.DEBUG
|
||||||
|
assert caplog.record_tuples[ROW][2] == BASE_LOGO
|
||||||
|
|
||||||
|
|
||||||
|
def test_logo_custom(app, caplog):
|
||||||
|
app.config.LOGO = "My Custom Logo"
|
||||||
|
|
||||||
|
server = app.create_server(debug=True)
|
||||||
|
loop = asyncio.new_event_loop()
|
||||||
|
asyncio.set_event_loop(loop)
|
||||||
|
loop._stopping = False
|
||||||
|
|
||||||
|
with caplog.at_level(logging.DEBUG):
|
||||||
|
_server = loop.run_until_complete(server)
|
||||||
|
|
||||||
|
_server.close()
|
||||||
|
loop.run_until_complete(_server.wait_closed())
|
||||||
|
app.stop()
|
||||||
|
|
||||||
|
assert caplog.record_tuples[ROW][1] == logging.DEBUG
|
||||||
|
assert caplog.record_tuples[ROW][2] == "My Custom Logo"
|
|
@ -9,6 +9,7 @@ from sanic.response import HTTPResponse, text
|
||||||
# GET
|
# GET
|
||||||
# ------------------------------------------------------------ #
|
# ------------------------------------------------------------ #
|
||||||
|
|
||||||
|
|
||||||
def test_middleware_request(app):
|
def test_middleware_request(app):
|
||||||
results = []
|
results = []
|
||||||
|
|
||||||
|
@ -16,168 +17,164 @@ def test_middleware_request(app):
|
||||||
async def handler1(request):
|
async def handler1(request):
|
||||||
results.append(request)
|
results.append(request)
|
||||||
|
|
||||||
@app.route('/')
|
@app.route("/")
|
||||||
async def handler2(request):
|
async def handler2(request):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
request, response = app.test_client.get('/')
|
request, response = app.test_client.get("/")
|
||||||
|
|
||||||
assert response.text == 'OK'
|
assert response.text == "OK"
|
||||||
assert type(results[0]) is Request
|
assert type(results[0]) is Request
|
||||||
|
|
||||||
|
|
||||||
def test_middleware_response(app):
|
def test_middleware_response(app):
|
||||||
results = []
|
results = []
|
||||||
|
|
||||||
@app.middleware('request')
|
@app.middleware("request")
|
||||||
async def process_request(request):
|
async def process_request(request):
|
||||||
results.append(request)
|
results.append(request)
|
||||||
|
|
||||||
@app.middleware('response')
|
@app.middleware("response")
|
||||||
async def process_response(request, response):
|
async def process_response(request, response):
|
||||||
results.append(request)
|
results.append(request)
|
||||||
results.append(response)
|
results.append(response)
|
||||||
|
|
||||||
@app.route('/')
|
@app.route("/")
|
||||||
async def handler(request):
|
async def handler(request):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
request, response = app.test_client.get('/')
|
request, response = app.test_client.get("/")
|
||||||
|
|
||||||
assert response.text == 'OK'
|
assert response.text == "OK"
|
||||||
assert type(results[0]) is Request
|
assert type(results[0]) is Request
|
||||||
assert type(results[1]) is Request
|
assert type(results[1]) is Request
|
||||||
assert isinstance(results[2], HTTPResponse)
|
assert isinstance(results[2], HTTPResponse)
|
||||||
|
|
||||||
|
|
||||||
def test_middleware_response_exception(app):
|
def test_middleware_response_exception(app):
|
||||||
result = {'status_code': None}
|
result = {"status_code": None}
|
||||||
|
|
||||||
@app.middleware('response')
|
@app.middleware("response")
|
||||||
async def process_response(request, response):
|
async def process_response(request, response):
|
||||||
result['status_code'] = response.status
|
result["status_code"] = response.status
|
||||||
return response
|
return response
|
||||||
|
|
||||||
@app.exception(NotFound)
|
@app.exception(NotFound)
|
||||||
async def error_handler(request, exception):
|
async def error_handler(request, exception):
|
||||||
return text('OK', exception.status_code)
|
return text("OK", exception.status_code)
|
||||||
|
|
||||||
@app.route('/')
|
@app.route("/")
|
||||||
async def handler(request):
|
async def handler(request):
|
||||||
return text('FAIL')
|
return text("FAIL")
|
||||||
|
|
||||||
request, response = app.test_client.get('/page_not_found')
|
request, response = app.test_client.get("/page_not_found")
|
||||||
assert response.text == 'OK'
|
assert response.text == "OK"
|
||||||
assert result['status_code'] == 404
|
assert result["status_code"] == 404
|
||||||
|
|
||||||
|
|
||||||
def test_middleware_response_raise_cancelled_error(app, caplog):
|
def test_middleware_response_raise_cancelled_error(app, caplog):
|
||||||
|
@app.middleware("response")
|
||||||
@app.middleware('response')
|
|
||||||
async def process_response(request, response):
|
async def process_response(request, response):
|
||||||
raise CancelledError('CancelledError at response middleware')
|
raise CancelledError("CancelledError at response middleware")
|
||||||
|
|
||||||
@app.get('/')
|
@app.get("/")
|
||||||
def handler(request):
|
def handler(request):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
with caplog.at_level(logging.ERROR):
|
with caplog.at_level(logging.ERROR):
|
||||||
reqrequest, response = app.test_client.get('/')
|
reqrequest, response = app.test_client.get("/")
|
||||||
|
|
||||||
assert response.status == 503
|
assert response.status == 503
|
||||||
assert caplog.record_tuples[0] == (
|
assert caplog.record_tuples[0] == (
|
||||||
'sanic.root',
|
"sanic.root",
|
||||||
logging.ERROR,
|
logging.ERROR,
|
||||||
'Exception occurred while handling uri: \'http://127.0.0.1:42101/\''
|
"Exception occurred while handling uri: 'http://127.0.0.1:42101/'",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_middleware_response_raise_exception(app, caplog):
|
def test_middleware_response_raise_exception(app, caplog):
|
||||||
|
@app.middleware("response")
|
||||||
@app.middleware('response')
|
|
||||||
async def process_response(request, response):
|
async def process_response(request, response):
|
||||||
raise Exception('Exception at response middleware')
|
raise Exception("Exception at response middleware")
|
||||||
|
|
||||||
with caplog.at_level(logging.ERROR):
|
with caplog.at_level(logging.ERROR):
|
||||||
reqrequest, response = app.test_client.get('/')
|
reqrequest, response = app.test_client.get("/")
|
||||||
|
|
||||||
assert response.status == 404
|
assert response.status == 404
|
||||||
assert caplog.record_tuples[0] == (
|
assert caplog.record_tuples[0] == (
|
||||||
'sanic.root',
|
"sanic.root",
|
||||||
logging.ERROR,
|
logging.ERROR,
|
||||||
'Exception occurred while handling uri: \'http://127.0.0.1:42101/\''
|
"Exception occurred while handling uri: 'http://127.0.0.1:42101/'",
|
||||||
)
|
)
|
||||||
assert caplog.record_tuples[1] == (
|
assert caplog.record_tuples[1] == (
|
||||||
'sanic.error',
|
"sanic.error",
|
||||||
logging.ERROR,
|
logging.ERROR,
|
||||||
'Exception occurred in one of response middleware handlers'
|
"Exception occurred in one of response middleware handlers",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_middleware_override_request(app):
|
def test_middleware_override_request(app):
|
||||||
|
|
||||||
@app.middleware
|
@app.middleware
|
||||||
async def halt_request(request):
|
async def halt_request(request):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
@app.route('/')
|
@app.route("/")
|
||||||
async def handler(request):
|
async def handler(request):
|
||||||
return text('FAIL')
|
return text("FAIL")
|
||||||
|
|
||||||
response = app.test_client.get('/', gather_request=False)
|
response = app.test_client.get("/", gather_request=False)
|
||||||
|
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == 'OK'
|
assert response.text == "OK"
|
||||||
|
|
||||||
|
|
||||||
def test_middleware_override_response(app):
|
def test_middleware_override_response(app):
|
||||||
|
@app.middleware("response")
|
||||||
@app.middleware('response')
|
|
||||||
async def process_response(request, response):
|
async def process_response(request, response):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
@app.route('/')
|
@app.route("/")
|
||||||
async def handler(request):
|
async def handler(request):
|
||||||
return text('FAIL')
|
return text("FAIL")
|
||||||
|
|
||||||
request, response = app.test_client.get('/')
|
request, response = app.test_client.get("/")
|
||||||
|
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == 'OK'
|
assert response.text == "OK"
|
||||||
|
|
||||||
|
|
||||||
def test_middleware_order(app):
|
def test_middleware_order(app):
|
||||||
order = []
|
order = []
|
||||||
|
|
||||||
@app.middleware('request')
|
@app.middleware("request")
|
||||||
async def request1(request):
|
async def request1(request):
|
||||||
order.append(1)
|
order.append(1)
|
||||||
|
|
||||||
@app.middleware('request')
|
@app.middleware("request")
|
||||||
async def request2(request):
|
async def request2(request):
|
||||||
order.append(2)
|
order.append(2)
|
||||||
|
|
||||||
@app.middleware('request')
|
@app.middleware("request")
|
||||||
async def request3(request):
|
async def request3(request):
|
||||||
order.append(3)
|
order.append(3)
|
||||||
|
|
||||||
@app.middleware('response')
|
@app.middleware("response")
|
||||||
async def response1(request, response):
|
async def response1(request, response):
|
||||||
order.append(6)
|
order.append(6)
|
||||||
|
|
||||||
@app.middleware('response')
|
@app.middleware("response")
|
||||||
async def response2(request, response):
|
async def response2(request, response):
|
||||||
order.append(5)
|
order.append(5)
|
||||||
|
|
||||||
@app.middleware('response')
|
@app.middleware("response")
|
||||||
async def response3(request, response):
|
async def response3(request, response):
|
||||||
order.append(4)
|
order.append(4)
|
||||||
|
|
||||||
@app.route('/')
|
@app.route("/")
|
||||||
async def handler(request):
|
async def handler(request):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
request, response = app.test_client.get('/')
|
request, response = app.test_client.get("/")
|
||||||
|
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert order == [1, 2, 3, 4, 5, 6]
|
assert order == [1, 2, 3, 4, 5, 6]
|
||||||
|
|
|
@ -9,9 +9,9 @@ from sanic.response import text
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(
|
@pytest.mark.skipif(
|
||||||
not hasattr(signal, 'SIGALRM'),
|
not hasattr(signal, "SIGALRM"),
|
||||||
reason='SIGALRM is not implemented for this platform, we have to come '
|
reason="SIGALRM is not implemented for this platform, we have to come "
|
||||||
'up with another timeout strategy to test these'
|
"up with another timeout strategy to test these",
|
||||||
)
|
)
|
||||||
def test_multiprocessing(app):
|
def test_multiprocessing(app):
|
||||||
"""Tests that the number of children we produce is correct"""
|
"""Tests that the number of children we produce is correct"""
|
||||||
|
@ -32,11 +32,12 @@ def test_multiprocessing(app):
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(
|
@pytest.mark.skipif(
|
||||||
not hasattr(signal, 'SIGALRM'),
|
not hasattr(signal, "SIGALRM"),
|
||||||
reason='SIGALRM is not implemented for this platform',
|
reason="SIGALRM is not implemented for this platform",
|
||||||
)
|
)
|
||||||
def test_multiprocessing_with_blueprint(app):
|
def test_multiprocessing_with_blueprint(app):
|
||||||
from sanic import Blueprint
|
from sanic import Blueprint
|
||||||
|
|
||||||
# Selects a number at random so we can spot check
|
# Selects a number at random so we can spot check
|
||||||
num_workers = random.choice(range(2, multiprocessing.cpu_count() * 2 + 1))
|
num_workers = random.choice(range(2, multiprocessing.cpu_count() * 2 + 1))
|
||||||
process_list = set()
|
process_list = set()
|
||||||
|
@ -49,7 +50,7 @@ def test_multiprocessing_with_blueprint(app):
|
||||||
signal.signal(signal.SIGALRM, stop_on_alarm)
|
signal.signal(signal.SIGALRM, stop_on_alarm)
|
||||||
signal.alarm(3)
|
signal.alarm(3)
|
||||||
|
|
||||||
bp = Blueprint('test_text')
|
bp = Blueprint("test_text")
|
||||||
app.blueprint(bp)
|
app.blueprint(bp)
|
||||||
app.run(HOST, PORT, workers=num_workers)
|
app.run(HOST, PORT, workers=num_workers)
|
||||||
|
|
||||||
|
@ -59,28 +60,30 @@ def test_multiprocessing_with_blueprint(app):
|
||||||
# this function must be outside a test function so that it can be
|
# this function must be outside a test function so that it can be
|
||||||
# able to be pickled (local functions cannot be pickled).
|
# able to be pickled (local functions cannot be pickled).
|
||||||
def handler(request):
|
def handler(request):
|
||||||
return text('Hello')
|
return text("Hello")
|
||||||
|
|
||||||
|
|
||||||
# Muliprocessing on Windows requires app to be able to be pickled
|
# Muliprocessing on Windows requires app to be able to be pickled
|
||||||
@pytest.mark.parametrize('protocol', [3, 4])
|
@pytest.mark.parametrize("protocol", [3, 4])
|
||||||
def test_pickle_app(app, protocol):
|
def test_pickle_app(app, protocol):
|
||||||
app.route('/')(handler)
|
app.route("/")(handler)
|
||||||
p_app = pickle.dumps(app, protocol=protocol)
|
p_app = pickle.dumps(app, protocol=protocol)
|
||||||
up_p_app = pickle.loads(p_app)
|
up_p_app = pickle.loads(p_app)
|
||||||
assert up_p_app
|
assert up_p_app
|
||||||
request, response = app.test_client.get('/')
|
request, response = app.test_client.get("/")
|
||||||
assert response.text == 'Hello'
|
assert response.text == "Hello"
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('protocol', [3, 4])
|
@pytest.mark.parametrize("protocol", [3, 4])
|
||||||
def test_pickle_app_with_bp(app, protocol):
|
def test_pickle_app_with_bp(app, protocol):
|
||||||
from sanic import Blueprint
|
from sanic import Blueprint
|
||||||
bp = Blueprint('test_text')
|
|
||||||
bp.route('/')(handler)
|
bp = Blueprint("test_text")
|
||||||
|
bp.route("/")(handler)
|
||||||
app.blueprint(bp)
|
app.blueprint(bp)
|
||||||
p_app = pickle.dumps(app, protocol=protocol)
|
p_app = pickle.dumps(app, protocol=protocol)
|
||||||
up_p_app = pickle.loads(p_app)
|
up_p_app = pickle.loads(p_app)
|
||||||
assert up_p_app
|
assert up_p_app
|
||||||
request, response = app.test_client.get('/')
|
request, response = app.test_client.get("/")
|
||||||
assert app.is_request_stream is False
|
assert app.is_request_stream is False
|
||||||
assert response.text == 'Hello'
|
assert response.text == "Hello"
|
||||||
|
|
|
@ -14,28 +14,32 @@ from sanic.constants import HTTP_METHODS
|
||||||
# UTF-8
|
# UTF-8
|
||||||
# ------------------------------------------------------------ #
|
# ------------------------------------------------------------ #
|
||||||
|
|
||||||
@pytest.mark.parametrize('method', HTTP_METHODS)
|
|
||||||
|
@pytest.mark.parametrize("method", HTTP_METHODS)
|
||||||
def test_versioned_named_routes_get(app, method):
|
def test_versioned_named_routes_get(app, method):
|
||||||
bp = Blueprint('test_bp', url_prefix='/bp')
|
bp = Blueprint("test_bp", url_prefix="/bp")
|
||||||
|
|
||||||
method = method.lower()
|
method = method.lower()
|
||||||
route_name = 'route_{}'.format(method)
|
route_name = "route_{}".format(method)
|
||||||
route_name2 = 'route2_{}'.format(method)
|
route_name2 = "route2_{}".format(method)
|
||||||
|
|
||||||
func = getattr(app, method)
|
func = getattr(app, method)
|
||||||
if callable(func):
|
if callable(func):
|
||||||
@func('/{}'.format(method), version=1, name=route_name)
|
|
||||||
|
@func("/{}".format(method), version=1, name=route_name)
|
||||||
def handler(request):
|
def handler(request):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
else:
|
else:
|
||||||
print(func)
|
print(func)
|
||||||
raise
|
raise
|
||||||
|
|
||||||
func = getattr(bp, method)
|
func = getattr(bp, method)
|
||||||
if callable(func):
|
if callable(func):
|
||||||
@func('/{}'.format(method), version=1, name=route_name2)
|
|
||||||
|
@func("/{}".format(method), version=1, name=route_name2)
|
||||||
def handler2(request):
|
def handler2(request):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
else:
|
else:
|
||||||
print(func)
|
print(func)
|
||||||
|
@ -43,261 +47,250 @@ def test_versioned_named_routes_get(app, method):
|
||||||
|
|
||||||
app.blueprint(bp)
|
app.blueprint(bp)
|
||||||
|
|
||||||
assert app.router.routes_all['/v1/{}'.format(method)].name == route_name
|
assert app.router.routes_all["/v1/{}".format(method)].name == route_name
|
||||||
|
|
||||||
route = app.router.routes_all['/v1/bp/{}'.format(method)]
|
route = app.router.routes_all["/v1/bp/{}".format(method)]
|
||||||
assert route.name == 'test_bp.{}'.format(route_name2)
|
assert route.name == "test_bp.{}".format(route_name2)
|
||||||
|
|
||||||
assert app.url_for(route_name) == '/v1/{}'.format(method)
|
assert app.url_for(route_name) == "/v1/{}".format(method)
|
||||||
url = app.url_for('test_bp.{}'.format(route_name2))
|
url = app.url_for("test_bp.{}".format(route_name2))
|
||||||
assert url == '/v1/bp/{}'.format(method)
|
assert url == "/v1/bp/{}".format(method)
|
||||||
with pytest.raises(URLBuildError):
|
with pytest.raises(URLBuildError):
|
||||||
app.url_for('handler')
|
app.url_for("handler")
|
||||||
|
|
||||||
|
|
||||||
def test_shorthand_default_routes_get(app):
|
def test_shorthand_default_routes_get(app):
|
||||||
|
@app.get("/get")
|
||||||
@app.get('/get')
|
|
||||||
def handler(request):
|
def handler(request):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
assert app.router.routes_all['/get'].name == 'handler'
|
assert app.router.routes_all["/get"].name == "handler"
|
||||||
assert app.url_for('handler') == '/get'
|
assert app.url_for("handler") == "/get"
|
||||||
|
|
||||||
|
|
||||||
def test_shorthand_named_routes_get(app):
|
def test_shorthand_named_routes_get(app):
|
||||||
bp = Blueprint('test_bp', url_prefix='/bp')
|
bp = Blueprint("test_bp", url_prefix="/bp")
|
||||||
|
|
||||||
@app.get('/get', name='route_get')
|
@app.get("/get", name="route_get")
|
||||||
def handler(request):
|
def handler(request):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
@bp.get('/get', name='route_bp')
|
@bp.get("/get", name="route_bp")
|
||||||
def handler2(request):
|
def handler2(request):
|
||||||
return text('Blueprint')
|
return text("Blueprint")
|
||||||
|
|
||||||
app.blueprint(bp)
|
app.blueprint(bp)
|
||||||
|
|
||||||
assert app.router.routes_all['/get'].name == 'route_get'
|
assert app.router.routes_all["/get"].name == "route_get"
|
||||||
assert app.url_for('route_get') == '/get'
|
assert app.url_for("route_get") == "/get"
|
||||||
with pytest.raises(URLBuildError):
|
with pytest.raises(URLBuildError):
|
||||||
app.url_for('handler')
|
app.url_for("handler")
|
||||||
|
|
||||||
assert app.router.routes_all['/bp/get'].name == 'test_bp.route_bp'
|
assert app.router.routes_all["/bp/get"].name == "test_bp.route_bp"
|
||||||
assert app.url_for('test_bp.route_bp') == '/bp/get'
|
assert app.url_for("test_bp.route_bp") == "/bp/get"
|
||||||
with pytest.raises(URLBuildError):
|
with pytest.raises(URLBuildError):
|
||||||
app.url_for('test_bp.handler2')
|
app.url_for("test_bp.handler2")
|
||||||
|
|
||||||
|
|
||||||
def test_shorthand_named_routes_post(app):
|
def test_shorthand_named_routes_post(app):
|
||||||
|
@app.post("/post", name="route_name")
|
||||||
@app.post('/post', name='route_name')
|
|
||||||
def handler(request):
|
def handler(request):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
assert app.router.routes_all['/post'].name == 'route_name'
|
assert app.router.routes_all["/post"].name == "route_name"
|
||||||
assert app.url_for('route_name') == '/post'
|
assert app.url_for("route_name") == "/post"
|
||||||
with pytest.raises(URLBuildError):
|
with pytest.raises(URLBuildError):
|
||||||
app.url_for('handler')
|
app.url_for("handler")
|
||||||
|
|
||||||
|
|
||||||
def test_shorthand_named_routes_put(app):
|
def test_shorthand_named_routes_put(app):
|
||||||
|
@app.put("/put", name="route_put")
|
||||||
@app.put('/put', name='route_put')
|
|
||||||
def handler(request):
|
def handler(request):
|
||||||
assert request.stream is None
|
assert request.stream is None
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
assert app.is_request_stream is False
|
assert app.is_request_stream is False
|
||||||
assert app.router.routes_all['/put'].name == 'route_put'
|
assert app.router.routes_all["/put"].name == "route_put"
|
||||||
assert app.url_for('route_put') == '/put'
|
assert app.url_for("route_put") == "/put"
|
||||||
with pytest.raises(URLBuildError):
|
with pytest.raises(URLBuildError):
|
||||||
app.url_for('handler')
|
app.url_for("handler")
|
||||||
|
|
||||||
|
|
||||||
def test_shorthand_named_routes_delete(app):
|
def test_shorthand_named_routes_delete(app):
|
||||||
|
@app.delete("/delete", name="route_delete")
|
||||||
@app.delete('/delete', name='route_delete')
|
|
||||||
def handler(request):
|
def handler(request):
|
||||||
assert request.stream is None
|
assert request.stream is None
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
assert app.is_request_stream is False
|
assert app.is_request_stream is False
|
||||||
assert app.router.routes_all['/delete'].name == 'route_delete'
|
assert app.router.routes_all["/delete"].name == "route_delete"
|
||||||
assert app.url_for('route_delete') == '/delete'
|
assert app.url_for("route_delete") == "/delete"
|
||||||
with pytest.raises(URLBuildError):
|
with pytest.raises(URLBuildError):
|
||||||
app.url_for('handler')
|
app.url_for("handler")
|
||||||
|
|
||||||
|
|
||||||
def test_shorthand_named_routes_patch(app):
|
def test_shorthand_named_routes_patch(app):
|
||||||
|
@app.patch("/patch", name="route_patch")
|
||||||
@app.patch('/patch', name='route_patch')
|
|
||||||
def handler(request):
|
def handler(request):
|
||||||
assert request.stream is None
|
assert request.stream is None
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
assert app.is_request_stream is False
|
assert app.is_request_stream is False
|
||||||
assert app.router.routes_all['/patch'].name == 'route_patch'
|
assert app.router.routes_all["/patch"].name == "route_patch"
|
||||||
assert app.url_for('route_patch') == '/patch'
|
assert app.url_for("route_patch") == "/patch"
|
||||||
with pytest.raises(URLBuildError):
|
with pytest.raises(URLBuildError):
|
||||||
app.url_for('handler')
|
app.url_for("handler")
|
||||||
|
|
||||||
|
|
||||||
def test_shorthand_named_routes_head(app):
|
def test_shorthand_named_routes_head(app):
|
||||||
|
@app.head("/head", name="route_head")
|
||||||
@app.head('/head', name='route_head')
|
|
||||||
def handler(request):
|
def handler(request):
|
||||||
assert request.stream is None
|
assert request.stream is None
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
assert app.is_request_stream is False
|
assert app.is_request_stream is False
|
||||||
assert app.router.routes_all['/head'].name == 'route_head'
|
assert app.router.routes_all["/head"].name == "route_head"
|
||||||
assert app.url_for('route_head') == '/head'
|
assert app.url_for("route_head") == "/head"
|
||||||
with pytest.raises(URLBuildError):
|
with pytest.raises(URLBuildError):
|
||||||
app.url_for('handler')
|
app.url_for("handler")
|
||||||
|
|
||||||
|
|
||||||
def test_shorthand_named_routes_options(app):
|
def test_shorthand_named_routes_options(app):
|
||||||
|
@app.options("/options", name="route_options")
|
||||||
@app.options('/options', name='route_options')
|
|
||||||
def handler(request):
|
def handler(request):
|
||||||
assert request.stream is None
|
assert request.stream is None
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
assert app.is_request_stream is False
|
assert app.is_request_stream is False
|
||||||
assert app.router.routes_all['/options'].name == 'route_options'
|
assert app.router.routes_all["/options"].name == "route_options"
|
||||||
assert app.url_for('route_options') == '/options'
|
assert app.url_for("route_options") == "/options"
|
||||||
with pytest.raises(URLBuildError):
|
with pytest.raises(URLBuildError):
|
||||||
app.url_for('handler')
|
app.url_for("handler")
|
||||||
|
|
||||||
|
|
||||||
def test_named_static_routes(app):
|
def test_named_static_routes(app):
|
||||||
|
@app.route("/test", name="route_test")
|
||||||
@app.route('/test', name='route_test')
|
|
||||||
async def handler1(request):
|
async def handler1(request):
|
||||||
return text('OK1')
|
return text("OK1")
|
||||||
|
|
||||||
@app.route('/pizazz', name='route_pizazz')
|
@app.route("/pizazz", name="route_pizazz")
|
||||||
async def handler2(request):
|
async def handler2(request):
|
||||||
return text('OK2')
|
return text("OK2")
|
||||||
|
|
||||||
assert app.router.routes_all['/test'].name == 'route_test'
|
assert app.router.routes_all["/test"].name == "route_test"
|
||||||
assert app.router.routes_static['/test'].name == 'route_test'
|
assert app.router.routes_static["/test"].name == "route_test"
|
||||||
assert app.url_for('route_test') == '/test'
|
assert app.url_for("route_test") == "/test"
|
||||||
with pytest.raises(URLBuildError):
|
with pytest.raises(URLBuildError):
|
||||||
app.url_for('handler1')
|
app.url_for("handler1")
|
||||||
|
|
||||||
assert app.router.routes_all['/pizazz'].name == 'route_pizazz'
|
assert app.router.routes_all["/pizazz"].name == "route_pizazz"
|
||||||
assert app.router.routes_static['/pizazz'].name == 'route_pizazz'
|
assert app.router.routes_static["/pizazz"].name == "route_pizazz"
|
||||||
assert app.url_for('route_pizazz') == '/pizazz'
|
assert app.url_for("route_pizazz") == "/pizazz"
|
||||||
with pytest.raises(URLBuildError):
|
with pytest.raises(URLBuildError):
|
||||||
app.url_for('handler2')
|
app.url_for("handler2")
|
||||||
|
|
||||||
|
|
||||||
def test_named_dynamic_route(app):
|
def test_named_dynamic_route(app):
|
||||||
results = []
|
results = []
|
||||||
|
|
||||||
@app.route('/folder/<name>', name='route_dynamic')
|
@app.route("/folder/<name>", name="route_dynamic")
|
||||||
async def handler(request, name):
|
async def handler(request, name):
|
||||||
results.append(name)
|
results.append(name)
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
assert app.router.routes_all['/folder/<name>'].name == 'route_dynamic'
|
assert app.router.routes_all["/folder/<name>"].name == "route_dynamic"
|
||||||
assert app.url_for('route_dynamic', name='test') == '/folder/test'
|
assert app.url_for("route_dynamic", name="test") == "/folder/test"
|
||||||
with pytest.raises(URLBuildError):
|
with pytest.raises(URLBuildError):
|
||||||
app.url_for('handler')
|
app.url_for("handler")
|
||||||
|
|
||||||
|
|
||||||
def test_dynamic_named_route_regex(app):
|
def test_dynamic_named_route_regex(app):
|
||||||
|
@app.route("/folder/<folder_id:[A-Za-z0-9]{0,4}>", name="route_re")
|
||||||
@app.route('/folder/<folder_id:[A-Za-z0-9]{0,4}>', name='route_re')
|
|
||||||
async def handler(request, folder_id):
|
async def handler(request, folder_id):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
route = app.router.routes_all['/folder/<folder_id:[A-Za-z0-9]{0,4}>']
|
route = app.router.routes_all["/folder/<folder_id:[A-Za-z0-9]{0,4}>"]
|
||||||
assert route.name == 'route_re'
|
assert route.name == "route_re"
|
||||||
assert app.url_for('route_re', folder_id='test') == '/folder/test'
|
assert app.url_for("route_re", folder_id="test") == "/folder/test"
|
||||||
with pytest.raises(URLBuildError):
|
with pytest.raises(URLBuildError):
|
||||||
app.url_for('handler')
|
app.url_for("handler")
|
||||||
|
|
||||||
|
|
||||||
def test_dynamic_named_route_path(app):
|
def test_dynamic_named_route_path(app):
|
||||||
|
@app.route("/<path:path>/info", name="route_dynamic_path")
|
||||||
@app.route('/<path:path>/info', name='route_dynamic_path')
|
|
||||||
async def handler(request, path):
|
async def handler(request, path):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
route = app.router.routes_all['/<path:path>/info']
|
route = app.router.routes_all["/<path:path>/info"]
|
||||||
assert route.name == 'route_dynamic_path'
|
assert route.name == "route_dynamic_path"
|
||||||
assert app.url_for('route_dynamic_path', path='path/1') == '/path/1/info'
|
assert app.url_for("route_dynamic_path", path="path/1") == "/path/1/info"
|
||||||
with pytest.raises(URLBuildError):
|
with pytest.raises(URLBuildError):
|
||||||
app.url_for('handler')
|
app.url_for("handler")
|
||||||
|
|
||||||
|
|
||||||
def test_dynamic_named_route_unhashable(app):
|
def test_dynamic_named_route_unhashable(app):
|
||||||
|
@app.route(
|
||||||
@app.route('/folder/<unhashable:[A-Za-z0-9/]+>/end/',
|
"/folder/<unhashable:[A-Za-z0-9/]+>/end/", name="route_unhashable"
|
||||||
name='route_unhashable')
|
)
|
||||||
async def handler(request, unhashable):
|
async def handler(request, unhashable):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
route = app.router.routes_all['/folder/<unhashable:[A-Za-z0-9/]+>/end/']
|
route = app.router.routes_all["/folder/<unhashable:[A-Za-z0-9/]+>/end/"]
|
||||||
assert route.name == 'route_unhashable'
|
assert route.name == "route_unhashable"
|
||||||
url = app.url_for('route_unhashable', unhashable='test/asdf')
|
url = app.url_for("route_unhashable", unhashable="test/asdf")
|
||||||
assert url == '/folder/test/asdf/end'
|
assert url == "/folder/test/asdf/end"
|
||||||
with pytest.raises(URLBuildError):
|
with pytest.raises(URLBuildError):
|
||||||
app.url_for('handler')
|
app.url_for("handler")
|
||||||
|
|
||||||
|
|
||||||
def test_websocket_named_route(app):
|
def test_websocket_named_route(app):
|
||||||
ev = asyncio.Event()
|
ev = asyncio.Event()
|
||||||
|
|
||||||
@app.websocket('/ws', name='route_ws')
|
@app.websocket("/ws", name="route_ws")
|
||||||
async def handler(request, ws):
|
async def handler(request, ws):
|
||||||
assert ws.subprotocol is None
|
assert ws.subprotocol is None
|
||||||
ev.set()
|
ev.set()
|
||||||
|
|
||||||
assert app.router.routes_all['/ws'].name == 'route_ws'
|
assert app.router.routes_all["/ws"].name == "route_ws"
|
||||||
assert app.url_for('route_ws') == '/ws'
|
assert app.url_for("route_ws") == "/ws"
|
||||||
with pytest.raises(URLBuildError):
|
with pytest.raises(URLBuildError):
|
||||||
app.url_for('handler')
|
app.url_for("handler")
|
||||||
|
|
||||||
|
|
||||||
def test_websocket_named_route_with_subprotocols(app):
|
def test_websocket_named_route_with_subprotocols(app):
|
||||||
results = []
|
results = []
|
||||||
|
|
||||||
@app.websocket('/ws', subprotocols=['foo', 'bar'], name='route_ws')
|
@app.websocket("/ws", subprotocols=["foo", "bar"], name="route_ws")
|
||||||
async def handler(request, ws):
|
async def handler(request, ws):
|
||||||
results.append(ws.subprotocol)
|
results.append(ws.subprotocol)
|
||||||
|
|
||||||
assert app.router.routes_all['/ws'].name == 'route_ws'
|
assert app.router.routes_all["/ws"].name == "route_ws"
|
||||||
assert app.url_for('route_ws') == '/ws'
|
assert app.url_for("route_ws") == "/ws"
|
||||||
with pytest.raises(URLBuildError):
|
with pytest.raises(URLBuildError):
|
||||||
app.url_for('handler')
|
app.url_for("handler")
|
||||||
|
|
||||||
|
|
||||||
def test_static_add_named_route(app):
|
def test_static_add_named_route(app):
|
||||||
|
|
||||||
async def handler1(request):
|
async def handler1(request):
|
||||||
return text('OK1')
|
return text("OK1")
|
||||||
|
|
||||||
async def handler2(request):
|
async def handler2(request):
|
||||||
return text('OK2')
|
return text("OK2")
|
||||||
|
|
||||||
app.add_route(handler1, '/test', name='route_test')
|
app.add_route(handler1, "/test", name="route_test")
|
||||||
app.add_route(handler2, '/test2', name='route_test2')
|
app.add_route(handler2, "/test2", name="route_test2")
|
||||||
|
|
||||||
assert app.router.routes_all['/test'].name == 'route_test'
|
assert app.router.routes_all["/test"].name == "route_test"
|
||||||
assert app.router.routes_static['/test'].name == 'route_test'
|
assert app.router.routes_static["/test"].name == "route_test"
|
||||||
assert app.url_for('route_test') == '/test'
|
assert app.url_for("route_test") == "/test"
|
||||||
with pytest.raises(URLBuildError):
|
with pytest.raises(URLBuildError):
|
||||||
app.url_for('handler1')
|
app.url_for("handler1")
|
||||||
|
|
||||||
assert app.router.routes_all['/test2'].name == 'route_test2'
|
assert app.router.routes_all["/test2"].name == "route_test2"
|
||||||
assert app.router.routes_static['/test2'].name == 'route_test2'
|
assert app.router.routes_static["/test2"].name == "route_test2"
|
||||||
assert app.url_for('route_test2') == '/test2'
|
assert app.url_for("route_test2") == "/test2"
|
||||||
with pytest.raises(URLBuildError):
|
with pytest.raises(URLBuildError):
|
||||||
app.url_for('handler2')
|
app.url_for("handler2")
|
||||||
|
|
||||||
|
|
||||||
def test_dynamic_add_named_route(app):
|
def test_dynamic_add_named_route(app):
|
||||||
|
@ -305,61 +298,62 @@ def test_dynamic_add_named_route(app):
|
||||||
|
|
||||||
async def handler(request, name):
|
async def handler(request, name):
|
||||||
results.append(name)
|
results.append(name)
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
app.add_route(handler, '/folder/<name>', name='route_dynamic')
|
app.add_route(handler, "/folder/<name>", name="route_dynamic")
|
||||||
assert app.router.routes_all['/folder/<name>'].name == 'route_dynamic'
|
assert app.router.routes_all["/folder/<name>"].name == "route_dynamic"
|
||||||
assert app.url_for('route_dynamic', name='test') == '/folder/test'
|
assert app.url_for("route_dynamic", name="test") == "/folder/test"
|
||||||
with pytest.raises(URLBuildError):
|
with pytest.raises(URLBuildError):
|
||||||
app.url_for('handler')
|
app.url_for("handler")
|
||||||
|
|
||||||
|
|
||||||
def test_dynamic_add_named_route_unhashable(app):
|
def test_dynamic_add_named_route_unhashable(app):
|
||||||
|
|
||||||
async def handler(request, unhashable):
|
async def handler(request, unhashable):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
app.add_route(handler, '/folder/<unhashable:[A-Za-z0-9/]+>/end/',
|
app.add_route(
|
||||||
name='route_unhashable')
|
handler,
|
||||||
route = app.router.routes_all['/folder/<unhashable:[A-Za-z0-9/]+>/end/']
|
"/folder/<unhashable:[A-Za-z0-9/]+>/end/",
|
||||||
assert route.name == 'route_unhashable'
|
name="route_unhashable",
|
||||||
url = app.url_for('route_unhashable', unhashable='folder1')
|
)
|
||||||
assert url == '/folder/folder1/end'
|
route = app.router.routes_all["/folder/<unhashable:[A-Za-z0-9/]+>/end/"]
|
||||||
|
assert route.name == "route_unhashable"
|
||||||
|
url = app.url_for("route_unhashable", unhashable="folder1")
|
||||||
|
assert url == "/folder/folder1/end"
|
||||||
with pytest.raises(URLBuildError):
|
with pytest.raises(URLBuildError):
|
||||||
app.url_for('handler')
|
app.url_for("handler")
|
||||||
|
|
||||||
|
|
||||||
def test_overload_routes(app):
|
def test_overload_routes(app):
|
||||||
|
@app.route("/overload", methods=["GET"], name="route_first")
|
||||||
@app.route('/overload', methods=['GET'], name='route_first')
|
|
||||||
async def handler1(request):
|
async def handler1(request):
|
||||||
return text('OK1')
|
return text("OK1")
|
||||||
|
|
||||||
@app.route('/overload', methods=['POST', 'PUT'], name='route_second')
|
@app.route("/overload", methods=["POST", "PUT"], name="route_second")
|
||||||
async def handler2(request):
|
async def handler2(request):
|
||||||
return text('OK2')
|
return text("OK2")
|
||||||
|
|
||||||
request, response = app.test_client.get(app.url_for('route_first'))
|
request, response = app.test_client.get(app.url_for("route_first"))
|
||||||
assert response.text == 'OK1'
|
assert response.text == "OK1"
|
||||||
|
|
||||||
request, response = app.test_client.post(app.url_for('route_first'))
|
request, response = app.test_client.post(app.url_for("route_first"))
|
||||||
assert response.text == 'OK2'
|
assert response.text == "OK2"
|
||||||
|
|
||||||
request, response = app.test_client.put(app.url_for('route_first'))
|
request, response = app.test_client.put(app.url_for("route_first"))
|
||||||
assert response.text == 'OK2'
|
assert response.text == "OK2"
|
||||||
|
|
||||||
request, response = app.test_client.get(app.url_for('route_second'))
|
request, response = app.test_client.get(app.url_for("route_second"))
|
||||||
assert response.text == 'OK1'
|
assert response.text == "OK1"
|
||||||
|
|
||||||
request, response = app.test_client.post(app.url_for('route_second'))
|
request, response = app.test_client.post(app.url_for("route_second"))
|
||||||
assert response.text == 'OK2'
|
assert response.text == "OK2"
|
||||||
|
|
||||||
request, response = app.test_client.put(app.url_for('route_second'))
|
request, response = app.test_client.put(app.url_for("route_second"))
|
||||||
assert response.text == 'OK2'
|
assert response.text == "OK2"
|
||||||
|
|
||||||
assert app.router.routes_all['/overload'].name == 'route_first'
|
assert app.router.routes_all["/overload"].name == "route_first"
|
||||||
with pytest.raises(URLBuildError):
|
with pytest.raises(URLBuildError):
|
||||||
app.url_for('handler1')
|
app.url_for("handler1")
|
||||||
|
|
||||||
assert app.url_for('route_first') == '/overload'
|
assert app.url_for("route_first") == "/overload"
|
||||||
assert app.url_for('route_second') == app.url_for('route_first')
|
assert app.url_for("route_second") == app.url_for("route_first")
|
||||||
|
|
|
@ -5,41 +5,39 @@ from sanic.response import text
|
||||||
def test_payload_too_large_from_error_handler(app):
|
def test_payload_too_large_from_error_handler(app):
|
||||||
app.config.REQUEST_MAX_SIZE = 1
|
app.config.REQUEST_MAX_SIZE = 1
|
||||||
|
|
||||||
@app.route('/1')
|
@app.route("/1")
|
||||||
async def handler1(request):
|
async def handler1(request):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
@app.exception(PayloadTooLarge)
|
@app.exception(PayloadTooLarge)
|
||||||
def handler_exception(request, exception):
|
def handler_exception(request, exception):
|
||||||
return text('Payload Too Large from error_handler.', 413)
|
return text("Payload Too Large from error_handler.", 413)
|
||||||
|
|
||||||
response = app.test_client.get('/1', gather_request=False)
|
response = app.test_client.get("/1", gather_request=False)
|
||||||
assert response.status == 413
|
assert response.status == 413
|
||||||
assert response.text == 'Payload Too Large from error_handler.'
|
assert response.text == "Payload Too Large from error_handler."
|
||||||
|
|
||||||
|
|
||||||
def test_payload_too_large_at_data_received_default(app):
|
def test_payload_too_large_at_data_received_default(app):
|
||||||
app.config.REQUEST_MAX_SIZE = 1
|
app.config.REQUEST_MAX_SIZE = 1
|
||||||
|
|
||||||
@app.route('/1')
|
@app.route("/1")
|
||||||
async def handler2(request):
|
async def handler2(request):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
response = app.test_client.get(
|
response = app.test_client.get("/1", gather_request=False)
|
||||||
'/1', gather_request=False)
|
|
||||||
assert response.status == 413
|
assert response.status == 413
|
||||||
assert response.text == 'Error: Payload Too Large'
|
assert response.text == "Error: Payload Too Large"
|
||||||
|
|
||||||
|
|
||||||
def test_payload_too_large_at_on_header_default(app):
|
def test_payload_too_large_at_on_header_default(app):
|
||||||
app.config.REQUEST_MAX_SIZE = 500
|
app.config.REQUEST_MAX_SIZE = 500
|
||||||
|
|
||||||
@app.post('/1')
|
@app.post("/1")
|
||||||
async def handler3(request):
|
async def handler3(request):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
data = 'a' * 1000
|
data = "a" * 1000
|
||||||
response = app.test_client.post(
|
response = app.test_client.post("/1", gather_request=False, data=data)
|
||||||
'/1', gather_request=False, data=data)
|
|
||||||
assert response.status == 413
|
assert response.status == 413
|
||||||
assert response.text == 'Error: Payload Too Large'
|
assert response.text == "Error: Payload Too Large"
|
||||||
|
|
|
@ -6,32 +6,31 @@ from sanic.response import text, redirect
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def redirect_app(app):
|
def redirect_app(app):
|
||||||
|
@app.route("/redirect_init")
|
||||||
@app.route('/redirect_init')
|
|
||||||
async def redirect_init(request):
|
async def redirect_init(request):
|
||||||
return redirect("/redirect_target")
|
return redirect("/redirect_target")
|
||||||
|
|
||||||
@app.route('/redirect_init_with_301')
|
@app.route("/redirect_init_with_301")
|
||||||
async def redirect_init_with_301(request):
|
async def redirect_init_with_301(request):
|
||||||
return redirect("/redirect_target", status=301)
|
return redirect("/redirect_target", status=301)
|
||||||
|
|
||||||
@app.route('/redirect_target')
|
@app.route("/redirect_target")
|
||||||
async def redirect_target(request):
|
async def redirect_target(request):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
@app.route('/1')
|
@app.route("/1")
|
||||||
def handler1(request):
|
def handler1(request):
|
||||||
return redirect('/2')
|
return redirect("/2")
|
||||||
|
|
||||||
@app.route('/2')
|
@app.route("/2")
|
||||||
def handler2(request):
|
def handler2(request):
|
||||||
return redirect('/3')
|
return redirect("/3")
|
||||||
|
|
||||||
@app.route('/3')
|
@app.route("/3")
|
||||||
def handler3(request):
|
def handler3(request):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
@app.route('/redirect_with_header_injection')
|
@app.route("/redirect_with_header_injection")
|
||||||
async def redirect_with_header_injection(request):
|
async def redirect_with_header_injection(request):
|
||||||
return redirect("/unsafe\ntest-header: test-value\n\ntest-body")
|
return redirect("/unsafe\ntest-header: test-value\n\ntest-body")
|
||||||
|
|
||||||
|
@ -43,19 +42,18 @@ def test_redirect_default_302(redirect_app):
|
||||||
We expect a 302 default status code and the headers to be set.
|
We expect a 302 default status code and the headers to be set.
|
||||||
"""
|
"""
|
||||||
request, response = redirect_app.test_client.get(
|
request, response = redirect_app.test_client.get(
|
||||||
'/redirect_init',
|
"/redirect_init", allow_redirects=False
|
||||||
allow_redirects=False)
|
)
|
||||||
|
|
||||||
assert response.status == 302
|
assert response.status == 302
|
||||||
assert response.headers["Location"] == "/redirect_target"
|
assert response.headers["Location"] == "/redirect_target"
|
||||||
assert response.headers["Content-Type"] == 'text/html; charset=utf-8'
|
assert response.headers["Content-Type"] == "text/html; charset=utf-8"
|
||||||
|
|
||||||
|
|
||||||
def test_redirect_headers_none(redirect_app):
|
def test_redirect_headers_none(redirect_app):
|
||||||
request, response = redirect_app.test_client.get(
|
request, response = redirect_app.test_client.get(
|
||||||
uri="/redirect_init",
|
uri="/redirect_init", headers=None, allow_redirects=False
|
||||||
headers=None,
|
)
|
||||||
allow_redirects=False)
|
|
||||||
|
|
||||||
assert response.status == 302
|
assert response.status == 302
|
||||||
assert response.headers["Location"] == "/redirect_target"
|
assert response.headers["Location"] == "/redirect_target"
|
||||||
|
@ -66,8 +64,8 @@ def test_redirect_with_301(redirect_app):
|
||||||
Test redirection with a different status code.
|
Test redirection with a different status code.
|
||||||
"""
|
"""
|
||||||
request, response = redirect_app.test_client.get(
|
request, response = redirect_app.test_client.get(
|
||||||
"/redirect_init_with_301",
|
"/redirect_init_with_301", allow_redirects=False
|
||||||
allow_redirects=False)
|
)
|
||||||
|
|
||||||
assert response.status == 301
|
assert response.status == 301
|
||||||
assert response.headers["Location"] == "/redirect_target"
|
assert response.headers["Location"] == "/redirect_target"
|
||||||
|
@ -78,23 +76,23 @@ def test_get_then_redirect_follow_redirect(redirect_app):
|
||||||
With `allow_redirects` we expect a 200.
|
With `allow_redirects` we expect a 200.
|
||||||
"""
|
"""
|
||||||
request, response = redirect_app.test_client.get(
|
request, response = redirect_app.test_client.get(
|
||||||
"/redirect_init",
|
"/redirect_init", allow_redirects=True
|
||||||
allow_redirects=True)
|
)
|
||||||
|
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == 'OK'
|
assert response.text == "OK"
|
||||||
|
|
||||||
|
|
||||||
def test_chained_redirect(redirect_app):
|
def test_chained_redirect(redirect_app):
|
||||||
"""Test test_client is working for redirection"""
|
"""Test test_client is working for redirection"""
|
||||||
request, response = redirect_app.test_client.get('/1')
|
request, response = redirect_app.test_client.get("/1")
|
||||||
assert request.url.endswith('/1')
|
assert request.url.endswith("/1")
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == 'OK'
|
assert response.text == "OK"
|
||||||
try:
|
try:
|
||||||
assert response.url.endswith('/3')
|
assert response.url.endswith("/3")
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
assert response.url.path.endswith('/3')
|
assert response.url.path.endswith("/3")
|
||||||
|
|
||||||
|
|
||||||
def test_redirect_with_header_injection(redirect_app):
|
def test_redirect_with_header_injection(redirect_app):
|
||||||
|
@ -102,17 +100,16 @@ def test_redirect_with_header_injection(redirect_app):
|
||||||
Test redirection to a URL with header and body injections.
|
Test redirection to a URL with header and body injections.
|
||||||
"""
|
"""
|
||||||
request, response = redirect_app.test_client.get(
|
request, response = redirect_app.test_client.get(
|
||||||
"/redirect_with_header_injection",
|
"/redirect_with_header_injection", allow_redirects=False
|
||||||
allow_redirects=False)
|
)
|
||||||
|
|
||||||
assert response.status == 302
|
assert response.status == 302
|
||||||
assert "test-header" not in response.headers
|
assert "test-header" not in response.headers
|
||||||
assert not response.text.startswith('test-body')
|
assert not response.text.startswith("test-body")
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("test_str", ["sanic-test", "sanictest", "sanic test"])
|
@pytest.mark.parametrize("test_str", ["sanic-test", "sanictest", "sanic test"])
|
||||||
async def test_redirect_with_params(app, test_client, test_str):
|
async def test_redirect_with_params(app, test_client, test_str):
|
||||||
|
|
||||||
@app.route("/api/v1/test/<test>/")
|
@app.route("/api/v1/test/<test>/")
|
||||||
async def init_handler(request, test):
|
async def init_handler(request, test):
|
||||||
assert test == test_str
|
assert test == test_str
|
||||||
|
|
|
@ -7,17 +7,17 @@ from sanic.response import text, stream
|
||||||
async def test_request_cancel_when_connection_lost(loop, app, test_client):
|
async def test_request_cancel_when_connection_lost(loop, app, test_client):
|
||||||
app.still_serving_cancelled_request = False
|
app.still_serving_cancelled_request = False
|
||||||
|
|
||||||
@app.get('/')
|
@app.get("/")
|
||||||
async def handler(request):
|
async def handler(request):
|
||||||
await asyncio.sleep(1.0)
|
await asyncio.sleep(1.0)
|
||||||
# at this point client is already disconnected
|
# at this point client is already disconnected
|
||||||
app.still_serving_cancelled_request = True
|
app.still_serving_cancelled_request = True
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
test_cli = await test_client(app)
|
test_cli = await test_client(app)
|
||||||
|
|
||||||
# schedule client call
|
# schedule client call
|
||||||
task = loop.create_task(test_cli.get('/'))
|
task = loop.create_task(test_cli.get("/"))
|
||||||
loop.call_later(0.01, task)
|
loop.call_later(0.01, task)
|
||||||
await asyncio.sleep(0.5)
|
await asyncio.sleep(0.5)
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ async def test_request_cancel_when_connection_lost(loop, app, test_client):
|
||||||
async def test_stream_request_cancel_when_conn_lost(loop, app, test_client):
|
async def test_stream_request_cancel_when_conn_lost(loop, app, test_client):
|
||||||
app.still_serving_cancelled_request = False
|
app.still_serving_cancelled_request = False
|
||||||
|
|
||||||
@app.post('/post/<id>', stream=True)
|
@app.post("/post/<id>", stream=True)
|
||||||
async def post(request, id):
|
async def post(request, id):
|
||||||
assert isinstance(request.stream, asyncio.Queue)
|
assert isinstance(request.stream, asyncio.Queue)
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ async def test_stream_request_cancel_when_conn_lost(loop, app, test_client):
|
||||||
body = await request.stream.get()
|
body = await request.stream.get()
|
||||||
if body is None:
|
if body is None:
|
||||||
break
|
break
|
||||||
await response.write(body.decode('utf-8'))
|
await response.write(body.decode("utf-8"))
|
||||||
|
|
||||||
await asyncio.sleep(1.0)
|
await asyncio.sleep(1.0)
|
||||||
# at this point client is already disconnected
|
# at this point client is already disconnected
|
||||||
|
@ -56,7 +56,7 @@ async def test_stream_request_cancel_when_conn_lost(loop, app, test_client):
|
||||||
test_cli = await test_client(app)
|
test_cli = await test_client(app)
|
||||||
|
|
||||||
# schedule client call
|
# schedule client call
|
||||||
task = loop.create_task(test_cli.post('/post/1'))
|
task = loop.create_task(test_cli.post("/post/1"))
|
||||||
loop.call_later(0.01, task)
|
loop.call_later(0.01, task)
|
||||||
await asyncio.sleep(0.5)
|
await asyncio.sleep(0.5)
|
||||||
|
|
||||||
|
|
|
@ -9,39 +9,37 @@ except ImportError:
|
||||||
|
|
||||||
|
|
||||||
def test_storage(app):
|
def test_storage(app):
|
||||||
|
@app.middleware("request")
|
||||||
@app.middleware('request')
|
|
||||||
def store(request):
|
def store(request):
|
||||||
request['user'] = 'sanic'
|
request["user"] = "sanic"
|
||||||
request['sidekick'] = 'tails'
|
request["sidekick"] = "tails"
|
||||||
del request['sidekick']
|
del request["sidekick"]
|
||||||
|
|
||||||
@app.route('/')
|
@app.route("/")
|
||||||
def handler(request):
|
def handler(request):
|
||||||
return json({
|
return json(
|
||||||
'user': request.get('user'),
|
{"user": request.get("user"), "sidekick": request.get("sidekick")}
|
||||||
'sidekick': request.get('sidekick')
|
)
|
||||||
})
|
|
||||||
|
|
||||||
request, response = app.test_client.get('/')
|
request, response = app.test_client.get("/")
|
||||||
|
|
||||||
response_json = loads(response.text)
|
response_json = loads(response.text)
|
||||||
assert response_json['user'] == 'sanic'
|
assert response_json["user"] == "sanic"
|
||||||
assert response_json.get('sidekick') is None
|
assert response_json.get("sidekick") is None
|
||||||
|
|
||||||
|
|
||||||
def test_app_injection(app):
|
def test_app_injection(app):
|
||||||
expected = random.choice(range(0, 100))
|
expected = random.choice(range(0, 100))
|
||||||
|
|
||||||
@app.listener('after_server_start')
|
@app.listener("after_server_start")
|
||||||
async def inject_data(app, loop):
|
async def inject_data(app, loop):
|
||||||
app.injected = expected
|
app.injected = expected
|
||||||
|
|
||||||
@app.get('/')
|
@app.get("/")
|
||||||
async def handler(request):
|
async def handler(request):
|
||||||
return json({'injected': request.app.injected})
|
return json({"injected": request.app.injected})
|
||||||
|
|
||||||
request, response = app.test_client.get('/')
|
request, response = app.test_client.get("/")
|
||||||
|
|
||||||
response_json = loads(response.text)
|
response_json = loads(response.text)
|
||||||
assert response_json['injected'] == expected
|
assert response_json["injected"] == expected
|
||||||
|
|
|
@ -11,67 +11,66 @@ data = "abc" * 10000000
|
||||||
|
|
||||||
|
|
||||||
def test_request_stream_method_view(app):
|
def test_request_stream_method_view(app):
|
||||||
'''for self.is_request_stream = True'''
|
"""for self.is_request_stream = True"""
|
||||||
|
|
||||||
class SimpleView(HTTPMethodView):
|
class SimpleView(HTTPMethodView):
|
||||||
|
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
assert request.stream is None
|
assert request.stream is None
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
@stream_decorator
|
@stream_decorator
|
||||||
async def post(self, request):
|
async def post(self, request):
|
||||||
assert isinstance(request.stream, StreamBuffer)
|
assert isinstance(request.stream, StreamBuffer)
|
||||||
result = ''
|
result = ""
|
||||||
while True:
|
while True:
|
||||||
body = await request.stream.read()
|
body = await request.stream.read()
|
||||||
if body is None:
|
if body is None:
|
||||||
break
|
break
|
||||||
result += body.decode('utf-8')
|
result += body.decode("utf-8")
|
||||||
return text(result)
|
return text(result)
|
||||||
|
|
||||||
app.add_route(SimpleView.as_view(), '/method_view')
|
app.add_route(SimpleView.as_view(), "/method_view")
|
||||||
|
|
||||||
assert app.is_request_stream is True
|
assert app.is_request_stream is True
|
||||||
|
|
||||||
request, response = app.test_client.get('/method_view')
|
request, response = app.test_client.get("/method_view")
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == 'OK'
|
assert response.text == "OK"
|
||||||
|
|
||||||
request, response = app.test_client.post('/method_view', data=data)
|
request, response = app.test_client.post("/method_view", data=data)
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == data
|
assert response.text == data
|
||||||
|
|
||||||
|
|
||||||
def test_request_stream_app(app):
|
def test_request_stream_app(app):
|
||||||
'''for self.is_request_stream = True and decorators'''
|
"""for self.is_request_stream = True and decorators"""
|
||||||
|
|
||||||
@app.get('/get')
|
@app.get("/get")
|
||||||
async def get(request):
|
async def get(request):
|
||||||
assert request.stream is None
|
assert request.stream is None
|
||||||
return text('GET')
|
return text("GET")
|
||||||
|
|
||||||
@app.head('/head')
|
@app.head("/head")
|
||||||
async def head(request):
|
async def head(request):
|
||||||
assert request.stream is None
|
assert request.stream is None
|
||||||
return text('HEAD')
|
return text("HEAD")
|
||||||
|
|
||||||
@app.delete('/delete')
|
@app.delete("/delete")
|
||||||
async def delete(request):
|
async def delete(request):
|
||||||
assert request.stream is None
|
assert request.stream is None
|
||||||
return text('DELETE')
|
return text("DELETE")
|
||||||
|
|
||||||
@app.options('/options')
|
@app.options("/options")
|
||||||
async def options(request):
|
async def options(request):
|
||||||
assert request.stream is None
|
assert request.stream is None
|
||||||
return text('OPTIONS')
|
return text("OPTIONS")
|
||||||
|
|
||||||
@app.post('/_post/<id>')
|
@app.post("/_post/<id>")
|
||||||
async def _post(request, id):
|
async def _post(request, id):
|
||||||
assert request.stream is None
|
assert request.stream is None
|
||||||
return text('_POST')
|
return text("_POST")
|
||||||
|
|
||||||
@app.post('/post/<id>', stream=True)
|
@app.post("/post/<id>", stream=True)
|
||||||
async def post(request, id):
|
async def post(request, id):
|
||||||
assert isinstance(request.stream, StreamBuffer)
|
assert isinstance(request.stream, StreamBuffer)
|
||||||
|
|
||||||
|
@ -80,15 +79,16 @@ def test_request_stream_app(app):
|
||||||
body = await request.stream.read()
|
body = await request.stream.read()
|
||||||
if body is None:
|
if body is None:
|
||||||
break
|
break
|
||||||
await response.write(body.decode('utf-8'))
|
await response.write(body.decode("utf-8"))
|
||||||
|
|
||||||
return stream(streaming)
|
return stream(streaming)
|
||||||
|
|
||||||
@app.put('/_put')
|
@app.put("/_put")
|
||||||
async def _put(request):
|
async def _put(request):
|
||||||
assert request.stream is None
|
assert request.stream is None
|
||||||
return text('_PUT')
|
return text("_PUT")
|
||||||
|
|
||||||
@app.put('/put', stream=True)
|
@app.put("/put", stream=True)
|
||||||
async def put(request):
|
async def put(request):
|
||||||
assert isinstance(request.stream, StreamBuffer)
|
assert isinstance(request.stream, StreamBuffer)
|
||||||
|
|
||||||
|
@ -97,15 +97,16 @@ def test_request_stream_app(app):
|
||||||
body = await request.stream.read()
|
body = await request.stream.read()
|
||||||
if body is None:
|
if body is None:
|
||||||
break
|
break
|
||||||
await response.write(body.decode('utf-8'))
|
await response.write(body.decode("utf-8"))
|
||||||
|
|
||||||
return stream(streaming)
|
return stream(streaming)
|
||||||
|
|
||||||
@app.patch('/_patch')
|
@app.patch("/_patch")
|
||||||
async def _patch(request):
|
async def _patch(request):
|
||||||
assert request.stream is None
|
assert request.stream is None
|
||||||
return text('_PATCH')
|
return text("_PATCH")
|
||||||
|
|
||||||
@app.patch('/patch', stream=True)
|
@app.patch("/patch", stream=True)
|
||||||
async def patch(request):
|
async def patch(request):
|
||||||
assert isinstance(request.stream, StreamBuffer)
|
assert isinstance(request.stream, StreamBuffer)
|
||||||
|
|
||||||
|
@ -114,56 +115,57 @@ def test_request_stream_app(app):
|
||||||
body = await request.stream.read()
|
body = await request.stream.read()
|
||||||
if body is None:
|
if body is None:
|
||||||
break
|
break
|
||||||
await response.write(body.decode('utf-8'))
|
await response.write(body.decode("utf-8"))
|
||||||
|
|
||||||
return stream(streaming)
|
return stream(streaming)
|
||||||
|
|
||||||
assert app.is_request_stream is True
|
assert app.is_request_stream is True
|
||||||
|
|
||||||
request, response = app.test_client.get('/get')
|
request, response = app.test_client.get("/get")
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == 'GET'
|
assert response.text == "GET"
|
||||||
|
|
||||||
request, response = app.test_client.head('/head')
|
request, response = app.test_client.head("/head")
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == ''
|
assert response.text == ""
|
||||||
|
|
||||||
request, response = app.test_client.delete('/delete')
|
request, response = app.test_client.delete("/delete")
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == 'DELETE'
|
assert response.text == "DELETE"
|
||||||
|
|
||||||
request, response = app.test_client.options('/options')
|
request, response = app.test_client.options("/options")
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == 'OPTIONS'
|
assert response.text == "OPTIONS"
|
||||||
|
|
||||||
request, response = app.test_client.post('/_post/1', data=data)
|
request, response = app.test_client.post("/_post/1", data=data)
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == '_POST'
|
assert response.text == "_POST"
|
||||||
|
|
||||||
request, response = app.test_client.post('/post/1', data=data)
|
request, response = app.test_client.post("/post/1", data=data)
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == data
|
assert response.text == data
|
||||||
|
|
||||||
request, response = app.test_client.put('/_put', data=data)
|
request, response = app.test_client.put("/_put", data=data)
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == '_PUT'
|
assert response.text == "_PUT"
|
||||||
|
|
||||||
request, response = app.test_client.put('/put', data=data)
|
request, response = app.test_client.put("/put", data=data)
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == data
|
assert response.text == data
|
||||||
|
|
||||||
request, response = app.test_client.patch('/_patch', data=data)
|
request, response = app.test_client.patch("/_patch", data=data)
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == '_PATCH'
|
assert response.text == "_PATCH"
|
||||||
|
|
||||||
request, response = app.test_client.patch('/patch', data=data)
|
request, response = app.test_client.patch("/patch", data=data)
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == data
|
assert response.text == data
|
||||||
|
|
||||||
|
|
||||||
def test_request_stream_handle_exception(app):
|
def test_request_stream_handle_exception(app):
|
||||||
'''for handling exceptions properly'''
|
"""for handling exceptions properly"""
|
||||||
|
|
||||||
@app.post('/post/<id>', stream=True)
|
@app.post("/post/<id>", stream=True)
|
||||||
async def post(request, id):
|
async def post(request, id):
|
||||||
assert isinstance(request.stream, StreamBuffer)
|
assert isinstance(request.stream, StreamBuffer)
|
||||||
|
|
||||||
|
@ -172,51 +174,54 @@ def test_request_stream_handle_exception(app):
|
||||||
body = await request.stream.read()
|
body = await request.stream.read()
|
||||||
if body is None:
|
if body is None:
|
||||||
break
|
break
|
||||||
await response.write(body.decode('utf-8'))
|
await response.write(body.decode("utf-8"))
|
||||||
|
|
||||||
return stream(streaming)
|
return stream(streaming)
|
||||||
|
|
||||||
# 404
|
# 404
|
||||||
request, response = app.test_client.post('/in_valid_post', data=data)
|
request, response = app.test_client.post("/in_valid_post", data=data)
|
||||||
assert response.status == 404
|
assert response.status == 404
|
||||||
assert response.text == 'Error: Requested URL /in_valid_post not found'
|
assert response.text == "Error: Requested URL /in_valid_post not found"
|
||||||
|
|
||||||
# 405
|
# 405
|
||||||
request, response = app.test_client.get('/post/random_id', data=data)
|
request, response = app.test_client.get("/post/random_id", data=data)
|
||||||
assert response.status == 405
|
assert response.status == 405
|
||||||
assert response.text == 'Error: Method GET not allowed for URL' \
|
assert (
|
||||||
' /post/random_id'
|
response.text == "Error: Method GET not allowed for URL"
|
||||||
|
" /post/random_id"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_request_stream_blueprint(app):
|
def test_request_stream_blueprint(app):
|
||||||
'''for self.is_request_stream = True'''
|
"""for self.is_request_stream = True"""
|
||||||
bp = Blueprint('test_blueprint_request_stream_blueprint')
|
bp = Blueprint("test_blueprint_request_stream_blueprint")
|
||||||
|
|
||||||
@app.get('/get')
|
@app.get("/get")
|
||||||
async def get(request):
|
async def get(request):
|
||||||
assert request.stream is None
|
assert request.stream is None
|
||||||
return text('GET')
|
return text("GET")
|
||||||
|
|
||||||
@bp.head('/head')
|
@bp.head("/head")
|
||||||
async def head(request):
|
async def head(request):
|
||||||
assert request.stream is None
|
assert request.stream is None
|
||||||
return text('HEAD')
|
return text("HEAD")
|
||||||
|
|
||||||
@bp.delete('/delete')
|
@bp.delete("/delete")
|
||||||
async def delete(request):
|
async def delete(request):
|
||||||
assert request.stream is None
|
assert request.stream is None
|
||||||
return text('DELETE')
|
return text("DELETE")
|
||||||
|
|
||||||
@bp.options('/options')
|
@bp.options("/options")
|
||||||
async def options(request):
|
async def options(request):
|
||||||
assert request.stream is None
|
assert request.stream is None
|
||||||
return text('OPTIONS')
|
return text("OPTIONS")
|
||||||
|
|
||||||
@bp.post('/_post/<id>')
|
@bp.post("/_post/<id>")
|
||||||
async def _post(request, id):
|
async def _post(request, id):
|
||||||
assert request.stream is None
|
assert request.stream is None
|
||||||
return text('_POST')
|
return text("_POST")
|
||||||
|
|
||||||
@bp.post('/post/<id>', stream=True)
|
@bp.post("/post/<id>", stream=True)
|
||||||
async def post(request, id):
|
async def post(request, id):
|
||||||
assert isinstance(request.stream, StreamBuffer)
|
assert isinstance(request.stream, StreamBuffer)
|
||||||
|
|
||||||
|
@ -225,15 +230,16 @@ def test_request_stream_blueprint(app):
|
||||||
body = await request.stream.read()
|
body = await request.stream.read()
|
||||||
if body is None:
|
if body is None:
|
||||||
break
|
break
|
||||||
await response.write(body.decode('utf-8'))
|
await response.write(body.decode("utf-8"))
|
||||||
|
|
||||||
return stream(streaming)
|
return stream(streaming)
|
||||||
|
|
||||||
@bp.put('/_put')
|
@bp.put("/_put")
|
||||||
async def _put(request):
|
async def _put(request):
|
||||||
assert request.stream is None
|
assert request.stream is None
|
||||||
return text('_PUT')
|
return text("_PUT")
|
||||||
|
|
||||||
@bp.put('/put', stream=True)
|
@bp.put("/put", stream=True)
|
||||||
async def put(request):
|
async def put(request):
|
||||||
assert isinstance(request.stream, StreamBuffer)
|
assert isinstance(request.stream, StreamBuffer)
|
||||||
|
|
||||||
|
@ -242,15 +248,16 @@ def test_request_stream_blueprint(app):
|
||||||
body = await request.stream.read()
|
body = await request.stream.read()
|
||||||
if body is None:
|
if body is None:
|
||||||
break
|
break
|
||||||
await response.write(body.decode('utf-8'))
|
await response.write(body.decode("utf-8"))
|
||||||
|
|
||||||
return stream(streaming)
|
return stream(streaming)
|
||||||
|
|
||||||
@bp.patch('/_patch')
|
@bp.patch("/_patch")
|
||||||
async def _patch(request):
|
async def _patch(request):
|
||||||
assert request.stream is None
|
assert request.stream is None
|
||||||
return text('_PATCH')
|
return text("_PATCH")
|
||||||
|
|
||||||
@bp.patch('/patch', stream=True)
|
@bp.patch("/patch", stream=True)
|
||||||
async def patch(request):
|
async def patch(request):
|
||||||
assert isinstance(request.stream, StreamBuffer)
|
assert isinstance(request.stream, StreamBuffer)
|
||||||
|
|
||||||
|
@ -259,109 +266,109 @@ def test_request_stream_blueprint(app):
|
||||||
body = await request.stream.read()
|
body = await request.stream.read()
|
||||||
if body is None:
|
if body is None:
|
||||||
break
|
break
|
||||||
await response.write(body.decode('utf-8'))
|
await response.write(body.decode("utf-8"))
|
||||||
|
|
||||||
return stream(streaming)
|
return stream(streaming)
|
||||||
|
|
||||||
app.blueprint(bp)
|
app.blueprint(bp)
|
||||||
|
|
||||||
assert app.is_request_stream is True
|
assert app.is_request_stream is True
|
||||||
|
|
||||||
request, response = app.test_client.get('/get')
|
request, response = app.test_client.get("/get")
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == 'GET'
|
assert response.text == "GET"
|
||||||
|
|
||||||
request, response = app.test_client.head('/head')
|
request, response = app.test_client.head("/head")
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == ''
|
assert response.text == ""
|
||||||
|
|
||||||
request, response = app.test_client.delete('/delete')
|
request, response = app.test_client.delete("/delete")
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == 'DELETE'
|
assert response.text == "DELETE"
|
||||||
|
|
||||||
request, response = app.test_client.options('/options')
|
request, response = app.test_client.options("/options")
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == 'OPTIONS'
|
assert response.text == "OPTIONS"
|
||||||
|
|
||||||
request, response = app.test_client.post('/_post/1', data=data)
|
request, response = app.test_client.post("/_post/1", data=data)
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == '_POST'
|
assert response.text == "_POST"
|
||||||
|
|
||||||
request, response = app.test_client.post('/post/1', data=data)
|
request, response = app.test_client.post("/post/1", data=data)
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == data
|
assert response.text == data
|
||||||
|
|
||||||
request, response = app.test_client.put('/_put', data=data)
|
request, response = app.test_client.put("/_put", data=data)
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == '_PUT'
|
assert response.text == "_PUT"
|
||||||
|
|
||||||
request, response = app.test_client.put('/put', data=data)
|
request, response = app.test_client.put("/put", data=data)
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == data
|
assert response.text == data
|
||||||
|
|
||||||
request, response = app.test_client.patch('/_patch', data=data)
|
request, response = app.test_client.patch("/_patch", data=data)
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == '_PATCH'
|
assert response.text == "_PATCH"
|
||||||
|
|
||||||
request, response = app.test_client.patch('/patch', data=data)
|
request, response = app.test_client.patch("/patch", data=data)
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == data
|
assert response.text == data
|
||||||
|
|
||||||
|
|
||||||
def test_request_stream_composition_view(app):
|
def test_request_stream_composition_view(app):
|
||||||
'''for self.is_request_stream = True'''
|
"""for self.is_request_stream = True"""
|
||||||
|
|
||||||
def get_handler(request):
|
def get_handler(request):
|
||||||
assert request.stream is None
|
assert request.stream is None
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
async def post_handler(request):
|
async def post_handler(request):
|
||||||
assert isinstance(request.stream, StreamBuffer)
|
assert isinstance(request.stream, StreamBuffer)
|
||||||
result = ''
|
result = ""
|
||||||
while True:
|
while True:
|
||||||
body = await request.stream.read()
|
body = await request.stream.read()
|
||||||
if body is None:
|
if body is None:
|
||||||
break
|
break
|
||||||
result += body.decode('utf-8')
|
result += body.decode("utf-8")
|
||||||
return text(result)
|
return text(result)
|
||||||
|
|
||||||
view = CompositionView()
|
view = CompositionView()
|
||||||
view.add(['GET'], get_handler)
|
view.add(["GET"], get_handler)
|
||||||
view.add(['POST'], post_handler, stream=True)
|
view.add(["POST"], post_handler, stream=True)
|
||||||
app.add_route(view, '/composition_view')
|
app.add_route(view, "/composition_view")
|
||||||
|
|
||||||
assert app.is_request_stream is True
|
assert app.is_request_stream is True
|
||||||
|
|
||||||
request, response = app.test_client.get('/composition_view')
|
request, response = app.test_client.get("/composition_view")
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == 'OK'
|
assert response.text == "OK"
|
||||||
|
|
||||||
request, response = app.test_client.post('/composition_view', data=data)
|
request, response = app.test_client.post("/composition_view", data=data)
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == data
|
assert response.text == data
|
||||||
|
|
||||||
|
|
||||||
def test_request_stream(app):
|
def test_request_stream(app):
|
||||||
'''test for complex application'''
|
"""test for complex application"""
|
||||||
bp = Blueprint('test_blueprint_request_stream')
|
bp = Blueprint("test_blueprint_request_stream")
|
||||||
|
|
||||||
class SimpleView(HTTPMethodView):
|
class SimpleView(HTTPMethodView):
|
||||||
|
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
assert request.stream is None
|
assert request.stream is None
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
@stream_decorator
|
@stream_decorator
|
||||||
async def post(self, request):
|
async def post(self, request):
|
||||||
assert isinstance(request.stream, StreamBuffer)
|
assert isinstance(request.stream, StreamBuffer)
|
||||||
result = ''
|
result = ""
|
||||||
while True:
|
while True:
|
||||||
body = await request.stream.read()
|
body = await request.stream.read()
|
||||||
if body is None:
|
if body is None:
|
||||||
break
|
break
|
||||||
result += body.decode('utf-8')
|
result += body.decode("utf-8")
|
||||||
return text(result)
|
return text(result)
|
||||||
|
|
||||||
@app.post('/stream', stream=True)
|
@app.post("/stream", stream=True)
|
||||||
async def handler(request):
|
async def handler(request):
|
||||||
assert isinstance(request.stream, StreamBuffer)
|
assert isinstance(request.stream, StreamBuffer)
|
||||||
|
|
||||||
|
@ -370,84 +377,85 @@ def test_request_stream(app):
|
||||||
body = await request.stream.read()
|
body = await request.stream.read()
|
||||||
if body is None:
|
if body is None:
|
||||||
break
|
break
|
||||||
await response.write(body.decode('utf-8'))
|
await response.write(body.decode("utf-8"))
|
||||||
|
|
||||||
return stream(streaming)
|
return stream(streaming)
|
||||||
|
|
||||||
@app.get('/get')
|
@app.get("/get")
|
||||||
async def get(request):
|
async def get(request):
|
||||||
assert request.stream is None
|
assert request.stream is None
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
@bp.post('/bp_stream', stream=True)
|
@bp.post("/bp_stream", stream=True)
|
||||||
async def bp_stream(request):
|
async def bp_stream(request):
|
||||||
assert isinstance(request.stream, StreamBuffer)
|
assert isinstance(request.stream, StreamBuffer)
|
||||||
result = ''
|
result = ""
|
||||||
while True:
|
while True:
|
||||||
body = await request.stream.read()
|
body = await request.stream.read()
|
||||||
if body is None:
|
if body is None:
|
||||||
break
|
break
|
||||||
result += body.decode('utf-8')
|
result += body.decode("utf-8")
|
||||||
return text(result)
|
return text(result)
|
||||||
|
|
||||||
@bp.get('/bp_get')
|
@bp.get("/bp_get")
|
||||||
async def bp_get(request):
|
async def bp_get(request):
|
||||||
assert request.stream is None
|
assert request.stream is None
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
def get_handler(request):
|
def get_handler(request):
|
||||||
assert request.stream is None
|
assert request.stream is None
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
async def post_handler(request):
|
async def post_handler(request):
|
||||||
assert isinstance(request.stream, StreamBuffer)
|
assert isinstance(request.stream, StreamBuffer)
|
||||||
result = ''
|
result = ""
|
||||||
while True:
|
while True:
|
||||||
body = await request.stream.read()
|
body = await request.stream.read()
|
||||||
if body is None:
|
if body is None:
|
||||||
break
|
break
|
||||||
result += body.decode('utf-8')
|
result += body.decode("utf-8")
|
||||||
return text(result)
|
return text(result)
|
||||||
|
|
||||||
app.add_route(SimpleView.as_view(), '/method_view')
|
app.add_route(SimpleView.as_view(), "/method_view")
|
||||||
|
|
||||||
view = CompositionView()
|
view = CompositionView()
|
||||||
view.add(['GET'], get_handler)
|
view.add(["GET"], get_handler)
|
||||||
view.add(['POST'], post_handler, stream=True)
|
view.add(["POST"], post_handler, stream=True)
|
||||||
|
|
||||||
app.blueprint(bp)
|
app.blueprint(bp)
|
||||||
|
|
||||||
app.add_route(view, '/composition_view')
|
app.add_route(view, "/composition_view")
|
||||||
|
|
||||||
assert app.is_request_stream is True
|
assert app.is_request_stream is True
|
||||||
|
|
||||||
request, response = app.test_client.get('/method_view')
|
request, response = app.test_client.get("/method_view")
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == 'OK'
|
assert response.text == "OK"
|
||||||
|
|
||||||
request, response = app.test_client.post('/method_view', data=data)
|
request, response = app.test_client.post("/method_view", data=data)
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == data
|
assert response.text == data
|
||||||
|
|
||||||
request, response = app.test_client.get('/composition_view')
|
request, response = app.test_client.get("/composition_view")
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == 'OK'
|
assert response.text == "OK"
|
||||||
|
|
||||||
request, response = app.test_client.post('/composition_view', data=data)
|
request, response = app.test_client.post("/composition_view", data=data)
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == data
|
assert response.text == data
|
||||||
|
|
||||||
request, response = app.test_client.get('/get')
|
request, response = app.test_client.get("/get")
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == 'OK'
|
assert response.text == "OK"
|
||||||
|
|
||||||
request, response = app.test_client.post('/stream', data=data)
|
request, response = app.test_client.post("/stream", data=data)
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == data
|
assert response.text == data
|
||||||
|
|
||||||
request, response = app.test_client.get('/bp_get')
|
request, response = app.test_client.get("/bp_get")
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == 'OK'
|
assert response.text == "OK"
|
||||||
|
|
||||||
request, response = app.test_client.post('/bp_stream', data=data)
|
request, response = app.test_client.post("/bp_stream", data=data)
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == data
|
assert response.text == data
|
||||||
|
|
|
@ -12,6 +12,7 @@ try:
|
||||||
try:
|
try:
|
||||||
# direct use
|
# direct use
|
||||||
import packaging
|
import packaging
|
||||||
|
|
||||||
version = packaging.version
|
version = packaging.version
|
||||||
except (ImportError, AttributeError):
|
except (ImportError, AttributeError):
|
||||||
# setuptools v39.0 and above.
|
# setuptools v39.0 and above.
|
||||||
|
@ -29,15 +30,15 @@ aiohttp_version = version.parse(aiohttp.__version__)
|
||||||
|
|
||||||
|
|
||||||
class DelayableTCPConnector(TCPConnector):
|
class DelayableTCPConnector(TCPConnector):
|
||||||
|
|
||||||
class RequestContextManager(object):
|
class RequestContextManager(object):
|
||||||
def __new__(cls, req, delay):
|
def __new__(cls, req, delay):
|
||||||
cls = super(DelayableTCPConnector.RequestContextManager, cls).\
|
cls = super(
|
||||||
__new__(cls)
|
DelayableTCPConnector.RequestContextManager, cls
|
||||||
|
).__new__(cls)
|
||||||
cls.req = req
|
cls.req = req
|
||||||
cls.send_task = None
|
cls.send_task = None
|
||||||
cls.resp = None
|
cls.resp = None
|
||||||
cls.orig_send = getattr(req, 'send')
|
cls.orig_send = getattr(req, "send")
|
||||||
cls.orig_start = None
|
cls.orig_start = None
|
||||||
cls.delay = delay
|
cls.delay = delay
|
||||||
cls._acting_as = req
|
cls._acting_as = req
|
||||||
|
@ -54,7 +55,7 @@ class DelayableTCPConnector(TCPConnector):
|
||||||
self.send_task = None
|
self.send_task = None
|
||||||
self.resp = resp
|
self.resp = resp
|
||||||
self._acting_as = self.resp
|
self._acting_as = self.resp
|
||||||
self.orig_start = getattr(resp, 'start')
|
self.orig_start = getattr(resp, "start")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if aiohttp_version >= version.parse("3.3.0"):
|
if aiohttp_version >= version.parse("3.3.0"):
|
||||||
|
@ -92,10 +93,10 @@ class DelayableTCPConnector(TCPConnector):
|
||||||
request_info=None,
|
request_info=None,
|
||||||
traces=[],
|
traces=[],
|
||||||
loop=req.loop,
|
loop=req.loop,
|
||||||
session=None
|
session=None,
|
||||||
)
|
)
|
||||||
if aiohttp_version < version.parse("3.3.0"):
|
if aiohttp_version < version.parse("3.3.0"):
|
||||||
kw['auto_decompress'] = None
|
kw["auto_decompress"] = None
|
||||||
return aiohttp.ClientResponse(req.method, req.url, **kw)
|
return aiohttp.ClientResponse(req.method, req.url, **kw)
|
||||||
|
|
||||||
def _send(self, *args, **kwargs):
|
def _send(self, *args, **kwargs):
|
||||||
|
@ -109,24 +110,26 @@ class DelayableTCPConnector(TCPConnector):
|
||||||
# aiohttp changed the request.send method to async
|
# aiohttp changed the request.send method to async
|
||||||
async def send(self, *args, **kwargs):
|
async def send(self, *args, **kwargs):
|
||||||
return self._send(*args, **kwargs)
|
return self._send(*args, **kwargs)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
send = _send
|
send = _send
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
_post_connect_delay = kwargs.pop('post_connect_delay', 0)
|
_post_connect_delay = kwargs.pop("post_connect_delay", 0)
|
||||||
_pre_request_delay = kwargs.pop('pre_request_delay', 0)
|
_pre_request_delay = kwargs.pop("pre_request_delay", 0)
|
||||||
super(DelayableTCPConnector, self).__init__(*args, **kwargs)
|
super(DelayableTCPConnector, self).__init__(*args, **kwargs)
|
||||||
self._post_connect_delay = _post_connect_delay
|
self._post_connect_delay = _post_connect_delay
|
||||||
self._pre_request_delay = _pre_request_delay
|
self._pre_request_delay = _pre_request_delay
|
||||||
|
|
||||||
async def connect(self, req, *args, **kwargs):
|
async def connect(self, req, *args, **kwargs):
|
||||||
d_req = DelayableTCPConnector.\
|
d_req = DelayableTCPConnector.RequestContextManager(
|
||||||
RequestContextManager(req, self._pre_request_delay)
|
req, self._pre_request_delay
|
||||||
conn = await super(DelayableTCPConnector, self).\
|
)
|
||||||
connect(req, *args, **kwargs)
|
conn = await super(DelayableTCPConnector, self).connect(
|
||||||
|
req, *args, **kwargs
|
||||||
|
)
|
||||||
if self._post_connect_delay and self._post_connect_delay > 0:
|
if self._post_connect_delay and self._post_connect_delay > 0:
|
||||||
await asyncio.sleep(self._post_connect_delay,
|
await asyncio.sleep(self._post_connect_delay, loop=self._loop)
|
||||||
loop=self._loop)
|
|
||||||
req.send = d_req.send
|
req.send = d_req.send
|
||||||
t = req.loop.time()
|
t = req.loop.time()
|
||||||
print("Connected at {}".format(t), flush=True)
|
print("Connected at {}".format(t), flush=True)
|
||||||
|
@ -139,24 +142,29 @@ class DelayableSanicTestClient(SanicTestClient):
|
||||||
self._request_delay = request_delay
|
self._request_delay = request_delay
|
||||||
self._loop = None
|
self._loop = None
|
||||||
|
|
||||||
async def _local_request(self, method, uri, cookies=None, *args,
|
async def _local_request(self, method, uri, cookies=None, *args, **kwargs):
|
||||||
**kwargs):
|
|
||||||
if self._loop is None:
|
if self._loop is None:
|
||||||
self._loop = asyncio.get_event_loop()
|
self._loop = asyncio.get_event_loop()
|
||||||
if uri.startswith(('http:', 'https:', 'ftp:', 'ftps://' '//')):
|
if uri.startswith(("http:", "https:", "ftp:", "ftps://" "//")):
|
||||||
url = uri
|
url = uri
|
||||||
else:
|
else:
|
||||||
url = 'http://{host}:{port}{uri}'.format(
|
url = "http://{host}:{port}{uri}".format(
|
||||||
host=HOST, port=self.port, uri=uri)
|
host=HOST, port=self.port, uri=uri
|
||||||
conn = DelayableTCPConnector(pre_request_delay=self._request_delay,
|
)
|
||||||
verify_ssl=False, loop=self._loop)
|
conn = DelayableTCPConnector(
|
||||||
async with aiohttp.ClientSession(cookies=cookies, connector=conn,
|
pre_request_delay=self._request_delay,
|
||||||
loop=self._loop) as session:
|
verify_ssl=False,
|
||||||
|
loop=self._loop,
|
||||||
|
)
|
||||||
|
async with aiohttp.ClientSession(
|
||||||
|
cookies=cookies, connector=conn, loop=self._loop
|
||||||
|
) as session:
|
||||||
# Insert a delay after creating the connection
|
# Insert a delay after creating the connection
|
||||||
# But before sending the request.
|
# But before sending the request.
|
||||||
|
|
||||||
async with getattr(session, method.lower())(
|
async with getattr(session, method.lower())(
|
||||||
url, *args, **kwargs) as response:
|
url, *args, **kwargs
|
||||||
|
) as response:
|
||||||
try:
|
try:
|
||||||
response.text = await response.text()
|
response.text = await response.text()
|
||||||
except UnicodeDecodeError:
|
except UnicodeDecodeError:
|
||||||
|
@ -164,9 +172,11 @@ class DelayableSanicTestClient(SanicTestClient):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
response.json = await response.json()
|
response.json = await response.json()
|
||||||
except (JSONDecodeError,
|
except (
|
||||||
UnicodeDecodeError,
|
JSONDecodeError,
|
||||||
aiohttp.ClientResponseError):
|
UnicodeDecodeError,
|
||||||
|
aiohttp.ClientResponseError,
|
||||||
|
):
|
||||||
response.json = None
|
response.json = None
|
||||||
|
|
||||||
response.body = await response.read()
|
response.body = await response.read()
|
||||||
|
@ -174,50 +184,50 @@ class DelayableSanicTestClient(SanicTestClient):
|
||||||
|
|
||||||
|
|
||||||
Config.REQUEST_TIMEOUT = 0.6
|
Config.REQUEST_TIMEOUT = 0.6
|
||||||
request_timeout_default_app = Sanic('test_request_timeout_default')
|
request_timeout_default_app = Sanic("test_request_timeout_default")
|
||||||
request_no_timeout_app = Sanic('test_request_no_timeout')
|
request_no_timeout_app = Sanic("test_request_no_timeout")
|
||||||
|
|
||||||
|
|
||||||
@request_timeout_default_app.route('/1')
|
@request_timeout_default_app.route("/1")
|
||||||
async def handler1(request):
|
async def handler1(request):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
|
|
||||||
@request_no_timeout_app.route('/1')
|
@request_no_timeout_app.route("/1")
|
||||||
async def handler2(request):
|
async def handler2(request):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
|
|
||||||
@request_timeout_default_app.websocket('/ws1')
|
@request_timeout_default_app.websocket("/ws1")
|
||||||
async def ws_handler1(request, ws):
|
async def ws_handler1(request, ws):
|
||||||
await ws.send('OK')
|
await ws.send("OK")
|
||||||
|
|
||||||
|
|
||||||
def test_default_server_error_request_timeout():
|
def test_default_server_error_request_timeout():
|
||||||
client = DelayableSanicTestClient(request_timeout_default_app, None, 2)
|
client = DelayableSanicTestClient(request_timeout_default_app, None, 2)
|
||||||
request, response = client.get('/1')
|
request, response = client.get("/1")
|
||||||
assert response.status == 408
|
assert response.status == 408
|
||||||
assert response.text == 'Error: Request Timeout'
|
assert response.text == "Error: Request Timeout"
|
||||||
|
|
||||||
|
|
||||||
def test_default_server_error_request_dont_timeout():
|
def test_default_server_error_request_dont_timeout():
|
||||||
client = DelayableSanicTestClient(request_no_timeout_app, None, 0.2)
|
client = DelayableSanicTestClient(request_no_timeout_app, None, 0.2)
|
||||||
request, response = client.get('/1')
|
request, response = client.get("/1")
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == 'OK'
|
assert response.text == "OK"
|
||||||
|
|
||||||
|
|
||||||
def test_default_server_error_websocket_request_timeout():
|
def test_default_server_error_websocket_request_timeout():
|
||||||
|
|
||||||
headers={
|
headers = {
|
||||||
'Upgrade': 'websocket',
|
"Upgrade": "websocket",
|
||||||
'Connection': 'upgrade',
|
"Connection": "upgrade",
|
||||||
'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==',
|
"Sec-WebSocket-Key": "dGhlIHNhbXBsZSBub25jZQ==",
|
||||||
'Sec-WebSocket-Version': '13'
|
"Sec-WebSocket-Version": "13",
|
||||||
}
|
}
|
||||||
|
|
||||||
client = DelayableSanicTestClient(request_timeout_default_app, None, 2)
|
client = DelayableSanicTestClient(request_timeout_default_app, None, 2)
|
||||||
request, response = client.get('/ws1', headers=headers)
|
request, response = client.get("/ws1", headers=headers)
|
||||||
|
|
||||||
assert response.status == 408
|
assert response.status == 408
|
||||||
assert response.text == 'Error: Request Timeout'
|
assert response.text == "Error: Request Timeout"
|
||||||
|
|
|
@ -16,235 +16,214 @@ from sanic.testing import HOST, PORT
|
||||||
# GET
|
# GET
|
||||||
# ------------------------------------------------------------ #
|
# ------------------------------------------------------------ #
|
||||||
|
|
||||||
|
|
||||||
def test_sync(app):
|
def test_sync(app):
|
||||||
|
@app.route("/")
|
||||||
@app.route('/')
|
|
||||||
def handler(request):
|
def handler(request):
|
||||||
return text('Hello')
|
return text("Hello")
|
||||||
|
|
||||||
request, response = app.test_client.get('/')
|
request, response = app.test_client.get("/")
|
||||||
|
|
||||||
assert response.text == 'Hello'
|
assert response.text == "Hello"
|
||||||
|
|
||||||
|
|
||||||
def test_remote_address(app):
|
def test_remote_address(app):
|
||||||
|
@app.route("/")
|
||||||
@app.route('/')
|
|
||||||
def handler(request):
|
def handler(request):
|
||||||
return text("{}".format(request.ip))
|
return text("{}".format(request.ip))
|
||||||
|
|
||||||
request, response = app.test_client.get('/')
|
request, response = app.test_client.get("/")
|
||||||
|
|
||||||
assert response.text == '127.0.0.1'
|
assert response.text == "127.0.0.1"
|
||||||
|
|
||||||
|
|
||||||
def test_text(app):
|
def test_text(app):
|
||||||
|
@app.route("/")
|
||||||
@app.route('/')
|
|
||||||
async def handler(request):
|
async def handler(request):
|
||||||
return text('Hello')
|
return text("Hello")
|
||||||
|
|
||||||
request, response = app.test_client.get('/')
|
request, response = app.test_client.get("/")
|
||||||
|
|
||||||
assert response.text == 'Hello'
|
assert response.text == "Hello"
|
||||||
|
|
||||||
|
|
||||||
def test_headers(app):
|
def test_headers(app):
|
||||||
|
@app.route("/")
|
||||||
@app.route('/')
|
|
||||||
async def handler(request):
|
async def handler(request):
|
||||||
headers = {"spam": "great"}
|
headers = {"spam": "great"}
|
||||||
return text('Hello', headers=headers)
|
return text("Hello", headers=headers)
|
||||||
|
|
||||||
request, response = app.test_client.get('/')
|
request, response = app.test_client.get("/")
|
||||||
|
|
||||||
assert response.headers.get('spam') == 'great'
|
assert response.headers.get("spam") == "great"
|
||||||
|
|
||||||
|
|
||||||
def test_non_str_headers(app):
|
def test_non_str_headers(app):
|
||||||
|
@app.route("/")
|
||||||
@app.route('/')
|
|
||||||
async def handler(request):
|
async def handler(request):
|
||||||
headers = {"answer": 42}
|
headers = {"answer": 42}
|
||||||
return text('Hello', headers=headers)
|
return text("Hello", headers=headers)
|
||||||
|
|
||||||
request, response = app.test_client.get('/')
|
request, response = app.test_client.get("/")
|
||||||
|
|
||||||
assert response.headers.get('answer') == '42'
|
assert response.headers.get("answer") == "42"
|
||||||
|
|
||||||
|
|
||||||
def test_invalid_response(app):
|
def test_invalid_response(app):
|
||||||
|
|
||||||
@app.exception(ServerError)
|
@app.exception(ServerError)
|
||||||
def handler_exception(request, exception):
|
def handler_exception(request, exception):
|
||||||
return text('Internal Server Error.', 500)
|
return text("Internal Server Error.", 500)
|
||||||
|
|
||||||
@app.route('/')
|
@app.route("/")
|
||||||
async def handler(request):
|
async def handler(request):
|
||||||
return 'This should fail'
|
return "This should fail"
|
||||||
|
|
||||||
request, response = app.test_client.get('/')
|
request, response = app.test_client.get("/")
|
||||||
assert response.status == 500
|
assert response.status == 500
|
||||||
assert response.text == "Internal Server Error."
|
assert response.text == "Internal Server Error."
|
||||||
|
|
||||||
|
|
||||||
def test_json(app):
|
def test_json(app):
|
||||||
|
@app.route("/")
|
||||||
@app.route('/')
|
|
||||||
async def handler(request):
|
async def handler(request):
|
||||||
return json({"test": True})
|
return json({"test": True})
|
||||||
|
|
||||||
request, response = app.test_client.get('/')
|
request, response = app.test_client.get("/")
|
||||||
|
|
||||||
results = json_loads(response.text)
|
results = json_loads(response.text)
|
||||||
|
|
||||||
assert results.get('test') is True
|
assert results.get("test") is True
|
||||||
|
|
||||||
|
|
||||||
def test_empty_json(app):
|
def test_empty_json(app):
|
||||||
|
@app.route("/")
|
||||||
@app.route('/')
|
|
||||||
async def handler(request):
|
async def handler(request):
|
||||||
assert request.json is None
|
assert request.json is None
|
||||||
return json(request.json)
|
return json(request.json)
|
||||||
|
|
||||||
request, response = app.test_client.get('/')
|
request, response = app.test_client.get("/")
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == 'null'
|
assert response.text == "null"
|
||||||
|
|
||||||
|
|
||||||
def test_invalid_json(app):
|
def test_invalid_json(app):
|
||||||
|
@app.route("/")
|
||||||
@app.route('/')
|
|
||||||
async def handler(request):
|
async def handler(request):
|
||||||
return json(request.json)
|
return json(request.json)
|
||||||
|
|
||||||
data = "I am not json"
|
data = "I am not json"
|
||||||
request, response = app.test_client.get('/', data=data)
|
request, response = app.test_client.get("/", data=data)
|
||||||
|
|
||||||
assert response.status == 400
|
assert response.status == 400
|
||||||
|
|
||||||
|
|
||||||
def test_query_string(app):
|
def test_query_string(app):
|
||||||
|
@app.route("/")
|
||||||
@app.route('/')
|
|
||||||
async def handler(request):
|
async def handler(request):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
request, response = app.test_client.get(
|
request, response = app.test_client.get(
|
||||||
'/', params=[("test1", "1"), ("test2", "false"), ("test2", "true")])
|
"/", params=[("test1", "1"), ("test2", "false"), ("test2", "true")]
|
||||||
|
)
|
||||||
|
|
||||||
assert request.args.get('test1') == '1'
|
assert request.args.get("test1") == "1"
|
||||||
assert request.args.get('test2') == 'false'
|
assert request.args.get("test2") == "false"
|
||||||
|
|
||||||
|
|
||||||
def test_uri_template(app):
|
def test_uri_template(app):
|
||||||
|
@app.route("/foo/<id:int>/bar/<name:[A-z]+>")
|
||||||
@app.route('/foo/<id:int>/bar/<name:[A-z]+>')
|
|
||||||
async def handler(request):
|
async def handler(request):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
request, response = app.test_client.get('/foo/123/bar/baz')
|
request, response = app.test_client.get("/foo/123/bar/baz")
|
||||||
assert request.uri_template == '/foo/<id:int>/bar/<name:[A-z]+>'
|
assert request.uri_template == "/foo/<id:int>/bar/<name:[A-z]+>"
|
||||||
|
|
||||||
|
|
||||||
def test_token(app):
|
def test_token(app):
|
||||||
|
@app.route("/")
|
||||||
@app.route('/')
|
|
||||||
async def handler(request):
|
async def handler(request):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
# uuid4 generated token.
|
# uuid4 generated token.
|
||||||
token = 'a1d895e0-553a-421a-8e22-5ff8ecb48cbf'
|
token = "a1d895e0-553a-421a-8e22-5ff8ecb48cbf"
|
||||||
headers = {
|
headers = {
|
||||||
'content-type': 'application/json',
|
"content-type": "application/json",
|
||||||
'Authorization': '{}'.format(token)
|
"Authorization": "{}".format(token),
|
||||||
}
|
}
|
||||||
|
|
||||||
request, response = app.test_client.get('/', headers=headers)
|
request, response = app.test_client.get("/", headers=headers)
|
||||||
|
|
||||||
assert request.token == token
|
assert request.token == token
|
||||||
|
|
||||||
token = 'a1d895e0-553a-421a-8e22-5ff8ecb48cbf'
|
token = "a1d895e0-553a-421a-8e22-5ff8ecb48cbf"
|
||||||
headers = {
|
headers = {
|
||||||
'content-type': 'application/json',
|
"content-type": "application/json",
|
||||||
'Authorization': 'Token {}'.format(token)
|
"Authorization": "Token {}".format(token),
|
||||||
}
|
}
|
||||||
|
|
||||||
request, response = app.test_client.get('/', headers=headers)
|
request, response = app.test_client.get("/", headers=headers)
|
||||||
|
|
||||||
assert request.token == token
|
assert request.token == token
|
||||||
|
|
||||||
token = 'a1d895e0-553a-421a-8e22-5ff8ecb48cbf'
|
token = "a1d895e0-553a-421a-8e22-5ff8ecb48cbf"
|
||||||
headers = {
|
headers = {
|
||||||
'content-type': 'application/json',
|
"content-type": "application/json",
|
||||||
'Authorization': 'Bearer {}'.format(token)
|
"Authorization": "Bearer {}".format(token),
|
||||||
}
|
}
|
||||||
|
|
||||||
request, response = app.test_client.get('/', headers=headers)
|
request, response = app.test_client.get("/", headers=headers)
|
||||||
|
|
||||||
assert request.token == token
|
assert request.token == token
|
||||||
|
|
||||||
# no Authorization headers
|
# no Authorization headers
|
||||||
headers = {
|
headers = {"content-type": "application/json"}
|
||||||
'content-type': 'application/json'
|
|
||||||
}
|
|
||||||
|
|
||||||
request, response = app.test_client.get('/', headers=headers)
|
request, response = app.test_client.get("/", headers=headers)
|
||||||
|
|
||||||
assert request.token is None
|
assert request.token is None
|
||||||
|
|
||||||
|
|
||||||
def test_content_type(app):
|
def test_content_type(app):
|
||||||
|
@app.route("/")
|
||||||
@app.route('/')
|
|
||||||
async def handler(request):
|
async def handler(request):
|
||||||
return text(request.content_type)
|
return text(request.content_type)
|
||||||
|
|
||||||
request, response = app.test_client.get('/')
|
request, response = app.test_client.get("/")
|
||||||
assert request.content_type == DEFAULT_HTTP_CONTENT_TYPE
|
assert request.content_type == DEFAULT_HTTP_CONTENT_TYPE
|
||||||
assert response.text == DEFAULT_HTTP_CONTENT_TYPE
|
assert response.text == DEFAULT_HTTP_CONTENT_TYPE
|
||||||
|
|
||||||
headers = {
|
headers = {"content-type": "application/json"}
|
||||||
'content-type': 'application/json',
|
request, response = app.test_client.get("/", headers=headers)
|
||||||
}
|
assert request.content_type == "application/json"
|
||||||
request, response = app.test_client.get('/', headers=headers)
|
assert response.text == "application/json"
|
||||||
assert request.content_type == 'application/json'
|
|
||||||
assert response.text == 'application/json'
|
|
||||||
|
|
||||||
|
|
||||||
def test_remote_addr(app):
|
def test_remote_addr(app):
|
||||||
|
@app.route("/")
|
||||||
@app.route('/')
|
|
||||||
async def handler(request):
|
async def handler(request):
|
||||||
return text(request.remote_addr)
|
return text(request.remote_addr)
|
||||||
|
|
||||||
headers = {
|
headers = {"X-Forwarded-For": "127.0.0.1, 127.0.1.2"}
|
||||||
'X-Forwarded-For': '127.0.0.1, 127.0.1.2'
|
request, response = app.test_client.get("/", headers=headers)
|
||||||
}
|
assert request.remote_addr == "127.0.0.1"
|
||||||
request, response = app.test_client.get('/', headers=headers)
|
assert response.text == "127.0.0.1"
|
||||||
assert request.remote_addr == '127.0.0.1'
|
|
||||||
assert response.text == '127.0.0.1'
|
|
||||||
|
|
||||||
request, response = app.test_client.get('/')
|
request, response = app.test_client.get("/")
|
||||||
assert request.remote_addr == ''
|
assert request.remote_addr == ""
|
||||||
assert response.text == ''
|
assert response.text == ""
|
||||||
|
|
||||||
headers = {
|
headers = {"X-Forwarded-For": "127.0.0.1, , ,,127.0.1.2"}
|
||||||
'X-Forwarded-For': '127.0.0.1, , ,,127.0.1.2'
|
request, response = app.test_client.get("/", headers=headers)
|
||||||
}
|
assert request.remote_addr == "127.0.0.1"
|
||||||
request, response = app.test_client.get('/', headers=headers)
|
assert response.text == "127.0.0.1"
|
||||||
assert request.remote_addr == '127.0.0.1'
|
|
||||||
assert response.text == '127.0.0.1'
|
|
||||||
|
|
||||||
|
|
||||||
def test_match_info(app):
|
def test_match_info(app):
|
||||||
|
@app.route("/api/v1/user/<user_id>/")
|
||||||
@app.route('/api/v1/user/<user_id>/')
|
|
||||||
async def handler(request, user_id):
|
async def handler(request, user_id):
|
||||||
return json(request.match_info)
|
return json(request.match_info)
|
||||||
|
|
||||||
request, response = app.test_client.get('/api/v1/user/sanic_user/')
|
request, response = app.test_client.get("/api/v1/user/sanic_user/")
|
||||||
|
|
||||||
assert request.match_info == {"user_id": "sanic_user"}
|
assert request.match_info == {"user_id": "sanic_user"}
|
||||||
assert json_loads(response.text) == {"user_id": "sanic_user"}
|
assert json_loads(response.text) == {"user_id": "sanic_user"}
|
||||||
|
@ -254,79 +233,82 @@ def test_match_info(app):
|
||||||
# POST
|
# POST
|
||||||
# ------------------------------------------------------------ #
|
# ------------------------------------------------------------ #
|
||||||
|
|
||||||
|
|
||||||
def test_post_json(app):
|
def test_post_json(app):
|
||||||
|
@app.route("/", methods=["POST"])
|
||||||
@app.route('/', methods=['POST'])
|
|
||||||
async def handler(request):
|
async def handler(request):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
payload = {'test': 'OK'}
|
payload = {"test": "OK"}
|
||||||
headers = {'content-type': 'application/json'}
|
headers = {"content-type": "application/json"}
|
||||||
|
|
||||||
request, response = app.test_client.post(
|
request, response = app.test_client.post(
|
||||||
'/', data=json_dumps(payload), headers=headers)
|
"/", data=json_dumps(payload), headers=headers
|
||||||
|
)
|
||||||
|
|
||||||
assert request.json.get('test') == 'OK'
|
assert request.json.get("test") == "OK"
|
||||||
assert request.json.get('test') == 'OK' # for request.parsed_json
|
assert request.json.get("test") == "OK" # for request.parsed_json
|
||||||
assert response.text == 'OK'
|
assert response.text == "OK"
|
||||||
|
|
||||||
|
|
||||||
def test_post_form_urlencoded(app):
|
def test_post_form_urlencoded(app):
|
||||||
|
@app.route("/", methods=["POST"])
|
||||||
@app.route('/', methods=['POST'])
|
|
||||||
async def handler(request):
|
async def handler(request):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
payload = 'test=OK'
|
payload = "test=OK"
|
||||||
headers = {'content-type': 'application/x-www-form-urlencoded'}
|
headers = {"content-type": "application/x-www-form-urlencoded"}
|
||||||
|
|
||||||
request, response = app.test_client.post('/', data=payload,
|
request, response = app.test_client.post(
|
||||||
headers=headers)
|
"/", data=payload, headers=headers
|
||||||
|
)
|
||||||
|
|
||||||
assert request.form.get('test') == 'OK'
|
assert request.form.get("test") == "OK"
|
||||||
assert request.form.get('test') == 'OK' # For request.parsed_form
|
assert request.form.get("test") == "OK" # For request.parsed_form
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
'payload', [
|
"payload",
|
||||||
'------sanic\r\n'
|
[
|
||||||
|
"------sanic\r\n"
|
||||||
'Content-Disposition: form-data; name="test"\r\n'
|
'Content-Disposition: form-data; name="test"\r\n'
|
||||||
'\r\n'
|
"\r\n"
|
||||||
'OK\r\n'
|
"OK\r\n"
|
||||||
'------sanic--\r\n',
|
"------sanic--\r\n",
|
||||||
'------sanic\r\n'
|
"------sanic\r\n"
|
||||||
'content-disposition: form-data; name="test"\r\n'
|
'content-disposition: form-data; name="test"\r\n'
|
||||||
'\r\n'
|
"\r\n"
|
||||||
'OK\r\n'
|
"OK\r\n"
|
||||||
'------sanic--\r\n',
|
"------sanic--\r\n",
|
||||||
])
|
],
|
||||||
|
)
|
||||||
def test_post_form_multipart_form_data(app, payload):
|
def test_post_form_multipart_form_data(app, payload):
|
||||||
|
@app.route("/", methods=["POST"])
|
||||||
@app.route('/', methods=['POST'])
|
|
||||||
async def handler(request):
|
async def handler(request):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
headers = {'content-type': 'multipart/form-data; boundary=----sanic'}
|
headers = {"content-type": "multipart/form-data; boundary=----sanic"}
|
||||||
|
|
||||||
request, response = app.test_client.post(data=payload, headers=headers)
|
request, response = app.test_client.post(data=payload, headers=headers)
|
||||||
|
|
||||||
assert request.form.get('test') == 'OK'
|
assert request.form.get("test") == "OK"
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
'path,query,expected_url', [
|
"path,query,expected_url",
|
||||||
('/foo', '', 'http://{}:{}/foo'),
|
[
|
||||||
('/bar/baz', '', 'http://{}:{}/bar/baz'),
|
("/foo", "", "http://{}:{}/foo"),
|
||||||
('/moo/boo', 'arg1=val1', 'http://{}:{}/moo/boo?arg1=val1')
|
("/bar/baz", "", "http://{}:{}/bar/baz"),
|
||||||
])
|
("/moo/boo", "arg1=val1", "http://{}:{}/moo/boo?arg1=val1"),
|
||||||
|
],
|
||||||
|
)
|
||||||
def test_url_attributes_no_ssl(app, path, query, expected_url):
|
def test_url_attributes_no_ssl(app, path, query, expected_url):
|
||||||
|
|
||||||
async def handler(request):
|
async def handler(request):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
app.add_route(handler, path)
|
app.add_route(handler, path)
|
||||||
|
|
||||||
request, response = app.test_client.get(path + '?{}'.format(query))
|
request, response = app.test_client.get(path + "?{}".format(query))
|
||||||
assert request.url == expected_url.format(HOST, PORT)
|
assert request.url == expected_url.format(HOST, PORT)
|
||||||
|
|
||||||
parsed = urlparse(request.url)
|
parsed = urlparse(request.url)
|
||||||
|
@ -338,26 +320,30 @@ def test_url_attributes_no_ssl(app, path, query, expected_url):
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
'path,query,expected_url', [
|
"path,query,expected_url",
|
||||||
('/foo', '', 'https://{}:{}/foo'),
|
[
|
||||||
('/bar/baz', '', 'https://{}:{}/bar/baz'),
|
("/foo", "", "https://{}:{}/foo"),
|
||||||
('/moo/boo', 'arg1=val1', 'https://{}:{}/moo/boo?arg1=val1')
|
("/bar/baz", "", "https://{}:{}/bar/baz"),
|
||||||
])
|
("/moo/boo", "arg1=val1", "https://{}:{}/moo/boo?arg1=val1"),
|
||||||
|
],
|
||||||
|
)
|
||||||
def test_url_attributes_with_ssl_context(app, path, query, expected_url):
|
def test_url_attributes_with_ssl_context(app, path, query, expected_url):
|
||||||
current_dir = os.path.dirname(os.path.realpath(__file__))
|
current_dir = os.path.dirname(os.path.realpath(__file__))
|
||||||
context = ssl.create_default_context(purpose=ssl.Purpose.CLIENT_AUTH)
|
context = ssl.create_default_context(purpose=ssl.Purpose.CLIENT_AUTH)
|
||||||
context.load_cert_chain(
|
context.load_cert_chain(
|
||||||
os.path.join(current_dir, 'certs/selfsigned.cert'),
|
os.path.join(current_dir, "certs/selfsigned.cert"),
|
||||||
keyfile=os.path.join(current_dir, 'certs/selfsigned.key'))
|
keyfile=os.path.join(current_dir, "certs/selfsigned.key"),
|
||||||
|
)
|
||||||
|
|
||||||
async def handler(request):
|
async def handler(request):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
app.add_route(handler, path)
|
app.add_route(handler, path)
|
||||||
|
|
||||||
request, response = app.test_client.get(
|
request, response = app.test_client.get(
|
||||||
'https://{}:{}'.format(HOST, PORT) + path + '?{}'.format(query),
|
"https://{}:{}".format(HOST, PORT) + path + "?{}".format(query),
|
||||||
server_kwargs={'ssl': context})
|
server_kwargs={"ssl": context},
|
||||||
|
)
|
||||||
assert request.url == expected_url.format(HOST, PORT)
|
assert request.url == expected_url.format(HOST, PORT)
|
||||||
|
|
||||||
parsed = urlparse(request.url)
|
parsed = urlparse(request.url)
|
||||||
|
@ -369,30 +355,30 @@ def test_url_attributes_with_ssl_context(app, path, query, expected_url):
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
'path,query,expected_url', [
|
"path,query,expected_url",
|
||||||
('/foo', '', 'https://{}:{}/foo'),
|
[
|
||||||
('/bar/baz', '', 'https://{}:{}/bar/baz'),
|
("/foo", "", "https://{}:{}/foo"),
|
||||||
('/moo/boo', 'arg1=val1', 'https://{}:{}/moo/boo?arg1=val1')
|
("/bar/baz", "", "https://{}:{}/bar/baz"),
|
||||||
])
|
("/moo/boo", "arg1=val1", "https://{}:{}/moo/boo?arg1=val1"),
|
||||||
|
],
|
||||||
|
)
|
||||||
def test_url_attributes_with_ssl_dict(app, path, query, expected_url):
|
def test_url_attributes_with_ssl_dict(app, path, query, expected_url):
|
||||||
|
|
||||||
current_dir = os.path.dirname(os.path.realpath(__file__))
|
current_dir = os.path.dirname(os.path.realpath(__file__))
|
||||||
ssl_cert = os.path.join(current_dir, 'certs/selfsigned.cert')
|
ssl_cert = os.path.join(current_dir, "certs/selfsigned.cert")
|
||||||
ssl_key = os.path.join(current_dir, 'certs/selfsigned.key')
|
ssl_key = os.path.join(current_dir, "certs/selfsigned.key")
|
||||||
|
|
||||||
ssl_dict = {
|
ssl_dict = {"cert": ssl_cert, "key": ssl_key}
|
||||||
'cert': ssl_cert,
|
|
||||||
'key': ssl_key
|
|
||||||
}
|
|
||||||
|
|
||||||
async def handler(request):
|
async def handler(request):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
app.add_route(handler, path)
|
app.add_route(handler, path)
|
||||||
|
|
||||||
request, response = app.test_client.get(
|
request, response = app.test_client.get(
|
||||||
'https://{}:{}'.format(HOST, PORT) + path + '?{}'.format(query),
|
"https://{}:{}".format(HOST, PORT) + path + "?{}".format(query),
|
||||||
server_kwargs={'ssl': ssl_dict})
|
server_kwargs={"ssl": ssl_dict},
|
||||||
|
)
|
||||||
assert request.url == expected_url.format(HOST, PORT)
|
assert request.url == expected_url.format(HOST, PORT)
|
||||||
|
|
||||||
parsed = urlparse(request.url)
|
parsed = urlparse(request.url)
|
||||||
|
@ -404,69 +390,69 @@ def test_url_attributes_with_ssl_dict(app, path, query, expected_url):
|
||||||
|
|
||||||
|
|
||||||
def test_invalid_ssl_dict(app):
|
def test_invalid_ssl_dict(app):
|
||||||
|
@app.get("/test")
|
||||||
@app.get('/test')
|
|
||||||
async def handler(request):
|
async def handler(request):
|
||||||
return text('ssl test')
|
return text("ssl test")
|
||||||
|
|
||||||
ssl_dict = {
|
ssl_dict = {"cert": None, "key": None}
|
||||||
'cert': None,
|
|
||||||
'key': None
|
|
||||||
}
|
|
||||||
|
|
||||||
with pytest.raises(ValueError) as excinfo:
|
with pytest.raises(ValueError) as excinfo:
|
||||||
request, response = app.test_client.get('/test', server_kwargs={'ssl': ssl_dict})
|
request, response = app.test_client.get(
|
||||||
|
"/test", server_kwargs={"ssl": ssl_dict}
|
||||||
|
)
|
||||||
|
|
||||||
assert str(excinfo.value) == 'SSLContext or certificate and key required.'
|
assert str(excinfo.value) == "SSLContext or certificate and key required."
|
||||||
|
|
||||||
|
|
||||||
def test_form_with_multiple_values(app):
|
def test_form_with_multiple_values(app):
|
||||||
|
@app.route("/", methods=["POST"])
|
||||||
@app.route('/', methods=['POST'])
|
|
||||||
async def handler(request):
|
async def handler(request):
|
||||||
return text("OK")
|
return text("OK")
|
||||||
|
|
||||||
payload="selectedItems=v1&selectedItems=v2&selectedItems=v3"
|
payload = "selectedItems=v1&selectedItems=v2&selectedItems=v3"
|
||||||
|
|
||||||
headers = {'content-type': 'application/x-www-form-urlencoded'}
|
headers = {"content-type": "application/x-www-form-urlencoded"}
|
||||||
|
|
||||||
request, response = app.test_client.post('/', data=payload,
|
request, response = app.test_client.post(
|
||||||
headers=headers)
|
"/", data=payload, headers=headers
|
||||||
|
)
|
||||||
|
|
||||||
assert request.form.getlist("selectedItems") == ["v1", "v2", "v3"]
|
assert request.form.getlist("selectedItems") == ["v1", "v2", "v3"]
|
||||||
|
|
||||||
|
|
||||||
def test_request_string_representation(app):
|
def test_request_string_representation(app):
|
||||||
@app.route('/', methods=["GET"])
|
@app.route("/", methods=["GET"])
|
||||||
async def get(request):
|
async def get(request):
|
||||||
return text("OK")
|
return text("OK")
|
||||||
|
|
||||||
request, _ = app.test_client.get("/")
|
request, _ = app.test_client.get("/")
|
||||||
assert repr(request) == '<Request: GET />'
|
assert repr(request) == "<Request: GET />"
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
'payload', [
|
"payload",
|
||||||
'------sanic\r\n'
|
[
|
||||||
|
"------sanic\r\n"
|
||||||
'Content-Disposition: form-data; filename="filename"; name="test"\r\n'
|
'Content-Disposition: form-data; filename="filename"; name="test"\r\n'
|
||||||
'\r\n'
|
"\r\n"
|
||||||
'OK\r\n'
|
"OK\r\n"
|
||||||
'------sanic--\r\n',
|
"------sanic--\r\n",
|
||||||
'------sanic\r\n'
|
"------sanic\r\n"
|
||||||
'content-disposition: form-data; filename="filename"; name="test"\r\n'
|
'content-disposition: form-data; filename="filename"; name="test"\r\n'
|
||||||
'\r\n'
|
"\r\n"
|
||||||
'content-type: application/json; {"field": "value"}\r\n'
|
'content-type: application/json; {"field": "value"}\r\n'
|
||||||
'------sanic--\r\n',
|
"------sanic--\r\n",
|
||||||
])
|
],
|
||||||
|
)
|
||||||
def test_request_multipart_files(app, payload):
|
def test_request_multipart_files(app, payload):
|
||||||
@app.route("/", methods=["POST"])
|
@app.route("/", methods=["POST"])
|
||||||
async def post(request):
|
async def post(request):
|
||||||
return text("OK")
|
return text("OK")
|
||||||
|
|
||||||
headers = {'content-type': 'multipart/form-data; boundary=----sanic'}
|
headers = {"content-type": "multipart/form-data; boundary=----sanic"}
|
||||||
|
|
||||||
request, _ = app.test_client.post(data=payload, headers=headers)
|
request, _ = app.test_client.post(data=payload, headers=headers)
|
||||||
assert request.files.get('test').name == "filename"
|
assert request.files.get("test").name == "filename"
|
||||||
|
|
||||||
|
|
||||||
def test_request_multipart_file_with_json_content_type(app):
|
def test_request_multipart_file_with_json_content_type(app):
|
||||||
|
@ -475,72 +461,79 @@ def test_request_multipart_file_with_json_content_type(app):
|
||||||
return text("OK")
|
return text("OK")
|
||||||
|
|
||||||
payload = (
|
payload = (
|
||||||
'------sanic\r\n'
|
"------sanic\r\n"
|
||||||
'Content-Disposition: form-data; name="file"; filename="test.json"\r\n'
|
'Content-Disposition: form-data; name="file"; filename="test.json"\r\n'
|
||||||
'Content-Type: application/json\r\n'
|
"Content-Type: application/json\r\n"
|
||||||
'Content-Length: 0'
|
"Content-Length: 0"
|
||||||
'\r\n'
|
"\r\n"
|
||||||
'\r\n'
|
"\r\n"
|
||||||
'------sanic--'
|
"------sanic--"
|
||||||
)
|
)
|
||||||
|
|
||||||
headers = {'content-type': 'multipart/form-data; boundary=------sanic'}
|
headers = {"content-type": "multipart/form-data; boundary=------sanic"}
|
||||||
|
|
||||||
request, _ = app.test_client.post(data=payload, headers=headers)
|
request, _ = app.test_client.post(data=payload, headers=headers)
|
||||||
assert request.files.get('file').type == 'application/json'
|
assert request.files.get("file").type == "application/json"
|
||||||
|
|
||||||
|
|
||||||
def test_request_multipart_file_without_field_name(app, caplog):
|
def test_request_multipart_file_without_field_name(app, caplog):
|
||||||
|
|
||||||
@app.route("/", methods=["POST"])
|
@app.route("/", methods=["POST"])
|
||||||
async def post(request):
|
async def post(request):
|
||||||
return text("OK")
|
return text("OK")
|
||||||
|
|
||||||
payload = (
|
payload = (
|
||||||
'------sanic\r\nContent-Disposition: form-data; filename="test.json"'
|
'------sanic\r\nContent-Disposition: form-data; filename="test.json"'
|
||||||
'\r\nContent-Type: application/json\r\n\r\n\r\n------sanic--'
|
"\r\nContent-Type: application/json\r\n\r\n\r\n------sanic--"
|
||||||
)
|
)
|
||||||
|
|
||||||
headers = {'content-type': 'multipart/form-data; boundary=------sanic'}
|
headers = {"content-type": "multipart/form-data; boundary=------sanic"}
|
||||||
|
|
||||||
request, _ = app.test_client.post(data=payload, headers=headers, debug=True)
|
request, _ = app.test_client.post(
|
||||||
|
data=payload, headers=headers, debug=True
|
||||||
|
)
|
||||||
with caplog.at_level(logging.DEBUG):
|
with caplog.at_level(logging.DEBUG):
|
||||||
request.form
|
request.form
|
||||||
|
|
||||||
assert caplog.record_tuples[-1] == ('sanic.root', logging.DEBUG,
|
assert caplog.record_tuples[-1] == (
|
||||||
|
"sanic.root",
|
||||||
|
logging.DEBUG,
|
||||||
"Form-data field does not have a 'name' parameter "
|
"Form-data field does not have a 'name' parameter "
|
||||||
"in the Content-Disposition header"
|
"in the Content-Disposition header",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_request_multipart_file_duplicate_filed_name(app):
|
def test_request_multipart_file_duplicate_filed_name(app):
|
||||||
|
|
||||||
@app.route("/", methods=["POST"])
|
@app.route("/", methods=["POST"])
|
||||||
async def post(request):
|
async def post(request):
|
||||||
return text("OK")
|
return text("OK")
|
||||||
|
|
||||||
payload = (
|
payload = (
|
||||||
'--e73ffaa8b1b2472b8ec848de833cb05b\r\n'
|
"--e73ffaa8b1b2472b8ec848de833cb05b\r\n"
|
||||||
'Content-Disposition: form-data; name="file"\r\n'
|
'Content-Disposition: form-data; name="file"\r\n'
|
||||||
'Content-Type: application/octet-stream\r\n'
|
"Content-Type: application/octet-stream\r\n"
|
||||||
'Content-Length: 15\r\n'
|
"Content-Length: 15\r\n"
|
||||||
'\r\n'
|
"\r\n"
|
||||||
'{"test":"json"}\r\n'
|
'{"test":"json"}\r\n'
|
||||||
'--e73ffaa8b1b2472b8ec848de833cb05b\r\n'
|
"--e73ffaa8b1b2472b8ec848de833cb05b\r\n"
|
||||||
'Content-Disposition: form-data; name="file"\r\n'
|
'Content-Disposition: form-data; name="file"\r\n'
|
||||||
'Content-Type: application/octet-stream\r\n'
|
"Content-Type: application/octet-stream\r\n"
|
||||||
'Content-Length: 15\r\n'
|
"Content-Length: 15\r\n"
|
||||||
'\r\n'
|
"\r\n"
|
||||||
'{"test":"json2"}\r\n'
|
'{"test":"json2"}\r\n'
|
||||||
'--e73ffaa8b1b2472b8ec848de833cb05b--\r\n'
|
"--e73ffaa8b1b2472b8ec848de833cb05b--\r\n"
|
||||||
)
|
)
|
||||||
|
|
||||||
headers = {
|
headers = {
|
||||||
'Content-Type': 'multipart/form-data; boundary=e73ffaa8b1b2472b8ec848de833cb05b'
|
"Content-Type": "multipart/form-data; boundary=e73ffaa8b1b2472b8ec848de833cb05b"
|
||||||
}
|
}
|
||||||
|
|
||||||
request, _ = app.test_client.post(data=payload, headers=headers, debug=True)
|
request, _ = app.test_client.post(
|
||||||
assert request.form.getlist('file') == ['{"test":"json"}', '{"test":"json2"}']
|
data=payload, headers=headers, debug=True
|
||||||
|
)
|
||||||
|
assert request.form.getlist("file") == [
|
||||||
|
'{"test":"json"}',
|
||||||
|
'{"test":"json2"}',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def test_request_multipart_with_multiple_files_and_type(app):
|
def test_request_multipart_with_multiple_files_and_type(app):
|
||||||
|
@ -548,38 +541,38 @@ def test_request_multipart_with_multiple_files_and_type(app):
|
||||||
async def post(request):
|
async def post(request):
|
||||||
return text("OK")
|
return text("OK")
|
||||||
|
|
||||||
payload = '------sanic\r\nContent-Disposition: form-data; name="file"; filename="test.json"' \
|
payload = (
|
||||||
'\r\nContent-Type: application/json\r\n\r\n\r\n' \
|
'------sanic\r\nContent-Disposition: form-data; name="file"; filename="test.json"'
|
||||||
'------sanic\r\nContent-Disposition: form-data; name="file"; filename="some_file.pdf"\r\n' \
|
"\r\nContent-Type: application/json\r\n\r\n\r\n"
|
||||||
'Content-Type: application/pdf\r\n\r\n\r\n------sanic--'
|
'------sanic\r\nContent-Disposition: form-data; name="file"; filename="some_file.pdf"\r\n'
|
||||||
headers = {'content-type': 'multipart/form-data; boundary=------sanic'}
|
"Content-Type: application/pdf\r\n\r\n\r\n------sanic--"
|
||||||
|
)
|
||||||
|
headers = {"content-type": "multipart/form-data; boundary=------sanic"}
|
||||||
|
|
||||||
request, _ = app.test_client.post(data=payload, headers=headers)
|
request, _ = app.test_client.post(data=payload, headers=headers)
|
||||||
assert len(request.files.getlist('file')) == 2
|
assert len(request.files.getlist("file")) == 2
|
||||||
assert request.files.getlist('file')[0].type == 'application/json'
|
assert request.files.getlist("file")[0].type == "application/json"
|
||||||
assert request.files.getlist('file')[1].type == 'application/pdf'
|
assert request.files.getlist("file")[1].type == "application/pdf"
|
||||||
|
|
||||||
|
|
||||||
def test_request_repr(app):
|
def test_request_repr(app):
|
||||||
|
@app.get("/")
|
||||||
@app.get('/')
|
|
||||||
def handler(request):
|
def handler(request):
|
||||||
return text('pass')
|
return text("pass")
|
||||||
|
|
||||||
request, response = app.test_client.get('/')
|
request, response = app.test_client.get("/")
|
||||||
assert repr(request) == '<Request: GET />'
|
assert repr(request) == "<Request: GET />"
|
||||||
|
|
||||||
request.method = None
|
request.method = None
|
||||||
assert repr(request) == '<Request>'
|
assert repr(request) == "<Request>"
|
||||||
|
|
||||||
|
|
||||||
def test_request_bool(app):
|
def test_request_bool(app):
|
||||||
|
@app.get("/")
|
||||||
@app.get('/')
|
|
||||||
def handler(request):
|
def handler(request):
|
||||||
return text('pass')
|
return text("pass")
|
||||||
|
|
||||||
request, response = app.test_client.get('/')
|
request, response = app.test_client.get("/")
|
||||||
assert bool(request)
|
assert bool(request)
|
||||||
|
|
||||||
request.transport = False
|
request.transport = False
|
||||||
|
@ -587,98 +580,99 @@ def test_request_bool(app):
|
||||||
|
|
||||||
|
|
||||||
def test_request_parsing_form_failed(app, caplog):
|
def test_request_parsing_form_failed(app, caplog):
|
||||||
|
@app.route("/", methods=["POST"])
|
||||||
@app.route('/', methods=['POST'])
|
|
||||||
async def handler(request):
|
async def handler(request):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
payload = 'test=OK'
|
payload = "test=OK"
|
||||||
headers = {'content-type': 'multipart/form-data'}
|
headers = {"content-type": "multipart/form-data"}
|
||||||
|
|
||||||
request, response = app.test_client.post('/', data=payload, headers=headers)
|
request, response = app.test_client.post(
|
||||||
|
"/", data=payload, headers=headers
|
||||||
|
)
|
||||||
|
|
||||||
with caplog.at_level(logging.ERROR):
|
with caplog.at_level(logging.ERROR):
|
||||||
request.form
|
request.form
|
||||||
|
|
||||||
assert caplog.record_tuples[-1] == ('sanic.error', logging.ERROR, 'Failed when parsing form')
|
assert caplog.record_tuples[-1] == (
|
||||||
|
"sanic.error",
|
||||||
|
logging.ERROR,
|
||||||
|
"Failed when parsing form",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_request_args_no_query_string(app):
|
def test_request_args_no_query_string(app):
|
||||||
|
@app.get("/")
|
||||||
@app.get('/')
|
|
||||||
def handler(request):
|
def handler(request):
|
||||||
return text('pass')
|
return text("pass")
|
||||||
|
|
||||||
request, response = app.test_client.get('/')
|
request, response = app.test_client.get("/")
|
||||||
|
|
||||||
assert request.args == {}
|
assert request.args == {}
|
||||||
|
|
||||||
|
|
||||||
def test_request_raw_args(app):
|
def test_request_raw_args(app):
|
||||||
|
|
||||||
params = {'test': 'OK'}
|
params = {"test": "OK"}
|
||||||
|
|
||||||
@app.get('/')
|
@app.get("/")
|
||||||
def handler(request):
|
def handler(request):
|
||||||
return text('pass')
|
return text("pass")
|
||||||
|
|
||||||
request, response = app.test_client.get('/', params=params)
|
request, response = app.test_client.get("/", params=params)
|
||||||
|
|
||||||
assert request.raw_args == params
|
assert request.raw_args == params
|
||||||
|
|
||||||
|
|
||||||
def test_request_cookies(app):
|
def test_request_cookies(app):
|
||||||
|
|
||||||
cookies = {'test': 'OK'}
|
cookies = {"test": "OK"}
|
||||||
|
|
||||||
@app.get('/')
|
@app.get("/")
|
||||||
def handler(request):
|
def handler(request):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
request, response = app.test_client.get('/', cookies=cookies)
|
request, response = app.test_client.get("/", cookies=cookies)
|
||||||
|
|
||||||
assert request.cookies == cookies
|
assert request.cookies == cookies
|
||||||
assert request.cookies == cookies # For request._cookies
|
assert request.cookies == cookies # For request._cookies
|
||||||
|
|
||||||
|
|
||||||
def test_request_cookies_without_cookies(app):
|
def test_request_cookies_without_cookies(app):
|
||||||
|
@app.get("/")
|
||||||
@app.get('/')
|
|
||||||
def handler(request):
|
def handler(request):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
request, response = app.test_client.get('/')
|
request, response = app.test_client.get("/")
|
||||||
|
|
||||||
assert request.cookies == {}
|
assert request.cookies == {}
|
||||||
|
|
||||||
|
|
||||||
def test_request_port(app):
|
def test_request_port(app):
|
||||||
|
@app.get("/")
|
||||||
@app.get('/')
|
|
||||||
def handler(request):
|
def handler(request):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
request, response = app.test_client.get('/')
|
request, response = app.test_client.get("/")
|
||||||
|
|
||||||
port = request.port
|
port = request.port
|
||||||
assert isinstance(port, int)
|
assert isinstance(port, int)
|
||||||
|
|
||||||
delattr(request, '_socket')
|
delattr(request, "_socket")
|
||||||
delattr(request, '_port')
|
delattr(request, "_port")
|
||||||
|
|
||||||
port = request.port
|
port = request.port
|
||||||
assert isinstance(port, int)
|
assert isinstance(port, int)
|
||||||
assert hasattr(request, '_socket')
|
assert hasattr(request, "_socket")
|
||||||
assert hasattr(request, '_port')
|
assert hasattr(request, "_port")
|
||||||
|
|
||||||
|
|
||||||
def test_request_socket(app):
|
def test_request_socket(app):
|
||||||
|
@app.get("/")
|
||||||
@app.get('/')
|
|
||||||
def handler(request):
|
def handler(request):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
request, response = app.test_client.get('/')
|
request, response = app.test_client.get("/")
|
||||||
|
|
||||||
socket = request.socket
|
socket = request.socket
|
||||||
assert isinstance(socket, tuple)
|
assert isinstance(socket, tuple)
|
||||||
|
@ -689,19 +683,18 @@ def test_request_socket(app):
|
||||||
assert ip == request.ip
|
assert ip == request.ip
|
||||||
assert port == request.port
|
assert port == request.port
|
||||||
|
|
||||||
delattr(request, '_socket')
|
delattr(request, "_socket")
|
||||||
|
|
||||||
socket = request.socket
|
socket = request.socket
|
||||||
assert isinstance(socket, tuple)
|
assert isinstance(socket, tuple)
|
||||||
assert hasattr(request, '_socket')
|
assert hasattr(request, "_socket")
|
||||||
|
|
||||||
|
|
||||||
def test_request_form_invalid_content_type(app):
|
def test_request_form_invalid_content_type(app):
|
||||||
|
|
||||||
@app.route("/", methods=["POST"])
|
@app.route("/", methods=["POST"])
|
||||||
async def post(request):
|
async def post(request):
|
||||||
return text("OK")
|
return text("OK")
|
||||||
|
|
||||||
request, response = app.test_client.post('/', json={'test': 'OK'})
|
request, response = app.test_client.post("/", json={"test": "OK"})
|
||||||
|
|
||||||
assert request.form == {}
|
assert request.form == {}
|
||||||
|
|
|
@ -10,127 +10,128 @@ from urllib.parse import unquote
|
||||||
import pytest
|
import pytest
|
||||||
from aiofiles import os as async_os
|
from aiofiles import os as async_os
|
||||||
|
|
||||||
from sanic.response import (HTTPResponse, StreamingHTTPResponse, file,
|
from sanic.response import (
|
||||||
file_stream, json, raw, stream, text)
|
HTTPResponse,
|
||||||
|
StreamingHTTPResponse,
|
||||||
|
file,
|
||||||
|
file_stream,
|
||||||
|
json,
|
||||||
|
raw,
|
||||||
|
stream,
|
||||||
|
text,
|
||||||
|
)
|
||||||
from sanic.server import HttpProtocol
|
from sanic.server import HttpProtocol
|
||||||
from sanic.testing import HOST, PORT
|
from sanic.testing import HOST, PORT
|
||||||
|
|
||||||
JSON_DATA = {'ok': True}
|
JSON_DATA = {"ok": True}
|
||||||
|
|
||||||
|
|
||||||
def test_response_body_not_a_string(app):
|
def test_response_body_not_a_string(app):
|
||||||
"""Test when a response body sent from the application is not a string"""
|
"""Test when a response body sent from the application is not a string"""
|
||||||
random_num = choice(range(1000))
|
random_num = choice(range(1000))
|
||||||
|
|
||||||
@app.route('/hello')
|
@app.route("/hello")
|
||||||
async def hello_route(request):
|
async def hello_route(request):
|
||||||
return HTTPResponse(body=random_num)
|
return HTTPResponse(body=random_num)
|
||||||
|
|
||||||
request, response = app.test_client.get('/hello')
|
request, response = app.test_client.get("/hello")
|
||||||
assert response.text == str(random_num)
|
assert response.text == str(random_num)
|
||||||
|
|
||||||
|
|
||||||
async def sample_streaming_fn(response):
|
async def sample_streaming_fn(response):
|
||||||
await response.write('foo,')
|
await response.write("foo,")
|
||||||
await asyncio.sleep(.001)
|
await asyncio.sleep(0.001)
|
||||||
await response.write('bar')
|
await response.write("bar")
|
||||||
|
|
||||||
|
|
||||||
def test_method_not_allowed(app):
|
def test_method_not_allowed(app):
|
||||||
@app.get('/')
|
@app.get("/")
|
||||||
async def test_get(request):
|
async def test_get(request):
|
||||||
return response.json({'hello': 'world'})
|
return response.json({"hello": "world"})
|
||||||
|
|
||||||
request, response = app.test_client.head('/')
|
request, response = app.test_client.head("/")
|
||||||
assert response.headers['Allow'] == 'GET'
|
assert response.headers["Allow"] == "GET"
|
||||||
|
|
||||||
request, response = app.test_client.post('/')
|
request, response = app.test_client.post("/")
|
||||||
assert response.headers['Allow'] == 'GET'
|
assert response.headers["Allow"] == "GET"
|
||||||
|
|
||||||
@app.post('/')
|
@app.post("/")
|
||||||
async def test_post(request):
|
async def test_post(request):
|
||||||
return response.json({'hello': 'world'})
|
return response.json({"hello": "world"})
|
||||||
|
|
||||||
request, response = app.test_client.head('/')
|
request, response = app.test_client.head("/")
|
||||||
assert response.status == 405
|
assert response.status == 405
|
||||||
assert set(response.headers['Allow'].split(', ')) == {'GET', 'POST'}
|
assert set(response.headers["Allow"].split(", ")) == {"GET", "POST"}
|
||||||
assert response.headers['Content-Length'] == '0'
|
assert response.headers["Content-Length"] == "0"
|
||||||
|
|
||||||
request, response = app.test_client.patch('/')
|
request, response = app.test_client.patch("/")
|
||||||
assert response.status == 405
|
assert response.status == 405
|
||||||
assert set(response.headers['Allow'].split(', ')) == {'GET', 'POST'}
|
assert set(response.headers["Allow"].split(", ")) == {"GET", "POST"}
|
||||||
assert response.headers['Content-Length'] == '0'
|
assert response.headers["Content-Length"] == "0"
|
||||||
|
|
||||||
|
|
||||||
def test_response_header(app):
|
def test_response_header(app):
|
||||||
|
@app.get("/")
|
||||||
@app.get('/')
|
|
||||||
async def test(request):
|
async def test(request):
|
||||||
return json({
|
return json({"ok": True}, headers={"CONTENT-TYPE": "application/json"})
|
||||||
"ok": True
|
|
||||||
}, headers={
|
|
||||||
'CONTENT-TYPE': 'application/json'
|
|
||||||
})
|
|
||||||
|
|
||||||
request, response = app.test_client.get('/')
|
request, response = app.test_client.get("/")
|
||||||
assert dict(response.headers) == {
|
assert dict(response.headers) == {
|
||||||
'Connection': 'keep-alive',
|
"Connection": "keep-alive",
|
||||||
'Keep-Alive': str(app.config.KEEP_ALIVE_TIMEOUT),
|
"Keep-Alive": str(app.config.KEEP_ALIVE_TIMEOUT),
|
||||||
'Content-Length': '11',
|
"Content-Length": "11",
|
||||||
'Content-Type': 'application/json',
|
"Content-Type": "application/json",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def test_response_content_length(app):
|
def test_response_content_length(app):
|
||||||
@app.get("/response_with_space")
|
@app.get("/response_with_space")
|
||||||
async def response_with_space(request):
|
async def response_with_space(request):
|
||||||
return json({
|
return json(
|
||||||
"message": "Data",
|
{"message": "Data", "details": "Some Details"},
|
||||||
"details": "Some Details"
|
headers={"CONTENT-TYPE": "application/json"},
|
||||||
}, headers={
|
)
|
||||||
'CONTENT-TYPE': 'application/json'
|
|
||||||
})
|
|
||||||
|
|
||||||
@app.get("/response_without_space")
|
@app.get("/response_without_space")
|
||||||
async def response_without_space(request):
|
async def response_without_space(request):
|
||||||
return json({
|
return json(
|
||||||
"message":"Data",
|
{"message": "Data", "details": "Some Details"},
|
||||||
"details":"Some Details"
|
headers={"CONTENT-TYPE": "application/json"},
|
||||||
}, headers={
|
)
|
||||||
'CONTENT-TYPE': 'application/json'
|
|
||||||
})
|
|
||||||
|
|
||||||
_, response = app.test_client.get("/response_with_space")
|
_, response = app.test_client.get("/response_with_space")
|
||||||
content_length_for_response_with_space = response.headers.get("Content-Length")
|
content_length_for_response_with_space = response.headers.get(
|
||||||
|
"Content-Length"
|
||||||
|
)
|
||||||
|
|
||||||
_, response = app.test_client.get("/response_without_space")
|
_, response = app.test_client.get("/response_without_space")
|
||||||
content_length_for_response_without_space = response.headers.get("Content-Length")
|
content_length_for_response_without_space = response.headers.get(
|
||||||
|
"Content-Length"
|
||||||
|
)
|
||||||
|
|
||||||
assert content_length_for_response_with_space == content_length_for_response_without_space
|
assert (
|
||||||
|
content_length_for_response_with_space
|
||||||
|
== content_length_for_response_without_space
|
||||||
|
)
|
||||||
|
|
||||||
assert content_length_for_response_with_space == '43'
|
assert content_length_for_response_with_space == "43"
|
||||||
|
|
||||||
|
|
||||||
def test_response_content_length_with_different_data_types(app):
|
def test_response_content_length_with_different_data_types(app):
|
||||||
@app.get("/")
|
@app.get("/")
|
||||||
async def get_data_with_different_types(request):
|
async def get_data_with_different_types(request):
|
||||||
# Indentation issues in the Response is intentional. Please do not fix
|
# Indentation issues in the Response is intentional. Please do not fix
|
||||||
return json({
|
return json(
|
||||||
'bool': True,
|
{"bool": True, "none": None, "string": "string", "number": -1},
|
||||||
'none': None,
|
headers={"CONTENT-TYPE": "application/json"},
|
||||||
'string':'string',
|
)
|
||||||
'number': -1},
|
|
||||||
headers={
|
|
||||||
'CONTENT-TYPE': 'application/json'
|
|
||||||
})
|
|
||||||
|
|
||||||
_, response = app.test_client.get("/")
|
_, response = app.test_client.get("/")
|
||||||
assert response.headers.get("Content-Length") == '55'
|
assert response.headers.get("Content-Length") == "55"
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def json_app(app):
|
def json_app(app):
|
||||||
|
|
||||||
@app.route("/")
|
@app.route("/")
|
||||||
async def test(request):
|
async def test(request):
|
||||||
return json(JSON_DATA)
|
return json(JSON_DATA)
|
||||||
|
@ -156,70 +157,72 @@ def json_app(app):
|
||||||
|
|
||||||
def test_json_response(json_app):
|
def test_json_response(json_app):
|
||||||
from sanic.response import json_dumps
|
from sanic.response import json_dumps
|
||||||
request, response = json_app.test_client.get('/')
|
|
||||||
|
request, response = json_app.test_client.get("/")
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == json_dumps(JSON_DATA)
|
assert response.text == json_dumps(JSON_DATA)
|
||||||
assert response.json == JSON_DATA
|
assert response.json == JSON_DATA
|
||||||
|
|
||||||
|
|
||||||
def test_no_content(json_app):
|
def test_no_content(json_app):
|
||||||
request, response = json_app.test_client.get('/no-content')
|
request, response = json_app.test_client.get("/no-content")
|
||||||
assert response.status == 204
|
assert response.status == 204
|
||||||
assert response.text == ''
|
assert response.text == ""
|
||||||
assert 'Content-Length' not in response.headers
|
assert "Content-Length" not in response.headers
|
||||||
|
|
||||||
request, response = json_app.test_client.get('/no-content/unmodified')
|
request, response = json_app.test_client.get("/no-content/unmodified")
|
||||||
assert response.status == 304
|
assert response.status == 304
|
||||||
assert response.text == ''
|
assert response.text == ""
|
||||||
assert 'Content-Length' not in response.headers
|
assert "Content-Length" not in response.headers
|
||||||
assert 'Content-Type' not in response.headers
|
assert "Content-Type" not in response.headers
|
||||||
|
|
||||||
request, response = json_app.test_client.get('/unmodified')
|
request, response = json_app.test_client.get("/unmodified")
|
||||||
assert response.status == 304
|
assert response.status == 304
|
||||||
assert response.text == ''
|
assert response.text == ""
|
||||||
assert 'Content-Length' not in response.headers
|
assert "Content-Length" not in response.headers
|
||||||
assert 'Content-Type' not in response.headers
|
assert "Content-Type" not in response.headers
|
||||||
|
|
||||||
request, response = json_app.test_client.delete('/')
|
request, response = json_app.test_client.delete("/")
|
||||||
assert response.status == 204
|
assert response.status == 204
|
||||||
assert response.text == ''
|
assert response.text == ""
|
||||||
assert 'Content-Length' not in response.headers
|
assert "Content-Length" not in response.headers
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def streaming_app(app):
|
def streaming_app(app):
|
||||||
|
|
||||||
@app.route("/")
|
@app.route("/")
|
||||||
async def test(request):
|
async def test(request):
|
||||||
return stream(sample_streaming_fn, content_type='text/csv')
|
return stream(sample_streaming_fn, content_type="text/csv")
|
||||||
|
|
||||||
return app
|
return app
|
||||||
|
|
||||||
|
|
||||||
def test_streaming_adds_correct_headers(streaming_app):
|
def test_streaming_adds_correct_headers(streaming_app):
|
||||||
request, response = streaming_app.test_client.get('/')
|
request, response = streaming_app.test_client.get("/")
|
||||||
assert response.headers['Transfer-Encoding'] == 'chunked'
|
assert response.headers["Transfer-Encoding"] == "chunked"
|
||||||
assert response.headers['Content-Type'] == 'text/csv'
|
assert response.headers["Content-Type"] == "text/csv"
|
||||||
|
|
||||||
|
|
||||||
def test_streaming_returns_correct_content(streaming_app):
|
def test_streaming_returns_correct_content(streaming_app):
|
||||||
request, response = streaming_app.test_client.get('/')
|
request, response = streaming_app.test_client.get("/")
|
||||||
assert response.text == 'foo,bar'
|
assert response.text == "foo,bar"
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('status', [200, 201, 400, 401])
|
@pytest.mark.parametrize("status", [200, 201, 400, 401])
|
||||||
def test_stream_response_status_returns_correct_headers(status):
|
def test_stream_response_status_returns_correct_headers(status):
|
||||||
response = StreamingHTTPResponse(sample_streaming_fn, status=status)
|
response = StreamingHTTPResponse(sample_streaming_fn, status=status)
|
||||||
headers = response.get_headers()
|
headers = response.get_headers()
|
||||||
assert b"HTTP/1.1 %s" % str(status).encode() in headers
|
assert b"HTTP/1.1 %s" % str(status).encode() in headers
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('keep_alive_timeout', [10, 20, 30])
|
@pytest.mark.parametrize("keep_alive_timeout", [10, 20, 30])
|
||||||
def test_stream_response_keep_alive_returns_correct_headers(
|
def test_stream_response_keep_alive_returns_correct_headers(
|
||||||
keep_alive_timeout):
|
keep_alive_timeout
|
||||||
|
):
|
||||||
response = StreamingHTTPResponse(sample_streaming_fn)
|
response = StreamingHTTPResponse(sample_streaming_fn)
|
||||||
headers = response.get_headers(
|
headers = response.get_headers(
|
||||||
keep_alive=True, keep_alive_timeout=keep_alive_timeout)
|
keep_alive=True, keep_alive_timeout=keep_alive_timeout
|
||||||
|
)
|
||||||
|
|
||||||
assert b"Keep-Alive: %s\r\n" % str(keep_alive_timeout).encode() in headers
|
assert b"Keep-Alive: %s\r\n" % str(keep_alive_timeout).encode() in headers
|
||||||
|
|
||||||
|
@ -244,19 +247,19 @@ def test_stream_response_writes_correct_content_to_transport(streaming_app):
|
||||||
response.protocol.push_data = mock_push_data
|
response.protocol.push_data = mock_push_data
|
||||||
response.protocol.drain = mock_drain
|
response.protocol.drain = mock_drain
|
||||||
|
|
||||||
@streaming_app.listener('after_server_start')
|
@streaming_app.listener("after_server_start")
|
||||||
async def run_stream(app, loop):
|
async def run_stream(app, loop):
|
||||||
await response.stream()
|
await response.stream()
|
||||||
assert response.protocol.transport.write.call_args_list[1][0][0] == (
|
assert response.protocol.transport.write.call_args_list[1][0][0] == (
|
||||||
b'4\r\nfoo,\r\n'
|
b"4\r\nfoo,\r\n"
|
||||||
)
|
)
|
||||||
|
|
||||||
assert response.protocol.transport.write.call_args_list[2][0][0] == (
|
assert response.protocol.transport.write.call_args_list[2][0][0] == (
|
||||||
b'3\r\nbar\r\n'
|
b"3\r\nbar\r\n"
|
||||||
)
|
)
|
||||||
|
|
||||||
assert response.protocol.transport.write.call_args_list[3][0][0] == (
|
assert response.protocol.transport.write.call_args_list[3][0][0] == (
|
||||||
b'0\r\n\r\n'
|
b"0\r\n\r\n"
|
||||||
)
|
)
|
||||||
|
|
||||||
app.stop()
|
app.stop()
|
||||||
|
@ -265,25 +268,23 @@ def test_stream_response_writes_correct_content_to_transport(streaming_app):
|
||||||
|
|
||||||
|
|
||||||
def test_stream_response_with_cookies(app):
|
def test_stream_response_with_cookies(app):
|
||||||
|
|
||||||
@app.route("/")
|
@app.route("/")
|
||||||
async def test(request):
|
async def test(request):
|
||||||
response = stream(sample_streaming_fn, content_type='text/csv')
|
response = stream(sample_streaming_fn, content_type="text/csv")
|
||||||
response.cookies['test'] = 'modified'
|
response.cookies["test"] = "modified"
|
||||||
response.cookies['test'] = 'pass'
|
response.cookies["test"] = "pass"
|
||||||
return response
|
return response
|
||||||
|
|
||||||
request, response = app.test_client.get('/')
|
request, response = app.test_client.get("/")
|
||||||
assert response.cookies['test'].value == 'pass'
|
assert response.cookies["test"].value == "pass"
|
||||||
|
|
||||||
|
|
||||||
def test_stream_response_without_cookies(app):
|
def test_stream_response_without_cookies(app):
|
||||||
|
|
||||||
@app.route("/")
|
@app.route("/")
|
||||||
async def test(request):
|
async def test(request):
|
||||||
return stream(sample_streaming_fn, content_type='text/csv')
|
return stream(sample_streaming_fn, content_type="text/csv")
|
||||||
|
|
||||||
request, response = app.test_client.get('/')
|
request, response = app.test_client.get("/")
|
||||||
assert response.cookies == {}
|
assert response.cookies == {}
|
||||||
|
|
||||||
|
|
||||||
|
@ -292,195 +293,214 @@ def static_file_directory():
|
||||||
"""The static directory to serve"""
|
"""The static directory to serve"""
|
||||||
current_file = inspect.getfile(inspect.currentframe())
|
current_file = inspect.getfile(inspect.currentframe())
|
||||||
current_directory = os.path.dirname(os.path.abspath(current_file))
|
current_directory = os.path.dirname(os.path.abspath(current_file))
|
||||||
static_directory = os.path.join(current_directory, 'static')
|
static_directory = os.path.join(current_directory, "static")
|
||||||
return static_directory
|
return static_directory
|
||||||
|
|
||||||
|
|
||||||
def get_file_content(static_file_directory, file_name):
|
def get_file_content(static_file_directory, file_name):
|
||||||
"""The content of the static file to check"""
|
"""The content of the static file to check"""
|
||||||
with open(os.path.join(static_file_directory, file_name), 'rb') as file:
|
with open(os.path.join(static_file_directory, file_name), "rb") as file:
|
||||||
return file.read()
|
return file.read()
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('file_name',
|
@pytest.mark.parametrize(
|
||||||
['test.file', 'decode me.txt', 'python.png'])
|
"file_name", ["test.file", "decode me.txt", "python.png"]
|
||||||
@pytest.mark.parametrize('status', [200, 401])
|
)
|
||||||
|
@pytest.mark.parametrize("status", [200, 401])
|
||||||
def test_file_response(app, file_name, static_file_directory, status):
|
def test_file_response(app, file_name, static_file_directory, status):
|
||||||
|
@app.route("/files/<filename>", methods=["GET"])
|
||||||
@app.route('/files/<filename>', methods=['GET'])
|
|
||||||
def file_route(request, filename):
|
def file_route(request, filename):
|
||||||
file_path = os.path.join(static_file_directory, filename)
|
file_path = os.path.join(static_file_directory, filename)
|
||||||
file_path = os.path.abspath(unquote(file_path))
|
file_path = os.path.abspath(unquote(file_path))
|
||||||
return file(file_path, status=status,
|
return file(
|
||||||
mime_type=guess_type(file_path)[0] or 'text/plain')
|
file_path,
|
||||||
|
status=status,
|
||||||
|
mime_type=guess_type(file_path)[0] or "text/plain",
|
||||||
|
)
|
||||||
|
|
||||||
request, response = app.test_client.get('/files/{}'.format(file_name))
|
request, response = app.test_client.get("/files/{}".format(file_name))
|
||||||
assert response.status == status
|
assert response.status == status
|
||||||
assert response.body == get_file_content(static_file_directory, file_name)
|
assert response.body == get_file_content(static_file_directory, file_name)
|
||||||
assert 'Content-Disposition' not in response.headers
|
assert "Content-Disposition" not in response.headers
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
'source,dest',
|
"source,dest",
|
||||||
[
|
[
|
||||||
('test.file', 'my_file.txt'), ('decode me.txt', 'readme.md'),
|
("test.file", "my_file.txt"),
|
||||||
('python.png', 'logo.png')
|
("decode me.txt", "readme.md"),
|
||||||
]
|
("python.png", "logo.png"),
|
||||||
|
],
|
||||||
)
|
)
|
||||||
def test_file_response_custom_filename(app, source, dest,
|
def test_file_response_custom_filename(
|
||||||
static_file_directory):
|
app, source, dest, static_file_directory
|
||||||
|
):
|
||||||
@app.route('/files/<filename>', methods=['GET'])
|
@app.route("/files/<filename>", methods=["GET"])
|
||||||
def file_route(request, filename):
|
def file_route(request, filename):
|
||||||
file_path = os.path.join(static_file_directory, filename)
|
file_path = os.path.join(static_file_directory, filename)
|
||||||
file_path = os.path.abspath(unquote(file_path))
|
file_path = os.path.abspath(unquote(file_path))
|
||||||
return file(file_path, filename=dest)
|
return file(file_path, filename=dest)
|
||||||
|
|
||||||
request, response = app.test_client.get('/files/{}'.format(source))
|
request, response = app.test_client.get("/files/{}".format(source))
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.body == get_file_content(static_file_directory, source)
|
assert response.body == get_file_content(static_file_directory, source)
|
||||||
assert response.headers['Content-Disposition'] == \
|
assert response.headers[
|
||||||
'attachment; filename="{}"'.format(dest)
|
"Content-Disposition"
|
||||||
|
] == 'attachment; filename="{}"'.format(dest)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt'])
|
@pytest.mark.parametrize("file_name", ["test.file", "decode me.txt"])
|
||||||
def test_file_head_response(app, file_name, static_file_directory):
|
def test_file_head_response(app, file_name, static_file_directory):
|
||||||
|
@app.route("/files/<filename>", methods=["GET", "HEAD"])
|
||||||
@app.route('/files/<filename>', methods=['GET', 'HEAD'])
|
|
||||||
async def file_route(request, filename):
|
async def file_route(request, filename):
|
||||||
file_path = os.path.join(static_file_directory, filename)
|
file_path = os.path.join(static_file_directory, filename)
|
||||||
file_path = os.path.abspath(unquote(file_path))
|
file_path = os.path.abspath(unquote(file_path))
|
||||||
stats = await async_os.stat(file_path)
|
stats = await async_os.stat(file_path)
|
||||||
headers = dict()
|
headers = dict()
|
||||||
headers['Accept-Ranges'] = 'bytes'
|
headers["Accept-Ranges"] = "bytes"
|
||||||
headers['Content-Length'] = str(stats.st_size)
|
headers["Content-Length"] = str(stats.st_size)
|
||||||
if request.method == "HEAD":
|
if request.method == "HEAD":
|
||||||
return HTTPResponse(
|
return HTTPResponse(
|
||||||
headers=headers,
|
headers=headers,
|
||||||
content_type=guess_type(file_path)[0] or 'text/plain')
|
content_type=guess_type(file_path)[0] or "text/plain",
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
return file(file_path, headers=headers,
|
return file(
|
||||||
mime_type=guess_type(file_path)[0] or 'text/plain')
|
file_path,
|
||||||
|
headers=headers,
|
||||||
|
mime_type=guess_type(file_path)[0] or "text/plain",
|
||||||
|
)
|
||||||
|
|
||||||
request, response = app.test_client.head('/files/{}'.format(file_name))
|
request, response = app.test_client.head("/files/{}".format(file_name))
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert 'Accept-Ranges' in response.headers
|
assert "Accept-Ranges" in response.headers
|
||||||
assert 'Content-Length' in response.headers
|
assert "Content-Length" in response.headers
|
||||||
assert int(response.headers[
|
assert int(response.headers["Content-Length"]) == len(
|
||||||
'Content-Length']) == len(
|
get_file_content(static_file_directory, file_name)
|
||||||
get_file_content(static_file_directory, file_name))
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('file_name',
|
|
||||||
['test.file', 'decode me.txt', 'python.png'])
|
|
||||||
def test_file_stream_response(app, file_name, static_file_directory):
|
|
||||||
|
|
||||||
@app.route('/files/<filename>', methods=['GET'])
|
|
||||||
def file_route(request, filename):
|
|
||||||
file_path = os.path.join(static_file_directory, filename)
|
|
||||||
file_path = os.path.abspath(unquote(file_path))
|
|
||||||
return file_stream(file_path, chunk_size=32,
|
|
||||||
mime_type=guess_type(file_path)[0] or 'text/plain')
|
|
||||||
|
|
||||||
request, response = app.test_client.get('/files/{}'.format(file_name))
|
|
||||||
assert response.status == 200
|
|
||||||
assert response.body == get_file_content(static_file_directory, file_name)
|
|
||||||
assert 'Content-Disposition' not in response.headers
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
'source,dest',
|
"file_name", ["test.file", "decode me.txt", "python.png"]
|
||||||
[
|
|
||||||
('test.file', 'my_file.txt'), ('decode me.txt', 'readme.md'),
|
|
||||||
('python.png', 'logo.png')
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
def test_file_stream_response_custom_filename(app, source, dest,
|
def test_file_stream_response(app, file_name, static_file_directory):
|
||||||
static_file_directory):
|
@app.route("/files/<filename>", methods=["GET"])
|
||||||
|
|
||||||
@app.route('/files/<filename>', methods=['GET'])
|
|
||||||
def file_route(request, filename):
|
|
||||||
file_path = os.path.join(static_file_directory, filename)
|
|
||||||
file_path = os.path.abspath(unquote(file_path))
|
|
||||||
return file_stream(file_path, chunk_size=32, filename=dest)
|
|
||||||
|
|
||||||
request, response = app.test_client.get('/files/{}'.format(source))
|
|
||||||
assert response.status == 200
|
|
||||||
assert response.body == get_file_content(static_file_directory, source)
|
|
||||||
assert response.headers['Content-Disposition'] == \
|
|
||||||
'attachment; filename="{}"'.format(dest)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt'])
|
|
||||||
def test_file_stream_head_response(app, file_name, static_file_directory):
|
|
||||||
|
|
||||||
@app.route('/files/<filename>', methods=['GET', 'HEAD'])
|
|
||||||
async def file_route(request, filename):
|
|
||||||
file_path = os.path.join(static_file_directory, filename)
|
|
||||||
file_path = os.path.abspath(unquote(file_path))
|
|
||||||
headers = dict()
|
|
||||||
headers['Accept-Ranges'] = 'bytes'
|
|
||||||
if request.method == "HEAD":
|
|
||||||
# Return a normal HTTPResponse, not a
|
|
||||||
# StreamingHTTPResponse for a HEAD request
|
|
||||||
stats = await async_os.stat(file_path)
|
|
||||||
headers['Content-Length'] = str(stats.st_size)
|
|
||||||
return HTTPResponse(
|
|
||||||
headers=headers,
|
|
||||||
content_type=guess_type(file_path)[0] or 'text/plain')
|
|
||||||
else:
|
|
||||||
return file_stream(
|
|
||||||
file_path, chunk_size=32, headers=headers,
|
|
||||||
mime_type=guess_type(file_path)[0] or 'text/plain'
|
|
||||||
)
|
|
||||||
|
|
||||||
request, response = app.test_client.head('/files/{}'.format(file_name))
|
|
||||||
assert response.status == 200
|
|
||||||
# A HEAD request should never be streamed/chunked.
|
|
||||||
if 'Transfer-Encoding' in response.headers:
|
|
||||||
assert response.headers['Transfer-Encoding'] != "chunked"
|
|
||||||
assert 'Accept-Ranges' in response.headers
|
|
||||||
# A HEAD request should get the Content-Length too
|
|
||||||
assert 'Content-Length' in response.headers
|
|
||||||
assert int(response.headers[
|
|
||||||
'Content-Length']) == len(
|
|
||||||
get_file_content(static_file_directory, file_name))
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('file_name',
|
|
||||||
['test.file', 'decode me.txt', 'python.png'])
|
|
||||||
@pytest.mark.parametrize('size,start,end', [
|
|
||||||
(1024, 0, 1024),
|
|
||||||
(4096, 1024, 8192),
|
|
||||||
])
|
|
||||||
def test_file_stream_response_range(app, file_name, static_file_directory, size, start, end):
|
|
||||||
|
|
||||||
Range = namedtuple('Range', ['size', 'start', 'end', 'total'])
|
|
||||||
total = len(get_file_content(static_file_directory, file_name))
|
|
||||||
range = Range(size=size, start=start, end=end, total=total)
|
|
||||||
|
|
||||||
@app.route('/files/<filename>', methods=['GET'])
|
|
||||||
def file_route(request, filename):
|
def file_route(request, filename):
|
||||||
file_path = os.path.join(static_file_directory, filename)
|
file_path = os.path.join(static_file_directory, filename)
|
||||||
file_path = os.path.abspath(unquote(file_path))
|
file_path = os.path.abspath(unquote(file_path))
|
||||||
return file_stream(
|
return file_stream(
|
||||||
file_path,
|
file_path,
|
||||||
chunk_size=32,
|
chunk_size=32,
|
||||||
mime_type=guess_type(file_path)[0] or 'text/plain',
|
mime_type=guess_type(file_path)[0] or "text/plain",
|
||||||
_range=range)
|
)
|
||||||
|
|
||||||
request, response = app.test_client.get('/files/{}'.format(file_name))
|
request, response = app.test_client.get("/files/{}".format(file_name))
|
||||||
|
assert response.status == 200
|
||||||
|
assert response.body == get_file_content(static_file_directory, file_name)
|
||||||
|
assert "Content-Disposition" not in response.headers
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"source,dest",
|
||||||
|
[
|
||||||
|
("test.file", "my_file.txt"),
|
||||||
|
("decode me.txt", "readme.md"),
|
||||||
|
("python.png", "logo.png"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_file_stream_response_custom_filename(
|
||||||
|
app, source, dest, static_file_directory
|
||||||
|
):
|
||||||
|
@app.route("/files/<filename>", methods=["GET"])
|
||||||
|
def file_route(request, filename):
|
||||||
|
file_path = os.path.join(static_file_directory, filename)
|
||||||
|
file_path = os.path.abspath(unquote(file_path))
|
||||||
|
return file_stream(file_path, chunk_size=32, filename=dest)
|
||||||
|
|
||||||
|
request, response = app.test_client.get("/files/{}".format(source))
|
||||||
|
assert response.status == 200
|
||||||
|
assert response.body == get_file_content(static_file_directory, source)
|
||||||
|
assert response.headers[
|
||||||
|
"Content-Disposition"
|
||||||
|
] == 'attachment; filename="{}"'.format(dest)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("file_name", ["test.file", "decode me.txt"])
|
||||||
|
def test_file_stream_head_response(app, file_name, static_file_directory):
|
||||||
|
@app.route("/files/<filename>", methods=["GET", "HEAD"])
|
||||||
|
async def file_route(request, filename):
|
||||||
|
file_path = os.path.join(static_file_directory, filename)
|
||||||
|
file_path = os.path.abspath(unquote(file_path))
|
||||||
|
headers = dict()
|
||||||
|
headers["Accept-Ranges"] = "bytes"
|
||||||
|
if request.method == "HEAD":
|
||||||
|
# Return a normal HTTPResponse, not a
|
||||||
|
# StreamingHTTPResponse for a HEAD request
|
||||||
|
stats = await async_os.stat(file_path)
|
||||||
|
headers["Content-Length"] = str(stats.st_size)
|
||||||
|
return HTTPResponse(
|
||||||
|
headers=headers,
|
||||||
|
content_type=guess_type(file_path)[0] or "text/plain",
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return file_stream(
|
||||||
|
file_path,
|
||||||
|
chunk_size=32,
|
||||||
|
headers=headers,
|
||||||
|
mime_type=guess_type(file_path)[0] or "text/plain",
|
||||||
|
)
|
||||||
|
|
||||||
|
request, response = app.test_client.head("/files/{}".format(file_name))
|
||||||
|
assert response.status == 200
|
||||||
|
# A HEAD request should never be streamed/chunked.
|
||||||
|
if "Transfer-Encoding" in response.headers:
|
||||||
|
assert response.headers["Transfer-Encoding"] != "chunked"
|
||||||
|
assert "Accept-Ranges" in response.headers
|
||||||
|
# A HEAD request should get the Content-Length too
|
||||||
|
assert "Content-Length" in response.headers
|
||||||
|
assert int(response.headers["Content-Length"]) == len(
|
||||||
|
get_file_content(static_file_directory, file_name)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"file_name", ["test.file", "decode me.txt", "python.png"]
|
||||||
|
)
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"size,start,end", [(1024, 0, 1024), (4096, 1024, 8192)]
|
||||||
|
)
|
||||||
|
def test_file_stream_response_range(
|
||||||
|
app, file_name, static_file_directory, size, start, end
|
||||||
|
):
|
||||||
|
|
||||||
|
Range = namedtuple("Range", ["size", "start", "end", "total"])
|
||||||
|
total = len(get_file_content(static_file_directory, file_name))
|
||||||
|
range = Range(size=size, start=start, end=end, total=total)
|
||||||
|
|
||||||
|
@app.route("/files/<filename>", methods=["GET"])
|
||||||
|
def file_route(request, filename):
|
||||||
|
file_path = os.path.join(static_file_directory, filename)
|
||||||
|
file_path = os.path.abspath(unquote(file_path))
|
||||||
|
return file_stream(
|
||||||
|
file_path,
|
||||||
|
chunk_size=32,
|
||||||
|
mime_type=guess_type(file_path)[0] or "text/plain",
|
||||||
|
_range=range,
|
||||||
|
)
|
||||||
|
|
||||||
|
request, response = app.test_client.get("/files/{}".format(file_name))
|
||||||
assert response.status == 206
|
assert response.status == 206
|
||||||
assert 'Content-Range' in response.headers
|
assert "Content-Range" in response.headers
|
||||||
assert response.headers['Content-Range'] == 'bytes {}-{}/{}'.format(range.start, range.end, range.total)
|
assert response.headers["Content-Range"] == "bytes {}-{}/{}".format(
|
||||||
|
range.start, range.end, range.total
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_raw_response(app):
|
def test_raw_response(app):
|
||||||
|
@app.get("/test")
|
||||||
@app.get('/test')
|
|
||||||
def handler(request):
|
def handler(request):
|
||||||
return raw(b'raw_response')
|
return raw(b"raw_response")
|
||||||
|
|
||||||
request, response = app.test_client.get('/test')
|
request, response = app.test_client.get("/test")
|
||||||
assert response.content_type == 'application/octet-stream'
|
assert response.content_type == "application/octet-stream"
|
||||||
assert response.body == b'raw_response'
|
assert response.body == b"raw_response"
|
||||||
|
|
|
@ -5,38 +5,38 @@ from sanic.exceptions import ServiceUnavailable
|
||||||
from sanic.config import Config
|
from sanic.config import Config
|
||||||
|
|
||||||
Config.RESPONSE_TIMEOUT = 1
|
Config.RESPONSE_TIMEOUT = 1
|
||||||
response_timeout_app = Sanic('test_response_timeout')
|
response_timeout_app = Sanic("test_response_timeout")
|
||||||
response_timeout_default_app = Sanic('test_response_timeout_default')
|
response_timeout_default_app = Sanic("test_response_timeout_default")
|
||||||
response_handler_cancelled_app = Sanic('test_response_handler_cancelled')
|
response_handler_cancelled_app = Sanic("test_response_handler_cancelled")
|
||||||
|
|
||||||
|
|
||||||
@response_timeout_app.route('/1')
|
@response_timeout_app.route("/1")
|
||||||
async def handler_1(request):
|
async def handler_1(request):
|
||||||
await asyncio.sleep(2)
|
await asyncio.sleep(2)
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
|
|
||||||
@response_timeout_app.exception(ServiceUnavailable)
|
@response_timeout_app.exception(ServiceUnavailable)
|
||||||
def handler_exception(request, exception):
|
def handler_exception(request, exception):
|
||||||
return text('Response Timeout from error_handler.', 503)
|
return text("Response Timeout from error_handler.", 503)
|
||||||
|
|
||||||
|
|
||||||
def test_server_error_response_timeout():
|
def test_server_error_response_timeout():
|
||||||
request, response = response_timeout_app.test_client.get('/1')
|
request, response = response_timeout_app.test_client.get("/1")
|
||||||
assert response.status == 503
|
assert response.status == 503
|
||||||
assert response.text == 'Response Timeout from error_handler.'
|
assert response.text == "Response Timeout from error_handler."
|
||||||
|
|
||||||
|
|
||||||
@response_timeout_default_app.route('/1')
|
@response_timeout_default_app.route("/1")
|
||||||
async def handler_2(request):
|
async def handler_2(request):
|
||||||
await asyncio.sleep(2)
|
await asyncio.sleep(2)
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
|
|
||||||
def test_default_server_error_response_timeout():
|
def test_default_server_error_response_timeout():
|
||||||
request, response = response_timeout_default_app.test_client.get('/1')
|
request, response = response_timeout_default_app.test_client.get("/1")
|
||||||
assert response.status == 503
|
assert response.status == 503
|
||||||
assert response.text == 'Error: Response Timeout'
|
assert response.text == "Error: Response Timeout"
|
||||||
|
|
||||||
|
|
||||||
response_handler_cancelled_app.flag = False
|
response_handler_cancelled_app.flag = False
|
||||||
|
@ -52,14 +52,14 @@ def handler_cancelled(request, exception):
|
||||||
# is already closed when we get a CancelledError.
|
# is already closed when we get a CancelledError.
|
||||||
|
|
||||||
|
|
||||||
@response_handler_cancelled_app.route('/1')
|
@response_handler_cancelled_app.route("/1")
|
||||||
async def handler_3(request):
|
async def handler_3(request):
|
||||||
await asyncio.sleep(2)
|
await asyncio.sleep(2)
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
|
|
||||||
def test_response_handler_cancelled():
|
def test_response_handler_cancelled():
|
||||||
request, response = response_handler_cancelled_app.test_client.get('/1')
|
request, response = response_handler_cancelled_app.test_client.get("/1")
|
||||||
assert response.status == 503
|
assert response.status == 503
|
||||||
assert response.text == 'Error: Response Timeout'
|
assert response.text == "Error: Response Timeout"
|
||||||
assert response_handler_cancelled_app.flag is False
|
assert response_handler_cancelled_app.flag is False
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -5,30 +5,30 @@ import pytest
|
||||||
from sanic.testing import HOST, PORT
|
from sanic.testing import HOST, PORT
|
||||||
|
|
||||||
AVAILABLE_LISTENERS = [
|
AVAILABLE_LISTENERS = [
|
||||||
'before_server_start',
|
"before_server_start",
|
||||||
'after_server_start',
|
"after_server_start",
|
||||||
'before_server_stop',
|
"before_server_stop",
|
||||||
'after_server_stop'
|
"after_server_stop",
|
||||||
]
|
]
|
||||||
|
|
||||||
skipif_no_alarm = pytest.mark.skipif(
|
skipif_no_alarm = pytest.mark.skipif(
|
||||||
not hasattr(signal, 'SIGALRM'),
|
not hasattr(signal, "SIGALRM"),
|
||||||
reason='SIGALRM is not implemented for this platform, we have to come '
|
reason="SIGALRM is not implemented for this platform, we have to come "
|
||||||
'up with another timeout strategy to test these'
|
"up with another timeout strategy to test these",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def create_listener(listener_name, in_list):
|
def create_listener(listener_name, in_list):
|
||||||
async def _listener(app, loop):
|
async def _listener(app, loop):
|
||||||
print('DEBUG MESSAGE FOR PYTEST for {}'.format(listener_name))
|
print("DEBUG MESSAGE FOR PYTEST for {}".format(listener_name))
|
||||||
in_list.insert(0, app.name + listener_name)
|
in_list.insert(0, app.name + listener_name)
|
||||||
|
|
||||||
return _listener
|
return _listener
|
||||||
|
|
||||||
|
|
||||||
def start_stop_app(random_name_app, **run_kwargs):
|
def start_stop_app(random_name_app, **run_kwargs):
|
||||||
|
|
||||||
def stop_on_alarm(signum, frame):
|
def stop_on_alarm(signum, frame):
|
||||||
raise KeyboardInterrupt('SIGINT for sanic to stop gracefully')
|
raise KeyboardInterrupt("SIGINT for sanic to stop gracefully")
|
||||||
|
|
||||||
signal.signal(signal.SIGALRM, stop_on_alarm)
|
signal.signal(signal.SIGALRM, stop_on_alarm)
|
||||||
signal.alarm(1)
|
signal.alarm(1)
|
||||||
|
@ -39,19 +39,18 @@ def start_stop_app(random_name_app, **run_kwargs):
|
||||||
|
|
||||||
|
|
||||||
@skipif_no_alarm
|
@skipif_no_alarm
|
||||||
@pytest.mark.parametrize('listener_name', AVAILABLE_LISTENERS)
|
@pytest.mark.parametrize("listener_name", AVAILABLE_LISTENERS)
|
||||||
def test_single_listener(app, listener_name):
|
def test_single_listener(app, listener_name):
|
||||||
"""Test that listeners on their own work"""
|
"""Test that listeners on their own work"""
|
||||||
output = []
|
output = []
|
||||||
# Register listener
|
# Register listener
|
||||||
app.listener(listener_name)(
|
app.listener(listener_name)(create_listener(listener_name, output))
|
||||||
create_listener(listener_name, output))
|
|
||||||
start_stop_app(app)
|
start_stop_app(app)
|
||||||
assert app.name + listener_name == output.pop()
|
assert app.name + listener_name == output.pop()
|
||||||
|
|
||||||
|
|
||||||
@skipif_no_alarm
|
@skipif_no_alarm
|
||||||
@pytest.mark.parametrize('listener_name', AVAILABLE_LISTENERS)
|
@pytest.mark.parametrize("listener_name", AVAILABLE_LISTENERS)
|
||||||
def test_register_listener(app, listener_name):
|
def test_register_listener(app, listener_name):
|
||||||
"""
|
"""
|
||||||
Test that listeners on their own work with
|
Test that listeners on their own work with
|
||||||
|
@ -77,11 +76,10 @@ def test_all_listeners(app):
|
||||||
|
|
||||||
|
|
||||||
async def test_trigger_before_events_create_server(app):
|
async def test_trigger_before_events_create_server(app):
|
||||||
|
|
||||||
class MySanicDb:
|
class MySanicDb:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@app.listener('before_server_start')
|
@app.listener("before_server_start")
|
||||||
async def init_db(app, loop):
|
async def init_db(app, loop):
|
||||||
app.db = MySanicDb()
|
app.db = MySanicDb()
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ async def stop(app, loop):
|
||||||
await asyncio.sleep(0.1)
|
await asyncio.sleep(0.1)
|
||||||
app.stop()
|
app.stop()
|
||||||
|
|
||||||
|
|
||||||
calledq = Queue()
|
calledq = Queue()
|
||||||
|
|
||||||
|
|
||||||
|
@ -23,13 +24,13 @@ def after(app, loop):
|
||||||
def test_register_system_signals(app):
|
def test_register_system_signals(app):
|
||||||
"""Test if sanic register system signals"""
|
"""Test if sanic register system signals"""
|
||||||
|
|
||||||
@app.route('/hello')
|
@app.route("/hello")
|
||||||
async def hello_route(request):
|
async def hello_route(request):
|
||||||
return HTTPResponse()
|
return HTTPResponse()
|
||||||
|
|
||||||
app.listener('after_server_start')(stop)
|
app.listener("after_server_start")(stop)
|
||||||
app.listener('before_server_start')(set_loop)
|
app.listener("before_server_start")(set_loop)
|
||||||
app.listener('after_server_stop')(after)
|
app.listener("after_server_stop")(after)
|
||||||
|
|
||||||
app.run(HOST, PORT)
|
app.run(HOST, PORT)
|
||||||
assert calledq.get() is True
|
assert calledq.get() is True
|
||||||
|
@ -38,13 +39,13 @@ def test_register_system_signals(app):
|
||||||
def test_dont_register_system_signals(app):
|
def test_dont_register_system_signals(app):
|
||||||
"""Test if sanic don't register system signals"""
|
"""Test if sanic don't register system signals"""
|
||||||
|
|
||||||
@app.route('/hello')
|
@app.route("/hello")
|
||||||
async def hello_route(request):
|
async def hello_route(request):
|
||||||
return HTTPResponse()
|
return HTTPResponse()
|
||||||
|
|
||||||
app.listener('after_server_start')(stop)
|
app.listener("after_server_start")(stop)
|
||||||
app.listener('before_server_start')(set_loop)
|
app.listener("before_server_start")(set_loop)
|
||||||
app.listener('after_server_stop')(after)
|
app.listener("after_server_stop")(after)
|
||||||
|
|
||||||
app.run(HOST, PORT, register_sys_signals=False)
|
app.run(HOST, PORT, register_sys_signals=False)
|
||||||
assert calledq.get() is False
|
assert calledq.get() is False
|
||||||
|
|
|
@ -5,12 +5,12 @@ from time import gmtime, strftime
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope='module')
|
@pytest.fixture(scope="module")
|
||||||
def static_file_directory():
|
def static_file_directory():
|
||||||
"""The static directory to serve"""
|
"""The static directory to serve"""
|
||||||
current_file = inspect.getfile(inspect.currentframe())
|
current_file = inspect.getfile(inspect.currentframe())
|
||||||
current_directory = os.path.dirname(os.path.abspath(current_file))
|
current_directory = os.path.dirname(os.path.abspath(current_file))
|
||||||
static_directory = os.path.join(current_directory, 'static')
|
static_directory = os.path.join(current_directory, "static")
|
||||||
return static_directory
|
return static_directory
|
||||||
|
|
||||||
|
|
||||||
|
@ -20,336 +20,376 @@ def get_file_path(static_file_directory, file_name):
|
||||||
|
|
||||||
def get_file_content(static_file_directory, file_name):
|
def get_file_content(static_file_directory, file_name):
|
||||||
"""The content of the static file to check"""
|
"""The content of the static file to check"""
|
||||||
with open(get_file_path(static_file_directory, file_name), 'rb') as file:
|
with open(get_file_path(static_file_directory, file_name), "rb") as file:
|
||||||
return file.read()
|
return file.read()
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope='module')
|
@pytest.fixture(scope="module")
|
||||||
def large_file(static_file_directory):
|
def large_file(static_file_directory):
|
||||||
large_file_path = os.path.join(static_file_directory, 'large.file')
|
large_file_path = os.path.join(static_file_directory, "large.file")
|
||||||
|
|
||||||
size = 2 * 1024 * 1024
|
size = 2 * 1024 * 1024
|
||||||
with open(large_file_path, 'w') as f:
|
with open(large_file_path, "w") as f:
|
||||||
f.write('a' * size)
|
f.write("a" * size)
|
||||||
|
|
||||||
yield large_file_path
|
yield large_file_path
|
||||||
|
|
||||||
os.remove(large_file_path)
|
os.remove(large_file_path)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(autouse=True, scope='module')
|
@pytest.fixture(autouse=True, scope="module")
|
||||||
def symlink(static_file_directory):
|
def symlink(static_file_directory):
|
||||||
src = os.path.abspath(os.path.join(os.path.dirname(static_file_directory), 'conftest.py'))
|
src = os.path.abspath(
|
||||||
symlink = 'symlink'
|
os.path.join(os.path.dirname(static_file_directory), "conftest.py")
|
||||||
|
)
|
||||||
|
symlink = "symlink"
|
||||||
dist = os.path.join(static_file_directory, symlink)
|
dist = os.path.join(static_file_directory, symlink)
|
||||||
os.symlink(src, dist)
|
os.symlink(src, dist)
|
||||||
yield symlink
|
yield symlink
|
||||||
os.remove(dist)
|
os.remove(dist)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(autouse=True, scope='module')
|
@pytest.fixture(autouse=True, scope="module")
|
||||||
def hard_link(static_file_directory):
|
def hard_link(static_file_directory):
|
||||||
src = os.path.abspath(os.path.join(os.path.dirname(static_file_directory), 'conftest.py'))
|
src = os.path.abspath(
|
||||||
hard_link = 'hard_link'
|
os.path.join(os.path.dirname(static_file_directory), "conftest.py")
|
||||||
|
)
|
||||||
|
hard_link = "hard_link"
|
||||||
dist = os.path.join(static_file_directory, hard_link)
|
dist = os.path.join(static_file_directory, hard_link)
|
||||||
os.link(src, dist)
|
os.link(src, dist)
|
||||||
yield hard_link
|
yield hard_link
|
||||||
os.remove(dist)
|
os.remove(dist)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('file_name',
|
@pytest.mark.parametrize(
|
||||||
['test.file', 'decode me.txt', 'python.png', 'symlink', 'hard_link'])
|
"file_name",
|
||||||
|
["test.file", "decode me.txt", "python.png", "symlink", "hard_link"],
|
||||||
|
)
|
||||||
def test_static_file(app, static_file_directory, file_name):
|
def test_static_file(app, static_file_directory, file_name):
|
||||||
app.static(
|
app.static(
|
||||||
'/testing.file', get_file_path(static_file_directory, file_name))
|
"/testing.file", get_file_path(static_file_directory, file_name)
|
||||||
|
|
||||||
request, response = app.test_client.get('/testing.file')
|
|
||||||
assert response.status == 200
|
|
||||||
assert response.body == get_file_content(static_file_directory, file_name)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('file_name', ['test.html'])
|
|
||||||
def test_static_file_content_type(app, static_file_directory, file_name):
|
|
||||||
app.static(
|
|
||||||
'/testing.file',
|
|
||||||
get_file_path(static_file_directory, file_name),
|
|
||||||
content_type='text/html; charset=utf-8'
|
|
||||||
)
|
)
|
||||||
|
|
||||||
request, response = app.test_client.get('/testing.file')
|
request, response = app.test_client.get("/testing.file")
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.body == get_file_content(static_file_directory, file_name)
|
assert response.body == get_file_content(static_file_directory, file_name)
|
||||||
assert response.headers['Content-Type'] == 'text/html; charset=utf-8'
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt', 'symlink', 'hard_link'])
|
@pytest.mark.parametrize("file_name", ["test.html"])
|
||||||
@pytest.mark.parametrize('base_uri', ['/static', '', '/dir'])
|
def test_static_file_content_type(app, static_file_directory, file_name):
|
||||||
|
app.static(
|
||||||
|
"/testing.file",
|
||||||
|
get_file_path(static_file_directory, file_name),
|
||||||
|
content_type="text/html; charset=utf-8",
|
||||||
|
)
|
||||||
|
|
||||||
|
request, response = app.test_client.get("/testing.file")
|
||||||
|
assert response.status == 200
|
||||||
|
assert response.body == get_file_content(static_file_directory, file_name)
|
||||||
|
assert response.headers["Content-Type"] == "text/html; charset=utf-8"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"file_name", ["test.file", "decode me.txt", "symlink", "hard_link"]
|
||||||
|
)
|
||||||
|
@pytest.mark.parametrize("base_uri", ["/static", "", "/dir"])
|
||||||
def test_static_directory(app, file_name, base_uri, static_file_directory):
|
def test_static_directory(app, file_name, base_uri, static_file_directory):
|
||||||
app.static(base_uri, static_file_directory)
|
app.static(base_uri, static_file_directory)
|
||||||
|
|
||||||
request, response = app.test_client.get(
|
request, response = app.test_client.get(
|
||||||
uri='{}/{}'.format(base_uri, file_name))
|
uri="{}/{}".format(base_uri, file_name)
|
||||||
|
)
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.body == get_file_content(static_file_directory, file_name)
|
assert response.body == get_file_content(static_file_directory, file_name)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt'])
|
@pytest.mark.parametrize("file_name", ["test.file", "decode me.txt"])
|
||||||
def test_static_head_request(app, file_name, static_file_directory):
|
def test_static_head_request(app, file_name, static_file_directory):
|
||||||
app.static(
|
app.static(
|
||||||
'/testing.file', get_file_path(static_file_directory, file_name),
|
"/testing.file",
|
||||||
use_content_range=True)
|
|
||||||
|
|
||||||
request, response = app.test_client.head('/testing.file')
|
|
||||||
assert response.status == 200
|
|
||||||
assert 'Accept-Ranges' in response.headers
|
|
||||||
assert 'Content-Length' in response.headers
|
|
||||||
assert int(response.headers[
|
|
||||||
'Content-Length']) == len(
|
|
||||||
get_file_content(static_file_directory, file_name))
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt'])
|
|
||||||
def test_static_content_range_correct(app, file_name, static_file_directory):
|
|
||||||
app.static(
|
|
||||||
'/testing.file', get_file_path(static_file_directory, file_name),
|
|
||||||
use_content_range=True)
|
|
||||||
|
|
||||||
headers = {
|
|
||||||
'Range': 'bytes=12-19'
|
|
||||||
}
|
|
||||||
request, response = app.test_client.get('/testing.file', headers=headers)
|
|
||||||
assert response.status == 206
|
|
||||||
assert 'Content-Length' in response.headers
|
|
||||||
assert 'Content-Range' in response.headers
|
|
||||||
static_content = bytes(get_file_content(
|
|
||||||
static_file_directory, file_name))[12:20]
|
|
||||||
assert int(response.headers[
|
|
||||||
'Content-Length']) == len(static_content)
|
|
||||||
assert response.body == static_content
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt'])
|
|
||||||
def test_static_content_range_front(app, file_name, static_file_directory):
|
|
||||||
app.static(
|
|
||||||
'/testing.file', get_file_path(static_file_directory, file_name),
|
|
||||||
use_content_range=True)
|
|
||||||
|
|
||||||
headers = {
|
|
||||||
'Range': 'bytes=12-'
|
|
||||||
}
|
|
||||||
request, response = app.test_client.get('/testing.file', headers=headers)
|
|
||||||
assert response.status == 206
|
|
||||||
assert 'Content-Length' in response.headers
|
|
||||||
assert 'Content-Range' in response.headers
|
|
||||||
static_content = bytes(get_file_content(
|
|
||||||
static_file_directory, file_name))[12:]
|
|
||||||
assert int(response.headers[
|
|
||||||
'Content-Length']) == len(static_content)
|
|
||||||
assert response.body == static_content
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt'])
|
|
||||||
def test_static_content_range_back(app, file_name, static_file_directory):
|
|
||||||
app.static(
|
|
||||||
'/testing.file', get_file_path(static_file_directory, file_name),
|
|
||||||
use_content_range=True)
|
|
||||||
|
|
||||||
headers = {
|
|
||||||
'Range': 'bytes=-12'
|
|
||||||
}
|
|
||||||
request, response = app.test_client.get('/testing.file', headers=headers)
|
|
||||||
assert response.status == 206
|
|
||||||
assert 'Content-Length' in response.headers
|
|
||||||
assert 'Content-Range' in response.headers
|
|
||||||
static_content = bytes(get_file_content(
|
|
||||||
static_file_directory, file_name))[-12:]
|
|
||||||
assert int(response.headers[
|
|
||||||
'Content-Length']) == len(static_content)
|
|
||||||
assert response.body == static_content
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('use_modified_since', [True, False])
|
|
||||||
@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt'])
|
|
||||||
def test_static_content_range_empty(app, file_name, static_file_directory, use_modified_since):
|
|
||||||
app.static(
|
|
||||||
'/testing.file',
|
|
||||||
get_file_path(static_file_directory, file_name),
|
get_file_path(static_file_directory, file_name),
|
||||||
use_content_range=True,
|
use_content_range=True,
|
||||||
use_modified_since=use_modified_since
|
|
||||||
)
|
)
|
||||||
|
|
||||||
request, response = app.test_client.get('/testing.file')
|
request, response = app.test_client.head("/testing.file")
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert 'Content-Length' in response.headers
|
assert "Accept-Ranges" in response.headers
|
||||||
assert 'Content-Range' not in response.headers
|
assert "Content-Length" in response.headers
|
||||||
assert int(response.headers['Content-Length']) == \
|
assert int(response.headers["Content-Length"]) == len(
|
||||||
len(get_file_content(static_file_directory, file_name))
|
get_file_content(static_file_directory, file_name)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("file_name", ["test.file", "decode me.txt"])
|
||||||
|
def test_static_content_range_correct(app, file_name, static_file_directory):
|
||||||
|
app.static(
|
||||||
|
"/testing.file",
|
||||||
|
get_file_path(static_file_directory, file_name),
|
||||||
|
use_content_range=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
headers = {"Range": "bytes=12-19"}
|
||||||
|
request, response = app.test_client.get("/testing.file", headers=headers)
|
||||||
|
assert response.status == 206
|
||||||
|
assert "Content-Length" in response.headers
|
||||||
|
assert "Content-Range" in response.headers
|
||||||
|
static_content = bytes(get_file_content(static_file_directory, file_name))[
|
||||||
|
12:20
|
||||||
|
]
|
||||||
|
assert int(response.headers["Content-Length"]) == len(static_content)
|
||||||
|
assert response.body == static_content
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("file_name", ["test.file", "decode me.txt"])
|
||||||
|
def test_static_content_range_front(app, file_name, static_file_directory):
|
||||||
|
app.static(
|
||||||
|
"/testing.file",
|
||||||
|
get_file_path(static_file_directory, file_name),
|
||||||
|
use_content_range=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
headers = {"Range": "bytes=12-"}
|
||||||
|
request, response = app.test_client.get("/testing.file", headers=headers)
|
||||||
|
assert response.status == 206
|
||||||
|
assert "Content-Length" in response.headers
|
||||||
|
assert "Content-Range" in response.headers
|
||||||
|
static_content = bytes(get_file_content(static_file_directory, file_name))[
|
||||||
|
12:
|
||||||
|
]
|
||||||
|
assert int(response.headers["Content-Length"]) == len(static_content)
|
||||||
|
assert response.body == static_content
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("file_name", ["test.file", "decode me.txt"])
|
||||||
|
def test_static_content_range_back(app, file_name, static_file_directory):
|
||||||
|
app.static(
|
||||||
|
"/testing.file",
|
||||||
|
get_file_path(static_file_directory, file_name),
|
||||||
|
use_content_range=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
headers = {"Range": "bytes=-12"}
|
||||||
|
request, response = app.test_client.get("/testing.file", headers=headers)
|
||||||
|
assert response.status == 206
|
||||||
|
assert "Content-Length" in response.headers
|
||||||
|
assert "Content-Range" in response.headers
|
||||||
|
static_content = bytes(get_file_content(static_file_directory, file_name))[
|
||||||
|
-12:
|
||||||
|
]
|
||||||
|
assert int(response.headers["Content-Length"]) == len(static_content)
|
||||||
|
assert response.body == static_content
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("use_modified_since", [True, False])
|
||||||
|
@pytest.mark.parametrize("file_name", ["test.file", "decode me.txt"])
|
||||||
|
def test_static_content_range_empty(
|
||||||
|
app, file_name, static_file_directory, use_modified_since
|
||||||
|
):
|
||||||
|
app.static(
|
||||||
|
"/testing.file",
|
||||||
|
get_file_path(static_file_directory, file_name),
|
||||||
|
use_content_range=True,
|
||||||
|
use_modified_since=use_modified_since,
|
||||||
|
)
|
||||||
|
|
||||||
|
request, response = app.test_client.get("/testing.file")
|
||||||
|
assert response.status == 200
|
||||||
|
assert "Content-Length" in response.headers
|
||||||
|
assert "Content-Range" not in response.headers
|
||||||
|
assert int(response.headers["Content-Length"]) == len(
|
||||||
|
get_file_content(static_file_directory, file_name)
|
||||||
|
)
|
||||||
assert response.body == bytes(
|
assert response.body == bytes(
|
||||||
get_file_content(static_file_directory, file_name))
|
get_file_content(static_file_directory, file_name)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt'])
|
@pytest.mark.parametrize("file_name", ["test.file", "decode me.txt"])
|
||||||
def test_static_content_range_error(app, file_name, static_file_directory):
|
def test_static_content_range_error(app, file_name, static_file_directory):
|
||||||
app.static(
|
app.static(
|
||||||
'/testing.file', get_file_path(static_file_directory, file_name),
|
"/testing.file",
|
||||||
use_content_range=True)
|
get_file_path(static_file_directory, file_name),
|
||||||
|
use_content_range=True,
|
||||||
|
)
|
||||||
|
|
||||||
headers = {
|
headers = {"Range": "bytes=1-0"}
|
||||||
'Range': 'bytes=1-0'
|
request, response = app.test_client.get("/testing.file", headers=headers)
|
||||||
}
|
|
||||||
request, response = app.test_client.get('/testing.file', headers=headers)
|
|
||||||
assert response.status == 416
|
assert response.status == 416
|
||||||
assert 'Content-Length' in response.headers
|
assert "Content-Length" in response.headers
|
||||||
assert 'Content-Range' in response.headers
|
assert "Content-Range" in response.headers
|
||||||
assert response.headers['Content-Range'] == "bytes */%s" % (
|
assert response.headers["Content-Range"] == "bytes */%s" % (
|
||||||
len(get_file_content(static_file_directory, file_name)),)
|
len(get_file_content(static_file_directory, file_name)),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt'])
|
@pytest.mark.parametrize("file_name", ["test.file", "decode me.txt"])
|
||||||
def test_static_content_range_invalid_unit(app, file_name, static_file_directory):
|
def test_static_content_range_invalid_unit(
|
||||||
|
app, file_name, static_file_directory
|
||||||
|
):
|
||||||
app.static(
|
app.static(
|
||||||
'/testing.file', get_file_path(static_file_directory, file_name),
|
"/testing.file",
|
||||||
use_content_range=True)
|
get_file_path(static_file_directory, file_name),
|
||||||
|
use_content_range=True,
|
||||||
|
)
|
||||||
|
|
||||||
unit = 'bit'
|
unit = "bit"
|
||||||
headers = {
|
headers = {"Range": "{}=1-0".format(unit)}
|
||||||
'Range': '{}=1-0'.format(unit)
|
request, response = app.test_client.get("/testing.file", headers=headers)
|
||||||
}
|
|
||||||
request, response = app.test_client.get('/testing.file', headers=headers)
|
|
||||||
|
|
||||||
assert response.status == 416
|
assert response.status == 416
|
||||||
assert response.text == "Error: {} is not a valid Range Type".format(unit)
|
assert response.text == "Error: {} is not a valid Range Type".format(unit)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt'])
|
@pytest.mark.parametrize("file_name", ["test.file", "decode me.txt"])
|
||||||
def test_static_content_range_invalid_start(app, file_name, static_file_directory):
|
def test_static_content_range_invalid_start(
|
||||||
|
app, file_name, static_file_directory
|
||||||
|
):
|
||||||
app.static(
|
app.static(
|
||||||
'/testing.file', get_file_path(static_file_directory, file_name),
|
"/testing.file",
|
||||||
use_content_range=True)
|
get_file_path(static_file_directory, file_name),
|
||||||
|
use_content_range=True,
|
||||||
|
)
|
||||||
|
|
||||||
start = 'start'
|
start = "start"
|
||||||
headers = {
|
headers = {"Range": "bytes={}-0".format(start)}
|
||||||
'Range': 'bytes={}-0'.format(start)
|
request, response = app.test_client.get("/testing.file", headers=headers)
|
||||||
}
|
|
||||||
request, response = app.test_client.get('/testing.file', headers=headers)
|
|
||||||
|
|
||||||
assert response.status == 416
|
assert response.status == 416
|
||||||
assert response.text == "Error: '{}' is invalid for Content Range".format(start)
|
assert response.text == "Error: '{}' is invalid for Content Range".format(
|
||||||
|
start
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt'])
|
@pytest.mark.parametrize("file_name", ["test.file", "decode me.txt"])
|
||||||
def test_static_content_range_invalid_end(app, file_name, static_file_directory):
|
def test_static_content_range_invalid_end(
|
||||||
|
app, file_name, static_file_directory
|
||||||
|
):
|
||||||
app.static(
|
app.static(
|
||||||
'/testing.file', get_file_path(static_file_directory, file_name),
|
"/testing.file",
|
||||||
use_content_range=True)
|
get_file_path(static_file_directory, file_name),
|
||||||
|
use_content_range=True,
|
||||||
|
)
|
||||||
|
|
||||||
end = 'end'
|
end = "end"
|
||||||
headers = {
|
headers = {"Range": "bytes=1-{}".format(end)}
|
||||||
'Range': 'bytes=1-{}'.format(end)
|
request, response = app.test_client.get("/testing.file", headers=headers)
|
||||||
}
|
|
||||||
request, response = app.test_client.get('/testing.file', headers=headers)
|
|
||||||
|
|
||||||
assert response.status == 416
|
assert response.status == 416
|
||||||
assert response.text == "Error: '{}' is invalid for Content Range".format(end)
|
assert response.text == "Error: '{}' is invalid for Content Range".format(
|
||||||
|
end
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt'])
|
@pytest.mark.parametrize("file_name", ["test.file", "decode me.txt"])
|
||||||
def test_static_content_range_invalid_parameters(app, file_name, static_file_directory):
|
def test_static_content_range_invalid_parameters(
|
||||||
|
app, file_name, static_file_directory
|
||||||
|
):
|
||||||
app.static(
|
app.static(
|
||||||
'/testing.file', get_file_path(static_file_directory, file_name),
|
"/testing.file",
|
||||||
use_content_range=True)
|
get_file_path(static_file_directory, file_name),
|
||||||
|
use_content_range=True,
|
||||||
|
)
|
||||||
|
|
||||||
headers = {
|
headers = {"Range": "bytes=-"}
|
||||||
'Range': 'bytes=-'
|
request, response = app.test_client.get("/testing.file", headers=headers)
|
||||||
}
|
|
||||||
request, response = app.test_client.get('/testing.file', headers=headers)
|
|
||||||
|
|
||||||
assert response.status == 416
|
assert response.status == 416
|
||||||
assert response.text == "Error: Invalid for Content Range parameters"
|
assert response.text == "Error: Invalid for Content Range parameters"
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('file_name',
|
@pytest.mark.parametrize(
|
||||||
['test.file', 'decode me.txt', 'python.png'])
|
"file_name", ["test.file", "decode me.txt", "python.png"]
|
||||||
|
)
|
||||||
def test_static_file_specified_host(app, static_file_directory, file_name):
|
def test_static_file_specified_host(app, static_file_directory, file_name):
|
||||||
app.static(
|
app.static(
|
||||||
'/testing.file',
|
"/testing.file",
|
||||||
get_file_path(static_file_directory, file_name),
|
get_file_path(static_file_directory, file_name),
|
||||||
host="www.example.com"
|
host="www.example.com",
|
||||||
)
|
)
|
||||||
|
|
||||||
headers = {"Host": "www.example.com"}
|
headers = {"Host": "www.example.com"}
|
||||||
request, response = app.test_client.get('/testing.file', headers=headers)
|
request, response = app.test_client.get("/testing.file", headers=headers)
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.body == get_file_content(static_file_directory, file_name)
|
assert response.body == get_file_content(static_file_directory, file_name)
|
||||||
request, response = app.test_client.get('/testing.file')
|
request, response = app.test_client.get("/testing.file")
|
||||||
assert response.status == 404
|
assert response.status == 404
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('use_modified_since', [True, False])
|
@pytest.mark.parametrize("use_modified_since", [True, False])
|
||||||
@pytest.mark.parametrize('stream_large_files', [True, 1024])
|
@pytest.mark.parametrize("stream_large_files", [True, 1024])
|
||||||
@pytest.mark.parametrize('file_name', ['test.file', 'large.file'])
|
@pytest.mark.parametrize("file_name", ["test.file", "large.file"])
|
||||||
def test_static_stream_large_file(app, static_file_directory, file_name, use_modified_since, stream_large_files, large_file):
|
def test_static_stream_large_file(
|
||||||
|
app,
|
||||||
|
static_file_directory,
|
||||||
|
file_name,
|
||||||
|
use_modified_since,
|
||||||
|
stream_large_files,
|
||||||
|
large_file,
|
||||||
|
):
|
||||||
app.static(
|
app.static(
|
||||||
'/testing.file',
|
"/testing.file",
|
||||||
get_file_path(static_file_directory, file_name),
|
get_file_path(static_file_directory, file_name),
|
||||||
use_modified_since=use_modified_since,
|
use_modified_since=use_modified_since,
|
||||||
stream_large_files=stream_large_files
|
stream_large_files=stream_large_files,
|
||||||
)
|
)
|
||||||
|
|
||||||
request, response = app.test_client.get('/testing.file')
|
request, response = app.test_client.get("/testing.file")
|
||||||
|
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.body == get_file_content(static_file_directory, file_name)
|
assert response.body == get_file_content(static_file_directory, file_name)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt', 'python.png'])
|
@pytest.mark.parametrize(
|
||||||
|
"file_name", ["test.file", "decode me.txt", "python.png"]
|
||||||
|
)
|
||||||
def test_use_modified_since(app, static_file_directory, file_name):
|
def test_use_modified_since(app, static_file_directory, file_name):
|
||||||
|
|
||||||
file_stat = os.stat(get_file_path(static_file_directory, file_name))
|
file_stat = os.stat(get_file_path(static_file_directory, file_name))
|
||||||
modified_since = strftime("%a, %d %b %Y %H:%M:%S GMT", gmtime(file_stat.st_mtime))
|
modified_since = strftime(
|
||||||
|
"%a, %d %b %Y %H:%M:%S GMT", gmtime(file_stat.st_mtime)
|
||||||
|
)
|
||||||
|
|
||||||
app.static(
|
app.static(
|
||||||
'/testing.file',
|
"/testing.file",
|
||||||
get_file_path(static_file_directory, file_name),
|
get_file_path(static_file_directory, file_name),
|
||||||
use_modified_since=True
|
use_modified_since=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
request, response = app.test_client.get(
|
request, response = app.test_client.get(
|
||||||
'/testing.file', headers={'If-Modified-Since': modified_since})
|
"/testing.file", headers={"If-Modified-Since": modified_since}
|
||||||
|
)
|
||||||
|
|
||||||
assert response.status == 304
|
assert response.status == 304
|
||||||
|
|
||||||
|
|
||||||
def test_file_not_found(app, static_file_directory):
|
def test_file_not_found(app, static_file_directory):
|
||||||
app.static('/static', static_file_directory)
|
app.static("/static", static_file_directory)
|
||||||
|
|
||||||
request, response = app.test_client.get('/static/not_found')
|
request, response = app.test_client.get("/static/not_found")
|
||||||
|
|
||||||
assert response.status == 404
|
assert response.status == 404
|
||||||
assert response.text == 'Error: File not found'
|
assert response.text == "Error: File not found"
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('static_name', ['_static_name', 'static'])
|
@pytest.mark.parametrize("static_name", ["_static_name", "static"])
|
||||||
@pytest.mark.parametrize('file_name', ['test.html'])
|
@pytest.mark.parametrize("file_name", ["test.html"])
|
||||||
def test_static_name(app, static_file_directory, static_name, file_name):
|
def test_static_name(app, static_file_directory, static_name, file_name):
|
||||||
app.static('/static', static_file_directory, name=static_name)
|
app.static("/static", static_file_directory, name=static_name)
|
||||||
|
|
||||||
request, response = app.test_client.get('/static/{}'.format(file_name))
|
request, response = app.test_client.get("/static/{}".format(file_name))
|
||||||
|
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('file_name',
|
@pytest.mark.parametrize("file_name", ["test.file"])
|
||||||
['test.file'])
|
|
||||||
def test_static_remove_route(app, static_file_directory, file_name):
|
def test_static_remove_route(app, static_file_directory, file_name):
|
||||||
app.static(
|
app.static(
|
||||||
'/testing.file',
|
"/testing.file", get_file_path(static_file_directory, file_name)
|
||||||
get_file_path(static_file_directory, file_name)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
request, response = app.test_client.get('/testing.file')
|
request, response = app.test_client.get("/testing.file")
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
|
|
||||||
app.remove_route('/testing.file')
|
app.remove_route("/testing.file")
|
||||||
request, response = app.test_client.get('/testing.file')
|
request, response = app.test_client.get("/testing.file")
|
||||||
assert response.status == 404
|
assert response.status == 404
|
||||||
|
|
|
@ -9,27 +9,39 @@ from sanic.exceptions import URLBuildError
|
||||||
|
|
||||||
import string
|
import string
|
||||||
|
|
||||||
URL_FOR_ARGS1 = dict(arg1=['v1', 'v2'])
|
URL_FOR_ARGS1 = dict(arg1=["v1", "v2"])
|
||||||
URL_FOR_VALUE1 = '/myurl?arg1=v1&arg1=v2'
|
URL_FOR_VALUE1 = "/myurl?arg1=v1&arg1=v2"
|
||||||
URL_FOR_ARGS2 = dict(arg1=['v1', 'v2'], _anchor='anchor')
|
URL_FOR_ARGS2 = dict(arg1=["v1", "v2"], _anchor="anchor")
|
||||||
URL_FOR_VALUE2 = '/myurl?arg1=v1&arg1=v2#anchor'
|
URL_FOR_VALUE2 = "/myurl?arg1=v1&arg1=v2#anchor"
|
||||||
URL_FOR_ARGS3 = dict(
|
URL_FOR_ARGS3 = dict(
|
||||||
arg1='v1', _anchor='anchor', _scheme='http',
|
arg1="v1",
|
||||||
_server='{}:{}'.format(test_host, test_port), _external=True
|
_anchor="anchor",
|
||||||
|
_scheme="http",
|
||||||
|
_server="{}:{}".format(test_host, test_port),
|
||||||
|
_external=True,
|
||||||
|
)
|
||||||
|
URL_FOR_VALUE3 = "http://{}:{}/myurl?arg1=v1#anchor".format(
|
||||||
|
test_host, test_port
|
||||||
|
)
|
||||||
|
URL_FOR_ARGS4 = dict(
|
||||||
|
arg1="v1",
|
||||||
|
_anchor="anchor",
|
||||||
|
_external=True,
|
||||||
|
_server="http://{}:{}".format(test_host, test_port),
|
||||||
|
)
|
||||||
|
URL_FOR_VALUE4 = "http://{}:{}/myurl?arg1=v1#anchor".format(
|
||||||
|
test_host, test_port
|
||||||
)
|
)
|
||||||
URL_FOR_VALUE3 = 'http://{}:{}/myurl?arg1=v1#anchor'.format(test_host,
|
|
||||||
test_port)
|
|
||||||
URL_FOR_ARGS4 = dict(arg1='v1', _anchor='anchor', _external=True,
|
|
||||||
_server='http://{}:{}'.format(test_host, test_port))
|
|
||||||
URL_FOR_VALUE4 = 'http://{}:{}/myurl?arg1=v1#anchor'.format(test_host,
|
|
||||||
test_port)
|
|
||||||
|
|
||||||
|
|
||||||
def _generate_handlers_from_names(app, l):
|
def _generate_handlers_from_names(app, l):
|
||||||
for name in l:
|
for name in l:
|
||||||
# this is the easiest way to generate functions with dynamic names
|
# this is the easiest way to generate functions with dynamic names
|
||||||
exec('@app.route(name)\ndef {}(request):\n\treturn text("{}")'.format(
|
exec(
|
||||||
name, name))
|
'@app.route(name)\ndef {}(request):\n\treturn text("{}")'.format(
|
||||||
|
name, name
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
|
@ -45,69 +57,69 @@ def test_simple_url_for_getting(simple_app):
|
||||||
for letter in string.ascii_letters:
|
for letter in string.ascii_letters:
|
||||||
url = simple_app.url_for(letter)
|
url = simple_app.url_for(letter)
|
||||||
|
|
||||||
assert url == '/{}'.format(letter)
|
assert url == "/{}".format(letter)
|
||||||
request, response = simple_app.test_client.get(url)
|
request, response = simple_app.test_client.get(url)
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == letter
|
assert response.text == letter
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('args,url',
|
@pytest.mark.parametrize(
|
||||||
[(URL_FOR_ARGS1, URL_FOR_VALUE1),
|
"args,url",
|
||||||
(URL_FOR_ARGS2, URL_FOR_VALUE2),
|
[
|
||||||
(URL_FOR_ARGS3, URL_FOR_VALUE3),
|
(URL_FOR_ARGS1, URL_FOR_VALUE1),
|
||||||
(URL_FOR_ARGS4, URL_FOR_VALUE4)])
|
(URL_FOR_ARGS2, URL_FOR_VALUE2),
|
||||||
|
(URL_FOR_ARGS3, URL_FOR_VALUE3),
|
||||||
|
(URL_FOR_ARGS4, URL_FOR_VALUE4),
|
||||||
|
],
|
||||||
|
)
|
||||||
def test_simple_url_for_getting_with_more_params(app, args, url):
|
def test_simple_url_for_getting_with_more_params(app, args, url):
|
||||||
|
@app.route("/myurl")
|
||||||
@app.route('/myurl')
|
|
||||||
def passes(request):
|
def passes(request):
|
||||||
return text('this should pass')
|
return text("this should pass")
|
||||||
|
|
||||||
assert url == app.url_for('passes', **args)
|
assert url == app.url_for("passes", **args)
|
||||||
request, response = app.test_client.get(url)
|
request, response = app.test_client.get(url)
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == 'this should pass'
|
assert response.text == "this should pass"
|
||||||
|
|
||||||
|
|
||||||
def test_url_for_with_server_name(app):
|
def test_url_for_with_server_name(app):
|
||||||
|
|
||||||
server_name = '{}:{}'.format(test_host, test_port)
|
server_name = "{}:{}".format(test_host, test_port)
|
||||||
app.config.update({
|
app.config.update({"SERVER_NAME": server_name})
|
||||||
'SERVER_NAME': server_name
|
path = "/myurl"
|
||||||
})
|
|
||||||
path = '/myurl'
|
|
||||||
|
|
||||||
@app.route(path)
|
@app.route(path)
|
||||||
def passes(request):
|
def passes(request):
|
||||||
return text('this should pass')
|
return text("this should pass")
|
||||||
|
|
||||||
url = 'http://{}{}'.format(server_name, path)
|
url = "http://{}{}".format(server_name, path)
|
||||||
assert url == app.url_for('passes', _server=None, _external=True)
|
assert url == app.url_for("passes", _server=None, _external=True)
|
||||||
request, response = app.test_client.get(url)
|
request, response = app.test_client.get(url)
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == 'this should pass'
|
assert response.text == "this should pass"
|
||||||
|
|
||||||
|
|
||||||
def test_fails_if_endpoint_not_found(app):
|
def test_fails_if_endpoint_not_found(app):
|
||||||
|
@app.route("/fail")
|
||||||
@app.route('/fail')
|
|
||||||
def fail(request):
|
def fail(request):
|
||||||
return text('this should fail')
|
return text("this should fail")
|
||||||
|
|
||||||
with pytest.raises(URLBuildError) as e:
|
with pytest.raises(URLBuildError) as e:
|
||||||
app.url_for('passes')
|
app.url_for("passes")
|
||||||
|
|
||||||
assert str(e.value) == 'Endpoint with name `passes` was not found'
|
assert str(e.value) == "Endpoint with name `passes` was not found"
|
||||||
|
|
||||||
|
|
||||||
def test_fails_url_build_if_param_not_passed(app):
|
def test_fails_url_build_if_param_not_passed(app):
|
||||||
url = '/'
|
url = "/"
|
||||||
|
|
||||||
for letter in string.ascii_letters:
|
for letter in string.ascii_letters:
|
||||||
url += '<{}>/'.format(letter)
|
url += "<{}>/".format(letter)
|
||||||
|
|
||||||
@app.route(url)
|
@app.route(url)
|
||||||
def fail(request):
|
def fail(request):
|
||||||
return text('this should fail')
|
return text("this should fail")
|
||||||
|
|
||||||
fail_args = list(string.ascii_letters)
|
fail_args = list(string.ascii_letters)
|
||||||
fail_args.pop()
|
fail_args.pop()
|
||||||
|
@ -115,130 +127,130 @@ def test_fails_url_build_if_param_not_passed(app):
|
||||||
fail_kwargs = {l: l for l in fail_args}
|
fail_kwargs = {l: l for l in fail_args}
|
||||||
|
|
||||||
with pytest.raises(URLBuildError) as e:
|
with pytest.raises(URLBuildError) as e:
|
||||||
app.url_for('fail', **fail_kwargs)
|
app.url_for("fail", **fail_kwargs)
|
||||||
|
|
||||||
assert 'Required parameter `Z` was not passed to url_for' in str(e.value)
|
assert "Required parameter `Z` was not passed to url_for" in str(e.value)
|
||||||
|
|
||||||
|
|
||||||
def test_fails_url_build_if_params_not_passed(app):
|
def test_fails_url_build_if_params_not_passed(app):
|
||||||
|
@app.route("/fail")
|
||||||
@app.route('/fail')
|
|
||||||
def fail(request):
|
def fail(request):
|
||||||
return text('this should fail')
|
return text("this should fail")
|
||||||
|
|
||||||
with pytest.raises(ValueError) as e:
|
with pytest.raises(ValueError) as e:
|
||||||
app.url_for('fail', _scheme='http')
|
app.url_for("fail", _scheme="http")
|
||||||
|
|
||||||
assert str(e.value) == 'When specifying _scheme, _external must be True'
|
assert str(e.value) == "When specifying _scheme, _external must be True"
|
||||||
|
|
||||||
|
|
||||||
COMPLEX_PARAM_URL = (
|
COMPLEX_PARAM_URL = (
|
||||||
'/<foo:int>/<four_letter_string:[A-z]{4}>/'
|
"/<foo:int>/<four_letter_string:[A-z]{4}>/"
|
||||||
'<two_letter_string:[A-z]{2}>/<normal_string>/<some_number:number>')
|
"<two_letter_string:[A-z]{2}>/<normal_string>/<some_number:number>"
|
||||||
|
)
|
||||||
PASSING_KWARGS = {
|
PASSING_KWARGS = {
|
||||||
'foo': 4, 'four_letter_string': 'woof',
|
"foo": 4,
|
||||||
'two_letter_string': 'ba', 'normal_string': 'normal',
|
"four_letter_string": "woof",
|
||||||
'some_number': '1.001'}
|
"two_letter_string": "ba",
|
||||||
EXPECTED_BUILT_URL = '/4/woof/ba/normal/1.001'
|
"normal_string": "normal",
|
||||||
|
"some_number": "1.001",
|
||||||
|
}
|
||||||
|
EXPECTED_BUILT_URL = "/4/woof/ba/normal/1.001"
|
||||||
|
|
||||||
|
|
||||||
def test_fails_with_int_message(app):
|
def test_fails_with_int_message(app):
|
||||||
|
|
||||||
@app.route(COMPLEX_PARAM_URL)
|
@app.route(COMPLEX_PARAM_URL)
|
||||||
def fail(request):
|
def fail(request):
|
||||||
return text('this should fail')
|
return text("this should fail")
|
||||||
|
|
||||||
failing_kwargs = dict(PASSING_KWARGS)
|
failing_kwargs = dict(PASSING_KWARGS)
|
||||||
failing_kwargs['foo'] = 'not_int'
|
failing_kwargs["foo"] = "not_int"
|
||||||
|
|
||||||
with pytest.raises(URLBuildError) as e:
|
with pytest.raises(URLBuildError) as e:
|
||||||
app.url_for('fail', **failing_kwargs)
|
app.url_for("fail", **failing_kwargs)
|
||||||
|
|
||||||
expected_error = (
|
expected_error = (
|
||||||
'Value "not_int" for parameter `foo` '
|
'Value "not_int" for parameter `foo` '
|
||||||
'does not match pattern for type `int`: \d+')
|
"does not match pattern for type `int`: \d+"
|
||||||
|
)
|
||||||
assert str(e.value) == expected_error
|
assert str(e.value) == expected_error
|
||||||
|
|
||||||
|
|
||||||
def test_fails_with_two_letter_string_message(app):
|
def test_fails_with_two_letter_string_message(app):
|
||||||
|
|
||||||
@app.route(COMPLEX_PARAM_URL)
|
@app.route(COMPLEX_PARAM_URL)
|
||||||
def fail(request):
|
def fail(request):
|
||||||
return text('this should fail')
|
return text("this should fail")
|
||||||
|
|
||||||
failing_kwargs = dict(PASSING_KWARGS)
|
failing_kwargs = dict(PASSING_KWARGS)
|
||||||
failing_kwargs['two_letter_string'] = 'foobar'
|
failing_kwargs["two_letter_string"] = "foobar"
|
||||||
|
|
||||||
with pytest.raises(URLBuildError) as e:
|
with pytest.raises(URLBuildError) as e:
|
||||||
app.url_for('fail', **failing_kwargs)
|
app.url_for("fail", **failing_kwargs)
|
||||||
|
|
||||||
expected_error = (
|
expected_error = (
|
||||||
'Value "foobar" for parameter `two_letter_string` '
|
'Value "foobar" for parameter `two_letter_string` '
|
||||||
'does not satisfy pattern [A-z]{2}')
|
"does not satisfy pattern [A-z]{2}"
|
||||||
|
)
|
||||||
|
|
||||||
assert str(e.value) == expected_error
|
assert str(e.value) == expected_error
|
||||||
|
|
||||||
|
|
||||||
def test_fails_with_number_message(app):
|
def test_fails_with_number_message(app):
|
||||||
|
|
||||||
@app.route(COMPLEX_PARAM_URL)
|
@app.route(COMPLEX_PARAM_URL)
|
||||||
def fail(request):
|
def fail(request):
|
||||||
return text('this should fail')
|
return text("this should fail")
|
||||||
|
|
||||||
failing_kwargs = dict(PASSING_KWARGS)
|
failing_kwargs = dict(PASSING_KWARGS)
|
||||||
failing_kwargs['some_number'] = 'foo'
|
failing_kwargs["some_number"] = "foo"
|
||||||
|
|
||||||
with pytest.raises(URLBuildError) as e:
|
with pytest.raises(URLBuildError) as e:
|
||||||
app.url_for('fail', **failing_kwargs)
|
app.url_for("fail", **failing_kwargs)
|
||||||
|
|
||||||
expected_error = (
|
expected_error = (
|
||||||
'Value "foo" for parameter `some_number` '
|
'Value "foo" for parameter `some_number` '
|
||||||
'does not match pattern for type `float`: [0-9\\\\.]+')
|
"does not match pattern for type `float`: [0-9\\\\.]+"
|
||||||
|
)
|
||||||
|
|
||||||
assert str(e.value) == expected_error
|
assert str(e.value) == expected_error
|
||||||
|
|
||||||
|
|
||||||
def test_adds_other_supplied_values_as_query_string(app):
|
def test_adds_other_supplied_values_as_query_string(app):
|
||||||
|
|
||||||
@app.route(COMPLEX_PARAM_URL)
|
@app.route(COMPLEX_PARAM_URL)
|
||||||
def passes(request):
|
def passes(request):
|
||||||
return text('this should pass')
|
return text("this should pass")
|
||||||
|
|
||||||
new_kwargs = dict(PASSING_KWARGS)
|
new_kwargs = dict(PASSING_KWARGS)
|
||||||
new_kwargs['added_value_one'] = 'one'
|
new_kwargs["added_value_one"] = "one"
|
||||||
new_kwargs['added_value_two'] = 'two'
|
new_kwargs["added_value_two"] = "two"
|
||||||
|
|
||||||
url = app.url_for('passes', **new_kwargs)
|
url = app.url_for("passes", **new_kwargs)
|
||||||
|
|
||||||
query = dict(parse_qsl(urlsplit(url).query))
|
query = dict(parse_qsl(urlsplit(url).query))
|
||||||
|
|
||||||
assert query['added_value_one'] == 'one'
|
assert query["added_value_one"] == "one"
|
||||||
assert query['added_value_two'] == 'two'
|
assert query["added_value_two"] == "two"
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def blueprint_app(app):
|
def blueprint_app(app):
|
||||||
|
|
||||||
first_print = Blueprint('first', url_prefix='/first')
|
first_print = Blueprint("first", url_prefix="/first")
|
||||||
second_print = Blueprint('second', url_prefix='/second')
|
second_print = Blueprint("second", url_prefix="/second")
|
||||||
|
|
||||||
@first_print.route('/foo')
|
@first_print.route("/foo")
|
||||||
def foo(request):
|
def foo(request):
|
||||||
return text('foo from first')
|
return text("foo from first")
|
||||||
|
|
||||||
@first_print.route('/foo/<param>')
|
@first_print.route("/foo/<param>")
|
||||||
def foo_with_param(request, param):
|
def foo_with_param(request, param):
|
||||||
return text(
|
return text("foo from first : {}".format(param))
|
||||||
'foo from first : {}'.format(param))
|
|
||||||
|
|
||||||
@second_print.route('/foo') # noqa
|
@second_print.route("/foo") # noqa
|
||||||
def foo(request):
|
def foo(request):
|
||||||
return text('foo from second')
|
return text("foo from second")
|
||||||
|
|
||||||
@second_print.route('/foo/<param>') # noqa
|
@second_print.route("/foo/<param>") # noqa
|
||||||
def foo_with_param(request, param):
|
def foo_with_param(request, param):
|
||||||
return text(
|
return text("foo from second : {}".format(param))
|
||||||
'foo from second : {}'.format(param))
|
|
||||||
|
|
||||||
app.blueprint(first_print)
|
app.blueprint(first_print)
|
||||||
app.blueprint(second_print)
|
app.blueprint(second_print)
|
||||||
|
@ -247,66 +259,65 @@ def blueprint_app(app):
|
||||||
|
|
||||||
|
|
||||||
def test_blueprints_are_named_correctly(blueprint_app):
|
def test_blueprints_are_named_correctly(blueprint_app):
|
||||||
first_url = blueprint_app.url_for('first.foo')
|
first_url = blueprint_app.url_for("first.foo")
|
||||||
assert first_url == '/first/foo'
|
assert first_url == "/first/foo"
|
||||||
|
|
||||||
second_url = blueprint_app.url_for('second.foo')
|
second_url = blueprint_app.url_for("second.foo")
|
||||||
assert second_url == '/second/foo'
|
assert second_url == "/second/foo"
|
||||||
|
|
||||||
|
|
||||||
def test_blueprints_work_with_params(blueprint_app):
|
def test_blueprints_work_with_params(blueprint_app):
|
||||||
first_url = blueprint_app.url_for('first.foo_with_param', param='bar')
|
first_url = blueprint_app.url_for("first.foo_with_param", param="bar")
|
||||||
assert first_url == '/first/foo/bar'
|
assert first_url == "/first/foo/bar"
|
||||||
|
|
||||||
second_url = blueprint_app.url_for('second.foo_with_param', param='bar')
|
second_url = blueprint_app.url_for("second.foo_with_param", param="bar")
|
||||||
assert second_url == '/second/foo/bar'
|
assert second_url == "/second/foo/bar"
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def methodview_app(app):
|
def methodview_app(app):
|
||||||
|
|
||||||
class ViewOne(HTTPMethodView):
|
class ViewOne(HTTPMethodView):
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
return text('I am get method')
|
return text("I am get method")
|
||||||
|
|
||||||
def post(self, request):
|
def post(self, request):
|
||||||
return text('I am post method')
|
return text("I am post method")
|
||||||
|
|
||||||
def put(self, request):
|
def put(self, request):
|
||||||
return text('I am put method')
|
return text("I am put method")
|
||||||
|
|
||||||
def patch(self, request):
|
def patch(self, request):
|
||||||
return text('I am patch method')
|
return text("I am patch method")
|
||||||
|
|
||||||
def delete(self, request):
|
def delete(self, request):
|
||||||
return text('I am delete method')
|
return text("I am delete method")
|
||||||
|
|
||||||
app.add_route(ViewOne.as_view('view_one'), '/view_one')
|
app.add_route(ViewOne.as_view("view_one"), "/view_one")
|
||||||
|
|
||||||
class ViewTwo(HTTPMethodView):
|
class ViewTwo(HTTPMethodView):
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
return text('I am get method')
|
return text("I am get method")
|
||||||
|
|
||||||
def post(self, request):
|
def post(self, request):
|
||||||
return text('I am post method')
|
return text("I am post method")
|
||||||
|
|
||||||
def put(self, request):
|
def put(self, request):
|
||||||
return text('I am put method')
|
return text("I am put method")
|
||||||
|
|
||||||
def patch(self, request):
|
def patch(self, request):
|
||||||
return text('I am patch method')
|
return text("I am patch method")
|
||||||
|
|
||||||
def delete(self, request):
|
def delete(self, request):
|
||||||
return text('I am delete method')
|
return text("I am delete method")
|
||||||
|
|
||||||
app.add_route(ViewTwo.as_view(), '/view_two')
|
app.add_route(ViewTwo.as_view(), "/view_two")
|
||||||
|
|
||||||
return app
|
return app
|
||||||
|
|
||||||
|
|
||||||
def test_methodview_naming(methodview_app):
|
def test_methodview_naming(methodview_app):
|
||||||
viewone_url = methodview_app.url_for('ViewOne')
|
viewone_url = methodview_app.url_for("ViewOne")
|
||||||
viewtwo_url = methodview_app.url_for('ViewTwo')
|
viewtwo_url = methodview_app.url_for("ViewTwo")
|
||||||
|
|
||||||
assert viewone_url == '/view_one'
|
assert viewone_url == "/view_one"
|
||||||
assert viewtwo_url == '/view_two'
|
assert viewtwo_url == "/view_two"
|
||||||
|
|
|
@ -6,12 +6,12 @@ import pytest
|
||||||
from sanic.blueprints import Blueprint
|
from sanic.blueprints import Blueprint
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope='module')
|
@pytest.fixture(scope="module")
|
||||||
def static_file_directory():
|
def static_file_directory():
|
||||||
"""The static directory to serve"""
|
"""The static directory to serve"""
|
||||||
current_file = inspect.getfile(inspect.currentframe())
|
current_file = inspect.getfile(inspect.currentframe())
|
||||||
current_directory = os.path.dirname(os.path.abspath(current_file))
|
current_directory = os.path.dirname(os.path.abspath(current_file))
|
||||||
static_directory = os.path.join(current_directory, 'static')
|
static_directory = os.path.join(current_directory, "static")
|
||||||
return static_directory
|
return static_directory
|
||||||
|
|
||||||
|
|
||||||
|
@ -21,24 +21,28 @@ def get_file_path(static_file_directory, file_name):
|
||||||
|
|
||||||
def get_file_content(static_file_directory, file_name):
|
def get_file_content(static_file_directory, file_name):
|
||||||
"""The content of the static file to check"""
|
"""The content of the static file to check"""
|
||||||
with open(get_file_path(static_file_directory, file_name), 'rb') as file:
|
with open(get_file_path(static_file_directory, file_name), "rb") as file:
|
||||||
return file.read()
|
return file.read()
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('file_name',
|
@pytest.mark.parametrize(
|
||||||
['test.file', 'decode me.txt', 'python.png'])
|
"file_name", ["test.file", "decode me.txt", "python.png"]
|
||||||
|
)
|
||||||
def test_static_file(app, static_file_directory, file_name):
|
def test_static_file(app, static_file_directory, file_name):
|
||||||
app.static(
|
app.static(
|
||||||
'/testing.file', get_file_path(static_file_directory, file_name))
|
"/testing.file", get_file_path(static_file_directory, file_name)
|
||||||
|
)
|
||||||
app.static(
|
app.static(
|
||||||
'/testing2.file', get_file_path(static_file_directory, file_name),
|
"/testing2.file",
|
||||||
name='testing_file')
|
get_file_path(static_file_directory, file_name),
|
||||||
|
name="testing_file",
|
||||||
|
)
|
||||||
|
|
||||||
uri = app.url_for('static')
|
uri = app.url_for("static")
|
||||||
uri2 = app.url_for('static', filename='any')
|
uri2 = app.url_for("static", filename="any")
|
||||||
uri3 = app.url_for('static', name='static', filename='any')
|
uri3 = app.url_for("static", name="static", filename="any")
|
||||||
|
|
||||||
assert uri == '/testing.file'
|
assert uri == "/testing.file"
|
||||||
assert uri == uri2
|
assert uri == uri2
|
||||||
assert uri2 == uri3
|
assert uri2 == uri3
|
||||||
|
|
||||||
|
@ -46,23 +50,25 @@ def test_static_file(app, static_file_directory, file_name):
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.body == get_file_content(static_file_directory, file_name)
|
assert response.body == get_file_content(static_file_directory, file_name)
|
||||||
|
|
||||||
bp = Blueprint('test_bp_static', url_prefix='/bp')
|
bp = Blueprint("test_bp_static", url_prefix="/bp")
|
||||||
|
|
||||||
bp.static('/testing.file', get_file_path(static_file_directory, file_name))
|
bp.static("/testing.file", get_file_path(static_file_directory, file_name))
|
||||||
bp.static('/testing2.file',
|
bp.static(
|
||||||
get_file_path(static_file_directory, file_name),
|
"/testing2.file",
|
||||||
name='testing_file')
|
get_file_path(static_file_directory, file_name),
|
||||||
|
name="testing_file",
|
||||||
|
)
|
||||||
|
|
||||||
app.blueprint(bp)
|
app.blueprint(bp)
|
||||||
|
|
||||||
uri = app.url_for('static', name='test_bp_static.static')
|
uri = app.url_for("static", name="test_bp_static.static")
|
||||||
uri2 = app.url_for('static', name='test_bp_static.static', filename='any')
|
uri2 = app.url_for("static", name="test_bp_static.static", filename="any")
|
||||||
uri3 = app.url_for('test_bp_static.static')
|
uri3 = app.url_for("test_bp_static.static")
|
||||||
uri4 = app.url_for('test_bp_static.static', name='any')
|
uri4 = app.url_for("test_bp_static.static", name="any")
|
||||||
uri5 = app.url_for('test_bp_static.static', filename='any')
|
uri5 = app.url_for("test_bp_static.static", filename="any")
|
||||||
uri6 = app.url_for('test_bp_static.static', name='any', filename='any')
|
uri6 = app.url_for("test_bp_static.static", name="any", filename="any")
|
||||||
|
|
||||||
assert uri == '/bp/testing.file'
|
assert uri == "/bp/testing.file"
|
||||||
assert uri == uri2
|
assert uri == uri2
|
||||||
assert uri2 == uri3
|
assert uri2 == uri3
|
||||||
assert uri3 == uri4
|
assert uri3 == uri4
|
||||||
|
@ -74,78 +80,87 @@ def test_static_file(app, static_file_directory, file_name):
|
||||||
assert response.body == get_file_content(static_file_directory, file_name)
|
assert response.body == get_file_content(static_file_directory, file_name)
|
||||||
|
|
||||||
# test for other parameters
|
# test for other parameters
|
||||||
uri = app.url_for('static', _external=True, _server='http://localhost')
|
uri = app.url_for("static", _external=True, _server="http://localhost")
|
||||||
assert uri == 'http://localhost/testing.file'
|
assert uri == "http://localhost/testing.file"
|
||||||
|
|
||||||
uri = app.url_for('static', name='test_bp_static.static',
|
uri = app.url_for(
|
||||||
_external=True, _server='http://localhost')
|
"static",
|
||||||
assert uri == 'http://localhost/bp/testing.file'
|
name="test_bp_static.static",
|
||||||
|
_external=True,
|
||||||
|
_server="http://localhost",
|
||||||
|
)
|
||||||
|
assert uri == "http://localhost/bp/testing.file"
|
||||||
|
|
||||||
# test for defined name
|
# test for defined name
|
||||||
uri = app.url_for('static', name='testing_file')
|
uri = app.url_for("static", name="testing_file")
|
||||||
assert uri == '/testing2.file'
|
assert uri == "/testing2.file"
|
||||||
|
|
||||||
request, response = app.test_client.get(uri)
|
request, response = app.test_client.get(uri)
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.body == get_file_content(static_file_directory, file_name)
|
assert response.body == get_file_content(static_file_directory, file_name)
|
||||||
|
|
||||||
uri = app.url_for('static', name='test_bp_static.testing_file')
|
uri = app.url_for("static", name="test_bp_static.testing_file")
|
||||||
assert uri == '/bp/testing2.file'
|
assert uri == "/bp/testing2.file"
|
||||||
assert uri == app.url_for('static', name='test_bp_static.testing_file',
|
assert uri == app.url_for(
|
||||||
filename='any')
|
"static", name="test_bp_static.testing_file", filename="any"
|
||||||
|
)
|
||||||
|
|
||||||
request, response = app.test_client.get(uri)
|
request, response = app.test_client.get(uri)
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.body == get_file_content(static_file_directory, file_name)
|
assert response.body == get_file_content(static_file_directory, file_name)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt'])
|
@pytest.mark.parametrize("file_name", ["test.file", "decode me.txt"])
|
||||||
@pytest.mark.parametrize('base_uri', ['/static', '', '/dir'])
|
@pytest.mark.parametrize("base_uri", ["/static", "", "/dir"])
|
||||||
def test_static_directory(app, file_name, base_uri, static_file_directory):
|
def test_static_directory(app, file_name, base_uri, static_file_directory):
|
||||||
app.static(base_uri, static_file_directory)
|
app.static(base_uri, static_file_directory)
|
||||||
base_uri2 = base_uri + '/2'
|
base_uri2 = base_uri + "/2"
|
||||||
app.static(base_uri2, static_file_directory, name='uploads')
|
app.static(base_uri2, static_file_directory, name="uploads")
|
||||||
|
|
||||||
uri = app.url_for('static', name='static', filename=file_name)
|
uri = app.url_for("static", name="static", filename=file_name)
|
||||||
assert uri == '{}/{}'.format(base_uri, file_name)
|
assert uri == "{}/{}".format(base_uri, file_name)
|
||||||
|
|
||||||
request, response = app.test_client.get(uri)
|
request, response = app.test_client.get(uri)
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.body == get_file_content(static_file_directory, file_name)
|
assert response.body == get_file_content(static_file_directory, file_name)
|
||||||
|
|
||||||
uri2 = app.url_for('static', name='static', filename='/' + file_name)
|
uri2 = app.url_for("static", name="static", filename="/" + file_name)
|
||||||
uri3 = app.url_for('static', filename=file_name)
|
uri3 = app.url_for("static", filename=file_name)
|
||||||
uri4 = app.url_for('static', filename='/' + file_name)
|
uri4 = app.url_for("static", filename="/" + file_name)
|
||||||
uri5 = app.url_for('static', name='uploads', filename=file_name)
|
uri5 = app.url_for("static", name="uploads", filename=file_name)
|
||||||
uri6 = app.url_for('static', name='uploads', filename='/' + file_name)
|
uri6 = app.url_for("static", name="uploads", filename="/" + file_name)
|
||||||
|
|
||||||
assert uri == uri2
|
assert uri == uri2
|
||||||
assert uri2 == uri3
|
assert uri2 == uri3
|
||||||
assert uri3 == uri4
|
assert uri3 == uri4
|
||||||
|
|
||||||
assert uri5 == '{}/{}'.format(base_uri2, file_name)
|
assert uri5 == "{}/{}".format(base_uri2, file_name)
|
||||||
assert uri5 == uri6
|
assert uri5 == uri6
|
||||||
|
|
||||||
bp = Blueprint('test_bp_static', url_prefix='/bp')
|
bp = Blueprint("test_bp_static", url_prefix="/bp")
|
||||||
|
|
||||||
bp.static(base_uri, static_file_directory)
|
bp.static(base_uri, static_file_directory)
|
||||||
bp.static(base_uri2, static_file_directory, name='uploads')
|
bp.static(base_uri2, static_file_directory, name="uploads")
|
||||||
app.blueprint(bp)
|
app.blueprint(bp)
|
||||||
|
|
||||||
uri = app.url_for('static', name='test_bp_static.static',
|
uri = app.url_for(
|
||||||
filename=file_name)
|
"static", name="test_bp_static.static", filename=file_name
|
||||||
uri2 = app.url_for('static', name='test_bp_static.static',
|
)
|
||||||
filename='/' + file_name)
|
uri2 = app.url_for(
|
||||||
|
"static", name="test_bp_static.static", filename="/" + file_name
|
||||||
|
)
|
||||||
|
|
||||||
uri4 = app.url_for('static', name='test_bp_static.uploads',
|
uri4 = app.url_for(
|
||||||
filename=file_name)
|
"static", name="test_bp_static.uploads", filename=file_name
|
||||||
uri5 = app.url_for('static', name='test_bp_static.uploads',
|
)
|
||||||
filename='/' + file_name)
|
uri5 = app.url_for(
|
||||||
|
"static", name="test_bp_static.uploads", filename="/" + file_name
|
||||||
|
)
|
||||||
|
|
||||||
assert uri == '/bp{}/{}'.format(base_uri, file_name)
|
assert uri == "/bp{}/{}".format(base_uri, file_name)
|
||||||
assert uri == uri2
|
assert uri == uri2
|
||||||
|
|
||||||
assert uri4 == '/bp{}/{}'.format(base_uri2, file_name)
|
assert uri4 == "/bp{}/{}".format(base_uri2, file_name)
|
||||||
assert uri4 == uri5
|
assert uri4 == uri5
|
||||||
|
|
||||||
request, response = app.test_client.get(uri)
|
request, response = app.test_client.get(uri)
|
||||||
|
@ -153,284 +168,323 @@ def test_static_directory(app, file_name, base_uri, static_file_directory):
|
||||||
assert response.body == get_file_content(static_file_directory, file_name)
|
assert response.body == get_file_content(static_file_directory, file_name)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt'])
|
@pytest.mark.parametrize("file_name", ["test.file", "decode me.txt"])
|
||||||
def test_static_head_request(app, file_name, static_file_directory):
|
def test_static_head_request(app, file_name, static_file_directory):
|
||||||
app.static(
|
app.static(
|
||||||
'/testing.file', get_file_path(static_file_directory, file_name),
|
"/testing.file",
|
||||||
use_content_range=True)
|
get_file_path(static_file_directory, file_name),
|
||||||
|
use_content_range=True,
|
||||||
|
)
|
||||||
|
|
||||||
bp = Blueprint('test_bp_static', url_prefix='/bp')
|
bp = Blueprint("test_bp_static", url_prefix="/bp")
|
||||||
bp.static('/testing.file', get_file_path(static_file_directory, file_name),
|
bp.static(
|
||||||
use_content_range=True)
|
"/testing.file",
|
||||||
|
get_file_path(static_file_directory, file_name),
|
||||||
|
use_content_range=True,
|
||||||
|
)
|
||||||
app.blueprint(bp)
|
app.blueprint(bp)
|
||||||
|
|
||||||
uri = app.url_for('static')
|
uri = app.url_for("static")
|
||||||
assert uri == '/testing.file'
|
assert uri == "/testing.file"
|
||||||
assert uri == app.url_for('static', name='static')
|
assert uri == app.url_for("static", name="static")
|
||||||
assert uri == app.url_for('static', name='static', filename='any')
|
assert uri == app.url_for("static", name="static", filename="any")
|
||||||
|
|
||||||
request, response = app.test_client.head(uri)
|
request, response = app.test_client.head(uri)
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert 'Accept-Ranges' in response.headers
|
assert "Accept-Ranges" in response.headers
|
||||||
assert 'Content-Length' in response.headers
|
assert "Content-Length" in response.headers
|
||||||
assert int(response.headers[
|
assert int(response.headers["Content-Length"]) == len(
|
||||||
'Content-Length']) == len(
|
get_file_content(static_file_directory, file_name)
|
||||||
get_file_content(static_file_directory, file_name))
|
)
|
||||||
|
|
||||||
# blueprint
|
# blueprint
|
||||||
uri = app.url_for('static', name='test_bp_static.static')
|
uri = app.url_for("static", name="test_bp_static.static")
|
||||||
assert uri == '/bp/testing.file'
|
assert uri == "/bp/testing.file"
|
||||||
assert uri == app.url_for('static', name='test_bp_static.static',
|
assert uri == app.url_for(
|
||||||
filename='any')
|
"static", name="test_bp_static.static", filename="any"
|
||||||
|
)
|
||||||
|
|
||||||
request, response = app.test_client.head(uri)
|
request, response = app.test_client.head(uri)
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert 'Accept-Ranges' in response.headers
|
assert "Accept-Ranges" in response.headers
|
||||||
assert 'Content-Length' in response.headers
|
assert "Content-Length" in response.headers
|
||||||
assert int(response.headers[
|
assert int(response.headers["Content-Length"]) == len(
|
||||||
'Content-Length']) == len(
|
get_file_content(static_file_directory, file_name)
|
||||||
get_file_content(static_file_directory, file_name))
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt'])
|
@pytest.mark.parametrize("file_name", ["test.file", "decode me.txt"])
|
||||||
def test_static_content_range_correct(app, file_name, static_file_directory):
|
def test_static_content_range_correct(app, file_name, static_file_directory):
|
||||||
app.static(
|
app.static(
|
||||||
'/testing.file', get_file_path(static_file_directory, file_name),
|
"/testing.file",
|
||||||
use_content_range=True)
|
get_file_path(static_file_directory, file_name),
|
||||||
|
use_content_range=True,
|
||||||
|
)
|
||||||
|
|
||||||
bp = Blueprint('test_bp_static', url_prefix='/bp')
|
bp = Blueprint("test_bp_static", url_prefix="/bp")
|
||||||
bp.static('/testing.file', get_file_path(static_file_directory, file_name),
|
bp.static(
|
||||||
use_content_range=True)
|
"/testing.file",
|
||||||
|
get_file_path(static_file_directory, file_name),
|
||||||
|
use_content_range=True,
|
||||||
|
)
|
||||||
app.blueprint(bp)
|
app.blueprint(bp)
|
||||||
|
|
||||||
headers = {
|
headers = {"Range": "bytes=12-19"}
|
||||||
'Range': 'bytes=12-19'
|
uri = app.url_for("static")
|
||||||
}
|
assert uri == "/testing.file"
|
||||||
uri = app.url_for('static')
|
assert uri == app.url_for("static", name="static")
|
||||||
assert uri == '/testing.file'
|
assert uri == app.url_for("static", name="static", filename="any")
|
||||||
assert uri == app.url_for('static', name='static')
|
|
||||||
assert uri == app.url_for('static', name='static', filename='any')
|
|
||||||
|
|
||||||
request, response = app.test_client.get(uri, headers=headers)
|
request, response = app.test_client.get(uri, headers=headers)
|
||||||
assert response.status == 206
|
assert response.status == 206
|
||||||
assert 'Content-Length' in response.headers
|
assert "Content-Length" in response.headers
|
||||||
assert 'Content-Range' in response.headers
|
assert "Content-Range" in response.headers
|
||||||
static_content = bytes(get_file_content(
|
static_content = bytes(get_file_content(static_file_directory, file_name))[
|
||||||
static_file_directory, file_name))[12:20]
|
12:20
|
||||||
assert int(response.headers[
|
]
|
||||||
'Content-Length']) == len(static_content)
|
assert int(response.headers["Content-Length"]) == len(static_content)
|
||||||
assert response.body == static_content
|
assert response.body == static_content
|
||||||
|
|
||||||
# blueprint
|
# blueprint
|
||||||
uri = app.url_for('static', name='test_bp_static.static')
|
uri = app.url_for("static", name="test_bp_static.static")
|
||||||
assert uri == '/bp/testing.file'
|
assert uri == "/bp/testing.file"
|
||||||
assert uri == app.url_for('static', name='test_bp_static.static',
|
assert uri == app.url_for(
|
||||||
filename='any')
|
"static", name="test_bp_static.static", filename="any"
|
||||||
assert uri == app.url_for('test_bp_static.static')
|
)
|
||||||
assert uri == app.url_for('test_bp_static.static', name='any')
|
assert uri == app.url_for("test_bp_static.static")
|
||||||
assert uri == app.url_for('test_bp_static.static', filename='any')
|
assert uri == app.url_for("test_bp_static.static", name="any")
|
||||||
assert uri == app.url_for('test_bp_static.static', name='any',
|
assert uri == app.url_for("test_bp_static.static", filename="any")
|
||||||
filename='any')
|
assert uri == app.url_for(
|
||||||
|
"test_bp_static.static", name="any", filename="any"
|
||||||
|
)
|
||||||
|
|
||||||
request, response = app.test_client.get(uri, headers=headers)
|
request, response = app.test_client.get(uri, headers=headers)
|
||||||
assert response.status == 206
|
assert response.status == 206
|
||||||
assert 'Content-Length' in response.headers
|
assert "Content-Length" in response.headers
|
||||||
assert 'Content-Range' in response.headers
|
assert "Content-Range" in response.headers
|
||||||
static_content = bytes(get_file_content(
|
static_content = bytes(get_file_content(static_file_directory, file_name))[
|
||||||
static_file_directory, file_name))[12:20]
|
12:20
|
||||||
assert int(response.headers[
|
]
|
||||||
'Content-Length']) == len(static_content)
|
assert int(response.headers["Content-Length"]) == len(static_content)
|
||||||
assert response.body == static_content
|
assert response.body == static_content
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt'])
|
@pytest.mark.parametrize("file_name", ["test.file", "decode me.txt"])
|
||||||
def test_static_content_range_front(app, file_name, static_file_directory):
|
def test_static_content_range_front(app, file_name, static_file_directory):
|
||||||
app.static(
|
app.static(
|
||||||
'/testing.file', get_file_path(static_file_directory, file_name),
|
"/testing.file",
|
||||||
use_content_range=True)
|
get_file_path(static_file_directory, file_name),
|
||||||
|
use_content_range=True,
|
||||||
|
)
|
||||||
|
|
||||||
bp = Blueprint('test_bp_static', url_prefix='/bp')
|
bp = Blueprint("test_bp_static", url_prefix="/bp")
|
||||||
bp.static('/testing.file', get_file_path(static_file_directory, file_name),
|
bp.static(
|
||||||
use_content_range=True)
|
"/testing.file",
|
||||||
|
get_file_path(static_file_directory, file_name),
|
||||||
|
use_content_range=True,
|
||||||
|
)
|
||||||
app.blueprint(bp)
|
app.blueprint(bp)
|
||||||
|
|
||||||
headers = {
|
headers = {"Range": "bytes=12-"}
|
||||||
'Range': 'bytes=12-'
|
uri = app.url_for("static")
|
||||||
}
|
assert uri == "/testing.file"
|
||||||
uri = app.url_for('static')
|
assert uri == app.url_for("static", name="static")
|
||||||
assert uri == '/testing.file'
|
assert uri == app.url_for("static", name="static", filename="any")
|
||||||
assert uri == app.url_for('static', name='static')
|
|
||||||
assert uri == app.url_for('static', name='static', filename='any')
|
|
||||||
|
|
||||||
request, response = app.test_client.get(uri, headers=headers)
|
request, response = app.test_client.get(uri, headers=headers)
|
||||||
assert response.status == 206
|
assert response.status == 206
|
||||||
assert 'Content-Length' in response.headers
|
assert "Content-Length" in response.headers
|
||||||
assert 'Content-Range' in response.headers
|
assert "Content-Range" in response.headers
|
||||||
static_content = bytes(get_file_content(
|
static_content = bytes(get_file_content(static_file_directory, file_name))[
|
||||||
static_file_directory, file_name))[12:]
|
12:
|
||||||
assert int(response.headers[
|
]
|
||||||
'Content-Length']) == len(static_content)
|
assert int(response.headers["Content-Length"]) == len(static_content)
|
||||||
assert response.body == static_content
|
assert response.body == static_content
|
||||||
|
|
||||||
# blueprint
|
# blueprint
|
||||||
uri = app.url_for('static', name='test_bp_static.static')
|
uri = app.url_for("static", name="test_bp_static.static")
|
||||||
assert uri == '/bp/testing.file'
|
assert uri == "/bp/testing.file"
|
||||||
assert uri == app.url_for('static', name='test_bp_static.static',
|
assert uri == app.url_for(
|
||||||
filename='any')
|
"static", name="test_bp_static.static", filename="any"
|
||||||
assert uri == app.url_for('test_bp_static.static')
|
)
|
||||||
assert uri == app.url_for('test_bp_static.static', name='any')
|
assert uri == app.url_for("test_bp_static.static")
|
||||||
assert uri == app.url_for('test_bp_static.static', filename='any')
|
assert uri == app.url_for("test_bp_static.static", name="any")
|
||||||
assert uri == app.url_for('test_bp_static.static', name='any',
|
assert uri == app.url_for("test_bp_static.static", filename="any")
|
||||||
filename='any')
|
assert uri == app.url_for(
|
||||||
|
"test_bp_static.static", name="any", filename="any"
|
||||||
|
)
|
||||||
|
|
||||||
request, response = app.test_client.get(uri, headers=headers)
|
request, response = app.test_client.get(uri, headers=headers)
|
||||||
assert response.status == 206
|
assert response.status == 206
|
||||||
assert 'Content-Length' in response.headers
|
assert "Content-Length" in response.headers
|
||||||
assert 'Content-Range' in response.headers
|
assert "Content-Range" in response.headers
|
||||||
static_content = bytes(get_file_content(
|
static_content = bytes(get_file_content(static_file_directory, file_name))[
|
||||||
static_file_directory, file_name))[12:]
|
12:
|
||||||
assert int(response.headers[
|
]
|
||||||
'Content-Length']) == len(static_content)
|
assert int(response.headers["Content-Length"]) == len(static_content)
|
||||||
assert response.body == static_content
|
assert response.body == static_content
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt'])
|
@pytest.mark.parametrize("file_name", ["test.file", "decode me.txt"])
|
||||||
def test_static_content_range_back(app, file_name, static_file_directory):
|
def test_static_content_range_back(app, file_name, static_file_directory):
|
||||||
app.static(
|
app.static(
|
||||||
'/testing.file', get_file_path(static_file_directory, file_name),
|
"/testing.file",
|
||||||
use_content_range=True)
|
get_file_path(static_file_directory, file_name),
|
||||||
|
use_content_range=True,
|
||||||
|
)
|
||||||
|
|
||||||
bp = Blueprint('test_bp_static', url_prefix='/bp')
|
bp = Blueprint("test_bp_static", url_prefix="/bp")
|
||||||
bp.static('/testing.file', get_file_path(static_file_directory, file_name),
|
bp.static(
|
||||||
use_content_range=True)
|
"/testing.file",
|
||||||
|
get_file_path(static_file_directory, file_name),
|
||||||
|
use_content_range=True,
|
||||||
|
)
|
||||||
app.blueprint(bp)
|
app.blueprint(bp)
|
||||||
|
|
||||||
headers = {
|
headers = {"Range": "bytes=-12"}
|
||||||
'Range': 'bytes=-12'
|
uri = app.url_for("static")
|
||||||
}
|
assert uri == "/testing.file"
|
||||||
uri = app.url_for('static')
|
assert uri == app.url_for("static", name="static")
|
||||||
assert uri == '/testing.file'
|
assert uri == app.url_for("static", name="static", filename="any")
|
||||||
assert uri == app.url_for('static', name='static')
|
|
||||||
assert uri == app.url_for('static', name='static', filename='any')
|
|
||||||
|
|
||||||
request, response = app.test_client.get(uri, headers=headers)
|
request, response = app.test_client.get(uri, headers=headers)
|
||||||
assert response.status == 206
|
assert response.status == 206
|
||||||
assert 'Content-Length' in response.headers
|
assert "Content-Length" in response.headers
|
||||||
assert 'Content-Range' in response.headers
|
assert "Content-Range" in response.headers
|
||||||
static_content = bytes(get_file_content(
|
static_content = bytes(get_file_content(static_file_directory, file_name))[
|
||||||
static_file_directory, file_name))[-12:]
|
-12:
|
||||||
assert int(response.headers[
|
]
|
||||||
'Content-Length']) == len(static_content)
|
assert int(response.headers["Content-Length"]) == len(static_content)
|
||||||
assert response.body == static_content
|
assert response.body == static_content
|
||||||
|
|
||||||
# blueprint
|
# blueprint
|
||||||
uri = app.url_for('static', name='test_bp_static.static')
|
uri = app.url_for("static", name="test_bp_static.static")
|
||||||
assert uri == '/bp/testing.file'
|
assert uri == "/bp/testing.file"
|
||||||
assert uri == app.url_for('static', name='test_bp_static.static',
|
assert uri == app.url_for(
|
||||||
filename='any')
|
"static", name="test_bp_static.static", filename="any"
|
||||||
assert uri == app.url_for('test_bp_static.static')
|
)
|
||||||
assert uri == app.url_for('test_bp_static.static', name='any')
|
assert uri == app.url_for("test_bp_static.static")
|
||||||
assert uri == app.url_for('test_bp_static.static', filename='any')
|
assert uri == app.url_for("test_bp_static.static", name="any")
|
||||||
assert uri == app.url_for('test_bp_static.static', name='any',
|
assert uri == app.url_for("test_bp_static.static", filename="any")
|
||||||
filename='any')
|
assert uri == app.url_for(
|
||||||
|
"test_bp_static.static", name="any", filename="any"
|
||||||
|
)
|
||||||
|
|
||||||
request, response = app.test_client.get(uri, headers=headers)
|
request, response = app.test_client.get(uri, headers=headers)
|
||||||
assert response.status == 206
|
assert response.status == 206
|
||||||
assert 'Content-Length' in response.headers
|
assert "Content-Length" in response.headers
|
||||||
assert 'Content-Range' in response.headers
|
assert "Content-Range" in response.headers
|
||||||
static_content = bytes(get_file_content(
|
static_content = bytes(get_file_content(static_file_directory, file_name))[
|
||||||
static_file_directory, file_name))[-12:]
|
-12:
|
||||||
assert int(response.headers[
|
]
|
||||||
'Content-Length']) == len(static_content)
|
assert int(response.headers["Content-Length"]) == len(static_content)
|
||||||
assert response.body == static_content
|
assert response.body == static_content
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt'])
|
@pytest.mark.parametrize("file_name", ["test.file", "decode me.txt"])
|
||||||
def test_static_content_range_empty(app, file_name, static_file_directory):
|
def test_static_content_range_empty(app, file_name, static_file_directory):
|
||||||
app.static(
|
app.static(
|
||||||
'/testing.file', get_file_path(static_file_directory, file_name),
|
"/testing.file",
|
||||||
use_content_range=True)
|
get_file_path(static_file_directory, file_name),
|
||||||
|
use_content_range=True,
|
||||||
|
)
|
||||||
|
|
||||||
bp = Blueprint('test_bp_static', url_prefix='/bp')
|
bp = Blueprint("test_bp_static", url_prefix="/bp")
|
||||||
bp.static('/testing.file', get_file_path(static_file_directory, file_name),
|
bp.static(
|
||||||
use_content_range=True)
|
"/testing.file",
|
||||||
|
get_file_path(static_file_directory, file_name),
|
||||||
|
use_content_range=True,
|
||||||
|
)
|
||||||
app.blueprint(bp)
|
app.blueprint(bp)
|
||||||
|
|
||||||
uri = app.url_for('static')
|
uri = app.url_for("static")
|
||||||
assert uri == '/testing.file'
|
assert uri == "/testing.file"
|
||||||
assert uri == app.url_for('static', name='static')
|
assert uri == app.url_for("static", name="static")
|
||||||
assert uri == app.url_for('static', name='static', filename='any')
|
assert uri == app.url_for("static", name="static", filename="any")
|
||||||
|
|
||||||
request, response = app.test_client.get(uri)
|
request, response = app.test_client.get(uri)
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert 'Content-Length' in response.headers
|
assert "Content-Length" in response.headers
|
||||||
assert 'Content-Range' not in response.headers
|
assert "Content-Range" not in response.headers
|
||||||
assert int(response.headers['Content-Length']) == \
|
assert int(response.headers["Content-Length"]) == len(
|
||||||
len(get_file_content(static_file_directory, file_name))
|
get_file_content(static_file_directory, file_name)
|
||||||
|
)
|
||||||
assert response.body == bytes(
|
assert response.body == bytes(
|
||||||
get_file_content(static_file_directory, file_name))
|
get_file_content(static_file_directory, file_name)
|
||||||
|
)
|
||||||
|
|
||||||
# blueprint
|
# blueprint
|
||||||
uri = app.url_for('static', name='test_bp_static.static')
|
uri = app.url_for("static", name="test_bp_static.static")
|
||||||
assert uri == '/bp/testing.file'
|
assert uri == "/bp/testing.file"
|
||||||
assert uri == app.url_for('static', name='test_bp_static.static',
|
assert uri == app.url_for(
|
||||||
filename='any')
|
"static", name="test_bp_static.static", filename="any"
|
||||||
assert uri == app.url_for('test_bp_static.static')
|
)
|
||||||
assert uri == app.url_for('test_bp_static.static', name='any')
|
assert uri == app.url_for("test_bp_static.static")
|
||||||
assert uri == app.url_for('test_bp_static.static', filename='any')
|
assert uri == app.url_for("test_bp_static.static", name="any")
|
||||||
assert uri == app.url_for('test_bp_static.static', name='any',
|
assert uri == app.url_for("test_bp_static.static", filename="any")
|
||||||
filename='any')
|
assert uri == app.url_for(
|
||||||
|
"test_bp_static.static", name="any", filename="any"
|
||||||
|
)
|
||||||
|
|
||||||
request, response = app.test_client.get(uri)
|
request, response = app.test_client.get(uri)
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert 'Content-Length' in response.headers
|
assert "Content-Length" in response.headers
|
||||||
assert 'Content-Range' not in response.headers
|
assert "Content-Range" not in response.headers
|
||||||
assert int(response.headers['Content-Length']) == \
|
assert int(response.headers["Content-Length"]) == len(
|
||||||
len(get_file_content(static_file_directory, file_name))
|
get_file_content(static_file_directory, file_name)
|
||||||
|
)
|
||||||
assert response.body == bytes(
|
assert response.body == bytes(
|
||||||
get_file_content(static_file_directory, file_name))
|
get_file_content(static_file_directory, file_name)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt'])
|
@pytest.mark.parametrize("file_name", ["test.file", "decode me.txt"])
|
||||||
def test_static_content_range_error(app, file_name, static_file_directory):
|
def test_static_content_range_error(app, file_name, static_file_directory):
|
||||||
app.static(
|
app.static(
|
||||||
'/testing.file', get_file_path(static_file_directory, file_name),
|
"/testing.file",
|
||||||
use_content_range=True)
|
get_file_path(static_file_directory, file_name),
|
||||||
|
use_content_range=True,
|
||||||
|
)
|
||||||
|
|
||||||
bp = Blueprint('test_bp_static', url_prefix='/bp')
|
bp = Blueprint("test_bp_static", url_prefix="/bp")
|
||||||
bp.static('/testing.file', get_file_path(static_file_directory, file_name),
|
bp.static(
|
||||||
use_content_range=True)
|
"/testing.file",
|
||||||
|
get_file_path(static_file_directory, file_name),
|
||||||
|
use_content_range=True,
|
||||||
|
)
|
||||||
app.blueprint(bp)
|
app.blueprint(bp)
|
||||||
|
|
||||||
headers = {
|
headers = {"Range": "bytes=1-0"}
|
||||||
'Range': 'bytes=1-0'
|
uri = app.url_for("static")
|
||||||
}
|
assert uri == "/testing.file"
|
||||||
uri = app.url_for('static')
|
assert uri == app.url_for("static", name="static")
|
||||||
assert uri == '/testing.file'
|
assert uri == app.url_for("static", name="static", filename="any")
|
||||||
assert uri == app.url_for('static', name='static')
|
|
||||||
assert uri == app.url_for('static', name='static', filename='any')
|
|
||||||
|
|
||||||
request, response = app.test_client.get(uri, headers=headers)
|
request, response = app.test_client.get(uri, headers=headers)
|
||||||
assert response.status == 416
|
assert response.status == 416
|
||||||
assert 'Content-Length' in response.headers
|
assert "Content-Length" in response.headers
|
||||||
assert 'Content-Range' in response.headers
|
assert "Content-Range" in response.headers
|
||||||
assert response.headers['Content-Range'] == "bytes */%s" % (
|
assert response.headers["Content-Range"] == "bytes */%s" % (
|
||||||
len(get_file_content(static_file_directory, file_name)),)
|
len(get_file_content(static_file_directory, file_name)),
|
||||||
|
)
|
||||||
|
|
||||||
# blueprint
|
# blueprint
|
||||||
uri = app.url_for('static', name='test_bp_static.static')
|
uri = app.url_for("static", name="test_bp_static.static")
|
||||||
assert uri == '/bp/testing.file'
|
assert uri == "/bp/testing.file"
|
||||||
assert uri == app.url_for('static', name='test_bp_static.static',
|
assert uri == app.url_for(
|
||||||
filename='any')
|
"static", name="test_bp_static.static", filename="any"
|
||||||
assert uri == app.url_for('test_bp_static.static')
|
)
|
||||||
assert uri == app.url_for('test_bp_static.static', name='any')
|
assert uri == app.url_for("test_bp_static.static")
|
||||||
assert uri == app.url_for('test_bp_static.static', filename='any')
|
assert uri == app.url_for("test_bp_static.static", name="any")
|
||||||
assert uri == app.url_for('test_bp_static.static', name='any',
|
assert uri == app.url_for("test_bp_static.static", filename="any")
|
||||||
filename='any')
|
assert uri == app.url_for(
|
||||||
|
"test_bp_static.static", name="any", filename="any"
|
||||||
|
)
|
||||||
|
|
||||||
request, response = app.test_client.get(uri, headers=headers)
|
request, response = app.test_client.get(uri, headers=headers)
|
||||||
assert response.status == 416
|
assert response.status == 416
|
||||||
assert 'Content-Length' in response.headers
|
assert "Content-Length" in response.headers
|
||||||
assert 'Content-Range' in response.headers
|
assert "Content-Range" in response.headers
|
||||||
assert response.headers['Content-Range'] == "bytes */%s" % (
|
assert response.headers["Content-Range"] == "bytes */%s" % (
|
||||||
len(get_file_content(static_file_directory, file_name)),)
|
len(get_file_content(static_file_directory, file_name)),
|
||||||
|
)
|
||||||
|
|
|
@ -6,49 +6,46 @@ from sanic.response import text
|
||||||
# UTF-8
|
# UTF-8
|
||||||
# ------------------------------------------------------------ #
|
# ------------------------------------------------------------ #
|
||||||
|
|
||||||
|
|
||||||
def test_utf8_query_string(app):
|
def test_utf8_query_string(app):
|
||||||
|
@app.route("/")
|
||||||
@app.route('/')
|
|
||||||
async def handler(request):
|
async def handler(request):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
request, response = app.test_client.get('/', params=[("utf8", '✓')])
|
request, response = app.test_client.get("/", params=[("utf8", "✓")])
|
||||||
assert request.args.get('utf8') == '✓'
|
assert request.args.get("utf8") == "✓"
|
||||||
|
|
||||||
|
|
||||||
def test_utf8_response(app):
|
def test_utf8_response(app):
|
||||||
|
@app.route("/")
|
||||||
@app.route('/')
|
|
||||||
async def handler(request):
|
async def handler(request):
|
||||||
return text('✓')
|
return text("✓")
|
||||||
|
|
||||||
request, response = app.test_client.get('/')
|
request, response = app.test_client.get("/")
|
||||||
assert response.text == '✓'
|
assert response.text == "✓"
|
||||||
|
|
||||||
|
|
||||||
def skip_test_utf8_route(app):
|
def skip_test_utf8_route(app):
|
||||||
|
@app.route("/")
|
||||||
@app.route('/')
|
|
||||||
async def handler(request):
|
async def handler(request):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
# UTF-8 Paths are not supported
|
# UTF-8 Paths are not supported
|
||||||
request, response = app.test_client.get('/✓')
|
request, response = app.test_client.get("/✓")
|
||||||
assert response.text == 'OK'
|
assert response.text == "OK"
|
||||||
|
|
||||||
|
|
||||||
def test_utf8_post_json(app):
|
def test_utf8_post_json(app):
|
||||||
|
@app.route("/")
|
||||||
@app.route('/')
|
|
||||||
async def handler(request):
|
async def handler(request):
|
||||||
return text('OK')
|
return text("OK")
|
||||||
|
|
||||||
payload = {'test': '✓'}
|
payload = {"test": "✓"}
|
||||||
headers = {'content-type': 'application/json'}
|
headers = {"content-type": "application/json"}
|
||||||
|
|
||||||
request, response = app.test_client.get(
|
request, response = app.test_client.get(
|
||||||
'/',
|
"/", data=json_dumps(payload), headers=headers
|
||||||
data=json_dumps(payload), headers=headers)
|
)
|
||||||
|
|
||||||
assert request.json.get('test') == '✓'
|
assert request.json.get("test") == "✓"
|
||||||
assert response.text == 'OK'
|
assert response.text == "OK"
|
||||||
|
|
|
@ -2,67 +2,63 @@ from sanic.response import text
|
||||||
|
|
||||||
|
|
||||||
def test_vhosts(app):
|
def test_vhosts(app):
|
||||||
|
@app.route("/", host="example.com")
|
||||||
@app.route('/', host="example.com")
|
|
||||||
async def handler1(request):
|
async def handler1(request):
|
||||||
return text("You're at example.com!")
|
return text("You're at example.com!")
|
||||||
|
|
||||||
@app.route('/', host="subdomain.example.com")
|
@app.route("/", host="subdomain.example.com")
|
||||||
async def handler2(request):
|
async def handler2(request):
|
||||||
return text("You're at subdomain.example.com!")
|
return text("You're at subdomain.example.com!")
|
||||||
|
|
||||||
headers = {"Host": "example.com"}
|
headers = {"Host": "example.com"}
|
||||||
request, response = app.test_client.get('/', headers=headers)
|
request, response = app.test_client.get("/", headers=headers)
|
||||||
assert response.text == "You're at example.com!"
|
assert response.text == "You're at example.com!"
|
||||||
|
|
||||||
headers = {"Host": "subdomain.example.com"}
|
headers = {"Host": "subdomain.example.com"}
|
||||||
request, response = app.test_client.get('/', headers=headers)
|
request, response = app.test_client.get("/", headers=headers)
|
||||||
assert response.text == "You're at subdomain.example.com!"
|
assert response.text == "You're at subdomain.example.com!"
|
||||||
|
|
||||||
|
|
||||||
def test_vhosts_with_list(app):
|
def test_vhosts_with_list(app):
|
||||||
|
@app.route("/", host=["hello.com", "world.com"])
|
||||||
@app.route('/', host=["hello.com", "world.com"])
|
|
||||||
async def handler(request):
|
async def handler(request):
|
||||||
return text("Hello, world!")
|
return text("Hello, world!")
|
||||||
|
|
||||||
headers = {"Host": "hello.com"}
|
headers = {"Host": "hello.com"}
|
||||||
request, response = app.test_client.get('/', headers=headers)
|
request, response = app.test_client.get("/", headers=headers)
|
||||||
assert response.text == "Hello, world!"
|
assert response.text == "Hello, world!"
|
||||||
|
|
||||||
headers = {"Host": "world.com"}
|
headers = {"Host": "world.com"}
|
||||||
request, response = app.test_client.get('/', headers=headers)
|
request, response = app.test_client.get("/", headers=headers)
|
||||||
assert response.text == "Hello, world!"
|
assert response.text == "Hello, world!"
|
||||||
|
|
||||||
|
|
||||||
def test_vhosts_with_defaults(app):
|
def test_vhosts_with_defaults(app):
|
||||||
|
@app.route("/", host="hello.com")
|
||||||
@app.route('/', host="hello.com")
|
|
||||||
async def handler1(request):
|
async def handler1(request):
|
||||||
return text("Hello, world!")
|
return text("Hello, world!")
|
||||||
|
|
||||||
@app.route('/')
|
@app.route("/")
|
||||||
async def handler2(request):
|
async def handler2(request):
|
||||||
return text("default")
|
return text("default")
|
||||||
|
|
||||||
headers = {"Host": "hello.com"}
|
headers = {"Host": "hello.com"}
|
||||||
request, response = app.test_client.get('/', headers=headers)
|
request, response = app.test_client.get("/", headers=headers)
|
||||||
assert response.text == "Hello, world!"
|
assert response.text == "Hello, world!"
|
||||||
|
|
||||||
request, response = app.test_client.get('/')
|
request, response = app.test_client.get("/")
|
||||||
assert response.text == "default"
|
assert response.text == "default"
|
||||||
|
|
||||||
|
|
||||||
def test_remove_vhost_route(app):
|
def test_remove_vhost_route(app):
|
||||||
|
@app.route("/", host="example.com")
|
||||||
@app.route('/', host="example.com")
|
|
||||||
async def handler1(request):
|
async def handler1(request):
|
||||||
return text("You're at example.com!")
|
return text("You're at example.com!")
|
||||||
|
|
||||||
headers = {"Host": "example.com"}
|
headers = {"Host": "example.com"}
|
||||||
request, response = app.test_client.get('/', headers=headers)
|
request, response = app.test_client.get("/", headers=headers)
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
|
|
||||||
app.remove_route('/', host="example.com")
|
app.remove_route("/", host="example.com")
|
||||||
request, response = app.test_client.get('/', headers=headers)
|
request, response = app.test_client.get("/", headers=headers)
|
||||||
assert response.status == 404
|
assert response.status == 404
|
||||||
|
|
|
@ -8,110 +8,100 @@ from sanic.request import Request
|
||||||
from sanic.constants import HTTP_METHODS
|
from sanic.constants import HTTP_METHODS
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('method', HTTP_METHODS)
|
@pytest.mark.parametrize("method", HTTP_METHODS)
|
||||||
def test_methods(app, method):
|
def test_methods(app, method):
|
||||||
|
|
||||||
class DummyView(HTTPMethodView):
|
class DummyView(HTTPMethodView):
|
||||||
|
|
||||||
async def get(self, request):
|
async def get(self, request):
|
||||||
assert request.stream is None
|
assert request.stream is None
|
||||||
return text('', headers={'method': 'GET'})
|
return text("", headers={"method": "GET"})
|
||||||
|
|
||||||
def post(self, request):
|
def post(self, request):
|
||||||
return text('', headers={'method': 'POST'})
|
return text("", headers={"method": "POST"})
|
||||||
|
|
||||||
async def put(self, request):
|
async def put(self, request):
|
||||||
return text('', headers={'method': 'PUT'})
|
return text("", headers={"method": "PUT"})
|
||||||
|
|
||||||
def head(self, request):
|
def head(self, request):
|
||||||
return text('', headers={'method': 'HEAD'})
|
return text("", headers={"method": "HEAD"})
|
||||||
|
|
||||||
def options(self, request):
|
def options(self, request):
|
||||||
return text('', headers={'method': 'OPTIONS'})
|
return text("", headers={"method": "OPTIONS"})
|
||||||
|
|
||||||
async def patch(self, request):
|
async def patch(self, request):
|
||||||
return text('', headers={'method': 'PATCH'})
|
return text("", headers={"method": "PATCH"})
|
||||||
|
|
||||||
def delete(self, request):
|
def delete(self, request):
|
||||||
return text('', headers={'method': 'DELETE'})
|
return text("", headers={"method": "DELETE"})
|
||||||
|
|
||||||
app.add_route(DummyView.as_view(), '/')
|
app.add_route(DummyView.as_view(), "/")
|
||||||
assert app.is_request_stream is False
|
assert app.is_request_stream is False
|
||||||
|
|
||||||
request, response = getattr(app.test_client, method.lower())('/')
|
request, response = getattr(app.test_client, method.lower())("/")
|
||||||
assert response.headers['method'] == method
|
assert response.headers["method"] == method
|
||||||
|
|
||||||
|
|
||||||
def test_unexisting_methods(app):
|
def test_unexisting_methods(app):
|
||||||
|
|
||||||
class DummyView(HTTPMethodView):
|
class DummyView(HTTPMethodView):
|
||||||
|
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
return text('I am get method')
|
return text("I am get method")
|
||||||
|
|
||||||
app.add_route(DummyView.as_view(), '/')
|
app.add_route(DummyView.as_view(), "/")
|
||||||
request, response = app.test_client.get('/')
|
request, response = app.test_client.get("/")
|
||||||
assert response.text == 'I am get method'
|
assert response.text == "I am get method"
|
||||||
request, response = app.test_client.post('/')
|
request, response = app.test_client.post("/")
|
||||||
assert response.text == 'Error: Method POST not allowed for URL /'
|
assert response.text == "Error: Method POST not allowed for URL /"
|
||||||
|
|
||||||
|
|
||||||
def test_argument_methods(app):
|
def test_argument_methods(app):
|
||||||
|
|
||||||
class DummyView(HTTPMethodView):
|
class DummyView(HTTPMethodView):
|
||||||
|
|
||||||
def get(self, request, my_param_here):
|
def get(self, request, my_param_here):
|
||||||
return text('I am get method with %s' % my_param_here)
|
return text("I am get method with %s" % my_param_here)
|
||||||
|
|
||||||
app.add_route(DummyView.as_view(), '/<my_param_here>')
|
app.add_route(DummyView.as_view(), "/<my_param_here>")
|
||||||
|
|
||||||
request, response = app.test_client.get('/test123')
|
request, response = app.test_client.get("/test123")
|
||||||
|
|
||||||
assert response.text == 'I am get method with test123'
|
assert response.text == "I am get method with test123"
|
||||||
|
|
||||||
|
|
||||||
def test_with_bp(app):
|
def test_with_bp(app):
|
||||||
bp = Blueprint('test_text')
|
bp = Blueprint("test_text")
|
||||||
|
|
||||||
class DummyView(HTTPMethodView):
|
class DummyView(HTTPMethodView):
|
||||||
|
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
assert request.stream is None
|
assert request.stream is None
|
||||||
return text('I am get method')
|
return text("I am get method")
|
||||||
|
|
||||||
bp.add_route(DummyView.as_view(), '/')
|
bp.add_route(DummyView.as_view(), "/")
|
||||||
|
|
||||||
app.blueprint(bp)
|
app.blueprint(bp)
|
||||||
request, response = app.test_client.get('/')
|
request, response = app.test_client.get("/")
|
||||||
|
|
||||||
assert app.is_request_stream is False
|
assert app.is_request_stream is False
|
||||||
assert response.text == 'I am get method'
|
assert response.text == "I am get method"
|
||||||
|
|
||||||
|
|
||||||
def test_with_bp_with_url_prefix(app):
|
def test_with_bp_with_url_prefix(app):
|
||||||
bp = Blueprint('test_text', url_prefix='/test1')
|
bp = Blueprint("test_text", url_prefix="/test1")
|
||||||
|
|
||||||
class DummyView(HTTPMethodView):
|
class DummyView(HTTPMethodView):
|
||||||
|
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
return text('I am get method')
|
return text("I am get method")
|
||||||
|
|
||||||
bp.add_route(DummyView.as_view(), '/')
|
bp.add_route(DummyView.as_view(), "/")
|
||||||
|
|
||||||
app.blueprint(bp)
|
app.blueprint(bp)
|
||||||
request, response = app.test_client.get('/test1/')
|
request, response = app.test_client.get("/test1/")
|
||||||
|
|
||||||
assert response.text == 'I am get method'
|
assert response.text == "I am get method"
|
||||||
|
|
||||||
|
|
||||||
def test_with_middleware(app):
|
def test_with_middleware(app):
|
||||||
|
|
||||||
class DummyView(HTTPMethodView):
|
class DummyView(HTTPMethodView):
|
||||||
|
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
return text('I am get method')
|
return text("I am get method")
|
||||||
|
|
||||||
app.add_route(DummyView.as_view(), '/')
|
app.add_route(DummyView.as_view(), "/")
|
||||||
|
|
||||||
results = []
|
results = []
|
||||||
|
|
||||||
|
@ -119,41 +109,39 @@ def test_with_middleware(app):
|
||||||
async def handler(request):
|
async def handler(request):
|
||||||
results.append(request)
|
results.append(request)
|
||||||
|
|
||||||
request, response = app.test_client.get('/')
|
request, response = app.test_client.get("/")
|
||||||
|
|
||||||
assert response.text == 'I am get method'
|
assert response.text == "I am get method"
|
||||||
assert type(results[0]) is Request
|
assert type(results[0]) is Request
|
||||||
|
|
||||||
|
|
||||||
def test_with_middleware_response(app):
|
def test_with_middleware_response(app):
|
||||||
results = []
|
results = []
|
||||||
|
|
||||||
@app.middleware('request')
|
@app.middleware("request")
|
||||||
async def process_request(request):
|
async def process_request(request):
|
||||||
results.append(request)
|
results.append(request)
|
||||||
|
|
||||||
@app.middleware('response')
|
@app.middleware("response")
|
||||||
async def process_response(request, response):
|
async def process_response(request, response):
|
||||||
results.append(request)
|
results.append(request)
|
||||||
results.append(response)
|
results.append(response)
|
||||||
|
|
||||||
class DummyView(HTTPMethodView):
|
class DummyView(HTTPMethodView):
|
||||||
|
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
return text('I am get method')
|
return text("I am get method")
|
||||||
|
|
||||||
app.add_route(DummyView.as_view(), '/')
|
app.add_route(DummyView.as_view(), "/")
|
||||||
|
|
||||||
request, response = app.test_client.get('/')
|
request, response = app.test_client.get("/")
|
||||||
|
|
||||||
assert response.text == 'I am get method'
|
assert response.text == "I am get method"
|
||||||
assert type(results[0]) is Request
|
assert type(results[0]) is Request
|
||||||
assert type(results[1]) is Request
|
assert type(results[1]) is Request
|
||||||
assert isinstance(results[2], HTTPResponse)
|
assert isinstance(results[2], HTTPResponse)
|
||||||
|
|
||||||
|
|
||||||
def test_with_custom_class_methods(app):
|
def test_with_custom_class_methods(app):
|
||||||
|
|
||||||
class DummyView(HTTPMethodView):
|
class DummyView(HTTPMethodView):
|
||||||
global_var = 0
|
global_var = 0
|
||||||
|
|
||||||
|
@ -162,12 +150,14 @@ def test_with_custom_class_methods(app):
|
||||||
|
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
self._iternal_method()
|
self._iternal_method()
|
||||||
return text('I am get method and global var '
|
return text(
|
||||||
'is {}'.format(self.global_var))
|
"I am get method and global var "
|
||||||
|
"is {}".format(self.global_var)
|
||||||
|
)
|
||||||
|
|
||||||
app.add_route(DummyView.as_view(), '/')
|
app.add_route(DummyView.as_view(), "/")
|
||||||
request, response = app.test_client.get('/')
|
request, response = app.test_client.get("/")
|
||||||
assert response.text == 'I am get method and global var is 10'
|
assert response.text == "I am get method and global var is 10"
|
||||||
|
|
||||||
|
|
||||||
def test_with_decorator(app):
|
def test_with_decorator(app):
|
||||||
|
@ -177,84 +167,86 @@ def test_with_decorator(app):
|
||||||
def decorator(*args, **kwargs):
|
def decorator(*args, **kwargs):
|
||||||
results.append(1)
|
results.append(1)
|
||||||
return view(*args, **kwargs)
|
return view(*args, **kwargs)
|
||||||
|
|
||||||
return decorator
|
return decorator
|
||||||
|
|
||||||
class DummyView(HTTPMethodView):
|
class DummyView(HTTPMethodView):
|
||||||
decorators = [stupid_decorator]
|
decorators = [stupid_decorator]
|
||||||
|
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
return text('I am get method')
|
return text("I am get method")
|
||||||
|
|
||||||
app.add_route(DummyView.as_view(), '/')
|
app.add_route(DummyView.as_view(), "/")
|
||||||
request, response = app.test_client.get('/')
|
request, response = app.test_client.get("/")
|
||||||
assert response.text == 'I am get method'
|
assert response.text == "I am get method"
|
||||||
assert results[0] == 1
|
assert results[0] == 1
|
||||||
|
|
||||||
|
|
||||||
def test_composition_view_rejects_incorrect_methods():
|
def test_composition_view_rejects_incorrect_methods():
|
||||||
def foo(request):
|
def foo(request):
|
||||||
return text('Foo')
|
return text("Foo")
|
||||||
|
|
||||||
view = CompositionView()
|
view = CompositionView()
|
||||||
|
|
||||||
with pytest.raises(InvalidUsage) as e:
|
with pytest.raises(InvalidUsage) as e:
|
||||||
view.add(['GET', 'FOO'], foo)
|
view.add(["GET", "FOO"], foo)
|
||||||
|
|
||||||
assert str(e.value) == 'FOO is not a valid HTTP method.'
|
assert str(e.value) == "FOO is not a valid HTTP method."
|
||||||
|
|
||||||
|
|
||||||
def test_composition_view_rejects_duplicate_methods():
|
def test_composition_view_rejects_duplicate_methods():
|
||||||
def foo(request):
|
def foo(request):
|
||||||
return text('Foo')
|
return text("Foo")
|
||||||
|
|
||||||
view = CompositionView()
|
view = CompositionView()
|
||||||
|
|
||||||
with pytest.raises(InvalidUsage) as e:
|
with pytest.raises(InvalidUsage) as e:
|
||||||
view.add(['GET', 'POST', 'GET'], foo)
|
view.add(["GET", "POST", "GET"], foo)
|
||||||
|
|
||||||
assert str(e.value) == 'Method GET is already registered.'
|
assert str(e.value) == "Method GET is already registered."
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('method', HTTP_METHODS)
|
@pytest.mark.parametrize("method", HTTP_METHODS)
|
||||||
def test_composition_view_runs_methods_as_expected(app, method):
|
def test_composition_view_runs_methods_as_expected(app, method):
|
||||||
view = CompositionView()
|
view = CompositionView()
|
||||||
|
|
||||||
def first(request):
|
def first(request):
|
||||||
assert request.stream is None
|
assert request.stream is None
|
||||||
return text('first method')
|
return text("first method")
|
||||||
view.add(['GET', 'POST', 'PUT'], first)
|
|
||||||
view.add(['DELETE', 'PATCH'], lambda x: text('second method'))
|
|
||||||
|
|
||||||
app.add_route(view, '/')
|
view.add(["GET", "POST", "PUT"], first)
|
||||||
|
view.add(["DELETE", "PATCH"], lambda x: text("second method"))
|
||||||
|
|
||||||
|
app.add_route(view, "/")
|
||||||
assert app.is_request_stream is False
|
assert app.is_request_stream is False
|
||||||
|
|
||||||
if method in ['GET', 'POST', 'PUT']:
|
if method in ["GET", "POST", "PUT"]:
|
||||||
request, response = getattr(app.test_client, method.lower())('/')
|
request, response = getattr(app.test_client, method.lower())("/")
|
||||||
assert response.text == 'first method'
|
assert response.text == "first method"
|
||||||
|
|
||||||
response = view(request)
|
response = view(request)
|
||||||
assert response.body.decode() == 'first method'
|
assert response.body.decode() == "first method"
|
||||||
|
|
||||||
if method in ['DELETE', 'PATCH']:
|
if method in ["DELETE", "PATCH"]:
|
||||||
request, response = getattr(app.test_client, method.lower())('/')
|
request, response = getattr(app.test_client, method.lower())("/")
|
||||||
assert response.text == 'second method'
|
assert response.text == "second method"
|
||||||
|
|
||||||
response = view(request)
|
response = view(request)
|
||||||
assert response.body.decode() == 'second method'
|
assert response.body.decode() == "second method"
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('method', HTTP_METHODS)
|
@pytest.mark.parametrize("method", HTTP_METHODS)
|
||||||
def test_composition_view_rejects_invalid_methods(app, method):
|
def test_composition_view_rejects_invalid_methods(app, method):
|
||||||
view = CompositionView()
|
view = CompositionView()
|
||||||
view.add(['GET', 'POST', 'PUT'], lambda x: text('first method'))
|
view.add(["GET", "POST", "PUT"], lambda x: text("first method"))
|
||||||
|
|
||||||
app.add_route(view, '/')
|
app.add_route(view, "/")
|
||||||
|
|
||||||
if method in ['GET', 'POST', 'PUT']:
|
if method in ["GET", "POST", "PUT"]:
|
||||||
request, response = getattr(app.test_client, method.lower())('/')
|
request, response = getattr(app.test_client, method.lower())("/")
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == 'first method'
|
assert response.text == "first method"
|
||||||
|
|
||||||
if method in ['DELETE', 'PATCH']:
|
if method in ["DELETE", "PATCH"]:
|
||||||
request, response = getattr(app.test_client, method.lower())('/')
|
request, response = getattr(app.test_client, method.lower())("/")
|
||||||
assert response.status == 405
|
assert response.status == 405
|
||||||
|
|
|
@ -10,13 +10,13 @@ import asyncio
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope='module')
|
@pytest.fixture(scope="module")
|
||||||
def gunicorn_worker():
|
def gunicorn_worker():
|
||||||
command = (
|
command = (
|
||||||
'gunicorn '
|
"gunicorn "
|
||||||
'--bind 127.0.0.1:1337 '
|
"--bind 127.0.0.1:1337 "
|
||||||
'--worker-class sanic.worker.GunicornWorker '
|
"--worker-class sanic.worker.GunicornWorker "
|
||||||
'examples.simple_server:app'
|
"examples.simple_server:app"
|
||||||
)
|
)
|
||||||
worker = subprocess.Popen(shlex.split(command))
|
worker = subprocess.Popen(shlex.split(command))
|
||||||
time.sleep(3)
|
time.sleep(3)
|
||||||
|
@ -25,13 +25,12 @@ def gunicorn_worker():
|
||||||
|
|
||||||
|
|
||||||
def test_gunicorn_worker(gunicorn_worker):
|
def test_gunicorn_worker(gunicorn_worker):
|
||||||
with urllib.request.urlopen('http://localhost:1337/') as f:
|
with urllib.request.urlopen("http://localhost:1337/") as f:
|
||||||
res = json.loads(f.read(100).decode())
|
res = json.loads(f.read(100).decode())
|
||||||
assert res['test']
|
assert res["test"]
|
||||||
|
|
||||||
|
|
||||||
class GunicornTestWorker(GunicornWorker):
|
class GunicornTestWorker(GunicornWorker):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.app = mock.Mock()
|
self.app = mock.Mock()
|
||||||
self.app.callable = Sanic("test_gunicorn_worker")
|
self.app.callable = Sanic("test_gunicorn_worker")
|
||||||
|
@ -47,7 +46,7 @@ def worker():
|
||||||
|
|
||||||
|
|
||||||
def test_worker_init_process(worker):
|
def test_worker_init_process(worker):
|
||||||
with mock.patch('sanic.worker.asyncio') as mock_asyncio:
|
with mock.patch("sanic.worker.asyncio") as mock_asyncio:
|
||||||
try:
|
try:
|
||||||
worker.init_process()
|
worker.init_process()
|
||||||
except TypeError:
|
except TypeError:
|
||||||
|
@ -65,7 +64,7 @@ def test_worker_init_signals(worker):
|
||||||
|
|
||||||
|
|
||||||
def test_handle_abort(worker):
|
def test_handle_abort(worker):
|
||||||
with mock.patch('sanic.worker.sys') as mock_sys:
|
with mock.patch("sanic.worker.sys") as mock_sys:
|
||||||
worker.handle_abort(object(), object())
|
worker.handle_abort(object(), object())
|
||||||
assert not worker.alive
|
assert not worker.alive
|
||||||
assert worker.exit_code == 1
|
assert worker.exit_code == 1
|
||||||
|
@ -83,7 +82,7 @@ def test_run_max_requests_exceeded(worker):
|
||||||
worker.ppid = 1
|
worker.ppid = 1
|
||||||
worker.alive = True
|
worker.alive = True
|
||||||
sock = mock.Mock()
|
sock = mock.Mock()
|
||||||
sock.cfg_addr = ('localhost', 8080)
|
sock.cfg_addr = ("localhost", 8080)
|
||||||
worker.sockets = [sock]
|
worker.sockets = [sock]
|
||||||
worker.wsgi = mock.Mock()
|
worker.wsgi = mock.Mock()
|
||||||
worker.connections = set()
|
worker.connections = set()
|
||||||
|
@ -102,8 +101,9 @@ def test_run_max_requests_exceeded(worker):
|
||||||
|
|
||||||
assert not worker.alive
|
assert not worker.alive
|
||||||
worker.notify.assert_called_with()
|
worker.notify.assert_called_with()
|
||||||
worker.log.info.assert_called_with("Max requests exceeded, shutting "
|
worker.log.info.assert_called_with(
|
||||||
"down: %s", worker)
|
"Max requests exceeded, shutting " "down: %s", worker
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_worker_close(worker):
|
def test_worker_close(worker):
|
||||||
|
@ -125,11 +125,10 @@ def test_worker_close(worker):
|
||||||
worker.loop = loop
|
worker.loop = loop
|
||||||
server = mock.Mock()
|
server = mock.Mock()
|
||||||
server.close = mock.Mock(wraps=lambda *a, **kw: None)
|
server.close = mock.Mock(wraps=lambda *a, **kw: None)
|
||||||
server.wait_closed = mock.Mock(wraps=asyncio.coroutine(
|
server.wait_closed = mock.Mock(
|
||||||
lambda *a, **kw: None))
|
wraps=asyncio.coroutine(lambda *a, **kw: None)
|
||||||
worker.servers = {
|
)
|
||||||
server: {"requests_count": 14},
|
worker.servers = {server: {"requests_count": 14}}
|
||||||
}
|
|
||||||
worker.max_requests = 10
|
worker.max_requests = 10
|
||||||
|
|
||||||
# close worker
|
# close worker
|
||||||
|
|
Loading…
Reference in New Issue
Block a user