1 # Patchwork - automated patch tracking system
2 # Copyright (C) 2009 Jeremy Kerr <jk@ozlabs.org>
4 # This file is part of the Patchwork package.
6 # Patchwork is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # Patchwork is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with Patchwork; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 from django.test import TestCase
23 from django.test.client import Client
24 from django.utils.http import urlencode
25 from patchwork.models import Patch, Bundle, BundlePatch, Person
26 from patchwork.tests.utils import defaults, create_user, find_in_context
28 class BundleListTest(TestCase):
30 self.user = create_user()
31 self.client.login(username = self.user.username,
32 password = self.user.username)
34 def testNoBundles(self):
35 response = self.client.get('/user/bundles/')
36 self.failUnlessEqual(response.status_code, 200)
38 len(find_in_context(response.context, 'bundles')), 0)
40 def testSingleBundle(self):
41 defaults.project.save()
42 bundle = Bundle(owner = self.user, project = defaults.project)
44 response = self.client.get('/user/bundles/')
45 self.failUnlessEqual(response.status_code, 200)
47 len(find_in_context(response.context, 'bundles')), 1)
52 class BundleTestBase(TestCase):
53 def setUp(self, patch_count=3):
54 patch_names = ['testpatch%d' % (i) for i in range(1, patch_count+1)]
55 self.user = create_user()
56 self.client.login(username = self.user.username,
57 password = self.user.username)
58 defaults.project.save()
59 self.bundle = Bundle(owner = self.user, project = defaults.project,
64 for patch_name in patch_names:
65 patch = Patch(project = defaults.project,
66 msgid = patch_name, name = patch_name,
67 submitter = Person.objects.get(user = self.user),
70 self.patches.append(patch)
73 for patch in self.patches:
78 class BundleViewTest(BundleTestBase):
80 def testEmptyBundle(self):
81 response = self.client.get('/user/bundle/%d/' % self.bundle.id)
82 self.failUnlessEqual(response.status_code, 200)
83 page = find_in_context(response.context, 'page')
84 self.failUnlessEqual(len(page.object_list), 0)
86 def testNonEmptyBundle(self):
87 self.bundle.append_patch(self.patches[0])
89 response = self.client.get('/user/bundle/%d/' % self.bundle.id)
90 self.failUnlessEqual(response.status_code, 200)
91 page = find_in_context(response.context, 'page')
92 self.failUnlessEqual(len(page.object_list), 1)
94 def testBundleOrder(self):
95 for patch in self.patches:
96 self.bundle.append_patch(patch)
98 response = self.client.get('/user/bundle/%d/' % self.bundle.id)
101 for patch in self.patches:
102 next_pos = response.content.find(patch.name)
103 # ensure that this patch is after the previous
104 self.failUnless(next_pos > pos)
107 # reorder and recheck
109 for patch in self.patches.__reversed__():
110 bundlepatch = BundlePatch.objects.get(bundle = self.bundle,
112 bundlepatch.order = i
116 response = self.client.get('/user/bundle/%d/' % self.bundle.id)
117 pos = len(response.content)
118 for patch in self.patches:
119 next_pos = response.content.find(patch.name)
120 # ensure that this patch is now *before* the previous
121 self.failUnless(next_pos < pos)
124 class BundleCreateFromListTest(BundleTestBase):
125 def testCreateEmptyBundle(self):
126 newbundlename = 'testbundle-new'
127 params = {'form': 'patchlistform',
128 'bundle_name': newbundlename,
130 'project': defaults.project.id}
132 response = self.client.post(
133 '/project/%s/list/' % defaults.project.linkname,
136 self.assertContains(response, 'Bundle %s created' % newbundlename)
138 def testCreateNonEmptyBundle(self):
139 newbundlename = 'testbundle-new'
140 patch = self.patches[0]
142 params = {'form': 'patchlistform',
143 'bundle_name': newbundlename,
145 'project': defaults.project.id,
146 'patch_id:%d' % patch.id: 'checked'}
148 response = self.client.post(
149 '/project/%s/list/' % defaults.project.linkname,
152 self.assertContains(response, 'Bundle %s created' % newbundlename)
153 self.assertContains(response, 'added to bundle %s' % newbundlename,
156 bundle = Bundle.objects.get(name = newbundlename)
157 self.failUnlessEqual(bundle.patches.count(), 1)
158 self.failUnlessEqual(bundle.patches.all()[0], patch)
160 def testCreateNonEmptyBundleEmptyName(self):
161 newbundlename = 'testbundle-new'
162 patch = self.patches[0]
164 n_bundles = Bundle.objects.count()
166 params = {'form': 'patchlistform',
169 'project': defaults.project.id,
170 'patch_id:%d' % patch.id: 'checked'}
172 response = self.client.post(
173 '/project/%s/list/' % defaults.project.linkname,
176 self.assertContains(response, 'No bundle name was specified',
179 # test that no new bundles are present
180 self.failUnlessEqual(n_bundles, Bundle.objects.count())
182 class BundleCreateFromPatchTest(BundleTestBase):
183 def testCreateNonEmptyBundle(self):
184 newbundlename = 'testbundle-new'
185 patch = self.patches[0]
187 params = {'name': newbundlename,
188 'action': 'createbundle'}
190 response = self.client.post('/patch/%d/' % patch.id, params)
192 self.assertContains(response,
193 'Bundle %s created' % newbundlename)
195 bundle = Bundle.objects.get(name = newbundlename)
196 self.failUnlessEqual(bundle.patches.count(), 1)
197 self.failUnlessEqual(bundle.patches.all()[0], patch)
199 def testCreateWithExistingName(self):
200 newbundlename = self.bundle.name
201 patch = self.patches[0]
203 params = {'name': newbundlename,
204 'action': 'createbundle'}
206 response = self.client.post('/patch/%d/' % patch.id, params)
208 self.assertContains(response,
209 'A bundle called %s already exists' % newbundlename)
211 count = Bundle.objects.count()
212 self.failUnlessEqual(Bundle.objects.count(), 1)
214 class BundleAddFromListTest(BundleTestBase):
215 def testAddToEmptyBundle(self):
216 patch = self.patches[0]
217 params = {'form': 'patchlistform',
219 'project': defaults.project.id,
220 'bundle_id': self.bundle.id,
221 'patch_id:%d' % patch.id: 'checked'}
223 response = self.client.post(
224 '/project/%s/list/' % defaults.project.linkname,
227 self.assertContains(response, 'added to bundle %s' % self.bundle.name,
230 self.failUnlessEqual(self.bundle.patches.count(), 1)
231 self.failUnlessEqual(self.bundle.patches.all()[0], patch)
233 def testAddToNonEmptyBundle(self):
234 self.bundle.append_patch(self.patches[0])
235 patch = self.patches[1]
236 params = {'form': 'patchlistform',
238 'project': defaults.project.id,
239 'bundle_id': self.bundle.id,
240 'patch_id:%d' % patch.id: 'checked'}
242 response = self.client.post(
243 '/project/%s/list/' % defaults.project.linkname,
246 self.assertContains(response, 'added to bundle %s' % self.bundle.name,
249 self.failUnlessEqual(self.bundle.patches.count(), 2)
250 self.failUnless(self.patches[0] in self.bundle.patches.all())
251 self.failUnless(self.patches[1] in self.bundle.patches.all())
254 bps = [ BundlePatch.objects.get(bundle = self.bundle,
255 patch = self.patches[i]) \
257 self.failUnless(bps[0].order < bps[1].order)
259 def testAddDuplicate(self):
260 self.bundle.append_patch(self.patches[0])
261 count = self.bundle.patches.count()
262 patch = self.patches[0]
264 params = {'form': 'patchlistform',
266 'project': defaults.project.id,
267 'bundle_id': self.bundle.id,
268 'patch_id:%d' % patch.id: 'checked'}
270 response = self.client.post(
271 '/project/%s/list/' % defaults.project.linkname,
274 self.assertContains(response, 'Patch '%s' already in bundle' \
275 % patch.name, count = 1, status_code = 200)
277 self.assertEquals(count, self.bundle.patches.count())
279 def testAddNewAndDuplicate(self):
280 self.bundle.append_patch(self.patches[0])
281 count = self.bundle.patches.count()
282 patch = self.patches[0]
284 params = {'form': 'patchlistform',
286 'project': defaults.project.id,
287 'bundle_id': self.bundle.id,
288 'patch_id:%d' % patch.id: 'checked',
289 'patch_id:%d' % self.patches[1].id: 'checked'}
291 response = self.client.post(
292 '/project/%s/list/' % defaults.project.linkname,
295 self.assertContains(response, 'Patch '%s' already in bundle' \
296 % patch.name, count = 1, status_code = 200)
297 self.assertContains(response, 'Patch '%s' added to bundle' \
298 % self.patches[1].name, count = 1,
300 self.assertEquals(count + 1, self.bundle.patches.count())
302 class BundleAddFromPatchTest(BundleTestBase):
303 def testAddToEmptyBundle(self):
304 patch = self.patches[0]
305 params = {'action': 'addtobundle',
306 'bundle_id': self.bundle.id}
308 response = self.client.post('/patch/%d/' % patch.id, params)
310 self.assertContains(response,
311 'added to bundle "%s"' % self.bundle.name,
314 self.failUnlessEqual(self.bundle.patches.count(), 1)
315 self.failUnlessEqual(self.bundle.patches.all()[0], patch)
317 def testAddToNonEmptyBundle(self):
318 self.bundle.append_patch(self.patches[0])
319 patch = self.patches[1]
320 params = {'action': 'addtobundle',
321 'bundle_id': self.bundle.id}
323 response = self.client.post('/patch/%d/' % patch.id, params)
325 self.assertContains(response,
326 'added to bundle "%s"' % self.bundle.name,
329 self.failUnlessEqual(self.bundle.patches.count(), 2)
330 self.failUnless(self.patches[0] in self.bundle.patches.all())
331 self.failUnless(self.patches[1] in self.bundle.patches.all())
334 bps = [ BundlePatch.objects.get(bundle = self.bundle,
335 patch = self.patches[i]) \
337 self.failUnless(bps[0].order < bps[1].order)
339 class BundleInitialOrderTest(BundleTestBase):
340 """When creating bundles from a patch list, ensure that the patches in the
341 bundle are ordered by date"""
344 super(BundleInitialOrderTest, self).setUp(5)
346 # put patches in an arbitrary order
347 idxs = [2, 4, 3, 1, 0]
348 self.patches = [ self.patches[i] for i in idxs ]
350 # set dates to be sequential
351 last_patch = self.patches[0]
352 for patch in self.patches[1:]:
353 patch.date = last_patch.date + datetime.timedelta(0, 1)
357 def _testOrder(self, ids, expected_order):
358 newbundlename = 'testbundle-new'
360 # need to define our querystring explicity to enforce ordering
361 params = {'form': 'patchlistform',
362 'bundle_name': newbundlename,
364 'project': defaults.project.id,
367 data = urlencode(params) + \
368 ''.join([ '&patch_id:%d=checked' % i for i in ids ])
370 response = self.client.post(
371 '/project/%s/list/' % defaults.project.linkname,
373 content_type = 'application/x-www-form-urlencoded',
376 self.assertContains(response, 'Bundle %s created' % newbundlename)
377 self.assertContains(response, 'added to bundle %s' % newbundlename,
380 bundle = Bundle.objects.get(name = newbundlename)
382 # BundlePatches should be sorted by .order by default
383 bps = BundlePatch.objects.filter(bundle = bundle)
385 for (bp, p) in zip(bps, expected_order):
386 self.assertEqual(bp.patch.pk, p.pk)
390 def testBundleForwardOrder(self):
391 ids = map(lambda p: p.id, self.patches)
392 self._testOrder(ids, self.patches)
394 def testBundleReverseOrder(self):
395 ids = map(lambda p: p.id, self.patches)
397 self._testOrder(ids, self.patches)
399 class BundleReorderTest(BundleTestBase):
401 super(BundleReorderTest, self).setUp(5)
403 self.bundle.append_patch(self.patches[i])
405 def checkReordering(self, neworder, start, end):
406 neworder_ids = [ self.patches[i].id for i in neworder ]
408 firstpatch = BundlePatch.objects.get(bundle = self.bundle,
409 patch = self.patches[start]).patch
411 slice_ids = neworder_ids[start:end]
412 params = {'form': 'reorderform',
413 'order_start': firstpatch.id,
414 'neworder': slice_ids}
416 response = self.client.post('/user/bundle/%d/' % self.bundle.id,
419 self.failUnlessEqual(response.status_code, 200)
421 bps = BundlePatch.objects.filter(bundle = self.bundle) \
424 # check if patch IDs are in the expected order:
425 bundle_ids = [ bp.patch.id for bp in bps ]
426 self.failUnlessEqual(neworder_ids, bundle_ids)
428 # check if order field is still sequential:
429 order_numbers = [ bp.order for bp in bps ]
430 expected_order = range(1, len(neworder)+1) # [1 ... len(neworder)]
431 self.failUnlessEqual(order_numbers, expected_order)
433 def testBundleReorderAll(self):
434 # reorder all patches:
435 self.checkReordering([2,1,4,0,3], 0, 5)
437 def testBundleReorderEnd(self):
438 # reorder only the last three patches
439 self.checkReordering([0,1,3,2,4], 2, 5)
441 def testBundleReorderBegin(self):
442 # reorder only the first three patches
443 self.checkReordering([2,0,1,3,4], 0, 3)
445 def testBundleReorderMiddle(self):
446 # reorder only 2nd, 3rd, and 4th patches
447 self.checkReordering([0,2,3,1,4], 1, 4)