Merge branch 'main' into accept-enhance
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
import asyncio
|
||||
import inspect
|
||||
import logging
|
||||
import os
|
||||
import random
|
||||
import re
|
||||
import string
|
||||
@@ -58,7 +60,6 @@ CACHE: Dict[str, Any] = {}
|
||||
|
||||
|
||||
class RouteStringGenerator:
|
||||
|
||||
ROUTE_COUNT_PER_DEPTH = 100
|
||||
HTTP_METHODS = HTTP_METHODS
|
||||
ROUTE_PARAM_TYPES = ["str", "int", "float", "alpha", "uuid"]
|
||||
@@ -232,3 +233,12 @@ def urlopen():
|
||||
urlopen.read = Mock()
|
||||
with patch("sanic.cli.inspector_client.urlopen", urlopen):
|
||||
yield urlopen
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def static_file_directory():
|
||||
"""The static directory to serve"""
|
||||
current_file = inspect.getfile(inspect.currentframe())
|
||||
current_directory = os.path.dirname(os.path.abspath(current_file))
|
||||
static_directory = os.path.join(current_directory, "static")
|
||||
return static_directory
|
||||
|
||||
@@ -36,6 +36,7 @@ def test_app_loop_running(app: Sanic):
|
||||
assert response.text == "pass"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
def test_create_asyncio_server(app: Sanic):
|
||||
loop = asyncio.get_event_loop()
|
||||
asyncio_srv_coro = app.create_server(return_asyncio_server=True)
|
||||
@@ -44,6 +45,7 @@ def test_create_asyncio_server(app: Sanic):
|
||||
assert srv.is_serving() is True
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
def test_asyncio_server_no_start_serving(app: Sanic):
|
||||
loop = asyncio.get_event_loop()
|
||||
asyncio_srv_coro = app.create_server(
|
||||
@@ -55,6 +57,7 @@ def test_asyncio_server_no_start_serving(app: Sanic):
|
||||
assert srv.is_serving() is False
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
def test_asyncio_server_start_serving(app: Sanic):
|
||||
loop = asyncio.get_event_loop()
|
||||
asyncio_srv_coro = app.create_server(
|
||||
@@ -72,6 +75,7 @@ def test_asyncio_server_start_serving(app: Sanic):
|
||||
# Looks like we can't easily test `serve_forever()`
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
def test_create_server_main(app: Sanic, caplog):
|
||||
app.listener("main_process_start")(lambda *_: ...)
|
||||
loop = asyncio.get_event_loop()
|
||||
@@ -86,6 +90,7 @@ def test_create_server_main(app: Sanic, caplog):
|
||||
) in caplog.record_tuples
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
def test_create_server_no_startup(app: Sanic):
|
||||
loop = asyncio.get_event_loop()
|
||||
asyncio_srv_coro = app.create_server(
|
||||
@@ -101,6 +106,7 @@ def test_create_server_no_startup(app: Sanic):
|
||||
loop.run_until_complete(srv.start_serving())
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
def test_create_server_main_convenience(app: Sanic, caplog):
|
||||
app.main_process_start(lambda *_: ...)
|
||||
loop = asyncio.get_event_loop()
|
||||
@@ -126,7 +132,6 @@ def test_app_loop_not_running(app: Sanic):
|
||||
|
||||
|
||||
def test_app_run_raise_type_error(app: Sanic):
|
||||
|
||||
with pytest.raises(TypeError) as excinfo:
|
||||
app.run(loop="loop")
|
||||
|
||||
@@ -139,7 +144,6 @@ def test_app_run_raise_type_error(app: Sanic):
|
||||
|
||||
|
||||
def test_app_route_raise_value_error(app: Sanic):
|
||||
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
|
||||
@app.route("/test")
|
||||
@@ -221,7 +225,6 @@ def test_app_websocket_parameters(websocket_protocol_mock, app: Sanic):
|
||||
|
||||
|
||||
def test_handle_request_with_nested_exception(app: Sanic, monkeypatch):
|
||||
|
||||
err_msg = "Mock Exception"
|
||||
|
||||
def mock_error_handler_response(*args, **kwargs):
|
||||
@@ -241,7 +244,6 @@ def test_handle_request_with_nested_exception(app: Sanic, monkeypatch):
|
||||
|
||||
|
||||
def test_handle_request_with_nested_exception_debug(app: Sanic, monkeypatch):
|
||||
|
||||
err_msg = "Mock Exception"
|
||||
|
||||
def mock_error_handler_response(*args, **kwargs):
|
||||
@@ -470,6 +472,7 @@ def test_uvloop_config(app: Sanic, monkeypatch, use):
|
||||
try_use_uvloop.assert_not_called()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
def test_uvloop_cannot_never_called_with_create_server(caplog, monkeypatch):
|
||||
apps = (Sanic("default-uvloop"), Sanic("no-uvloop"), Sanic("yes-uvloop"))
|
||||
|
||||
@@ -506,6 +509,7 @@ def test_uvloop_cannot_never_called_with_create_server(caplog, monkeypatch):
|
||||
assert counter[(logging.WARNING, message)] == modified
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
def test_multiple_uvloop_configs_display_warning(caplog):
|
||||
Sanic._uvloop_setting = None # Reset the setting (changed in prev tests)
|
||||
|
||||
|
||||
@@ -342,7 +342,7 @@ async def test_websocket_send(send, receive, message_stack):
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_websocket_receive(send, receive, message_stack):
|
||||
async def test_websocket_text_receive(send, receive, message_stack):
|
||||
msg = {"text": "hello", "type": "websocket.receive"}
|
||||
message_stack.append(msg)
|
||||
|
||||
@@ -351,6 +351,15 @@ async def test_websocket_receive(send, receive, message_stack):
|
||||
|
||||
assert text == msg["text"]
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_websocket_bytes_receive(send, receive, message_stack):
|
||||
msg = {"bytes": b"hello", "type": "websocket.receive"}
|
||||
message_stack.append(msg)
|
||||
|
||||
ws = WebSocketConnection(send, receive)
|
||||
data = await ws.receive()
|
||||
|
||||
assert data == msg["bytes"]
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_websocket_accept_with_no_subprotocols(
|
||||
|
||||
@@ -148,7 +148,6 @@ def test_cookie_set_unknown_property():
|
||||
|
||||
|
||||
def test_cookie_set_same_key(app):
|
||||
|
||||
cookies = {"test": "wait"}
|
||||
|
||||
@app.get("/")
|
||||
|
||||
@@ -62,7 +62,6 @@ def exception_handler_app():
|
||||
|
||||
@exception_handler_app.route("/8", error_format="html")
|
||||
def handler_8(request):
|
||||
|
||||
raise ErrorWithRequestCtx("OK")
|
||||
|
||||
@exception_handler_app.exception(ErrorWithRequestCtx, NotFound)
|
||||
@@ -214,7 +213,7 @@ def test_error_handler_noisy_log(
|
||||
exception_handler_app: Sanic, monkeypatch: MonkeyPatch
|
||||
):
|
||||
err_logger = Mock()
|
||||
monkeypatch.setattr(handlers, "error_logger", err_logger)
|
||||
monkeypatch.setattr(handlers.error, "error_logger", err_logger)
|
||||
|
||||
exception_handler_app.config["NOISY_EXCEPTIONS"] = False
|
||||
exception_handler_app.test_client.get("/1")
|
||||
|
||||
@@ -514,7 +514,6 @@ def test_file_stream_head_response(
|
||||
def test_file_stream_response_range(
|
||||
app: Sanic, 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)
|
||||
|
||||
@@ -722,7 +722,6 @@ def test_add_webscoket_route_with_version(app):
|
||||
|
||||
|
||||
def test_route_duplicate(app):
|
||||
|
||||
with pytest.raises(RouteExists):
|
||||
|
||||
@app.route("/test")
|
||||
@@ -819,7 +818,6 @@ def test_unquote_add_route(app, unquote):
|
||||
|
||||
|
||||
def test_dynamic_add_route(app):
|
||||
|
||||
results = []
|
||||
|
||||
async def handler(request, name):
|
||||
@@ -834,7 +832,6 @@ def test_dynamic_add_route(app):
|
||||
|
||||
|
||||
def test_dynamic_add_route_string(app):
|
||||
|
||||
results = []
|
||||
|
||||
async def handler(request, name):
|
||||
@@ -938,7 +935,6 @@ def test_dynamic_add_route_unhashable(app):
|
||||
|
||||
|
||||
def test_add_route_duplicate(app):
|
||||
|
||||
with pytest.raises(RouteExists):
|
||||
|
||||
async def handler1(request):
|
||||
@@ -1120,7 +1116,6 @@ def test_route_raise_ParameterNameConflicts(app):
|
||||
|
||||
|
||||
def test_route_invalid_host(app):
|
||||
|
||||
host = 321
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
|
||||
|
||||
@@ -93,6 +93,7 @@ def test_dont_register_system_signals(app):
|
||||
@pytest.mark.skipif(os.name == "nt", reason="windows cannot SIGINT processes")
|
||||
def test_windows_workaround():
|
||||
"""Test Windows workaround (on any other OS)"""
|
||||
|
||||
# At least some code coverage, even though this test doesn't work on
|
||||
# Windows...
|
||||
class MockApp:
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import inspect
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
@@ -13,15 +12,6 @@ from sanic import Sanic, text
|
||||
from sanic.exceptions import FileNotFound
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def static_file_directory():
|
||||
"""The static directory to serve"""
|
||||
current_file = inspect.getfile(inspect.currentframe())
|
||||
current_directory = os.path.dirname(os.path.abspath(current_file))
|
||||
static_directory = os.path.join(current_directory, "static")
|
||||
return static_directory
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def double_dotted_directory_file(static_file_directory: str):
|
||||
"""Generate double dotted directory and its files"""
|
||||
@@ -118,7 +108,12 @@ def test_static_file_pathlib(app, static_file_directory, file_name):
|
||||
def test_static_file_bytes(app, static_file_directory, file_name):
|
||||
bsep = os.path.sep.encode("utf-8")
|
||||
file_path = static_file_directory.encode("utf-8") + bsep + file_name
|
||||
app.static("/testing.file", file_path)
|
||||
message = (
|
||||
"Serving a static directory with a bytes "
|
||||
"string is deprecated and will be removed in v22.9."
|
||||
)
|
||||
with pytest.warns(DeprecationWarning, match=message):
|
||||
app.static("/testing.file", file_path)
|
||||
request, response = app.test_client.get("/testing.file")
|
||||
assert response.status == 200
|
||||
|
||||
@@ -431,7 +426,6 @@ def test_static_stream_large_file(
|
||||
"file_name", ["test.file", "decode me.txt", "python.png"]
|
||||
)
|
||||
def test_use_modified_since(app, 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)
|
||||
|
||||
123
tests/test_static_directory.py
Normal file
123
tests/test_static_directory.py
Normal file
@@ -0,0 +1,123 @@
|
||||
import os
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from sanic import Sanic
|
||||
from sanic.handlers.directory import DirectoryHandler
|
||||
|
||||
|
||||
def get_file_path(static_file_directory, file_name):
|
||||
return os.path.join(static_file_directory, file_name)
|
||||
|
||||
|
||||
def get_file_content(static_file_directory, file_name):
|
||||
"""The content of the static file to check"""
|
||||
with open(get_file_path(static_file_directory, file_name), "rb") as file:
|
||||
return file.read()
|
||||
|
||||
|
||||
def test_static_directory_view(app: Sanic, static_file_directory: str):
|
||||
app.static("/static", static_file_directory, directory_view=True)
|
||||
|
||||
_, response = app.test_client.get("/static/")
|
||||
assert response.status == 200
|
||||
assert response.content_type == "text/html; charset=utf-8"
|
||||
assert "<title>Directory Viewer</title>" in response.text
|
||||
|
||||
|
||||
def test_static_index_single(app: Sanic, static_file_directory: str):
|
||||
app.static("/static", static_file_directory, index="test.html")
|
||||
|
||||
_, response = app.test_client.get("/static/")
|
||||
assert response.status == 200
|
||||
assert response.body == get_file_content(
|
||||
static_file_directory, "test.html"
|
||||
)
|
||||
assert response.headers["Content-Type"] == "text/html"
|
||||
|
||||
|
||||
def test_static_index_single_not_found(app: Sanic, static_file_directory: str):
|
||||
app.static("/static", static_file_directory, index="index.html")
|
||||
|
||||
_, response = app.test_client.get("/static/")
|
||||
assert response.status == 404
|
||||
|
||||
|
||||
def test_static_index_multiple(app: Sanic, static_file_directory: str):
|
||||
app.static(
|
||||
"/static",
|
||||
static_file_directory,
|
||||
index=["index.html", "test.html"],
|
||||
)
|
||||
|
||||
_, response = app.test_client.get("/static/")
|
||||
assert response.status == 200
|
||||
assert response.body == get_file_content(
|
||||
static_file_directory, "test.html"
|
||||
)
|
||||
assert response.headers["Content-Type"] == "text/html"
|
||||
|
||||
|
||||
def test_static_directory_view_and_index(
|
||||
app: Sanic, static_file_directory: str
|
||||
):
|
||||
app.static(
|
||||
"/static",
|
||||
static_file_directory,
|
||||
directory_view=True,
|
||||
index="foo.txt",
|
||||
)
|
||||
|
||||
_, response = app.test_client.get("/static/nested/")
|
||||
assert response.status == 200
|
||||
assert response.content_type == "text/html; charset=utf-8"
|
||||
assert "<title>Directory Viewer</title>" in response.text
|
||||
|
||||
_, response = app.test_client.get("/static/nested/dir/")
|
||||
assert response.status == 200
|
||||
assert response.body == get_file_content(
|
||||
f"{static_file_directory}/nested/dir", "foo.txt"
|
||||
)
|
||||
assert response.content_type == "text/plain"
|
||||
|
||||
|
||||
def test_static_directory_handler(app: Sanic, static_file_directory: str):
|
||||
dh = DirectoryHandler(
|
||||
"/static",
|
||||
Path(static_file_directory),
|
||||
directory_view=True,
|
||||
index="foo.txt",
|
||||
)
|
||||
app.static("/static", static_file_directory, directory_handler=dh)
|
||||
|
||||
_, response = app.test_client.get("/static/nested/")
|
||||
assert response.status == 200
|
||||
assert response.content_type == "text/html; charset=utf-8"
|
||||
assert "<title>Directory Viewer</title>" in response.text
|
||||
|
||||
_, response = app.test_client.get("/static/nested/dir/")
|
||||
assert response.status == 200
|
||||
assert response.body == get_file_content(
|
||||
f"{static_file_directory}/nested/dir", "foo.txt"
|
||||
)
|
||||
assert response.content_type == "text/plain"
|
||||
|
||||
|
||||
def test_static_directory_handler_fails(app: Sanic):
|
||||
dh = DirectoryHandler(
|
||||
"/static",
|
||||
Path(""),
|
||||
directory_view=True,
|
||||
index="foo.txt",
|
||||
)
|
||||
message = (
|
||||
"When explicitly setting directory_handler, you cannot "
|
||||
"set either directory_view or index. Instead, pass "
|
||||
"these arguments to your DirectoryHandler instance."
|
||||
)
|
||||
with pytest.raises(ValueError, match=message):
|
||||
app.static("/static", "", directory_handler=dh, directory_view=True)
|
||||
with pytest.raises(ValueError, match=message):
|
||||
app.static("/static", "", directory_handler=dh, index="index.html")
|
||||
@@ -654,7 +654,6 @@ def test_sanic_ssl_context_create():
|
||||
reason="This test requires fork context",
|
||||
)
|
||||
def test_ssl_in_multiprocess_mode(app: Sanic, caplog):
|
||||
|
||||
ssl_dict = {"cert": localhost_cert, "key": localhost_key}
|
||||
event = Event()
|
||||
|
||||
|
||||
@@ -176,7 +176,6 @@ def handler(request: Request):
|
||||
|
||||
async def client(app: Sanic, loop: AbstractEventLoop):
|
||||
try:
|
||||
|
||||
transport = httpx.AsyncHTTPTransport(uds=SOCKPATH)
|
||||
async with httpx.AsyncClient(transport=transport) as client:
|
||||
r = await client.get("http://myhost.invalid/")
|
||||
|
||||
@@ -83,7 +83,6 @@ def test_simple_url_for_getting_with_more_params(app, args, url):
|
||||
|
||||
|
||||
def test_url_for_with_server_name(app):
|
||||
|
||||
server_name = f"{test_host}:{test_port}"
|
||||
app.config.update({"SERVER_NAME": server_name})
|
||||
path = "/myurl"
|
||||
|
||||
@@ -38,7 +38,6 @@ def test_load_module_from_file_location_with_non_existing_env_variable():
|
||||
LoadFileException,
|
||||
match="The following environment variables are not set: MuuMilk",
|
||||
):
|
||||
|
||||
load_module_from_file_location("${MuuMilk}")
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user