Skip to content

Commit 32fd8de

Browse files
committed
[4.2.x] Added helpers in csrf_tests and logging_tests to assert logs from log_response().
Backport of ad6f998 from main.
1 parent acbe655 commit 32fd8de

File tree

2 files changed

+57
-38
lines changed

2 files changed

+57
-38
lines changed

tests/csrf_tests/tests.py

Lines changed: 26 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import logging
12
import re
23

34
from django.conf import settings
@@ -57,6 +58,21 @@ def assertMaskedSecretCorrect(self, masked_secret, secret):
5758
actual = _unmask_cipher_token(masked_secret)
5859
self.assertEqual(actual, secret)
5960

61+
def assertForbiddenReason(
62+
self, response, logger_cm, reason, levelno=logging.WARNING
63+
):
64+
self.assertEqual(
65+
records_len := len(logger_cm.records),
66+
1,
67+
f"Unexpected number of records for {logger_cm=} in {levelno=} (expected 1, "
68+
f"got {records_len}).",
69+
)
70+
record = logger_cm.records[0]
71+
self.assertEqual(record.getMessage(), "Forbidden (%s): " % reason)
72+
self.assertEqual(record.levelno, levelno)
73+
self.assertEqual(record.status_code, 403)
74+
self.assertEqual(response.status_code, 403)
75+
6076

6177
class CsrfFunctionTests(CsrfFunctionTestMixin, SimpleTestCase):
6278
def test_unmask_cipher_token(self):
@@ -347,8 +363,7 @@ def _check_bad_or_missing_cookie(self, cookie, expected):
347363
mw.process_request(req)
348364
with self.assertLogs("django.security.csrf", "WARNING") as cm:
349365
resp = mw.process_view(req, post_form_view, (), {})
350-
self.assertEqual(403, resp.status_code)
351-
self.assertEqual(cm.records[0].getMessage(), "Forbidden (%s): " % expected)
366+
self.assertForbiddenReason(resp, cm, expected)
352367

353368
def test_no_csrf_cookie(self):
354369
"""
@@ -373,9 +388,8 @@ def _check_bad_or_missing_token(
373388
mw.process_request(req)
374389
with self.assertLogs("django.security.csrf", "WARNING") as cm:
375390
resp = mw.process_view(req, post_form_view, (), {})
376-
self.assertEqual(403, resp.status_code)
377391
self.assertEqual(resp["Content-Type"], "text/html; charset=utf-8")
378-
self.assertEqual(cm.records[0].getMessage(), "Forbidden (%s): " % expected)
392+
self.assertForbiddenReason(resp, cm, expected)
379393

380394
def test_csrf_cookie_bad_or_missing_token(self):
381395
"""
@@ -480,18 +494,12 @@ def test_put_and_delete_rejected(self):
480494
mw = CsrfViewMiddleware(post_form_view)
481495
with self.assertLogs("django.security.csrf", "WARNING") as cm:
482496
resp = mw.process_view(req, post_form_view, (), {})
483-
self.assertEqual(403, resp.status_code)
484-
self.assertEqual(
485-
cm.records[0].getMessage(), "Forbidden (%s): " % REASON_NO_CSRF_COOKIE
486-
)
497+
self.assertForbiddenReason(resp, cm, REASON_NO_CSRF_COOKIE)
487498

488499
req = self._get_request(method="DELETE")
489500
with self.assertLogs("django.security.csrf", "WARNING") as cm:
490501
resp = mw.process_view(req, post_form_view, (), {})
491-
self.assertEqual(403, resp.status_code)
492-
self.assertEqual(
493-
cm.records[0].getMessage(), "Forbidden (%s): " % REASON_NO_CSRF_COOKIE
494-
)
502+
self.assertForbiddenReason(resp, cm, REASON_NO_CSRF_COOKIE)
495503

496504
def test_put_and_delete_allowed(self):
497505
"""
@@ -879,11 +887,7 @@ def test_reading_post_data_raises_unreadable_post_error(self):
879887
mw.process_request(req)
880888
with self.assertLogs("django.security.csrf", "WARNING") as cm:
881889
resp = mw.process_view(req, post_form_view, (), {})
882-
self.assertEqual(resp.status_code, 403)
883-
self.assertEqual(
884-
cm.records[0].getMessage(),
885-
"Forbidden (%s): " % REASON_CSRF_TOKEN_MISSING,
886-
)
890+
self.assertForbiddenReason(resp, cm, REASON_CSRF_TOKEN_MISSING)
887891

888892
def test_reading_post_data_raises_os_error(self):
889893
"""
@@ -908,9 +912,8 @@ def test_bad_origin_bad_domain(self):
908912
self.assertIs(mw._origin_verified(req), False)
909913
with self.assertLogs("django.security.csrf", "WARNING") as cm:
910914
response = mw.process_view(req, post_form_view, (), {})
911-
self.assertEqual(response.status_code, 403)
912915
msg = REASON_BAD_ORIGIN % req.META["HTTP_ORIGIN"]
913-
self.assertEqual(cm.records[0].getMessage(), "Forbidden (%s): " % msg)
916+
self.assertForbiddenReason(response, cm, msg)
914917

