From 6eb3ce11e4d6be237ad2e4895d8ae0b7bc1803dc Mon Sep 17 00:00:00 2001 From: Simon Charette Date: Thu, 4 Feb 2016 11:47:51 -0500 Subject: Fixed #26089 -- Removed custom user test models from public API. Thanks to Tim Graham for the review. --- django/contrib/auth/tests/custom_user.py | 113 -------------------------- docs/releases/1.10.txt | 7 ++ tests/auth_tests/models/__init__.py | 6 +- tests/auth_tests/models/custom_permissions.py | 5 +- tests/auth_tests/models/custom_user.py | 107 ++++++++++++++++++++++++ tests/auth_tests/models/uuid_pk.py | 3 +- tests/auth_tests/test_auth_backends.py | 7 +- tests/auth_tests/test_basic.py | 5 +- tests/auth_tests/test_decorators.py | 10 +-- tests/auth_tests/test_handlers.py | 6 +- tests/auth_tests/test_management.py | 9 +- tests/auth_tests/test_mixins.py | 16 ++-- tests/auth_tests/test_views.py | 5 +- 13 files changed, 154 insertions(+), 145 deletions(-) delete mode 100644 django/contrib/auth/tests/custom_user.py create mode 100644 tests/auth_tests/models/custom_user.py diff --git a/django/contrib/auth/tests/custom_user.py b/django/contrib/auth/tests/custom_user.py deleted file mode 100644 index f06d7d814b..0000000000 --- a/django/contrib/auth/tests/custom_user.py +++ /dev/null @@ -1,113 +0,0 @@ -from django.contrib.auth.models import ( - AbstractBaseUser, AbstractUser, BaseUserManager, Group, Permission, - PermissionsMixin, UserManager, -) -from django.db import models - - -# The custom User uses email as the unique identifier, and requires -# that every user provide a date of birth. This lets us test -# changes in username datatype, and non-text required fields. -class CustomUserManager(BaseUserManager): - def create_user(self, email, date_of_birth, password=None): - """ - Creates and saves a User with the given email and password. - """ - if not email: - raise ValueError('Users must have an email address') - - user = self.model( - email=self.normalize_email(email), - date_of_birth=date_of_birth, - ) - - user.set_password(password) - user.save(using=self._db) - return user - - def create_superuser(self, email, password, date_of_birth): - u = self.create_user(email, password=password, date_of_birth=date_of_birth) - u.is_admin = True - u.save(using=self._db) - return u - - -class CustomUser(AbstractBaseUser): - email = models.EmailField(verbose_name='email address', max_length=255, unique=True) - is_active = models.BooleanField(default=True) - is_admin = models.BooleanField(default=False) - date_of_birth = models.DateField() - - custom_objects = CustomUserManager() - - USERNAME_FIELD = 'email' - REQUIRED_FIELDS = ['date_of_birth'] - - class Meta: - app_label = 'auth' - - def get_full_name(self): - return self.email - - def get_short_name(self): - return self.email - - def __unicode__(self): - return self.email - - # Maybe required? - def get_group_permissions(self, obj=None): - return set() - - def get_all_permissions(self, obj=None): - return set() - - def has_perm(self, perm, obj=None): - return True - - def has_perms(self, perm_list, obj=None): - return True - - def has_module_perms(self, app_label): - return True - - # Admin required fields - @property - def is_staff(self): - return self.is_admin - - -class RemoveGroupsAndPermissions(object): - """ - A context manager to temporarily remove the groups and user_permissions M2M - fields from the AbstractUser class, so they don't clash with the - related_name sets. - """ - def __enter__(self): - self._old_au_local_m2m = AbstractUser._meta.local_many_to_many - self._old_pm_local_m2m = PermissionsMixin._meta.local_many_to_many - groups = models.ManyToManyField(Group, blank=True) - groups.contribute_to_class(PermissionsMixin, "groups") - user_permissions = models.ManyToManyField(Permission, blank=True) - user_permissions.contribute_to_class(PermissionsMixin, "user_permissions") - PermissionsMixin._meta.local_many_to_many = [groups, user_permissions] - AbstractUser._meta.local_many_to_many = [groups, user_permissions] - - def __exit__(self, exc_type, exc_value, traceback): - AbstractUser._meta.local_many_to_many = self._old_au_local_m2m - PermissionsMixin._meta.local_many_to_many = self._old_pm_local_m2m - - -# The extension user is a simple extension of the built-in user class, -# adding a required date_of_birth field. This allows us to check for -# any hard references to the name "User" in forms/handlers etc. -with RemoveGroupsAndPermissions(): - class ExtensionUser(AbstractUser): - date_of_birth = models.DateField() - - custom_objects = UserManager() - - REQUIRED_FIELDS = AbstractUser.REQUIRED_FIELDS + ['date_of_birth'] - - class Meta: - app_label = 'auth' diff --git a/docs/releases/1.10.txt b/docs/releases/1.10.txt index 7329a6717d..602bf311f3 100644 --- a/docs/releases/1.10.txt +++ b/docs/releases/1.10.txt @@ -448,6 +448,13 @@ output:: } } +``auth.CustomUser`` and ``auth.ExtensionUser`` test models were removed. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Since the introduction of migrations for the contrib apps in Django 1.8, the +tables of these custom user test models were not created anymore making them +unusable in a testing context. + Miscellaneous ~~~~~~~~~~~~~ diff --git a/tests/auth_tests/models/__init__.py b/tests/auth_tests/models/__init__.py index 3f3bd89793..d7275e177f 100644 --- a/tests/auth_tests/models/__init__.py +++ b/tests/auth_tests/models/__init__.py @@ -1,10 +1,12 @@ from .custom_permissions import CustomPermissionsUser +from .custom_user import CustomUser, ExtensionUser from .invalid_models import CustomUserNonUniqueUsername from .is_active import IsActiveTestUser1 from .uuid_pk import UUIDUser from .with_foreign_key import CustomUserWithFK, Email __all__ = ( - 'CustomPermissionsUser', 'CustomUserWithFK', 'Email', - 'IsActiveTestUser1', 'UUIDUser', 'CustomUserNonUniqueUsername', + 'CustomUser', 'CustomPermissionsUser', 'CustomUserWithFK', 'Email', + 'ExtensionUser', 'IsActiveTestUser1', 'UUIDUser', + 'CustomUserNonUniqueUsername', ) diff --git a/tests/auth_tests/models/custom_permissions.py b/tests/auth_tests/models/custom_permissions.py index 7687d95df6..a6c5a1e96a 100644 --- a/tests/auth_tests/models/custom_permissions.py +++ b/tests/auth_tests/models/custom_permissions.py @@ -4,12 +4,11 @@ Django permissions model. This allows us to check that the PermissionsMixin includes everything that is needed to interact with the ModelBackend. """ from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin -from django.contrib.auth.tests.custom_user import ( - CustomUserManager, RemoveGroupsAndPermissions, -) from django.db import models from django.utils.encoding import python_2_unicode_compatible +from .custom_user import CustomUserManager, RemoveGroupsAndPermissions + class CustomPermissionsUserManager(CustomUserManager): def create_superuser(self, email, password, date_of_birth): diff --git a/tests/auth_tests/models/custom_user.py b/tests/auth_tests/models/custom_user.py new file mode 100644 index 0000000000..0519b09b75 --- /dev/null +++ b/tests/auth_tests/models/custom_user.py @@ -0,0 +1,107 @@ +from django.contrib.auth.models import ( + AbstractBaseUser, AbstractUser, BaseUserManager, Group, Permission, + PermissionsMixin, UserManager, +) +from django.db import models + + +# The custom User uses email as the unique identifier, and requires +# that every user provide a date of birth. This lets us test +# changes in username datatype, and non-text required fields. +class CustomUserManager(BaseUserManager): + def create_user(self, email, date_of_birth, password=None): + """ + Creates and saves a User with the given email and password. + """ + if not email: + raise ValueError('Users must have an email address') + + user = self.model( + email=self.normalize_email(email), + date_of_birth=date_of_birth, + ) + + user.set_password(password) + user.save(using=self._db) + return user + + def create_superuser(self, email, password, date_of_birth): + u = self.create_user(email, password=password, date_of_birth=date_of_birth) + u.is_admin = True + u.save(using=self._db) + return u + + +class CustomUser(AbstractBaseUser): + email = models.EmailField(verbose_name='email address', max_length=255, unique=True) + is_active = models.BooleanField(default=True) + is_admin = models.BooleanField(default=False) + date_of_birth = models.DateField() + + custom_objects = CustomUserManager() + + USERNAME_FIELD = 'email' + REQUIRED_FIELDS = ['date_of_birth'] + + def get_full_name(self): + return self.email + + def get_short_name(self): + return self.email + + def __unicode__(self): + return self.email + + # Maybe required? + def get_group_permissions(self, obj=None): + return set() + + def get_all_permissions(self, obj=None): + return set() + + def has_perm(self, perm, obj=None): + return True + + def has_perms(self, perm_list, obj=None): + return True + + def has_module_perms(self, app_label): + return True + + # Admin required fields + @property + def is_staff(self): + return self.is_admin + + +class RemoveGroupsAndPermissions(object): + """ + A context manager to temporarily remove the groups and user_permissions M2M + fields from the AbstractUser class, so they don't clash with the + related_name sets. + """ + def __enter__(self): + self._old_au_local_m2m = AbstractUser._meta.local_many_to_many + self._old_pm_local_m2m = PermissionsMixin._meta.local_many_to_many + groups = models.ManyToManyField(Group, blank=True) + groups.contribute_to_class(PermissionsMixin, "groups") + user_permissions = models.ManyToManyField(Permission, blank=True) + user_permissions.contribute_to_class(PermissionsMixin, "user_permissions") + PermissionsMixin._meta.local_many_to_many = [groups, user_permissions] + AbstractUser._meta.local_many_to_many = [groups, user_permissions] + + def __exit__(self, exc_type, exc_value, traceback): + AbstractUser._meta.local_many_to_many = self._old_au_local_m2m + PermissionsMixin._meta.local_many_to_many = self._old_pm_local_m2m + + +# The extension user is a simple extension of the built-in user class, +# adding a required date_of_birth field. This allows us to check for +# any hard references to the name "User" in forms/handlers etc. +with RemoveGroupsAndPermissions(): + class ExtensionUser(AbstractUser): + date_of_birth = models.DateField() + + custom_objects = UserManager() + + REQUIRED_FIELDS = AbstractUser.REQUIRED_FIELDS + ['date_of_birth'] diff --git a/tests/auth_tests/models/uuid_pk.py b/tests/auth_tests/models/uuid_pk.py index 7c65226493..87a4ee0658 100644 --- a/tests/auth_tests/models/uuid_pk.py +++ b/tests/auth_tests/models/uuid_pk.py @@ -1,9 +1,10 @@ import uuid from django.contrib.auth.models import AbstractUser -from django.contrib.auth.tests.custom_user import RemoveGroupsAndPermissions from django.db import models +from .custom_user import RemoveGroupsAndPermissions + with RemoveGroupsAndPermissions(): class UUIDUser(AbstractUser): """A user with a UUID as primary key""" diff --git a/tests/auth_tests/test_auth_backends.py b/tests/auth_tests/test_auth_backends.py index 54a863bcda..2f28c6cdf1 100644 --- a/tests/auth_tests/test_auth_backends.py +++ b/tests/auth_tests/test_auth_backends.py @@ -8,7 +8,6 @@ from django.contrib.auth import ( from django.contrib.auth.backends import ModelBackend from django.contrib.auth.hashers import MD5PasswordHasher from django.contrib.auth.models import AnonymousUser, Group, Permission, User -from django.contrib.auth.tests.custom_user import CustomUser, ExtensionUser from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ImproperlyConfigured, PermissionDenied from django.http import HttpRequest @@ -16,7 +15,7 @@ from django.test import ( SimpleTestCase, TestCase, modify_settings, override_settings, ) -from .models import CustomPermissionsUser, UUIDUser +from .models import CustomPermissionsUser, CustomUser, ExtensionUser, UUIDUser class CountingMD5PasswordHasher(MD5PasswordHasher): @@ -215,7 +214,7 @@ class ModelBackendTest(BaseModelBackendTest, TestCase): ) -@override_settings(AUTH_USER_MODEL='auth.ExtensionUser') +@override_settings(AUTH_USER_MODEL='auth_tests.ExtensionUser') class ExtensionUserModelBackendTest(BaseModelBackendTest, TestCase): """ Tests for the ModelBackend using the custom ExtensionUser model. @@ -275,7 +274,7 @@ class CustomPermissionsUserModelBackendTest(BaseModelBackendTest, TestCase): ) -@override_settings(AUTH_USER_MODEL='auth.CustomUser') +@override_settings(AUTH_USER_MODEL='auth_tests.CustomUser') class CustomUserModelBackendAuthenticateTest(TestCase): """ Tests that the model backend can accept a credentials kwarg labeled with diff --git a/tests/auth_tests/test_basic.py b/tests/auth_tests/test_basic.py index 6fe88f769f..81b7ac9c56 100644 --- a/tests/auth_tests/test_basic.py +++ b/tests/auth_tests/test_basic.py @@ -3,13 +3,14 @@ from __future__ import unicode_literals from django.apps import apps from django.contrib.auth import get_user_model from django.contrib.auth.models import AnonymousUser, User -from django.contrib.auth.tests.custom_user import CustomUser from django.core.exceptions import ImproperlyConfigured from django.dispatch import receiver from django.test import TestCase, override_settings from django.test.signals import setting_changed from django.utils import translation +from .models import CustomUser + @receiver(setting_changed) def user_model_swapped(**kwargs): @@ -87,7 +88,7 @@ class BasicTestCase(TestCase): "The current user model can be retrieved" self.assertEqual(get_user_model(), User) - @override_settings(AUTH_USER_MODEL='auth.CustomUser') + @override_settings(AUTH_USER_MODEL='auth_tests.CustomUser') def test_swappable_user(self): "The current user model can be swapped out for another" self.assertEqual(get_user_model(), CustomUser) diff --git a/tests/auth_tests/test_decorators.py b/tests/auth_tests/test_decorators.py index d1ad87f528..bff1c11427 100644 --- a/tests/auth_tests/test_decorators.py +++ b/tests/auth_tests/test_decorators.py @@ -68,7 +68,7 @@ class PermissionsRequiredDecoratorTest(TestCase): def test_many_permissions_pass(self): - @permission_required(['auth.add_customuser', 'auth.change_customuser']) + @permission_required(['auth_tests.add_customuser', 'auth_tests.change_customuser']) def a_view(request): return HttpResponse() request = self.factory.get('/rand') @@ -78,7 +78,7 @@ class PermissionsRequiredDecoratorTest(TestCase): def test_many_permissions_in_set_pass(self): - @permission_required({'auth.add_customuser', 'auth.change_customuser'}) + @permission_required({'auth_tests.add_customuser', 'auth_tests.change_customuser'}) def a_view(request): return HttpResponse() request = self.factory.get('/rand') @@ -88,7 +88,7 @@ class PermissionsRequiredDecoratorTest(TestCase): def test_single_permission_pass(self): - @permission_required('auth.add_customuser') + @permission_required('auth_tests.add_customuser') def a_view(request): return HttpResponse() request = self.factory.get('/rand') @@ -98,7 +98,7 @@ class PermissionsRequiredDecoratorTest(TestCase): def test_permissioned_denied_redirect(self): - @permission_required(['auth.add_customuser', 'auth.change_customuser', 'non-existent-permission']) + @permission_required(['auth_tests.add_customuser', 'auth_tests.change_customuser', 'non-existent-permission']) def a_view(request): return HttpResponse() request = self.factory.get('/rand') @@ -109,7 +109,7 @@ class PermissionsRequiredDecoratorTest(TestCase): def test_permissioned_denied_exception_raised(self): @permission_required([ - 'auth.add_customuser', 'auth.change_customuser', 'non-existent-permission' + 'auth_tests.add_customuser', 'auth_tests.change_customuser', 'non-existent-permission' ], raise_exception=True) def a_view(request): return HttpResponse() diff --git a/tests/auth_tests/test_handlers.py b/tests/auth_tests/test_handlers.py index e2ceab9c4e..c0751a0825 100644 --- a/tests/auth_tests/test_handlers.py +++ b/tests/auth_tests/test_handlers.py @@ -4,9 +4,10 @@ from django.contrib.auth.handlers.modwsgi import ( check_password, groups_for_user, ) from django.contrib.auth.models import Group, User -from django.contrib.auth.tests.custom_user import CustomUser from django.test import TransactionTestCase, override_settings +from .models import CustomUser + # This must be a TransactionTestCase because the WSGI auth handler performs # its own transaction management. @@ -18,6 +19,7 @@ class ModWsgiHandlerTestCase(TransactionTestCase): available_apps = [ 'django.contrib.auth', 'django.contrib.contenttypes', + 'auth_tests', ] def test_check_password(self): @@ -40,7 +42,7 @@ class ModWsgiHandlerTestCase(TransactionTestCase): # Valid user with incorrect password self.assertFalse(check_password({}, 'test', 'incorrect')) - @override_settings(AUTH_USER_MODEL='auth.CustomUser') + @override_settings(AUTH_USER_MODEL='auth_tests.CustomUser') def test_check_password_custom_user(self): """ Verify that check_password returns the correct values as per diff --git a/tests/auth_tests/test_management.py b/tests/auth_tests/test_management.py index ab8e8a60e0..4183c96c8e 100644 --- a/tests/auth_tests/test_management.py +++ b/tests/auth_tests/test_management.py @@ -14,7 +14,6 @@ from django.contrib.auth.management.commands import ( from django.contrib.auth.models import ( AbstractBaseUser, Group, Permission, 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 @@ -28,7 +27,9 @@ from django.utils import six from django.utils.encoding import force_str from django.utils.translation import ugettext_lazy as _ -from .models import CustomUserNonUniqueUsername, CustomUserWithFK, Email +from .models import ( + CustomUser, CustomUserNonUniqueUsername, CustomUserWithFK, Email, +) def mock_inputs(inputs): @@ -287,7 +288,7 @@ class CreatesuperuserManagementCommandTestCase(TestCase): self.assertEqual(u.email, 'joe@somewhere.org') self.assertFalse(u.has_usable_password()) - @override_settings(AUTH_USER_MODEL='auth.CustomUser') + @override_settings(AUTH_USER_MODEL='auth_tests.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 @@ -309,7 +310,7 @@ class CreatesuperuserManagementCommandTestCase(TestCase): # created password should be unusable self.assertFalse(u.has_usable_password()) - @override_settings(AUTH_USER_MODEL='auth.CustomUser') + @override_settings(AUTH_USER_MODEL='auth_tests.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 diff --git a/tests/auth_tests/test_mixins.py b/tests/auth_tests/test_mixins.py index 6ada1f59bb..22e5709bc3 100644 --- a/tests/auth_tests/test_mixins.py +++ b/tests/auth_tests/test_mixins.py @@ -35,12 +35,12 @@ class AlwaysFalseView(AlwaysFalseMixin, EmptyResponseView): class StackedMixinsView1(LoginRequiredMixin, PermissionRequiredMixin, EmptyResponseView): - permission_required = ['auth.add_customuser', 'auth.change_customuser'] + permission_required = ['auth_tests.add_customuser', 'auth_tests.change_customuser'] raise_exception = True class StackedMixinsView2(PermissionRequiredMixin, LoginRequiredMixin, EmptyResponseView): - permission_required = ['auth.add_customuser', 'auth.change_customuser'] + permission_required = ['auth_tests.add_customuser', 'auth_tests.change_customuser'] raise_exception = True @@ -217,7 +217,7 @@ class PermissionsRequiredMixinTests(TestCase): def test_many_permissions_pass(self): class AView(PermissionRequiredMixin, EmptyResponseView): - permission_required = ['auth.add_customuser', 'auth.change_customuser'] + permission_required = ['auth_tests.add_customuser', 'auth_tests.change_customuser'] request = self.factory.get('/rand') request.user = self.user @@ -226,7 +226,7 @@ class PermissionsRequiredMixinTests(TestCase): def test_single_permission_pass(self): class AView(PermissionRequiredMixin, EmptyResponseView): - permission_required = 'auth.add_customuser' + permission_required = 'auth_tests.add_customuser' request = self.factory.get('/rand') request.user = self.user @@ -235,7 +235,9 @@ class PermissionsRequiredMixinTests(TestCase): def test_permissioned_denied_redirect(self): class AView(PermissionRequiredMixin, EmptyResponseView): - permission_required = ['auth.add_customuser', 'auth.change_customuser', 'non-existent-permission'] + permission_required = [ + 'auth_tests.add_customuser', 'auth_tests.change_customuser', 'non-existent-permission', + ] request = self.factory.get('/rand') request.user = self.user @@ -244,7 +246,9 @@ class PermissionsRequiredMixinTests(TestCase): def test_permissioned_denied_exception_raised(self): class AView(PermissionRequiredMixin, EmptyResponseView): - permission_required = ['auth.add_customuser', 'auth.change_customuser', 'non-existent-permission'] + permission_required = [ + 'auth_tests.add_customuser', 'auth_tests.change_customuser', 'non-existent-permission', + ] raise_exception = True request = self.factory.get('/rand') diff --git a/tests/auth_tests/test_views.py b/tests/auth_tests/test_views.py index 76a1abf6ed..336e9a1482 100644 --- a/tests/auth_tests/test_views.py +++ b/tests/auth_tests/test_views.py @@ -15,7 +15,6 @@ from django.contrib.auth.forms import ( AuthenticationForm, PasswordChangeForm, SetPasswordForm, ) from django.contrib.auth.models import User -from django.contrib.auth.tests.custom_user import CustomUser from django.contrib.auth.views import login as login_view, redirect_to_login from django.contrib.sessions.middleware import SessionMiddleware from django.contrib.sites.requests import RequestSite @@ -31,7 +30,7 @@ from django.utils.http import urlquote from django.utils.six.moves.urllib.parse import ParseResult, urlparse from django.utils.translation import LANGUAGE_SESSION_KEY -from .models import UUIDUser +from .models import CustomUser, UUIDUser from .settings import AUTH_TEMPLATES @@ -367,7 +366,7 @@ class PasswordResetTest(AuthViewsTestCase): self.assertContains(response, "Hello, .") -@override_settings(AUTH_USER_MODEL='auth.CustomUser') +@override_settings(AUTH_USER_MODEL='auth_tests.CustomUser') class CustomUserPasswordResetTest(AuthViewsTestCase): user_email = 'staffmember@example.com' -- cgit v1.3