Skip to content

Commit bb92aca

Browse files
committed
[5.1.x] Refs #26688 -- Added tests for log_response() internal helper.
Backport of 8970468 from main.
1 parent 85bdeb3 commit bb92aca

File tree

1 file changed

+122
-1
lines changed

1 file changed

+122
-1
lines changed

tests/logging_tests/tests.py

Lines changed: 122 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import logging
22
from contextlib import contextmanager
33
from io import StringIO
4-
from unittest import mock
4+
from unittest import TestCase, mock
55

66
from admin_scripts.tests import AdminScriptTestCase
77

@@ -10,6 +10,7 @@
1010
from django.core.exceptions import DisallowedHost, PermissionDenied, SuspiciousOperation
1111
from django.core.files.temp import NamedTemporaryFile
1212
from django.core.management import color
13+
from django.http import HttpResponse
1314
from django.http.multipartparser import MultiPartParserError
1415
from django.test import RequestFactory, SimpleTestCase, override_settings
1516
from django.test.utils import LoggingCaptureMixin
@@ -20,6 +21,7 @@
2021
RequireDebugFalse,
2122
RequireDebugTrue,
2223
ServerFormatter,
24+
log_response,
2325
)
2426
from django.views.debug import ExceptionReporter
2527

@@ -665,3 +667,122 @@ def patch_django_server_logger():
665667
self.assertRegex(
666668
logger_output.getvalue(), r"^\[[/:,\w\s\d]+\] %s\n" % log_msg
667669
)
670+
671+
672+
class LogResponseRealLoggerTests(TestCase):
673+
674+
request = RequestFactory().get("/test-path/")
675+
676+
def assertResponseLogged(self, logger_cm, msg, levelno, status_code, request):
677+
self.assertEqual(
678+
records_len := len(logger_cm.records),
679+
1,
680+
f"Unexpected number of records for {logger_cm=} in {levelno=} (expected 1, "
681+
f"got {records_len}).",
682+
)
683+
record = logger_cm.records[0]
684+
self.assertEqual(record.getMessage(), msg)
685+
self.assertEqual(record.levelno, levelno)
686+
self.assertEqual(record.status_code, status_code)
687+
self.assertEqual(record.request, request)
688+
689+
def test_missing_response_raises_attribute_error(self):
690+
with self.assertRaises(AttributeError):
691+
log_response("No response provided", response=None, request=self.request)
692+
693+
def test_missing_request_logs_with_none(self):
694+
response = HttpResponse(status=403)
695+
with self.assertLogs("django.request", level="INFO") as cm:
696+
log_response(msg := "Missing request", response=response, request=None)
697+
self.assertResponseLogged(cm, msg, logging.WARNING, 403, request=None)
698+
699+
def test_logs_5xx_as_error(self):
700+
response = HttpResponse(status=508)
701+
with self.assertLogs("django.request", level="ERROR") as cm:
702+
log_response(
703+
msg := "Server error occurred", response=response, request=self.request
704+
)
705+
self.assertResponseLogged(cm, msg, logging.ERROR, 508, self.request)
706+
707+
def test_logs_4xx_as_warning(self):
708+
response = HttpResponse(status=418)
709+
with self.assertLogs("django.request", level="WARNING") as cm:
710+
log_response(
711+
msg := "This is a teapot!", response=response, request=self.request
712+
)
713+
self.assertResponseLogged(cm, msg, logging.WARNING, 418, self.request)
714+
715+
def test_logs_2xx_as_info(self):
716+
response = HttpResponse(status=201)
717+
with self.assertLogs("django.request", level="INFO") as cm:
718+
log_response(msg := "OK response", response=response, request=self.request)
719+
self.assertResponseLogged(cm, msg, logging.INFO, 201, self.request)
720+
721+
def test_custom_log_level(self):
722+
response = HttpResponse(status=403)
723+
with self.assertLogs("django.request", level="DEBUG") as cm:
724+
log_response(
725+
msg := "Debug level log",
726+
response=response,
727+
request=self.request,
728+
level="debug",
729+
)
730+
self.assertResponseLogged(cm, msg, logging.DEBUG, 403, self.request)
731+
732+
def test_logs_only_once_per_response(self):
733+
response = HttpResponse(status=500)
734+
with self.assertLogs("django.request", level="ERROR") as cm:
735+
log_response("First log", response=response, request=self.request)
736+
log_response("Second log", response=response, request=self.request)
737+
self.assertResponseLogged(cm, "First log", logging.ERROR, 500, self.request)
738+
739+
def test_exc_info_output(self):
740+
response = HttpResponse(status=500)
741+
try:
742+
raise ValueError("Simulated failure")
743+
except ValueError as exc:
744+
with self.assertLogs("django.request", level="ERROR") as cm:
745+
log_response(
746+
"With exception",
747+
response=response,
748+
request=self.request,
749+
exception=exc,
750+
)
751+
self.assertResponseLogged(
752+
cm, "With exception", logging.ERROR, 500, self.request
753+
)
754+
self.assertIn("ValueError", "\n".join(cm.output)) # Stack trace included
755+
756+
def test_format_args_are_applied(self):
757+
response = HttpResponse(status=500)
758+
with self.assertLogs("django.request", level="ERROR") as cm:
759+
log_response(
760+
"Something went wrong: %s (%d)",
761+
"DB error",
762+
42,
763+
response=response,
764+
request=self.request,
765+
)
766+
msg = "Something went wrong: DB error (42)"
767+
self.assertResponseLogged(cm, msg, logging.ERROR, 500, self.request)
768+
769+
def test_logs_with_custom_logger(self):
770+
handler = logging.StreamHandler(log_stream := StringIO())
771+
handler.setFormatter(logging.Formatter("%(levelname)s:%(name)s:%(message)s"))
772+
773+
custom_logger = logging.getLogger("my.custom.logger")
774+
custom_logger.setLevel(logging.DEBUG)
775+
custom_logger.addHandler(handler)
776+
self.addCleanup(custom_logger.removeHandler, handler)
777+
778+
response = HttpResponse(status=404)
779+
log_response(
780+
msg := "Handled by custom logger",
781+
response=response,
782+
request=self.request,
783+
logger=custom_logger,
784+
)
785+
786+
self.assertEqual(
787+
f"WARNING:my.custom.logger:{msg}", log_stream.getvalue().strip()
788+
)

0 commit comments

Comments
 (0)