mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	This is a relic of when the tests were stored in contrib.auth.tests.
Backport of 590b8c1c57 from master
		
	
		
			
				
	
	
		
			736 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			736 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| from __future__ import unicode_literals
 | |
| 
 | |
| import locale
 | |
| import sys
 | |
| from datetime import date
 | |
| 
 | |
| from django.apps import apps
 | |
| from django.contrib.auth import management, models
 | |
| from django.contrib.auth.checks import check_user_model
 | |
| from django.contrib.auth.management import create_permissions
 | |
| from django.contrib.auth.management.commands import (
 | |
|     changepassword, createsuperuser,
 | |
| )
 | |
| from django.contrib.auth.models import Group, User
 | |
| from django.contrib.auth.tests.custom_user import CustomUser
 | |
| from django.contrib.contenttypes.models import ContentType
 | |
| from django.core import checks, exceptions
 | |
| from django.core.management import call_command
 | |
| from django.core.management.base import CommandError
 | |
| from django.test import (
 | |
|     SimpleTestCase, TestCase, override_settings, override_system_checks,
 | |
| )
 | |
| from django.utils import six
 | |
| from django.utils.encoding import force_str
 | |
| from django.utils.translation import ugettext_lazy as _
 | |
| 
 | |
| from .models import (
 | |
|     CustomUserBadRequiredFields, CustomUserNonListRequiredFields,
 | |
|     CustomUserNonUniqueUsername, CustomUserWithFK, Email,
 | |
| )
 | |
| 
 | |
| 
 | |
| def mock_inputs(inputs):
 | |
|     """
 | |
|     Decorator to temporarily replace input/getpass to allow interactive
 | |
|     createsuperuser.
 | |
|     """
 | |
|     def inner(test_func):
 | |
|         def wrapped(*args):
 | |
|             class mock_getpass:
 | |
|                 @staticmethod
 | |
|                 def getpass(prompt=b'Password: ', stream=None):
 | |
|                     if six.PY2:
 | |
|                         # getpass on Windows only supports prompt as bytestring (#19807)
 | |
|                         assert isinstance(prompt, six.binary_type)
 | |
|                     if callable(inputs['password']):
 | |
|                         return inputs['password']()
 | |
|                     return inputs['password']
 | |
| 
 | |
|             def mock_input(prompt):
 | |
|                 # prompt should be encoded in Python 2. This line will raise an
 | |
|                 # Exception if prompt contains unencoded non-ASCII on Python 2.
 | |
|                 prompt = str(prompt)
 | |
|                 assert str('__proxy__') not in prompt
 | |
|                 response = ''
 | |
|                 for key, val in inputs.items():
 | |
|                     if force_str(key) in prompt.lower():
 | |
|                         response = val
 | |
|                         break
 | |
|                 return response
 | |
| 
 | |
|             old_getpass = createsuperuser.getpass
 | |
|             old_input = createsuperuser.input
 | |
|             createsuperuser.getpass = mock_getpass
 | |
|             createsuperuser.input = mock_input
 | |
|             try:
 | |
|                 test_func(*args)
 | |
|             finally:
 | |
|                 createsuperuser.getpass = old_getpass
 | |
|                 createsuperuser.input = old_input
 | |
|         return wrapped
 | |
|     return inner
 | |
| 
 | |
| 
 | |
| class MockTTY(object):
 | |
|     """
 | |
|     A fake stdin object that pretends to be a TTY to be used in conjunction
 | |
|     with mock_inputs.
 | |
|     """
 | |
|     def isatty(self):
 | |
|         return True
 | |
| 
 | |
| 
 | |
| class GetDefaultUsernameTestCase(TestCase):
 | |
| 
 | |
|     def setUp(self):
 | |
|         self.old_get_system_username = management.get_system_username
 | |
| 
 | |
|     def tearDown(self):
 | |
|         management.get_system_username = self.old_get_system_username
 | |
| 
 | |
|     def test_actual_implementation(self):
 | |
|         self.assertIsInstance(management.get_system_username(), six.text_type)
 | |
| 
 | |
|     def test_simple(self):
 | |
|         management.get_system_username = lambda: 'joe'
 | |
