+++ /dev/null
-# Patchwork - automated patch tracking system
-# Copyright (C) 2011 Jeremy Kerr <jk@ozlabs.org>
-#
-# SPDX-License-Identifier: GPL-2.0-or-later
-
-from django.test import TestCase
-from django.urls import reverse
-
-from patchwork.models import EmailConfirmation
-from patchwork.tests.utils import create_user
-
-
-def _confirmation_url(conf):
- return reverse('confirm', kwargs={'key': conf.key})
-
-
-def _generate_secondary_email(user):
- return 'secondary_%d@example.com' % user.id
-
-
-class InvalidConfirmationTest(TestCase):
-
- def setUp(self):
- self.user = create_user()
- self.secondary_email = _generate_secondary_email(self.user)
-
- self.conf = EmailConfirmation(type='userperson',
- email=self.secondary_email,
- user=self.user)
- self.conf.save()
-
- def test_inactive_confirmation(self):
- self.conf.active = False
- self.conf.save()
- response = self.client.get(_confirmation_url(self.conf))
- self.assertEqual(response.status_code, 200)
- self.assertTemplateUsed(response, 'patchwork/confirm-error.html')
- self.assertEqual(response.context['error'], 'inactive')
- self.assertEqual(response.context['conf'], self.conf)
-
- def test_expired_confirmation(self):
- self.conf.date -= self.conf.validity
- self.conf.save()
- response = self.client.get(_confirmation_url(self.conf))
- self.assertEqual(response.status_code, 200)
- self.assertTemplateUsed(response, 'patchwork/confirm-error.html')
- self.assertEqual(response.context['error'], 'expired')
- self.assertEqual(response.context['conf'], self.conf)
+++ /dev/null
-# Patchwork - automated patch tracking system
-# Copyright (C) 2016 Intel Corporation
-#
-# SPDX-License-Identifier: GPL-2.0-or-later
-
-from datetime import datetime as dt
-from datetime import timedelta
-
-from django.test import TestCase
-from django.urls import reverse
-
-from patchwork.models import Check
-from patchwork.tests.utils import create_check
-from patchwork.tests.utils import create_cover
-from patchwork.tests.utils import create_cover_comment
-from patchwork.tests.utils import create_patch
-from patchwork.tests.utils import create_patch_comment
-from patchwork.tests.utils import create_project
-from patchwork.tests.utils import create_user
-
-
-class CoverViewTest(TestCase):
-
- def test_redirect(self):
- patch = create_patch()
-
- requested_url = reverse('cover-detail',
- kwargs={'project_id': patch.project.linkname,
- 'msgid': patch.url_msgid})
- redirect_url = reverse('patch-detail',
- kwargs={'project_id': patch.project.linkname,
- 'msgid': patch.url_msgid})
-
- response = self.client.get(requested_url)
- self.assertRedirects(response, redirect_url)
-
- def test_old_detail_url(self):
- cover = create_cover()
-
- requested_url = reverse('cover-id-redirect',
- kwargs={'cover_id': cover.id})
- redirect_url = reverse('cover-detail',
- kwargs={'project_id': cover.project.linkname,
- 'msgid': cover.url_msgid})
-
- response = self.client.get(requested_url)
- self.assertRedirects(response, redirect_url)
-
- def test_old_mbox_url(self):
- cover = create_cover()
-
- requested_url = reverse('cover-mbox-redirect',
- kwargs={'cover_id': cover.id})
- redirect_url = reverse('cover-mbox',
- kwargs={'project_id': cover.project.linkname,
- 'msgid': cover.url_msgid})
-
- response = self.client.get(requested_url)
- self.assertRedirects(response, redirect_url)
-
- def test_invalid_project_id(self):
- requested_url = reverse(
- 'cover-detail',
- kwargs={'project_id': 'foo', 'msgid': 'bar'},
- )
- response = self.client.get(requested_url)
- self.assertEqual(response.status_code, 404)
-
- def test_invalid_cover_id(self):
- project = create_project()
- requested_url = reverse(
- 'cover-detail',
- kwargs={'project_id': project.linkname, 'msgid': 'foo'},
- )
- response = self.client.get(requested_url)
- self.assertEqual(response.status_code, 404)
-
-
-class PatchViewTest(TestCase):
-
- def test_redirect(self):
- cover = create_cover()
-
- requested_url = reverse('patch-detail',
- kwargs={'project_id': cover.project.linkname,
- 'msgid': cover.url_msgid})
- redirect_url = reverse('cover-detail',
- kwargs={'project_id': cover.project.linkname,
- 'msgid': cover.url_msgid})
-
- response = self.client.get(requested_url)
- self.assertRedirects(response, redirect_url)
-
- def test_old_detail_url(self):
- patch = create_patch()
-
- requested_url = reverse('patch-id-redirect',
- kwargs={'patch_id': patch.id})
- redirect_url = reverse('patch-detail',
- kwargs={'project_id': patch.project.linkname,
- 'msgid': patch.url_msgid})
-
- response = self.client.get(requested_url)
- self.assertRedirects(response, redirect_url)
-
- def test_old_mbox_url(self):
- patch = create_patch()
-
- requested_url = reverse('patch-mbox-redirect',
- kwargs={'patch_id': patch.id})
- redirect_url = reverse('patch-mbox',
- kwargs={'project_id': patch.project.linkname,
- 'msgid': patch.url_msgid})
-
- response = self.client.get(requested_url)
- self.assertRedirects(response, redirect_url)
-
- def test_old_raw_url(self):
- patch = create_patch()
-
- requested_url = reverse('patch-raw-redirect',
- kwargs={'patch_id': patch.id})
- redirect_url = reverse('patch-raw',
- kwargs={'project_id': patch.project.linkname,
- 'msgid': patch.url_msgid})
-
- response = self.client.get(requested_url)
- self.assertRedirects(response, redirect_url)
-
- def test_escaping(self):
- # Warning: this test doesn't guarantee anything - it only tests some
- # fields
- unescaped_string = 'blah<b>TEST</b>blah'
- patch = create_patch()
- patch.diff = unescaped_string
- patch.commit_ref = unescaped_string
- patch.pull_url = unescaped_string
- patch.name = unescaped_string
- patch.msgid = '<' + unescaped_string + '>'
- patch.headers = unescaped_string
- patch.content = unescaped_string
- patch.save()
- requested_url = reverse('patch-detail',
- kwargs={'project_id': patch.project.linkname,
- 'msgid': patch.url_msgid})
- response = self.client.get(requested_url)
- self.assertNotIn('<b>TEST</b>'.encode('utf-8'), response.content)
-
- def test_invalid_project_id(self):
- requested_url = reverse(
- 'patch-detail',
- kwargs={'project_id': 'foo', 'msgid': 'bar'},
- )
- response = self.client.get(requested_url)
- self.assertEqual(response.status_code, 404)
-
- def test_invalid_patch_id(self):
- project = create_project()
- requested_url = reverse(
- 'patch-detail',
- kwargs={'project_id': project.linkname, 'msgid': 'foo'},
- )
- response = self.client.get(requested_url)
- self.assertEqual(response.status_code, 404)
-
- def test_patch_with_checks(self):
- user = create_user()
- patch = create_patch()
- check_a = create_check(
- patch=patch, user=user, context='foo', state=Check.STATE_FAIL,
- date=(dt.utcnow() - timedelta(days=1)))
- create_check(
- patch=patch, user=user, context='foo', state=Check.STATE_SUCCESS)
- check_b = create_check(
- patch=patch, user=user, context='bar', state=Check.STATE_PENDING)
- requested_url = reverse(
- 'patch-detail',
- kwargs={
- 'project_id': patch.project.linkname,
- 'msgid': patch.url_msgid,
- },
- )
- response = self.client.get(requested_url)
-
- # the response should contain checks
- self.assertContains(response, '<h2>Checks</h2>')
-
- # and it should only show the unique checks
- self.assertEqual(
- 1, response.content.decode().count(
- f'<td>{check_a.user}/{check_a.context}</td>'
- ))
- self.assertEqual(
- 1, response.content.decode().count(
- f'<td>{check_b.user}/{check_b.context}</td>'
- ))
-
-
-class CommentRedirectTest(TestCase):
-
- def test_patch_redirect(self):
- patch = create_patch()
- comment_id = create_patch_comment(patch=patch).id
-
- requested_url = reverse('comment-redirect',
- kwargs={'comment_id': comment_id})
- redirect_url = '%s#%d' % (
- reverse('patch-detail',
- kwargs={'project_id': patch.project.linkname,
- 'msgid': patch.url_msgid}),
- comment_id)
-
- response = self.client.get(requested_url)
- self.assertRedirects(response, redirect_url)
-
- def test_cover_redirect(self):
- cover = create_cover()
- comment_id = create_cover_comment(cover=cover).id
-
- requested_url = reverse('comment-redirect',
- kwargs={'comment_id': comment_id})
- redirect_url = '%s#%d' % (
- reverse('cover-detail',
- kwargs={'project_id': cover.project.linkname,
- 'msgid': cover.url_msgid}),
- comment_id)
-
- response = self.client.get(requested_url)
- self.assertRedirects(response, redirect_url)
+++ /dev/null
-# Patchwork - automated patch tracking system
-# Copyright (C) 2008 Jeremy Kerr <jk@ozlabs.org>
-#
-# SPDX-License-Identifier: GPL-2.0-or-later
-
-from django.test import TestCase
-from django.urls import reverse
-
-from patchwork.tests.utils import create_person
-from patchwork.tests.utils import create_patch
-from patchwork.tests.utils import read_patch
-
-
-class UTF8PatchViewTest(TestCase):
-
- def setUp(self):
- patch_content = read_patch('0002-utf-8.patch', encoding='utf-8')
- self.patch = create_patch(diff=patch_content)
-
- def test_patch_view(self):
- response = self.client.get(reverse(
- 'patch-detail', args=[self.patch.project.linkname,
- self.patch.url_msgid]))
- self.assertContains(response, self.patch.name)
-
- def test_mbox_view(self):
- response = self.client.get(
- reverse('patch-mbox', args=[self.patch.project.linkname,
- self.patch.url_msgid]))
- self.assertEqual(response.status_code, 200)
- self.assertTrue(self.patch.diff in response.content.decode('utf-8'))
-
- def test_raw_view(self):
- response = self.client.get(reverse('patch-raw',
- args=[self.patch.project.linkname,
- self.patch.url_msgid]))
- self.assertEqual(response.status_code, 200)
- self.assertEqual(response.content.decode('utf-8'), self.patch.diff)
-
-
-class UTF8HeaderPatchViewTest(UTF8PatchViewTest):
-
- def setUp(self):
- author = create_person(name=u'P\xe4tch Author')
- patch_content = read_patch('0002-utf-8.patch', encoding='utf-8')
- self.patch = create_patch(submitter=author, diff=patch_content)
+++ /dev/null
-# Patchwork - automated patch tracking system
-# Copyright (C) 2011 Jeremy Kerr <jk@ozlabs.org>
-#
-# SPDX-License-Identifier: GPL-2.0-or-later
-
-from django.test import TestCase
-from django.urls import reverse
-
-from patchwork.tests.utils import create_project
-
-
-class FilterQueryStringTest(TestCase):
-
- def test_escaping(self):
- """Validate escaping of filter fragments in a query string.
-
- Stray ampersands should not get reflected back in the filter
- links.
- """
- project = create_project()
- url = reverse('patch-list', args=[project.linkname])
-
- response = self.client.get(url + '?submitter=a%%26b=c')
-
- self.assertEqual(response.status_code, 200)
- self.assertNotContains(response, 'submitter=a&b=c')
- self.assertNotContains(response, 'submitter=a&b=c')
-
- def test_utf8_handling(self):
- """Validate handling of non-ascii characters."""
- project = create_project()
- url = reverse('patch-list', args=[project.linkname])
-
- response = self.client.get(url + '?submitter=%%E2%%98%%83')
-
- self.assertEqual(response.status_code, 200)
+++ /dev/null
-# Patchwork - automated patch tracking system
-# Copyright (C) 2012 Jeremy Kerr <jk@ozlabs.org>
-#
-# SPDX-License-Identifier: GPL-2.0-or-later
-
-from datetime import datetime as dt
-import unittest
-import re
-
-from django.conf import settings
-from django.test import TestCase
-from django.urls import reverse
-
-from patchwork.models import Patch
-from patchwork.tests.utils import create_patch
-from patchwork.tests.utils import create_person
-from patchwork.tests.utils import create_project
-
-
-class EmptyPatchListTest(TestCase):
-
- def test_empty_patch_list(self):
- """Validates absence of table with zero patches."""
- project = create_project()
- url = reverse('patch-list', kwargs={'project_id': project.linkname})
- response = self.client.get(url)
- self.assertContains(response, 'No patches to display')
-
-
-class PatchOrderTest(TestCase):
-
- patchmeta = [
- ('AlCMyjOsx', 'AlxMyjOsx@nRbqkQV.wBw',
- dt(2014, 3, 16, 13, 4, 50, 155643)),
- ('MMZnrcDjT', 'MMmnrcDjT@qGaIfOl.tbk',
- dt(2014, 1, 25, 13, 4, 50, 162814)),
- ('WGirwRXgK', 'WGSrwRXgK@TriIETY.GhE',
- dt(2014, 2, 14, 13, 4, 50, 169305)),
- ('isjNIuiAc', 'issNIuiAc@OsEirYx.EJh',
- dt(2014, 3, 15, 13, 4, 50, 176264)),
- ('XkAQpYGws', 'XkFQpYGws@hzntTcm.JSE',
- dt(2014, 1, 18, 13, 4, 50, 182493)),
- ('uJuCPWMvi', 'uJACPWMvi@AVRBOBl.ecy',
- dt(2014, 3, 12, 13, 4, 50, 189554)),
- ('TyQmWtcbg', 'TylmWtcbg@DzrNeNH.JuB',
- dt(2014, 2, 3, 13, 4, 50, 195685)),
- ('FpvAhWRdX', 'FpKAhWRdX@agxnCAI.wFO',
- dt(2014, 3, 15, 13, 4, 50, 201398)),
- ('bmoYvnyWa', 'bmdYvnyWa@aeoPnlX.juy',
- dt(2014, 3, 4, 13, 4, 50, 206800)),
- ('CiReUQsAq', 'CiieUQsAq@DnOYRuf.TTI',
- dt(2014, 3, 28, 13, 4, 50, 212169)),
- ]
-
- def setUp(self):
- self.project = create_project()
-
- for name, email, date in self.patchmeta:
- person = create_person(name=name, email=email)
- create_patch(submitter=person, project=self.project,
- date=date)
-
- def _extract_patch_ids(self, response):
- id_re = re.compile(r'<tr id="patch_row:(\d+)"')
- ids = [int(m.group(1))
- for m in id_re.finditer(response.content.decode())]
-
- return ids
-
- def _test_sequence(self, response, test_fn):
- ids = self._extract_patch_ids(response)
- self.assertTrue(bool(ids))
- patches = [Patch.objects.get(id=i) for i in ids]
- pairs = list(zip(patches, patches[1:]))
-
- for p1, p2 in pairs:
- test_fn(p1, p2)
-
- def test_date_order(self):
- url = reverse('patch-list',
- kwargs={'project_id': self.project.linkname})
- response = self.client.get(url + '?order=date')
-
- def test_fn(p1, p2):
- self.assertLessEqual(p1.date, p2.date)
-
- self._test_sequence(response, test_fn)
-
- def test_date_reverse_order(self):
- url = reverse('patch-list',
- kwargs={'project_id': self.project.linkname})
- response = self.client.get(url + '?order=-date')
-
- def test_fn(p1, p2):
- self.assertGreaterEqual(p1.date, p2.date)
-
- self._test_sequence(response, test_fn)
-
- # TODO(stephenfin): Looks like this has been resolved in Django 2.1 [1]? If
- # not, it should be possible [2]
- #
- # [1] https://code.djangoproject.com/ticket/30248
- # [2] https://michaelsoolee.com/case-insensitive-sorting-sqlite/
- @unittest.skipIf('sqlite3' in settings.DATABASES['default']['ENGINE'],
- 'The sqlite3 backend does not support case insensitive '
- 'ordering')
- def test_submitter_order(self):
- url = reverse('patch-list',
- kwargs={'project_id': self.project.linkname})
- response = self.client.get(url + '?order=submitter')
-
- def test_fn(p1, p2):
- self.assertLessEqual(p1.submitter.name.lower(),
- p2.submitter.name.lower())
-
- self._test_sequence(response, test_fn)
-
- @unittest.skipIf('sqlite3' in settings.DATABASES['default']['ENGINE'],
- 'The sqlite3 backend does not support case insensitive '
- 'ordering')
- def test_submitter_reverse_order(self):
- url = reverse('patch-list',
- kwargs={'project_id': self.project.linkname})
- response = self.client.get(url + '?order=-submitter')
-
- def test_fn(p1, p2):
- self.assertGreaterEqual(p1.submitter.name.lower(),
- p2.submitter.name.lower())
-
- self._test_sequence(response, test_fn)
+++ /dev/null
-# Patchwork - automated patch tracking system
-# Copyright (C) 2010 Jeremy Kerr <jk@ozlabs.org>
-#
-# SPDX-License-Identifier: GPL-2.0-or-later
-
-from django.contrib.auth.models import User
-from django.core import mail
-from django.test.client import Client
-from django.test import TestCase
-from django.urls import reverse
-
-from patchwork.models import EmailConfirmation
-from patchwork.models import Person
-from patchwork.tests.utils import create_user
-
-
-def _confirmation_url(conf):
- return reverse('confirm', kwargs={'key': conf.key})
-
-
-class TestUser(object):
- firstname = 'Test'
- lastname = 'User'
- fullname = ' '.join([firstname, lastname])
- username = 'testuser'
- email = 'test@example.com'
- password = 'foobar'
-
-
-class RegistrationTest(TestCase):
-
- def setUp(self):
- self.user = TestUser()
- self.client = Client()
- self.default_data = {
- 'username': self.user.username,
- 'first_name': self.user.firstname,
- 'last_name': self.user.lastname,
- 'email': self.user.email,
- 'password': self.user.password,
- }
- self.required_error = 'This field is required.'
- self.invalid_error = 'Enter a valid value.'
-
- def test_registration_form(self):
- response = self.client.get('/register/')
- self.assertEqual(response.status_code, 200)
- self.assertTemplateUsed(response, 'patchwork/registration.html')
-
- def test_blank_fields(self):
- for field in ['username', 'email', 'password']:
- data = self.default_data.copy()
- del data[field]
- response = self.client.post('/register/', data)
- self.assertEqual(response.status_code, 200)
- self.assertFormError(response, 'form', field, self.required_error)
-
- def test_invalid_username(self):
- data = self.default_data.copy()
- data['username'] = 'invalid user'
- response = self.client.post('/register/', data)
- self.assertEqual(response.status_code, 200)
- self.assertFormError(response, 'form', 'username', self.invalid_error)
-
- def test_existing_username(self):
- user = create_user()
- data = self.default_data.copy()
- data['username'] = user.username
- response = self.client.post('/register/', data)
- self.assertEqual(response.status_code, 200)
- self.assertFormError(
- response, 'form', 'username',
- 'This username is already taken. Please choose another.')
-
- def test_existing_email(self):
- user = create_user()
- data = self.default_data.copy()
- data['email'] = user.email
- response = self.client.post('/register/', data)
- self.assertEqual(response.status_code, 200)
- self.assertFormError(
- response, 'form', 'email',
- 'This email address is already in use for the account '
- '"%s".\n' % user.username)
-
- def test_valid_registration(self):
- response = self.client.post('/register/', self.default_data)
- self.assertEqual(response.status_code, 200)
- self.assertContains(response, 'confirmation email has been sent')
-
- # check for presence of an inactive user object
- users = User.objects.filter(username=self.user.username)
- self.assertEqual(users.count(), 1)
- user = users[0]
- self.assertEqual(user.username, self.user.username)
- self.assertEqual(user.email, self.user.email)
- self.assertEqual(user.is_active, False)
-
- # check for confirmation object
- confs = EmailConfirmation.objects.filter(
- user=user, type='registration')
- self.assertEqual(len(confs), 1)
- conf = confs[0]
- self.assertEqual(conf.email, self.user.email)
-
- # check for a sent mail
- self.assertEqual(len(mail.outbox), 1)
- msg = mail.outbox[0]
- self.assertEqual(msg.subject, 'Patchwork account confirmation')
- self.assertIn(self.user.email, msg.to)
- self.assertIn(_confirmation_url(conf), msg.body)
-
- # ...and that the URL is valid
- response = self.client.get(_confirmation_url(conf))
- self.assertEqual(response.status_code, 200)
-
-
-class RegistrationConfirmationTest(TestCase):
-
- def setUp(self):
- self.user = TestUser()
- self.default_data = {
- 'username': self.user.username,
- 'first_name': self.user.firstname,
- 'last_name': self.user.lastname,
- 'email': self.user.email,
- 'password': self.user.password
- }
-
- def test_valid(self):
- """Test the success path."""
- self.assertEqual(EmailConfirmation.objects.count(), 0)
- response = self.client.post('/register/', self.default_data)
- self.assertEqual(response.status_code, 200)
- self.assertContains(response, 'confirmation email has been sent')
-
- self.assertEqual(EmailConfirmation.objects.count(), 1)
- conf = EmailConfirmation.objects.filter()[0]
- self.assertFalse(conf.user.is_active)
- self.assertTrue(conf.active)
-
- response = self.client.get(_confirmation_url(conf))
- self.assertEqual(response.status_code, 200)
- self.assertTemplateUsed(
- response, 'patchwork/registration-confirm.html')
-
- conf = EmailConfirmation.objects.get(pk=conf.pk)
- self.assertTrue(conf.user.is_active)
- self.assertFalse(conf.active)
-
- def test_new_person_setup(self):
- """Ensure a new Person is created after account setup.
-
- Create an account for a never before seen email. Check that a Person
- object is created after registration and has the correct details.
- """
- # register
- self.assertEqual(EmailConfirmation.objects.count(), 0)
- response = self.client.post('/register/', self.default_data)
- self.assertEqual(response.status_code, 200)
- self.assertFalse(Person.objects.exists())
-
- # confirm
- conf = EmailConfirmation.objects.filter()[0]
- response = self.client.get(_confirmation_url(conf))
- self.assertEqual(response.status_code, 200)
-
- qs = Person.objects.filter(email=self.user.email)
- self.assertTrue(qs.exists())
- person = Person.objects.get(email=self.user.email)
-
- self.assertEqual(person.name, self.user.fullname)
-
- def test_existing_person_setup(self):
- """Ensure an existing person is linked after account setup.
-
- Create an account for a user using an email we've previously seen.
- Check that the person object is updated after registration with the
- correct details.
- """
- person = Person(name=self.user.fullname, email=self.user.email)
- person.save()
-
- # register
- self.assertEqual(EmailConfirmation.objects.count(), 0)
- response = self.client.post('/register/', self.default_data)
- self.assertEqual(response.status_code, 200)
-
- # confirm
- conf = EmailConfirmation.objects.filter()[0]
- response = self.client.get(_confirmation_url(conf))
- self.assertEqual(response.status_code, 200)
-
- person = Person.objects.get(email=self.user.email)
-
- self.assertEqual(person.name, self.user.fullname)
-
- def test_existing_person_unmodified(self):
- """Ensure an existing person is not linked until registration is done.
-
- Create an account for a user using an email we've previously seen but
- don't confirm it. Check that the person object is not updated yet.
- """
- person = Person(name=self.user.fullname, email=self.user.email)
- person.save()
-
- # register
- data = self.default_data.copy()
- data['first_name'] = 'invalid'
- data['last_name'] = 'invalid'
- self.assertEqual(data['email'], person.email)
- response = self.client.post('/register/', data)
- self.assertEqual(response.status_code, 200)
-
- self.assertEqual(
- Person.objects.get(pk=person.pk).name, self.user.fullname)
+++ /dev/null
-# Patchwork - automated patch tracking system
-# Copyright (C) 2010 Jeremy Kerr <jk@ozlabs.org>
-#
-# SPDX-License-Identifier: GPL-2.0-or-later
-
-from django.test import TestCase
-from django.urls import reverse
-
-from patchwork.models import Patch
-from patchwork.models import State
-from patchwork.tests.utils import create_patches
-from patchwork.tests.utils import create_project
-from patchwork.tests.utils import create_state
-from patchwork.tests.utils import create_maintainer
-
-
-class MultipleUpdateTest(TestCase):
-
- properties_form_id = 'patchform-properties'
-
- def setUp(self):
- self.project = create_project()
- self.user = create_maintainer(self.project)
- self.patches = create_patches(3, project=self.project)
-
- self.client.login(username=self.user.username,
- password=self.user.username)
-
- self.url = reverse('patch-list', args=[self.project.linkname])
- self.base_data = {
- 'action': 'Update',
- 'project': str(self.project.id),
- 'form': 'patchlistform',
- 'archived': '*',
- 'delegate': '*',
- 'state': '*'
- }
-
- def _select_all_patches(self, data):
- for patch in self.patches:
- data['patch_id:%d' % patch.id] = 'checked'
-
- def test_archiving_patches(self):
- data = self.base_data.copy()
- data.update({'archived': 'True'})
- self._select_all_patches(data)
-
- response = self.client.post(self.url, data)
-
- self.assertContains(response, 'No patches to display',
- status_code=200)
- # Don't use the cached version of patches: retrieve from the DB
- for patch in [Patch.objects.get(pk=p.pk) for p in self.patches]:
- self.assertTrue(patch.archived)
-
- def test_unarchiving_patches(self):
- # Start with one patch archived and the remaining ones unarchived.
- self.patches[0].archived = True
- self.patches[0].save()
-
- data = self.base_data.copy()
- data.update({'archived': 'False'})
- self._select_all_patches(data)
-
- response = self.client.post(self.url, data)
-
- self.assertContains(response, self.properties_form_id,
- status_code=200)
- for patch in [Patch.objects.get(pk=p.pk) for p in self.patches]:
- self.assertFalse(patch.archived)
-
- def _test_state_change(self, state):
- data = self.base_data.copy()
- data.update({'state': str(state)})
- self._select_all_patches(data)
-
- response = self.client.post(self.url, data)
-
- self.assertContains(response, self.properties_form_id,
- status_code=200)
- return response
-
- def test_state_change_valid(self):
- state = create_state()
-
- self._test_state_change(state.pk)
-
- for patch in [Patch.objects.get(pk=p.pk) for p in self.patches]:
- self.assertEqual(patch.state, state)
-
- def test_state_change_invalid(self):
- state = max(State.objects.all().values_list('id', flat=True)) + 1
- orig_states = [patch.state for patch in self.patches]
-
- response = self._test_state_change(state)
-
- new_states = [Patch.objects.get(pk=p.pk).state for p in self.patches]
- self.assertEqual(new_states, orig_states)
- self.assertFormError(response, 'patchform', 'state',
- 'Select a valid choice. That choice is not one '
- 'of the available choices.')
-
- def _test_delegate_change(self, delegate_str):
- data = self.base_data.copy()
- data.update({'delegate': delegate_str})
- self._select_all_patches(data)
-
- response = self.client.post(self.url, data)
-
- self.assertContains(response, self.properties_form_id, status_code=200)
- return response
-
- def test_delegate_change_valid(self):
- delegate = create_maintainer(self.project)
-
- self._test_delegate_change(str(delegate.pk))
-
- for patch in [Patch.objects.get(pk=p.pk) for p in self.patches]:
- self.assertEqual(patch.delegate, delegate)
-
- def test_delegate_clear(self):
- self._test_delegate_change('')
-
- for patch in [Patch.objects.get(pk=p.pk) for p in self.patches]:
- self.assertEqual(patch.delegate, None)
--- /dev/null
+# Patchwork - automated patch tracking system
+# Copyright (C) 2016 Intel Corporation
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from django.test import TestCase
+from django.urls import reverse
+
+from patchwork.tests.utils import create_cover
+from patchwork.tests.utils import create_cover_comment
+from patchwork.tests.utils import create_project
+
+
+class CoverViewTest(TestCase):
+
+ def test_redirect(self):
+ cover = create_cover()
+
+ requested_url = reverse('patch-detail',
+ kwargs={'project_id': cover.project.linkname,
+ 'msgid': cover.url_msgid})
+ redirect_url = reverse('cover-detail',
+ kwargs={'project_id': cover.project.linkname,
+ 'msgid': cover.url_msgid})
+
+ response = self.client.get(requested_url)
+ self.assertRedirects(response, redirect_url)
+
+ def test_old_detail_url(self):
+ cover = create_cover()
+
+ requested_url = reverse('cover-id-redirect',
+ kwargs={'cover_id': cover.id})
+ redirect_url = reverse('cover-detail',
+ kwargs={'project_id': cover.project.linkname,
+ 'msgid': cover.url_msgid})
+
+ response = self.client.get(requested_url)
+ self.assertRedirects(response, redirect_url)
+
+ def test_old_mbox_url(self):
+ cover = create_cover()
+
+ requested_url = reverse('cover-mbox-redirect',
+ kwargs={'cover_id': cover.id})
+ redirect_url = reverse('cover-mbox',
+ kwargs={'project_id': cover.project.linkname,
+ 'msgid': cover.url_msgid})
+
+ response = self.client.get(requested_url)
+ self.assertRedirects(response, redirect_url)
+
+ def test_invalid_project_id(self):
+ requested_url = reverse(
+ 'cover-detail',
+ kwargs={'project_id': 'foo', 'msgid': 'bar'},
+ )
+ response = self.client.get(requested_url)
+ self.assertEqual(response.status_code, 404)
+
+ def test_invalid_cover_id(self):
+ project = create_project()
+ requested_url = reverse(
+ 'cover-detail',
+ kwargs={'project_id': project.linkname, 'msgid': 'foo'},
+ )
+ response = self.client.get(requested_url)
+ self.assertEqual(response.status_code, 404)
+
+
+class CommentRedirectTest(TestCase):
+
+ def test_cover_redirect(self):
+ cover = create_cover()
+ comment_id = create_cover_comment(cover=cover).id
+
+ requested_url = reverse('comment-redirect',
+ kwargs={'comment_id': comment_id})
+ redirect_url = '%s#%d' % (
+ reverse('cover-detail',
+ kwargs={'project_id': cover.project.linkname,
+ 'msgid': cover.url_msgid}),
+ comment_id)
+
+ response = self.client.get(requested_url)
+ self.assertRedirects(response, redirect_url)
--- /dev/null
+# Patchwork - automated patch tracking system
+# Copyright (C) 2012 Jeremy Kerr <jk@ozlabs.org>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from datetime import datetime as dt
+from datetime import timedelta
+import re
+import unittest
+
+from django.conf import settings
+from django.test import TestCase
+from django.urls import reverse
+
+from patchwork.models import Check
+from patchwork.models import Patch
+from patchwork.models import State
+from patchwork.tests.utils import create_check
+from patchwork.tests.utils import create_maintainer
+from patchwork.tests.utils import create_patch
+from patchwork.tests.utils import create_patch_comment
+from patchwork.tests.utils import create_patches
+from patchwork.tests.utils import create_person
+from patchwork.tests.utils import create_project
+from patchwork.tests.utils import create_state
+from patchwork.tests.utils import create_user
+from patchwork.tests.utils import read_patch
+
+
+class EmptyPatchListTest(TestCase):
+
+ def test_empty_patch_list(self):
+ """Validates absence of table with zero patches."""
+ project = create_project()
+ url = reverse('patch-list', kwargs={'project_id': project.linkname})
+ response = self.client.get(url)
+ self.assertContains(response, 'No patches to display')
+
+
+class PatchListOrderingTest(TestCase):
+
+ patchmeta = [
+ ('AlCMyjOsx', 'AlxMyjOsx@nRbqkQV.wBw',
+ dt(2014, 3, 16, 13, 4, 50, 155643)),
+ ('MMZnrcDjT', 'MMmnrcDjT@qGaIfOl.tbk',
+ dt(2014, 1, 25, 13, 4, 50, 162814)),
+ ('WGirwRXgK', 'WGSrwRXgK@TriIETY.GhE',
+ dt(2014, 2, 14, 13, 4, 50, 169305)),
+ ('isjNIuiAc', 'issNIuiAc@OsEirYx.EJh',
+ dt(2014, 3, 15, 13, 4, 50, 176264)),
+ ('XkAQpYGws', 'XkFQpYGws@hzntTcm.JSE',
+ dt(2014, 1, 18, 13, 4, 50, 182493)),
+ ('uJuCPWMvi', 'uJACPWMvi@AVRBOBl.ecy',
+ dt(2014, 3, 12, 13, 4, 50, 189554)),
+ ('TyQmWtcbg', 'TylmWtcbg@DzrNeNH.JuB',
+ dt(2014, 2, 3, 13, 4, 50, 195685)),
+ ('FpvAhWRdX', 'FpKAhWRdX@agxnCAI.wFO',
+ dt(2014, 3, 15, 13, 4, 50, 201398)),
+ ('bmoYvnyWa', 'bmdYvnyWa@aeoPnlX.juy',
+ dt(2014, 3, 4, 13, 4, 50, 206800)),
+ ('CiReUQsAq', 'CiieUQsAq@DnOYRuf.TTI',
+ dt(2014, 3, 28, 13, 4, 50, 212169)),
+ ]
+
+ def setUp(self):
+ self.project = create_project()
+
+ for name, email, date in self.patchmeta:
+ person = create_person(name=name, email=email)
+ create_patch(submitter=person, project=self.project,
+ date=date)
+
+ def _extract_patch_ids(self, response):
+ id_re = re.compile(r'<tr id="patch_row:(\d+)"')
+ ids = [int(m.group(1))
+ for m in id_re.finditer(response.content.decode())]
+
+ return ids
+
+ def _test_sequence(self, response, test_fn):
+ ids = self._extract_patch_ids(response)
+ self.assertTrue(bool(ids))
+ patches = [Patch.objects.get(id=i) for i in ids]
+ pairs = list(zip(patches, patches[1:]))
+
+ for p1, p2 in pairs:
+ test_fn(p1, p2)
+
+ def test_date_order(self):
+ url = reverse('patch-list',
+ kwargs={'project_id': self.project.linkname})
+ response = self.client.get(url + '?order=date')
+
+ def test_fn(p1, p2):
+ self.assertLessEqual(p1.date, p2.date)
+
+ self._test_sequence(response, test_fn)
+
+ def test_date_reverse_order(self):
+ url = reverse('patch-list',
+ kwargs={'project_id': self.project.linkname})
+ response = self.client.get(url + '?order=-date')
+
+ def test_fn(p1, p2):
+ self.assertGreaterEqual(p1.date, p2.date)
+
+ self._test_sequence(response, test_fn)
+
+ # TODO(stephenfin): Looks like this has been resolved in Django 2.1 [1]? If
+ # not, it should be possible [2]
+ #
+ # [1] https://code.djangoproject.com/ticket/30248
+ # [2] https://michaelsoolee.com/case-insensitive-sorting-sqlite/
+ @unittest.skipIf('sqlite3' in settings.DATABASES['default']['ENGINE'],
+ 'The sqlite3 backend does not support case insensitive '
+ 'ordering')
+ def test_submitter_order(self):
+ url = reverse('patch-list',
+ kwargs={'project_id': self.project.linkname})
+ response = self.client.get(url + '?order=submitter')
+
+ def test_fn(p1, p2):
+ self.assertLessEqual(p1.submitter.name.lower(),
+ p2.submitter.name.lower())
+
+ self._test_sequence(response, test_fn)
+
+ @unittest.skipIf('sqlite3' in settings.DATABASES['default']['ENGINE'],
+ 'The sqlite3 backend does not support case insensitive '
+ 'ordering')
+ def test_submitter_reverse_order(self):
+ url = reverse('patch-list',
+ kwargs={'project_id': self.project.linkname})
+ response = self.client.get(url + '?order=-submitter')
+
+ def test_fn(p1, p2):
+ self.assertGreaterEqual(p1.submitter.name.lower(),
+ p2.submitter.name.lower())
+
+ self._test_sequence(response, test_fn)
+
+
+class PatchListFilteringTest(TestCase):
+
+ def test_escaping(self):
+ """Validate escaping of filter fragments in a query string.
+
+ Stray ampersands should not get reflected back in the filter
+ links.
+ """
+ project = create_project()
+ url = reverse('patch-list', args=[project.linkname])
+
+ response = self.client.get(url + '?submitter=a%%26b=c')
+
+ self.assertEqual(response.status_code, 200)
+ self.assertNotContains(response, 'submitter=a&b=c')
+ self.assertNotContains(response, 'submitter=a&b=c')
+
+ def test_utf8_handling(self):
+ """Validate handling of non-ascii characters."""
+ project = create_project()
+ url = reverse('patch-list', args=[project.linkname])
+
+ response = self.client.get(url + '?submitter=%%E2%%98%%83')
+
+ self.assertEqual(response.status_code, 200)
+
+
+class PatchViewTest(TestCase):
+
+ def test_redirect(self):
+ patch = create_patch()
+
+ requested_url = reverse('cover-detail',
+ kwargs={'project_id': patch.project.linkname,
+ 'msgid': patch.url_msgid})
+ redirect_url = reverse('patch-detail',
+ kwargs={'project_id': patch.project.linkname,
+ 'msgid': patch.url_msgid})
+
+ response = self.client.get(requested_url)
+ self.assertRedirects(response, redirect_url)
+
+ def test_comment_redirect(self):
+ patch = create_patch()
+ comment_id = create_patch_comment(patch=patch).id
+
+ requested_url = reverse('comment-redirect',
+ kwargs={'comment_id': comment_id})
+ redirect_url = '%s#%d' % (
+ reverse('patch-detail',
+ kwargs={'project_id': patch.project.linkname,
+ 'msgid': patch.url_msgid}),
+ comment_id)
+
+ response = self.client.get(requested_url)
+ self.assertRedirects(response, redirect_url)
+
+ def test_old_detail_url(self):
+ patch = create_patch()
+
+ requested_url = reverse('patch-id-redirect',
+ kwargs={'patch_id': patch.id})
+ redirect_url = reverse('patch-detail',
+ kwargs={'project_id': patch.project.linkname,
+ 'msgid': patch.url_msgid})
+
+ response = self.client.get(requested_url)
+ self.assertRedirects(response, redirect_url)
+
+ def test_old_mbox_url(self):
+ patch = create_patch()
+
+ requested_url = reverse('patch-mbox-redirect',
+ kwargs={'patch_id': patch.id})
+ redirect_url = reverse('patch-mbox',
+ kwargs={'project_id': patch.project.linkname,
+ 'msgid': patch.url_msgid})
+
+ response = self.client.get(requested_url)
+ self.assertRedirects(response, redirect_url)
+
+ def test_old_raw_url(self):
+ patch = create_patch()
+
+ requested_url = reverse('patch-raw-redirect',
+ kwargs={'patch_id': patch.id})
+ redirect_url = reverse('patch-raw',
+ kwargs={'project_id': patch.project.linkname,
+ 'msgid': patch.url_msgid})
+
+ response = self.client.get(requested_url)
+ self.assertRedirects(response, redirect_url)
+
+ def test_escaping(self):
+ # Warning: this test doesn't guarantee anything - it only tests some
+ # fields
+ unescaped_string = 'blah<b>TEST</b>blah'
+ patch = create_patch()
+ patch.diff = unescaped_string
+ patch.commit_ref = unescaped_string
+ patch.pull_url = unescaped_string
+ patch.name = unescaped_string
+ patch.msgid = '<' + unescaped_string + '>'
+ patch.headers = unescaped_string
+ patch.content = unescaped_string
+ patch.save()
+ requested_url = reverse('patch-detail',
+ kwargs={'project_id': patch.project.linkname,
+ 'msgid': patch.url_msgid})
+ response = self.client.get(requested_url)
+ self.assertNotIn('<b>TEST</b>'.encode('utf-8'), response.content)
+
+ def test_invalid_project_id(self):
+ requested_url = reverse(
+ 'patch-detail',
+ kwargs={'project_id': 'foo', 'msgid': 'bar'},
+ )
+ response = self.client.get(requested_url)
+ self.assertEqual(response.status_code, 404)
+
+ def test_invalid_patch_id(self):
+ project = create_project()
+ requested_url = reverse(
+ 'patch-detail',
+ kwargs={'project_id': project.linkname, 'msgid': 'foo'},
+ )
+ response = self.client.get(requested_url)
+ self.assertEqual(response.status_code, 404)
+
+ def test_patch_with_checks(self):
+ user = create_user()
+ patch = create_patch()
+ check_a = create_check(
+ patch=patch, user=user, context='foo', state=Check.STATE_FAIL,
+ date=(dt.utcnow() - timedelta(days=1)))
+ create_check(
+ patch=patch, user=user, context='foo', state=Check.STATE_SUCCESS)
+ check_b = create_check(
+ patch=patch, user=user, context='bar', state=Check.STATE_PENDING)
+ requested_url = reverse(
+ 'patch-detail',
+ kwargs={
+ 'project_id': patch.project.linkname,
+ 'msgid': patch.url_msgid,
+ },
+ )
+ response = self.client.get(requested_url)
+
+ # the response should contain checks
+ self.assertContains(response, '<h2>Checks</h2>')
+
+ # and it should only show the unique checks
+ self.assertEqual(
+ 1, response.content.decode().count(
+ f'<td>{check_a.user}/{check_a.context}</td>'
+ ))
+ self.assertEqual(
+ 1, response.content.decode().count(
+ f'<td>{check_b.user}/{check_b.context}</td>'
+ ))
+
+
+class PatchUpdateTest(TestCase):
+
+ properties_form_id = 'patchform-properties'
+
+ def setUp(self):
+ self.project = create_project()
+ self.user = create_maintainer(self.project)
+ self.patches = create_patches(3, project=self.project)
+
+ self.client.login(username=self.user.username,
+ password=self.user.username)
+
+ self.url = reverse('patch-list', args=[self.project.linkname])
+ self.base_data = {
+ 'action': 'Update',
+ 'project': str(self.project.id),
+ 'form': 'patchlistform',
+ 'archived': '*',
+ 'delegate': '*',
+ 'state': '*'
+ }
+
+ def _select_all_patches(self, data):
+ for patch in self.patches:
+ data['patch_id:%d' % patch.id] = 'checked'
+
+ def test_archiving_patches(self):
+ data = self.base_data.copy()
+ data.update({'archived': 'True'})
+ self._select_all_patches(data)
+
+ response = self.client.post(self.url, data)
+
+ self.assertContains(response, 'No patches to display',
+ status_code=200)
+ # Don't use the cached version of patches: retrieve from the DB
+ for patch in [Patch.objects.get(pk=p.pk) for p in self.patches]:
+ self.assertTrue(patch.archived)
+
+ def test_unarchiving_patches(self):
+ # Start with one patch archived and the remaining ones unarchived.
+ self.patches[0].archived = True
+ self.patches[0].save()
+
+ data = self.base_data.copy()
+ data.update({'archived': 'False'})
+ self._select_all_patches(data)
+
+ response = self.client.post(self.url, data)
+
+ self.assertContains(response, self.properties_form_id,
+ status_code=200)
+ for patch in [Patch.objects.get(pk=p.pk) for p in self.patches]:
+ self.assertFalse(patch.archived)
+
+ def _test_state_change(self, state):
+ data = self.base_data.copy()
+ data.update({'state': str(state)})
+ self._select_all_patches(data)
+
+ response = self.client.post(self.url, data)
+
+ self.assertContains(response, self.properties_form_id,
+ status_code=200)
+ return response
+
+ def test_state_change_valid(self):
+ state = create_state()
+
+ self._test_state_change(state.pk)
+
+ for patch in [Patch.objects.get(pk=p.pk) for p in self.patches]:
+ self.assertEqual(patch.state, state)
+
+ def test_state_change_invalid(self):
+ state = max(State.objects.all().values_list('id', flat=True)) + 1
+ orig_states = [patch.state for patch in self.patches]
+
+ response = self._test_state_change(state)
+
+ new_states = [Patch.objects.get(pk=p.pk).state for p in self.patches]
+ self.assertEqual(new_states, orig_states)
+ self.assertFormError(response, 'patchform', 'state',
+ 'Select a valid choice. That choice is not one '
+ 'of the available choices.')
+
+ def _test_delegate_change(self, delegate_str):
+ data = self.base_data.copy()
+ data.update({'delegate': delegate_str})
+ self._select_all_patches(data)
+
+ response = self.client.post(self.url, data)
+
+ self.assertContains(response, self.properties_form_id, status_code=200)
+ return response
+
+ def test_delegate_change_valid(self):
+ delegate = create_maintainer(self.project)
+
+ self._test_delegate_change(str(delegate.pk))
+
+ for patch in [Patch.objects.get(pk=p.pk) for p in self.patches]:
+ self.assertEqual(patch.delegate, delegate)
+
+ def test_delegate_clear(self):
+ self._test_delegate_change('')
+
+ for patch in [Patch.objects.get(pk=p.pk) for p in self.patches]:
+ self.assertEqual(patch.delegate, None)
+
+
+class UTF8PatchViewTest(TestCase):
+
+ def setUp(self):
+ patch_content = read_patch('0002-utf-8.patch', encoding='utf-8')
+ self.patch = create_patch(diff=patch_content)
+
+ def test_patch_view(self):
+ response = self.client.get(reverse(
+ 'patch-detail', args=[self.patch.project.linkname,
+ self.patch.url_msgid]))
+ self.assertContains(response, self.patch.name)
+
+ def test_mbox_view(self):
+ response = self.client.get(
+ reverse('patch-mbox', args=[self.patch.project.linkname,
+ self.patch.url_msgid]))
+ self.assertEqual(response.status_code, 200)
+ self.assertTrue(self.patch.diff in response.content.decode('utf-8'))
+
+ def test_raw_view(self):
+ response = self.client.get(reverse('patch-raw',
+ args=[self.patch.project.linkname,
+ self.patch.url_msgid]))
+ self.assertEqual(response.status_code, 200)
+ self.assertEqual(response.content.decode('utf-8'), self.patch.diff)
+
+
+class UTF8HeaderPatchViewTest(UTF8PatchViewTest):
+
+ def setUp(self):
+ author = create_person(name=u'P\xe4tch Author')
+ patch_content = read_patch('0002-utf-8.patch', encoding='utf-8')
+ self.patch = create_patch(submitter=author, diff=patch_content)
from django.contrib.auth.models import User
from django.core import mail
+from django.test.client import Client
from django.test import TestCase
from django.urls import reverse
from patchwork.models import EmailConfirmation
from patchwork.models import Person
from patchwork.models import UserProfile
+from patchwork.tests import utils
from patchwork.tests.utils import create_bundle
from patchwork.tests.utils import create_user
from patchwork.tests.utils import error_strings
-from patchwork.tests import utils
def _confirmation_url(conf):
password=self.password)
-class UserPersonRequestTest(_UserTestCase):
+class TestUser(object):
+ firstname = 'Test'
+ lastname = 'User'
+ fullname = ' '.join([firstname, lastname])
+ username = 'testuser'
+ email = 'test@example.com'
+ password = 'foobar'
+
+
+class RegistrationTest(TestCase):
def setUp(self):
- super(UserPersonRequestTest, self).setUp()
+ self.user = TestUser()
+ self.client = Client()
+ self.default_data = {
+ 'username': self.user.username,
+ 'first_name': self.user.firstname,
+ 'last_name': self.user.lastname,
+ 'email': self.user.email,
+ 'password': self.user.password,
+ }
+ self.required_error = 'This field is required.'
+ self.invalid_error = 'Enter a valid value.'
+
+ def test_registration_form(self):
+ response = self.client.get('/register/')
+ self.assertEqual(response.status_code, 200)
+ self.assertTemplateUsed(response, 'patchwork/registration.html')
+
+ def test_blank_fields(self):
+ for field in ['username', 'email', 'password']:
+ data = self.default_data.copy()
+ del data[field]
+ response = self.client.post('/register/', data)
+ self.assertEqual(response.status_code, 200)
+ self.assertFormError(response, 'form', field, self.required_error)
+
+ def test_invalid_username(self):
+ data = self.default_data.copy()
+ data['username'] = 'invalid user'
+ response = self.client.post('/register/', data)
+ self.assertEqual(response.status_code, 200)
+ self.assertFormError(response, 'form', 'username', self.invalid_error)
+
+ def test_existing_username(self):
+ user = create_user()
+ data = self.default_data.copy()
+ data['username'] = user.username
+ response = self.client.post('/register/', data)
+ self.assertEqual(response.status_code, 200)
+ self.assertFormError(
+ response, 'form', 'username',
+ 'This username is already taken. Please choose another.')
+
+ def test_existing_email(self):
+ user = create_user()
+ data = self.default_data.copy()
+ data['email'] = user.email
+ response = self.client.post('/register/', data)
+ self.assertEqual(response.status_code, 200)
+ self.assertFormError(
+ response, 'form', 'email',
+ 'This email address is already in use for the account '
+ '"%s".\n' % user.username)
+
+ def test_valid_registration(self):
+ response = self.client.post('/register/', self.default_data)
+ self.assertEqual(response.status_code, 200)
+ self.assertContains(response, 'confirmation email has been sent')
+
+ # check for presence of an inactive user object
+ users = User.objects.filter(username=self.user.username)
+ self.assertEqual(users.count(), 1)
+ user = users[0]
+ self.assertEqual(user.username, self.user.username)
+ self.assertEqual(user.email, self.user.email)
+ self.assertEqual(user.is_active, False)
+
+ # check for confirmation object
+ confs = EmailConfirmation.objects.filter(
+ user=user, type='registration')
+ self.assertEqual(len(confs), 1)
+ conf = confs[0]
+ self.assertEqual(conf.email, self.user.email)
+
+ # check for a sent mail
+ self.assertEqual(len(mail.outbox), 1)
+ msg = mail.outbox[0]
+ self.assertEqual(msg.subject, 'Patchwork account confirmation')
+ self.assertIn(self.user.email, msg.to)
+ self.assertIn(_confirmation_url(conf), msg.body)
+
+ # ...and that the URL is valid
+ response = self.client.get(_confirmation_url(conf))
+ self.assertEqual(response.status_code, 200)
+
+
+class RegistrationConfirmationTest(TestCase):
+
+ def setUp(self):
+ self.user = TestUser()
+ self.default_data = {
+ 'username': self.user.username,
+ 'first_name': self.user.firstname,
+ 'last_name': self.user.lastname,
+ 'email': self.user.email,
+ 'password': self.user.password
+ }
+
+ def test_valid(self):
+ """Test the success path."""
+ self.assertEqual(EmailConfirmation.objects.count(), 0)
+ response = self.client.post('/register/', self.default_data)
+ self.assertEqual(response.status_code, 200)
+ self.assertContains(response, 'confirmation email has been sent')
+
+ self.assertEqual(EmailConfirmation.objects.count(), 1)
+ conf = EmailConfirmation.objects.filter()[0]
+ self.assertFalse(conf.user.is_active)
+ self.assertTrue(conf.active)
+
+ response = self.client.get(_confirmation_url(conf))
+ self.assertEqual(response.status_code, 200)
+ self.assertTemplateUsed(
+ response, 'patchwork/registration-confirm.html')
+
+ conf = EmailConfirmation.objects.get(pk=conf.pk)
+ self.assertTrue(conf.user.is_active)
+ self.assertFalse(conf.active)
+
+ def test_new_person_setup(self):
+ """Ensure a new Person is created after account setup.
+
+ Create an account for a never before seen email. Check that a Person
+ object is created after registration and has the correct details.
+ """
+ # register
+ self.assertEqual(EmailConfirmation.objects.count(), 0)
+ response = self.client.post('/register/', self.default_data)
+ self.assertEqual(response.status_code, 200)
+ self.assertFalse(Person.objects.exists())
+
+ # confirm
+ conf = EmailConfirmation.objects.filter()[0]
+ response = self.client.get(_confirmation_url(conf))
+ self.assertEqual(response.status_code, 200)
+
+ qs = Person.objects.filter(email=self.user.email)
+ self.assertTrue(qs.exists())
+ person = Person.objects.get(email=self.user.email)
+
+ self.assertEqual(person.name, self.user.fullname)
+
+ def test_existing_person_setup(self):
+ """Ensure an existing person is linked after account setup.
+
+ Create an account for a user using an email we've previously seen.
+ Check that the person object is updated after registration with the
+ correct details.
+ """
+ person = Person(name=self.user.fullname, email=self.user.email)
+ person.save()
+
+ # register
+ self.assertEqual(EmailConfirmation.objects.count(), 0)
+ response = self.client.post('/register/', self.default_data)
+ self.assertEqual(response.status_code, 200)
+
+ # confirm
+ conf = EmailConfirmation.objects.filter()[0]
+ response = self.client.get(_confirmation_url(conf))
+ self.assertEqual(response.status_code, 200)
+
+ person = Person.objects.get(email=self.user.email)
+
+ self.assertEqual(person.name, self.user.fullname)
+
+ def test_existing_person_unmodified(self):
+ """Ensure an existing person is not linked until registration is done.
+
+ Create an account for a user using an email we've previously seen but
+ don't confirm it. Check that the person object is not updated yet.
+ """
+ person = Person(name=self.user.fullname, email=self.user.email)
+ person.save()
+
+ # register
+ data = self.default_data.copy()
+ data['first_name'] = 'invalid'
+ data['last_name'] = 'invalid'
+ self.assertEqual(data['email'], person.email)
+ response = self.client.post('/register/', data)
+ self.assertEqual(response.status_code, 200)
+
+ self.assertEqual(
+ Person.objects.get(pk=person.pk).name, self.user.fullname)
+
+
+class UserLinkTest(_UserTestCase):
+
+ def setUp(self):
+ super().setUp()
self.secondary_email = _generate_secondary_email(self.user)
def test_user_person_request_form(self):
self.assertTemplateUsed(response, 'patchwork/user-link-confirm.html')
-class UserPersonConfirmTest(TestCase):
+class ConfirmationTest(TestCase):
def setUp(self):
self.user = create_user(link_person=False)
self.assertEqual(conf.active, False)
-class UserLoginRedirectTest(TestCase):
+class InvalidConfirmationTest(TestCase):
+
+ def setUp(self):
+ self.user = create_user()
+ self.secondary_email = _generate_secondary_email(self.user)
+
+ self.conf = EmailConfirmation(type='userperson',
+ email=self.secondary_email,
+ user=self.user)
+ self.conf.save()
+
+ def test_inactive_confirmation(self):
+ self.conf.active = False
+ self.conf.save()
+ response = self.client.get(_confirmation_url(self.conf))
+ self.assertEqual(response.status_code, 200)
+ self.assertTemplateUsed(response, 'patchwork/confirm-error.html')
+ self.assertEqual(response.context['error'], 'inactive')
+ self.assertEqual(response.context['conf'], self.conf)
+
+ def test_expired_confirmation(self):
+ self.conf.date -= self.conf.validity
+ self.conf.save()
+ response = self.client.get(_confirmation_url(self.conf))
+ self.assertEqual(response.status_code, 200)
+ self.assertTemplateUsed(response, 'patchwork/confirm-error.html')
+ self.assertEqual(response.context['error'], 'expired')
+ self.assertEqual(response.context['conf'], self.conf)
+
+
+class LoginRedirectTest(TestCase):
def test_user_login_redirect(self):
url = reverse('user-profile')
self.assertEqual(user_profile.items_per_page, old_ppp)
-class UserPasswordChangeTest(_UserTestCase):
+class PasswordChangeTest(_UserTestCase):
def test_password_change_form(self):
response = self.client.get(reverse('password_change'))