~launchpad-pqm/launchpad/devel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
= The Queue Builder =

QueueBuilder is a script to sanely initialize new build jobs. It
verifies each DistroArchSeries that is available for which we are
able to:

 * Build packages,
 * Repair broken Build entries, if it makes sense to do so,
 * Verify the packages pending to build,
 * Install the jobs in the BuildQueue table, and
 * Score the build according to a set of parameters, which will be
   discussed later.


== Setting up ==

    >>> from lp.soyuz.scripts.buildd import QueueBuilder

Import the bunch of required database classes:

    >>> from lp.buildmaster.model.buildqueue import BuildQueue
    >>> from lp.registry.interfaces.pocket import PackagePublishingPocket
    >>> from lp.registry.model.distroseries import DistroSeries
    >>> from lp.soyuz.enums import PackagePublishingStatus
    >>> from lp.soyuz.model.binarypackagebuild import BinaryPackageBuild
    >>> from lp.soyuz.model.distroarchseries import (
    ...     DistroArchSeries, PocketChroot)

The Master side of Buildd requires access to Launchpad Database, the
user designed for this kind of access is 'fiera', see
test_system_documentation.py for more information.

    >>> from lp.services.log.logger import DevNullLogger
    >>> logger = DevNullLogger()

Now that we have satisfied all of the needs for QueueBuilder, let's
instantiate it.

If I pass the current 'transaction' to QueueBuilder it will call
commit() on it for it build created. It apparently mess with the
transaction manager is a way that the builds created in the sampledata
catch-up (line 103) do not persist for the test build creation (line
469). This issue results in new build records exactly for the same
souces and locations but with higher IDs.

    >>> class FakeZtm:
    ...     def commit(self):
    ...         flush_database_updates()

    >>> queue_builder = QueueBuilder(name='queue-builder', test_args=[])
    >>> queue_builder.txn = FakeZtm()
    >>> queue_builder.logger = logger

Emulate a PocketChroot entry to validate the following
distroarchseries:

 * Ubuntu/Warty/i386/RELEASE
 * Ubuntu/Hoary/i386/RELEASE
 * Debian/Woody/i386/RELEASE

    >>> warty = DistroSeries.selectOneBy(name="warty")
    >>> unused = PocketChroot(distroarchseries=warty['i386'], chroot=1)

    >>> hoary = DistroSeries.selectOneBy(name='hoary')
    >>> unsused = PocketChroot(distroarchseries=hoary['i386'], chroot=1)
    >>> unused = PocketChroot(distroarchseries=hoary['hppa'], chroot=2)

    >>> ubuntu = hoary.distribution
    >>> breezy_autotest = ubuntu.getSeries('breezy-autotest')
    >>> breezy_autotest_i386 = breezy_autotest['i386']
    >>> unused = PocketChroot(
    ...     distroarchseries=breezy_autotest_i386, chroot=3)

    >>> woody = DistroSeries.selectOneBy(name='woody')
    >>> unused = PocketChroot(distroarchseries=woody['i386'], chroot=4)

Produce a set of available DistroArchSeries, for which the
build jobs will be created.

    >>> distroseries = set()
    >>> archseries = set()

    >>> for das in DistroArchSeries.select():
    ...     distroseries.add(das.distroseries)
    ...     if das.getChroot():
    ...         archseries.add(das)

    >>> import operator
    >>> distroseries = sorted(
    ...     distroseries, key=operator.attrgetter('name'))

Among all the available distroarchseries only the one with chroot will
be considered.

    >>> for arch in sorted(archseries, key=operator.attrgetter('id')):
    ...     print arch.title
    The Warty Warthog Release for i386 (x86)
    The Hoary Hedgehog Release for i386 (x86)
    WOODY for i386 (x86)
    Breezy Badger Autotest for i386 (x86)
    The Hoary Hedgehog Release for hppa (hppa)


== Ensure sampledata is processed ==

Kick off any pending builds we have to avoid any misleading result in
our tests (there are a couple that will be created based on our
sampledata).

This is to allow us to study carefully what is being added as we add
new series and builds.

    >>> for series in distroseries:
    ...      queue_builder.createMissingBuilds(series)

Add the missing build queue entries.

    >>> queue_builder.addMissingBuildQueueEntries(archseries)

Store current status of the database:

    >>> old_build_ids = [build.id for build in BinaryPackageBuild.select()]
    >>> old_job_ids = [build_queue.id for build_queue in BuildQueue.select()]


== Create some series and publications ==

We will create a group of source publications that represent the
exact circumstances we want to test below.

    >>> from lp.registry.interfaces.person import IPersonSet
    >>> cprov = getUtility(IPersonSet).getByName('cprov')

    >>> from canonical.database.sqlbase import commit
    >>> from lp.soyuz.tests.test_publishing import (
    ...     SoyuzTestPublisher)
    >>> from canonical.testing.layers import LaunchpadZopelessLayer

    >>> commit()
    >>> LaunchpadZopelessLayer.switchDbUser('launchpad')