|         self.assertEqual(management.get_default_username(), 'joe')
 | |
| 
 | |
|     def test_existing(self):
 | |
|         models.User.objects.create(username='joe')
 | |
|         management.get_system_username = lambda: 'joe'
 | |
|         self.assertEqual(management.get_default_username(), '')
 | |
|         self.assertEqual(
 | |
|             management.get_default_username(check_db=False), 'joe')
 | |
| 
 | |
|     def test_i18n(self):
 | |
|         # 'Julia' with accented 'u':
 | |
|         management.get_system_username = lambda: 'J\xfalia'
 | |
|         self.assertEqual(management.get_default_username(), 'julia')
 | |
| 
 | |
| 
 | |
| @override_settings(AUTH_PASSWORD_VALIDATORS=[
 | |
|     {'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator'},
 | |
| ])
 | |
| class ChangepasswordManagementCommandTestCase(TestCase):
 | |
| 
 | |
|     def setUp(self):
 | |
|         self.user = models.User.objects.create_user(username='joe', password='qwerty')
 | |
|         self.stdout = six.StringIO()
 | |
|         self.stderr = six.StringIO()
 | |
| 
 | |
|     def tearDown(self):
 | |
|         self.stdout.close()
 | |
|         self.stderr.close()
 | |
| 
 | |
|     def test_that_changepassword_command_changes_joes_password(self):
 | |
|         "Executing the changepassword management command should change joe's password"
 | |
|         self.assertTrue(self.user.check_password('qwerty'))
 | |
|         command = changepassword.Command()
 | |
|         command._get_pass = lambda *args: 'not qwerty'
 | |
| 
 | |
|         command.execute(username="joe", stdout=self.stdout)
 | |
|         command_output = self.stdout.getvalue().strip()
 | |
| 
 | |
|         self.assertEqual(
 | |
|             command_output,
 | |
|             "Changing password for user 'joe'\nPassword changed successfully for user 'joe'"
 | |
|         )
 | |
|         self.assertTrue(models.User.objects.get(username="joe").check_password("not qwerty"))
 | |
| 
 | |
|     def test_that_max_tries_exits_1(self):
 | |
|         """
 | |
|         A CommandError should be thrown by handle() if the user enters in
 | |
|         mismatched passwords three times.
 | |
|         """
 | |
|         command = changepassword.Command()
 | |
|         command._get_pass = lambda *args: str(args) or 'foo'
 | |
| 
 | |
|         with self.assertRaises(CommandError):
 | |
|             command.execute(username="joe", stdout=self.stdout, stderr=self.stderr)
 | |
| 
 | |
|     def test_password_validation(self):
 | |
|         """
 | |
|         A CommandError should be raised if the user enters in passwords which
 | |
|         fail validation three times.
 | |
|         """
 | |
|         command = changepassword.Command()
 | |
|         command._get_pass = lambda *args: '1234567890'
 | |
| 
 | |
|         abort_msg = "Aborting password change for user 'joe' after 3 attempts"
 | |
|         with self.assertRaisesMessage(CommandError, abort_msg):
 | |
|             command.execute(username="joe", stdout=self.stdout, stderr=self.stderr)
 | |
|         self.assertIn('This password is entirely numeric.', self.stderr.getvalue())
 | |
| 
 | |
|     def test_that_changepassword_command_works_with_nonascii_output(self):
 | |
|         """
 | |
|         #21627 -- Executing the changepassword management command should allow
 | |
|         non-ASCII characters from the User object representation.
 | |
|         """
 | |
|         # 'Julia' with accented 'u':
 | |
|         models.User.objects.create_user(username='J\xfalia', password='qwerty')
 | |
| 
 | |
|         command = changepassword.Command()
 | |
|         command._get_pass = lambda *args: 'not qwerty'
 | |
| 
 | |
|         command.execute(username="J\xfalia", stdout=self.stdout)
 | |
| 
 | |
| 
 | |
| @override_settings(
 | |
|     SILENCED_SYSTEM_CHECKS=['fields.W342'],  # ForeignKey(unique=True)
 | |
|     AUTH_PASSWORD_VALIDATORS=[{'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator'}],
 | |
| )
 | |
