Merge lp:~allenap/launchpad/checkwatches-bulk-reload-bug-572211 into lp:launchpad

Proposed by Gavin Panella
Status: Merged
Approved by: Gavin Panella
Approved revision: no longer in the source branch.
Merged at revision: 10892
Proposed branch: lp:~allenap/launchpad/checkwatches-bulk-reload-bug-572211
Merge into: lp:launchpad
Prerequisite: lp:~allenap/launchpad/storm-bulk-reload-bug-572211
Diff against target: 668 lines (+594/-4)
3 files modified
lib/lp/bugs/scripts/checkwatches/core.py (+5/-0)
lib/lp/bugs/scripts/tests/test_bugimport.py (+9/-4)
lib/lp/code/model/tests/test_sourcepackagerecipe.py (+580/-0)
To merge this branch: bzr merge lp:~allenap/launchpad/checkwatches-bulk-reload-bug-572211
Reviewer Review Type Date Requested Status
Abel Deuring (community) code Approve
Review via email: mp+24493@code.launchpad.net

Commit message

Use bulk.reload() to improve the performance of checkwatches.

Description of the change

This uses the new bulk.reload() method to improve the performance of checkwatches. See the linked bug and the merge proposal for the prerequisite branch for an explanation how.

To post a comment you must log in.
Revision history for this message
Abel Deuring (adeuring) :
review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/bugs/scripts/checkwatches/core.py'
--- lib/lp/bugs/scripts/checkwatches/core.py 2010-05-11 13:11:43 +0000
+++ lib/lp/bugs/scripts/checkwatches/core.py 2010-05-17 14:12:39 +0000
@@ -49,6 +49,7 @@
49from lp.bugs.scripts.checkwatches.remotebugupdater import RemoteBugUpdater49from lp.bugs.scripts.checkwatches.remotebugupdater import RemoteBugUpdater
50from lp.bugs.scripts.checkwatches.utilities import (50from lp.bugs.scripts.checkwatches.utilities import (
51 get_bugwatcherrortype_for_error)51 get_bugwatcherrortype_for_error)
52from lp.services.database.bulk import reload
52from lp.services.scripts.base import LaunchpadCronScript53from lp.services.scripts.base import LaunchpadCronScript
5354
5455
@@ -336,6 +337,7 @@
336 other_watches = []337 other_watches = []
337338
338 with self.transaction:339 with self.transaction:
340 reload(bug_watches)
339 remote_bug_ids = [341 remote_bug_ids = [
340 bug_watch.remotebug for bug_watch in bug_watches]342 bug_watch.remotebug for bug_watch in bug_watches]
341343
@@ -344,6 +346,7 @@
344 remote_bug_ids))346 remote_bug_ids))
345347
346 with self.transaction:348 with self.transaction:
349 reload(bug_watches)
347 for bug_watch in bug_watches:350 for bug_watch in bug_watches:
348 if (remote_products.get(bug_watch.remotebug) in351 if (remote_products.get(bug_watch.remotebug) in
349 self._syncable_gnome_products):352 self._syncable_gnome_products):
@@ -450,6 +453,7 @@
450 batch_size = remotesystem.batch_size453 batch_size = remotesystem.batch_size
451454
452 with self.transaction:455 with self.transaction:
456 reload(bug_watches)
453 old_bug_watches = set(457 old_bug_watches = set(
454 bug_watch for bug_watch in bug_watches458 bug_watch for bug_watch in bug_watches
455 if bug_watch.lastchecked is not None)459 if bug_watch.lastchecked is not None)
@@ -573,6 +577,7 @@
573 # Remove from the list of bug watches any watch whose remote ID577 # Remove from the list of bug watches any watch whose remote ID
574 # doesn't appear in the list of IDs to check.578 # doesn't appear in the list of IDs to check.
575 with self.transaction:579 with self.transaction:
580 reload(bug_watches)
576 for bug_watch in list(bug_watches):581 for bug_watch in list(bug_watches):
577 if bug_watch.remotebug not in remote_ids_to_check:582 if bug_watch.remotebug not in remote_ids_to_check:
578 bug_watches.remove(bug_watch)583 bug_watches.remove(bug_watch)
579584
=== modified file 'lib/lp/bugs/scripts/tests/test_bugimport.py'
--- lib/lp/bugs/scripts/tests/test_bugimport.py 2010-05-04 16:42:03 +0000
+++ lib/lp/bugs/scripts/tests/test_bugimport.py 2010-05-17 14:12:39 +0000
@@ -17,10 +17,10 @@
1717
18from canonical.config import config18from canonical.config import config
19from canonical.database.sqlbase import cursor19from canonical.database.sqlbase import cursor
20from lp.bugs.externalbugtracker import (
21 ExternalBugTracker)
22from canonical.launchpad.database import BugNotification20from canonical.launchpad.database import BugNotification
23from canonical.launchpad.interfaces.emailaddress import IEmailAddressSet21from canonical.launchpad.interfaces.emailaddress import IEmailAddressSet
22
23from lp.bugs.externalbugtracker import ExternalBugTracker
24from lp.bugs.interfaces.bug import CreateBugParams, IBugSet24from lp.bugs.interfaces.bug import CreateBugParams, IBugSet
25from lp.bugs.interfaces.bugattachment import BugAttachmentType25from lp.bugs.interfaces.bugattachment import BugAttachmentType
26from lp.bugs.interfaces.bugtask import BugTaskImportance, BugTaskStatus26from lp.bugs.interfaces.bugtask import BugTaskImportance, BugTaskStatus
@@ -29,7 +29,7 @@
29from lp.bugs.interfaces.externalbugtracker import UNKNOWN_REMOTE_IMPORTANCE29from lp.bugs.interfaces.externalbugtracker import UNKNOWN_REMOTE_IMPORTANCE
30from lp.bugs.scripts import bugimport30from lp.bugs.scripts import bugimport
31from lp.bugs.scripts.bugimport import ET31from lp.bugs.scripts.bugimport import ET
32from lp.bugs.scripts.checkwatches import CheckwatchesMaster32from lp.bugs.scripts.checkwatches import CheckwatchesMaster, core
33from lp.bugs.scripts.checkwatches.remotebugupdater import RemoteBugUpdater33from lp.bugs.scripts.checkwatches.remotebugupdater import RemoteBugUpdater
34from lp.registry.interfaces.person import IPersonSet, PersonCreationRationale34from lp.registry.interfaces.person import IPersonSet, PersonCreationRationale
35from lp.registry.interfaces.product import IProductSet35from lp.registry.interfaces.product import IProductSet
@@ -923,7 +923,12 @@
923 def _updateBugTracker(self, bug_tracker):923 def _updateBugTracker(self, bug_tracker):
924 # Save the current bug tracker, so _getBugWatch can reference it.924 # Save the current bug tracker, so _getBugWatch can reference it.
925 self.bugtracker = bug_tracker925 self.bugtracker = bug_tracker
926 super(TestCheckwatchesMaster, self)._updateBugTracker(bug_tracker)926 reload = core.reload
927 try:
928 core.reload = lambda objects: objects
929 super(TestCheckwatchesMaster, self)._updateBugTracker(bug_tracker)
930 finally:
931 core.reload = reload
927932
928 def _getExternalBugTrackersAndWatches(self, bug_tracker, bug_watches):933 def _getExternalBugTrackersAndWatches(self, bug_tracker, bug_watches):
929 """See `CheckwatchesMaster`."""934 """See `CheckwatchesMaster`."""
930935
=== added file 'lib/lp/code/model/tests/test_sourcepackagerecipe.py'
--- lib/lp/code/model/tests/test_sourcepackagerecipe.py 1970-01-01 00:00:00 +0000
+++ lib/lp/code/model/tests/test_sourcepackagerecipe.py 2010-05-11 14:09:44 +0000
@@ -0,0 +1,580 @@
1# Copyright 2009, 2010 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).
3
4"""Tests for the SourcePackageRecipe content type."""
5
6from __future__ import with_statement
7
8__metaclass__ = type
9
10from datetime import datetime
11import textwrap
12import unittest
13
14from bzrlib.plugins.builder.recipe import RecipeParser
15
16from pytz import UTC
17from storm.locals import Store
18
19import transaction
20from zope.component import getUtility
21from zope.security.interfaces import Unauthorized
22from zope.security.proxy import removeSecurityProxy
23
24from canonical.testing.layers import DatabaseFunctionalLayer, AppServerLayer
25
26from canonical.launchpad.webapp.authorization import check_permission
27from lp.soyuz.interfaces.archive import (
28 ArchiveDisabled, ArchivePurpose, CannotUploadToArchive, InvalidPocketForPPA)
29from lp.buildmaster.interfaces.buildqueue import IBuildQueue
30from lp.buildmaster.model.buildqueue import BuildQueue
31from lp.code.interfaces.sourcepackagerecipe import (
32 ForbiddenInstruction, ISourcePackageRecipe, ISourcePackageRecipeSource,
33 TooNewRecipeFormat, MINIMAL_RECIPE_TEXT)
34from lp.code.interfaces.sourcepackagerecipebuild import (
35 ISourcePackageRecipeBuild, ISourcePackageRecipeBuildJob)
36from lp.code.model.sourcepackagerecipebuild import (
37 SourcePackageRecipeBuildJob)
38from lp.code.model.sourcepackagerecipe import (
39 NonPPABuildRequest)
40from lp.registry.interfaces.pocket import PackagePublishingPocket
41from lp.services.job.interfaces.job import (
42 IJob, JobStatus)
43from lp.testing import (
44 ANONYMOUS, launchpadlib_for, login, login_person, person_logged_in,
45 TestCaseWithFactory, ws_object)
46
47
48class TestSourcePackageRecipe(TestCaseWithFactory):
49 """Tests for `SourcePackageRecipe` objects."""
50
51 layer = DatabaseFunctionalLayer
52
53 def makeSourcePackageRecipeFromBuilderRecipe(self, builder_recipe):
54 """Make a SourcePackageRecipe from a recipe with arbitrary other data.
55 """
56 registrant = self.factory.makePerson()
57 owner = self.factory.makeTeam(owner=registrant)
58 distroseries = self.factory.makeDistroSeries()
59 sourcepackagename = self.factory.makeSourcePackageName()
60 name = self.factory.getUniqueString(u'recipe-name')
61 description = self.factory.getUniqueString(u'recipe-description')
62 return getUtility(ISourcePackageRecipeSource).new(
63 registrant=registrant, owner=owner, distroseries=[distroseries],
64 sourcepackagename=sourcepackagename, name=name,
65 description=description, builder_recipe=builder_recipe)
66
67 def test_creation(self):
68 # The metadata supplied when a SourcePackageRecipe is created is
69 # present on the new object.
70 registrant = self.factory.makePerson()
71 owner = self.factory.makeTeam(owner=registrant)
72 distroseries = self.factory.makeDistroSeries()
73 sourcepackagename = self.factory.makeSourcePackageName()
74 name = self.factory.getUniqueString(u'recipe-name')
75 description = self.factory.getUniqueString(u'recipe-description')
76 builder_recipe = self.factory.makeRecipe()
77 recipe = getUtility(ISourcePackageRecipeSource).new(
78 registrant=registrant, owner=owner, distroseries=[distroseries],
79 sourcepackagename=sourcepackagename, name=name,
80 description=description, builder_recipe=builder_recipe)
81 self.assertEquals(
82 (registrant, owner, set([distroseries]), sourcepackagename, name),
83 (recipe.registrant, recipe.owner, set(recipe.distroseries),
84 recipe.sourcepackagename, recipe.name))
85
86 def test_source_implements_interface(self):
87 # The SourcePackageRecipe class implements ISourcePackageRecipeSource.
88 self.assertProvides(
89 getUtility(ISourcePackageRecipeSource),
90 ISourcePackageRecipeSource)
91
92 def test_recipe_implements_interface(self):
93 # SourcePackageRecipe objects implement ISourcePackageRecipe.
94 recipe = self.makeSourcePackageRecipeFromBuilderRecipe(
95 self.factory.makeRecipe())
96 self.assertProvides(recipe, ISourcePackageRecipe)
97
98 def test_base_branch(self):
99 # When a recipe is created, we can access its base branch.
100 branch = self.factory.makeAnyBranch()
101 builder_recipe = self.factory.makeRecipe(branch)
102 sp_recipe = self.makeSourcePackageRecipeFromBuilderRecipe(
103 builder_recipe)
104 self.assertEquals(branch, sp_recipe.base_branch)
105
106 def test_branch_links_created(self):
107 # When a recipe is created, we can query it for links to the branch
108 # it references.
109 branch = self.factory.makeAnyBranch()
110 builder_recipe = self.factory.makeRecipe(branch)
111 sp_recipe = self.makeSourcePackageRecipeFromBuilderRecipe(
112 builder_recipe)
113 self.assertEquals([branch], list(sp_recipe.getReferencedBranches()))
114
115 def test_multiple_branch_links_created(self):
116 # If a recipe links to more than one branch, getReferencedBranches()
117 # returns all of them.
118 branch1 = self.factory.makeAnyBranch()
119 branch2 = self.factory.makeAnyBranch()
120 builder_recipe = self.factory.makeRecipe(branch1, branch2)
121 sp_recipe = self.makeSourcePackageRecipeFromBuilderRecipe(
122 builder_recipe)
123 self.assertEquals(
124 sorted([branch1, branch2]),
125 sorted(sp_recipe.getReferencedBranches()))
126
127 def test_random_user_cant_edit(self):
128 # An arbitrary user can't set attributes.
129 branch1 = self.factory.makeAnyBranch()
130 builder_recipe1 = self.factory.makeRecipe(branch1)
131 sp_recipe = self.makeSourcePackageRecipeFromBuilderRecipe(
132 builder_recipe1)
133 branch2 = self.factory.makeAnyBranch()
134 builder_recipe2 = self.factory.makeRecipe(branch2)
135 login_person(self.factory.makePerson())
136 self.assertRaises(
137 Unauthorized, setattr, sp_recipe, 'builder_recipe',
138 builder_recipe2)
139
140 def test_set_recipe_text_resets_branch_references(self):
141 # When the recipe_text is replaced, getReferencedBranches returns
142 # (only) the branches referenced by the new recipe.
143 branch1 = self.factory.makeAnyBranch()
144 builder_recipe1 = self.factory.makeRecipe(branch1)
145 sp_recipe = self.makeSourcePackageRecipeFromBuilderRecipe(
146 builder_recipe1)
147 branch2 = self.factory.makeAnyBranch()
148 builder_recipe2 = self.factory.makeRecipe(branch2)
149 login_person(sp_recipe.owner.teamowner)
150 #import pdb; pdb.set_trace()
151 sp_recipe.builder_recipe = builder_recipe2
152 self.assertEquals([branch2], list(sp_recipe.getReferencedBranches()))
153
154 def test_rejects_run_command(self):
155 recipe_text = '''\
156 # bzr-builder format 0.2 deb-version 0.1-{revno}
157 %(base)s
158 run touch test
159 ''' % dict(base=self.factory.makeAnyBranch().bzr_identity)
160 parser = RecipeParser(textwrap.dedent(recipe_text))
161 builder_recipe = parser.parse()
162 self.assertRaises(
163 ForbiddenInstruction,
164 self.makeSourcePackageRecipeFromBuilderRecipe, builder_recipe)
165
166 def test_run_rejected_without_mangling_recipe(self):
167 branch1 = self.factory.makeAnyBranch()
168 builder_recipe1 = self.factory.makeRecipe(branch1)
169 sp_recipe = self.makeSourcePackageRecipeFromBuilderRecipe(
170 builder_recipe1)
171 recipe_text = '''\
172 # bzr-builder format 0.2 deb-version 0.1-{revno}
173 %(base)s
174 run touch test
175 ''' % dict(base=self.factory.makeAnyBranch().bzr_identity)
176 parser = RecipeParser(textwrap.dedent(recipe_text))
177 builder_recipe2 = parser.parse()
178 login_person(sp_recipe.owner.teamowner)
179 self.assertRaises(
180 ForbiddenInstruction, setattr, sp_recipe, 'builder_recipe',
181 builder_recipe2)
182 self.assertEquals([branch1], list(sp_recipe.getReferencedBranches()))
183
184 def test_reject_newer_formats(self):
185 builder_recipe = self.factory.makeRecipe()
186 builder_recipe.format = 0.3
187 self.assertRaises(
188 TooNewRecipeFormat,
189 self.makeSourcePackageRecipeFromBuilderRecipe, builder_recipe)
190
191 def test_requestBuild(self):
192 recipe = self.factory.makeSourcePackageRecipe()
193 (distroseries,) = list(recipe.distroseries)
194 ppa = self.factory.makeArchive()
195 build = recipe.requestBuild(ppa, ppa.owner, distroseries,
196 PackagePublishingPocket.RELEASE)
197 self.assertProvides(build, ISourcePackageRecipeBuild)
198 self.assertEqual(build.archive, ppa)
199 self.assertEqual(build.distroseries, distroseries)
200 self.assertEqual(build.requester, ppa.owner)
201 store = Store.of(build)
202 store.flush()
203 build_job = store.find(SourcePackageRecipeBuildJob,
204 SourcePackageRecipeBuildJob.build_id==build.id).one()
205 self.assertProvides(build_job, ISourcePackageRecipeBuildJob)
206 self.assertTrue(build_job.virtualized)
207 job = build_job.job
208 self.assertProvides(job, IJob)
209 self.assertEquals(job.status, JobStatus.WAITING)
210 build_queue = store.find(BuildQueue, BuildQueue.job==job.id).one()
211 self.assertProvides(build_queue, IBuildQueue)
212 self.assertTrue(build_queue.virtualized)
213
214 def test_requestBuildRejectsNotPPA(self):
215 recipe = self.factory.makeSourcePackageRecipe()
216 not_ppa = self.factory.makeArchive(purpose=ArchivePurpose.PRIMARY)
217 (distroseries,) = list(recipe.distroseries)
218 self.assertRaises(NonPPABuildRequest, recipe.requestBuild, not_ppa,
219 not_ppa.owner, distroseries, PackagePublishingPocket.RELEASE)
220
221 def test_requestBuildRejectsNoPermission(self):
222 recipe = self.factory.makeSourcePackageRecipe()
223 ppa = self.factory.makeArchive()
224 requester = self.factory.makePerson()
225 (distroseries,) = list(recipe.distroseries)
226 self.assertRaises(CannotUploadToArchive, recipe.requestBuild, ppa,
227 requester, distroseries, PackagePublishingPocket.RELEASE)
228
229 def test_requestBuildRejectsInvalidPocket(self):
230 recipe = self.factory.makeSourcePackageRecipe()
231 ppa = self.factory.makeArchive()
232 (distroseries,) = list(recipe.distroseries)
233 self.assertRaises(InvalidPocketForPPA, recipe.requestBuild, ppa,
234 ppa.owner, distroseries, PackagePublishingPocket.BACKPORTS)
235
236 def test_requestBuildRejectsDisabledArchive(self):
237 recipe = self.factory.makeSourcePackageRecipe()
238 ppa = self.factory.makeArchive()
239 removeSecurityProxy(ppa).disable()
240 (distroseries,) = list(recipe.distroseries)
241 self.assertRaises(ArchiveDisabled, recipe.requestBuild, ppa,
242 ppa.owner, distroseries, PackagePublishingPocket.RELEASE)
243
244 def test_sourcepackagerecipe_description(self):
245 """Ensure that the SourcePackageRecipe has a proper description."""
246 description = u'The whoozits and whatzits.'
247 source_package_recipe = self.factory.makeSourcePackageRecipe(
248 description=description)
249 self.assertEqual(description, source_package_recipe.description)
250
251 def test_distroseries(self):
252 """Test that the distroseries behaves as a set."""
253 recipe = self.factory.makeSourcePackageRecipe()
254 distroseries = self.factory.makeDistroSeries()
255 (old_distroseries,) = recipe.distroseries
256 recipe.distroseries.add(distroseries)
257 self.assertEqual(
258 set([distroseries, old_distroseries]), set(recipe.distroseries))
259 recipe.distroseries.remove(distroseries)
260 self.assertEqual([old_distroseries], list(recipe.distroseries))
261 recipe.distroseries.clear()
262 self.assertEqual([], list(recipe.distroseries))
263
264 def test_build_daily(self):
265 """Test that build_daily behaves as a bool."""
266 recipe = self.factory.makeSourcePackageRecipe()
267 self.assertFalse(recipe.build_daily)
268 login_person(recipe.owner)
269 recipe.build_daily = True
270 self.assertTrue(recipe.build_daily)
271
272 def test_view_public(self):
273 """Anyone can view a recipe with public branches."""
274 owner = self.factory.makePerson()
275 branch = self.factory.makeAnyBranch(owner=owner)
276 with person_logged_in(owner):
277 recipe = self.factory.makeSourcePackageRecipe(branches=[branch])
278 self.assertTrue(check_permission('launchpad.View', recipe))
279 with person_logged_in(self.factory.makePerson()):
280 self.assertTrue(check_permission('launchpad.View', recipe))
281 self.assertTrue(check_permission('launchpad.View', recipe))
282
283 def test_view_private(self):
284 """Recipes with private branches are restricted."""
285 owner = self.factory.makePerson()
286 branch = self.factory.makeAnyBranch(owner=owner, private=True)
287 with person_logged_in(owner):
288 recipe = self.factory.makeSourcePackageRecipe(branches=[branch])
289 self.assertTrue(check_permission('launchpad.View', recipe))
290 with person_logged_in(self.factory.makePerson()):
291 self.assertFalse(check_permission('launchpad.View', recipe))
292 self.assertFalse(check_permission('launchpad.View', recipe))
293
294 def test_edit(self):
295 """Only the owner can edit a sourcepackagerecipe."""
296 recipe = self.factory.makeSourcePackageRecipe()
297 self.assertFalse(check_permission('launchpad.Edit', recipe))
298 with person_logged_in(self.factory.makePerson()):
299 self.assertFalse(check_permission('launchpad.Edit', recipe))
300 with person_logged_in(recipe.owner):
301 self.assertTrue(check_permission('launchpad.Edit', recipe))
302
303 def test_destroySelf(self):
304 """Should destroy associated builds, distroseries, etc."""
305 # Recipe should have at least one datainstruction.
306 branches = [self.factory.makeBranch() for count in range(2)]
307 recipe = self.factory.makeSourcePackageRecipe(branches=branches)
308 pending_build = self.factory.makeSourcePackageRecipeBuild(
309 recipe=recipe)
310 self.factory.makeSourcePackageRecipeBuildJob(
311 recipe_build=pending_build)
312 past_build = self.factory.makeSourcePackageRecipeBuild(
313 recipe=recipe)
314 self.factory.makeSourcePackageRecipeBuildJob(
315 recipe_build=past_build)
316 removeSecurityProxy(past_build).datebuilt = datetime.now(UTC)
317 recipe.destroySelf()
318 # Show no database constraints were violated
319 Store.of(recipe).flush()
320
321
322class TestRecipeBranchRoundTripping(TestCaseWithFactory):
323
324 layer = DatabaseFunctionalLayer
325
326 def setUp(self):
327 super(TestRecipeBranchRoundTripping, self).setUp()
328 self.base_branch = self.factory.makeAnyBranch()
329 self.nested_branch = self.factory.makeAnyBranch()
330 self.merged_branch = self.factory.makeAnyBranch()
331 self.branch_identities = {
332 'base': self.base_branch.bzr_identity,
333 'nested': self.nested_branch.bzr_identity,
334 'merged': self.merged_branch.bzr_identity,
335 }
336
337 def get_recipe(self, recipe_text):
338 builder_recipe = RecipeParser(textwrap.dedent(recipe_text)).parse()
339 registrant = self.factory.makePerson()
340 owner = self.factory.makeTeam(owner=registrant)
341 distroseries = self.factory.makeDistroSeries()
342 sourcepackagename = self.factory.makeSourcePackageName()
343 name = self.factory.getUniqueString(u'recipe-name')
344 description = self.factory.getUniqueString(u'recipe-description')
345 recipe = getUtility(ISourcePackageRecipeSource).new(
346 registrant=registrant, owner=owner, distroseries=[distroseries],
347 sourcepackagename=sourcepackagename, name=name,
348 description=description, builder_recipe=builder_recipe)
349 return recipe.builder_recipe
350
351 def check_base_recipe_branch(self, branch, url, revspec=None,
352 num_child_branches=0, revid=None, deb_version=None):
353 self.check_recipe_branch(branch, None, url, revspec=revspec,
354 num_child_branches=num_child_branches, revid=revid)
355 self.assertEqual(deb_version, branch.deb_version)
356
357 def check_recipe_branch(self, branch, name, url, revspec=None,
358 num_child_branches=0, revid=None):
359 self.assertEqual(name, branch.name)
360 self.assertEqual(url, branch.url)
361 self.assertEqual(revspec, branch.revspec)
362 self.assertEqual(revid, branch.revid)
363 self.assertEqual(num_child_branches, len(branch.child_branches))
364
365 def test_builds_simplest_recipe(self):
366 recipe_text = '''\
367 # bzr-builder format 0.2 deb-version 0.1-{revno}
368 %(base)s
369 ''' % self.branch_identities
370 base_branch = self.get_recipe(recipe_text)
371 self.check_base_recipe_branch(
372 base_branch, self.base_branch.bzr_identity,
373 deb_version='0.1-{revno}')
374
375 def test_builds_recipe_with_merge(self):
376 recipe_text = '''\
377 # bzr-builder format 0.2 deb-version 0.1-{revno}
378 %(base)s
379 merge bar %(merged)s
380 ''' % self.branch_identities
381 base_branch = self.get_recipe(recipe_text)
382 self.check_base_recipe_branch(
383 base_branch, self.base_branch.bzr_identity, num_child_branches=1,
384 deb_version='0.1-{revno}')
385 child_branch, location = base_branch.child_branches[0].as_tuple()
386 self.assertEqual(None, location)
387 self.check_recipe_branch(
388 child_branch, "bar", self.merged_branch.bzr_identity)
389
390 def test_builds_recipe_with_nest(self):
391 recipe_text = '''\
392 # bzr-builder format 0.2 deb-version 0.1-{revno}
393 %(base)s
394 nest bar %(nested)s baz
395 ''' % self.branch_identities
396 base_branch = self.get_recipe(recipe_text)
397 self.check_base_recipe_branch(
398 base_branch, self.base_branch.bzr_identity, num_child_branches=1,
399 deb_version='0.1-{revno}')
400 child_branch, location = base_branch.child_branches[0].as_tuple()
401 self.assertEqual("baz", location)
402 self.check_recipe_branch(
403 child_branch, "bar", self.nested_branch.bzr_identity)
404
405 def test_builds_recipe_with_nest_then_merge(self):
406 recipe_text = '''\
407 # bzr-builder format 0.2 deb-version 0.1-{revno}
408 %(base)s
409 nest bar %(nested)s baz
410 merge zam %(merged)s
411 ''' % self.branch_identities
412 base_branch = self.get_recipe(recipe_text)
413 self.check_base_recipe_branch(
414 base_branch, self.base_branch.bzr_identity, num_child_branches=2,
415 deb_version='0.1-{revno}')
416 child_branch, location = base_branch.child_branches[0].as_tuple()
417 self.assertEqual("baz", location)
418 self.check_recipe_branch(
419 child_branch, "bar", self.nested_branch.bzr_identity)
420 child_branch, location = base_branch.child_branches[1].as_tuple()
421 self.assertEqual(None, location)
422 self.check_recipe_branch(
423 child_branch, "zam", self.merged_branch.bzr_identity)
424
425 def test_builds_recipe_with_merge_then_nest(self):
426 recipe_text = '''\
427 # bzr-builder format 0.2 deb-version 0.1-{revno}
428 %(base)s
429 merge zam %(merged)s
430 nest bar %(nested)s baz
431 ''' % self.branch_identities
432 base_branch = self.get_recipe(recipe_text)
433 self.check_base_recipe_branch(
434 base_branch, self.base_branch.bzr_identity, num_child_branches=2,
435 deb_version='0.1-{revno}')
436 child_branch, location = base_branch.child_branches[0].as_tuple()
437 self.assertEqual(None, location)
438 self.check_recipe_branch(
439 child_branch, "zam", self.merged_branch.bzr_identity)
440 child_branch, location = base_branch.child_branches[1].as_tuple()
441 self.assertEqual("baz", location)
442 self.check_recipe_branch(
443 child_branch, "bar", self.nested_branch.bzr_identity)
444
445 def test_builds_a_merge_in_to_a_nest(self):
446 recipe_text = '''\
447 # bzr-builder format 0.2 deb-version 0.1-{revno}
448 %(base)s
449 nest bar %(nested)s baz
450 merge zam %(merged)s
451 ''' % self.branch_identities
452 base_branch = self.get_recipe(recipe_text)
453 self.check_base_recipe_branch(
454 base_branch, self.base_branch.bzr_identity, num_child_branches=1,
455 deb_version='0.1-{revno}')
456 child_branch, location = base_branch.child_branches[0].as_tuple()
457 self.assertEqual("baz", location)
458 self.check_recipe_branch(
459 child_branch, "bar", self.nested_branch.bzr_identity,
460 num_child_branches=1)
461 child_branch, location = child_branch.child_branches[0].as_tuple()
462 self.assertEqual(None, location)
463 self.check_recipe_branch(
464 child_branch, "zam", self.merged_branch.bzr_identity)
465
466 def tests_builds_nest_into_a_nest(self):
467 nested2 = self.factory.makeAnyBranch()
468 self.branch_identities['nested2'] = nested2.bzr_identity
469 recipe_text = '''\
470 # bzr-builder format 0.2 deb-version 0.1-{revno}
471 %(base)s
472 nest bar %(nested)s baz
473 nest zam %(nested2)s zoo
474 ''' % self.branch_identities
475 base_branch = self.get_recipe(recipe_text)
476 self.check_base_recipe_branch(
477 base_branch, self.base_branch.bzr_identity, num_child_branches=1,
478 deb_version='0.1-{revno}')
479 child_branch, location = base_branch.child_branches[0].as_tuple()
480 self.assertEqual("baz", location)
481 self.check_recipe_branch(
482 child_branch, "bar", self.nested_branch.bzr_identity,
483 num_child_branches=1)
484 child_branch, location = child_branch.child_branches[0].as_tuple()
485 self.assertEqual("zoo", location)
486 self.check_recipe_branch(child_branch, "zam", nested2.bzr_identity)
487
488 def tests_builds_recipe_with_revspecs(self):
489 recipe_text = '''\
490 # bzr-builder format 0.2 deb-version 0.1-{revno}
491 %(base)s revid:a
492 nest bar %(nested)s baz tag:b
493 merge zam %(merged)s 2
494 ''' % self.branch_identities
495 base_branch = self.get_recipe(recipe_text)
496 self.check_base_recipe_branch(
497 base_branch, self.base_branch.bzr_identity, num_child_branches=2,
498 revspec="revid:a", deb_version='0.1-{revno}')
499 instruction = base_branch.child_branches[0]
500 child_branch = instruction.recipe_branch
501 location = instruction.nest_path
502 self.assertEqual("baz", location)
503 self.check_recipe_branch(
504 child_branch, "bar", self.nested_branch.bzr_identity,
505 revspec="tag:b")
506 child_branch, location = base_branch.child_branches[1].as_tuple()
507 self.assertEqual(None, location)
508 self.check_recipe_branch(
509 child_branch, "zam", self.merged_branch.bzr_identity, revspec="2")
510
511
512class TestWebservice(TestCaseWithFactory):
513
514 layer = AppServerLayer
515
516 def makeRecipeText(self):
517 branch = self.factory.makeBranch()
518 return MINIMAL_RECIPE_TEXT % branch.bzr_identity
519
520 def makeRecipe(self, user=None, owner=None, recipe_text=None):
521 if user is None:
522 user = self.factory.makePerson()
523 if owner is None:
524 owner = user
525 db_distroseries = self.factory.makeDistroSeries()
526 if recipe_text is None:
527 recipe_text = self.makeRecipeText()
528 launchpad = launchpadlib_for('test', user,
529 service_root="http://api.launchpad.dev:8085")
530 login(ANONYMOUS)
531 distroseries = ws_object(launchpad, db_distroseries)
532 ws_owner = ws_object(launchpad, owner)
533 recipe = ws_owner.createRecipe(
534 name='toaster-1', sourcepackagename='toaster',
535 description='a recipe', distroseries=[distroseries.self_link],
536 recipe_text=recipe_text)
537 # at the moment, distroseries is not exposed in the API.
538 transaction.commit()
539 db_recipe = owner.getRecipe(name=u'toaster-1')
540 self.assertEqual(set([db_distroseries]), set(db_recipe.distroseries))
541 return recipe, ws_owner, launchpad
542
543 def test_createRecipe(self):
544 """Ensure recipe creation works."""
545 team = self.factory.makeTeam()
546 recipe_text = self.makeRecipeText()
547 recipe, user = self.makeRecipe(user=team.teamowner, owner=team,
548 recipe_text=recipe_text)[:2]
549 self.assertEqual(team.name, recipe.owner.name)
550 self.assertEqual(team.teamowner.name, recipe.registrant.name)
551 self.assertEqual('toaster-1', recipe.name)
552 self.assertEqual(recipe_text, recipe.recipe_text)
553 self.assertEqual('toaster', recipe.sourcepackagename)
554
555 def test_recipe_text(self):
556 recipe_text2 = self.makeRecipeText()
557 recipe = self.makeRecipe()[0]
558 recipe.setRecipeText(recipe_text=recipe_text2)
559 self.assertEqual(recipe_text2, recipe.recipe_text)
560
561 def test_getRecipe(self):
562 """Person.getRecipe returns the named recipe."""
563 recipe, user = self.makeRecipe()[:-1]
564 self.assertEqual(recipe, user.getRecipe(name=recipe.name))
565
566 def test_requestBuild(self):
567 """Build requests can be performed."""
568 person = self.factory.makePerson()
569 archive = self.factory.makeArchive(owner=person)
570 distroseries = self.factory.makeDistroSeries()
571 recipe, user, launchpad = self.makeRecipe(person)
572 distroseries = ws_object(launchpad, distroseries)
573 archive = ws_object(launchpad, archive)
574 recipe.requestBuild(
575 archive=archive, distroseries=distroseries,
576 pocket=PackagePublishingPocket.RELEASE.title)
577
578
579def test_suite():
580 return unittest.TestLoader().loadTestsFromName(__name__)