No tracebacks on normal errors and prettier error pages (#1768)
* Default error handler now only logs traceback on 500 errors and all responses are HTML formatted. * Tests passing. * Ability to flag any exception object with self.quiet = True following @ashleysommer suggestion. * Refactor HTML formatting into errorpages.py. String escapes for debug tracebacks. * Remove extra includes * Auto-set quiet flag also when decorator is used. * Cleanup, make error pages (probably) HTML5-compliant and similar for debug and non-debug modes. * Fix lookup of non-existant status codes * No logging of 503 errors after all. * lint
This commit is contained in:
committed by
Stephen Sadowski
parent
b565072ed9
commit
ba9b432993
@@ -105,10 +105,7 @@ def test_app_handle_request_handler_is_none(app, monkeypatch):
|
||||
|
||||
request, response = app.test_client.get("/test")
|
||||
|
||||
assert (
|
||||
response.text
|
||||
== "Error: 'None' was returned while requesting a handler from the router"
|
||||
)
|
||||
assert "'None' was returned while requesting a handler from the router" in response.text
|
||||
|
||||
|
||||
@pytest.mark.parametrize("websocket_enabled", [True, False])
|
||||
@@ -189,7 +186,7 @@ def test_handle_request_with_nested_sanic_exception(app, monkeypatch, caplog):
|
||||
with caplog.at_level(logging.ERROR):
|
||||
request, response = app.test_client.get("/")
|
||||
assert response.status == 500
|
||||
assert response.text == "Error: Mock SanicException"
|
||||
assert "Mock SanicException" in response.text
|
||||
assert (
|
||||
"sanic.root",
|
||||
logging.ERROR,
|
||||
|
||||
@@ -18,4 +18,4 @@ def test_bad_request_response(app):
|
||||
|
||||
app.run(host="127.0.0.1", port=42101, debug=False)
|
||||
assert lines[0] == b"HTTP/1.1 400 Bad Request\r\n"
|
||||
assert lines[-1] == b"Error: Bad Request"
|
||||
assert b"Bad Request" in lines[-1]
|
||||
|
||||
@@ -172,7 +172,7 @@ def test_handled_unhandled_exception(exception_app):
|
||||
request, response = exception_app.test_client.get("/divide_by_zero")
|
||||
assert response.status == 500
|
||||
soup = BeautifulSoup(response.body, "html.parser")
|
||||
assert soup.h1.text == "Internal Server Error"
|
||||
assert "Internal Server Error" in soup.h1.text
|
||||
|
||||
message = " ".join(soup.p.text.split())
|
||||
assert message == (
|
||||
@@ -218,4 +218,4 @@ def test_abort(exception_app):
|
||||
|
||||
request, response = exception_app.test_client.get("/abort/message")
|
||||
assert response.status == 500
|
||||
assert response.text == "Error: Abort"
|
||||
assert "Abort" in response.text
|
||||
|
||||
@@ -86,7 +86,7 @@ def test_html_traceback_output_in_debug_mode():
|
||||
|
||||
summary_text = " ".join(soup.select(".summary")[0].text.split())
|
||||
assert (
|
||||
"NameError: name 'bar' " "is not defined while handling path /4"
|
||||
"NameError: name 'bar' is not defined while handling path /4"
|
||||
) == summary_text
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@ def test_chained_exception_handler():
|
||||
|
||||
summary_text = " ".join(soup.select(".summary")[0].text.split())
|
||||
assert (
|
||||
"ZeroDivisionError: division by zero " "while handling path /6/0"
|
||||
"ZeroDivisionError: division by zero while handling path /6/0"
|
||||
) == summary_text
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import logging
|
||||
|
||||
from asyncio import CancelledError
|
||||
|
||||
from sanic.exceptions import NotFound
|
||||
from sanic.exceptions import NotFound, SanicException
|
||||
from sanic.request import Request
|
||||
from sanic.response import HTTPResponse, text
|
||||
|
||||
@@ -93,7 +93,7 @@ def test_middleware_response_raise_cancelled_error(app, caplog):
|
||||
"sanic.root",
|
||||
logging.ERROR,
|
||||
"Exception occurred while handling uri: 'http://127.0.0.1:42101/'",
|
||||
) in caplog.record_tuples
|
||||
) not in caplog.record_tuples
|
||||
|
||||
|
||||
def test_middleware_response_raise_exception(app, caplog):
|
||||
@@ -102,14 +102,16 @@ def test_middleware_response_raise_exception(app, caplog):
|
||||
raise Exception("Exception at response middleware")
|
||||
|
||||
with caplog.at_level(logging.ERROR):
|
||||
reqrequest, response = app.test_client.get("/")
|
||||
reqrequest, response = app.test_client.get("/fail")
|
||||
|
||||
assert response.status == 404
|
||||
# 404 errors are not logged
|
||||
assert (
|
||||
"sanic.root",
|
||||
logging.ERROR,
|
||||
"Exception occurred while handling uri: 'http://127.0.0.1:42101/'",
|
||||
) in caplog.record_tuples
|
||||
) not in caplog.record_tuples
|
||||
# Middleware exception ignored but logged
|
||||
assert (
|
||||
"sanic.error",
|
||||
logging.ERROR,
|
||||
|
||||
@@ -27,7 +27,7 @@ def test_payload_too_large_at_data_received_default(app):
|
||||
|
||||
response = app.test_client.get("/1", gather_request=False)
|
||||
assert response.status == 413
|
||||
assert response.text == "Error: Payload Too Large"
|
||||
assert "Payload Too Large" in response.text
|
||||
|
||||
|
||||
def test_payload_too_large_at_on_header_default(app):
|
||||
@@ -40,4 +40,4 @@ def test_payload_too_large_at_on_header_default(app):
|
||||
data = "a" * 1000
|
||||
response = app.test_client.post("/1", gather_request=False, data=data)
|
||||
assert response.status == 413
|
||||
assert response.text == "Error: Payload Too Large"
|
||||
assert "Payload Too Large" in response.text
|
||||
|
||||
@@ -329,15 +329,12 @@ def test_request_stream_handle_exception(app):
|
||||
# 404
|
||||
request, response = app.test_client.post("/in_valid_post", data=data)
|
||||
assert response.status == 404
|
||||
assert response.text == "Error: Requested URL /in_valid_post not found"
|
||||
assert "Requested URL /in_valid_post not found" in response.text
|
||||
|
||||
# 405
|
||||
request, response = app.test_client.get("/post/random_id")
|
||||
assert response.status == 405
|
||||
assert (
|
||||
response.text == "Error: Method GET not allowed for URL"
|
||||
" /post/random_id"
|
||||
)
|
||||
assert "Method GET not allowed for URL /post/random_id" in response.text
|
||||
|
||||
|
||||
def test_request_stream_blueprint(app):
|
||||
|
||||
@@ -102,7 +102,7 @@ def test_default_server_error_request_timeout():
|
||||
client = DelayableSanicTestClient(request_timeout_default_app, 2)
|
||||
request, response = client.get("/1")
|
||||
assert response.status == 408
|
||||
assert response.text == "Error: Request Timeout"
|
||||
assert "Request Timeout" in response.text
|
||||
|
||||
|
||||
def test_default_server_error_request_dont_timeout():
|
||||
@@ -125,4 +125,4 @@ def test_default_server_error_websocket_request_timeout():
|
||||
request, response = client.get("/ws1", headers=headers)
|
||||
|
||||
assert response.status == 408
|
||||
assert response.text == "Error: Request Timeout"
|
||||
assert "Request Timeout" in response.text
|
||||
|
||||
@@ -40,7 +40,7 @@ async def handler_2(request):
|
||||
def test_default_server_error_response_timeout():
|
||||
request, response = response_timeout_default_app.test_client.get("/1")
|
||||
assert response.status == 503
|
||||
assert response.text == "Error: Response Timeout"
|
||||
assert "Response Timeout" in response.text
|
||||
|
||||
|
||||
response_handler_cancelled_app.flag = False
|
||||
@@ -65,5 +65,5 @@ async def handler_3(request):
|
||||
def test_response_handler_cancelled():
|
||||
request, response = response_handler_cancelled_app.test_client.get("/1")
|
||||
assert response.status == 503
|
||||
assert response.text == "Error: Response Timeout"
|
||||
assert "Response Timeout" in response.text
|
||||
assert response_handler_cancelled_app.flag is False
|
||||
|
||||
@@ -238,7 +238,7 @@ def test_static_content_range_invalid_unit(
|
||||
request, response = app.test_client.get("/testing.file", headers=headers)
|
||||
|
||||
assert response.status == 416
|
||||
assert response.text == "Error: {} is not a valid Range Type".format(unit)
|
||||
assert f"{unit} is not a valid Range Type" in response.text
|
||||
|
||||
|
||||
@pytest.mark.parametrize("file_name", ["test.file", "decode me.txt"])
|
||||
@@ -256,9 +256,7 @@ def test_static_content_range_invalid_start(
|
||||
request, response = app.test_client.get("/testing.file", headers=headers)
|
||||
|
||||
assert response.status == 416
|
||||
assert response.text == "Error: '{}' is invalid for Content Range".format(
|
||||
start
|
||||
)
|
||||
assert f"'{start}' is invalid for Content Range" in response.text
|
||||
|
||||
|
||||
@pytest.mark.parametrize("file_name", ["test.file", "decode me.txt"])
|
||||
@@ -276,9 +274,7 @@ def test_static_content_range_invalid_end(
|
||||
request, response = app.test_client.get("/testing.file", headers=headers)
|
||||
|
||||
assert response.status == 416
|
||||
assert response.text == "Error: '{}' is invalid for Content Range".format(
|
||||
end
|
||||
)
|
||||
assert f"'{end}' is invalid for Content Range" in response.text
|
||||
|
||||
|
||||
@pytest.mark.parametrize("file_name", ["test.file", "decode me.txt"])
|
||||
@@ -295,7 +291,7 @@ def test_static_content_range_invalid_parameters(
|
||||
request, response = app.test_client.get("/testing.file", headers=headers)
|
||||
|
||||
assert response.status == 416
|
||||
assert response.text == "Error: Invalid for Content Range parameters"
|
||||
assert "Invalid for Content Range parameters" in response.text
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
@@ -369,7 +365,7 @@ def test_file_not_found(app, static_file_directory):
|
||||
request, response = app.test_client.get("/static/not_found")
|
||||
|
||||
assert response.status == 404
|
||||
assert response.text == "Error: File not found"
|
||||
assert "File not found" in response.text
|
||||
|
||||
|
||||
@pytest.mark.parametrize("static_name", ["_static_name", "static"])
|
||||
|
||||
@@ -49,7 +49,7 @@ def test_unexisting_methods(app):
|
||||
request, response = app.test_client.get("/")
|
||||
assert response.text == "I am get method"
|
||||
request, response = app.test_client.post("/")
|
||||
assert response.text == "Error: Method POST not allowed for URL /"
|
||||
assert "Method POST not allowed for URL /" in response.text
|
||||
|
||||
|
||||
def test_argument_methods(app):
|
||||
|
||||
Reference in New Issue
Block a user