""" 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 hashlib from django.conf import settings from django.contrib.auth.models import User from django.core import mail from django.core import management from django.core.urlresolvers import reverse from django.test import TestCase 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.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(hashlib.sha1('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`` 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': hashlib.sha1('foo').hexdigest() })) self.failIf(response.context['account'])