152
145
self.assertEqual(build_spns, self.expected_build_spns)
154
def createSourceDistroSeries(self):
155
"""Create a DistroSeries suitable for copying.
157
Creates a distroseries with a DistroArchSeries and nominatedarchindep,
158
which makes it suitable for copying because it will create some builds.
160
distro_name = "foobuntu"
161
distro = self.factory.makeDistribution(name=distro_name)
162
distroseries_name = "maudlin"
163
distroseries = self.factory.makeDistroSeries(
164
distribution=distro, name=distroseries_name)
165
das = self.factory.makeDistroArchSeries(
166
distroseries=distroseries, architecturetag="i386",
167
processorfamily=ProcessorFamilySet().getByName("x86"),
168
supports_virtualized=True)
169
distroseries.nominatedarchindep = das
172
def createTargetOwner(self):
173
"""Create a person suitable to own a copy archive."""
174
person_name = "copy-archive-owner"
175
owner = self.factory.makePerson(name=person_name)
178
def getTargetArchiveName(self, distribution):
179
"""Get a suitable name for a copy archive.
181
It also checks that the archive doesn't currently exist.
183
archive_name = "msa%s" % int(time.time())
184
copy_archive = getUtility(IArchiveSet).getByDistroPurpose(
185
distribution, ArchivePurpose.COPY, archive_name)
186
# This is a sanity check: a copy archive with this name should not
188
self.assertIs(None, copy_archive)
191
def createSourcePublication(self, info, distroseries):
192
"""Create a SourcePackagePublishingHistory based on a PackageInfo."""
193
if info.arch_hint is None:
196
arch_hint = info.arch_hint
198
self.factory.makeSourcePackagePublishingHistory(
199
sourcepackagename=self.factory.getOrMakeSourcePackageName(
201
distroseries=distroseries, component=self.factory.makeComponent(
203
version=info.version, architecturehintlist=arch_hint,
204
archive=distroseries.distribution.main_archive,
205
status=info.status, pocket=PackagePublishingPocket.RELEASE)
207
def createSourcePublications(self, package_infos, distroseries):
208
"""Create a source publication for each item in package_infos."""
209
for package_info in package_infos:
210
self.createSourcePublication(package_info, distroseries)
212
def getScript(self, test_args=None):
213
"""Return an ArchivePopulator instance."""
214
if test_args is None:
216
script = ArchivePopulator("test copy archives", test_args=test_args)
217
script.logger = QuietFakeLogger()
218
script.txn = self.layer.txn
221
def copyArchive(self, distroseries, archive_name, owner,
222
architectures=None, component="main", from_user=None,
223
from_archive=None, packageset_names=None, nonvirtualized=False):
224
"""Run the copy-archive script."""
226
'--from-distribution', distroseries.distribution.name,
227
'--from-suite', distroseries.name,
228
'--to-distribution', distroseries.distribution.name,
229
'--to-suite', distroseries.name,
230
'--to-archive', archive_name,
231
'--to-user', owner.name,
233
'"copy archive from %s"' % datetime.ctime(datetime.utcnow()),
234
'--component', component,
237
if from_user is not None:
238
extra_args.extend(["--from-user", from_user])
240
if from_archive is not None:
241
extra_args.extend(["--from-archive", from_archive])
243
if architectures is None:
244
architectures = ["386"]
247
extra_args.extend(["--nonvirtualized"])
249
for architecture in architectures:
250
extra_args.extend(['-a', architecture])
252
if packageset_names is None:
253
packageset_names = []
255
for packageset_name in packageset_names:
256
extra_args.extend(['--package-set', packageset_name])
258
script = self.getScript(test_args=extra_args)
261
# Make sure the copy archive with the desired name was
263
copy_archive = getUtility(IArchiveSet).getByDistroPurpose(
264
distroseries.distribution, ArchivePurpose.COPY, archive_name)
265
self.assertTrue(copy_archive is not None)
267
# Ascertain that the new copy archive was created with the 'enabled'
269
self.assertFalse(copy_archive.enabled)
271
# Assert the virtualization is correct.
272
virtual = not nonvirtualized
273
self.assertEqual(copy_archive.require_virtualized, virtual)
277
def checkCopiedSources(self, archive, distroseries, expected):
278
"""Check the sources published in an archive against an expected set.
280
Given an archive and a target distroseries the sources published in
281
that distroseries are checked against a set of PackageInfo to
282
ensure that the correct package names and versions are published.
284
expected_set = set([(info.name, info.version) for info in expected])
285
sources = archive.getPublishedSources(
286
distroseries=distroseries, status=self.pending_statuses)
288
for source in sources:
289
source = removeSecurityProxy(source)
291
(source.source_package_name, source.source_package_version))
292
self.assertEqual(expected_set, actual_set)
294
def createSourceDistribution(self, package_infos):
295
"""Create a distribution to be the source of a copy archive."""
296
distroseries = self.createSourceDistroSeries()
297
self.createSourcePublications(package_infos, distroseries)
300
def makeCopyArchive(self, package_infos, component="main",
301
nonvirtualized=False):
302
"""Make a copy archive based on a new distribution."""
303
owner = self.createTargetOwner()
304
distroseries = self.createSourceDistribution(package_infos)
305
archive_name = self.getTargetArchiveName(distroseries.distribution)
306
copy_archive = self.copyArchive(
307
distroseries, archive_name, owner, component=component,
308
nonvirtualized=nonvirtualized)
309
return (copy_archive, distroseries)
311
def checkBuilds(self, archive, package_infos):
312
"""Check the build records pending in an archive.
314
Given a set of PackageInfo objects check that each has a build
317
expected_builds = list(
318
[(info.name, info.version) for info in package_infos])
320
getUtility(IBinaryPackageBuildSet).getBuildsForArchive(
321
archive, status=BuildStatus.NEEDSBUILD))
322
actual_builds = list()
324
naked_build = removeSecurityProxy(build)
325
spr = naked_build.source_package_release
326
actual_builds.append((spr.name, spr.version))
327
self.assertEqual(sorted(expected_builds), sorted(actual_builds))
329
def testCopyArchiveRunScript(self):
330
"""Check that we can exec the script to copy an archive."""
331
package_info = PackageInfo(
332
"bzr", "2.1", status=PackagePublishingStatus.PUBLISHED)
333
owner = self.createTargetOwner()
334
distroseries = self.createSourceDistribution([package_info])
335
archive_name = self.getTargetArchiveName(distroseries.distribution)
336
# We must commit as we are going to exec a script that will run
337
# in a different transaction and must be able to see the
338
# objects we just created.
342
'--from-distribution', distroseries.distribution.name,
343
'--from-suite', distroseries.name,
344
'--to-distribution', distroseries.distribution.name,
345
'--to-suite', distroseries.name,
346
'--to-archive', archive_name,
347
'--to-user', owner.name,
349
'"copy archive from %s"' % datetime.ctime(datetime.utcnow()),
350
'--component', "main",
353
(exitcode, out, err) = self.runWrapperScript(extra_args)
354
# Check for zero exit code.
356
exitcode, 0, "\n=> %s\n=> %s\n=> %s\n" % (exitcode, out, err))
357
# Make sure the copy archive with the desired name was
359
copy_archive = getUtility(IArchiveSet).getByDistroPurpose(
360
distroseries.distribution, ArchivePurpose.COPY, archive_name)
361
self.assertTrue(copy_archive is not None)
363
# Ascertain that the new copy archive was created with the 'enabled'
365
self.assertFalse(copy_archive.enabled)
367
# Also, make sure that the builds for the new copy archive will be
368
# carried out on non-virtual builders.
369
self.assertTrue(copy_archive.require_virtualized)
370
self.checkCopiedSources(
371
copy_archive, distroseries, [package_info])
373
def testCopyArchiveCreateCopiesPublished(self):
374
"""Test that PUBLISHED sources are copied."""
375
package_info = PackageInfo(
376
"bzr", "2.1", status=PackagePublishingStatus.PUBLISHED)
377
copy_archive, distroseries = self.makeCopyArchive([package_info])
378
self.checkCopiedSources(
379
copy_archive, distroseries, [package_info])
381
def testCopyArchiveCreateCopiesPending(self):
382
"""Test that PENDING sources are copied."""
383
package_info = PackageInfo(
384
"bzr", "2.1", status=PackagePublishingStatus.PENDING)
385
copy_archive, distroseries = self.makeCopyArchive([package_info])
386
self.checkCopiedSources(
387
copy_archive, distroseries, [package_info])
389
def testCopyArchiveCreateDoesntCopySuperseded(self):
390
"""Test that SUPERSEDED sources are not copied."""
391
package_info = PackageInfo(
392
"bzr", "2.1", status=PackagePublishingStatus.SUPERSEDED)
393
copy_archive, distroseries = self.makeCopyArchive([package_info])
394
self.checkCopiedSources(
395
copy_archive, distroseries, [])
397
def testCopyArchiveCreateDoesntCopyDeleted(self):
398
"""Test that DELETED sources are not copied."""
399
package_info = PackageInfo(
400
"bzr", "2.1", status=PackagePublishingStatus.DELETED)
401
copy_archive, distroseries = self.makeCopyArchive([package_info])
402
self.checkCopiedSources(
403
copy_archive, distroseries, [])
405
def testCopyArchiveCreateDoesntCopyObsolete(self):
406
"""Test that OBSOLETE sources are not copied."""
407
package_info = PackageInfo(
408
"bzr", "2.1", status=PackagePublishingStatus.OBSOLETE)
409
copy_archive, distroseries = self.makeCopyArchive([package_info])
410
self.checkCopiedSources(
411
copy_archive, distroseries, [])
413
def testCopyArchiveCreatesBuilds(self):
414
"""Test that a copy archive creates builds for the copied packages."""
415
package_info = PackageInfo(
416
"bzr", "2.1", status=PackagePublishingStatus.PUBLISHED)
417
copy_archive, distroseries = self.makeCopyArchive([package_info])
418
self.checkBuilds(copy_archive, [package_info])
420
def testCopyArchiveArchTagNotAvailableInSource(self):
421
"""Test creating a copy archive for an arch not in the source.
423
If we request a copy to an architecture that doesn't have
424
a DistroArchSeries in the source then we won't get any builds
425
created in the copy archive.
427
family = self.factory.makeProcessorFamily(name="armel")
428
self.factory.makeProcessor(family=family, name="armel")
429
package_info = PackageInfo(
430
"bzr", "2.1", status=PackagePublishingStatus.PUBLISHED)
431
owner = self.createTargetOwner()
432
# Creates an archive with just x86
433
distroseries = self.createSourceDistribution([package_info])
434
archive_name = self.getTargetArchiveName(distroseries.distribution)
435
# Different architecture, so there won't be any builds
436
copy_archive = self.copyArchive(
437
distroseries, archive_name, owner, architectures=["armel"])
438
self.checkBuilds(copy_archive, [])
440
# Also, make sure the package copy request status was updated.
442
IPackageCopyRequestSet).getByTargetArchive(copy_archive)
443
self.assertTrue(pcr.status == PackageCopyStatus.COMPLETE)
445
# This date is set when the copy request makes the transition to
446
# the "in progress" state.
447
self.assertTrue(pcr.date_started is not None)
448
# This date is set when the copy request makes the transition to
449
# the "completed" state.
450
self.assertTrue(pcr.date_completed is not None)
451
self.assertTrue(pcr.date_started <= pcr.date_completed)
453
def testMultipleArchTagsWithSubsetInSource(self):
454
"""Try copy archive population with multiple architecture tags.
456
The user may specify a number of given architecture tags on the
458
The script should create build records only for the specified
459
architecture tags that are supported by the destination distro series.
461
In this (test) case the script should create the build records for the
464
family = self.factory.makeProcessorFamily(name="armel")
465
self.factory.makeProcessor(family=family, name="armel")
466
package_info = PackageInfo(
467
"bzr", "2.1", status=PackagePublishingStatus.PUBLISHED)
468
owner = self.createTargetOwner()
469
# Creates an archive with just x86
470
distroseries = self.createSourceDistribution([package_info])
471
archive_name = self.getTargetArchiveName(distroseries.distribution)
472
# There is only a DAS for i386, so armel won't produce any
474
copy_archive = self.copyArchive(
475
distroseries, archive_name, owner,
476
architectures=["386", "armel"])
477
self.checkBuilds(copy_archive, [package_info])
479
def testCopyArchiveCreatesSubsetOfBuilds(self):
480
"""Create a copy archive with a subset of the architectures.
482
We copy from an archive with multiple architecture DistroArchSeries,
483
but request only one of those architectures in the target,
484
so we only get builds for that one architecture.
486
package_info = PackageInfo(
487
"bzr", "2.1", status=PackagePublishingStatus.PUBLISHED)
488
owner = self.createTargetOwner()
489
distroseries = self.createSourceDistribution([package_info])
490
self.factory.makeDistroArchSeries(
491
distroseries=distroseries, architecturetag="amd64",
492
processorfamily=ProcessorFamilySet().getByName("amd64"),
493
supports_virtualized=True)
494
archive_name = self.getTargetArchiveName(distroseries.distribution)
495
copy_archive = self.copyArchive(
496
distroseries, archive_name, owner,
497
architectures=["386"])
498
# We only get a single build, as we only requested 386, not
500
self.checkBuilds(copy_archive, [package_info])
502
def testNoBuildsForArchAll(self):
503
# If we have a copy for an architecture that is not the
504
# nominatedarchindep architecture, then we don't want to create
505
# builds for arch-all packages, as they can't be built at all
506
# and createMissingBuilds blows up when it checks that.
507
package_info = PackageInfo(
508
"bzr", "2.1", status=PackagePublishingStatus.PUBLISHED,
510
owner = self.createTargetOwner()
511
distroseries = self.createSourceDistribution([package_info])
512
self.factory.makeDistroArchSeries(
513
distroseries=distroseries, architecturetag="amd64",
514
processorfamily=ProcessorFamilySet().getByName("amd64"),
515
supports_virtualized=True)
516
archive_name = self.getTargetArchiveName(distroseries.distribution)
517
copy_archive = self.copyArchive(
518
distroseries, archive_name, owner,
519
architectures=["amd64"])
520
# We don't get any builds since amd64 is not the
521
# nomindatedarchindep, i386 is.
523
distroseries.nominatedarchindep.architecturetag, "i386")
524
self.checkBuilds(copy_archive, [])
526
def testMultipleArchTags(self):
527
"""Test copying an archive with multiple architectures.
529
We create a source with two architectures, and then request
530
a copy of both, so we get a build for each of those architectures.
532
package_info = PackageInfo(
533
"bzr", "2.1", status=PackagePublishingStatus.PUBLISHED)
534
owner = self.createTargetOwner()
535
distroseries = self.createSourceDistribution([package_info])
536
self.factory.makeDistroArchSeries(
537
distroseries=distroseries, architecturetag="amd64",
538
processorfamily=ProcessorFamilySet().getByName("amd64"),
539
supports_virtualized=True)
540
archive_name = self.getTargetArchiveName(distroseries.distribution)
541
copy_archive = self.copyArchive(
542
distroseries, archive_name, owner,
543
architectures=["386", "amd64"])
544
self.checkBuilds(copy_archive, [package_info, package_info])
546
def testCopyArchiveCopiesRightComponents(self):
547
"""Test that packages from the right components are copied.
549
When copying you specify a component, that component should
550
limit the packages copied. We create a source in main and one in
551
universe, and then copy with --component main, and expect to see
552
only main in the copy.
554
package_info_universe = PackageInfo(
555
"bzr", "2.1", status=PackagePublishingStatus.PUBLISHED,
556
component="universe")
557
package_info_main = PackageInfo(
558
"apt", "2.2", status=PackagePublishingStatus.PUBLISHED,
560
package_infos_both = [package_info_universe, package_info_main]
561
copy_archive, distroseries = self.makeCopyArchive(
562
package_infos_both, component="main")
563
self.checkBuilds(copy_archive, [package_info_main])
565
def testCopyArchiveSubsetsBasedOnPackageset(self):
566
"""Test that --package-set limits the sources copied."""
569
"bzr", "2.1", status=PackagePublishingStatus.PUBLISHED),
571
"apt", "2.2", status=PackagePublishingStatus.PUBLISHED),
573
owner = self.createTargetOwner()
574
distroseries = self.createSourceDistribution(package_infos)
575
packageset_name = u"apt-packageset"
576
spn = self.factory.getOrMakeSourcePackageName(name="apt")
577
self.factory.makePackageset(
578
name=packageset_name, distroseries=distroseries, packages=(spn,))
579
archive_name = self.getTargetArchiveName(distroseries.distribution)
580
copy_archive = self.copyArchive(
581
distroseries, archive_name, owner,
582
packageset_names=[packageset_name])
583
self.checkCopiedSources(
584
copy_archive, distroseries, [package_infos[1]])
586
def testCopyArchiveUnionsPackagesets(self):
587
"""Test that package sets are unioned when copying archives."""
590
"bzr", "2.1", status=PackagePublishingStatus.PUBLISHED),
592
"apt", "2.2", status=PackagePublishingStatus.PUBLISHED),
594
"gcc", "4.5", status=PackagePublishingStatus.PUBLISHED),
596
owner = self.createTargetOwner()
597
distroseries = self.createSourceDistribution(package_infos)
598
apt_packageset_name = u"apt-packageset"
599
apt_spn = self.factory.getOrMakeSourcePackageName(name="apt")
600
gcc_packageset_name = u"gcc-packageset"
601
gcc_spn = self.factory.getOrMakeSourcePackageName(name="gcc")
602
self.factory.makePackageset(
603
name=apt_packageset_name, distroseries=distroseries,
605
self.factory.makePackageset(
606
name=gcc_packageset_name, distroseries=distroseries,
608
archive_name = self.getTargetArchiveName(distroseries.distribution)
609
copy_archive = self.copyArchive(
610
distroseries, archive_name, owner,
611
packageset_names=[apt_packageset_name, gcc_packageset_name])
612
self.checkCopiedSources(
613
copy_archive, distroseries, package_infos[1:])
615
def testCopyArchiveRecursivelyCopiesPackagesets(self):
616
"""Test that package set copies include subsets."""
619
"bzr", "2.1", status=PackagePublishingStatus.PUBLISHED),
621
"apt", "2.2", status=PackagePublishingStatus.PUBLISHED),
623
"gcc", "4.5", status=PackagePublishingStatus.PUBLISHED),
625
owner = self.createTargetOwner()
626
distroseries = self.createSourceDistribution(package_infos)
627
apt_packageset_name = u"apt-packageset"
628
apt_spn = self.factory.getOrMakeSourcePackageName(name="apt")
629
gcc_packageset_name = u"gcc-packageset"
630
gcc_spn = self.factory.getOrMakeSourcePackageName(name="gcc")
631
apt_packageset = self.factory.makePackageset(
632
name=apt_packageset_name, distroseries=distroseries,
634
gcc_packageset = self.factory.makePackageset(
635
name=gcc_packageset_name, distroseries=distroseries,
637
apt_packageset.add((gcc_packageset,))
638
archive_name = self.getTargetArchiveName(distroseries.distribution)
639
copy_archive = self.copyArchive(
640
distroseries, archive_name, owner,
641
packageset_names=[apt_packageset_name])
642
self.checkCopiedSources(
643
copy_archive, distroseries, package_infos[1:])
645
def testCopyFromPPA(self):
646
"""Test we can create a copy archive with a PPA as the source."""
647
ppa_owner_name = "ppa-owner"
649
ppa_owner = self.factory.makePerson(name=ppa_owner_name)
650
distroseries = self.createSourceDistroSeries()
651
ppa = self.factory.makeArchive(
652
name=ppa_name, purpose=ArchivePurpose.PPA,
653
distribution=distroseries.distribution, owner=ppa_owner)
654
package_info = PackageInfo(
655
"bzr", "2.1", status=PackagePublishingStatus.PUBLISHED,
656
component="universe")
657
self.factory.makeSourcePackagePublishingHistory(
658
sourcepackagename=self.factory.getOrMakeSourcePackageName(
659
name=package_info.name),
660
distroseries=distroseries, component=self.factory.makeComponent(
661
package_info.component),
662
version=package_info.version, archive=ppa,
663
status=package_info.status, architecturehintlist='any',
664
pocket=PackagePublishingPocket.RELEASE)
665
owner = self.createTargetOwner()
666
archive_name = self.getTargetArchiveName(distroseries.distribution)
667
copy_archive = self.copyArchive(
668
distroseries, archive_name, owner, from_user=ppa_owner_name,
669
from_archive=ppa_name, component=package_info.component)
670
self.checkCopiedSources(
671
copy_archive, distroseries, [package_info])
674
148
self, archive_name=None, suite='hoary', user='salgado',
675
149
exists_before=None, exists_after=None, exception_type=None,
676
150
exception_text=None, extra_args=None, copy_archive_name=None,
677
reason=None, output_substr=None):
151
reason=None, output_substr=None, nonvirtualized=False):
678
152
"""Run the script to test.
680
154
:type archive_name: `str`