| class CreatesuperuserManagementCommandTestCase(TestCase):
 | |
| 
 | |
|     def test_basic_usage(self):
 | |
|         "Check the operation of the createsuperuser management command"
 | |
|         # We can use the management command to create a superuser
 | |
|         new_io = six.StringIO()
 | |
|         call_command(
 | |
|             "createsuperuser",
 | |
|             interactive=False,
 | |
|             username="joe",
 | |
|             email="joe@somewhere.org",
 | |
|             stdout=new_io
 | |
|         )
 | |
|         command_output = new_io.getvalue().strip()
 | |
|         self.assertEqual(command_output, 'Superuser created successfully.')
 | |
|         u = User.objects.get(username="joe")
 | |
|         self.assertEqual(u.email, 'joe@somewhere.org')
 | |
| 
 | |
|         # created password should be unusable
 | |
|         self.assertFalse(u.has_usable_password())
 | |
| 
 | |
|     @mock_inputs({'password': "nopasswd"})
 | |
|     def test_nolocale(self):
 | |
|         """
 | |
|         Check that createsuperuser does not break when no locale is set. See
 | |
|         ticket #16017.
 | |
|         """
 | |
| 
 | |
|         old_getdefaultlocale = locale.getdefaultlocale
 | |
|         try:
 | |
|             # Temporarily remove locale information
 | |
|             locale.getdefaultlocale = lambda: (None, None)
 | |
| 
 | |
|             # Call the command in this new environment
 | |
|             call_command(
 | |
|                 "createsuperuser",
 | |
|                 interactive=True,
 | |
|                 username="nolocale@somewhere.org",
 | |
|                 email="nolocale@somewhere.org",
 | |
|                 verbosity=0,
 | |
|                 stdin=MockTTY(),
 | |
|             )
 | |
| 
 | |
|         except TypeError:
 | |
|             self.fail("createsuperuser fails if the OS provides no information about the current locale")
 | |
| 
 | |
|         finally:
 | |
|             # Re-apply locale information
 | |
|             locale.getdefaultlocale = old_getdefaultlocale
 | |
| 
 | |
|         # If we were successful, a user should have been created
 | |
|         u = User.objects.get(username="nolocale@somewhere.org")
 | |
|         self.assertEqual(u.email, 'nolocale@somewhere.org')
 | |
| 
 | |
|     @mock_inputs({
 | |
|         'password': "nopasswd",
 | |
|         'u\u017eivatel': 'foo',  # username (cz)
 | |
|         'email': 'nolocale@somewhere.org'})
 | |
|     def test_non_ascii_verbose_name(self):
 | |
|         username_field = User._meta.get_field('username')
 | |
|         old_verbose_name = username_field.verbose_name
 | |
|         username_field.verbose_name = _('u\u017eivatel')
 | |
|         new_io = six.StringIO()
 | |
|         try:
 | |
|             call_command(
 | |
|                 "createsuperuser",
 | |
|                 interactive=True,
 | |
|                 stdout=new_io,
 | |
|                 stdin=MockTTY(),
 | |
|             )
 | |
|         finally:
 | |
|             username_field.verbose_name = old_verbose_name
 | |
| 
 | |
|         command_output = new_io.getvalue().strip()
 | |
|         self.assertEqual(command_output, 'Superuser created successfully.')
 | |
| 
 | |
|     def test_verbosity_zero(self):
 | |
|         # We can suppress output on the management command
 | |
|         new_io = six.StringIO()
 | |
|         call_command(
 | |
|             "createsuperuser",
 | |
|             interactive=False,
 | |
|             username="joe2",
 | |
|             email="joe2@somewhere.org",
 | |
|             verbosity=0,
 | |
|             stdout=new_io
 | |
|         )
 | |
|         command_output = new_io.getvalue().strip()
 | |
|         self.assertEqual(command_output, '')
 | |
|         u = User.objects.get(username="joe2")
 | |
|         self.assertEqual(u.email, 'joe2@somewhere.org')
 | |
|         self.assertFalse(u.has_usable_password())
 | |
| 
 | |
|     def test_email_in_username(self):
 | |
