]> git.ozlabs.org Git - patchwork/blob - apps/patchwork/tests/bundles.py
views: use id__in = get_patch_ids() to get the modified patch set
[patchwork] / apps / patchwork / tests / bundles.py
1 # Patchwork - automated patch tracking system
2 # Copyright (C) 2009 Jeremy Kerr <jk@ozlabs.org>
3 #
4 # This file is part of the Patchwork package.
5 #
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.
10 #
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.
15 #
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
19
20 import unittest
21 import datetime
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
27
28 class BundleListTest(TestCase):
29     def setUp(self):
30         self.user = create_user()
31         self.client.login(username = self.user.username,
32                 password = self.user.username)
33
34     def testNoBundles(self):
35         response = self.client.get('/user/bundles/')
36         self.failUnlessEqual(response.status_code, 200)
37         self.failUnlessEqual(
38                 len(find_in_context(response.context, 'bundles')), 0)
39
40     def testSingleBundle(self):
41         defaults.project.save()
42         bundle = Bundle(owner = self.user, project = defaults.project)
43         bundle.save()
44         response = self.client.get('/user/bundles/')
45         self.failUnlessEqual(response.status_code, 200)
46         self.failUnlessEqual(
47                 len(find_in_context(response.context, 'bundles')), 1)
48
49     def tearDown(self):
50         self.user.delete()
51
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,
60                 name = 'testbundle')
61         self.bundle.save()
62         self.patches = []
63
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),
68                                content = '')
69             patch.save()
70             self.patches.append(patch)
71
72     def tearDown(self):
73         for patch in self.patches:
74             patch.delete()
75         self.bundle.delete()
76         self.user.delete()
77
78 class BundleViewTest(BundleTestBase):
79
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)
85
86     def testNonEmptyBundle(self):
87         self.bundle.append_patch(self.patches[0])
88
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)
93
94     def testBundleOrder(self):
95         for patch in self.patches:
96             self.bundle.append_patch(patch)
97
98         response = self.client.get('/user/bundle/%d/' % self.bundle.id)
99
100         pos = 0
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)
105             pos = next_pos
106
107         # reorder and recheck
108         i = 0
109         for patch in self.patches.__reversed__():
110             bundlepatch = BundlePatch.objects.get(bundle = self.bundle,
111                     patch = patch)
112             bundlepatch.order = i
113             bundlepatch.save()
114             i += 1
115
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)
122             pos = next_pos
123
124 class BundleCreateFromListTest(BundleTestBase):
125     def testCreateEmptyBundle(self):
126         newbundlename = 'testbundle-new'
127         params = {'form': 'patchlistform',
128                   'bundle_name': newbundlename,
129                   'action': 'Create',
130                   'project': defaults.project.id}
131
132         response = self.client.post(
133                 '/project/%s/list/' % defaults.project.linkname,
134                 params)
135
136         self.assertContains(response, 'Bundle %s created' % newbundlename)
137
138     def testCreateNonEmptyBundle(self):
139         newbundlename = 'testbundle-new'
140         patch = self.patches[0]
141
142         params = {'form': 'patchlistform',
143                   'bundle_name': newbundlename,
144                   'action': 'Create',
145                   'project': defaults.project.id,
146                   'patch_id:%d' % patch.id: 'checked'}
147
148         response = self.client.post(
149                 '/project/%s/list/' % defaults.project.linkname,
150                 params)
151
152         self.assertContains(response, 'Bundle %s created' % newbundlename)
153         self.assertContains(response, 'added to bundle %s' % newbundlename,
154             count = 1)
155
156         bundle = Bundle.objects.get(name = newbundlename)
157         self.failUnlessEqual(bundle.patches.count(), 1)
158         self.failUnlessEqual(bundle.patches.all()[0], patch)
159
160     def testCreateNonEmptyBundleEmptyName(self):
161         newbundlename = 'testbundle-new'
162         patch = self.patches[0]
163
164         n_bundles = Bundle.objects.count()
165
166         params = {'form': 'patchlistform',
167                   'bundle_name': '',
168                   'action': 'Create',
169                   'project': defaults.project.id,
170                   'patch_id:%d' % patch.id: 'checked'}
171
172         response = self.client.post(
173                 '/project/%s/list/' % defaults.project.linkname,
174                 params)
175
176         self.assertContains(response, 'No bundle name was specified',
177                 status_code = 200)
178
179         # test that no new bundles are present
180         self.failUnlessEqual(n_bundles, Bundle.objects.count())
181
182 class BundleCreateFromPatchTest(BundleTestBase):
183     def testCreateNonEmptyBundle(self):
184         newbundlename = 'testbundle-new'
185         patch = self.patches[0]
186
187         params = {'name': newbundlename,
188                   'action': 'createbundle'}
189
190         response = self.client.post('/patch/%d/' % patch.id, params)
191
192         self.assertContains(response,
193                 'Bundle %s created' % newbundlename)
194
195         bundle = Bundle.objects.get(name = newbundlename)
196         self.failUnlessEqual(bundle.patches.count(), 1)
197         self.failUnlessEqual(bundle.patches.all()[0], patch)
198
199     def testCreateWithExistingName(self):
200         newbundlename = self.bundle.name
201         patch = self.patches[0]
202
203         params = {'name': newbundlename,
204                   'action': 'createbundle'}
205
206         response = self.client.post('/patch/%d/' % patch.id, params)
207
208         self.assertContains(response,
209                 'A bundle called %s already exists' % newbundlename)
210
211         count = Bundle.objects.count()
212         self.failUnlessEqual(Bundle.objects.count(), 1)
213
214 class BundleAddFromListTest(BundleTestBase):
215     def testAddToEmptyBundle(self):
216         patch = self.patches[0]
217         params = {'form': 'patchlistform',
218                   'action': 'Add',
219                   'project': defaults.project.id,
220                   'bundle_id': self.bundle.id,
221                   'patch_id:%d' % patch.id: 'checked'}
222
223         response = self.client.post(
224                 '/project/%s/list/' % defaults.project.linkname,
225                 params)
226
227         self.assertContains(response, 'added to bundle %s' % self.bundle.name,
228             count = 1)
229
230         self.failUnlessEqual(self.bundle.patches.count(), 1)
231         self.failUnlessEqual(self.bundle.patches.all()[0], patch)
232
233     def testAddToNonEmptyBundle(self):
234         self.bundle.append_patch(self.patches[0])
235         patch = self.patches[1]
236         params = {'form': 'patchlistform',
237                   'action': 'Add',
238                   'project': defaults.project.id,
239                   'bundle_id': self.bundle.id,
240                   'patch_id:%d' % patch.id: 'checked'}
241
242         response = self.client.post(
243                 '/project/%s/list/' % defaults.project.linkname,
244                 params)
245
246         self.assertContains(response, 'added to bundle %s' % self.bundle.name,
247             count = 1)
248
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())
252
253         # check order
254         bps = [ BundlePatch.objects.get(bundle = self.bundle,
255                                         patch = self.patches[i]) \
256                 for i in [0, 1] ]
257         self.failUnless(bps[0].order < bps[1].order)
258
259     def testAddDuplicate(self):
260         self.bundle.append_patch(self.patches[0])
261         count = self.bundle.patches.count()
262         patch = self.patches[0]
263
264         params = {'form': 'patchlistform',
265                   'action': 'Add',
266                   'project': defaults.project.id,
267                   'bundle_id': self.bundle.id,
268                   'patch_id:%d' % patch.id: 'checked'}
269
270         response = self.client.post(
271                 '/project/%s/list/' % defaults.project.linkname,
272                 params)
273
274         self.assertContains(response, 'Patch &#39;%s&#39; already in bundle' \
275                             % patch.name, count = 1, status_code = 200)
276
277         self.assertEquals(count, self.bundle.patches.count())
278
279     def testAddNewAndDuplicate(self):
280         self.bundle.append_patch(self.patches[0])
281         count = self.bundle.patches.count()
282         patch = self.patches[0]
283
284         params = {'form': 'patchlistform',
285                   'action': 'Add',
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'}
290
291         response = self.client.post(
292                 '/project/%s/list/' % defaults.project.linkname,
293                 params)
294
295         self.assertContains(response, 'Patch &#39;%s&#39; already in bundle' \
296                             % patch.name, count = 1, status_code = 200)
297         self.assertContains(response, 'Patch &#39;%s&#39; added to bundle' \
298                             % self.patches[1].name, count = 1,
299                             status_code = 200)
300         self.assertEquals(count + 1, self.bundle.patches.count())
301
302 class BundleAddFromPatchTest(BundleTestBase):
303     def testAddToEmptyBundle(self):
304         patch = self.patches[0]
305         params = {'action': 'addtobundle',
306                   'bundle_id': self.bundle.id}
307
308         response = self.client.post('/patch/%d/' % patch.id, params)
309
310         self.assertContains(response,
311                 'added to bundle &quot;%s&quot;' % self.bundle.name,
312                 count = 1)
313
314         self.failUnlessEqual(self.bundle.patches.count(), 1)
315         self.failUnlessEqual(self.bundle.patches.all()[0], patch)
316
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}
322
323         response = self.client.post('/patch/%d/' % patch.id, params)
324
325         self.assertContains(response,
326                 'added to bundle &quot;%s&quot;' % self.bundle.name,
327                 count = 1)
328
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())
332
333         # check order
334         bps = [ BundlePatch.objects.get(bundle = self.bundle,
335                                         patch = self.patches[i]) \
336                 for i in [0, 1] ]
337         self.failUnless(bps[0].order < bps[1].order)
338
339 class BundleInitialOrderTest(BundleTestBase):
340     """When creating bundles from a patch list, ensure that the patches in the
341        bundle are ordered by date"""
342
343     def setUp(self):
344         super(BundleInitialOrderTest, self).setUp(5)
345
346         # put patches in an arbitrary order
347         idxs = [2, 4, 3, 1, 0]
348         self.patches = [ self.patches[i] for i in idxs ]
349
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)
354             patch.save()
355             last_patch = patch
356
357     def _testOrder(self, ids, expected_order):
358         newbundlename = 'testbundle-new'
359
360         # need to define our querystring explicity to enforce ordering
361         params = {'form': 'patchlistform',
362                   'bundle_name': newbundlename,
363                   'action': 'Create',
364                   'project': defaults.project.id,
365         }
366
367         data = urlencode(params) + \
368                ''.join([ '&patch_id:%d=checked' % i for i in ids ])
369
370         response = self.client.post(
371                 '/project/%s/list/' % defaults.project.linkname,
372                 data = data,
373                 content_type = 'application/x-www-form-urlencoded',
374                 )
375
376         self.assertContains(response, 'Bundle %s created' % newbundlename)
377         self.assertContains(response, 'added to bundle %s' % newbundlename,
378             count = 5)
379
380         bundle = Bundle.objects.get(name = newbundlename)
381
382         # BundlePatches should be sorted by .order by default
383         bps = BundlePatch.objects.filter(bundle = bundle)
384
385         for (bp, p) in zip(bps, expected_order):
386             self.assertEqual(bp.patch.pk, p.pk)
387
388         bundle.delete()
389
390     def testBundleForwardOrder(self):
391         ids = map(lambda p: p.id, self.patches)
392         self._testOrder(ids, self.patches)
393
394     def testBundleReverseOrder(self):
395         ids = map(lambda p: p.id, self.patches)
396         ids.reverse()
397         self._testOrder(ids, self.patches)
398
399 class BundleReorderTest(BundleTestBase):
400     def setUp(self):
401         super(BundleReorderTest, self).setUp(5)
402         for i in range(5):
403             self.bundle.append_patch(self.patches[i])
404
405     def checkReordering(self, neworder, start, end):
406         neworder_ids = [ self.patches[i].id for i in neworder ]
407
408         firstpatch = BundlePatch.objects.get(bundle = self.bundle,
409                 patch = self.patches[start]).patch
410
411         slice_ids = neworder_ids[start:end]
412         params = {'form': 'reorderform',
413                   'order_start': firstpatch.id,
414                   'neworder': slice_ids}
415
416         response = self.client.post('/user/bundle/%d/' % self.bundle.id,
417                                     params)
418
419         self.failUnlessEqual(response.status_code, 200)
420
421         bps = BundlePatch.objects.filter(bundle = self.bundle) \
422                         .order_by('order')
423
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)
427
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)
432
433     def testBundleReorderAll(self):
434         # reorder all patches:
435         self.checkReordering([2,1,4,0,3], 0, 5)
436
437     def testBundleReorderEnd(self):
438         # reorder only the last three patches
439         self.checkReordering([0,1,3,2,4], 2, 5)
440
441     def testBundleReorderBegin(self):
442         # reorder only the first three patches
443         self.checkReordering([2,0,1,3,4], 0, 3)
444
445     def testBundleReorderMiddle(self):
446         # reorder only 2nd, 3rd, and 4th patches
447         self.checkReordering([0,2,3,1,4], 1, 4)