Let's use SoyuzTestPublisher to create a set of publications in the
exact state to expose the features that we want to test.

    >>> test_publisher = SoyuzTestPublisher()
    >>> test_publisher.prepareBreezyAutotest()

Publishing a source in debian/woody won't result in a new build
because this distroseries lacks 'nominatedarchindep'.

    >>> pub_woody = test_publisher.getPubSource(
    ...     sourcename='test-buildd-5', version='671', distroseries=woody,
    ...     architecturehintlist="hppa",
    ...     status=PackagePublishingStatus.PUBLISHED,
    ...     pocket=PackagePublishingPocket.RELEASE)

Several source publications for ubuntu/hoary/RELEASE, which is in
DEVELOPMENT state, so we expect builds to be created respecting
architecturehintlist and PAS restrictions. See details about the PAS
system below.

    >>> pub_all = test_publisher.getPubSource(
    ...     sourcename='test-buildd', version='667', distroseries=hoary,
    ...     status=PackagePublishingStatus.PUBLISHED,
    ...     pocket=PackagePublishingPocket.RELEASE)

    >>> pub_any = test_publisher.getPubSource(
    ...     sourcename='test-buildd-2', version='668', distroseries=hoary,
    ...     architecturehintlist="any",
    ...     status=PackagePublishingStatus.PUBLISHED,
    ...     pocket=PackagePublishingPocket.RELEASE)

    >>> pub_three = test_publisher.getPubSource(
    ...     sourcename='test-buildd-3', version='669', distroseries=hoary,
    ...     architecturehintlist="i386 hppa amd64",
    ...     status=PackagePublishingStatus.PUBLISHED,
    ...     pocket=PackagePublishingPocket.RELEASE)

    >>> pub_one = test_publisher.getPubSource(
    ...     sourcename='test-buildd-4', version='670', distroseries=hoary,
    ...     architecturehintlist="hppa",
    ...     status=PackagePublishingStatus.PUBLISHED,
    ...     pocket=PackagePublishingPocket.RELEASE)

The two publishing sources that are created in this block are only used
in the 'Check support for kernel notation in architecture hint list'
section.

    >>> pub_any_foo = test_publisher.getPubSource(
    ...     sourcename='test-buildd-6', version='672', distroseries=hoary,
    ...     architecturehintlist="any-hppa",
    ...     status=PackagePublishingStatus.PUBLISHED,
    ...     pocket=PackagePublishingPocket.RELEASE)

    >>> pub_linux_foo = test_publisher.getPubSource(
    ...     sourcename='test-buildd-7', version='673', distroseries=hoary,
    ...     architecturehintlist="linux-i386",
    ...     status=PackagePublishingStatus.PUBLISHED,
    ...     pocket=PackagePublishingPocket.RELEASE)

Publishing a source in warty/UPDATES, a stable release update (SRU),
will result in a build. Once a distroseries is released, only
source publications to post-RELEASE pockets (UPDATES, PROPOSED,
BACKPORTS, SECURITY) will be considered, preserving the RELEASE pocket
as it was at the release time.

    >>> pub_updates = test_publisher.getPubSource(
    ...     sourcename='test-updates', version='665', distroseries=warty,
    ...     status=PackagePublishingStatus.PUBLISHED,
    ...     pocket=PackagePublishingPocket.UPDATES)

A source published in warty/RELEASE will be ignored, i.e., it won't
result in a new build record because we cannot modify the RELEASE
pocket.

    >>> pub_ignored = test_publisher.getPubSource(
    ...     sourcename='test-buildd-not', version='666', distroseries=warty,
    ...     status=PackagePublishingStatus.PUBLISHED,
    ...     pocket=PackagePublishingPocket.RELEASE)

If we publish the same source in warty and hoary, and create a
corresponding build record that has failed to build in this context,
we see that the queue-builder triggers a rebuild in the new context
for published sources that have failed to build in previous
distroseries (see bug 181328).

    >>> pub_failed = test_publisher.getPubSource(
    ...     sourcename='test-failed', version='1.0', distroseries=warty,
    ...     status=PackagePublishingStatus.PUBLISHED,
    ...     pocket=PackagePublishingPocket.RELEASE)

    >>> copied_pub = pub_failed.copyTo(
    ...     hoary, PackagePublishingPocket.RELEASE, warty.main_archive)

    >>> from lp.buildmaster.enums import BuildStatus
    >>> from lp.soyuz.interfaces.binarypackagebuild import (
    ...     IBinaryPackageBuildSet)
    >>> failed_build = pub_failed.sourcepackagerelease.createBuild(
    ...     warty['i386'], PackagePublishingPocket.RELEASE,
    ...     warty.main_archive, status=BuildStatus.FAILEDTOBUILD)

In contrast with the previous case, if we publish the same source in
warty and hoary, and attach a successfully built build record in the
warty context we will see that the queue-builder won't create a new
build in the hoary context.

    >>> pub_success = test_publisher.getPubSource(
    ...     sourcename='test-success', version='1.0', distroseries=warty,
    ...     status=PackagePublishingStatus.PUBLISHED,
    ...     pocket=PackagePublishingPocket.RELEASE)

    >>> copied_pub = pub_success.copyTo(
    ...     hoary, PackagePublishingPocket.RELEASE, warty.main_archive)

    >>> ok_build = pub_success.sourcepackagerelease.createBuild(
    ...     warty['i386'], PackagePublishingPocket.RELEASE,
    ...     warty.main_archive, status=BuildStatus.FULLYBUILT)