|         new_io = six.StringIO()
 | |
|         call_command(
 | |
|             "createsuperuser",
 | |
|             interactive=False,
 | |
|             username="joe+admin@somewhere.org",
 | |
|             email="joe@somewhere.org",
 | |
|             stdout=new_io
 | |
|         )
 | |
|         u = User._default_manager.get(username="joe+admin@somewhere.org")
 | |
|         self.assertEqual(u.email, 'joe@somewhere.org')
 | |
|         self.assertFalse(u.has_usable_password())
 | |
| 
 | |
|     @override_settings(AUTH_USER_MODEL='auth.CustomUser')
 | |
|     def test_swappable_user(self):
 | |
|         "A superuser can be created when a custom User model is in use"
 | |
|         # We can use the management command to create a superuser
 | |
|         # We skip validation because the temporary substitution of the
 | |
|         # swappable User model messes with validation.
 | |
|         new_io = six.StringIO()
 | |
|         call_command(
 | |
|             "createsuperuser",
 | |
|             interactive=False,
 | |
|             email="joe@somewhere.org",
 | |
|             date_of_birth="1976-04-01",
 | |
|             stdout=new_io,
 | |
|         )
 | |
|         command_output = new_io.getvalue().strip()
 | |
|         self.assertEqual(command_output, 'Superuser created successfully.')
 | |
|         u = CustomUser._default_manager.get(email="joe@somewhere.org")
 | |
|         self.assertEqual(u.date_of_birth, date(1976, 4, 1))
 | |
| 
 | |
|         # created password should be unusable
 | |
|         self.assertFalse(u.has_usable_password())
 | |
| 
 | |
|     @override_settings(AUTH_USER_MODEL='auth.CustomUser')
 | |
|     def test_swappable_user_missing_required_field(self):
 | |
|         "A Custom superuser won't be created when a required field isn't provided"
 | |
|         # We can use the management command to create a superuser
 | |
|         # We skip validation because the temporary substitution of the
 | |
|         # swappable User model messes with validation.
 | |
|         new_io = six.StringIO()
 | |
|         with self.assertRaises(CommandError):
 | |
|             call_command(
 | |
|                 "createsuperuser",
 | |
|                 interactive=False,
 | |
|                 username="joe@somewhere.org",
 | |
|                 stdout=new_io,
 | |
|                 stderr=new_io,
 | |
|             )
 | |
| 
 | |
|         self.assertEqual(CustomUser._default_manager.count(), 0)
 | |
| 
 | |
|     @override_settings(
 | |
|         AUTH_USER_MODEL='auth_tests.CustomUserNonUniqueUsername',
 | |
|         AUTHENTICATION_BACKENDS=['my.custom.backend'],
 | |
|     )
 | |
|     def test_swappable_user_username_non_unique(self):
 | |
|         @mock_inputs({
 | |
|             'username': 'joe',
 | |
|             'password': 'nopasswd',
 | |
|         })
 | |
|         def createsuperuser():
 | |
|             new_io = six.StringIO()
 | |
|             call_command(
 | |
|                 "createsuperuser",
 | |
|                 interactive=True,
 | |
|                 email="joe@somewhere.org",
 | |
|                 stdout=new_io,
 | |
|                 stdin=MockTTY(),
 | |
|             )
 | |
|             command_output = new_io.getvalue().strip()
 | |
|             self.assertEqual(command_output, 'Superuser created successfully.')
 | |
| 
 | |
|         for i in range(2):
 | |
|             createsuperuser()
 | |
| 
 | |
|         users = CustomUserNonUniqueUsername.objects.filter(username="joe")
 | |
|         self.assertEqual(users.count(), 2)
 | |
| 
 | |
|     def test_skip_if_not_in_TTY(self):
 | |
|         """
 | |
|         If the command is not called from a TTY, it should be skipped and a
 | |
|         message should be displayed (#7423).
 | |
|         """
 | |
|         class FakeStdin(object):
 | |
|             """A fake stdin object that has isatty() return False."""
 | |
|             def isatty(self):
 | |
|                 return False
 | |
| 
 | |
|         out = six.StringIO()
 | |
