From: Stephen Finucane Date: Sat, 6 Mar 2021 15:12:00 +0000 (+0000) Subject: tests: Move view tests to their own directory X-Git-Tag: v3.1.0~92 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=2d3b3477bf4e3300d3d12e3650b31b0b6845ab26;p=thirdparty%2Fpatchwork.git tests: Move view tests to their own directory This lets our unit tests mirror the main code structure and highlights gaps in coverage. Signed-off-by: Stephen Finucane --- diff --git a/patchwork/tests/test_confirm.py b/patchwork/tests/test_confirm.py deleted file mode 100644 index 213e0f4d..00000000 --- a/patchwork/tests/test_confirm.py +++ /dev/null @@ -1,48 +0,0 @@ -# Patchwork - automated patch tracking system -# Copyright (C) 2011 Jeremy Kerr -# -# 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) diff --git a/patchwork/tests/test_detail.py b/patchwork/tests/test_detail.py deleted file mode 100644 index 5add40f9..00000000 --- a/patchwork/tests/test_detail.py +++ /dev/null @@ -1,229 +0,0 @@ -# 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 = 'blahTESTblah' - 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('TEST'.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, '

Checks

') - - # and it should only show the unique checks - self.assertEqual( - 1, response.content.decode().count( - f'{check_a.user}/{check_a.context}' - )) - self.assertEqual( - 1, response.content.decode().count( - f'{check_b.user}/{check_b.context}' - )) - - -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) diff --git a/patchwork/tests/test_encodings.py b/patchwork/tests/test_encodings.py deleted file mode 100644 index be9e6c32..00000000 --- a/patchwork/tests/test_encodings.py +++ /dev/null @@ -1,46 +0,0 @@ -# Patchwork - automated patch tracking system -# Copyright (C) 2008 Jeremy Kerr -# -# 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) diff --git a/patchwork/tests/test_filters.py b/patchwork/tests/test_filters.py deleted file mode 100644 index a69c4f85..00000000 --- a/patchwork/tests/test_filters.py +++ /dev/null @@ -1,36 +0,0 @@ -# Patchwork - automated patch tracking system -# Copyright (C) 2011 Jeremy Kerr -# -# 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) diff --git a/patchwork/tests/test_list.py b/patchwork/tests/test_list.py deleted file mode 100644 index c11a992c..00000000 --- a/patchwork/tests/test_list.py +++ /dev/null @@ -1,130 +0,0 @@ -# Patchwork - automated patch tracking system -# Copyright (C) 2012 Jeremy Kerr -# -# 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' -# -# 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) diff --git a/patchwork/tests/test_events.py b/patchwork/tests/test_signals.py similarity index 100% rename from patchwork/tests/test_events.py rename to patchwork/tests/test_signals.py diff --git a/patchwork/tests/test_updates.py b/patchwork/tests/test_updates.py deleted file mode 100644 index a554e38b..00000000 --- a/patchwork/tests/test_updates.py +++ /dev/null @@ -1,125 +0,0 @@ -# Patchwork - automated patch tracking system -# Copyright (C) 2010 Jeremy Kerr -# -# 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) diff --git a/patchwork/tests/views/__init__.py b/patchwork/tests/views/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/patchwork/tests/test_about.py b/patchwork/tests/views/test_about.py similarity index 100% rename from patchwork/tests/test_about.py rename to patchwork/tests/views/test_about.py diff --git a/patchwork/tests/test_completion.py b/patchwork/tests/views/test_api.py similarity index 100% rename from patchwork/tests/test_completion.py rename to patchwork/tests/views/test_api.py diff --git a/patchwork/tests/test_bundles.py b/patchwork/tests/views/test_bundles.py similarity index 100% rename from patchwork/tests/test_bundles.py rename to patchwork/tests/views/test_bundles.py diff --git a/patchwork/tests/views/test_cover.py b/patchwork/tests/views/test_cover.py new file mode 100644 index 00000000..6dc65bb7 --- /dev/null +++ b/patchwork/tests/views/test_cover.py @@ -0,0 +1,86 @@ +# 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) diff --git a/patchwork/tests/test_mail_settings.py b/patchwork/tests/views/test_mail.py similarity index 100% rename from patchwork/tests/test_mail_settings.py rename to patchwork/tests/views/test_mail.py diff --git a/patchwork/tests/views/test_patch.py b/patchwork/tests/views/test_patch.py new file mode 100644 index 00000000..1a1243cf --- /dev/null +++ b/patchwork/tests/views/test_patch.py @@ -0,0 +1,448 @@ +# Patchwork - automated patch tracking system +# Copyright (C) 2012 Jeremy Kerr +# +# 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'' + 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('TEST'.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, '

Checks

') + + # and it should only show the unique checks + self.assertEqual( + 1, response.content.decode().count( + f'{check_a.user}/{check_a.context}' + )) + self.assertEqual( + 1, response.content.decode().count( + f'{check_b.user}/{check_b.context}' + )) + + +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) diff --git a/patchwork/tests/test_projects.py b/patchwork/tests/views/test_projects.py similarity index 100% rename from patchwork/tests/test_projects.py rename to patchwork/tests/views/test_projects.py diff --git a/patchwork/tests/test_user.py b/patchwork/tests/views/test_user.py similarity index 50% rename from patchwork/tests/test_user.py rename to patchwork/tests/views/test_user.py index b476dbf1..22bb9839 100644 --- a/patchwork/tests/test_user.py +++ b/patchwork/tests/views/test_user.py @@ -5,16 +5,17 @@ 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): @@ -37,10 +38,208 @@ class _UserTestCase(TestCase): 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): @@ -88,7 +287,7 @@ class UserPersonRequestTest(_UserTestCase): self.assertTemplateUsed(response, 'patchwork/user-link-confirm.html') -class UserPersonConfirmTest(TestCase): +class ConfirmationTest(TestCase): def setUp(self): self.user = create_user(link_person=False) @@ -122,7 +321,37 @@ class UserPersonConfirmTest(TestCase): 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') @@ -178,7 +407,7 @@ class UserProfileTest(_UserTestCase): 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')) diff --git a/patchwork/tests/test_mboxviews.py b/patchwork/tests/views/test_utils.py similarity index 100% rename from patchwork/tests/test_mboxviews.py rename to patchwork/tests/views/test_utils.py