From 96f1cb4b0d4b10903502e917ddaa460bc05f5ca3 Mon Sep 17 00:00:00 2001 From: Aymeric Augustin Date: Fri, 1 Nov 2013 21:51:37 +0100 Subject: Split tests across several modules. Fix #426. --- tests/base.py | 26 +++ tests/commands/__init__.py | 0 tests/commands/test_debugsqlshell.py | 34 +++ tests/panels/__init__.py | 0 tests/panels/test_logger.py | 53 +++++ tests/panels/test_sql.py | 73 +++++++ tests/panels/test_template.py | 31 +++ tests/test_integration.py | 185 +++++++++++++++++ tests/test_utils.py | 24 +++ tests/tests.py | 389 +---------------------------------- 10 files changed, 433 insertions(+), 382 deletions(-) create mode 100644 tests/base.py create mode 100644 tests/commands/__init__.py create mode 100644 tests/commands/test_debugsqlshell.py create mode 100644 tests/panels/__init__.py create mode 100644 tests/panels/test_logger.py create mode 100644 tests/panels/test_sql.py create mode 100644 tests/panels/test_template.py create mode 100644 tests/test_integration.py create mode 100644 tests/test_utils.py (limited to 'tests') diff --git a/tests/base.py b/tests/base.py new file mode 100644 index 0000000..e6f6dac --- /dev/null +++ b/tests/base.py @@ -0,0 +1,26 @@ +from __future__ import unicode_literals + +import threading + +from django.http import HttpResponse +from django.test import TestCase, RequestFactory + +from debug_toolbar.middleware import DebugToolbarMiddleware +from debug_toolbar.toolbar.loader import DebugToolbar + +rf = RequestFactory() + + +class BaseTestCase(TestCase): + + def setUp(self): + request = rf.get('/') + response = HttpResponse() + toolbar = DebugToolbar(request) + + DebugToolbarMiddleware.debug_toolbars[threading.current_thread().ident] = toolbar + + self.request = request + self.response = response + self.toolbar = toolbar + self.toolbar.stats = {} diff --git a/tests/commands/__init__.py b/tests/commands/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/commands/test_debugsqlshell.py b/tests/commands/test_debugsqlshell.py new file mode 100644 index 0000000..f35ef07 --- /dev/null +++ b/tests/commands/test_debugsqlshell.py @@ -0,0 +1,34 @@ +from __future__ import unicode_literals + +import sys + +from django.contrib.auth.models import User +from django.core import management +from django.db.backends import util +from django.test import TestCase +from django.test.utils import override_settings +from django.utils import six + + +@override_settings(DEBUG=True) +class DebugSQLShellTestCase(TestCase): + + def setUp(self): + self.original_cursor_wrapper = util.CursorDebugWrapper + # Since debugsqlshell monkey-patches django.db.backends.util, we can + # test it simply by loading it, without executing it. But we have to + # undo the monkey-patch on exit. + command_name = 'debugsqlshell' + app_name = management.get_commands()[command_name] + management.load_command_class(app_name, command_name) + + def tearDown(self): + util.CursorDebugWrapper = self.original_cursor_wrapper + + def test_command(self): + original_stdout, sys.stdout = sys.stdout, six.StringIO() + try: + User.objects.count() + self.assertIn("SELECT COUNT(*)", sys.stdout.getvalue()) + finally: + sys.stdout = original_stdout diff --git a/tests/panels/__init__.py b/tests/panels/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/panels/test_logger.py b/tests/panels/test_logger.py new file mode 100644 index 0000000..477d100 --- /dev/null +++ b/tests/panels/test_logger.py @@ -0,0 +1,53 @@ +from __future__ import unicode_literals + +import logging + +from debug_toolbar.panels.logger import ( + LoggingPanel, MESSAGE_IF_STRING_REPRESENTATION_INVALID) + +from ..base import BaseTestCase + + +class LoggingPanelTestCase(BaseTestCase): + + def test_happy_case(self): + logger = logging.getLogger(__name__) + logger.info('Nothing to see here, move along!') + + logging_panel = self.toolbar.get_panel(LoggingPanel) + logging_panel.process_response(None, None) + records = logging_panel.get_stats()['records'] + + self.assertEqual(1, len(records)) + self.assertEqual('Nothing to see here, move along!', + records[0]['message']) + + def test_formatting(self): + logger = logging.getLogger(__name__) + logger.info('There are %d %s', 5, 'apples') + + logging_panel = self.toolbar.get_panel(LoggingPanel) + logging_panel.process_response(None, None) + records = logging_panel.get_stats()['records'] + + self.assertEqual(1, len(records)) + self.assertEqual('There are 5 apples', + records[0]['message']) + + def test_failing_formatting(self): + class BadClass(object): + def __str__(self): + raise Exception('Please not stringify me!') + + logger = logging.getLogger(__name__) + + # should not raise exception, but fail silently + logger.debug('This class is misbehaving: %s', BadClass()) + + logging_panel = self.toolbar.get_panel(LoggingPanel) + logging_panel.process_response(None, None) + records = logging_panel.get_stats()['records'] + + self.assertEqual(1, len(records)) + self.assertEqual(MESSAGE_IF_STRING_REPRESENTATION_INVALID, + records[0]['message']) diff --git a/tests/panels/test_sql.py b/tests/panels/test_sql.py new file mode 100644 index 0000000..10846f5 --- /dev/null +++ b/tests/panels/test_sql.py @@ -0,0 +1,73 @@ +# coding: utf-8 + +from __future__ import unicode_literals + +from django.contrib.auth.models import User +from django.db import connection +from django.db.utils import DatabaseError +from django.utils import unittest + +from debug_toolbar.panels.sql import SQLDebugPanel + +from ..base import BaseTestCase + + +class SQLPanelTestCase(BaseTestCase): + + def test_recording(self): + panel = self.toolbar.get_panel(SQLDebugPanel) + self.assertEqual(len(panel._queries), 0) + + list(User.objects.all()) + + # ensure query was logged + self.assertEqual(len(panel._queries), 1) + query = panel._queries[0] + self.assertEqual(query[0], 'default') + self.assertTrue('sql' in query[1]) + self.assertTrue('duration' in query[1]) + self.assertTrue('stacktrace' in query[1]) + + # ensure the stacktrace is populated + self.assertTrue(len(query[1]['stacktrace']) > 0) + + def test_non_ascii_query(self): + panel = self.toolbar.get_panel(SQLDebugPanel) + self.assertEqual(len(panel._queries), 0) + + # non-ASCII query + list(User.objects.extra(where=["username = 'café'"])) + self.assertEqual(len(panel._queries), 1) + + # non-ASCII parameters + list(User.objects.filter(username='café')) + self.assertEqual(len(panel._queries), 2) + + @unittest.skipUnless(connection.vendor == 'postgresql', + 'Test valid only on PostgreSQL') + def test_erroneous_query(self): + """ + Test that an error in the query isn't swallowed by the middleware. + """ + try: + connection.cursor().execute("erroneous query") + except DatabaseError as e: + self.assertTrue('erroneous query' in str(e)) + + def test_disable_stacktraces(self): + panel = self.toolbar.get_panel(SQLDebugPanel) + self.assertEqual(len(panel._queries), 0) + + with self.settings(DEBUG_TOOLBAR_CONFIG={'ENABLE_STACKTRACES': False}): + list(User.objects.all()) + + # ensure query was logged + self.assertEqual(len(panel._queries), 1) + query = panel._queries[0] + self.assertEqual(query[0], 'default') + self.assertTrue('sql' in query[1]) + self.assertTrue('duration' in query[1]) + self.assertTrue('stacktrace' in query[1]) + + # ensure the stacktrace is empty + self.assertEqual([], query[1]['stacktrace']) diff --git a/tests/panels/test_template.py b/tests/panels/test_template.py new file mode 100644 index 0000000..4e30a73 --- /dev/null +++ b/tests/panels/test_template.py @@ -0,0 +1,31 @@ +from __future__ import unicode_literals + +import django +from django.contrib.auth.models import User +from django.template import Template, Context + +from debug_toolbar.panels.template import TemplateDebugPanel +from debug_toolbar.panels.sql import SQLDebugPanel + +from ..base import BaseTestCase + + +class TemplateDebugPanelTestCase(BaseTestCase): + + def test_queryset_hook(self): + template_panel = self.toolbar.get_panel(TemplateDebugPanel) + sql_panel = self.toolbar.get_panel(SQLDebugPanel) + t = Template("No context variables here!") + c = Context({ + 'queryset': User.objects.all(), + 'deep_queryset': { + 'queryset': User.objects.all(), + } + }) + t.render(c) + # ensure the query was NOT logged + self.assertEqual(len(sql_panel._queries), 0) + base_ctx_idx = 1 if django.VERSION[:2] >= (1, 5) else 0 + ctx = template_panel.templates[0]['context'][base_ctx_idx] + self.assertIn('<>', ctx) + self.assertIn('<>', ctx) diff --git a/tests/test_integration.py b/tests/test_integration.py new file mode 100644 index 0000000..41206fc --- /dev/null +++ b/tests/test_integration.py @@ -0,0 +1,185 @@ +# coding: utf-8 + +from __future__ import unicode_literals + +from xml.etree import ElementTree as ET + +from django.contrib.auth.models import User +from django.db import IntegrityError, transaction +from django.test import TestCase, RequestFactory +from django.test.utils import override_settings +from django.utils import six + +from debug_toolbar.middleware import DebugToolbarMiddleware, show_toolbar +from debug_toolbar.panels.request_vars import RequestVarsDebugPanel + +from .base import BaseTestCase + + +rf = RequestFactory() + + +@override_settings(DEBUG=True) +class DebugToolbarTestCase(BaseTestCase): + + urls = 'tests.urls' + + def test_show_toolbar(self): + self.assertTrue(show_toolbar(self.request)) + + def test_show_toolbar_DEBUG(self): + with self.settings(DEBUG=False): + self.assertFalse(show_toolbar(self.request)) + + def test_show_toolbar_INTERNAL_IPS(self): + with self.settings(INTERNAL_IPS=[]): + self.assertFalse(show_toolbar(self.request)) + + def test_request_urlconf_string(self): + request = rf.get('/') + request.urlconf = 'tests.urls' + middleware = DebugToolbarMiddleware() + + middleware.process_request(request) + + self.assertFalse(isinstance(request.urlconf, six.string_types)) + + patterns = request.urlconf.urlpatterns + self.assertTrue(hasattr(patterns[1], '_callback_str')) + self.assertEqual(patterns[-1]._callback_str, 'tests.views.execute_sql') + + def test_request_urlconf_string_per_request(self): + request = rf.get('/') + request.urlconf = 'debug_toolbar.urls' + middleware = DebugToolbarMiddleware() + + middleware.process_request(request) + request.urlconf = 'tests.urls' + middleware.process_request(request) + + self.assertFalse(isinstance(request.urlconf, six.string_types)) + + patterns = request.urlconf.urlpatterns + self.assertTrue(hasattr(patterns[1], '_callback_str')) + self.assertEqual(patterns[-1]._callback_str, 'tests.views.execute_sql') + + def test_request_urlconf_module(self): + request = rf.get('/') + request.urlconf = __import__('tests.urls').urls + middleware = DebugToolbarMiddleware() + + middleware.process_request(request) + + self.assertFalse(isinstance(request.urlconf, six.string_types)) + + patterns = request.urlconf.urlpatterns + self.assertTrue(hasattr(patterns[1], '_callback_str')) + self.assertEqual(patterns[-1]._callback_str, 'tests.views.execute_sql') + + def test_tuple_urlconf(self): + request = rf.get('/') + urls = __import__('tests.urls').urls + urls.urlpatterns = tuple(urls.urlpatterns) + request.urlconf = urls + middleware = DebugToolbarMiddleware() + + middleware.process_request(request) + + self.assertFalse(isinstance(request.urlconf, six.string_types)) + + def _resolve_stats(self, path): + # takes stats from RequestVars panel + self.request.path = path + panel = self.toolbar.get_panel(RequestVarsDebugPanel) + panel.process_request(self.request) + panel.process_response(self.request, self.response) + return self.toolbar.stats['requestvars'] + + def test_url_resolving_positional(self): + stats = self._resolve_stats('/resolving1/a/b/') + self.assertEqual(stats['view_urlname'], 'positional-resolving') + self.assertEqual(stats['view_func'], 'tests.views.resolving_view') + self.assertEqual(stats['view_args'], ('a', 'b')) + self.assertEqual(stats['view_kwargs'], {}) + + def test_url_resolving_named(self): + stats = self._resolve_stats('/resolving2/a/b/') + self.assertEqual(stats['view_args'], ()) + self.assertEqual(stats['view_kwargs'], {'arg1': 'a', 'arg2': 'b'}) + + def test_url_resolving_mixed(self): + stats = self._resolve_stats('/resolving3/a/') + self.assertEqual(stats['view_args'], ('a',)) + self.assertEqual(stats['view_kwargs'], {'arg2': 'default'}) + + def test_url_resolving_bad(self): + stats = self._resolve_stats('/non-existing-url/') + self.assertEqual(stats['view_urlname'], 'None') + self.assertEqual(stats['view_args'], 'None') + self.assertEqual(stats['view_kwargs'], 'None') + self.assertEqual(stats['view_func'], '') + + +@override_settings(DEBUG=True) +class DebugToolbarIntegrationTestCase(TestCase): + + urls = 'tests.urls' + + def test_middleware(self): + response = self.client.get('/execute_sql/') + self.assertEqual(response.status_code, 200) + + @override_settings(DEFAULT_CHARSET='iso-8859-1') + def test_non_utf8_charset(self): + response = self.client.get('/regular/ASCII/') + self.assertContains(response, 'ASCII') # template + self.assertContains(response, 'djDebug') # toolbar + + response = self.client.get('/regular/LÀTÍN/') + self.assertContains(response, 'LÀTÍN') # template + self.assertContains(response, 'djDebug') # toolbar + + def test_non_ascii_bytes_in_db_params(self): + response = self.client.get('/non_ascii_bytes_in_db_params/') + if six.PY3: + self.assertContains(response, 'djàngó') + else: + self.assertContains(response, 'dj\\xe0ng\\xf3') + + def test_non_ascii_session(self): + response = self.client.get('/set_session/') + if six.PY3: + self.assertContains(response, 'où') + else: + self.assertContains(response, 'o\\xf9') + self.assertContains(response, 'l\\xc3\\xa0') + + def test_object_with_non_ascii_repr_in_context(self): + response = self.client.get('/non_ascii_context/') + self.assertContains(response, 'nôt åscíì') + + def test_object_with_non_ascii_repr_in_request_vars(self): + response = self.client.get('/non_ascii_request/') + self.assertContains(response, 'nôt åscíì') + + def test_xml_validation(self): + response = self.client.get('/regular/XML/') + ET.fromstring(response.content) # shouldn't raise ParseError + + def test_view_executed_once(self): + with self.settings( + DEBUG_TOOLBAR_PANELS=['debug_toolbar.panels.profiling.ProfilingDebugPanel']): + + self.assertEqual(User.objects.count(), 0) + + response = self.client.get('/new_user/') + self.assertContains(response, 'Profiling') + self.assertEqual(User.objects.count(), 1) + + with self.assertRaises(IntegrityError): + if hasattr(transaction, 'atomic'): # Django >= 1.6 + with transaction.atomic(): + response = self.client.get('/new_user/') + else: + response = self.client.get('/new_user/') + self.assertEqual(User.objects.count(), 1) diff --git a/tests/test_utils.py b/tests/test_utils.py new file mode 100644 index 0000000..a930894 --- /dev/null +++ b/tests/test_utils.py @@ -0,0 +1,24 @@ +from __future__ import unicode_literals + +from django.utils.unittest import TestCase + +from debug_toolbar.utils import get_name_from_obj + + +class GetNameFromObjTestCase(TestCase): + + def test_func(self): + def x(): + return 1 + res = get_name_from_obj(x) + self.assertEqual(res, 'tests.test_utils.x') + + def test_lambda(self): + res = get_name_from_obj(lambda: 1) + self.assertEqual(res, 'tests.test_utils.') + + def test_class(self): + class A: + pass + res = get_name_from_obj(A) + self.assertEqual(res, 'tests.test_utils.A') diff --git a/tests/tests.py b/tests/tests.py index 8bbf5b0..10e0a9b 100644 --- a/tests/tests.py +++ b/tests/tests.py @@ -1,384 +1,9 @@ -# coding: utf-8 - -from __future__ import unicode_literals - -import logging -import sys -import threading -from xml.etree import ElementTree as ET - import django -from django.contrib.auth.models import User -from django.core import management -from django.db import connection, IntegrityError, transaction -from django.db.backends import util -from django.http import HttpResponse -from django.test import TestCase, RequestFactory -from django.test.utils import override_settings -from django.template import Template, Context -from django.utils import six -from django.utils import unittest - -from debug_toolbar.middleware import DebugToolbarMiddleware, show_toolbar -from debug_toolbar.panels.logger import ( - LoggingPanel, MESSAGE_IF_STRING_REPRESENTATION_INVALID) -from debug_toolbar.panels.sql import SQLDebugPanel -from debug_toolbar.panels.request_vars import RequestVarsDebugPanel -from debug_toolbar.panels.template import TemplateDebugPanel -from debug_toolbar.toolbar.loader import DebugToolbar -from debug_toolbar.utils import get_name_from_obj - - -rf = RequestFactory() - - -class BaseTestCase(TestCase): - - def setUp(self): - request = rf.get('/') - response = HttpResponse() - toolbar = DebugToolbar(request) - - DebugToolbarMiddleware.debug_toolbars[threading.current_thread().ident] = toolbar - - self.request = request - self.response = response - self.toolbar = toolbar - self.toolbar.stats = {} - - -@override_settings(DEBUG=True) -class DebugToolbarTestCase(BaseTestCase): - - urls = 'tests.urls' - - def test_show_toolbar(self): - self.assertTrue(show_toolbar(self.request)) - - def test_show_toolbar_DEBUG(self): - with self.settings(DEBUG=False): - self.assertFalse(show_toolbar(self.request)) - - def test_show_toolbar_INTERNAL_IPS(self): - with self.settings(INTERNAL_IPS=[]): - self.assertFalse(show_toolbar(self.request)) - - def test_request_urlconf_string(self): - request = rf.get('/') - request.urlconf = 'tests.urls' - middleware = DebugToolbarMiddleware() - - middleware.process_request(request) - - self.assertFalse(isinstance(request.urlconf, six.string_types)) - - patterns = request.urlconf.urlpatterns - self.assertTrue(hasattr(patterns[1], '_callback_str')) - self.assertEqual(patterns[-1]._callback_str, 'tests.views.execute_sql') - - def test_request_urlconf_string_per_request(self): - request = rf.get('/') - request.urlconf = 'debug_toolbar.urls' - middleware = DebugToolbarMiddleware() - - middleware.process_request(request) - request.urlconf = 'tests.urls' - middleware.process_request(request) - - self.assertFalse(isinstance(request.urlconf, six.string_types)) - - patterns = request.urlconf.urlpatterns - self.assertTrue(hasattr(patterns[1], '_callback_str')) - self.assertEqual(patterns[-1]._callback_str, 'tests.views.execute_sql') - - def test_request_urlconf_module(self): - request = rf.get('/') - request.urlconf = __import__('tests.urls').urls - middleware = DebugToolbarMiddleware() - - middleware.process_request(request) - - self.assertFalse(isinstance(request.urlconf, six.string_types)) - - patterns = request.urlconf.urlpatterns - self.assertTrue(hasattr(patterns[1], '_callback_str')) - self.assertEqual(patterns[-1]._callback_str, 'tests.views.execute_sql') - - def test_tuple_urlconf(self): - request = rf.get('/') - urls = __import__('tests.urls').urls - urls.urlpatterns = tuple(urls.urlpatterns) - request.urlconf = urls - middleware = DebugToolbarMiddleware() - - middleware.process_request(request) - - self.assertFalse(isinstance(request.urlconf, six.string_types)) - - def _resolve_stats(self, path): - # takes stats from RequestVars panel - self.request.path = path - panel = self.toolbar.get_panel(RequestVarsDebugPanel) - panel.process_request(self.request) - panel.process_response(self.request, self.response) - return self.toolbar.stats['requestvars'] - - def test_url_resolving_positional(self): - stats = self._resolve_stats('/resolving1/a/b/') - self.assertEqual(stats['view_urlname'], 'positional-resolving') - self.assertEqual(stats['view_func'], 'tests.views.resolving_view') - self.assertEqual(stats['view_args'], ('a', 'b')) - self.assertEqual(stats['view_kwargs'], {}) - - def test_url_resolving_named(self): - stats = self._resolve_stats('/resolving2/a/b/') - self.assertEqual(stats['view_args'], ()) - self.assertEqual(stats['view_kwargs'], {'arg1': 'a', 'arg2': 'b'}) - - def test_url_resolving_mixed(self): - stats = self._resolve_stats('/resolving3/a/') - self.assertEqual(stats['view_args'], ('a',)) - self.assertEqual(stats['view_kwargs'], {'arg2': 'default'}) - - def test_url_resolving_bad(self): - stats = self._resolve_stats('/non-existing-url/') - self.assertEqual(stats['view_urlname'], 'None') - self.assertEqual(stats['view_args'], 'None') - self.assertEqual(stats['view_kwargs'], 'None') - self.assertEqual(stats['view_func'], '') - - -@override_settings(DEBUG=True) -class DebugToolbarIntegrationTestCase(TestCase): - - urls = 'tests.urls' - - def test_middleware(self): - response = self.client.get('/execute_sql/') - self.assertEqual(response.status_code, 200) - - @override_settings(DEFAULT_CHARSET='iso-8859-1') - def test_non_utf8_charset(self): - response = self.client.get('/regular/ASCII/') - self.assertContains(response, 'ASCII') # template - self.assertContains(response, 'djDebug') # toolbar - - response = self.client.get('/regular/LÀTÍN/') - self.assertContains(response, 'LÀTÍN') # template - self.assertContains(response, 'djDebug') # toolbar - - def test_non_ascii_bytes_in_db_params(self): - response = self.client.get('/non_ascii_bytes_in_db_params/') - if six.PY3: - self.assertContains(response, 'djàngó') - else: - self.assertContains(response, 'dj\\xe0ng\\xf3') - - def test_non_ascii_session(self): - response = self.client.get('/set_session/') - if six.PY3: - self.assertContains(response, 'où') - else: - self.assertContains(response, 'o\\xf9') - self.assertContains(response, 'l\\xc3\\xa0') - - def test_object_with_non_ascii_repr_in_context(self): - response = self.client.get('/non_ascii_context/') - self.assertContains(response, 'nôt åscíì') - - def test_object_with_non_ascii_repr_in_request_vars(self): - response = self.client.get('/non_ascii_request/') - self.assertContains(response, 'nôt åscíì') - - def test_xml_validation(self): - response = self.client.get('/regular/XML/') - ET.fromstring(response.content) # shouldn't raise ParseError - - def test_view_executed_once(self): - with self.settings( - DEBUG_TOOLBAR_PANELS=['debug_toolbar.panels.profiling.ProfilingDebugPanel']): - - self.assertEqual(User.objects.count(), 0) - - response = self.client.get('/new_user/') - self.assertContains(response, 'Profiling') - self.assertEqual(User.objects.count(), 1) - - with self.assertRaises(IntegrityError): - if hasattr(transaction, 'atomic'): # Django >= 1.6 - with transaction.atomic(): - response = self.client.get('/new_user/') - else: - response = self.client.get('/new_user/') - self.assertEqual(User.objects.count(), 1) - - -class DebugToolbarNameFromObjectTest(BaseTestCase): - - def test_func(self): - def x(): - return 1 - res = get_name_from_obj(x) - self.assertEqual(res, 'tests.tests.x') - - def test_lambda(self): - res = get_name_from_obj(lambda: 1) - self.assertEqual(res, 'tests.tests.') - - def test_class(self): - class A: - pass - res = get_name_from_obj(A) - self.assertEqual(res, 'tests.tests.A') - - -class SQLPanelTestCase(BaseTestCase): - - def test_recording(self): - panel = self.toolbar.get_panel(SQLDebugPanel) - self.assertEqual(len(panel._queries), 0) - - list(User.objects.all()) - - # ensure query was logged - self.assertEqual(len(panel._queries), 1) - query = panel._queries[0] - self.assertEqual(query[0], 'default') - self.assertTrue('sql' in query[1]) - self.assertTrue('duration' in query[1]) - self.assertTrue('stacktrace' in query[1]) - - # ensure the stacktrace is populated - self.assertTrue(len(query[1]['stacktrace']) > 0) - - def test_non_ascii_query(self): - panel = self.toolbar.get_panel(SQLDebugPanel) - self.assertEqual(len(panel._queries), 0) - - # non-ASCII query - list(User.objects.extra(where=["username = 'café'"])) - self.assertEqual(len(panel._queries), 1) - - # non-ASCII parameters - list(User.objects.filter(username='café')) - self.assertEqual(len(panel._queries), 2) - - @unittest.skipUnless(connection.vendor == 'postgresql', - 'Test valid only on PostgreSQL') - def test_erroneous_query(self): - """ - Test that an error in the query isn't swallowed by the middleware. - """ - from django.db import connection - from django.db.utils import DatabaseError - try: - connection.cursor().execute("erroneous query") - except DatabaseError as e: - self.assertTrue('erroneous query' in str(e)) - - def test_disable_stacktraces(self): - panel = self.toolbar.get_panel(SQLDebugPanel) - self.assertEqual(len(panel._queries), 0) - - with self.settings(DEBUG_TOOLBAR_CONFIG={'ENABLE_STACKTRACES': False}): - list(User.objects.all()) - - # ensure query was logged - self.assertEqual(len(panel._queries), 1) - query = panel._queries[0] - self.assertEqual(query[0], 'default') - self.assertTrue('sql' in query[1]) - self.assertTrue('duration' in query[1]) - self.assertTrue('stacktrace' in query[1]) - - # ensure the stacktrace is empty - self.assertEqual([], query[1]['stacktrace']) - - -class TemplatePanelTestCase(BaseTestCase): - - def test_queryset_hook(self): - template_panel = self.toolbar.get_panel(TemplateDebugPanel) - sql_panel = self.toolbar.get_panel(SQLDebugPanel) - t = Template("No context variables here!") - c = Context({ - 'queryset': User.objects.all(), - 'deep_queryset': { - 'queryset': User.objects.all(), - } - }) - t.render(c) - # ensure the query was NOT logged - self.assertEqual(len(sql_panel._queries), 0) - base_ctx_idx = 1 if django.VERSION[:2] >= (1, 5) else 0 - ctx = template_panel.templates[0]['context'][base_ctx_idx] - self.assertIn('<>', ctx) - self.assertIn('<>', ctx) - - -class LoggingPanelTestCase(BaseTestCase): - def test_happy_case(self): - logger = logging.getLogger(__name__) - logger.info('Nothing to see here, move along!') - - logging_panel = self.toolbar.get_panel(LoggingPanel) - logging_panel.process_response(None, None) - records = logging_panel.get_stats()['records'] - - self.assertEqual(1, len(records)) - self.assertEqual('Nothing to see here, move along!', - records[0]['message']) - - def test_formatting(self): - logger = logging.getLogger(__name__) - logger.info('There are %d %s', 5, 'apples') - - logging_panel = self.toolbar.get_panel(LoggingPanel) - logging_panel.process_response(None, None) - records = logging_panel.get_stats()['records'] - - self.assertEqual(1, len(records)) - self.assertEqual('There are 5 apples', - records[0]['message']) - - def test_failing_formatting(self): - class BadClass(object): - def __str__(self): - raise Exception('Please not stringify me!') - - logger = logging.getLogger(__name__) - - # should not raise exception, but fail silently - logger.debug('This class is misbehaving: %s', BadClass()) - - logging_panel = self.toolbar.get_panel(LoggingPanel) - logging_panel.process_response(None, None) - records = logging_panel.get_stats()['records'] - - self.assertEqual(1, len(records)) - self.assertEqual(MESSAGE_IF_STRING_REPRESENTATION_INVALID, - records[0]['message']) - - -@override_settings(DEBUG=True) -class DebugSQLShellTestCase(TestCase): - - def setUp(self): - self.original_cursor_wrapper = util.CursorDebugWrapper - # Since debugsqlshell monkey-patches django.db.backends.util, we can - # test it simply by loading it, without executing it. But we have to - # undo the monkey-patch on exit. - command_name = 'debugsqlshell' - app_name = management.get_commands()[command_name] - management.load_command_class(app_name, command_name) - - def tearDown(self): - util.CursorDebugWrapper = self.original_cursor_wrapper - def test_command(self): - original_stdout, sys.stdout = sys.stdout, six.StringIO() - try: - User.objects.count() - self.assertIn("SELECT COUNT(*)", sys.stdout.getvalue()) - finally: - sys.stdout = original_stdout +if django.VERSION[:2] < (1, 6): # unittest-style discovery isn't available + from .commands.test_debugsqlshell import * # noqa + from .panels.test_logger import * # noqa + from .panels.test_sql import * # noqa + from .panels.test_template import * # noqa + from .test_integration import * # noqa + from .test_utils import * # noqa -- cgit v1.2.3