|         call_command(
 | |
|             "createsuperuser",
 | |
|             stdin=FakeStdin(),
 | |
|             stdout=out,
 | |
|             interactive=True,
 | |
|         )
 | |
| 
 | |
|         self.assertEqual(User._default_manager.count(), 0)
 | |
|         self.assertIn("Superuser creation skipped", out.getvalue())
 | |
| 
 | |
|     def test_passing_stdin(self):
 | |
|         """
 | |
|         You can pass a stdin object as an option and it should be
 | |
|         available on self.stdin.
 | |
|         If no such option is passed, it defaults to sys.stdin.
 | |
|         """
 | |
|         sentinel = object()
 | |
|         command = createsuperuser.Command()
 | |
|         command.check = lambda: []
 | |
|         command.execute(
 | |
|             stdin=sentinel,
 | |
|             stdout=six.StringIO(),
 | |
|             stderr=six.StringIO(),
 | |
|             interactive=False,
 | |
|             verbosity=0,
 | |
|             username='janet',
 | |
|             email='janet@example.com',
 | |
|         )
 | |
|         self.assertIs(command.stdin, sentinel)
 | |
| 
 | |
|         command = createsuperuser.Command()
 | |
|         command.check = lambda: []
 | |
|         command.execute(
 | |
|             stdout=six.StringIO(),
 | |
|             stderr=six.StringIO(),
 | |
|             interactive=False,
 | |
|             verbosity=0,
 | |
|             username='joe',
 | |
|             email='joe@example.com',
 | |
|         )
 | |
|         self.assertIs(command.stdin, sys.stdin)
 | |
| 
 | |
|     @override_settings(AUTH_USER_MODEL='auth_tests.CustomUserWithFK')
 | |
|     def test_fields_with_fk(self):
 | |
|         new_io = six.StringIO()
 | |
|         group = Group.objects.create(name='mygroup')
 | |
|         email = Email.objects.create(email='mymail@gmail.com')
 | |
|         call_command(
 | |
|             'createsuperuser',
 | |
|             interactive=False,
 | |
|             username=email.pk,
 | |
|             email=email.email,
 | |
|             group=group.pk,
 | |
|             stdout=new_io,
 | |
|         )
 | |
|         command_output = new_io.getvalue().strip()
 | |
|         self.assertEqual(command_output, 'Superuser created successfully.')
 | |
|         u = CustomUserWithFK._default_manager.get(email=email)
 | |
|         self.assertEqual(u.username, email)
 | |
|         self.assertEqual(u.group, group)
 | |
| 
 | |
|         non_existent_email = 'mymail2@gmail.com'
 | |
|         with self.assertRaisesMessage(CommandError,
 | |
|                 'email instance with email %r does not exist.' % non_existent_email):
 | |
|             call_command(
 | |
|                 'createsuperuser',
 | |
|                 interactive=False,
 | |
|                 username=email.pk,
 | |
|                 email=non_existent_email,
 | |
|                 stdout=new_io,
 | |
|             )
 | |
| 
 | |
|     @override_settings(AUTH_USER_MODEL='auth_tests.CustomUserWithFK')
 | |
|     def test_fields_with_fk_interactive(self):
 | |
|         new_io = six.StringIO()
 | |
|         group = Group.objects.create(name='mygroup')
 | |
|         email = Email.objects.create(email='mymail@gmail.com')
 | |
| 
 | |
|         @mock_inputs({
 | |
|             'password': 'nopasswd',
 | |
|             'username (email.id)': email.pk,
 | |
|             'email (email.email)': email.email,
 | |
|             'group (group.id)': group.pk,
 | |
|         })
 | |
|         def test(self):
 | |
|             call_command(
 | |
|                 'createsuperuser',
 | |
|                 interactive=True,
 | |
|                 stdout=new_io,
 | |
|                 stdin=MockTTY(),
 | |
|             )
 | |
| 
 | |
|             command_output = new_io.getvalue().strip()
 | |
|             self.assertEqual(command_output, 'Superuser created successfully.')
 | |
|             u = CustomUserWithFK._default_manager.get(email=email)
 | |
|             self.assertEqual(u.username, email)
 | |
|             self.assertEqual(u.group, group)
 | |
