Source

django-registration / registration / tests.py

Full commit
"""
Unit tests for django-registration.

These tests assume that you've completed all the prerequisites for
getting django-registration running in the default setup, to wit:

1. You have ``registration`` in your ``INSTALLED_APPS`` setting.

2. You have created all of the templates mentioned in this
   application's documentation.

3. You have added the setting ``ACCOUNT_ACTIVATION_DAYS`` to your
   settings file.

4. You have URL patterns pointing to the registration and activation
   views, with the names ``registration_register`` and
   ``registration_activate``, respectively, and a URL pattern named
   'registration_complete'.

"""

import datetime
import sha

from django.conf import settings

try:
    user_model = get_model(*settings.CUSTOM_USER_MODEL.split('.', 2))
except AttributeError:
    from django.contrib.auth.models import User as user_model

from django.core import mail
from django.core import management
from django.core.urlresolvers import reverse
from django.test import TestCase
from django.db.models import get_model

from registration import forms
from registration.models import RegistrationProfile
from registration import signals


class RegistrationTestCase(TestCase):
    """
    Base class for the test cases; this sets up two users -- one
    expired, one not -- which are used to exercise various parts of
    the application.
    
    """
    def setUp(self):
        self.sample_user = RegistrationProfile.objects.create_inactive_user(username='alice',
                                                                            password='secret',
                                                                            email='alice@example.com')
        self.expired_user = RegistrationProfile.objects.create_inactive_user(username='bob',
                                                                             password='swordfish',
                                                                             email='bob@example.com')
        self.expired_user.date_joined -= datetime.timedelta(days=settings.ACCOUNT_ACTIVATION_DAYS + 1)
        self.expired_user.save()


class RegistrationModelTests(RegistrationTestCase):
    """
    Tests for the model-oriented functionality of django-registration,
    including ``RegistrationProfile`` and its custom manager.
    
    """
    def test_new_user_is_inactive(self):
        """
        Test that a newly-created user is inactive.
        
        """
        self.failIf(self.sample_user.is_active)

    def test_registration_profile_created(self):
        """
        Test that a ``RegistrationProfile`` is created for a new user.
        
        """
        self.assertEqual(RegistrationProfile.objects.count(), 2)

    def test_activation_email(self):
        """
        Test that user signup sends an activation email.
        
        """
        self.assertEqual(len(mail.outbox), 2)

    def test_activation_email_disable(self):
        """
        Test that activation email can be disabled.
        
        """
        RegistrationProfile.objects.create_inactive_user(username='noemail',
                                                         password='foo',
                                                         email='nobody@example.com',
                                                         send_email=False)
        self.assertEqual(len(mail.outbox), 2)

    def test_activation(self):
        """
        Test that user activation actually activates the user and
        properly resets the activation key, and fails for an
        already-active or expired user, or an invalid key.
        
        """
        # Activating a valid user returns the user.
        self.failUnlessEqual(RegistrationProfile.objects.activate_user(RegistrationProfile.objects.get(user=self.sample_user).activation_key).pk,
                             self.sample_user.pk)
        
        # The activated user must now be active.
        self.failUnless(user_model.objects.get(pk=self.sample_user.pk).is_active)
        
        # The activation key must now be reset to the "already activated" constant.
        self.failUnlessEqual(RegistrationProfile.objects.get(user=self.sample_user).activation_key,
                             RegistrationProfile.ACTIVATED)
        
        # Activating an expired user returns False.
        self.failIf(RegistrationProfile.objects.activate_user(RegistrationProfile.objects.get(user=self.expired_user).activation_key))
        
        # Activating from a key that isn't a SHA1 hash returns False.
        self.failIf(RegistrationProfile.objects.activate_user('foo'))
        
        # Activating from a key that doesn't exist returns False.
        self.failIf(RegistrationProfile.objects.activate_user(sha.new('foo').hexdigest()))

    def test_account_expiration_condition(self):
        """
        Test that ``RegistrationProfile.activation_key_expired()``
        returns ``True`` for expired users and for active users, and
        ``False`` otherwise.
        
        """
        # Unexpired user returns False.
        self.failIf(RegistrationProfile.objects.get(user=self.sample_user).activation_key_expired())

        # Expired user returns True.
        self.failUnless(RegistrationProfile.objects.get(user=self.expired_user).activation_key_expired())

        # Activated user returns True.
        RegistrationProfile.objects.activate_user(RegistrationProfile.objects.get(user=self.sample_user).activation_key)
        self.failUnless(RegistrationProfile.objects.get(user=self.sample_user).activation_key_expired())

    def test_expired_user_deletion(self):
        """
        Test that
        ``RegistrationProfile.objects.delete_expired_users()`` deletes
        only inactive users whose activation window has expired.
        
        """
        RegistrationProfile.objects.delete_expired_users()
        self.assertEqual(RegistrationProfile.objects.count(), 1)

    def test_management_command(self):
        """
        Test that ``manage.py cleanupregistration`` functions
        correctly.
        
        """
        management.call_command('cleanupregistration')
        self.assertEqual(RegistrationProfile.objects.count(), 1)

    def test_signals(self):
        """
        Test that the ``user_registered`` and ``user_activated``
        signals are sent, and that they send the ``user_model`` as an
        argument.
        
        """
        def receiver(sender, **kwargs):
            self.assert_('user' in kwargs)
            self.assertEqual(kwargs['user'].username, u'signal_test')
            received_signals.append(kwargs.get('signal'))

        received_signals = []
        expected_signals = [signals.user_registered, signals.user_activated]
        for signal in expected_signals:
            signal.connect(receiver)

        RegistrationProfile.objects.create_inactive_user(username='signal_test',
                                                         password='foo',
                                                         email='nobody@example.com',
                                                         send_email=False)
        RegistrationProfile.objects.activate_user(RegistrationProfile.objects.get(user__username='signal_test').activation_key)

        self.assertEqual(received_signals, expected_signals)


