~launchpad-pqm/launchpad/devel

« back to all changes in this revision

Viewing changes to lib/lp/soyuz/tests/test_packagecopyjob.py

[rs=buildbot-poller] automatic merge from stable. Revisions: 13201,
        13202, 13203, 13204, 13205 included.

Show diffs side-by-side

added added

removed removed

Lines of Context:
12
12
from zope.component import getUtility
13
13
from zope.security.proxy import removeSecurityProxy
14
14
 
 
15
from storm.store import Store
 
16
 
15
17
from canonical.config import config
16
18
from canonical.launchpad.interfaces.lpstorm import IStore
17
19
from canonical.launchpad.webapp.testing import verifyObject
20
22
    DistroSeriesDifferenceComment,
21
23
    )
22
24
from lp.registry.interfaces.pocket import PackagePublishingPocket
 
25
from lp.registry.interfaces.series import SeriesStatus
23
26
from lp.services.features.testing import FeatureFixture
24
 
from lp.services.job.interfaces.job import JobStatus
 
27
from lp.services.job.interfaces.job import (
 
28
    JobStatus,
 
29
    SuspendJobException,
 
30
    )
25
31
from lp.soyuz.adapters.overrides import SourceOverride
26
32
from lp.soyuz.enums import (
27
33
    ArchivePurpose,
28
34
    PackageCopyPolicy,
 
35
    PackageUploadStatus,
29
36
    SourcePackageFormat,
30
37
    )
31
38
from lp.soyuz.model.distroseriesdifferencejob import (
32
39
    FEATURE_FLAG_ENABLE_MODULE,
33
40
    )
 
41
from lp.soyuz.model.queue import PackageUpload
34
42
from lp.soyuz.interfaces.archive import CannotCopy
35
43
from lp.soyuz.interfaces.component import IComponentSet
36
44
from lp.soyuz.interfaces.packagecopyjob import (
39
47
    IPlainPackageCopyJobSource,
40
48
    )
41
49
from lp.soyuz.interfaces.publishing import PackagePublishingStatus
 
50
from lp.soyuz.interfaces.queue import IPackageUploadSet
42
51
from lp.soyuz.interfaces.section import ISectionSet
43
52
from lp.soyuz.interfaces.sourcepackageformat import (
44
53
    ISourcePackageFormatSelectionSet,
48
57
    run_script,
49
58
    TestCaseWithFactory,
50
59
    )
 
60
from lp.testing.mail_helpers import pop_notifications
51
61
from lp.testing.fakemethod import FakeMethod
52
62
 
53
63
 
61
71
class LocalTestHelper:
62
72
    """Put test helpers that want to be in the test classes here."""
63
73
 
 
74
    dbuser = config.IPlainPackageCopyJobSource.dbuser
 
75
 
64
76
    def makeJob(self, dsd=None, **kwargs):
65
77
        """Create a `PlainPackageCopyJob` that would resolve `dsd`."""
66
78
        if dsd is None:
77
89
    def runJob(self, job):
78
90
        """Helper to switch to the right DB user and run the job."""
79
91
        self.layer.txn.commit()
80
 
        self.layer.switchDbUser('sync_packages')
 
92
        self.layer.switchDbUser(self.dbuser)
81
93
        job.run()
82
94
 
83
95
 
284
296
            distroseries=distroseries, sourcename="libc",
285
297
            version="2.8-1", status=PackagePublishingStatus.PUBLISHED,
286
298
            archive=breezy_archive)
 
299
        # The target archive needs ancestry so the package is
 
300
        # auto-accepted.
 
301
        ancestry = publisher.getPubSource(
 
302
            distroseries=target_series, sourcename="libc",
 
303
            version="2.8-0", status=PackagePublishingStatus.PUBLISHED,
 
304
            archive=target_archive)
287
305
 
288
306
        source = getUtility(IPlainPackageCopyJobSource)
