test_management.py 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744
  1. from __future__ import unicode_literals
  2. import locale
  3. import sys
  4. from datetime import date
  5. from django.apps import apps
  6. from django.contrib.auth import management
  7. from django.contrib.auth.checks import check_user_model
  8. from django.contrib.auth.management import create_permissions
  9. from django.contrib.auth.management.commands import (
  10. changepassword, createsuperuser,
  11. )
  12. from django.contrib.auth.models import (
  13. AbstractBaseUser, Group, Permission, User,
  14. )
  15. from django.contrib.contenttypes.models import ContentType
  16. from django.core import checks, exceptions
  17. from django.core.management import call_command
  18. from django.core.management.base import CommandError
  19. from django.db import models
  20. from django.test import (
  21. SimpleTestCase, TestCase, override_settings, override_system_checks,
  22. )
  23. from django.test.utils import isolate_apps
  24. from django.utils import six
  25. from django.utils.encoding import force_str
  26. from django.utils.translation import ugettext_lazy as _
  27. from .models import (
  28. CustomUser, CustomUserNonUniqueUsername, CustomUserWithFK, Email,
  29. )
  30. def mock_inputs(inputs):
  31. """
  32. Decorator to temporarily replace input/getpass to allow interactive
  33. createsuperuser.
  34. """
  35. def inner(test_func):
  36. def wrapped(*args):
  37. class mock_getpass:
  38. @staticmethod
  39. def getpass(prompt=b'Password: ', stream=None):
  40. if six.PY2:
  41. # getpass on Windows only supports prompt as bytestring (#19807)
  42. assert isinstance(prompt, six.binary_type)
  43. if callable(inputs['password']):
  44. return inputs['password']()
  45. return inputs['password']
  46. def mock_input(prompt):
  47. # prompt should be encoded in Python 2. This line will raise an
  48. # Exception if prompt contains unencoded non-ASCII on Python 2.
  49. prompt = str(prompt)
  50. assert str('__proxy__') not in prompt
  51. response = ''
  52. for key, val in inputs.items():
  53. if force_str(key) in prompt.lower():
  54. response = val
  55. break
  56. return response
  57. old_getpass = createsuperuser.getpass
  58. old_input = createsuperuser.input
  59. createsuperuser.getpass = mock_getpass
  60. createsuperuser.input = mock_input
  61. try:
  62. test_func(*args)
  63. finally:
  64. createsuperuser.getpass = old_getpass
  65. createsuperuser.input = old_input
  66. return wrapped
  67. return inner
  68. class MockTTY(object):
  69. """
  70. A fake stdin object that pretends to be a TTY to be used in conjunction
  71. with mock_inputs.
  72. """
  73. def isatty(self):
  74. return True
  75. class GetDefaultUsernameTestCase(TestCase):
  76. def setUp(self):
  77. self.old_get_system_username = management.get_system_username
  78. def tearDown(self):
  79. management.get_system_username = self.old_get_system_username
  80. def test_actual_implementation(self):
  81. self.assertIsInstance(management.get_system_username(), six.text_type)
  82. def test_simple(self):
  83. management.get_system_username = lambda: 'joe'
  84. self.assertEqual(management.get_default_username(), 'joe')
  85. def test_existing(self):
  86. User.objects.create(username='joe')
  87. management.get_system_username = lambda: 'joe'
  88. self.assertEqual(management.get_default_username(), '')
  89. self.assertEqual(
  90. management.get_default_username(check_db=False), 'joe')
  91. def test_i18n(self):
  92. # 'Julia' with accented 'u':
  93. management.get_system_username = lambda: 'J\xfalia'
  94. self.assertEqual(management.get_default_username(), 'julia')
  95. @override_settings(AUTH_PASSWORD_VALIDATORS=[
  96. {'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator'},
  97. ])
  98. class ChangepasswordManagementCommandTestCase(TestCase):
  99. def setUp(self):
  100. self.user = User.objects.create_user(username='joe', password='qwerty')
  101. self.stdout = six.StringIO()
  102. self.stderr = six.StringIO()
  103. def tearDown(self):
  104. self.stdout.close()
  105. self.stderr.close()
  106. def test_that_changepassword_command_changes_joes_password(self):
  107. "Executing the changepassword management command should change joe's password"
  108. self.assertTrue(self.user.check_password('qwerty'))
  109. command = changepassword.Command()
  110. command._get_pass = lambda *args: 'not qwerty'
  111. command.execute(username="joe", stdout=self.stdout)
  112. command_output = self.stdout.getvalue().strip()
  113. self.assertEqual(
  114. command_output,
  115. "Changing password for user 'joe'\nPassword changed successfully for user 'joe'"
  116. )
  117. self.assertTrue(User.objects.get(username="joe").check_password("not qwerty"))
  118. def test_that_max_tries_exits_1(self):
  119. """
  120. A CommandError should be thrown by handle() if the user enters in
  121. mismatched passwords three times.
  122. """
  123. command = changepassword.Command()
  124. command._get_pass = lambda *args: str(args) or 'foo'
  125. with self.assertRaises(CommandError):
  126. command.execute(username="joe", stdout=self.stdout, stderr=self.stderr)
  127. def test_password_validation(self):
  128. """
  129. A CommandError should be raised if the user enters in passwords which
  130. fail validation three times.
  131. """
  132. command = changepassword.Command()
  133. command._get_pass = lambda *args: '1234567890'
  134. abort_msg = "Aborting password change for user 'joe' after 3 attempts"
  135. with self.assertRaisesMessage(CommandError, abort_msg):
  136. command.execute(username="joe", stdout=self.stdout, stderr=self.stderr)
  137. self.assertIn('This password is entirely numeric.', self.stderr.getvalue())
  138. def test_that_changepassword_command_works_with_nonascii_output(self):
  139. """
  140. #21627 -- Executing the changepassword management command should allow
  141. non-ASCII characters from the User object representation.
  142. """
  143. # 'Julia' with accented 'u':
  144. User.objects.create_user(username='J\xfalia', password='qwerty')
  145. command = changepassword.Command()
  146. command._get_pass = lambda *args: 'not qwerty'
  147. command.execute(username="J\xfalia", stdout=self.stdout)
  148. @override_settings(
  149. SILENCED_SYSTEM_CHECKS=['fields.W342'], # ForeignKey(unique=True)
  150. AUTH_PASSWORD_VALIDATORS=[{'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator'}],
  151. )
  152. class CreatesuperuserManagementCommandTestCase(TestCase):
  153. def test_basic_usage(self):
  154. "Check the operation of the createsuperuser management command"
  155. # We can use the management command to create a superuser
  156. new_io = six.StringIO()
  157. call_command(
  158. "createsuperuser",
  159. interactive=False,
  160. username="joe",
  161. email="joe@somewhere.org",
  162. stdout=new_io
  163. )
  164. command_output = new_io.getvalue().strip()
  165. self.assertEqual(command_output, 'Superuser created successfully.')
  166. u = User.objects.get(username="joe")
  167. self.assertEqual(u.email, 'joe@somewhere.org')
  168. # created password should be unusable
  169. self.assertFalse(u.has_usable_password())
  170. @mock_inputs({'password': "nopasswd"})
  171. def test_nolocale(self):
  172. """
  173. Check that createsuperuser does not break when no locale is set. See
  174. ticket #16017.
  175. """
  176. old_getdefaultlocale = locale.getdefaultlocale
  177. try:
  178. # Temporarily remove locale information
  179. locale.getdefaultlocale = lambda: (None, None)
  180. # Call the command in this new environment
  181. call_command(
  182. "createsuperuser",
  183. interactive=True,
  184. username="nolocale@somewhere.org",
  185. email="nolocale@somewhere.org",
  186. verbosity=0,
  187. stdin=MockTTY(),
  188. )
  189. except TypeError:
  190. self.fail("createsuperuser fails if the OS provides no information about the current locale")
  191. finally:
  192. # Re-apply locale information
  193. locale.getdefaultlocale = old_getdefaultlocale
  194. # If we were successful, a user should have been created
  195. u = User.objects.get(username="nolocale@somewhere.org")
  196. self.assertEqual(u.email, 'nolocale@somewhere.org')
  197. @mock_inputs({
  198. 'password': "nopasswd",
  199. 'u\u017eivatel': 'foo', # username (cz)
  200. 'email': 'nolocale@somewhere.org'})
  201. def test_non_ascii_verbose_name(self):
  202. username_field = User._meta.get_field('username')
  203. old_verbose_name = username_field.verbose_name
  204. username_field.verbose_name = _('u\u017eivatel')
  205. new_io = six.StringIO()
  206. try:
  207. call_command(
  208. "createsuperuser",
  209. interactive=True,
  210. stdout=new_io,
  211. stdin=MockTTY(),
  212. )
  213. finally:
  214. username_field.verbose_name = old_verbose_name
  215. command_output = new_io.getvalue().strip()
  216. self.assertEqual(command_output, 'Superuser created successfully.')
  217. def test_verbosity_zero(self):
  218. # We can suppress output on the management command
  219. new_io = six.StringIO()
  220. call_command(
  221. "createsuperuser",
  222. interactive=False,
  223. username="joe2",
  224. email="joe2@somewhere.org",
  225. verbosity=0,
  226. stdout=new_io
  227. )
  228. command_output = new_io.getvalue().strip()
  229. self.assertEqual(command_output, '')
  230. u = User.objects.get(username="joe2")
  231. self.assertEqual(u.email, 'joe2@somewhere.org')
  232. self.assertFalse(u.has_usable_password())
  233. def test_email_in_username(self):
  234. new_io = six.StringIO()
  235. call_command(
  236. "createsuperuser",
  237. interactive=False,
  238. username="joe+admin@somewhere.org",
  239. email="joe@somewhere.org",
  240. stdout=new_io
  241. )
  242. u = User._default_manager.get(username="joe+admin@somewhere.org")
  243. self.assertEqual(u.email, 'joe@somewhere.org')
  244. self.assertFalse(u.has_usable_password())
  245. @override_settings(AUTH_USER_MODEL='auth_tests.CustomUser')
  246. def test_swappable_user(self):
  247. "A superuser can be created when a custom User model is in use"
  248. # We can use the management command to create a superuser
  249. # We skip validation because the temporary substitution of the
  250. # swappable User model messes with validation.
  251. new_io = six.StringIO()
  252. call_command(
  253. "createsuperuser",
  254. interactive=False,
  255. email="joe@somewhere.org",
  256. date_of_birth="1976-04-01",
  257. stdout=new_io,
  258. )
  259. command_output = new_io.getvalue().strip()
  260. self.assertEqual(command_output, 'Superuser created successfully.')
  261. u = CustomUser._default_manager.get(email="joe@somewhere.org")
  262. self.assertEqual(u.date_of_birth, date(1976, 4, 1))
  263. # created password should be unusable
  264. self.assertFalse(u.has_usable_password())
  265. @override_settings(AUTH_USER_MODEL='auth_tests.CustomUser')
  266. def test_swappable_user_missing_required_field(self):
  267. "A Custom superuser won't be created when a required field isn't provided"
  268. # We can use the management command to create a superuser
  269. # We skip validation because the temporary substitution of the
  270. # swappable User model messes with validation.
  271. new_io = six.StringIO()
  272. with self.assertRaises(CommandError):
  273. call_command(
  274. "createsuperuser",
  275. interactive=False,
  276. username="joe@somewhere.org",
  277. stdout=new_io,
  278. stderr=new_io,
  279. )
  280. self.assertEqual(CustomUser._default_manager.count(), 0)
  281. @override_settings(
  282. AUTH_USER_MODEL='auth_tests.CustomUserNonUniqueUsername',
  283. AUTHENTICATION_BACKENDS=['my.custom.backend'],
  284. )
  285. def test_swappable_user_username_non_unique(self):
  286. @mock_inputs({
  287. 'username': 'joe',
  288. 'password': 'nopasswd',
  289. })
  290. def createsuperuser():
  291. new_io = six.StringIO()
  292. call_command(
  293. "createsuperuser",
  294. interactive=True,
  295. email="joe@somewhere.org",
  296. stdout=new_io,
  297. stdin=MockTTY(),
  298. )
  299. command_output = new_io.getvalue().strip()
  300. self.assertEqual(command_output, 'Superuser created successfully.')
  301. for i in range(2):
  302. createsuperuser()
  303. users = CustomUserNonUniqueUsername.objects.filter(username="joe")
  304. self.assertEqual(users.count(), 2)
  305. def test_skip_if_not_in_TTY(self):
  306. """
  307. If the command is not called from a TTY, it should be skipped and a
  308. message should be displayed (#7423).
  309. """
  310. class FakeStdin(object):
  311. """A fake stdin object that has isatty() return False."""
  312. def isatty(self):
  313. return False
  314. out = six.StringIO()
  315. call_command(
  316. "createsuperuser",
  317. stdin=FakeStdin(),
  318. stdout=out,
  319. interactive=True,
  320. )
  321. self.assertEqual(User._default_manager.count(), 0)
  322. self.assertIn("Superuser creation skipped", out.getvalue())
  323. def test_passing_stdin(self):
  324. """
  325. You can pass a stdin object as an option and it should be
  326. available on self.stdin.
  327. If no such option is passed, it defaults to sys.stdin.
  328. """
  329. sentinel = object()
  330. command = createsuperuser.Command()
  331. command.check = lambda: []
  332. command.execute(
  333. stdin=sentinel,
  334. stdout=six.StringIO(),
  335. stderr=six.StringIO(),
  336. interactive=False,
  337. verbosity=0,
  338. username='janet',
  339. email='janet@example.com',
  340. )
  341. self.assertIs(command.stdin, sentinel)
  342. command = createsuperuser.Command()
  343. command.check = lambda: []
  344. command.execute(
  345. stdout=six.StringIO(),
  346. stderr=six.StringIO(),
  347. interactive=False,
  348. verbosity=0,
  349. username='joe',
  350. email='joe@example.com',
  351. )
  352. self.assertIs(command.stdin, sys.stdin)
  353. @override_settings(AUTH_USER_MODEL='auth_tests.CustomUserWithFK')
  354. def test_fields_with_fk(self):
  355. new_io = six.StringIO()
  356. group = Group.objects.create(name='mygroup')
  357. email = Email.objects.create(email='mymail@gmail.com')
  358. call_command(
  359. 'createsuperuser',
  360. interactive=False,
  361. username=email.pk,
  362. email=email.email,
  363. group=group.pk,
  364. stdout=new_io,
  365. )
  366. command_output = new_io.getvalue().strip()
  367. self.assertEqual(command_output, 'Superuser created successfully.')
  368. u = CustomUserWithFK._default_manager.get(email=email)
  369. self.assertEqual(u.username, email)
  370. self.assertEqual(u.group, group)
  371. non_existent_email = 'mymail2@gmail.com'
  372. msg = 'email instance with email %r does not exist.' % non_existent_email
  373. with self.assertRaisesMessage(CommandError, msg):
  374. call_command(
  375. 'createsuperuser',
  376. interactive=False,
  377. username=email.pk,
  378. email=non_existent_email,
  379. stdout=new_io,
  380. )
  381. @override_settings(AUTH_USER_MODEL='auth_tests.CustomUserWithFK')
  382. def test_fields_with_fk_interactive(self):
  383. new_io = six.StringIO()
  384. group = Group.objects.create(name='mygroup')
  385. email = Email.objects.create(email='mymail@gmail.com')
  386. @mock_inputs({
  387. 'password': 'nopasswd',
  388. 'username (email.id)': email.pk,
  389. 'email (email.email)': email.email,
  390. 'group (group.id)': group.pk,
  391. })
  392. def test(self):
  393. call_command(
  394. 'createsuperuser',
  395. interactive=True,
  396. stdout=new_io,
  397. stdin=MockTTY(),
  398. )
  399. command_output = new_io.getvalue().strip()
  400. self.assertEqual(command_output, 'Superuser created successfully.')
  401. u = CustomUserWithFK._default_manager.get(email=email)
  402. self.assertEqual(u.username, email)
  403. self.assertEqual(u.group, group)
  404. test(self)
  405. def test_password_validation(self):
  406. """
  407. Creation should fail if the password fails validation.
  408. """
  409. new_io = six.StringIO()
  410. # Returns '1234567890' the first two times it is called, then
  411. # 'password' subsequently.
  412. def bad_then_good_password(index=[0]):
  413. index[0] += 1
  414. if index[0] <= 2:
  415. return '1234567890'
  416. return 'password'
  417. @mock_inputs({
  418. 'password': bad_then_good_password,
  419. 'username': 'joe1234567890',
  420. })
  421. def test(self):
  422. call_command(
  423. "createsuperuser",
  424. interactive=True,
  425. stdin=MockTTY(),
  426. stdout=new_io,
  427. stderr=new_io,
  428. )
  429. self.assertEqual(
  430. new_io.getvalue().strip(),
  431. "This password is entirely numeric.\n"
  432. "Superuser created successfully."
  433. )
  434. test(self)
  435. def test_validation_mismatched_passwords(self):
  436. """
  437. Creation should fail if the user enters mismatched passwords.
  438. """
  439. new_io = six.StringIO()
  440. # The first two passwords do not match, but the second two do match and
  441. # are valid.
  442. entered_passwords = ["password", "not password", "password2", "password2"]
  443. def mismatched_passwords_then_matched():
  444. return entered_passwords.pop(0)
  445. @mock_inputs({
  446. 'password': mismatched_passwords_then_matched,
  447. 'username': 'joe1234567890',
  448. })
  449. def test(self):
  450. call_command(
  451. "createsuperuser",
  452. interactive=True,
  453. stdin=MockTTY(),
  454. stdout=new_io,
  455. stderr=new_io,
  456. )
  457. self.assertEqual(
  458. new_io.getvalue().strip(),
  459. "Error: Your passwords didn't match.\n"
  460. "Superuser created successfully."
  461. )
  462. test(self)
  463. def test_validation_blank_password_entered(self):
  464. """
  465. Creation should fail if the user enters blank passwords.
  466. """
  467. new_io = six.StringIO()
  468. # The first two passwords are empty strings, but the second two are
  469. # valid.
  470. entered_passwords = ["", "", "password2", "password2"]
  471. def blank_passwords_then_valid():
  472. return entered_passwords.pop(0)
  473. @mock_inputs({
  474. 'password': blank_passwords_then_valid,
  475. 'username': 'joe1234567890',
  476. })
  477. def test(self):
  478. call_command(
  479. "createsuperuser",
  480. interactive=True,
  481. stdin=MockTTY(),
  482. stdout=new_io,
  483. stderr=new_io,
  484. )
  485. self.assertEqual(
  486. new_io.getvalue().strip(),
  487. "Error: Blank passwords aren't allowed.\n"
  488. "Superuser created successfully."
  489. )
  490. test(self)
  491. class CustomUserModelValidationTestCase(SimpleTestCase):
  492. @override_settings(AUTH_USER_MODEL='auth_tests.CustomUserNonListRequiredFields')
  493. @override_system_checks([check_user_model])
  494. @isolate_apps('auth_tests', kwarg_name='apps')
  495. def test_required_fields_is_list(self, apps):
  496. """REQUIRED_FIELDS should be a list."""
  497. class CustomUserNonListRequiredFields(AbstractBaseUser):
  498. username = models.CharField(max_length=30, unique=True)
  499. date_of_birth = models.DateField()
  500. USERNAME_FIELD = 'username'
  501. REQUIRED_FIELDS = 'date_of_birth'
  502. errors = checks.run_checks(app_configs=apps.get_app_configs())
  503. expected = [
  504. checks.Error(
  505. "'REQUIRED_FIELDS' must be a list or tuple.",
  506. obj=CustomUserNonListRequiredFields,
  507. id='auth.E001',
  508. ),
  509. ]
  510. self.assertEqual(errors, expected)
  511. @override_settings(AUTH_USER_MODEL='auth_tests.CustomUserBadRequiredFields')
  512. @override_system_checks([check_user_model])
  513. @isolate_apps('auth_tests', kwarg_name='apps')
  514. def test_username_not_in_required_fields(self, apps):
  515. """USERNAME_FIELD should not appear in REQUIRED_FIELDS."""
  516. class CustomUserBadRequiredFields(AbstractBaseUser):
  517. username = models.CharField(max_length=30, unique=True)
  518. date_of_birth = models.DateField()
  519. USERNAME_FIELD = 'username'
  520. REQUIRED_FIELDS = ['username', 'date_of_birth']
  521. errors = checks.run_checks(apps.get_app_configs())
  522. expected = [
  523. checks.Error(
  524. "The field named as the 'USERNAME_FIELD' for a custom user model "
  525. "must not be included in 'REQUIRED_FIELDS'.",
  526. obj=CustomUserBadRequiredFields,
  527. id='auth.E002',
  528. ),
  529. ]
  530. self.assertEqual(errors, expected)
  531. @override_settings(AUTH_USER_MODEL='auth_tests.CustomUserNonUniqueUsername')
  532. @override_system_checks([check_user_model])
  533. def test_username_non_unique(self):
  534. """
  535. A non-unique USERNAME_FIELD should raise an error only if we use the
  536. default authentication backend. Otherwise, an warning should be raised.
  537. """
  538. errors = checks.run_checks()
  539. expected = [
  540. checks.Error(
  541. "'CustomUserNonUniqueUsername.username' must be "
  542. "unique because it is named as the 'USERNAME_FIELD'.",
  543. obj=CustomUserNonUniqueUsername,
  544. id='auth.E003',
  545. ),
  546. ]
  547. self.assertEqual(errors, expected)
  548. with self.settings(AUTHENTICATION_BACKENDS=['my.custom.backend']):
  549. errors = checks.run_checks()
  550. expected = [
  551. checks.Warning(
  552. "'CustomUserNonUniqueUsername.username' is named as "
  553. "the 'USERNAME_FIELD', but it is not unique.",
  554. hint='Ensure that your authentication backend(s) can handle non-unique usernames.',
  555. obj=CustomUserNonUniqueUsername,
  556. id='auth.W004',
  557. )
  558. ]
  559. self.assertEqual(errors, expected)
  560. class PermissionTestCase(TestCase):
  561. def setUp(self):
  562. self._original_permissions = Permission._meta.permissions[:]
  563. self._original_default_permissions = Permission._meta.default_permissions
  564. self._original_verbose_name = Permission._meta.verbose_name
  565. def tearDown(self):
  566. Permission._meta.permissions = self._original_permissions
  567. Permission._meta.default_permissions = self._original_default_permissions
  568. Permission._meta.verbose_name = self._original_verbose_name
  569. ContentType.objects.clear_cache()
  570. def test_duplicated_permissions(self):
  571. """
  572. Test that we show proper error message if we are trying to create
  573. duplicate permissions.
  574. """
  575. auth_app_config = apps.get_app_config('auth')
  576. # check duplicated default permission
  577. Permission._meta.permissions = [
  578. ('change_permission', 'Can edit permission (duplicate)')]
  579. msg = (
  580. "The permission codename 'change_permission' clashes with a "
  581. "builtin permission for model 'auth.Permission'."
  582. )
  583. with self.assertRaisesMessage(CommandError, msg):
  584. create_permissions(auth_app_config, verbosity=0)
  585. # check duplicated custom permissions
  586. Permission._meta.permissions = [
  587. ('my_custom_permission', 'Some permission'),
  588. ('other_one', 'Some other permission'),
  589. ('my_custom_permission', 'Some permission with duplicate permission code'),
  590. ]
  591. msg = "The permission codename 'my_custom_permission' is duplicated for model 'auth.Permission'."
  592. with self.assertRaisesMessage(CommandError, msg):
  593. create_permissions(auth_app_config, verbosity=0)
  594. # should not raise anything
  595. Permission._meta.permissions = [
  596. ('my_custom_permission', 'Some permission'),
  597. ('other_one', 'Some other permission'),
  598. ]
  599. create_permissions(auth_app_config, verbosity=0)
  600. def test_default_permissions(self):
  601. auth_app_config = apps.get_app_config('auth')
  602. permission_content_type = ContentType.objects.get_by_natural_key('auth', 'permission')
  603. Permission._meta.permissions = [
  604. ('my_custom_permission', 'Some permission'),
  605. ]
  606. create_permissions(auth_app_config, verbosity=0)
  607. # add/change/delete permission by default + custom permission
  608. self.assertEqual(Permission.objects.filter(
  609. content_type=permission_content_type,
  610. ).count(), 4)
  611. Permission.objects.filter(content_type=permission_content_type).delete()
  612. Permission._meta.default_permissions = []
  613. create_permissions(auth_app_config, verbosity=0)
  614. # custom permission only since default permissions is empty
  615. self.assertEqual(Permission.objects.filter(
  616. content_type=permission_content_type,
  617. ).count(), 1)
  618. def test_verbose_name_length(self):
  619. auth_app_config = apps.get_app_config('auth')
  620. permission_content_type = ContentType.objects.get_by_natural_key('auth', 'permission')
  621. Permission.objects.filter(content_type=permission_content_type).delete()
  622. Permission._meta.verbose_name = "some ridiculously long verbose name that is out of control" * 5
  623. msg = "The verbose_name of auth.permission is longer than 244 characters"
  624. with self.assertRaisesMessage(exceptions.ValidationError, msg):
  625. create_permissions(auth_app_config, verbosity=0)
  626. def test_custom_permission_name_length(self):
  627. auth_app_config = apps.get_app_config('auth')
  628. ContentType.objects.get_by_natural_key('auth', 'permission')
  629. custom_perm_name = 'a' * 256
  630. Permission._meta.permissions = [
  631. ('my_custom_permission', custom_perm_name),
  632. ]
  633. try:
  634. msg = (
  635. "The permission name %s of auth.permission is longer than "
  636. "255 characters" % custom_perm_name
  637. )
  638. with self.assertRaisesMessage(exceptions.ValidationError, msg):
  639. create_permissions(auth_app_config, verbosity=0)
  640. finally:
  641. Permission._meta.permissions = []