class RegistrationFormTests(RegistrationTestCase):
    """
    Tests for the forms and custom validation logic included in
    django-registration.
    
    """
    def test_registration_form(self):
        """
        Test that ``RegistrationForm`` enforces username constraints
        and matching passwords.
        
        """
        invalid_data_dicts = [
            # Non-alphanumeric username.
            {
            'data':
            { 'username': 'foo/bar',
              'email': 'foo@example.com',
              'password1': 'foo',
              'password2': 'foo' },
            'error':
            ('username', [u"Enter a valid value."])
            },
            # Already-existing username.
            {
            'data':
            { 'username': 'alice',
              'email': 'alice@example.com',
              'password1': 'secret',
              'password2': 'secret' },
            'error':
            ('username', [u"This username is already taken. Please choose another."])
            },
            # Mismatched passwords.
            {
            'data':
            { 'username': 'foo',
              'email': 'foo@example.com',
              'password1': 'foo',
              'password2': 'bar' },
            'error':
            ('__all__', [u"You must type the same password each time"])
            },
            ]

        for invalid_dict in invalid_data_dicts:
            form = forms.RegistrationForm(data=invalid_dict['data'])
            self.failIf(form.is_valid())
            self.assertEqual(form.errors[invalid_dict['error'][0]], invalid_dict['error'][1])

        form = forms.RegistrationForm(data={ 'username': 'foo',
                                             'email': 'foo@example.com',
                                             'password1': 'foo',
                                             'password2': 'foo' })
        self.failUnless(form.is_valid())

    def test_registration_form_tos(self):
        """
        Test that ``RegistrationFormTermsOfService`` requires
        agreement to the terms of service.
        
        """
        form = forms.RegistrationFormTermsOfService(data={ 'username': 'foo',
                                                           'email': 'foo@example.com',
                                                           'password1': 'foo',
                                                           'password2': 'foo' })
        self.failIf(form.is_valid())
        self.assertEqual(form.errors['tos'], [u"You must agree to the terms to register"])
        
        form = forms.RegistrationFormTermsOfService(data={ 'username': 'foo',
                                                           'email': 'foo@example.com',
                                                           'password1': 'foo',
                                                           'password2': 'foo',
                                                           'tos': 'on' })
        self.failUnless(form.is_valid())

    def test_registration_form_unique_email(self):
        """
        Test that ``RegistrationFormUniqueEmail`` validates uniqueness
        of email addresses.
        
        """
        form = forms.RegistrationFormUniqueEmail(data={ 'username': 'foo',
                                                        'email': 'alice@example.com',
                                                        'password1': 'foo',
                                                        'password2': 'foo' })
        self.failIf(form.is_valid())
        self.assertEqual(form.errors['email'], [u"This email address is already in use. Please supply a different email address."])

        form = forms.RegistrationFormUniqueEmail(data={ 'username': 'foo',
                                                        'email': 'foo@example.com',
                                                        'password1': 'foo',
                                                        'password2': 'foo' })
        self.failUnless(form.is_valid())

    def test_registration_form_no_free_email(self):
        """
        Test that ``RegistrationFormNoFreeEmail`` disallows
        registration with free email addresses.
        
        """
        base_data = { 'username': 'foo',
                      'password1': 'foo',
                      'password2': 'foo' }
        for domain in ('aim.com', 'aol.com', 'email.com', 'gmail.com',
                       'googlemail.com', 'hotmail.com', 'hushmail.com',
                       'msn.com', 'mail.ru', 'mailinator.com', 'live.com'):
            invalid_data = base_data.copy()
            invalid_data['email'] = u"foo@%s" % domain
            form = forms.RegistrationFormNoFreeEmail(data=invalid_data)
            self.failIf(form.is_valid())
            self.assertEqual(form.errors['email'], [u"Registration using free email addresses is prohibited. Please supply a different email address."])

        base_data['email'] = 'foo@example.com'
        form = forms.RegistrationFormNoFreeEmail(data=base_data)
        self.failUnless(form.is_valid())


