diff options
author | Jeremy Kerr <jk@ozlabs.org> | 2015-05-24 16:57:33 +0800 |
---|---|---|
committer | Jeremy Kerr <jk@ozlabs.org> | 2015-05-27 10:26:41 +0800 |
commit | ad2762cf775a8dde508de47164d6429f3fd724f1 (patch) | |
tree | e63015a468cfe32c961908f0338d423227799815 /patchwork/tests/test_bundles.py | |
parent | f09e982f58384946111d4157fd2b7c2b31b78612 (diff) | |
download | patchwork-ad2762cf775a8dde508de47164d6429f3fd724f1.tar.bz2 patchwork-ad2762cf775a8dde508de47164d6429f3fd724f1.tar.xz |
Move to a more recent django project structure
This change updates patchwor to the newer project struture: we've moved
the actual application out of the apps/ directory, and the
patchwork-specific templates to under the patchwork application.
This gives us the manage.py script in the top-level now.
Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
Diffstat (limited to 'patchwork/tests/test_bundles.py')
-rw-r--r-- | patchwork/tests/test_bundles.py | 646 |
1 files changed, 646 insertions, 0 deletions
diff --git a/patchwork/tests/test_bundles.py b/patchwork/tests/test_bundles.py new file mode 100644 index 0000000..38f3a2c --- /dev/null +++ b/patchwork/tests/test_bundles.py @@ -0,0 +1,646 @@ +# Patchwork - automated patch tracking system +# Copyright (C) 2009 Jeremy Kerr <jk@ozlabs.org> +# +# This file is part of the Patchwork package. +# +# Patchwork is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# Patchwork is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Patchwork; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import unittest +import datetime +from django.test import TestCase +from django.test.client import Client +from django.utils.http import urlencode +from django.conf import settings +from patchwork.models import Patch, Bundle, BundlePatch, Person +from patchwork.tests.utils import defaults, create_user, find_in_context + +def bundle_url(bundle): + return '/bundle/%s/%s/' % (bundle.owner.username, bundle.name) + +class BundleListTest(TestCase): + def setUp(self): + self.user = create_user() + self.client.login(username = self.user.username, + password = self.user.username) + + def testNoBundles(self): + response = self.client.get('/user/bundles/') + self.failUnlessEqual(response.status_code, 200) + self.failUnlessEqual( + len(find_in_context(response.context, 'bundles')), 0) + + def testSingleBundle(self): + defaults.project.save() + bundle = Bundle(owner = self.user, project = defaults.project) + bundle.save() + response = self.client.get('/user/bundles/') + self.failUnlessEqual(response.status_code, 200) + self.failUnlessEqual( + len(find_in_context(response.context, 'bundles')), 1) + + def tearDown(self): + self.user.delete() + +class BundleTestBase(TestCase): + def setUp(self, patch_count=3): + patch_names = ['testpatch%d' % (i) for i in range(1, patch_count+1)] + self.user = create_user() + self.client.login(username = self.user.username, + password = self.user.username) + defaults.project.save() + self.bundle = Bundle(owner = self.user, project = defaults.project, + name = 'testbundle') + self.bundle.save() + self.patches = [] + + for patch_name in patch_names: + patch = Patch(project = defaults.project, + msgid = patch_name, name = patch_name, + submitter = Person.objects.get(user = self.user), + content = '') + patch.save() + self.patches.append(patch) + + def tearDown(self): + for patch in self.patches: + patch.delete() + self.bundle.delete() + self.user.delete() + +class BundleViewTest(BundleTestBase): + + def testEmptyBundle(self): + response = self.client.get(bundle_url(self.bundle)) + self.failUnlessEqual(response.status_code, 200) + page = find_in_context(response.context, 'page') + self.failUnlessEqual(len(page.object_list), 0) + + def testNonEmptyBundle(self): + self.bundle.append_patch(self.patches[0]) + + response = self.client.get(bundle_url(self.bundle)) + self.failUnlessEqual(response.status_code, 200) + page = find_in_context(response.context, 'page') + self.failUnlessEqual(len(page.object_list), 1) + + def testBundleOrder(self): + for patch in self.patches: + self.bundle.append_patch(patch) + + response = self.client.get(bundle_url(self.bundle)) + + pos = 0 + for patch in self.patches: + next_pos = response.content.find(patch.name) + # ensure that this patch is after the previous + self.failUnless(next_pos > pos) + pos = next_pos + + # reorder and recheck + i = 0 + for patch in self.patches.__reversed__(): + bundlepatch = BundlePatch.objects.get(bundle = self.bundle, + patch = patch) + bundlepatch.order = i + bundlepatch.save() + i += 1 + + response = self.client.get(bundle_url(self.bundle)) + pos = len(response.content) + for patch in self.patches: + next_pos = response.content.find(patch.name) + # ensure that this patch is now *before* the previous + self.failUnless(next_pos < pos) + pos = next_pos + +class BundleUpdateTest(BundleTestBase): + + def setUp(self): + super(BundleUpdateTest, self).setUp() + self.newname = 'newbundlename' + + def checkPatchformErrors(self, response): + formname = 'patchform' + if not formname in response.context: + return + form = response.context[formname] + if not form: + return + self.assertEquals(form.errors, {}) + + def publicString(self, public): + if public: + return 'on' + return '' + + def testNoAction(self): + data = { + 'form': 'bundle', + 'name': self.newname, + 'public': self.publicString(not self.bundle.public) + } + response = self.client.post(bundle_url(self.bundle), data) + self.assertEqual(response.status_code, 200) + + bundle = Bundle.objects.get(pk = self.bundle.pk) + self.assertEqual(bundle.name, self.bundle.name) + self.assertEqual(bundle.public, self.bundle.public) + + def testUpdateName(self): + newname = 'newbundlename' + data = { + 'form': 'bundle', + 'action': 'update', + 'name': newname, + 'public': self.publicString(self.bundle.public) + } + response = self.client.post(bundle_url(self.bundle), data) + bundle = Bundle.objects.get(pk = self.bundle.pk) + self.assertRedirects(response, bundle_url(bundle)) + self.assertEqual(bundle.name, newname) + self.assertEqual(bundle.public, self.bundle.public) + + def testUpdatePublic(self): + newname = 'newbundlename' + data = { + 'form': 'bundle', + 'action': 'update', + 'name': self.bundle.name, + 'public': self.publicString(not self.bundle.public) + } + response = self.client.post(bundle_url(self.bundle), data) + self.assertEqual(response.status_code, 200) + bundle = Bundle.objects.get(pk = self.bundle.pk) + self.assertEqual(bundle.name, self.bundle.name) + self.assertEqual(bundle.public, not self.bundle.public) + + # check other forms for errors + self.checkPatchformErrors(response) + +class BundleMaintainerUpdateTest(BundleUpdateTest): + + def setUp(self): + super(BundleMaintainerUpdateTest, self).setUp() + profile = self.user.profile + profile.maintainer_projects.add(defaults.project) + profile.save() + +class BundlePublicViewTest(BundleTestBase): + + def setUp(self): + super(BundlePublicViewTest, self).setUp() + self.client.logout() + self.bundle.append_patch(self.patches[0]) + self.url = bundle_url(self.bundle) + + def testPublicBundle(self): + self.bundle.public = True + self.bundle.save() + response = self.client.get(self.url) + self.assertEqual(response.status_code, 200) + self.assertContains(response, self.patches[0].name) + + def testPrivateBundle(self): + self.bundle.public = False + self.bundle.save() + response = self.client.get(self.url) + self.assertEqual(response.status_code, 404) + +class BundlePublicViewMboxTest(BundlePublicViewTest): + def setUp(self): + super(BundlePublicViewMboxTest, self).setUp() + self.url = bundle_url(self.bundle) + "mbox/" + +class BundlePublicModifyTest(BundleTestBase): + """Ensure that non-owners can't modify bundles""" + + def setUp(self): + super(BundlePublicModifyTest, self).setUp() + self.bundle.public = True + self.bundle.save() + self.other_user = create_user() + + def testBundleFormPresence(self): + """Check for presence of the modify form on the bundle""" + self.client.login(username = self.other_user.username, + password = self.other_user.username) + response = self.client.get(bundle_url(self.bundle)) + self.assertNotContains(response, 'name="form" value="bundle"') + self.assertNotContains(response, 'Change order') + + def testBundleFormSubmission(self): + oldname = 'oldbundlename' + newname = 'newbundlename' + data = { + 'form': 'bundle', + 'action': 'update', + 'name': newname, + } + self.bundle.name = oldname + self.bundle.save() + + # first, check that we can modify with the owner + self.client.login(username = self.user.username, + password = self.user.username) + response = self.client.post(bundle_url(self.bundle), data) + self.bundle = Bundle.objects.get(pk = self.bundle.pk) + self.assertEqual(self.bundle.name, newname) + + # reset bundle name + self.bundle.name = oldname + self.bundle.save() + + # log in with a different user, and check that we can no longer modify + self.client.login(username = self.other_user.username, + password = self.other_user.username) + response = self.client.post(bundle_url(self.bundle), data) + self.bundle = Bundle.objects.get(pk = self.bundle.pk) + self.assertNotEqual(self.bundle.name, newname) + +class BundleCreateFromListTest(BundleTestBase): + def testCreateEmptyBundle(self): + newbundlename = 'testbundle-new' + params = {'form': 'patchlistform', + 'bundle_name': newbundlename, + 'action': 'Create', + 'project': defaults.project.id} + + response = self.client.post( + '/project/%s/list/' % defaults.project.linkname, + params) + + self.assertContains(response, 'Bundle %s created' % newbundlename) + + def testCreateNonEmptyBundle(self): + newbundlename = 'testbundle-new' + patch = self.patches[0] + + params = {'form': 'patchlistform', + 'bundle_name': newbundlename, + 'action': 'Create', + 'project': defaults.project.id, + 'patch_id:%d' % patch.id: 'checked'} + + response = self.client.post( + '/project/%s/list/' % defaults.project.linkname, + params) + + self.assertContains(response, 'Bundle %s created' % newbundlename) + self.assertContains(response, 'added to bundle %s' % newbundlename, + count = 1) + + bundle = Bundle.objects.get(name = newbundlename) + self.failUnlessEqual(bundle.patches.count(), 1) + self.failUnlessEqual(bundle.patches.all()[0], patch) + + def testCreateNonEmptyBundleEmptyName(self): + newbundlename = 'testbundle-new' + patch = self.patches[0] + + n_bundles = Bundle.objects.count() + + params = {'form': 'patchlistform', + 'bundle_name': '', + 'action': 'Create', + 'project': defaults.project.id, + 'patch_id:%d' % patch.id: 'checked'} + + response = self.client.post( + '/project/%s/list/' % defaults.project.linkname, + params) + + self.assertContains(response, 'No bundle name was specified', + status_code = 200) + + # test that no new bundles are present + self.failUnlessEqual(n_bundles, Bundle.objects.count()) + + def testCreateDuplicateName(self): + newbundlename = 'testbundle-dup' + patch = self.patches[0] + + params = {'form': 'patchlistform', + 'bundle_name': newbundlename, + 'action': 'Create', + 'project': defaults.project.id, + 'patch_id:%d' % patch.id: 'checked'} + + response = self.client.post( + '/project/%s/list/' % defaults.project.linkname, + params) + + n_bundles = Bundle.objects.count() + self.assertContains(response, 'Bundle %s created' % newbundlename) + self.assertContains(response, 'added to bundle %s' % newbundlename, + count = 1) + + bundle = Bundle.objects.get(name = newbundlename) + self.failUnlessEqual(bundle.patches.count(), 1) + self.failUnlessEqual(bundle.patches.all()[0], patch) + + response = self.client.post( + '/project/%s/list/' % defaults.project.linkname, + params) + + self.assertNotContains(response, 'Bundle %s created' % newbundlename) + self.assertContains(response, 'You already have a bundle called') + self.assertEqual(Bundle.objects.count(), n_bundles) + self.assertEqual(bundle.patches.count(), 1) + +class BundleCreateFromPatchTest(BundleTestBase): + def testCreateNonEmptyBundle(self): + newbundlename = 'testbundle-new' + patch = self.patches[0] + + params = {'name': newbundlename, + 'action': 'createbundle'} + + response = self.client.post('/patch/%d/' % patch.id, params) + + self.assertContains(response, + 'Bundle %s created' % newbundlename) + + bundle = Bundle.objects.get(name = newbundlename) + self.failUnlessEqual(bundle.patches.count(), 1) + self.failUnlessEqual(bundle.patches.all()[0], patch) + + def testCreateWithExistingName(self): + newbundlename = self.bundle.name + patch = self.patches[0] + + params = {'name': newbundlename, + 'action': 'createbundle'} + + response = self.client.post('/patch/%d/' % patch.id, params) + + self.assertContains(response, + 'A bundle called %s already exists' % newbundlename) + + count = Bundle.objects.count() + self.failUnlessEqual(Bundle.objects.count(), 1) + +class BundleAddFromListTest(BundleTestBase): + def testAddToEmptyBundle(self): + patch = self.patches[0] + params = {'form': 'patchlistform', + 'action': 'Add', + 'project': defaults.project.id, + 'bundle_id': self.bundle.id, + 'patch_id:%d' % patch.id: 'checked'} + + response = self.client.post( + '/project/%s/list/' % defaults.project.linkname, + params) + + self.assertContains(response, 'added to bundle %s' % self.bundle.name, + count = 1) + + self.failUnlessEqual(self.bundle.patches.count(), 1) + self.failUnlessEqual(self.bundle.patches.all()[0], patch) + + def testAddToNonEmptyBundle(self): + self.bundle.append_patch(self.patches[0]) + patch = self.patches[1] + params = {'form': 'patchlistform', + 'action': 'Add', + 'project': defaults.project.id, + 'bundle_id': self.bundle.id, + 'patch_id:%d' % patch.id: 'checked'} + + response = self.client.post( + '/project/%s/list/' % defaults.project.linkname, + params) + + self.assertContains(response, 'added to bundle %s' % self.bundle.name, + count = 1) + + self.failUnlessEqual(self.bundle.patches.count(), 2) + self.failUnless(self.patches[0] in self.bundle.patches.all()) + self.failUnless(self.patches[1] in self.bundle.patches.all()) + + # check order + bps = [ BundlePatch.objects.get(bundle = self.bundle, + patch = self.patches[i]) \ + for i in [0, 1] ] + self.failUnless(bps[0].order < bps[1].order) + + def testAddDuplicate(self): + self.bundle.append_patch(self.patches[0]) + count = self.bundle.patches.count() + patch = self.patches[0] + + params = {'form': 'patchlistform', + 'action': 'Add', + 'project': defaults.project.id, + 'bundle_id': self.bundle.id, + 'patch_id:%d' % patch.id: 'checked'} + + response = self.client.post( + '/project/%s/list/' % defaults.project.linkname, + params) + + self.assertContains(response, 'Patch '%s' already in bundle' \ + % patch.name, count = 1, status_code = 200) + + self.assertEquals(count, self.bundle.patches.count()) + + def testAddNewAndDuplicate(self): + self.bundle.append_patch(self.patches[0]) + count = self.bundle.patches.count() + patch = self.patches[0] + + params = {'form': 'patchlistform', + 'action': 'Add', + 'project': defaults.project.id, + 'bundle_id': self.bundle.id, + 'patch_id:%d' % patch.id: 'checked', + 'patch_id:%d' % self.patches[1].id: 'checked'} + + response = self.client.post( + '/project/%s/list/' % defaults.project.linkname, + params) + + self.assertContains(response, 'Patch '%s' already in bundle' \ + % patch.name, count = 1, status_code = 200) + self.assertContains(response, 'Patch '%s' added to bundle' \ + % self.patches[1].name, count = 1, + status_code = 200) + self.assertEquals(count + 1, self.bundle.patches.count()) + +class BundleAddFromPatchTest(BundleTestBase): + def testAddToEmptyBundle(self): + patch = self.patches[0] + params = {'action': 'addtobundle', + 'bundle_id': self.bundle.id} + + response = self.client.post('/patch/%d/' % patch.id, params) + + self.assertContains(response, + 'added to bundle "%s"' % self.bundle.name, + count = 1) + + self.failUnlessEqual(self.bundle.patches.count(), 1) + self.failUnlessEqual(self.bundle.patches.all()[0], patch) + + def testAddToNonEmptyBundle(self): + self.bundle.append_patch(self.patches[0]) + patch = self.patches[1] + params = {'action': 'addtobundle', + 'bundle_id': self.bundle.id} + + response = self.client.post('/patch/%d/' % patch.id, params) + + self.assertContains(response, + 'added to bundle "%s"' % self.bundle.name, + count = 1) + + self.failUnlessEqual(self.bundle.patches.count(), 2) + self.failUnless(self.patches[0] in self.bundle.patches.all()) + self.failUnless(self.patches[1] in self.bundle.patches.all()) + + # check order + bps = [ BundlePatch.objects.get(bundle = self.bundle, + patch = self.patches[i]) \ + for i in [0, 1] ] + self.failUnless(bps[0].order < bps[1].order) + +class BundleInitialOrderTest(BundleTestBase): + """When creating bundles from a patch list, ensure that the patches in the + bundle are ordered by date""" + + def setUp(self): + super(BundleInitialOrderTest, self).setUp(5) + + # put patches in an arbitrary order + idxs = [2, 4, 3, 1, 0] + self.patches = [ self.patches[i] for i in idxs ] + + # set dates to be sequential + last_patch = self.patches[0] + for patch in self.patches[1:]: + patch.date = last_patch.date + datetime.timedelta(0, 1) + patch.save() + last_patch = patch + + def _testOrder(self, ids, expected_order): + newbundlename = 'testbundle-new' + + # need to define our querystring explicity to enforce ordering + params = {'form': 'patchlistform', + 'bundle_name': newbundlename, + 'action': 'Create', + 'project': defaults.project.id, + } + + data = urlencode(params) + \ + ''.join([ '&patch_id:%d=checked' % i for i in ids ]) + + response = self.client.post( + '/project/%s/list/' % defaults.project.linkname, + data = data, + content_type = 'application/x-www-form-urlencoded', + ) + + self.assertContains(response, 'Bundle %s created' % newbundlename) + self.assertContains(response, 'added to bundle %s' % newbundlename, + count = 5) + + bundle = Bundle.objects.get(name = newbundlename) + + # BundlePatches should be sorted by .order by default + bps = BundlePatch.objects.filter(bundle = bundle) + + for (bp, p) in zip(bps, expected_order): + self.assertEqual(bp.patch.pk, p.pk) + + bundle.delete() + + def testBundleForwardOrder(self): + ids = map(lambda p: p.id, self.patches) + self._testOrder(ids, self.patches) + + def testBundleReverseOrder(self): + ids = map(lambda p: p.id, self.patches) + ids.reverse() + self._testOrder(ids, self.patches) + +class BundleReorderTest(BundleTestBase): + def setUp(self): + super(BundleReorderTest, self).setUp(5) + for i in range(5): + self.bundle.append_patch(self.patches[i]) + + def checkReordering(self, neworder, start, end): + neworder_ids = [ self.patches[i].id for i in neworder ] + + firstpatch = BundlePatch.objects.get(bundle = self.bundle, + patch = self.patches[start]).patch + + slice_ids = neworder_ids[start:end] + params = {'form': 'reorderform', + 'order_start': firstpatch.id, + 'neworder': slice_ids} + + response = self.client.post(bundle_url(self.bundle), params) + + self.failUnlessEqual(response.status_code, 200) + + bps = BundlePatch.objects.filter(bundle = self.bundle) \ + .order_by('order') + + # check if patch IDs are in the expected order: + bundle_ids = [ bp.patch.id for bp in bps ] + self.failUnlessEqual(neworder_ids, bundle_ids) + + # check if order field is still sequential: + order_numbers = [ bp.order for bp in bps ] + expected_order = range(1, len(neworder)+1) # [1 ... len(neworder)] + self.failUnlessEqual(order_numbers, expected_order) + + def testBundleReorderAll(self): + # reorder all patches: + self.checkReordering([2,1,4,0,3], 0, 5) + + def testBundleReorderEnd(self): + # reorder only the last three patches + self.checkReordering([0,1,3,2,4], 2, 5) + + def testBundleReorderBegin(self): + # reorder only the first three patches + self.checkReordering([2,0,1,3,4], 0, 3) + + def testBundleReorderMiddle(self): + # reorder only 2nd, 3rd, and 4th patches + self.checkReordering([0,2,3,1,4], 1, 4) + +class BundleRedirTest(BundleTestBase): + # old URL: private bundles used to be under /user/bundle/<id> + + def setUp(self): + super(BundleRedirTest, self).setUp() + + @unittest.skipIf(not settings.COMPAT_REDIR, "compat redirections disabled") + def testBundleRedir(self): + url = '/user/bundle/%d/' % self.bundle.id + response = self.client.get(url) + self.assertRedirects(response, bundle_url(self.bundle)) + + @unittest.skipIf(not settings.COMPAT_REDIR, "compat redirections disabled") + def testMboxRedir(self): + url = '/user/bundle/%d/mbox/' % self.bundle.id + response = self.client.get(url) + self.assertRedirects(response,'/bundle/%s/%s/mbox/' % + (self.bundle.owner.username, + self.bundle.name)) |