| 
 | |
|         test(self)
 | |
| 
 | |
|     def test_password_validation(self):
 | |
|         """
 | |
|         Creation should fail if the password fails validation.
 | |
|         """
 | |
|         new_io = six.StringIO()
 | |
| 
 | |
|         # Returns '1234567890' the first two times it is called, then
 | |
|         # 'password' subsequently.
 | |
|         def bad_then_good_password(index=[0]):
 | |
|             index[0] += 1
 | |
|             if index[0] <= 2:
 | |
|                 return '1234567890'
 | |
|             return 'password'
 | |
| 
 | |
|         @mock_inputs({
 | |
|             'password': bad_then_good_password,
 | |
|             'username': 'joe1234567890',
 | |
|         })
 | |
|         def test(self):
 | |
|             call_command(
 | |
|                 "createsuperuser",
 | |
|                 interactive=True,
 | |
|                 stdin=MockTTY(),
 | |
|                 stdout=new_io,
 | |
|                 stderr=new_io,
 | |
|             )
 | |
|             self.assertEqual(
 | |
|                 new_io.getvalue().strip(),
 | |
|                 "This password is entirely numeric.\n"
 | |
|                 "Superuser created successfully."
 | |
|             )
 | |
| 
 | |
|         test(self)
 | |
| 
 | |
|     def test_validation_mismatched_passwords(self):
 | |
|         """
 | |
|         Creation should fail if the user enters mismatched passwords.
 | |
|         """
 | |
|         new_io = six.StringIO()
 | |
| 
 | |
|         # The first two passwords do not match, but the second two do match and
 | |
|         # are valid.
 | |
|         entered_passwords = ["password", "not password", "password2", "password2"]
 | |
| 
 | |
|         def mismatched_passwords_then_matched():
 | |
|             return entered_passwords.pop(0)
 | |
| 
 | |
|         @mock_inputs({
 | |
|             'password': mismatched_passwords_then_matched,
 | |
|             'username': 'joe1234567890',
 | |
|         })
 | |
|         def test(self):
 | |
|             call_command(
 | |
|                 "createsuperuser",
 | |
|                 interactive=True,
 | |
|                 stdin=MockTTY(),
 | |
|                 stdout=new_io,
 | |
|                 stderr=new_io,
 | |
|             )
 | |
|             self.assertEqual(
 | |
|                 new_io.getvalue().strip(),
 | |
|                 "Error: Your passwords didn't match.\n"
 | |
|                 "Superuser created successfully."
 | |
|             )
 | |
| 
 | |
|         test(self)
 | |
| 
 | |
|     def test_validation_blank_password_entered(self):
 | |
|         """
 | |
|         Creation should fail if the user enters blank passwords.
 | |
|         """
 | |
|         new_io = six.StringIO()
 | |
| 
 | |
|         # The first two passwords are empty strings, but the second two are
 | |
|         # valid.
 | |
|         entered_passwords = ["", "", "password2", "password2"]
 | |
| 
 | |
|         def blank_passwords_then_valid():
 | |
|             return entered_passwords.pop(0)
 | |
| 
 | |
|         @mock_inputs({
 | |
|             'password': blank_passwords_then_valid,
 | |
|             'username': 'joe1234567890',
 | |
|         })
 | |
|         def test(self):
 | |
|             call_command(
 | |
|                 "createsuperuser",
 | |
|                 interactive=True,
 | |
|                 stdin=MockTTY(),
 | |
|                 stdout=new_io,
 | |
|                 stderr=new_io,
 | |
|             )
 | |
|             self.assertEqual(
 | |
|                 new_io.getvalue().strip(),
 | |
|                 "Error: Blank passwords aren't allowed.\n"
 | |
|                 "Superuser created successfully."
 | |
|             )
 | |
| 
 | |
|         test(self)
 | |
| 
 | |
| 
 | |
| class CustomUserModelValidationTestCase(SimpleTestCase):
 | |
|     @override_settings(AUTH_USER_MODEL='auth_tests.CustomUserNonListRequiredFields')
 | |
|     @override_system_checks([check_user_model])
 | |
|     def test_required_fields_is_list(self):
 | |