If a source is published in Celso's PPA, a build will be created
for it respecting only 'architecturehintlist' and PPA-supported
architecture, it won't be submitted to P-a-s restrictions. It allows
PPA user to work on 'broken' ports of a given source, without
depending on lifting the PRIMARY archive PAS restrictions.

    >>> pub_hoary_ppa = test_publisher.getPubSource(
    ...     sourcename='test-ppa', version='674', distroseries=hoary,
    ...     architecturehintlist="i386 hppa", archive=cprov.archive,
    ...     status=PackagePublishingStatus.PUBLISHED,
    ...     pocket=PackagePublishingPocket.RELEASE)

We will remove the virtualization support from
ubuntu/breezy-autotest/i386, so we can verify that when a distroseries
exists but does not support any PPA archictecture the source
publications in PPA context are ignored; they don't result in any
build nor a misleading error in determineArchitectureToBuild.

    >>> breezy_autotest_i386.supports_virtualized = False

    >>> pub_breezy_autotest_ppa = test_publisher.getPubSource(
    ...     sourcename='test-no-ppa-support', version='999',
    ...     distroseries=breezy_autotest, archive=cprov.archive,
    ...     status=PackagePublishingStatus.PUBLISHED,
    ...     pocket=PackagePublishingPocket.RELEASE)

Before committing the previous changes, we have to annotated the
manually created build IDs so they can be excluded from subsequents
checks/counters within this test.

    >>> old_build_ids.append(failed_build.id)
    >>> old_build_ids.append(ok_build.id)

    >>> commit()
    >>> LaunchpadZopelessLayer.switchDbUser(test_dbuser)


== Create and verify the new builds ==

Create missing builds (packages w/o build entry) for those distroseries.

We expect to have a couple of new builds for the sane hoary/RELEASE,
one for warty/UPDATES and one for hoary/RELEASE/PPA.

    >>> for series in distroseries:
    ...      queue_builder.createMissingBuilds(series)

Check that we only created new Build entries for the new hoary releases:

    >>> new_builds = [build for build in BinaryPackageBuild.select()
    ...               if build.id not in old_build_ids]
    >>> for build in sorted(new_builds, key=operator.attrgetter('id')):
    ...   print build.title
    i386 build of test-buildd 667 in ubuntu hoary RELEASE
    hppa build of test-buildd-2 668 in ubuntu hoary RELEASE
    i386 build of test-buildd-2 668 in ubuntu hoary RELEASE
    hppa build of test-buildd-3 669 in ubuntu hoary RELEASE
    i386 build of test-buildd-3 669 in ubuntu hoary RELEASE
    hppa build of test-buildd-4 670 in ubuntu hoary RELEASE
    hppa build of test-buildd-6 672 in ubuntu hoary RELEASE
    i386 build of test-buildd-7 673 in ubuntu hoary RELEASE
    i386 build of test-failed 1.0 in ubuntu hoary RELEASE
    i386 build of test-ppa 674 in ubuntu hoary RELEASE
    i386 build of test-updates 665 in ubuntu warty UPDATES

And have a look at our architecture-independent-source's build:

    >>> arch_indep_build = BinaryPackageBuild.selectOneBy(
    ...     source_package_release=pub_all.sourcepackagerelease)

    >>> print arch_indep_build.title
    i386 build of test-buildd 667 in ubuntu hoary RELEASE


== Create and verify the new queue entries ==

BuildQueue records corresponding to the build records in NEEDSBUILD
state are immediately created.

    >>> active_jobs = [
    ...     build_queue for build_queue in BuildQueue.select(orderBy='id')
    ...     if build_queue.id not in old_job_ids]
    >>> len(active_jobs)
    11

The BuildQueue entries created are already 'scored', meaning the job
can be dispatched once operation is committed, i.e. dispatching can
happen in parallel with build creation.

    >>> build_queue = active_jobs[0]
    >>> build = getUtility(IBinaryPackageBuildSet).getByQueueEntry(
    ...     build_queue)
    >>> print build.title
    i386 build of test-buildd 667 in ubuntu hoary RELEASE
    >>> build_queue.lastscore
    2505

Check the published component name retriever, they might be different,
i.e., the published component can be different than the original component.

    >>> print build.current_component.name
    main
    >>> print build.source_package_release.component.name
    main

Missing BuildQueue records, resulting from given-back builds, are
created in the last stage of the queue-builder script.

    >>> given_back_build = getUtility(IBinaryPackageBuildSet).getByQueueEntry(
    ...     build_queue)
    >>> build_queue.destroySelf()
    >>> flush_database_updates()

    >>> print given_back_build.buildqueue_record
    None

    >>> queue_builder.addMissingBuildQueueEntries(archseries)

    >>> given_back_build.buildqueue_record is not None
    True