Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Limit the cases for E001 to likely scenarios #1925

Merged
merged 3 commits into from
Jul 3, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 30 additions & 2 deletions debug_toolbar/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
from django.conf import settings
from django.core.checks import Error, Warning, register
from django.middleware.gzip import GZipMiddleware
from django.urls import NoReverseMatch, reverse
from django.utils.module_loading import import_string
from django.utils.translation import gettext_lazy as _

from debug_toolbar import settings as dt_settings
from debug_toolbar import APP_NAME, settings as dt_settings
from debug_toolbar.settings import CONFIG_DEFAULTS


class DebugToolbarConfig(AppConfig):
Expand Down Expand Up @@ -213,7 +215,33 @@ def debug_toolbar_installed_when_running_tests_check(app_configs, **kwargs):
"""
Check that the toolbar is not being used when tests are running
"""
if not settings.DEBUG and dt_settings.get_config()["IS_RUNNING_TESTS"]:
# Check if show toolbar callback has changed
show_toolbar_changed = (
dt_settings.get_config()["SHOW_TOOLBAR_CALLBACK"]
!= CONFIG_DEFAULTS["SHOW_TOOLBAR_CALLBACK"]
)
try:
# Check if the toolbar's urls are installed
reverse(f"{APP_NAME}:render_panel")
toolbar_urls_installed = True
except NoReverseMatch:
toolbar_urls_installed = False

# If the user is using the default SHOW_TOOLBAR_CALLBACK,
# then the middleware will respect the change to settings.DEBUG.
# However, if the user has changed the callback to:
# DEBUG_TOOLBAR_CONFIG = {"SHOW_TOOLBAR_CALLBACK": lambda request: DEBUG}
# where DEBUG is not settings.DEBUG, then it won't pick up that Django'
# test runner has changed the value for settings.DEBUG, and the middleware
# will inject the toolbar, while the URLs aren't configured leading to a
# NoReverseMatch error.
likely_error_setup = show_toolbar_changed and not toolbar_urls_installed

if (
not settings.DEBUG
and dt_settings.get_config()["IS_RUNNING_TESTS"]
and likely_error_setup
):
return [
Error(
"The Django Debug Toolbar can't be used with tests",
Expand Down
4 changes: 4 additions & 0 deletions docs/changes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ Change log
Pending
-------

* Limit ``E001`` check to likely error cases when the
``SHOW_TOOLBAR_CALLBACK`` has changed, but the toolbar's URL
paths aren't installed.

4.4.2 (2024-05-27)
------------------

Expand Down
10 changes: 10 additions & 0 deletions docs/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,16 @@ Toolbar options
implication is that it is possible to execute arbitrary SQL through the
SQL panel when the ``SECRET_KEY`` value is leaked somehow.

.. warning::

Do not use
``DEBUG_TOOLBAR_CONFIG = {"SHOW_TOOLBAR_CALLBACK": lambda request: DEBUG}``
in your project's settings.py file. The toolbar expects to use
``django.conf.settings.DEBUG``. Using your project's setting's ``DEBUG``
is likely to cause unexpected when running your tests. This is because
tim-schilling marked this conversation as resolved.
Show resolved Hide resolved
Django automatically sets ``settings.DEBUG = False``, but your project's
setting's ``DEBUG`` will still be set to ``True``.

.. _OBSERVE_REQUEST_CALLBACK:

* ``OBSERVE_REQUEST_CALLBACK``
Expand Down
99 changes: 65 additions & 34 deletions tests/test_checks.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from unittest.mock import patch

from django.core.checks import Error, Warning, run_checks
from django.core.checks import Warning, run_checks
from django.test import SimpleTestCase, override_settings
from django.urls import NoReverseMatch

from debug_toolbar import settings as dt_settings
from debug_toolbar.apps import debug_toolbar_installed_when_running_tests_check


Expand Down Expand Up @@ -239,39 +239,70 @@ def test_check_w007_invalid(self, mocked_guess_type):
],
)

def test_debug_toolbar_installed_when_running_tests(self):
with self.settings(DEBUG=True):
# Update the config options because self.settings()
# would require redefining DEBUG_TOOLBAR_CONFIG entirely.
dt_settings.get_config()["IS_RUNNING_TESTS"] = True
errors = debug_toolbar_installed_when_running_tests_check(None)
self.assertEqual(len(errors), 0)

dt_settings.get_config()["IS_RUNNING_TESTS"] = False
errors = debug_toolbar_installed_when_running_tests_check(None)
self.assertEqual(len(errors), 0)
with self.settings(DEBUG=False):
dt_settings.get_config()["IS_RUNNING_TESTS"] = False
errors = debug_toolbar_installed_when_running_tests_check(None)
self.assertEqual(len(errors), 0)
@patch("debug_toolbar.apps.reverse")
def test_debug_toolbar_installed_when_running_tests(self, reverse):
params = [
{
"debug": True,
"running_tests": True,
"show_callback_changed": True,
"urls_installed": False,
"errors": False,
},
{
"debug": False,
"running_tests": False,
"show_callback_changed": True,
"urls_installed": False,
"errors": False,
},
{
"debug": False,
"running_tests": True,
"show_callback_changed": False,
"urls_installed": False,
"errors": False,
},
{
"debug": False,
"running_tests": True,
"show_callback_changed": True,
"urls_installed": True,
"errors": False,
},
{
"debug": False,
"running_tests": True,
"show_callback_changed": True,
"urls_installed": False,
"errors": True,
},
]
for config in params:
with self.subTest(**config):
config_setting = {
"RENDER_PANELS": False,
"IS_RUNNING_TESTS": config["running_tests"],
"SHOW_TOOLBAR_CALLBACK": (
(lambda *args: True)
if config["show_callback_changed"]
else "debug_toolbar.middleware.show_toolbar"
),
}
if config["urls_installed"]:
reverse.side_effect = lambda *args: None
else:
reverse.side_effect = NoReverseMatch()

dt_settings.get_config()["IS_RUNNING_TESTS"] = True
errors = debug_toolbar_installed_when_running_tests_check(None)
self.assertEqual(
errors,
[
Error(
"The Django Debug Toolbar can't be used with tests",
hint="Django changes the DEBUG setting to False when running "
"tests. By default the Django Debug Toolbar is installed because "
"DEBUG is set to True. For most cases, you need to avoid installing "
"the toolbar when running tests. If you feel this check is in error, "
"you can set `DEBUG_TOOLBAR_CONFIG['IS_RUNNING_TESTS'] = False` to "
"bypass this check.",
id="debug_toolbar.E001",
)
],
)
with self.settings(
DEBUG=config["debug"], DEBUG_TOOLBAR_CONFIG=config_setting
):
errors = debug_toolbar_installed_when_running_tests_check(None)
if config["errors"]:
self.assertEqual(len(errors), 1)
self.assertEqual(errors[0].id, "debug_toolbar.E001")
else:
self.assertEqual(len(errors), 0)

@override_settings(
DEBUG_TOOLBAR_CONFIG={
Expand Down