|         "REQUIRED_FIELDS should be a list."
 | |
|         errors = checks.run_checks()
 | |
|         expected = [
 | |
|             checks.Error(
 | |
|                 "'REQUIRED_FIELDS' must be a list or tuple.",
 | |
|                 hint=None,
 | |
|                 obj=CustomUserNonListRequiredFields,
 | |
|                 id='auth.E001',
 | |
|             ),
 | |
|         ]
 | |
|         self.assertEqual(errors, expected)
 | |
| 
 | |
|     @override_settings(AUTH_USER_MODEL='auth_tests.CustomUserBadRequiredFields')
 | |
|     @override_system_checks([check_user_model])
 | |
|     def test_username_not_in_required_fields(self):
 | |
|         "USERNAME_FIELD should not appear in REQUIRED_FIELDS."
 | |
|         errors = checks.run_checks()
 | |
|         expected = [
 | |
|             checks.Error(
 | |
|                 ("The field named as the 'USERNAME_FIELD' for a custom user model "
 | |
|                  "must not be included in 'REQUIRED_FIELDS'."),
 | |
|                 hint=None,
 | |
|                 obj=CustomUserBadRequiredFields,
 | |
|                 id='auth.E002',
 | |
|             ),
 | |
|         ]
 | |
|         self.assertEqual(errors, expected)
 | |
| 
 | |
|     @override_settings(AUTH_USER_MODEL='auth_tests.CustomUserNonUniqueUsername')
 | |
|     @override_system_checks([check_user_model])
 | |
|     def test_username_non_unique(self):
 | |
|         "A non-unique USERNAME_FIELD should raise a model validation error."
 | |
|         errors = checks.run_checks()
 | |
|         expected = [
 | |
|             checks.Error(
 | |
|                 ("'CustomUserNonUniqueUsername.username' must be "
 | |
|                  "unique because it is named as the 'USERNAME_FIELD'."),
 | |
|                 hint=None,
 | |
|                 obj=CustomUserNonUniqueUsername,
 | |
|                 id='auth.E003',
 | |
|             ),
 | |
|         ]
 | |
|         self.assertEqual(errors, expected)
 | |
| 
 | |
|     @override_settings(AUTH_USER_MODEL='auth_tests.CustomUserNonUniqueUsername',
 | |
|                        AUTHENTICATION_BACKENDS=[
 | |
|                            'my.custom.backend',
 | |
|                        ])
 | |
|     @override_system_checks([check_user_model])
 | |
|     def test_username_non_unique_with_custom_backend(self):
 | |
|         """ A non-unique USERNAME_FIELD should raise an error only if we use the
 | |
|         default authentication backend. Otherwise, an warning should be raised.
 | |
|         """
 | |
|         errors = checks.run_checks()
 | |
|         expected = [
 | |
|             checks.Warning(
 | |
|                 ("'CustomUserNonUniqueUsername.username' is named as "
 | |
|                  "the 'USERNAME_FIELD', but it is not unique."),
 | |
|                 hint=('Ensure that your authentication backend(s) can handle '
 | |
|                       'non-unique usernames.'),
 | |
|                 obj=CustomUserNonUniqueUsername,
 | |
|                 id='auth.W004',
 | |
|             )
 | |
|         ]
 | |
|         self.assertEqual(errors, expected)
 | |
| 
 | |
| 
 | |
| class PermissionTestCase(TestCase):
 | |
| 
 | |
|     def setUp(self):
 | |
|         self._original_permissions = models.Permission._meta.permissions[:]
 | |
|         self._original_default_permissions = models.Permission._meta.default_permissions
 | |
|         self._original_verbose_name = models.Permission._meta.verbose_name
 | |
| 
 | |
|     def tearDown(self):
 | |
|         models.Permission._meta.permissions = self._original_permissions
 | |
|         models.Permission._meta.default_permissions = self._original_default_permissions
 | |
|         models.Permission._meta.verbose_name = self._original_verbose_name
 | |
|         ContentType.objects.clear_cache()
 | |
| 
 | |
|     def test_duplicated_permissions(self):
 | |
|         """
 | |
|         Test that we show proper error message if we are trying to create
 | |
|         duplicate permissions.
 | |
|         """
 | |
