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