Merge lp:~jml/launchpad/buildd-slavescanner-bustage into lp:launchpad

Proposed by Jonathan Lange on 2010-09-21
Status: Merged
Merged at revision: 11601
Proposed branch: lp:~jml/launchpad/buildd-slavescanner-bustage
Merge into: lp:launchpad
Diff against target: 1155 lines (+274/-573)
11 files modified
lib/lp/buildmaster/model/builder.py (+5/-0)
lib/lp/services/twistedsupport/processmonitor.py (+1/-1)
lib/lp/soyuz/doc/archive-dependencies.txt (+15/-6)
lib/lp/soyuz/doc/buildd-slave.txt (+1/-37)
lib/lp/soyuz/doc/buildd-slavescanner.txt (+5/-495)
lib/lp/soyuz/model/binarypackagebuildbehavior.py (+3/-2)
lib/lp/soyuz/scripts/buildd.py (+3/-0)
lib/lp/soyuz/tests/soyuzbuilddhelpers.py (+25/-30)
lib/lp/soyuz/tests/test_binarypackagebuildbehavior.py (+204/-0)
lib/lp/testing/factory.py (+7/-2)
lib/lp/testing/tests/test_factory.py (+5/-0)
To merge this branch: bzr merge lp:~jml/launchpad/buildd-slavescanner-bustage
Reviewer Review Type Date Requested Status
Jeroen T. Vermeulen (community) 2010-09-21 Approve on 2010-09-22
Review via email: mp+36187@code.launchpad.net

Commit message

Bust up much of buildd-slavescanner.txt into better, more focused tests

Description of the change

This branch takes the tests in buildd-slavescanner.txt that were exercising the BinaryPackageBuildBehavior class and turns them into more-focused Python tests.

Some of the tests were moved to archive-dependencies.txt, since they were really testing something at a much lower level.

To do this we had to update the mocks that we use and tweak the factory a little.

There are a few incidental cleanups & comments in the actual code, but nothing that puts the massive test refactoring at risk.

To post a comment you must log in.
Jeroen T. Vermeulen (jtv) wrote :

Thanks for the work on this. We discussed many superficial changes on IRC, and you've made corresponding improvements: separate creation of complex expected values from comparisons to actual values. Better not import twisted.trial.unittest under that name since it leads to confusion with the global unittest. Use a list comprehension instead of a loop calling a function. Use transaction instead of layer.txn. Bear our syntax guidelines in mind when initializing dicts.

Discussed but not changed:
 * Testing the logic without Twisted. Complete the overhaul first, then be clever.
 * Extracting more of the unit test setup into helpers to make the tests shorter. First see what parameterization would be needed as the tests grow.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/buildmaster/model/builder.py'