|         auth_app_config = apps.get_app_config('auth')
 | |
| 
 | |
|         # check duplicated default permission
 | |
|         models.Permission._meta.permissions = [
 | |
|             ('change_permission', 'Can edit permission (duplicate)')]
 | |
|         six.assertRaisesRegex(self, CommandError,
 | |
|             "The permission codename 'change_permission' clashes with a "
 | |
|             "builtin permission for model 'auth.Permission'.",
 | |
|             create_permissions, auth_app_config, verbosity=0)
 | |
| 
 | |
|         # check duplicated custom permissions
 | |
|         models.Permission._meta.permissions = [
 | |
|             ('my_custom_permission', 'Some permission'),
 | |
|             ('other_one', 'Some other permission'),
 | |
|             ('my_custom_permission', 'Some permission with duplicate permission code'),
 | |
|         ]
 | |
|         six.assertRaisesRegex(self, CommandError,
 | |
|             "The permission codename 'my_custom_permission' is duplicated for model "
 | |
|             "'auth.Permission'.",
 | |
|             create_permissions, auth_app_config, verbosity=0)
 | |
| 
 | |
|         # should not raise anything
 | |
|         models.Permission._meta.permissions = [
 | |
|             ('my_custom_permission', 'Some permission'),
 | |
|             ('other_one', 'Some other permission'),
 | |
|         ]
 | |
|         create_permissions(auth_app_config, verbosity=0)
 | |
| 
 | |
|     def test_default_permissions(self):
 | |
|         auth_app_config = apps.get_app_config('auth')
 | |
| 
 | |
|         permission_content_type = ContentType.objects.get_by_natural_key('auth', 'permission')
 | |
|         models.Permission._meta.permissions = [
 | |
|             ('my_custom_permission', 'Some permission'),
 | |
|         ]
 | |
|         create_permissions(auth_app_config, verbosity=0)
 | |
| 
 | |
|         # add/change/delete permission by default + custom permission
 | |
|         self.assertEqual(models.Permission.objects.filter(
 | |
|             content_type=permission_content_type,
 | |
|         ).count(), 4)
 | |
| 
 | |
|         models.Permission.objects.filter(content_type=permission_content_type).delete()
 | |
|         models.Permission._meta.default_permissions = []
 | |
|         create_permissions(auth_app_config, verbosity=0)
 | |
| 
 | |
|         # custom permission only since default permissions is empty
 | |
|         self.assertEqual(models.Permission.objects.filter(
 | |
|             content_type=permission_content_type,
 | |
|         ).count(), 1)
 | |
| 
 | |
|     def test_verbose_name_length(self):
 | |
|         auth_app_config = apps.get_app_config('auth')
 | |
| 
 | |
|         permission_content_type = ContentType.objects.get_by_natural_key('auth', 'permission')
 | |
|         models.Permission.objects.filter(content_type=permission_content_type).delete()
 | |
|         models.Permission._meta.verbose_name = "some ridiculously long verbose name that is out of control" * 5
 | |
| 
 | |
|         six.assertRaisesRegex(self, exceptions.ValidationError,
 | |
|             "The verbose_name of auth.permission is longer than 244 characters",
 | |
|             create_permissions, auth_app_config, verbosity=0)
 | |
| 
 | |
|     def test_custom_permission_name_length(self):
 | |
|         auth_app_config = apps.get_app_config('auth')
 | |
| 
 | |
|         ContentType.objects.get_by_natural_key('auth', 'permission')
 | |
|         custom_perm_name = 'a' * 256
 | |
|         models.Permission._meta.permissions = [
 | |
|             ('my_custom_permission', custom_perm_name),
 | |
|         ]
 | |
|         try:
 | |
|             msg = (
 | |
|                 "The permission name %s of auth.permission is longer than "
 | |
|                 "255 characters" % custom_perm_name
 | |
|             )
 | |
|             with self.assertRaisesMessage(exceptions.ValidationError, msg):
 | |
|                 create_permissions(auth_app_config, verbosity=0)
 | |
|         finally:
 | |
|             models.Permission._meta.permissions = []
 |