class RegistrationViewTests(RegistrationTestCase):
    """
    Tests for the views included in django-registration.
    
    """
    def test_registration_view(self):
        """
        Test that the registration view rejects invalid submissions,
        and creates a new user and redirects after a valid submission.
        
        """
        # Invalid data fails.
        response = self.client.post(reverse('registration_register'),
                                    data={ 'username': 'alice', # Will fail on username uniqueness.
                                           'email': 'foo@example.com',
                                           'password1': 'foo',
                                           'password2': 'foo' })
        self.assertEqual(response.status_code, 200)
        self.failUnless(response.context['form'])
        self.failUnless(response.context['form'].errors)

        response = self.client.post(reverse('registration_register'),
                                    data={ 'username': 'foo',
                                           'email': 'foo@example.com',
                                           'password1': 'foo',
                                           'password2': 'foo' })
        self.assertEqual(response.status_code, 302)
        self.assertEqual(response['Location'], 'http://testserver%s' % reverse('registration_complete'))
        self.assertEqual(RegistrationProfile.objects.count(), 3)
    
    def test_activation_view(self):
        """
        Test that the activation view activates the user from a valid
        key and fails if the key is invalid or has expired.
       
        """
        # Valid user puts the user account into the context.
        response = self.client.get(reverse('registration_activate',
                                           kwargs={ 'activation_key': RegistrationProfile.objects.get(user=self.sample_user).activation_key }))
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.context['account'].pk, self.sample_user.pk)

        # Expired user sets the account to False.
        response = self.client.get(reverse('registration_activate',
                                           kwargs={ 'activation_key': RegistrationProfile.objects.get(user=self.expired_user).activation_key }))
        self.failIf(response.context['account'])

        # Invalid key gets to the view, but sets account to False.
        response = self.client.get(reverse('registration_activate',
                                           kwargs={ 'activation_key': 'foo' }))
        self.failIf(response.context['account'])

        # Nonexistent key sets the account to False.
        response = self.client.get(reverse('registration_activate',
                                           kwargs={ 'activation_key': sha.new('foo').hexdigest() }))
        self.failIf(response.context['account'])