915918
@override_settings(ALLOWED_HOSTS=["www.example.com"])
916919
def test_bad_origin_null_origin(self):
@@ -923,9 +926,8 @@ def test_bad_origin_null_origin(self):
923926
self.assertIs(mw._origin_verified(req), False)
924927
with self.assertLogs("django.security.csrf", "WARNING") as cm:
925928
response = mw.process_view(req, post_form_view, (), {})
926-
self.assertEqual(response.status_code, 403)
927929
msg = REASON_BAD_ORIGIN % req.META["HTTP_ORIGIN"]
928-
self.assertEqual(cm.records[0].getMessage(), "Forbidden (%s): " % msg)
930+
self.assertForbiddenReason(response, cm, msg)
929931

930932
@override_settings(ALLOWED_HOSTS=["www.example.com"])
931933
def test_bad_origin_bad_protocol(self):
@@ -939,9 +941,8 @@ def test_bad_origin_bad_protocol(self):
939941
self.assertIs(mw._origin_verified(req), False)
940942
with self.assertLogs("django.security.csrf", "WARNING") as cm:
941943
response = mw.process_view(req, post_form_view, (), {})
942-
self.assertEqual(response.status_code, 403)
943944
msg = REASON_BAD_ORIGIN % req.META["HTTP_ORIGIN"]
944-
self.assertEqual(cm.records[0].getMessage(), "Forbidden (%s): " % msg)
945+
self.assertForbiddenReason(response, cm, msg)
945946

946947
@override_settings(
947948
ALLOWED_HOSTS=["www.example.com"],
@@ -966,9 +967,8 @@ def test_bad_origin_csrf_trusted_origin_bad_protocol(self):
966967
self.assertIs(mw._origin_verified(req), False)
967968
with self.assertLogs("django.security.csrf", "WARNING") as cm:
968969
response = mw.process_view(req, post_form_view, (), {})
969-
self.assertEqual(response.status_code, 403)
970970
msg = REASON_BAD_ORIGIN % req.META["HTTP_ORIGIN"]
971-
self.assertEqual(cm.records[0].getMessage(), "Forbidden (%s): " % msg)
971+
self.assertForbiddenReason(response, cm, msg)
972972
self.assertEqual(mw.allowed_origins_exact, {"http://no-match.com"})
973973
self.assertEqual(
974974
mw.allowed_origin_subdomains,
@@ -992,9 +992,8 @@ def test_bad_origin_cannot_be_parsed(self):
992992
self.assertIs(mw._origin_verified(req), False)
993993
with self.assertLogs("django.security.csrf", "WARNING") as cm:
994994
response = mw.process_view(req, post_form_view, (), {})
995-
self.assertEqual(response.status_code, 403)
996995
msg = REASON_BAD_ORIGIN % req.META["HTTP_ORIGIN"]
997-
self.assertEqual(cm.records[0].getMessage(), "Forbidden (%s): " % msg)
996+
self.assertForbiddenReason(response, cm, msg)
998997

999998
@override_settings(ALLOWED_HOSTS=["www.example.com"])
1000999
def test_good_origin_insecure(self):

tests/logging_tests/tests.py

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,28 @@ def test_django_logger_debug(self):
9494

9595

9696
class LoggingAssertionMixin:
97+
98+
def assertLogRecord(
99+
self,
100+
logger_cm,
101+
level,
102+
msg,
103+
status_code,
104+
exc_class=None,
105+
):
106+
self.assertEqual(
107+
records_len := len(logger_cm.records),
108+
1,
109+
f"Wrong number of calls for {logger_cm=} in {level=} (expected 1, got "
110+
f"{records_len}).",
111+
)
112+
record = logger_cm.records[0]
113+
self.assertEqual(record.getMessage(), msg)
114+
self.assertEqual(record.status_code, status_code)
115+
if exc_class:
116+
self.assertIsNotNone(record.exc_info)
117+
self.assertEqual(record.exc_info[0], exc_class)
118+
97119
def assertLogsRequest(
98120
self, url, level, msg, status_code, logger="django.request", exc_class=None
99121
):
@@ -102,17 +124,7 @@ def assertLogsRequest(
102124
self.client.get(url)
103125
except views.UncaughtException:
104126
pass
105-
self.assertEqual(
106-
len(cm.records),
107-
1,
108-
"Wrong number of calls for logger %r in %r level." % (logger, level),
109-
)
110-
record = cm.records[0]
111-
self.assertEqual(record.getMessage(), msg)
112-
self.assertEqual(record.status_code, status_code)
113-
if exc_class:
114-
self.assertIsNotNone(record.exc_info)
115-
self.assertEqual(record.exc_info[0], exc_class)
127+
self.assertLogRecord(cm, level, msg, status_code, exc_class)
116128

117129

118130
@override_settings(DEBUG=True, ROOT_URLCONF="logging_tests.urls")
@@ -135,6 +147,14 @@ def test_page_not_found_warning(self):
135147
msg="Not Found: /does_not_exist/",
136148
)
137149

150+
async def test_async_page_not_found_warning(self):
151+
logger = "django.request"
152+
level = "WARNING"
153+
with self.assertLogs(logger, level) as cm:
154+
await self.async_client.get("/does_not_exist/")
155+
156+
self.assertLogRecord(cm, level, "Not Found: /does_not_exist/", 404)
157+
138158
def test_page_not_found_raised(self):
139159
self.assertLogsRequest(
140160
url="/does_not_exist_raised/",

0 commit comments

Comments
 (0)