289
307
        job = source.create(
298
316
        # Make sure everything hits the database, switching db users
299
317
        # aborts.
300
318
        transaction.commit()
301
 
        # XXX: GavinPanella 2011-04-20 bug=770297: The sync_packages database
302
 
        # user should be renamed to copy_packages.
303
 
        self.layer.switchDbUser('sync_packages')
 
319
        self.layer.switchDbUser(self.dbuser)
304
320
        job.run()
305
321
 
306
 
        published_sources = target_archive.getPublishedSources()
307
 
        spr = published_sources.one().sourcepackagerelease
308
 
        self.assertEquals("libc", spr.name)
309
 
        self.assertEquals("2.8-1", spr.version)
 
322
        published_sources = target_archive.getPublishedSources(
 
323
            name="libc", version="2.8-1")
 
324
        self.assertIsNot(None, published_sources.any())
 
325
 
 
326
        # The copy should have sent an email too. (see
 
327
        # soyuz/scripts/tests/test_copypackage.py for detailed
 
328
        # notification tests)
 
329
        emails = pop_notifications()
 
330
        self.assertTrue(len(emails) > 0)
310
331
 
311
332
        # Switch back to a db user that has permission to clean up
312
333
        # featureflag.
455
476
        self.assertEqual(
456
477
            {}, job_source.getPendingJobsPerPackage(dsd.derived_series))
457
478
 
 
479
    def test_copying_to_main_archive_ancestry_overrides(self):
 
480
        # The job will complete right away for auto-approved copies to a
 
481
        # main archive and apply any ancestry overrides.
 
482
        publisher = SoyuzTestPublisher()
 
483
        publisher.prepareBreezyAutotest()
 
484
        distroseries = publisher.breezy_autotest
 
485
 
 
486
        target_archive = self.factory.makeArchive(
 
487
            distroseries.distribution, purpose=ArchivePurpose.PRIMARY)
 
488
        source_archive = self.factory.makeArchive()
 
489
 
 
490
        # Publish a package in the source archive with some overridable
 
491
        # properties set to known values.
 
492
        source_package = publisher.getPubSource(
 
493
            distroseries=distroseries, sourcename="libc",
 
494
            component='universe', section='web',
 
495
            version="2.8-1", status=PackagePublishingStatus.PUBLISHED,
 
496
            archive=source_archive)
 
497
 
 
498
        # Now put the same named package in the target archive with
 
499
        # different override values.
 
500
        ancestry_package = publisher.getPubSource(
 
501
            distroseries=distroseries, sourcename="libc",
 
502
            component='restricted', section='games',
 
503
            version="2.8-0", status=PackagePublishingStatus.PUBLISHED,
 
504
            archive=target_archive)
 
505
 
 
506
        # Now, run the copy job, which should auto-approve the copy and
 
507
        # override the package with the existing values in the
 
508
        # target_archive.
 
509
 
 
510
        source = getUtility(IPlainPackageCopyJobSource)
 
511
        job = source.create(
 
512
            package_name="libc",
 
513
            package_version="2.8-1",
 
514
            source_archive=source_archive,
 
515
            target_archive=target_archive,
 
516
            target_distroseries=distroseries,
 
517
            target_pocket=PackagePublishingPocket.RELEASE,
 
518
            include_binaries=False)
 
519
 
 
520
        self.runJob(job)
 
521
 
 
522
        new_publication = target_archive.getPublishedSources(
 
523
            name='libc', version='2.8-1').one()
 
524
        self.assertEqual('restricted', new_publication.component.name)
 
525
        self.assertEqual('games', new_publication.section.name)
 
526
 
 
527
    def test_copying_to_main_archive_manual_overrides(self):
 
528
        # Test processing a packagecopyjob that has manual overrides.
 
529
        publisher = SoyuzTestPublisher()
 
530
        publisher.prepareBreezyAutotest()
 
531
        distroseries = publisher.breezy_autotest
 
532
 
 
533
        target_archive = self.factory.makeArchive(
 
534
            distroseries.distribution, purpose=ArchivePurpose.PRIMARY)
 
535
        source_archive = self.factory.makeArchive()
 
536
 
 
537
        # Publish a package in the source archive with some overridable
 
538
        # properties set to known values.
 
539
        source_package = publisher.getPubSource(
 
540
            distroseries=distroseries, sourcename="copyme",
 
541
            component='universe', section='web',
 
542
            version="2.8-1", status=PackagePublishingStatus.PUBLISHED,
 
543
            archive=source_archive)
 
544
 
 
545
        # Now, run the copy job, which should raise an error because
 
546
        # there's no ancestry.
 
547
        source = getUtility(IPlainPackageCopyJobSource)
 
548
        job = source.create(
 
549
            package_name="copyme",
 
550
            package_version="2.8-1",
 
551
            source_archive=source_archive,
 
552
            target_archive=target_archive,
 
553
            target_distroseries=distroseries,
 
554
            target_pocket=PackagePublishingPocket.RELEASE,
 
555
            include_binaries=False)
 
556
 
 
557
        self.assertRaises(SuspendJobException, self.runJob, job)
 
558
        # Simulate the job runner suspending after getting a
 
559
        # SuspendJobException
 
560
        job.suspend()
 
561
        self.layer.txn.commit()
 
562
        self.layer.switchDbUser("launchpad_main")
 
563
 
 
564
        # Add some overrides to the job.
 
565
        package = source_package.sourcepackagerelease.sourcepackagename
 
566
        restricted = getUtility(IComponentSet)['restricted']
 
567
        editors = getUtility(ISectionSet)['editors']
 
568
        override = SourceOverride(package, restricted, editors)
 
569
        job.addSourceOverride(override)
 
570
 
 
571
        # Accept the upload to release the job then run it.
 
572
        pu = getUtility(IPackageUploadSet).getByPackageCopyJobIDs(
 
573
            [removeSecurityProxy(job).context.id]).one()
 
574
        pu.acceptFromQueue()
 
575
        self.runJob(job)
 
576
 
 
577
        # The copied source should have the manual overrides, not the
 
578
        # original values.
 
579
        new_publication = target_archive.getPublishedSources(
 
580
            name='copyme', version='2.8-1').one()
 
581
        self.assertEqual('restricted', new_publication.component.name)
 
582
        self.assertEqual('editors', new_publication.section.name)
 
583
 
 
584
    def test_copying_to_main_archive_with_no_ancestry(self):
 
585
        # The job should suspend itself and create a packageupload with
 
586
        # a reference to the package_copy_job.
 
587
        publisher = SoyuzTestPublisher()
 
588
        publisher.prepareBreezyAutotest()
 
589
        distroseries = publisher.breezy_autotest
 
590
 
 
591
        target_archive = self.factory.makeArchive(
 
592
            distroseries.distribution, purpose=ArchivePurpose.PRIMARY)
 
593
        source_archive = self.factory.makeArchive()
 
594
 
 
595
        # Publish a package in the source archive with some overridable
 
596
        # properties set to known values.
 
597
        source_package = publisher.getPubSource(
 
598
            distroseries=distroseries, sourcename="copyme",
 
599
            component='multiverse', section='web',
 
600
            version="2.8-1", status=PackagePublishingStatus.PUBLISHED,
 
601
            archive=source_archive)
 
602
 
 
603
        # There is no package of the same name already in the target
 
604
        # archive.
 
605
        existing_sources = target_archive.getPublishedSources(name='copyme')
 
606
        self.assertEqual(None, existing_sources.any())
 
607
 
 
608
        # Now, run the copy job.
 
609
 
 
610
        source = getUtility(IPlainPackageCopyJobSource)
 
611
        job = source.create(
 
612
            package_name="copyme",
 
613
            package_version="2.8-1",
 
614
            source_archive=source_archive,
 
615
            target_archive=target_archive,
 
616
            target_distroseries=distroseries,
 
617
            target_pocket=PackagePublishingPocket.RELEASE,
 
618
            include_binaries=False)
 
619
 
 
620
        # The job should be suspended and there's a PackageUpload with
 
621
        # its package_copy_job set.
 
622
        self.assertRaises(SuspendJobException, self.runJob, job)
 
623
        pu = Store.of(target_archive).find(
 
624
            PackageUpload,
 
625
            PackageUpload.package_copy_job_id == job.id).one()
 
626
        pcj = removeSecurityProxy(job).context
 
627
        self.assertEqual(pcj, pu.package_copy_job)
 
628
 
 
629
        # The job metadata should contain default overrides from the
 
630
        # UnknownOverridePolicy policy.
 
631
        self.assertEqual('universe', pcj.metadata['component_override'])
 
632
 
 
633
    def test_copying_to_main_archive_unapproved(self):
 
634
        # Uploading to a series that is in a state that precludes auto
 
635
        # approval will cause the job to suspend and a packageupload
 
636
        # created in the UNAPPROVED state.
 
637
        publisher = SoyuzTestPublisher()
 
638
        publisher.prepareBreezyAutotest()
 
639
        distroseries = publisher.breezy_autotest
 
640
        # The series is frozen so it won't auto-approve new packages.
 
641
        distroseries.status = SeriesStatus.FROZEN
 
642
 
 
643
        target_archive = self.factory.makeArchive(
 
644
            distroseries.distribution, purpose=ArchivePurpose.PRIMARY)
 
645
        source_archive = self.factory.makeArchive()
 
646
 
 
647
        # Publish a package in the source archive.
 
648
        source_package = publisher.getPubSource(
 
649
            distroseries=distroseries, sourcename="copyme",
 
650
            version="2.8-1", status=PackagePublishingStatus.PUBLISHED,
 
651
            component='multiverse', section='web',
 
652
            archive=source_archive)
 
653
 
 
654
        # Now put the same named package in the target archive so it has
 
655
        # ancestry.
 
656
        ancestry_package = publisher.getPubSource(
 
657
            distroseries=distroseries, sourcename="copyme",
 
658
            version="2.8-0", status=PackagePublishingStatus.PUBLISHED,
 
659
            component='main', section='games',
 
660
            archive=target_archive)
 
661
 
 
662
        # Now, run the copy job.
 
663
        source = getUtility(IPlainPackageCopyJobSource)
 
664
        job = source.create(
 
665
            package_name="copyme",
 
666
            package_version="2.8-1",
 
667
            source_archive=source_archive,
 
668
            target_archive=target_archive,
 
669
            target_distroseries=distroseries,
 
670
            target_pocket=PackagePublishingPocket.RELEASE,
 
671
            include_binaries=False)
 
672
 
 
673
        # The job should be suspended and there's a PackageUpload with
 
674
        # its package_copy_job set in the UNAPPROVED queue.
 
675
        self.assertRaises(SuspendJobException, self.runJob, job)
 
676
 
 
677
        pu = Store.of(target_archive).find(
 
678
            PackageUpload,
 
679
            PackageUpload.package_copy_job_id == job.id).one()
 
680
        pcj = removeSecurityProxy(job).context
 
681
        self.assertEqual(pcj, pu.package_copy_job)
 
682
        self.assertEqual(PackageUploadStatus.UNAPPROVED, pu.status)
 
683
 
 
684
        # The job's metadata should contain the override ancestry from
 
685
        # the target archive.
 
686
        self.assertEqual('main', pcj.metadata['component_override'])
 
687
 
 
688
    def test_copying_after_job_released(self):
 
689
        # The first pass of the job may have created a PackageUpload and
 
690
        # suspended the job.  Here we test the second run to make sure
 
691
        # that it actually copies the package.
 
692
        publisher = SoyuzTestPublisher()
 
693
        publisher.prepareBreezyAutotest()
 
694
        distroseries = publisher.breezy_autotest
 
695
 
 
696
        target_archive = self.factory.makeArchive(
 
697
            distroseries.distribution, purpose=ArchivePurpose.PRIMARY)
 
698
        source_archive = self.factory.makeArchive()
 
699
 
 
700
        # Publish a package in the source archive.
 
701
        source_package = publisher.getPubSource(
 
702
            distroseries=distroseries, sourcename="copyme",
 
703
            version="2.8-1", status=PackagePublishingStatus.PUBLISHED,
 
704
            archive=source_archive)
 
705
 
 
706
        source = getUtility(IPlainPackageCopyJobSource)
 
707
        job = source.create(
 
708
            package_name="copyme",
 
709
            package_version="2.8-1",
 
710
            source_archive=source_archive,
 
711
            target_archive=target_archive,
 
712
            target_distroseries=distroseries,
 
713
            target_pocket=PackagePublishingPocket.RELEASE,
 
714
            include_binaries=False)
 
715
 
 
716
        # Run the job so it gains a PackageUpload.
 
717
        self.assertRaises(SuspendJobException, self.runJob, job)
 
718
        # Simulate the job runner suspending after getting a
 
719
        # SuspendJobException
 
720
        job.suspend()
 
721
        self.layer.txn.commit()
 
722
        self.layer.switchDbUser("launchpad_main")
 
723
 
 
724
        # Accept the upload to release the job then run it.
 
725
        pu = getUtility(IPackageUploadSet).getByPackageCopyJobIDs(
 
726
            [removeSecurityProxy(job).context.id]).one()
 
727
        pu.acceptFromQueue()
 
728
        self.runJob(job)
 
729
 
 
730
        existing_sources = target_archive.getPublishedSources(name='copyme')
 
731
        self.assertIsNot(None, existing_sources.any())
 
732
 
458
733
    def test_findMatchingDSDs_matches_all_DSDs_for_job(self):
459
734
        # findMatchingDSDs finds matching DSDs for any of the packages
460
735
        # in the job.
555
830
    def test_findMatchingDSDs(self):
556
831
        job = self.makeJob()
557
832
        transaction.commit()
558
 
        self.layer.switchDbUser(config.IPlainPackageCopyJobSource.dbuser)
 
833
        self.layer.switchDbUser(self.dbuser)
559
834
        removeSecurityProxy(job).findMatchingDSDs()
560
835
 
561
836
    def test_reportFailure(self):
562
837
        job = self.makeJob()
563
838
        transaction.commit()
564
 
        self.layer.switchDbUser(config.IPlainPackageCopyJobSource.dbuser)
 
839
        self.layer.switchDbUser(self.dbuser)
565
840
        removeSecurityProxy(job).reportFailure(CannotCopy("Mommy it hurts"))