2--- lib/lp/buildmaster/model/builder.py 2010-09-21 09:05:34 +0000
3+++ lib/lp/buildmaster/model/builder.py 2010-09-22 10:37:47 +0000
4@@ -115,6 +115,11 @@
5 class BuilderSlave(object):
6 """Add in a few useful methods for the XMLRPC slave."""
7
8+ # WARNING: If you change the API for this, you should also change the APIs
9+ # of the mocks in soyuzbuilderhelpers to match. Otherwise, you will have
10+ # many false positives in your test run and will most likely break
11+ # production.
12+
13 # XXX: This (BuilderSlave) should use composition, rather than
14 # inheritance.
15
16
17=== modified file 'lib/lp/services/twistedsupport/processmonitor.py'
18--- lib/lp/services/twistedsupport/processmonitor.py 2010-08-20 20:31:18 +0000
19+++ lib/lp/services/twistedsupport/processmonitor.py 2010-09-22 10:37:47 +0000
20@@ -300,7 +300,7 @@
21
22 def spawnProcess(self, *args, **kwargs):
23 """Start a process.
24-
25+
26 See reactor.spawnProcess.
27 """
28 self._process_transport = reactor.spawnProcess(
29
30=== modified file 'lib/lp/soyuz/doc/archive-dependencies.txt'
31--- lib/lp/soyuz/doc/archive-dependencies.txt 2010-08-24 15:29:01 +0000
32+++ lib/lp/soyuz/doc/archive-dependencies.txt 2010-09-22 10:37:47 +0000
33@@ -250,18 +250,27 @@
34 deb http://ftpmaster.internal/ubuntu hoary-updates
35 main restricted universe multiverse
36
37-Similarly, populated PPA dependencies are listed in the building
38+Similarly, unpopulated PPA dependencies are *not* listed in the building
39 'sources_list'.
40
41 >>> mark = getUtility(IPersonSet).getByName('mark')
42+ >>> archive_dependency = cprov.archive.addArchiveDependency(
43+ ... mark.archive, PackagePublishingPocket.RELEASE,
44+ ... getUtility(IComponentSet)['main'])
45+ >>> print_building_sources_list(a_build)
46+ deb http://ppa.launchpad.dev/cprov/ppa/ubuntu hoary main
47+ deb http://ftpmaster.internal/ubuntu hoary
48+ main restricted universe multiverse
49+ deb http://ftpmaster.internal/ubuntu hoary-security
50+ main restricted universe multiverse
51+ deb http://ftpmaster.internal/ubuntu hoary-updates
52+ main restricted universe multiverse
53+
54+But *populated* PPA dependencies *are* listed in the building 'sources_list'.
55+
56 >>> pub_binaries = test_publisher.getPubBinaries(
57 ... binaryname='dep-bin', archive=mark.archive,
58 ... status=PackagePublishingStatus.PUBLISHED)
59-
60- >>> archive_dependency = cprov.archive.addArchiveDependency(
61- ... mark.archive, PackagePublishingPocket.RELEASE,
62- ... getUtility(IComponentSet)['main'])
63-
64 >>> print_building_sources_list(a_build)
65 deb http://ppa.launchpad.dev/cprov/ppa/ubuntu hoary main
66 deb http://ppa.launchpad.dev/mark/ppa/ubuntu hoary main
67
68=== modified file 'lib/lp/soyuz/doc/buildd-slave.txt'
69--- lib/lp/soyuz/doc/buildd-slave.txt 2010-04-30 10:00:34 +0000
70+++ lib/lp/soyuz/doc/buildd-slave.txt 2010-09-22 10:37:47 +0000
71@@ -13,43 +13,6 @@
72 >>> from canonical.buildd.tests import BuilddSlaveTestSetup
73 >>> BuilddSlaveTestSetup().setUp()
74
75-Use simple xmlrpclib client to certify the BuildSlave is running
76-
77- >>> import xmlrpclib
78- >>> slave = xmlrpclib.Server('http://localhost:8221/rpc/')
79- >>> slave.echo('Hello World')
80- ['Hello World']
81-
82-With slave protocol v1.0new, the only way to get files to the slave is to
83-put them in the librarian first...
84-
85- >>> from canonical.librarian.client import LibrarianClient
86- >>> from StringIO import StringIO
87- >>> from canonical.launchpad.database import LibraryFileAlias
88- >>> import transaction
89- >>> lc = LibrarianClient()
90- >>> helloworld = "Hello World"
91- >>> hw_sio = StringIO(helloworld)
92- >>> alias = lc.addFile("HelloWorld.txt", len(helloworld),
93- ... hw_sio, "text/plain")
94- >>> transaction.commit()
95- >>> lf = LibraryFileAlias.get(alias)
96- >>> present, info = slave.ensurepresent(
97- ... lf.content.sha1, lf.http_url, "", "")
98- >>> present, info
99- (True, 'Download')
100-
101-As of slave protocol v1.0new, /filecache/SHA1SUM is *THE* way
102-to retrieve files from the slave. Verify it works...
103-
104- >>> from urllib2 import urlopen
105- >>> f = urlopen("http://localhost:8221/filecache/" + lf.content.sha1)
106- >>> hw_str = f.read()
107- >>> f.close()
108- >>> hw_str == helloworld
109- True
110-
111-
112 == BuilderSet polling operations ==
113
114 >>> import logging
115@@ -90,6 +53,7 @@
116
117 At this point the buildd-slave is not accessible anymore.
118
119+ >>> import xmlrpclib
120 >>> s = xmlrpclib.Server('http://localhost:8221/rpc/')
121 >>> s.info()
122 Traceback (most recent call last):
123
124=== modified file 'lib/lp/soyuz/doc/buildd-slavescanner.txt'
125--- lib/lp/soyuz/doc/buildd-slavescanner.txt 2010-09-16 14:36:47 +0000
126+++ lib/lp/soyuz/doc/buildd-slavescanner.txt 2010-09-22 10:37:47 +0000
127@@ -112,12 +112,10 @@
128
129 Make sure that a_builder has no active builds:
130
131- >>> from canonical.launchpad.ftests import syncUpdate
132 >>> if a_builder.currentjob is not None:
133 ... currentjob = a_builder.currentjob
134 ... currentjob.setDateStarted(None)
135 ... currentjob.builder = None
136- ... syncUpdate(currentjob)
137
138 Force the test builder to be 'ok' as the code required to do this
139 automatically is not yet factored into the content class.
140@@ -595,11 +593,9 @@
141 >>> resurrect_build = getUtility(IBinaryPackageBuildSet).getByQueueEntry(
142 ... current_job)
143 >>> resurrect_build.status = BuildStatus.NEEDSBUILD
144- >>> syncUpdate(resurrect_build)
145 >>> current_job.builder = None
146 >>> current_job.setDateStarted(None)
147 >>> current_job.lastscore = 0
148- >>> syncUpdate(current_job)
149
150 IBuilder.findCandidate also identifies if there are builds for
151 superseded source package releases in the queue and marks the
152@@ -740,66 +736,6 @@
153 >>> commit()
154 >>> LaunchpadZopelessLayer.switchDbUser(config.builddmaster.dbuser)
155
156-For building a candidate in the release pocket for the main component
157-and the primary archive It will pass an 'archives' argument to the
158-slave that contains sources.list entries for each pocket required in
159-the primary archive dependency tree.
160-
161-We also pass arguments called 'suite' which is the current distroseries and
162-pocket, (e.g. edgy-updates) and 'archive_purpose' which contains the build's
163-archive.purpose (e.g. PRIMARY or PPA). These latter two arguments are
164-used in the chroot to determine whether it needs to turn on some features
165-or not (like pkgstriptranslations and pkgmaintainermangler).
166-
167-Please note also that the 'archive_private' flag is passed to the slave
168-builder. It is True for private archives and False otherwise.
169-
170- >>> a_builder.setSlaveForTesting(OkSlave())
171- >>> a_builder.is_available
172- True
173- >>> candidate = a_build.queueBuild()
174- >>> removeSecurityProxy(a_builder)._dispatchBuildCandidate(candidate)
175- ensurepresent called, url=...
176- ensurepresent called,
177- url=http://localhost:58000/3/firefox_0.9.2.orig.tar.gz
178- OkSlave BUILDING
179- Archives:
180- deb http://ftpmaster.internal/ubuntu hoary main
181- Suite: hoary
182- Ogre-component: main
183- Archive Purpose: PRIMARY
184- Archive Private: False
185-
186- >>> candidate.destroySelf()
187-
188-Currently we can theoretically dispatch a build candidate for a
189-builder in 'manual' mode.
190-
191-Although this will not be optimal, because we can only
192-do it once the manual builder has been collected (due to the
193-BuildQueue.builder constraint). Also because we don't yet provide a
194-API/UI method to request the dispatch in advance.
195-
196- >>> a_builder.manual = True
197- >>> commit()
198- >>> a_builder.setSlaveForTesting(OkSlave())
199- >>> a_builder.is_available
200- True
201- >>> candidate = a_build.queueBuild()
202- >>> removeSecurityProxy(a_builder)._dispatchBuildCandidate(candidate)
203- ensurepresent called, url=...
204- ensurepresent called,
205- url=http://localhost:58000/3/firefox_0.9.2.orig.tar.gz
206- OkSlave BUILDING
207- Archives:
208- deb http://ftpmaster.internal/ubuntu hoary main
209- Suite: hoary
210- Ogre-component: main
211- Archive Purpose: PRIMARY
212- Archive Private: False
213-
214- >>> candidate.destroySelf()
215-
216 Partner archive builds will set up the 'archives' argument such that it
217 references all the required pockets/components in the primary archive, in
218 addition to a reference to the release pocket in the partner archive itself.
219@@ -812,10 +748,6 @@
220 >>> a_builder.is_available
221 True
222
223- >>> candidate = a_build.queueBuild()
224- >>> setupBuildQueue(candidate, a_builder)
225- >>> last_stub_mail_count = len(stub.test_emails)
226-
227 The partner archive won't be passed to the builder unless it has at
228 least one published binary availble in the target distroarchseries.
229 This feature fixes bug #196782, when archive/suites got passed to
230@@ -823,229 +755,12 @@
231 any PPA/suite will fail during the first 20 minutes because no empty
232 indexes are published.
233
234-Note that only a published binary in the right context will make the
235-archive relevant, anything PENDING or published in another context
236-wouldn't work.
237-
238- >>> warty = getUtility(IDistributionSet)['ubuntu']['warty']
239- >>> create_binary_publication_for(
240- ... partner_archive, warty, PackagePublishingStatus.PUBLISHED)
241-
242- >>> hoary = getUtility(IDistributionSet)['ubuntu']['hoary']
243- >>> create_binary_publication_for(
244- ... partner_archive, hoary, PackagePublishingStatus.PENDING)
245-
246-So, at moment, partner archive is still not relevant for builds in
247-hoary/i386. It's not passed to the builder.
248-
249- >>> removeSecurityProxy(a_builder)._dispatchBuildCandidate(candidate)
250- ensurepresent called, url=...
251- ensurepresent called,
252- url=http://localhost:58000/3/firefox_0.9.2.orig.tar.gz
253- OkSlave BUILDING
254- Archives:
255- deb http://ftpmaster.internal/ubuntu hoary main restricted universe multiverse
256- deb http://ftpmaster.internal/ubuntu hoary-security main restricted universe multiverse
257- deb http://ftpmaster.internal/ubuntu hoary-updates main restricted universe multiverse
258- Suite: hoary
259- Ogre-component: main
260- Archive Purpose: PARTNER
261- Archive Private: False
262-
263-Let's try it again.
264-
265- >>> candidate.destroySelf()
266- >>> a_builder.setSlaveForTesting(OkSlave())
267- >>> a_builder.is_available
268- True
269-
270- >>> candidate = a_build.queueBuild()
271- >>> setupBuildQueue(candidate, a_builder)
272- >>> last_stub_mail_count = len(stub.test_emails)
273-
274- >>> removeSecurityProxy(a_build).archive = ubuntu.main_archive
275- >>> candidate.destroySelf()
276-
277-But this time We will create a valid publication on partner hoary/i386.
278-
279- >>> from lp.soyuz.interfaces.component import IComponentSet
280- >>> commit()
281- >>> LaunchpadZopelessLayer.switchDbUser('launchpad')
282- >>> login('foo.bar@canonical.com')
283- >>> pub_source = test_publisher.getPubSource(
284- ... archive=partner_archive, distroseries=hoary,
285- ... status=PackagePublishingStatus.PUBLISHED,
286- ... component='partner')
287- >>> pub_binaries = test_publisher.getPubBinaries(
288- ... archive=partner_archive, pub_source=pub_source,
289- ... distroseries=hoary, status=PackagePublishingStatus.PUBLISHED)
290- >>> partner_build = pub_binaries[0].binarypackagerelease.build
291- >>> partner_candidate = partner_build.buildqueue_record
292- >>> commit()
293- >>> LaunchpadZopelessLayer.switchDbUser(config.builddmaster.dbuser)
294-
295-Now when we dispatch the partner build, since it has one published
296-binary in hoary/i386, the partner archive gets included in the builder
297-sources_list.
298-
299- >>> removeSecurityProxy(
300- ... a_builder)._dispatchBuildCandidate(partner_candidate)
301- ensurepresent called, url=...
302- ensurepresent called, url=http://localhost:58000/.../foo_666.dsc
303- OkSlave BUILDING
304- Archives:
305- deb http://ftpmaster.internal/ubuntu hoary
306- main restricted universe multiverse
307- deb http://ftpmaster.internal/ubuntu hoary-security
308- main restricted universe multiverse
309- deb http://ftpmaster.internal/ubuntu hoary-updates
310- main restricted universe multiverse
311- deb http://ftpmaster.internal/ubuntu-partner hoary partner
312- Suite: hoary
313- Ogre-component: partner
314- Archive Purpose: PARTNER
315- Archive Private: False
316-
317- >>> partner_candidate.destroySelf()
318-
319-Similarly, PPA builds pass the 'archives' arguments:
320-
321- >>> from canonical.launchpad.interfaces import IPersonSet
322- >>> cprov_archive = getUtility(IPersonSet).getByName('cprov').archive
323- >>> removeSecurityProxy(a_build).archive = cprov_archive
324- >>> a_builder.virtualized = True
325- >>> a_builder.vm_host = 'localhost.ppa'
326- >>> commit()
327- >>> a_builder.setSlaveForTesting(OkSlave())
328- >>> a_builder.is_available
329- True
330-
331- >>> candidate = a_build.queueBuild()
332- >>> setupBuildQueue(candidate, a_builder)
333- >>> last_stub_mail_count = len(stub.test_emails)
334-
335-Exactly as Partner, Celso's PPA won't be included if it doesn't
336-contain any published binary in hoary/i386. We will create it before
337-dispatching.
338-
339- >>> create_binary_publication_for(
340- ... cprov_archive, hoary, PackagePublishingStatus.PUBLISHED)
341-
342- >>> removeSecurityProxy(a_builder)._dispatchBuildCandidate(candidate)
343- ensurepresent called, url=...
344- ensurepresent called,
345- url=http://localhost:58000/3/firefox_0.9.2.orig.tar.gz
346- OkSlave BUILDING
347- Archives:
348- deb http://ftpmaster.internal/ubuntu hoary main restricted universe multiverse
349- deb http://ftpmaster.internal/ubuntu hoary-security main restricted universe multiverse
350- deb http://ftpmaster.internal/ubuntu hoary-updates main restricted universe multiverse
351- deb http://ppa.launchpad.dev/cprov/ppa/ubuntu hoary main
352- Suite: hoary
353- Ogre-component: main
354- Archive Purpose: PPA
355- Archive Private: False
356-
357-If the build is for a private PPA, the slave scanner will pass a
358-sources.list entry that contains a password to access the archive.
359-
360- >>> from canonical.testing import LaunchpadZopelessLayer
361- >>> commit()
362- >>> LaunchpadZopelessLayer.switchDbUser('launchpad')
363- >>> login('foo.bar@canonical.com')
364- >>> build = getUtility(IBinaryPackageBuildSet).getByQueueEntry(
365- ... candidate)
366- >>> for build_file in build.source_package_release.files:
367- ... removeSecurityProxy(build_file).libraryfile.restricted = True
368- >>> private_ppa = factory.makeArchive(
369- ... owner=cprov_archive.owner, name='pppa', private=True,
370- ... virtualized=False, distribution=ubuntu)
371-
372-It's necessary to publish some binaries into the private PPA, otherwise
373-the PPA won't be included as a dependency in the sources list below.
374-
375- >>> binaries = test_publisher.getPubBinaries(
376- ... distroseries=ubuntu['hoary'], archive=private_ppa,
377- ... status=PackagePublishingStatus.PUBLISHED)
378- >>> removeSecurityProxy(build).archive = private_ppa
379- >>> commit()
380- >>> LaunchpadZopelessLayer.switchDbUser(test_dbuser)
381- >>> login(ANONYMOUS)
382-
383-Dispatch the build again. Celso's archive sources.list entry now has the
384-buildd:secret@ part in the URL.
385-
386-Also note that when ensurepresent() is called, it receives a URL that
387-points to the private archive rather than the librarian for the private
388-firefox file. This is because the build slaves are not allowed to
389-access the restricted librarian as it cannot provide access via
390-credentials, unlike the archive itself.
391-
392-Finally, the archive purpose is overridden to PRIMARY instead of PPA
393-for any archives that have require_virtualized as False.
394-
395-In this circumstance, it also uses the component override from the PRIMARY
396-archive and not the one from the PPA, which on the absence of ancestry
397-defaults to 'universe'.
398-
399- >>> build = getUtility(IBinaryPackageBuildSet).getByQueueEntry(candidate)
400- >>> print build.current_component.name
401- main
402-
403-This is so that the mangling tools will run over the built packages.
404-
405- >>> removeSecurityProxy(a_builder)._dispatchBuildCandidate(candidate)
406- ensurepresent called, url=...
407- ensurepresent called,
408- url=http://private-ppa.../cprov/pppa/.../firefox_0.9.2.orig.tar.gz
409- URL authorisation with buildd/sekrit
410- OkSlave BUILDING
411- Archives:
412- deb http://buildd:sekrit@private-ppa.../cprov/pppa/ubuntu hoary main
413- deb http://ftpmaster.internal/ubuntu hoary
414- main restricted universe multiverse
415- deb http://ftpmaster.internal/ubuntu hoary-security
416- main restricted universe multiverse
417- deb http://ftpmaster.internal/ubuntu hoary-updates
418- main restricted universe multiverse
419- Suite: hoary
420- Ogre-component: universe
421- Archive Purpose: PRIMARY
422- Archive Private: True
423-
424-We will create an ancestry in the primary archive target to the 'main'
425-component and this time the dispatching will follow that component.
426-
427- >>> sourcename = build.source_package_release.name
428-
429- >>> LaunchpadZopelessLayer.switchDbUser('launchpad')
430- >>> login('foo.bar@canonical.com')
431-
432- >>> ancestry = test_publisher.getPubSource(
433- ... sourcename=sourcename, version='0.1', distroseries=hoary)
434-
435- >>> print ancestry.displayname
436- mozilla-firefox 0.1 in hoary
437-
438- >>> print ancestry.component.name
439- main
440-
441- >>> commit()
442- >>> LaunchpadZopelessLayer.switchDbUser(config.builddmaster.dbuser)
443- >>> login(ANONYMOUS)
444-
445- >>> removeSecurityProxy(a_builder)._dispatchBuildCandidate(candidate)
446- ensurepresent called, ...
447- ...
448- Ogre-component: main
449- ...
450-
451- >>> candidate.destroySelf()
452-
453 Since this is a build in a private archive, the log was uploaded to
454 the restricted librarian.
455
456- >>> candidate = a_build.queueBuild()
457+ >>> removeSecurityProxy(build).archive = private_ppa
458+ >>> commit()
459+ >>> candidate = build.queueBuild()
460 >>> setupBuildQueue(candidate, a_builder)
461 >>> build.upload_log = None
462 >>> candidate.builder.setSlaveForTesting(WaitingSlave('BuildStatus.OK'))
463@@ -1059,7 +774,7 @@
464 >>> lfa.restricted
465 True
466 >>> print lfa.filename
467- buildlog_ubuntu-hoary-i386.mozilla-firefox_0.9_BUILDING.txt.gz
468+ buildlog_ubuntu-warty-i386.mozilla-firefox_0.9_BUILDING.txt.gz
469
470 The attempt to fetch the buildlog from the common librarian will fail
471 since this is a build in a private archive and the buildlog was thus
472@@ -1079,7 +794,7 @@
473 ... getUtility(IRestrictedLibrarianClient).getFileByAlias(lfa.id))
474 >>> url_parts = urlparse.urlsplit(lfa2.file.geturl())
475 >>> print os.path.basename(url_parts[2])
476- buildlog_ubuntu-hoary-i386.mozilla-firefox_0.9_BUILDING.txt.gz
477+ buildlog_ubuntu-warty-i386.mozilla-firefox_0.9_BUILDING.txt.gz
478
479 A PPA can depend on another PPA. We can make Celso's PPA depend on
480 Mark's PPA:
481@@ -1088,218 +803,13 @@
482 >>> LaunchpadZopelessLayer.switchDbUser('launchpad')
483 >>> login('foo.bar@canonical.com')
484
485-We'll switch the build's archive back to Celso's PPA and set the PPA to
486-virtualized before adding the dependency on Mark's PPA.
487-
488- >>> removeSecurityProxy(build).archive = cprov_archive
489- >>> cprov_archive.require_virtualized = True
490- >>> for build_file in a_build.source_package_release.files:
491- ... removeSecurityProxy(build_file).libraryfile.restricted = False
492- >>> mark_archive = getUtility(IPersonSet).getByName('mark').archive
493-
494- >>> unused_dep = cprov_archive.addArchiveDependency(
495- ... mark_archive, PackagePublishingPocket.RELEASE,
496- ... getUtility(IComponentSet)['main'])
497-
498- >>> commit()
499- >>> LaunchpadZopelessLayer.switchDbUser(test_dbuser)
500- >>> login(ANONYMOUS)
501-
502-Now we can see that a build from Celso's PPA will be able to install
503-dependencies from Mark's PPA, if Mark's PPA has at least one binary
504-published in hoary/i386, which is not the case.
505-
506- >>> a_builder.setSlaveForTesting(OkSlave())
507- >>> a_builder.is_available
508- True
509-
510- >>> candidate = a_build.queueBuild()
511- >>> setupBuildQueue(candidate, a_builder)
512- >>> last_stub_mail_count = len(stub.test_emails)
513-
514- >>> removeSecurityProxy(a_builder)._dispatchBuildCandidate(candidate)
515- ensurepresent called, url=...
516- ensurepresent called,
517- url=http://localhost:58000/3/firefox_0.9.2.orig.tar.gz
518- OkSlave BUILDING
519- Archives:
520- deb http://ftpmaster.internal/ubuntu hoary main restricted universe multiverse
521- deb http://ftpmaster.internal/ubuntu hoary-security main restricted universe multiverse
522- deb http://ftpmaster.internal/ubuntu hoary-updates main restricted universe multiverse
523- deb http://ppa.launchpad.dev/cprov/ppa/ubuntu hoary main
524- Suite: hoary
525- Ogre-component: main
526- Archive Purpose: PPA
527- Archive Private: False
528-
529-We will create the required publication in Mark's PPA and try again.
530-
531- >>> candidate.destroySelf()
532- >>> a_builder.setSlaveForTesting(OkSlave())
533- >>> a_builder.is_available
534- True
535-
536- >>> candidate = a_build.queueBuild()
537- >>> setupBuildQueue(candidate, a_builder)
538- >>> last_stub_mail_count = len(stub.test_emails)
539-
540- >>> create_binary_publication_for(
541- ... mark_archive, hoary, PackagePublishingStatus.PUBLISHED)
542-
543- >>> removeSecurityProxy(a_builder)._dispatchBuildCandidate(candidate)
544- ensurepresent called, url=...
545- ensurepresent called,
546- url=http://localhost:58000/3/firefox_0.9.2.orig.tar.gz
547- OkSlave BUILDING
548- Archives:
549- deb http://ftpmaster.internal/ubuntu hoary main restricted universe multiverse
550- deb http://ftpmaster.internal/ubuntu hoary-security main restricted universe multiverse
551- deb http://ftpmaster.internal/ubuntu hoary-updates main restricted universe multiverse
552- deb http://ppa.launchpad.dev/cprov/ppa/ubuntu hoary main
553- deb http://ppa.launchpad.dev/mark/ppa/ubuntu hoary main
554- Suite: hoary
555- Ogre-component: main
556- Archive Purpose: PPA
557- Archive Private: False
558
559 Clean up before continuing:
560
561- >>> candidate.destroySelf()
562 >>> a_builder.virtualized = False
563 >>> removeSecurityProxy(a_build).archive = ubuntu.main_archive
564 >>> commit()
565
566-Builddmaster stops before starting to build a denied build.
567-Since hoary is in development, we are not able to dispatch
568-builds for post-release pockets:
569-
570- >>> candidate = a_build.queueBuild()
571- >>> setupBuildQueue(candidate, a_builder)
572- >>> last_stub_mail_count = len(stub.test_emails)
573-
574-Make a build in the updates pocket:
575-
576- >>> hoary = hoary_i386.distroseries
577- >>> hoary_evo = hoary.getSourcePackage(
578- ... 'evolution').currentrelease.sourcepackagerelease
579- >>> updates_build = hoary_evo.createBuild(
580- ... distro_arch_series=hoary_i386,
581- ... pocket=PackagePublishingPocket.UPDATES,
582- ... processor=hoary_i386.default_processor,
583- ... archive=hoary_i386.main_archive)
584- >>> updates_bqItem = updates_build.queueBuild()
585-
586- >>> hoary_i386.distroseries.status.name
587- 'DEVELOPMENT'
588- >>> removeSecurityProxy(a_builder)._dispatchBuildCandidate(updates_bqItem)
589- Traceback (most recent call last):
590- ...
591- AssertionError: i386 build of evolution 1.0 in ubuntu hoary UPDATES (...) can not be built for pocket UPDATES: invalid pocket due to the series status of hoary.
592-
593-== Pocket dependencies ==
594-
595-Change the distroseries status for testing. FROZEN allows building in
596-all pockets:
597-
598- >>> from canonical.launchpad.interfaces import SeriesStatus
599- >>> hoary_i386.distroseries.status = SeriesStatus.FROZEN
600-
601-Now we can start a build in other pockets, and see what archives are
602-passed to the slave.
603-
604-A build in the updates pocket:
605-
606- >>> a_builder.currentjob.destroySelf()
607-
608- >>> bqItem3 = a_build.queueBuild()
609- >>> build = getUtility(IBinaryPackageBuildSet).getByQueueEntry(bqItem3)
610- >>> removeSecurityProxy(build).pocket = (
611- ... PackagePublishingPocket.UPDATES)
612- >>> last_stub_mail_count = len(stub.test_emails)
613- >>> removeSecurityProxy(a_builder)._dispatchBuildCandidate(bqItem3)
614- ensurepresent called, url=...
615- ensurepresent called,
616- url=http://localhost:58000/3/firefox_0.9.2.orig.tar.gz
617- OkSlave BUILDING
618- Archives:
619- deb http://ftpmaster.internal/ubuntu hoary main
620- deb http://ftpmaster.internal/ubuntu hoary-security main
621- deb http://ftpmaster.internal/ubuntu hoary-updates main
622- Suite: hoary-updates
623- Ogre-component: main
624- Archive Purpose: PRIMARY
625- Archive Private: False
626-
627-A build in the proposed pocket:
628-
629- >>> a_builder.currentjob.destroySelf()
630-
631- >>> bqItem3 = a_build.queueBuild()
632- >>> removeSecurityProxy(build).pocket = (
633- ... PackagePublishingPocket.PROPOSED)
634- >>> last_stub_mail_count = len(stub.test_emails)
635- >>> removeSecurityProxy(a_builder)._dispatchBuildCandidate(bqItem3)
636- ensurepresent called, url=...
637- ensurepresent called,
638- url=http://localhost:58000/3/firefox_0.9.2.orig.tar.gz
639- OkSlave BUILDING
640- Archives:
641- deb http://ftpmaster.internal/ubuntu hoary main
642- deb http://ftpmaster.internal/ubuntu hoary-proposed main
643- deb http://ftpmaster.internal/ubuntu hoary-security main
644- deb http://ftpmaster.internal/ubuntu hoary-updates main
645- Suite: hoary-proposed
646- Ogre-component: main
647- Archive Purpose: PRIMARY
648- Archive Private: False
649-
650-A build in the backports pocket:
651-
652- >>> a_builder.currentjob.destroySelf()
653-
654- >>> bqItem3 = a_build.queueBuild()
655- >>> removeSecurityProxy(build).pocket = (
656- ... PackagePublishingPocket.BACKPORTS)
657- >>> last_stub_mail_count = len(stub.test_emails)
658- >>> removeSecurityProxy(a_builder)._dispatchBuildCandidate(bqItem3)
659- ensurepresent called, url=...
660- ensurepresent called,
661- url=http://localhost:58000/3/firefox_0.9.2.orig.tar.gz
662- OkSlave BUILDING
663- Archives:
664- deb http://ftpmaster.internal/ubuntu hoary main restricted universe multiverse
665- deb http://ftpmaster.internal/ubuntu hoary-backports main restricted universe multiverse
666- deb http://ftpmaster.internal/ubuntu hoary-security main restricted universe multiverse
667- deb http://ftpmaster.internal/ubuntu hoary-updates main restricted universe multiverse
668- Suite: hoary-backports
669- Ogre-component: main
670- Archive Purpose: PRIMARY
671- Archive Private: False
672-
673-A build in the security pocket:
674-
675- >>> a_builder.currentjob.destroySelf()
676-
677- >>> bqItem3 = a_build.queueBuild()
678- >>> removeSecurityProxy(build).status = (
679- ... BuildStatus.NEEDSBUILD)
680- >>> removeSecurityProxy(build).pocket = (
681- ... PackagePublishingPocket.SECURITY)
682- >>> last_stub_mail_count = len(stub.test_emails)
683-
684-The pocket-dependency infrastructure is ready to deal with SECURITY
685-pocket, however we explicitly skip security builds when dispatching
686-because Embargoed-Archives and Restricted-UI implementations are not
687-yet ready.
688-
689- >>> removeSecurityProxy(a_builder)._dispatchBuildCandidate(bqItem3)
690- Traceback (most recent call last):
691- ...
692- AssertionError: Soyuz is not yet capable of building SECURITY uploads.
693-
694-Builds for security pocket are marked as FAILEDTOBUILD inside the
695-_findBuildCandidate() method, see doc/buildd-dispatching.txt
696-
697
698 == Builder Status Handler ==
699
700
701=== modified file 'lib/lp/soyuz/model/binarypackagebuildbehavior.py'
702--- lib/lp/soyuz/model/binarypackagebuildbehavior.py 2010-08-23 16:51:11 +0000
703+++ lib/lp/soyuz/model/binarypackagebuildbehavior.py 2010-09-22 10:37:47 +0000
704@@ -99,8 +99,9 @@
705 distroseries state.
706 """
707 build = self.build
708- assert not (not self._builder.virtualized and build.is_virtualized), (
709- "Attempt to build non-virtual item on a virtual builder.")
710+ if build.is_virtualized and not self._builder.virtualized:
711+ raise AssertionError(
712+ "Attempt to build non-virtual item on a virtual builder.")
713
714 # Assert that we are not silently building SECURITY jobs.
715 # See findBuildCandidates. Once we start building SECURITY
716
717=== modified file 'lib/lp/soyuz/scripts/buildd.py'
718--- lib/lp/soyuz/scripts/buildd.py 2010-08-27 11:19:54 +0000
719+++ lib/lp/soyuz/scripts/buildd.py 2010-09-22 10:37:47 +0000
720@@ -276,6 +276,9 @@
721 self.txn.commit()
722
723
724+# XXX: JonathanLange 2010-09-22 bug=645046: This is the old slave
725+# scanner. Julian says it's not running on production. We should either delete
726+# it or update it to use the async apis.
727 class SlaveScanner(LaunchpadCronScript):
728
729 def main(self):
730
731=== modified file 'lib/lp/soyuz/tests/soyuzbuilddhelpers.py'
732--- lib/lp/soyuz/tests/soyuzbuilddhelpers.py 2010-09-20 11:52:51 +0000
733+++ lib/lp/soyuz/tests/soyuzbuilddhelpers.py 2010-09-22 10:37:47 +0000
734@@ -17,10 +17,8 @@
735 ]
736
737 from StringIO import StringIO
738-import subprocess
739 import xmlrpclib
740
741-from canonical.config import config
742 from lp.buildmaster.interfaces.builder import CannotFetchFile
743 from lp.buildmaster.model.builder import (
744 rescueBuilderIfLost,
745@@ -85,68 +83,53 @@
746 updateBuilderStatus(self, logger)
747
748
749+# XXX: It would be *really* nice to run some set of tests against the real
750+# BuilderSlave and this one to prevent interface skew.
751 class OkSlave:
752 """An idle mock slave that prints information about itself.
753
754 The architecture tag can be customised during initialisation."""
755
756 def __init__(self, arch_tag=I386_ARCHITECTURE_NAME):
757+ self.call_log = []
758 self.arch_tag = arch_tag
759
760 def status(self):
761 return ('BuilderStatus.IDLE', '')
762
763 def ensurepresent(self, sha1, url, user=None, password=None):
764- print "ensurepresent called, url=%s" % url
765- if user is not None and user != "":
766- print "URL authorisation with %s/%s" % (user, password)
767+ self.call_log.append(('ensurepresent', url, user, password))
768 return True, None
769
770 def build(self, buildid, buildtype, chroot, filemap, args):
771+ self.call_log.append(
772+ ('build', buildid, buildtype, chroot, filemap.keys(), args))
773 info = 'OkSlave BUILDING'
774- print info
775- if 'archives' in args:
776- print "Archives:"
777- for archive_line in sorted(args['archives']):
778- print " %s" % archive_line
779- else:
780- print "No archives set."
781- print "Suite: %s" % args['suite']
782- print "Ogre-component: %s" % args['ogrecomponent']
783- print "Archive Purpose: %s" % args['archive_purpose']
784- print "Archive Private: %s" % args['archive_private']
785 return ('BuildStatus.Building', info)
786
787- def fetchlogtail(self, size):
788- return 'BOGUS'
789-
790 def echo(self, *args):
791+ self.call_log.append(('echo',) + args)
792 return args
793
794 def clean(self):
795- pass
796+ self.call_log.append('clean')
797
798 def abort(self):
799- pass
800+ self.call_log.append('abort')
801
802 def info(self):
803+ self.call_log.append('info')
804 return ('1.0', self.arch_tag, 'debian')
805
806- def resume(self):
807- resume_argv = config.builddmaster.vm_resume_command.split()
808- resume_process = subprocess.Popen(
809- resume_argv, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
810- stdout, stderr = resume_process.communicate()
811-
812- return (stdout, stderr, resume_process.returncode)
813-
814 def sendFileToSlave(self, sha1, url, username="", password=""):
815+ self.call_log.append('sendFileToSlave')
816 present, info = self.ensurepresent(sha1, url, username, password)
817 if not present:
818 raise CannotFetchFile(url, info)
819
820 def cacheFile(self, logger, libraryfilealias):
821- self.sendFileToSlave(
822+ self.call_log.append('cacheFile')
823+ return self.sendFileToSlave(
824 libraryfilealias.content.sha1, libraryfilealias.http_url)
825
826
827@@ -158,10 +141,12 @@
828 self.build_id = build_id
829
830 def status(self):
831+ self.call_log.append('status')
832 buildlog = xmlrpclib.Binary("This is a build log")
833 return ('BuilderStatus.BUILDING', self.build_id, buildlog)
834
835 def getFile(self, sum):
836+ self.call_log.append('getFile')
837 if sum == "buildlog":
838 s = StringIO("This is a build log")
839 s.headers = {'content-length': 19}
840@@ -183,10 +168,12 @@
841 self.valid_file_hashes = ['buildlog']
842
843 def status(self):
844+ self.call_log.append('status')
845 return ('BuilderStatus.WAITING', self.state, self.build_id, {},
846 self.dependencies)
847
848 def getFile(self, hash):
849+ self.call_log.append('getFile')
850 if hash in self.valid_file_hashes:
851 content = "This is a %s" % hash
852 s = StringIO(content)
853@@ -198,6 +185,7 @@
854 """A mock slave that looks like it's in the process of aborting."""
855
856 def status(self):
857+ self.call_log.append('status')
858 return ('BuilderStatus.ABORTING', '1-1')
859
860
861@@ -205,6 +193,7 @@
862 """A mock slave that looks like it's aborted."""
863
864 def status(self):
865+ self.call_log.append('status')
866 return ('BuilderStatus.ABORTED', '1-1')
867
868
869@@ -214,10 +203,15 @@
870 When 'aborted' it raises an xmlrpclib.Fault(8002, 'Could not abort')
871 """
872
873+ def __init__(self):
874+ self.call_log = []
875+
876 def status(self):
877+ self.call_log.append('status')
878 return ('BuilderStatus.BUILDING', '1000-10000')
879
880 def abort(self):
881+ self.call_log.append('abort')
882 raise xmlrpclib.Fault(8002, "Could not abort")
883
884
885@@ -225,4 +219,5 @@
886 """A mock slave that reports that it is broken."""
887
888 def status(self):
889+ self.call_log.append('status')
890 raise xmlrpclib.Fault(8001, "Broken slave")
891
892=== added file 'lib/lp/soyuz/tests/test_binarypackagebuildbehavior.py'
893--- lib/lp/soyuz/tests/test_binarypackagebuildbehavior.py 1970-01-01 00:00:00 +0000
894+++ lib/lp/soyuz/tests/test_binarypackagebuildbehavior.py 2010-09-22 10:37:47 +0000
895@@ -0,0 +1,204 @@
896+# Copyright 2010 Canonical Ltd. This software is licensed under the
897+# GNU Affero General Public License version 3 (see the file LICENSE).
898+
899+from __future__ import with_statement
900+
901+"""Tests for BinaryPackageBuildBehavior."""
902+
903+__metaclass__ = type
904+
905+import transaction
906+
907+from twisted.internet import defer
908+from twisted.trial import unittest as trialtest
909+
910+from zope.security.proxy import removeSecurityProxy
911+
912+from canonical.launchpad.scripts.logger import QuietFakeLogger
913+from canonical.testing import TwistedLaunchpadZopelessLayer
914+
915+from lp.registry.interfaces.pocket import (
916+ PackagePublishingPocket,
917+ pocketsuffix,
918+ )
919+from lp.registry.interfaces.series import SeriesStatus
920+from lp.soyuz.adapters.archivedependencies import (
921+ get_sources_list_for_building,
922+ )
923+from lp.soyuz.enums import (
924+ ArchivePurpose,
925+ )
926+from lp.soyuz.tests.soyuzbuilddhelpers import OkSlave
927+from lp.testing import (
928+ ANONYMOUS,
929+ login_as,
930+ logout,
931+ )
932+from lp.testing.factory import LaunchpadObjectFactory
933+
934+
935+class TestBinaryBuildPackageBehavior(trialtest.TestCase):
936+ """Tests for the BinaryPackageBuildBehavior.
937+
938+ In particular, these tests are about how the BinaryPackageBuildBehavior
939+ interacts with the build slave. We test this by using a test double that
940+ implements the same interface as `BuilderSlave` but instead of actually
941+ making XML-RPC calls, just records any method invocations along with
942+ interesting parameters.
943+ """
944+
945+ layer = TwistedLaunchpadZopelessLayer
946+
947+ def setUp(self):
948+ super(TestBinaryBuildPackageBehavior, self).setUp()
949+ self.factory = LaunchpadObjectFactory()
950+ login_as(ANONYMOUS)
951+ self.addCleanup(logout)
952+ self.layer.switchDbUser('testadmin')
953+
954+ def assertExpectedInteraction(self, ignored, call_log, builder, build,
955+ chroot, archive, archive_purpose, component,
956+ extra_urls=None, filemap_names=None):
957+ expected = self.makeExpectedInteraction(
958+ builder, build, chroot, archive, archive_purpose, component,
959+ extra_urls, filemap_names)
960+ self.assertEqual(call_log, expected)
961+
962+ def makeExpectedInteraction(self, builder, build, chroot, archive,
963+ archive_purpose, component,
964+ extra_urls=None, filemap_names=None):
965+ """Build the log of calls that we expect to be made to the slave.
966+
967+ :param builder: The builder we are using to build the binary package.
968+ :param build: The build being done on the builder.
969+ :param chroot: The `LibraryFileAlias` for the chroot in which we are
970+ building.
971+ :param archive: The `IArchive` into which we are building.
972+ :param archive_purpose: The ArchivePurpose we are sending to the
973+ builder. We specify this separately from the archive because
974+ sometimes the behavior object has to give a different purpose
975+ in order to trick the slave into building correctly.
976+ :return: A list of the calls we expect to be made.
977+ """
978+ job = removeSecurityProxy(builder.current_build_behavior).buildfarmjob
979+ build_id = job.generateSlaveBuildCookie()
980+ ds_name = build.distro_arch_series.distroseries.name
981+ suite = ds_name + pocketsuffix[build.pocket]
982+ archives = get_sources_list_for_building(
983+ build, build.distro_arch_series,
984+ build.source_package_release.name)
985+ arch_indep = build.distro_arch_series.isNominatedArchIndep
986+ if filemap_names is None:
987+ filemap_names = []
988+ if extra_urls is None:
989+ extra_urls = []
990+
991+ upload_logs = [
992+ ['cacheFile', 'sendFileToSlave', ('ensurepresent', url, '', '')]
993+ for url in [chroot.http_url] + extra_urls]
994+
995+ extra_args = {
996+ 'arch_indep': arch_indep,
997+ 'arch_tag': build.distro_arch_series.architecturetag,
998+ 'archive_private': archive.private,
999+ 'archive_purpose': archive_purpose.name,
1000+ 'archives': archives,
1001+ 'build_debug_symbols': archive.build_debug_symbols,
1002+ 'ogrecomponent': component,
1003+ 'suite': suite,
1004+ }
1005+ build_log = [
1006+ ('build', build_id, 'binarypackage', chroot.content.sha1,
1007+ filemap_names, extra_args)]
1008+ return sum(upload_logs, []) + build_log
1009+
1010+ def startBuild(self, builder, candidate):
1011+ builder = removeSecurityProxy(builder)
1012+ candidate = removeSecurityProxy(candidate)
1013+ return defer.maybeDeferred(
1014+ builder.startBuild, candidate, QuietFakeLogger())
1015+
1016+ def test_non_virtual_ppa_dispatch(self):
1017+ # When the BinaryPackageBuildBehavior dispatches PPA builds to
1018+ # non-virtual builders, it stores the chroot on the server and
1019+ # requests a binary package build, lying to say that the archive
1020+ # purpose is "PRIMARY" because this ensures that the package mangling
1021+ # tools will run over the built packages.
1022+ archive = self.factory.makeArchive(virtualized=False)
1023+ slave = OkSlave()
1024+ builder = self.factory.makeBuilder(virtualized=False)
1025+ builder.setSlaveForTesting(slave)
1026+ build = self.factory.makeBinaryPackageBuild(
1027+ builder=builder, archive=archive)
1028+ lf = self.factory.makeLibraryFileAlias()
1029+ transaction.commit()
1030+ build.distro_arch_series.addOrUpdateChroot(lf)
1031+ candidate = build.queueBuild()
1032+ d = self.startBuild(builder, candidate)
1033+ d.addCallback(
1034+ self.assertExpectedInteraction, slave.call_log,
1035+ builder, build, lf, archive, ArchivePurpose.PRIMARY, 'universe')
1036+ return d
1037+
1038+ def test_partner_dispatch_no_publishing_history(self):
1039+ archive = self.factory.makeArchive(
1040+ virtualized=False, purpose=ArchivePurpose.PARTNER)
1041+ slave = OkSlave()
1042+ builder = self.factory.makeBuilder(virtualized=False)
1043+ builder.setSlaveForTesting(slave)
1044+ build = self.factory.makeBinaryPackageBuild(
1045+ builder=builder, archive=archive)
1046+ lf = self.factory.makeLibraryFileAlias()
1047+ transaction.commit()
1048+ build.distro_arch_series.addOrUpdateChroot(lf)
1049+ candidate = build.queueBuild()
1050+ d = self.startBuild(builder, candidate)
1051+ d.addCallback(
1052+ self.assertExpectedInteraction, slave.call_log,
1053+ builder, build, lf, archive,
1054+ ArchivePurpose.PARTNER, build.current_component.name)
1055+ return d
1056+
1057+ def test_dont_dispatch_release_builds(self):
1058+ archive = self.factory.makeArchive(purpose=ArchivePurpose.PRIMARY)
1059+ builder = self.factory.makeBuilder()
1060+ distroseries = self.factory.makeDistroSeries(
1061+ status=SeriesStatus.CURRENT, distribution=archive.distribution)
1062+ distro_arch_series = self.factory.makeDistroArchSeries(
1063+ distroseries=distroseries)
1064+ build = self.factory.makeBinaryPackageBuild(
1065+ builder=builder, archive=archive,
1066+ distroarchseries=distro_arch_series,
1067+ pocket=PackagePublishingPocket.RELEASE)
1068+ lf = self.factory.makeLibraryFileAlias()
1069+ transaction.commit()
1070+ build.distro_arch_series.addOrUpdateChroot(lf)
1071+ candidate = build.queueBuild()
1072+ behavior = candidate.required_build_behavior
1073+ behavior.setBuilder(build)
1074+ e = self.assertRaises(
1075+ AssertionError, behavior.verifyBuildRequest, QuietFakeLogger())
1076+ expected_message = (
1077+ "%s (%s) can not be built for pocket %s: invalid pocket due "
1078+ "to the series status of %s." % (
1079+ build.title, build.id, build.pocket.name,
1080+ build.distro_series.name))
1081+ self.assertEqual(expected_message, str(e))
1082+
1083+ def test_dont_dispatch_security_builds(self):
1084+ archive = self.factory.makeArchive(purpose=ArchivePurpose.PRIMARY)
1085+ builder = self.factory.makeBuilder()
1086+ build = self.factory.makeBinaryPackageBuild(
1087+ builder=builder, archive=archive,
1088+ pocket=PackagePublishingPocket.SECURITY)
1089+ lf = self.factory.makeLibraryFileAlias()
1090+ transaction.commit()
1091+ build.distro_arch_series.addOrUpdateChroot(lf)
1092+ candidate = build.queueBuild()
1093+ behavior = candidate.required_build_behavior
1094+ behavior.setBuilder(build)
1095+ e = self.assertRaises(
1096+ AssertionError, behavior.verifyBuildRequest, QuietFakeLogger())
1097+ self.assertEqual(
1098+ 'Soyuz is not yet capable of building SECURITY uploads.',
1099+ str(e))
1100
1101=== modified file 'lib/lp/testing/factory.py'
1102--- lib/lp/testing/factory.py 2010-09-21 11:45:15 +0000
1103+++ lib/lp/testing/factory.py 2010-09-22 10:37:47 +0000
1104@@ -1944,6 +1944,9 @@
1105 processorfamily = ProcessorFamilySet().getByName('powerpc')
1106 if owner is None:
1107 owner = self.makePerson()
1108+ # XXX: architecturetag & processerfamily are tightly coupled. It's
1109+ # wrong to just make a fresh architecture tag without also making a
1110+ # processor family to go with it (ideally with processors!)
1111 if architecturetag is None:
1112 architecturetag = self.getUniqueString('arch')
1113 return distroseries.newArch(
1114@@ -2625,7 +2628,7 @@
1115
1116 def makeBinaryPackageBuild(self, source_package_release=None,
1117 distroarchseries=None, archive=None, builder=None,
1118- status=None):
1119+ status=None, pocket=None):
1120 """Create a BinaryPackageBuild.
1121
1122 If archive is not supplied, the source_package_release is used
1123@@ -2656,13 +2659,15 @@
1124 processorfamily=processor.family)
1125 if status is None:
1126 status = BuildStatus.NEEDSBUILD
1127+ if pocket is None:
1128+ pocket = PackagePublishingPocket.RELEASE
1129 binary_package_build = getUtility(IBinaryPackageBuildSet).new(
1130 source_package_release=source_package_release,
1131 processor=processor,
1132 distro_arch_series=distroarchseries,
1133 status=status,
1134 archive=archive,
1135- pocket=PackagePublishingPocket.RELEASE,
1136+ pocket=pocket,
1137 date_created=self.getUniqueDate())
1138 naked_build = removeSecurityProxy(binary_package_build)
1139 naked_build.builder = builder
1140
1141=== modified file 'lib/lp/testing/tests/test_factory.py'
1142--- lib/lp/testing/tests/test_factory.py 2010-09-21 11:08:26 +0000
1143+++ lib/lp/testing/tests/test_factory.py 2010-09-22 10:37:47 +0000
1144@@ -113,6 +113,11 @@
1145 status=BuildStatus.FULLYBUILT)
1146 self.assertEqual(BuildStatus.FULLYBUILT, bpb.status)
1147
1148+ def test_makeBinaryPackageBuild_uses_pocket(self):
1149+ bpb = self.factory.makeBinaryPackageBuild(
1150+ pocket=PackagePublishingPocket.UPDATES)
1151+ self.assertEqual(PackagePublishingPocket.UPDATES, bpb.pocket)
1152+
1153 def test_makeBinaryPackageBuild_can_be_queued(self):
1154 build = self.factory.makeBinaryPackageBuild()
1155 # Just check that makeBinaryPackageBuild returns a build that can be