mirror of
https://github.com/django/django.git
synced 2025-06-05 11:39:13 +00:00
Captured logging in tests with self.assertLogs().
This commit is contained in:
parent
607970f31c
commit
523e04dfeb
@ -1,4 +1,3 @@
|
|||||||
import logging
|
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
from django.core.handlers.wsgi import WSGIRequest
|
from django.core.handlers.wsgi import WSGIRequest
|
||||||
@ -18,36 +17,26 @@ class Stub:
|
|||||||
class WSGIRequestHandlerTestCase(SimpleTestCase):
|
class WSGIRequestHandlerTestCase(SimpleTestCase):
|
||||||
|
|
||||||
def test_log_message(self):
|
def test_log_message(self):
|
||||||
# Silence the django.server logger by replacing its StreamHandler with
|
request = WSGIRequest(RequestFactory().get('/').environ)
|
||||||
# NullHandler.
|
request.makefile = lambda *args, **kwargs: BytesIO()
|
||||||
logger = logging.getLogger('django.server')
|
handler = WSGIRequestHandler(request, '192.168.0.2', None)
|
||||||
original_handlers = logger.handlers
|
level_status_codes = {
|
||||||
logger.handlers = [logging.NullHandler()]
|
'info': [200, 301, 304],
|
||||||
try:
|
'warning': [400, 403, 404],
|
||||||
request = WSGIRequest(RequestFactory().get('/').environ)
|
'error': [500, 503],
|
||||||
request.makefile = lambda *args, **kwargs: BytesIO()
|
}
|
||||||
handler = WSGIRequestHandler(request, '192.168.0.2', None)
|
for level, status_codes in level_status_codes.items():
|
||||||
level_status_codes = {
|
for status_code in status_codes:
|
||||||
'info': [200, 301, 304],
|
# The correct level gets the message.
|
||||||
'warning': [400, 403, 404],
|
with self.assertLogs('django.server', level.upper()) as cm:
|
||||||
'error': [500, 503],
|
handler.log_message('GET %s %s', 'A', str(status_code))
|
||||||
}
|
self.assertIn('GET A %d' % status_code, cm.output[0])
|
||||||
|
# Incorrect levels don't have any messages.
|
||||||
for level, status_codes in level_status_codes.items():
|
for wrong_level in level_status_codes:
|
||||||
for status_code in status_codes:
|
if wrong_level != level:
|
||||||
# The correct level gets the message.
|
with self.assertLogs('django.server', 'INFO') as cm:
|
||||||
with self.assertLogs('django.server', level.upper()) as cm:
|
handler.log_message('GET %s %s', 'A', str(status_code))
|
||||||
handler.log_message('GET %s %s', 'A', str(status_code))
|
self.assertNotEqual(cm.records[0].levelname, wrong_level.upper())
|
||||||
self.assertIn('GET A %d' % status_code, cm.output[0])
|
|
||||||
|
|
||||||
# Incorrect levels shouldn't have any messages.
|
|
||||||
for wrong_level in level_status_codes:
|
|
||||||
if wrong_level != level:
|
|
||||||
with self.assertRaisesMessage(AssertionError, 'no logs'):
|
|
||||||
with self.assertLogs('django.template', level.upper()):
|
|
||||||
handler.log_message('GET %s %s', 'A', str(status_code))
|
|
||||||
finally:
|
|
||||||
logger.handlers = original_handlers
|
|
||||||
|
|
||||||
def test_https(self):
|
def test_https(self):
|
||||||
request = WSGIRequest(RequestFactory().get('/').environ)
|
request = WSGIRequest(RequestFactory().get('/').environ)
|
||||||
|
@ -4,29 +4,7 @@ from django.template import Engine, Variable, VariableDoesNotExist
|
|||||||
from django.test import SimpleTestCase
|
from django.test import SimpleTestCase
|
||||||
|
|
||||||
|
|
||||||
class TestHandler(logging.Handler):
|
class VariableResolveLoggingTests(SimpleTestCase):
|
||||||
def __init__(self):
|
|
||||||
super().__init__()
|
|
||||||
self.log_record = None
|
|
||||||
|
|
||||||
def emit(self, record):
|
|
||||||
self.log_record = record
|
|
||||||
|
|
||||||
|
|
||||||
class BaseTemplateLoggingTestCase(SimpleTestCase):
|
|
||||||
def setUp(self):
|
|
||||||
self.test_handler = TestHandler()
|
|
||||||
self.logger = logging.getLogger('django.template')
|
|
||||||
self.original_level = self.logger.level
|
|
||||||
self.logger.addHandler(self.test_handler)
|
|
||||||
self.logger.setLevel(self.loglevel)
|
|
||||||
|
|
||||||
def tearDown(self):
|
|
||||||
self.logger.removeHandler(self.test_handler)
|
|
||||||
self.logger.level = self.original_level
|
|
||||||
|
|
||||||
|
|
||||||
class VariableResolveLoggingTests(BaseTemplateLoggingTestCase):
|
|
||||||
loglevel = logging.DEBUG
|
loglevel = logging.DEBUG
|
||||||
|
|
||||||
def test_log_on_variable_does_not_exist_silent(self):
|
def test_log_on_variable_does_not_exist_silent(self):
|
||||||
@ -52,31 +30,38 @@ class VariableResolveLoggingTests(BaseTemplateLoggingTestCase):
|
|||||||
def __getitem__(self, item):
|
def __getitem__(self, item):
|
||||||
return self.__dict__[item]
|
return self.__dict__[item]
|
||||||
|
|
||||||
Variable('article').resolve(TestObject())
|
with self.assertLogs('django.template', self.loglevel) as cm:
|
||||||
|
Variable('article').resolve(TestObject())
|
||||||
|
|
||||||
|
self.assertEqual(len(cm.records), 1)
|
||||||
|
log_record = cm.records[0]
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.test_handler.log_record.getMessage(),
|
log_record.getMessage(),
|
||||||
"Exception while resolving variable 'article' in template 'template_name'."
|
"Exception while resolving variable 'article' in template 'template_name'."
|
||||||
)
|
)
|
||||||
self.assertIsNotNone(self.test_handler.log_record.exc_info)
|
self.assertIsNotNone(log_record.exc_info)
|
||||||
raised_exception = self.test_handler.log_record.exc_info[1]
|
raised_exception = log_record.exc_info[1]
|
||||||
self.assertEqual(str(raised_exception), 'Attribute does not exist.')
|
self.assertEqual(str(raised_exception), 'Attribute does not exist.')
|
||||||
|
|
||||||
def test_log_on_variable_does_not_exist_not_silent(self):
|
def test_log_on_variable_does_not_exist_not_silent(self):
|
||||||
with self.assertRaises(VariableDoesNotExist):
|
with self.assertLogs('django.template', self.loglevel) as cm:
|
||||||
Variable('article.author').resolve({'article': {'section': 'News'}})
|
with self.assertRaises(VariableDoesNotExist):
|
||||||
|
Variable('article.author').resolve({'article': {'section': 'News'}})
|
||||||
|
|
||||||
|
self.assertEqual(len(cm.records), 1)
|
||||||
|
log_record = cm.records[0]
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.test_handler.log_record.getMessage(),
|
log_record.getMessage(),
|
||||||
"Exception while resolving variable 'author' in template 'unknown'."
|
"Exception while resolving variable 'author' in template 'unknown'."
|
||||||
)
|
)
|
||||||
self.assertIsNotNone(self.test_handler.log_record.exc_info)
|
self.assertIsNotNone(log_record.exc_info)
|
||||||
raised_exception = self.test_handler.log_record.exc_info[1]
|
raised_exception = log_record.exc_info[1]
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
str(raised_exception),
|
str(raised_exception),
|
||||||
"Failed lookup for key [author] in {'section': 'News'}"
|
"Failed lookup for key [author] in {'section': 'News'}"
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_no_log_when_variable_exists(self):
|
def test_no_log_when_variable_exists(self):
|
||||||
Variable('article.section').resolve({'article': {'section': 'News'}})
|
with self.assertRaisesMessage(AssertionError, 'no logs'):
|
||||||
self.assertIsNone(self.test_handler.log_record)
|
with self.assertLogs('django.template', self.loglevel):
|
||||||
|
Variable('article.section').resolve({'article': {'section': 'News'}})
|
||||||
|
@ -57,22 +57,25 @@ class CallableSettingWrapperTests(SimpleTestCase):
|
|||||||
|
|
||||||
|
|
||||||
@override_settings(DEBUG=True, ROOT_URLCONF='view_tests.urls')
|
@override_settings(DEBUG=True, ROOT_URLCONF='view_tests.urls')
|
||||||
class DebugViewTests(LoggingCaptureMixin, SimpleTestCase):
|
class DebugViewTests(SimpleTestCase):
|
||||||
|
|
||||||
def test_files(self):
|
def test_files(self):
|
||||||
response = self.client.get('/raises/')
|
with self.assertLogs('django.request', 'ERROR'):
|
||||||
|
response = self.client.get('/raises/')
|
||||||
self.assertEqual(response.status_code, 500)
|
self.assertEqual(response.status_code, 500)
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
'file_data.txt': SimpleUploadedFile('file_data.txt', b'haha'),
|
'file_data.txt': SimpleUploadedFile('file_data.txt', b'haha'),
|
||||||
}
|
}
|
||||||
response = self.client.post('/raises/', data)
|
with self.assertLogs('django.request', 'ERROR'):
|
||||||
|
response = self.client.post('/raises/', data)
|
||||||
self.assertContains(response, 'file_data.txt', status_code=500)
|
self.assertContains(response, 'file_data.txt', status_code=500)
|
||||||
self.assertNotContains(response, 'haha', status_code=500)
|
self.assertNotContains(response, 'haha', status_code=500)
|
||||||
|
|
||||||
def test_400(self):
|
def test_400(self):
|
||||||
# When DEBUG=True, technical_500_template() is called.
|
# When DEBUG=True, technical_500_template() is called.
|
||||||
response = self.client.get('/raises400/')
|
with self.assertLogs('django.security', 'WARNING'):
|
||||||
|
response = self.client.get('/raises400/')
|
||||||
self.assertContains(response, '<div class="context" id="', status_code=400)
|
self.assertContains(response, '<div class="context" id="', status_code=400)
|
||||||
|
|
||||||
# Ensure no 403.html template exists to test the default case.
|
# Ensure no 403.html template exists to test the default case.
|
||||||
@ -139,7 +142,8 @@ class DebugViewTests(LoggingCaptureMixin, SimpleTestCase):
|
|||||||
Numeric IDs and fancy traceback context blocks line numbers shouldn't be localized.
|
Numeric IDs and fancy traceback context blocks line numbers shouldn't be localized.
|
||||||
"""
|
"""
|
||||||
with self.settings(DEBUG=True, USE_L10N=True):
|
with self.settings(DEBUG=True, USE_L10N=True):
|
||||||
response = self.client.get('/raises500/')
|
with self.assertLogs('django.request', 'ERROR'):
|
||||||
|
response = self.client.get('/raises500/')
|
||||||
# We look for a HTML fragment of the form
|
# We look for a HTML fragment of the form
|
||||||
# '<div class="context" id="c38123208">', not '<div class="context" id="c38,123,208"'
|
# '<div class="context" id="c38123208">', not '<div class="context" id="c38,123,208"'
|
||||||
self.assertContains(response, '<div class="context" id="', status_code=500)
|
self.assertContains(response, '<div class="context" id="', status_code=500)
|
||||||
@ -152,15 +156,16 @@ class DebugViewTests(LoggingCaptureMixin, SimpleTestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def test_template_exceptions(self):
|
def test_template_exceptions(self):
|
||||||
try:
|
with self.assertLogs('django.request', 'ERROR'):
|
||||||
self.client.get(reverse('template_exception'))
|
try:
|
||||||
except Exception:
|
self.client.get(reverse('template_exception'))
|
||||||
raising_loc = inspect.trace()[-1][-2][0].strip()
|
except Exception:
|
||||||
self.assertNotEqual(
|
raising_loc = inspect.trace()[-1][-2][0].strip()
|
||||||
raising_loc.find("raise Exception('boom')"), -1,
|
self.assertNotEqual(
|
||||||
"Failed to find 'raise Exception' in last frame of "
|
raising_loc.find("raise Exception('boom')"), -1,
|
||||||
"traceback, instead found: %s" % raising_loc
|
"Failed to find 'raise Exception' in last frame of "
|
||||||
)
|
"traceback, instead found: %s" % raising_loc
|
||||||
|
)
|
||||||
|
|
||||||
def test_template_loader_postmortem(self):
|
def test_template_loader_postmortem(self):
|
||||||
"""Tests for not existing file"""
|
"""Tests for not existing file"""
|
||||||
@ -171,7 +176,7 @@ class DebugViewTests(LoggingCaptureMixin, SimpleTestCase):
|
|||||||
with override_settings(TEMPLATES=[{
|
with override_settings(TEMPLATES=[{
|
||||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||||
'DIRS': [tempdir],
|
'DIRS': [tempdir],
|
||||||
}]):
|
}]), self.assertLogs('django.request', 'ERROR'):
|
||||||
response = self.client.get(reverse('raises_template_does_not_exist', kwargs={"path": template_name}))
|
response = self.client.get(reverse('raises_template_does_not_exist', kwargs={"path": template_name}))
|
||||||
self.assertContains(response, "%s (Source does not exist)" % template_path, status_code=500, count=2)
|
self.assertContains(response, "%s (Source does not exist)" % template_path, status_code=500, count=2)
|
||||||
# Assert as HTML.
|
# Assert as HTML.
|
||||||
@ -187,8 +192,9 @@ class DebugViewTests(LoggingCaptureMixin, SimpleTestCase):
|
|||||||
"""
|
"""
|
||||||
Make sure if you don't specify a template, the debug view doesn't blow up.
|
Make sure if you don't specify a template, the debug view doesn't blow up.
|
||||||
"""
|
"""
|
||||||
with self.assertRaises(TemplateDoesNotExist):
|
with self.assertLogs('django.request', 'ERROR'):
|
||||||
self.client.get('/render_no_template/')
|
with self.assertRaises(TemplateDoesNotExist):
|
||||||
|
self.client.get('/render_no_template/')
|
||||||
|
|
||||||
@override_settings(ROOT_URLCONF='view_tests.default_urls')
|
@override_settings(ROOT_URLCONF='view_tests.default_urls')
|
||||||
def test_default_urlconf_template(self):
|
def test_default_urlconf_template(self):
|
||||||
@ -253,7 +259,8 @@ class NonDjangoTemplatesDebugViewTests(SimpleTestCase):
|
|||||||
|
|
||||||
def test_400(self):
|
def test_400(self):
|
||||||
# When DEBUG=True, technical_500_template() is called.
|
# When DEBUG=True, technical_500_template() is called.
|
||||||
response = self.client.get('/raises400/')
|
with self.assertLogs('django.security', 'WARNING'):
|
||||||
|
response = self.client.get('/raises400/')
|
||||||
self.assertContains(response, '<div class="context" id="', status_code=400)
|
self.assertContains(response, '<div class="context" id="', status_code=400)
|
||||||
|
|
||||||
def test_403(self):
|
def test_403(self):
|
||||||
@ -267,7 +274,8 @@ class NonDjangoTemplatesDebugViewTests(SimpleTestCase):
|
|||||||
def test_template_not_found_error(self):
|
def test_template_not_found_error(self):
|
||||||
# Raises a TemplateDoesNotExist exception and shows the debug view.
|
# Raises a TemplateDoesNotExist exception and shows the debug view.
|
||||||
url = reverse('raises_template_does_not_exist', kwargs={"path": "notfound.html"})
|
url = reverse('raises_template_does_not_exist', kwargs={"path": "notfound.html"})
|
||||||
response = self.client.get(url)
|
with self.assertLogs('django.request', 'ERROR'):
|
||||||
|
response = self.client.get(url)
|
||||||
self.assertContains(response, '<div class="context" id="', status_code=500)
|
self.assertContains(response, '<div class="context" id="', status_code=500)
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user