# -*- coding: utf-8 -*- from __future__ import unicode_literals from django.utils.six import StringIO import sys from django.apps import apps from django.conf import settings from django.core import checks from django.core.checks import Error, Warning from django.core.checks.registry import CheckRegistry from django.core.checks.compatibility.django_1_6_0 import check_1_6_compatibility from django.core.checks.compatibility.django_1_7_0 import check_1_7_compatibility from django.core.management.base import CommandError from django.core.management import call_command from django.db.models.fields import NOT_PROVIDED from django.test import TestCase from django.test.utils import override_settings, override_system_checks from django.utils.encoding import force_text from .models import SimpleModel, Book class DummyObj(object): def __repr__(self): return "obj" class SystemCheckFrameworkTests(TestCase): def test_register_and_run_checks(self): calls = [0] registry = CheckRegistry() @registry.register() def f(**kwargs): calls[0] += 1 return [1, 2, 3] errors = registry.run_checks() self.assertEqual(errors, [1, 2, 3]) self.assertEqual(calls[0], 1) class MessageTests(TestCase): def test_printing(self): e = Error("Message", hint="Hint", obj=DummyObj()) expected = "obj: Message\n\tHINT: Hint" self.assertEqual(force_text(e), expected) def test_printing_no_hint(self): e = Error("Message", hint=None, obj=DummyObj()) expected = "obj: Message" self.assertEqual(force_text(e), expected) def test_printing_no_object(self): e = Error("Message", hint="Hint", obj=None) expected = "?: Message\n\tHINT: Hint" self.assertEqual(force_text(e), expected) def test_printing_with_given_id(self): e = Error("Message", hint="Hint", obj=DummyObj(), id="ID") expected = "obj: (ID) Message\n\tHINT: Hint" self.assertEqual(force_text(e), expected) def test_printing_field_error(self): field = SimpleModel._meta.get_field('field') e = Error("Error", hint=None, obj=field) expected = "check_framework.SimpleModel.field: Error" self.assertEqual(force_text(e), expected) def test_printing_model_error(self): e = Error("Error", hint=None, obj=SimpleModel) expected = "check_framework.SimpleModel: Error" self.assertEqual(force_text(e), expected) def test_printing_manager_error(self): manager = SimpleModel.manager e = Error("Error", hint=None, obj=manager) expected = "check_framework.SimpleModel.manager: Error" self.assertEqual(force_text(e), expected) class Django_1_6_0_CompatibilityChecks(TestCase): @override_settings(TEST_RUNNER='django.test.runner.DiscoverRunner') def test_test_runner_new_default(self): errors = check_1_6_compatibility() self.assertEqual(errors, []) @override_settings(TEST_RUNNER='myapp.test.CustomRunner') def test_test_runner_overriden(self): errors = check_1_6_compatibility() self.assertEqual(errors, []) def test_test_runner_not_set_explicitly(self): # If TEST_RUNNER was set explicitly, temporarily pretend it wasn't test_runner_overridden = False if 'TEST_RUNNER' in settings._wrapped._explicit_settings: test_runner_overridden = True settings._wrapped._explicit_settings.remove('TEST_RUNNER') # We remove some settings to make this look like a project generated under Django 1.5. settings._wrapped._explicit_settings.add('MANAGERS') settings._wrapped._explicit_settings.add('ADMINS') try: errors = check_1_6_compatibility() expected = [ checks.Warning( "Some project unittests may not execute as expected.", hint=("Django 1.6 introduced a new default test runner. It looks like " "this project was generated using Django 1.5 or earlier. You should " "ensure your tests are all running & behaving as expected. See " "https://docs.djangoproject.com/en/dev/releases/1.6/#new-test-runner " "for more information."), obj=None, id='1_6.W001', ) ] self.assertEqual(errors, expected) finally: # Restore settings value if test_runner_overridden: settings._wrapped._explicit_settings.add('TEST_RUNNER') settings._wrapped._explicit_settings.remove('MANAGERS') settings._wrapped._explicit_settings.remove('ADMINS') def test_boolean_field_default_value(self): with self.settings(TEST_RUNNER='myapp.test.CustomRunnner'): # We patch the field's default value to trigger the warning boolean_field = Book._meta.get_field('is_published') old_default = boolean_field.default try: boolean_field.default = NOT_PROVIDED errors = check_1_6_compatibility() expected = [ checks.Warning( 'BooleanField does not have a default value.', hint=('Django 1.6 changed the default value of BooleanField from False to None. ' 'See https://docs.djangoproject.com/en/1.6/ref/models/fields/#booleanfield ' 'for more information.'), obj=boolean_field, id='1_6.W002', ) ] self.assertEqual(errors, expected) finally: # Restore the ``default`` boolean_field.default = old_default class Django_1_7_0_CompatibilityChecks(TestCase): @override_settings(MIDDLEWARE_CLASSES=('django.contrib.sessions.middleware.SessionMiddleware',)) def test_middleware_classes_overridden(self): errors = check_1_7_compatibility() self.assertEqual(errors, []) def test_middleware_classes_not_set_explicitly(self): # If MIDDLEWARE_CLASSES was set explicitly, temporarily pretend it wasn't middleware_classes_overridden = False if 'MIDDLEWARE_CLASSES' in settings._wrapped._explicit_settings: middleware_classes_overridden = True settings._wrapped._explicit_settings.remove('MIDDLEWARE_CLASSES') try: errors = check_1_7_compatibility() expected = [ checks.Warning( "MIDDLEWARE_CLASSES is not set.", hint=("Django 1.7 changed the global defaults for the MIDDLEWARE_CLASSES. " "django.contrib.sessions.middleware.SessionMiddleware, " "django.contrib.auth.middleware.AuthenticationMiddleware, and " "django.contrib.messages.middleware.MessageMiddleware were removed from the defaults. " "If your project needs these middleware then you should configure this setting."), obj=None, id='1_7.W001', ) ] self.assertEqual(errors, expected) finally: # Restore settings value if middleware_classes_overridden: settings._wrapped._explicit_settings.add('MIDDLEWARE_CLASSES') def simple_system_check(**kwargs): simple_system_check.kwargs = kwargs return [] def tagged_system_check(**kwargs): tagged_system_check.kwargs = kwargs return [] tagged_system_check.tags = ['simpletag'] class CheckCommandTests(TestCase): def setUp(self): simple_system_check.kwargs = None tagged_system_check.kwargs = None self.old_stdout, self.old_stderr = sys.stdout, sys.stderr sys.stdout, sys.stderr = StringIO(), StringIO() def tearDown(self): sys.stdout, sys.stderr = self.old_stdout, self.old_stderr @override_system_checks([simple_system_check, tagged_system_check]) def test_simple_call(self): call_command('check') self.assertEqual(simple_system_check.kwargs, {'app_configs': None}) self.assertEqual(tagged_system_check.kwargs, {'app_configs': None}) @override_system_checks([simple_system_check, tagged_system_check]) def test_given_app(self): call_command('check', 'auth', 'admin') auth_config = apps.get_app_config('auth') admin_config = apps.get_app_config('admin') self.assertEqual(simple_system_check.kwargs, {'app_configs': [auth_config, admin_config]}) self.assertEqual(tagged_system_check.kwargs, {'app_configs': [auth_config, admin_config]}) @override_system_checks([simple_system_check, tagged_system_check]) def test_given_tag(self): call_command('check', tags=['simpletag']) self.assertEqual(simple_system_check.kwargs, None) self.assertEqual(tagged_system_check.kwargs, {'app_configs': None}) @override_system_checks([simple_system_check, tagged_system_check]) def test_invalid_tag(self): self.assertRaises(CommandError, call_command, 'check', tags=['missingtag']) @override_system_checks([simple_system_check]) def test_list_tags_empty(self): call_command('check', list_tags=True) self.assertEqual('\n', sys.stdout.getvalue()) @override_system_checks([tagged_system_check]) def test_list_tags(self): call_command('check', list_tags=True) self.assertEqual('simpletag\n', sys.stdout.getvalue()) def custom_error_system_check(app_configs, **kwargs): return [ Error( 'Error', hint=None, id='myerrorcheck.E001', ) ] def custom_warning_system_check(app_configs, **kwargs): return [ Warning( 'Warning', hint=None, id='mywarningcheck.E001', ) ] class SilencingCheckTests(TestCase): def setUp(self): self.old_stdout, self.old_stderr = sys.stdout, sys.stderr self.stdout, self.stderr = StringIO(), StringIO() sys.stdout, sys.stderr = self.stdout, self.stderr def tearDown(self): sys.stdout, sys.stderr = self.old_stdout, self.old_stderr @override_settings(SILENCED_SYSTEM_CHECKS=['myerrorcheck.E001']) @override_system_checks([custom_error_system_check]) def test_silenced_error(self): out = StringIO() err = StringIO() try: call_command('check', stdout=out, stderr=err) except CommandError: self.fail("The mycheck.E001 check should be silenced.") self.assertEqual(out.getvalue(), '') self.assertEqual( err.getvalue(), 'System check identified some issues:\n\n' 'ERRORS:\n' '?: (myerrorcheck.E001) Error\n\n' 'System check identified 1 issue (0 silenced).\n' ) @override_settings(SILENCED_SYSTEM_CHECKS=['mywarningcheck.E001']) @override_system_checks([custom_warning_system_check]) def test_silenced_warning(self): out = StringIO() err = StringIO() try: call_command('check', stdout=out, stderr=err) except CommandError: self.fail("The mycheck.E001 check should be silenced.") self.assertEqual(out.getvalue(), 'System check identified no issues (1 silenced).\n') self.assertEqual(err.getvalue(), '')