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

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
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-slavescanner.txt into better, more focused tests

Description of the change

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

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

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

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

To post a comment you must log in.
Revision history for this message
Jeroen T. Vermeulen (jtv) wrote :

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

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

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/buildmaster/model/builder.py'
--- lib/lp/buildmaster/model/builder.py 2010-09-21 09:05:34 +0000
+++ lib/lp/buildmaster/model/builder.py 2010-09-22 10:37:47 +0000
@@ -115,6 +115,11 @@
115class BuilderSlave(object):115class BuilderSlave(object):
116 """Add in a few useful methods for the XMLRPC slave."""116 """Add in a few useful methods for the XMLRPC slave."""
117117
118 # WARNING: If you change the API for this, you should also change the APIs
119 # of the mocks in soyuzbuilderhelpers to match. Otherwise, you will have
120 # many false positives in your test run and will most likely break
121 # production.
122
118 # XXX: This (BuilderSlave) should use composition, rather than123 # XXX: This (BuilderSlave) should use composition, rather than
119 # inheritance.124 # inheritance.
120125
121126
=== modified file 'lib/lp/services/twistedsupport/processmonitor.py'
--- lib/lp/services/twistedsupport/processmonitor.py 2010-08-20 20:31:18 +0000
+++ lib/lp/services/twistedsupport/processmonitor.py 2010-09-22 10:37:47 +0000
@@ -300,7 +300,7 @@
300300
301 def spawnProcess(self, *args, **kwargs):301 def spawnProcess(self, *args, **kwargs):
302 """Start a process.302 """Start a process.
303 303
304 See reactor.spawnProcess.304 See reactor.spawnProcess.
305 """305 """
306 self._process_transport = reactor.spawnProcess(306 self._process_transport = reactor.spawnProcess(
307307
=== modified file 'lib/lp/soyuz/doc/archive-dependencies.txt'
--- lib/lp/soyuz/doc/archive-dependencies.txt 2010-08-24 15:29:01 +0000
+++ lib/lp/soyuz/doc/archive-dependencies.txt 2010-09-22 10:37:47 +0000
@@ -250,18 +250,27 @@
250 deb http://ftpmaster.internal/ubuntu hoary-updates250 deb http://ftpmaster.internal/ubuntu hoary-updates
251 main restricted universe multiverse251 main restricted universe multiverse
252252
253Similarly, populated PPA dependencies are listed in the building253Similarly, unpopulated PPA dependencies are *not* listed in the building
254'sources_list'.254'sources_list'.
255255
256 >>> mark = getUtility(IPersonSet).getByName('mark')256 >>> mark = getUtility(IPersonSet).getByName('mark')
257 >>> archive_dependency = cprov.archive.addArchiveDependency(
258 ... mark.archive, PackagePublishingPocket.RELEASE,
259 ... getUtility(IComponentSet)['main'])
260 >>> print_building_sources_list(a_build)
261 deb http://ppa.launchpad.dev/cprov/ppa/ubuntu hoary main
262 deb http://ftpmaster.internal/ubuntu hoary
263 main restricted universe multiverse
264 deb http://ftpmaster.internal/ubuntu hoary-security
265 main restricted universe multiverse
266 deb http://ftpmaster.internal/ubuntu hoary-updates
267 main restricted universe multiverse
268
269But *populated* PPA dependencies *are* listed in the building 'sources_list'.
270
257 >>> pub_binaries = test_publisher.getPubBinaries(271 >>> pub_binaries = test_publisher.getPubBinaries(
258 ... binaryname='dep-bin', archive=mark.archive,272 ... binaryname='dep-bin', archive=mark.archive,
259 ... status=PackagePublishingStatus.PUBLISHED)273 ... status=PackagePublishingStatus.PUBLISHED)
260
261 >>> archive_dependency = cprov.archive.addArchiveDependency(
262 ... mark.archive, PackagePublishingPocket.RELEASE,
263 ... getUtility(IComponentSet)['main'])
264
265 >>> print_building_sources_list(a_build)274 >>> print_building_sources_list(a_build)
266 deb http://ppa.launchpad.dev/cprov/ppa/ubuntu hoary main275 deb http://ppa.launchpad.dev/cprov/ppa/ubuntu hoary main
267 deb http://ppa.launchpad.dev/mark/ppa/ubuntu hoary main276 deb http://ppa.launchpad.dev/mark/ppa/ubuntu hoary main
268277
=== modified file 'lib/lp/soyuz/doc/buildd-slave.txt'
--- lib/lp/soyuz/doc/buildd-slave.txt 2010-04-30 10:00:34 +0000
+++ lib/lp/soyuz/doc/buildd-slave.txt 2010-09-22 10:37:47 +0000
@@ -13,43 +13,6 @@
13 >>> from canonical.buildd.tests import BuilddSlaveTestSetup13 >>> from canonical.buildd.tests import BuilddSlaveTestSetup
14 >>> BuilddSlaveTestSetup().setUp()14 >>> BuilddSlaveTestSetup().setUp()
1515
16Use simple xmlrpclib client to certify the BuildSlave is running
17
18 >>> import xmlrpclib
19 >>> slave = xmlrpclib.Server('http://localhost:8221/rpc/')
20 >>> slave.echo('Hello World')
21 ['Hello World']
22
23With slave protocol v1.0new, the only way to get files to the slave is to
24put them in the librarian first...
25
26 >>> from canonical.librarian.client import LibrarianClient
27 >>> from StringIO import StringIO
28 >>> from canonical.launchpad.database import LibraryFileAlias
29 >>> import transaction
30 >>> lc = LibrarianClient()
31 >>> helloworld = "Hello World"
32 >>> hw_sio = StringIO(helloworld)
33 >>> alias = lc.addFile("HelloWorld.txt", len(helloworld),
34 ... hw_sio, "text/plain")
35 >>> transaction.commit()
36 >>> lf = LibraryFileAlias.get(alias)
37 >>> present, info = slave.ensurepresent(
38 ... lf.content.sha1, lf.http_url, "", "")
39 >>> present, info
40 (True, 'Download')
41
42As of slave protocol v1.0new, /filecache/SHA1SUM is *THE* way
43to retrieve files from the slave. Verify it works...
44
45 >>> from urllib2 import urlopen
46 >>> f = urlopen("http://localhost:8221/filecache/" + lf.content.sha1)
47 >>> hw_str = f.read()
48 >>> f.close()
49 >>> hw_str == helloworld
50 True
51
52
53== BuilderSet polling operations ==16== BuilderSet polling operations ==
5417
55 >>> import logging18 >>> import logging
@@ -90,6 +53,7 @@
9053
91At this point the buildd-slave is not accessible anymore.54At this point the buildd-slave is not accessible anymore.
9255
56 >>> import xmlrpclib
93 >>> s = xmlrpclib.Server('http://localhost:8221/rpc/')57 >>> s = xmlrpclib.Server('http://localhost:8221/rpc/')
94 >>> s.info()58 >>> s.info()
95 Traceback (most recent call last):59 Traceback (most recent call last):
9660
=== modified file 'lib/lp/soyuz/doc/buildd-slavescanner.txt'
--- lib/lp/soyuz/doc/buildd-slavescanner.txt 2010-09-16 14:36:47 +0000
+++ lib/lp/soyuz/doc/buildd-slavescanner.txt 2010-09-22 10:37:47 +0000
@@ -112,12 +112,10 @@
112112
113Make sure that a_builder has no active builds:113Make sure that a_builder has no active builds:
114114
115 >>> from canonical.launchpad.ftests import syncUpdate
116 >>> if a_builder.currentjob is not None:115 >>> if a_builder.currentjob is not None:
117 ... currentjob = a_builder.currentjob116 ... currentjob = a_builder.currentjob
118 ... currentjob.setDateStarted(None)117 ... currentjob.setDateStarted(None)
119 ... currentjob.builder = None118 ... currentjob.builder = None
120 ... syncUpdate(currentjob)
121119
122Force the test builder to be 'ok' as the code required to do this120Force the test builder to be 'ok' as the code required to do this
123automatically is not yet factored into the content class.121automatically is not yet factored into the content class.
@@ -595,11 +593,9 @@
595 >>> resurrect_build = getUtility(IBinaryPackageBuildSet).getByQueueEntry(593 >>> resurrect_build = getUtility(IBinaryPackageBuildSet).getByQueueEntry(
596 ... current_job)594 ... current_job)
597 >>> resurrect_build.status = BuildStatus.NEEDSBUILD595 >>> resurrect_build.status = BuildStatus.NEEDSBUILD
598 >>> syncUpdate(resurrect_build)
599 >>> current_job.builder = None596 >>> current_job.builder = None
600 >>> current_job.setDateStarted(None)597 >>> current_job.setDateStarted(None)
601 >>> current_job.lastscore = 0598 >>> current_job.lastscore = 0
602 >>> syncUpdate(current_job)
603599
604IBuilder.findCandidate also identifies if there are builds for600IBuilder.findCandidate also identifies if there are builds for
605superseded source package releases in the queue and marks the601superseded source package releases in the queue and marks the
@@ -740,66 +736,6 @@
740 >>> commit()736 >>> commit()
741 >>> LaunchpadZopelessLayer.switchDbUser(config.builddmaster.dbuser)737 >>> LaunchpadZopelessLayer.switchDbUser(config.builddmaster.dbuser)
742738
743For building a candidate in the release pocket for the main component
744and the primary archive It will pass an 'archives' argument to the
745slave that contains sources.list entries for each pocket required in
746the primary archive dependency tree.
747
748We also pass arguments called 'suite' which is the current distroseries and
749pocket, (e.g. edgy-updates) and 'archive_purpose' which contains the build's
750archive.purpose (e.g. PRIMARY or PPA). These latter two arguments are
751used in the chroot to determine whether it needs to turn on some features
752or not (like pkgstriptranslations and pkgmaintainermangler).
753
754Please note also that the 'archive_private' flag is passed to the slave
755builder. It is True for private archives and False otherwise.
756
757 >>> a_builder.setSlaveForTesting(OkSlave())
758 >>> a_builder.is_available
759 True
760 >>> candidate = a_build.queueBuild()
761 >>> removeSecurityProxy(a_builder)._dispatchBuildCandidate(candidate)
762 ensurepresent called, url=...
763 ensurepresent called,
764 url=http://localhost:58000/3/firefox_0.9.2.orig.tar.gz
765 OkSlave BUILDING
766 Archives:
767 deb http://ftpmaster.internal/ubuntu hoary main
768 Suite: hoary
769 Ogre-component: main
770 Archive Purpose: PRIMARY
771 Archive Private: False
772
773 >>> candidate.destroySelf()
774
775Currently we can theoretically dispatch a build candidate for a
776builder in 'manual' mode.
777
778Although this will not be optimal, because we can only
779do it once the manual builder has been collected (due to the
780BuildQueue.builder constraint). Also because we don't yet provide a
781API/UI method to request the dispatch in advance.
782
783 >>> a_builder.manual = True
784 >>> commit()
785 >>> a_builder.setSlaveForTesting(OkSlave())
786 >>> a_builder.is_available
787 True
788 >>> candidate = a_build.queueBuild()
789 >>> removeSecurityProxy(a_builder)._dispatchBuildCandidate(candidate)
790 ensurepresent called, url=...
791 ensurepresent called,
792 url=http://localhost:58000/3/firefox_0.9.2.orig.tar.gz
793 OkSlave BUILDING
794 Archives:
795 deb http://ftpmaster.internal/ubuntu hoary main
796 Suite: hoary
797 Ogre-component: main
798 Archive Purpose: PRIMARY
799 Archive Private: False
800
801 >>> candidate.destroySelf()
802
803Partner archive builds will set up the 'archives' argument such that it739Partner archive builds will set up the 'archives' argument such that it
804references all the required pockets/components in the primary archive, in740references all the required pockets/components in the primary archive, in
805addition to a reference to the release pocket in the partner archive itself.741addition to a reference to the release pocket in the partner archive itself.
@@ -812,10 +748,6 @@
812 >>> a_builder.is_available748 >>> a_builder.is_available
813 True749 True
814750
815 >>> candidate = a_build.queueBuild()
816 >>> setupBuildQueue(candidate, a_builder)
817 >>> last_stub_mail_count = len(stub.test_emails)
818
819The partner archive won't be passed to the builder unless it has at751The partner archive won't be passed to the builder unless it has at
820least one published binary availble in the target distroarchseries.752least one published binary availble in the target distroarchseries.
821This feature fixes bug #196782, when archive/suites got passed to753This feature fixes bug #196782, when archive/suites got passed to
@@ -823,229 +755,12 @@
823any PPA/suite will fail during the first 20 minutes because no empty755any PPA/suite will fail during the first 20 minutes because no empty
824indexes are published.756indexes are published.
825757
826Note that only a published binary in the right context will make the
827archive relevant, anything PENDING or published in another context
828wouldn't work.
829
830 >>> warty = getUtility(IDistributionSet)['ubuntu']['warty']
831 >>> create_binary_publication_for(
832 ... partner_archive, warty, PackagePublishingStatus.PUBLISHED)
833
834 >>> hoary = getUtility(IDistributionSet)['ubuntu']['hoary']
835 >>> create_binary_publication_for(
836 ... partner_archive, hoary, PackagePublishingStatus.PENDING)
837
838So, at moment, partner archive is still not relevant for builds in
839hoary/i386. It's not passed to the builder.
840
841 >>> removeSecurityProxy(a_builder)._dispatchBuildCandidate(candidate)
842 ensurepresent called, url=...
843 ensurepresent called,
844 url=http://localhost:58000/3/firefox_0.9.2.orig.tar.gz
845 OkSlave BUILDING
846 Archives:
847 deb http://ftpmaster.internal/ubuntu hoary main restricted universe multiverse
848 deb http://ftpmaster.internal/ubuntu hoary-security main restricted universe multiverse
849 deb http://ftpmaster.internal/ubuntu hoary-updates main restricted universe multiverse
850 Suite: hoary
851 Ogre-component: main
852 Archive Purpose: PARTNER
853 Archive Private: False
854
855Let's try it again.
856
857 >>> candidate.destroySelf()
858 >>> a_builder.setSlaveForTesting(OkSlave())
859 >>> a_builder.is_available
860 True
861
862 >>> candidate = a_build.queueBuild()
863 >>> setupBuildQueue(candidate, a_builder)
864 >>> last_stub_mail_count = len(stub.test_emails)
865
866 >>> removeSecurityProxy(a_build).archive = ubuntu.main_archive
867 >>> candidate.destroySelf()
868
869But this time We will create a valid publication on partner hoary/i386.
870
871 >>> from lp.soyuz.interfaces.component import IComponentSet
872 >>> commit()
873 >>> LaunchpadZopelessLayer.switchDbUser('launchpad')
874 >>> login('foo.bar@canonical.com')
875 >>> pub_source = test_publisher.getPubSource(
876 ... archive=partner_archive, distroseries=hoary,
877 ... status=PackagePublishingStatus.PUBLISHED,
878 ... component='partner')
879 >>> pub_binaries = test_publisher.getPubBinaries(
880 ... archive=partner_archive, pub_source=pub_source,
881 ... distroseries=hoary, status=PackagePublishingStatus.PUBLISHED)
882 >>> partner_build = pub_binaries[0].binarypackagerelease.build
883 >>> partner_candidate = partner_build.buildqueue_record
884 >>> commit()
885 >>> LaunchpadZopelessLayer.switchDbUser(config.builddmaster.dbuser)
886
887Now when we dispatch the partner build, since it has one published
888binary in hoary/i386, the partner archive gets included in the builder
889sources_list.
890
891 >>> removeSecurityProxy(
892 ... a_builder)._dispatchBuildCandidate(partner_candidate)
893 ensurepresent called, url=...
894 ensurepresent called, url=http://localhost:58000/.../foo_666.dsc
895 OkSlave BUILDING
896 Archives:
897 deb http://ftpmaster.internal/ubuntu hoary
898 main restricted universe multiverse
899 deb http://ftpmaster.internal/ubuntu hoary-security
900 main restricted universe multiverse
901 deb http://ftpmaster.internal/ubuntu hoary-updates
902 main restricted universe multiverse
903 deb http://ftpmaster.internal/ubuntu-partner hoary partner
904 Suite: hoary
905 Ogre-component: partner
906 Archive Purpose: PARTNER
907 Archive Private: False
908
909 >>> partner_candidate.destroySelf()
910
911Similarly, PPA builds pass the 'archives' arguments:
912
913 >>> from canonical.launchpad.interfaces import IPersonSet
914 >>> cprov_archive = getUtility(IPersonSet).getByName('cprov').archive
915 >>> removeSecurityProxy(a_build).archive = cprov_archive
916 >>> a_builder.virtualized = True
917 >>> a_builder.vm_host = 'localhost.ppa'
918 >>> commit()
919 >>> a_builder.setSlaveForTesting(OkSlave())
920 >>> a_builder.is_available
921 True
922
923 >>> candidate = a_build.queueBuild()
924 >>> setupBuildQueue(candidate, a_builder)
925 >>> last_stub_mail_count = len(stub.test_emails)
926
927Exactly as Partner, Celso's PPA won't be included if it doesn't
928contain any published binary in hoary/i386. We will create it before
929dispatching.
930
931 >>> create_binary_publication_for(
932 ... cprov_archive, hoary, PackagePublishingStatus.PUBLISHED)
933
934 >>> removeSecurityProxy(a_builder)._dispatchBuildCandidate(candidate)
935 ensurepresent called, url=...
936 ensurepresent called,
937 url=http://localhost:58000/3/firefox_0.9.2.orig.tar.gz
938 OkSlave BUILDING
939 Archives:
940 deb http://ftpmaster.internal/ubuntu hoary main restricted universe multiverse
941 deb http://ftpmaster.internal/ubuntu hoary-security main restricted universe multiverse
942 deb http://ftpmaster.internal/ubuntu hoary-updates main restricted universe multiverse
943 deb http://ppa.launchpad.dev/cprov/ppa/ubuntu hoary main
944 Suite: hoary
945 Ogre-component: main
946 Archive Purpose: PPA
947 Archive Private: False
948
949If the build is for a private PPA, the slave scanner will pass a
950sources.list entry that contains a password to access the archive.
951
952 >>> from canonical.testing import LaunchpadZopelessLayer
953 >>> commit()
954 >>> LaunchpadZopelessLayer.switchDbUser('launchpad')
955 >>> login('foo.bar@canonical.com')
956 >>> build = getUtility(IBinaryPackageBuildSet).getByQueueEntry(
957 ... candidate)
958 >>> for build_file in build.source_package_release.files:
959 ... removeSecurityProxy(build_file).libraryfile.restricted = True
960 >>> private_ppa = factory.makeArchive(
961 ... owner=cprov_archive.owner, name='pppa', private=True,
962 ... virtualized=False, distribution=ubuntu)
963
964It's necessary to publish some binaries into the private PPA, otherwise
965the PPA won't be included as a dependency in the sources list below.
966
967 >>> binaries = test_publisher.getPubBinaries(
968 ... distroseries=ubuntu['hoary'], archive=private_ppa,
969 ... status=PackagePublishingStatus.PUBLISHED)
970 >>> removeSecurityProxy(build).archive = private_ppa
971 >>> commit()
972 >>> LaunchpadZopelessLayer.switchDbUser(test_dbuser)
973 >>> login(ANONYMOUS)
974
975Dispatch the build again. Celso's archive sources.list entry now has the
976buildd:secret@ part in the URL.
977
978Also note that when ensurepresent() is called, it receives a URL that
979points to the private archive rather than the librarian for the private
980firefox file. This is because the build slaves are not allowed to
981access the restricted librarian as it cannot provide access via
982credentials, unlike the archive itself.
983
984Finally, the archive purpose is overridden to PRIMARY instead of PPA
985for any archives that have require_virtualized as False.
986
987In this circumstance, it also uses the component override from the PRIMARY
988archive and not the one from the PPA, which on the absence of ancestry
989defaults to 'universe'.
990
991 >>> build = getUtility(IBinaryPackageBuildSet).getByQueueEntry(candidate)
992 >>> print build.current_component.name
993 main
994
995This is so that the mangling tools will run over the built packages.
996
997 >>> removeSecurityProxy(a_builder)._dispatchBuildCandidate(candidate)
998 ensurepresent called, url=...
999 ensurepresent called,
1000 url=http://private-ppa.../cprov/pppa/.../firefox_0.9.2.orig.tar.gz
1001 URL authorisation with buildd/sekrit
1002 OkSlave BUILDING
1003 Archives:
1004 deb http://buildd:sekrit@private-ppa.../cprov/pppa/ubuntu hoary main
1005 deb http://ftpmaster.internal/ubuntu hoary
1006 main restricted universe multiverse
1007 deb http://ftpmaster.internal/ubuntu hoary-security
1008 main restricted universe multiverse
1009 deb http://ftpmaster.internal/ubuntu hoary-updates
1010 main restricted universe multiverse
1011 Suite: hoary
1012 Ogre-component: universe
1013 Archive Purpose: PRIMARY
1014 Archive Private: True
1015
1016We will create an ancestry in the primary archive target to the 'main'
1017component and this time the dispatching will follow that component.
1018
1019 >>> sourcename = build.source_package_release.name
1020
1021 >>> LaunchpadZopelessLayer.switchDbUser('launchpad')
1022 >>> login('foo.bar@canonical.com')
1023
1024 >>> ancestry = test_publisher.getPubSource(
1025 ... sourcename=sourcename, version='0.1', distroseries=hoary)
1026
1027 >>> print ancestry.displayname
1028 mozilla-firefox 0.1 in hoary
1029
1030 >>> print ancestry.component.name
1031 main
1032
1033 >>> commit()
1034 >>> LaunchpadZopelessLayer.switchDbUser(config.builddmaster.dbuser)
1035 >>> login(ANONYMOUS)
1036
1037 >>> removeSecurityProxy(a_builder)._dispatchBuildCandidate(candidate)
1038 ensurepresent called, ...
1039 ...
1040 Ogre-component: main
1041 ...
1042
1043 >>> candidate.destroySelf()
1044
1045Since this is a build in a private archive, the log was uploaded to758Since this is a build in a private archive, the log was uploaded to
1046the restricted librarian.759the restricted librarian.
1047760
1048 >>> candidate = a_build.queueBuild()761 >>> removeSecurityProxy(build).archive = private_ppa
762 >>> commit()
763 >>> candidate = build.queueBuild()
1049 >>> setupBuildQueue(candidate, a_builder)764 >>> setupBuildQueue(candidate, a_builder)
1050 >>> build.upload_log = None765 >>> build.upload_log = None
1051 >>> candidate.builder.setSlaveForTesting(WaitingSlave('BuildStatus.OK'))766 >>> candidate.builder.setSlaveForTesting(WaitingSlave('BuildStatus.OK'))
@@ -1059,7 +774,7 @@
1059 >>> lfa.restricted774 >>> lfa.restricted
1060 True775 True
1061 >>> print lfa.filename776 >>> print lfa.filename
1062 buildlog_ubuntu-hoary-i386.mozilla-firefox_0.9_BUILDING.txt.gz777 buildlog_ubuntu-warty-i386.mozilla-firefox_0.9_BUILDING.txt.gz
1063778
1064The attempt to fetch the buildlog from the common librarian will fail779The attempt to fetch the buildlog from the common librarian will fail
1065since this is a build in a private archive and the buildlog was thus780since this is a build in a private archive and the buildlog was thus
@@ -1079,7 +794,7 @@
1079 ... getUtility(IRestrictedLibrarianClient).getFileByAlias(lfa.id))794 ... getUtility(IRestrictedLibrarianClient).getFileByAlias(lfa.id))
1080 >>> url_parts = urlparse.urlsplit(lfa2.file.geturl())795 >>> url_parts = urlparse.urlsplit(lfa2.file.geturl())
1081 >>> print os.path.basename(url_parts[2])796 >>> print os.path.basename(url_parts[2])
1082 buildlog_ubuntu-hoary-i386.mozilla-firefox_0.9_BUILDING.txt.gz797 buildlog_ubuntu-warty-i386.mozilla-firefox_0.9_BUILDING.txt.gz
1083798
1084A PPA can depend on another PPA. We can make Celso's PPA depend on799A PPA can depend on another PPA. We can make Celso's PPA depend on
1085Mark's PPA:800Mark's PPA:
@@ -1088,218 +803,13 @@
1088 >>> LaunchpadZopelessLayer.switchDbUser('launchpad')803 >>> LaunchpadZopelessLayer.switchDbUser('launchpad')
1089 >>> login('foo.bar@canonical.com')804 >>> login('foo.bar@canonical.com')
1090805
1091We'll switch the build's archive back to Celso's PPA and set the PPA to
1092virtualized before adding the dependency on Mark's PPA.
1093
1094 >>> removeSecurityProxy(build).archive = cprov_archive
1095 >>> cprov_archive.require_virtualized = True
1096 >>> for build_file in a_build.source_package_release.files:
1097 ... removeSecurityProxy(build_file).libraryfile.restricted = False
1098 >>> mark_archive = getUtility(IPersonSet).getByName('mark').archive
1099
1100 >>> unused_dep = cprov_archive.addArchiveDependency(
1101 ... mark_archive, PackagePublishingPocket.RELEASE,
1102 ... getUtility(IComponentSet)['main'])
1103
1104 >>> commit()
1105 >>> LaunchpadZopelessLayer.switchDbUser(test_dbuser)
1106 >>> login(ANONYMOUS)
1107
1108Now we can see that a build from Celso's PPA will be able to install
1109dependencies from Mark's PPA, if Mark's PPA has at least one binary
1110published in hoary/i386, which is not the case.
1111
1112 >>> a_builder.setSlaveForTesting(OkSlave())
1113 >>> a_builder.is_available
1114 True
1115
1116 >>> candidate = a_build.queueBuild()
1117 >>> setupBuildQueue(candidate, a_builder)
1118 >>> last_stub_mail_count = len(stub.test_emails)
1119
1120 >>> removeSecurityProxy(a_builder)._dispatchBuildCandidate(candidate)
1121 ensurepresent called, url=...
1122 ensurepresent called,
1123 url=http://localhost:58000/3/firefox_0.9.2.orig.tar.gz
1124 OkSlave BUILDING
1125 Archives:
1126 deb http://ftpmaster.internal/ubuntu hoary main restricted universe multiverse
1127 deb http://ftpmaster.internal/ubuntu hoary-security main restricted universe multiverse
1128 deb http://ftpmaster.internal/ubuntu hoary-updates main restricted universe multiverse
1129 deb http://ppa.launchpad.dev/cprov/ppa/ubuntu hoary main
1130 Suite: hoary
1131 Ogre-component: main
1132 Archive Purpose: PPA
1133 Archive Private: False
1134
1135We will create the required publication in Mark's PPA and try again.
1136
1137 >>> candidate.destroySelf()
1138 >>> a_builder.setSlaveForTesting(OkSlave())
1139 >>> a_builder.is_available
1140 True
1141
1142 >>> candidate = a_build.queueBuild()
1143 >>> setupBuildQueue(candidate, a_builder)
1144 >>> last_stub_mail_count = len(stub.test_emails)
1145
1146 >>> create_binary_publication_for(
1147 ... mark_archive, hoary, PackagePublishingStatus.PUBLISHED)
1148
1149 >>> removeSecurityProxy(a_builder)._dispatchBuildCandidate(candidate)
1150 ensurepresent called, url=...
1151 ensurepresent called,
1152 url=http://localhost:58000/3/firefox_0.9.2.orig.tar.gz
1153 OkSlave BUILDING
1154 Archives:
1155 deb http://ftpmaster.internal/ubuntu hoary main restricted universe multiverse
1156 deb http://ftpmaster.internal/ubuntu hoary-security main restricted universe multiverse
1157 deb http://ftpmaster.internal/ubuntu hoary-updates main restricted universe multiverse
1158 deb http://ppa.launchpad.dev/cprov/ppa/ubuntu hoary main
1159 deb http://ppa.launchpad.dev/mark/ppa/ubuntu hoary main
1160 Suite: hoary
1161 Ogre-component: main
1162 Archive Purpose: PPA
1163 Archive Private: False
1164806
1165Clean up before continuing:807Clean up before continuing:
1166808
1167 >>> candidate.destroySelf()
1168 >>> a_builder.virtualized = False809 >>> a_builder.virtualized = False
1169 >>> removeSecurityProxy(a_build).archive = ubuntu.main_archive810 >>> removeSecurityProxy(a_build).archive = ubuntu.main_archive
1170 >>> commit()811 >>> commit()
1171812
1172Builddmaster stops before starting to build a denied build.
1173Since hoary is in development, we are not able to dispatch
1174builds for post-release pockets:
1175
1176 >>> candidate = a_build.queueBuild()
1177 >>> setupBuildQueue(candidate, a_builder)
1178 >>> last_stub_mail_count = len(stub.test_emails)
1179
1180Make a build in the updates pocket:
1181
1182 >>> hoary = hoary_i386.distroseries
1183 >>> hoary_evo = hoary.getSourcePackage(
1184 ... 'evolution').currentrelease.sourcepackagerelease
1185 >>> updates_build = hoary_evo.createBuild(
1186 ... distro_arch_series=hoary_i386,
1187 ... pocket=PackagePublishingPocket.UPDATES,
1188 ... processor=hoary_i386.default_processor,
1189 ... archive=hoary_i386.main_archive)
1190 >>> updates_bqItem = updates_build.queueBuild()
1191
1192 >>> hoary_i386.distroseries.status.name
1193 'DEVELOPMENT'
1194 >>> removeSecurityProxy(a_builder)._dispatchBuildCandidate(updates_bqItem)
1195 Traceback (most recent call last):
1196 ...
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.
1198
1199== Pocket dependencies ==
1200
1201Change the distroseries status for testing. FROZEN allows building in
1202all pockets:
1203
1204 >>> from canonical.launchpad.interfaces import SeriesStatus
1205 >>> hoary_i386.distroseries.status = SeriesStatus.FROZEN
1206
1207Now we can start a build in other pockets, and see what archives are
1208passed to the slave.
1209
1210A build in the updates pocket:
1211
1212 >>> a_builder.currentjob.destroySelf()
1213
1214 >>> bqItem3 = a_build.queueBuild()
1215 >>> build = getUtility(IBinaryPackageBuildSet).getByQueueEntry(bqItem3)
1216 >>> removeSecurityProxy(build).pocket = (
1217 ... PackagePublishingPocket.UPDATES)
1218 >>> last_stub_mail_count = len(stub.test_emails)
1219 >>> removeSecurityProxy(a_builder)._dispatchBuildCandidate(bqItem3)
1220 ensurepresent called, url=...
1221 ensurepresent called,
1222 url=http://localhost:58000/3/firefox_0.9.2.orig.tar.gz
1223 OkSlave BUILDING
1224 Archives:
1225 deb http://ftpmaster.internal/ubuntu hoary main
1226 deb http://ftpmaster.internal/ubuntu hoary-security main
1227 deb http://ftpmaster.internal/ubuntu hoary-updates main
1228 Suite: hoary-updates
1229 Ogre-component: main
1230 Archive Purpose: PRIMARY
1231 Archive Private: False
1232
1233A build in the proposed pocket:
1234
1235 >>> a_builder.currentjob.destroySelf()
1236
1237 >>> bqItem3 = a_build.queueBuild()
1238 >>> removeSecurityProxy(build).pocket = (
1239 ... PackagePublishingPocket.PROPOSED)
1240 >>> last_stub_mail_count = len(stub.test_emails)
1241 >>> removeSecurityProxy(a_builder)._dispatchBuildCandidate(bqItem3)
1242 ensurepresent called, url=...
1243 ensurepresent called,
1244 url=http://localhost:58000/3/firefox_0.9.2.orig.tar.gz
1245 OkSlave BUILDING
1246 Archives:
1247 deb http://ftpmaster.internal/ubuntu hoary main
1248 deb http://ftpmaster.internal/ubuntu hoary-proposed main
1249 deb http://ftpmaster.internal/ubuntu hoary-security main
1250 deb http://ftpmaster.internal/ubuntu hoary-updates main
1251 Suite: hoary-proposed
1252 Ogre-component: main
1253 Archive Purpose: PRIMARY
1254 Archive Private: False
1255
1256A build in the backports pocket:
1257
1258 >>> a_builder.currentjob.destroySelf()
1259
1260 >>> bqItem3 = a_build.queueBuild()
1261 >>> removeSecurityProxy(build).pocket = (
1262 ... PackagePublishingPocket.BACKPORTS)
1263 >>> last_stub_mail_count = len(stub.test_emails)
1264 >>> removeSecurityProxy(a_builder)._dispatchBuildCandidate(bqItem3)
1265 ensurepresent called, url=...
1266 ensurepresent called,
1267 url=http://localhost:58000/3/firefox_0.9.2.orig.tar.gz
1268 OkSlave BUILDING
1269 Archives:
1270 deb http://ftpmaster.internal/ubuntu hoary main restricted universe multiverse
1271 deb http://ftpmaster.internal/ubuntu hoary-backports main restricted universe multiverse
1272 deb http://ftpmaster.internal/ubuntu hoary-security main restricted universe multiverse
1273 deb http://ftpmaster.internal/ubuntu hoary-updates main restricted universe multiverse
1274 Suite: hoary-backports
1275 Ogre-component: main
1276 Archive Purpose: PRIMARY
1277 Archive Private: False
1278
1279A build in the security pocket:
1280
1281 >>> a_builder.currentjob.destroySelf()
1282
1283 >>> bqItem3 = a_build.queueBuild()
1284 >>> removeSecurityProxy(build).status = (
1285 ... BuildStatus.NEEDSBUILD)
1286 >>> removeSecurityProxy(build).pocket = (
1287 ... PackagePublishingPocket.SECURITY)
1288 >>> last_stub_mail_count = len(stub.test_emails)
1289
1290The pocket-dependency infrastructure is ready to deal with SECURITY
1291pocket, however we explicitly skip security builds when dispatching
1292because Embargoed-Archives and Restricted-UI implementations are not
1293yet ready.
1294
1295 >>> removeSecurityProxy(a_builder)._dispatchBuildCandidate(bqItem3)
1296 Traceback (most recent call last):
1297 ...
1298 AssertionError: Soyuz is not yet capable of building SECURITY uploads.
1299
1300Builds for security pocket are marked as FAILEDTOBUILD inside the
1301_findBuildCandidate() method, see doc/buildd-dispatching.txt
1302
1303813
1304== Builder Status Handler ==814== Builder Status Handler ==
1305815
1306816
=== modified file 'lib/lp/soyuz/model/binarypackagebuildbehavior.py'
--- lib/lp/soyuz/model/binarypackagebuildbehavior.py 2010-08-23 16:51:11 +0000
+++ lib/lp/soyuz/model/binarypackagebuildbehavior.py 2010-09-22 10:37:47 +0000
@@ -99,8 +99,9 @@
99 distroseries state.99 distroseries state.
100 """100 """
101 build = self.build101 build = self.build
102 assert not (not self._builder.virtualized and build.is_virtualized), (102 if build.is_virtualized and not self._builder.virtualized:
103 "Attempt to build non-virtual item on a virtual builder.")103 raise AssertionError(
104 "Attempt to build non-virtual item on a virtual builder.")
104105
105 # Assert that we are not silently building SECURITY jobs.106 # Assert that we are not silently building SECURITY jobs.
106 # See findBuildCandidates. Once we start building SECURITY107 # See findBuildCandidates. Once we start building SECURITY
107108
=== modified file 'lib/lp/soyuz/scripts/buildd.py'
--- lib/lp/soyuz/scripts/buildd.py 2010-08-27 11:19:54 +0000
+++ lib/lp/soyuz/scripts/buildd.py 2010-09-22 10:37:47 +0000
@@ -276,6 +276,9 @@
276 self.txn.commit()276 self.txn.commit()
277277
278278
279# XXX: JonathanLange 2010-09-22 bug=645046: This is the old slave
280# scanner. Julian says it's not running on production. We should either delete
281# it or update it to use the async apis.
279class SlaveScanner(LaunchpadCronScript):282class SlaveScanner(LaunchpadCronScript):
280283
281 def main(self):284 def main(self):
282285
=== modified file 'lib/lp/soyuz/tests/soyuzbuilddhelpers.py'
--- lib/lp/soyuz/tests/soyuzbuilddhelpers.py 2010-09-20 11:52:51 +0000
+++ lib/lp/soyuz/tests/soyuzbuilddhelpers.py 2010-09-22 10:37:47 +0000
@@ -17,10 +17,8 @@
17 ]17 ]
1818
19from StringIO import StringIO19from StringIO import StringIO
20import subprocess
21import xmlrpclib20import xmlrpclib
2221
23from canonical.config import config
24from lp.buildmaster.interfaces.builder import CannotFetchFile22from lp.buildmaster.interfaces.builder import CannotFetchFile
25from lp.buildmaster.model.builder import (23from lp.buildmaster.model.builder import (
26 rescueBuilderIfLost,24 rescueBuilderIfLost,
@@ -85,68 +83,53 @@
85 updateBuilderStatus(self, logger)83 updateBuilderStatus(self, logger)
8684
8785
86# XXX: It would be *really* nice to run some set of tests against the real
87# BuilderSlave and this one to prevent interface skew.
88class OkSlave:88class OkSlave:
89 """An idle mock slave that prints information about itself.89 """An idle mock slave that prints information about itself.
9090
91 The architecture tag can be customised during initialisation."""91 The architecture tag can be customised during initialisation."""
9292
93 def __init__(self, arch_tag=I386_ARCHITECTURE_NAME):93 def __init__(self, arch_tag=I386_ARCHITECTURE_NAME):
94 self.call_log = []
94 self.arch_tag = arch_tag95 self.arch_tag = arch_tag
9596
96 def status(self):97 def status(self):
97 return ('BuilderStatus.IDLE', '')98 return ('BuilderStatus.IDLE', '')
9899
99 def ensurepresent(self, sha1, url, user=None, password=None):100 def ensurepresent(self, sha1, url, user=None, password=None):
100 print "ensurepresent called, url=%s" % url101 self.call_log.append(('ensurepresent', url, user, password))
101 if user is not None and user != "":
102 print "URL authorisation with %s/%s" % (user, password)
103 return True, None102 return True, None
104103
105 def build(self, buildid, buildtype, chroot, filemap, args):104 def build(self, buildid, buildtype, chroot, filemap, args):
105 self.call_log.append(
106 ('build', buildid, buildtype, chroot, filemap.keys(), args))
106 info = 'OkSlave BUILDING'107 info = 'OkSlave BUILDING'
107 print info
108 if 'archives' in args:
109 print "Archives:"
110 for archive_line in sorted(args['archives']):
111 print " %s" % archive_line
112 else:
113 print "No archives set."
114 print "Suite: %s" % args['suite']
115 print "Ogre-component: %s" % args['ogrecomponent']
116 print "Archive Purpose: %s" % args['archive_purpose']
117 print "Archive Private: %s" % args['archive_private']
118 return ('BuildStatus.Building', info)108 return ('BuildStatus.Building', info)
119109
120 def fetchlogtail(self, size):
121 return 'BOGUS'
122
123 def echo(self, *args):110 def echo(self, *args):
111 self.call_log.append(('echo',) + args)
124 return args112 return args
125113
126 def clean(self):114 def clean(self):
127 pass115 self.call_log.append('clean')
128116
129 def abort(self):117 def abort(self):
130 pass118 self.call_log.append('abort')
131119
132 def info(self):120 def info(self):
121 self.call_log.append('info')
133 return ('1.0', self.arch_tag, 'debian')122 return ('1.0', self.arch_tag, 'debian')
134123
135 def resume(self):
136 resume_argv = config.builddmaster.vm_resume_command.split()
137 resume_process = subprocess.Popen(
138 resume_argv, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
139 stdout, stderr = resume_process.communicate()
140
141 return (stdout, stderr, resume_process.returncode)
142
143 def sendFileToSlave(self, sha1, url, username="", password=""):124 def sendFileToSlave(self, sha1, url, username="", password=""):
125 self.call_log.append('sendFileToSlave')
144 present, info = self.ensurepresent(sha1, url, username, password)126 present, info = self.ensurepresent(sha1, url, username, password)
145 if not present:127 if not present:
146 raise CannotFetchFile(url, info)128 raise CannotFetchFile(url, info)
147129
148 def cacheFile(self, logger, libraryfilealias):130 def cacheFile(self, logger, libraryfilealias):
149 self.sendFileToSlave(131 self.call_log.append('cacheFile')
132 return self.sendFileToSlave(
150 libraryfilealias.content.sha1, libraryfilealias.http_url)133 libraryfilealias.content.sha1, libraryfilealias.http_url)
151134
152135
@@ -158,10 +141,12 @@
158 self.build_id = build_id141 self.build_id = build_id
159142
160 def status(self):143 def status(self):
144 self.call_log.append('status')
161 buildlog = xmlrpclib.Binary("This is a build log")145 buildlog = xmlrpclib.Binary("This is a build log")
162 return ('BuilderStatus.BUILDING', self.build_id, buildlog)146 return ('BuilderStatus.BUILDING', self.build_id, buildlog)
163147
164 def getFile(self, sum):148 def getFile(self, sum):
149 self.call_log.append('getFile')
165 if sum == "buildlog":150 if sum == "buildlog":
166 s = StringIO("This is a build log")151 s = StringIO("This is a build log")
167 s.headers = {'content-length': 19}152 s.headers = {'content-length': 19}
@@ -183,10 +168,12 @@
183 self.valid_file_hashes = ['buildlog']168 self.valid_file_hashes = ['buildlog']
184169
185 def status(self):170 def status(self):
171 self.call_log.append('status')
186 return ('BuilderStatus.WAITING', self.state, self.build_id, {},172 return ('BuilderStatus.WAITING', self.state, self.build_id, {},
187 self.dependencies)173 self.dependencies)
188174
189 def getFile(self, hash):175 def getFile(self, hash):
176 self.call_log.append('getFile')
190 if hash in self.valid_file_hashes:177 if hash in self.valid_file_hashes:
191 content = "This is a %s" % hash178 content = "This is a %s" % hash
192 s = StringIO(content)179 s = StringIO(content)
@@ -198,6 +185,7 @@
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."""
199186
200 def status(self):187 def status(self):
188 self.call_log.append('status')
201 return ('BuilderStatus.ABORTING', '1-1')189 return ('BuilderStatus.ABORTING', '1-1')
202190
203191
@@ -205,6 +193,7 @@
205 """A mock slave that looks like it's aborted."""193 """A mock slave that looks like it's aborted."""
206194
207 def status(self):195 def status(self):
196 self.call_log.append('status')
208 return ('BuilderStatus.ABORTED', '1-1')197 return ('BuilderStatus.ABORTED', '1-1')
209198
210199
@@ -214,10 +203,15 @@
214 When 'aborted' it raises an xmlrpclib.Fault(8002, 'Could not abort')203 When 'aborted' it raises an xmlrpclib.Fault(8002, 'Could not abort')
215 """204 """
216205
206 def __init__(self):
207 self.call_log = []
208
217 def status(self):209 def status(self):
210 self.call_log.append('status')
218 return ('BuilderStatus.BUILDING', '1000-10000')211 return ('BuilderStatus.BUILDING', '1000-10000')
219212
220 def abort(self):213 def abort(self):
214 self.call_log.append('abort')
221 raise xmlrpclib.Fault(8002, "Could not abort")215 raise xmlrpclib.Fault(8002, "Could not abort")
222216
223217
@@ -225,4 +219,5 @@
225 """A mock slave that reports that it is broken."""219 """A mock slave that reports that it is broken."""
226220
227 def status(self):221 def status(self):
222 self.call_log.append('status')
228 raise xmlrpclib.Fault(8001, "Broken slave")223 raise xmlrpclib.Fault(8001, "Broken slave")
229224
=== added file 'lib/lp/soyuz/tests/test_binarypackagebuildbehavior.py'
--- lib/lp/soyuz/tests/test_binarypackagebuildbehavior.py 1970-01-01 00:00:00 +0000
+++ lib/lp/soyuz/tests/test_binarypackagebuildbehavior.py 2010-09-22 10:37:47 +0000
@@ -0,0 +1,204 @@
1# Copyright 2010 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).
3
4from __future__ import with_statement
5
6"""Tests for BinaryPackageBuildBehavior."""
7
8__metaclass__ = type
9
10import transaction
11
12from twisted.internet import defer
13from twisted.trial import unittest as trialtest
14
15from zope.security.proxy import removeSecurityProxy
16
17from canonical.launchpad.scripts.logger import QuietFakeLogger
18from canonical.testing import TwistedLaunchpadZopelessLayer
19
20from lp.registry.interfaces.pocket import (
21 PackagePublishingPocket,
22 pocketsuffix,
23 )
24from lp.registry.interfaces.series import SeriesStatus
25from lp.soyuz.adapters.archivedependencies import (
26 get_sources_list_for_building,
27 )
28from lp.soyuz.enums import (
29 ArchivePurpose,
30 )
31from lp.soyuz.tests.soyuzbuilddhelpers import OkSlave
32from lp.testing import (
33 ANONYMOUS,
34 login_as,
35 logout,
36 )
37from lp.testing.factory import LaunchpadObjectFactory
38
39
40class TestBinaryBuildPackageBehavior(trialtest.TestCase):
41 """Tests for the BinaryPackageBuildBehavior.
42
43 In particular, these tests are about how the BinaryPackageBuildBehavior
44 interacts with the build slave. We test this by using a test double that
45 implements the same interface as `BuilderSlave` but instead of actually
46 making XML-RPC calls, just records any method invocations along with
47 interesting parameters.
48 """
49
50 layer = TwistedLaunchpadZopelessLayer
51
52 def setUp(self):
53 super(TestBinaryBuildPackageBehavior, self).setUp()
54 self.factory = LaunchpadObjectFactory()
55 login_as(ANONYMOUS)
56 self.addCleanup(logout)
57 self.layer.switchDbUser('testadmin')
58
59 def assertExpectedInteraction(self, ignored, call_log, builder, build,
60 chroot, archive, archive_purpose, component,
61 extra_urls=None, filemap_names=None):
62 expected = self.makeExpectedInteraction(
63 builder, build, chroot, archive, archive_purpose, component,
64 extra_urls, filemap_names)
65 self.assertEqual(call_log, expected)
66
67 def makeExpectedInteraction(self, builder, build, chroot, archive,
68 archive_purpose, component,
69 extra_urls=None, filemap_names=None):
70 """Build the log of calls that we expect to be made to the slave.
71
72 :param builder: The builder we are using to build the binary package.
73 :param build: The build being done on the builder.
74 :param chroot: The `LibraryFileAlias` for the chroot in which we are
75 building.
76 :param archive: The `IArchive` into which we are building.
77 :param archive_purpose: The ArchivePurpose we are sending to the
78 builder. We specify this separately from the archive because
79 sometimes the behavior object has to give a different purpose
80 in order to trick the slave into building correctly.
81 :return: A list of the calls we expect to be made.
82 """
83 job = removeSecurityProxy(builder.current_build_behavior).buildfarmjob
84 build_id = job.generateSlaveBuildCookie()
85 ds_name = build.distro_arch_series.distroseries.name
86 suite = ds_name + pocketsuffix[build.pocket]
87 archives = get_sources_list_for_building(
88 build, build.distro_arch_series,
89 build.source_package_release.name)
90 arch_indep = build.distro_arch_series.isNominatedArchIndep
91 if filemap_names is None:
92 filemap_names = []
93 if extra_urls is None:
94 extra_urls = []
95
96 upload_logs = [
97 ['cacheFile', 'sendFileToSlave', ('ensurepresent', url, '', '')]
98 for url in [chroot.http_url] + extra_urls]
99
100 extra_args = {
101 'arch_indep': arch_indep,
102 'arch_tag': build.distro_arch_series.architecturetag,
103 'archive_private': archive.private,
104 'archive_purpose': archive_purpose.name,
105 'archives': archives,
106 'build_debug_symbols': archive.build_debug_symbols,
107 'ogrecomponent': component,
108 'suite': suite,
109 }
110 build_log = [
111 ('build', build_id, 'binarypackage', chroot.content.sha1,
112 filemap_names, extra_args)]
113 return sum(upload_logs, []) + build_log
114
115 def startBuild(self, builder, candidate):
116 builder = removeSecurityProxy(builder)
117 candidate = removeSecurityProxy(candidate)
118 return defer.maybeDeferred(
119 builder.startBuild, candidate, QuietFakeLogger())
120
121 def test_non_virtual_ppa_dispatch(self):
122 # When the BinaryPackageBuildBehavior dispatches PPA builds to
123 # non-virtual builders, it stores the chroot on the server and
124 # requests a binary package build, lying to say that the archive
125 # purpose is "PRIMARY" because this ensures that the package mangling
126 # tools will run over the built packages.
127 archive = self.factory.makeArchive(virtualized=False)
128 slave = OkSlave()
129 builder = self.factory.makeBuilder(virtualized=False)
130 builder.setSlaveForTesting(slave)
131 build = self.factory.makeBinaryPackageBuild(
132 builder=builder, archive=archive)
133 lf = self.factory.makeLibraryFileAlias()
134 transaction.commit()
135 build.distro_arch_series.addOrUpdateChroot(lf)
136 candidate = build.queueBuild()
137 d = self.startBuild(builder, candidate)
138 d.addCallback(
139 self.assertExpectedInteraction, slave.call_log,
140 builder, build, lf, archive, ArchivePurpose.PRIMARY, 'universe')
141 return d
142
143 def test_partner_dispatch_no_publishing_history(self):
144 archive = self.factory.makeArchive(
145 virtualized=False, purpose=ArchivePurpose.PARTNER)
146 slave = OkSlave()
147 builder = self.factory.makeBuilder(virtualized=False)
148 builder.setSlaveForTesting(slave)
149 build = self.factory.makeBinaryPackageBuild(
150 builder=builder, archive=archive)
151 lf = self.factory.makeLibraryFileAlias()
152 transaction.commit()
153 build.distro_arch_series.addOrUpdateChroot(lf)
154 candidate = build.queueBuild()
155 d = self.startBuild(builder, candidate)
156 d.addCallback(
157 self.assertExpectedInteraction, slave.call_log,
158 builder, build, lf, archive,
159 ArchivePurpose.PARTNER, build.current_component.name)
160 return d
161
162 def test_dont_dispatch_release_builds(self):
163 archive = self.factory.makeArchive(purpose=ArchivePurpose.PRIMARY)
164 builder = self.factory.makeBuilder()
165 distroseries = self.factory.makeDistroSeries(
166 status=SeriesStatus.CURRENT, distribution=archive.distribution)
167 distro_arch_series = self.factory.makeDistroArchSeries(
168 distroseries=distroseries)
169 build = self.factory.makeBinaryPackageBuild(
170 builder=builder, archive=archive,
171 distroarchseries=distro_arch_series,
172 pocket=PackagePublishingPocket.RELEASE)
173 lf = self.factory.makeLibraryFileAlias()
174 transaction.commit()
175 build.distro_arch_series.addOrUpdateChroot(lf)
176 candidate = build.queueBuild()
177 behavior = candidate.required_build_behavior
178 behavior.setBuilder(build)
179 e = self.assertRaises(
180 AssertionError, behavior.verifyBuildRequest, QuietFakeLogger())
181 expected_message = (
182 "%s (%s) can not be built for pocket %s: invalid pocket due "
183 "to the series status of %s." % (
184 build.title, build.id, build.pocket.name,
185 build.distro_series.name))
186 self.assertEqual(expected_message, str(e))
187
188 def test_dont_dispatch_security_builds(self):
189 archive = self.factory.makeArchive(purpose=ArchivePurpose.PRIMARY)
190 builder = self.factory.makeBuilder()
191 build = self.factory.makeBinaryPackageBuild(
192 builder=builder, archive=archive,
193 pocket=PackagePublishingPocket.SECURITY)
194 lf = self.factory.makeLibraryFileAlias()
195 transaction.commit()
196 build.distro_arch_series.addOrUpdateChroot(lf)
197 candidate = build.queueBuild()
198 behavior = candidate.required_build_behavior
199 behavior.setBuilder(build)
200 e = self.assertRaises(
201 AssertionError, behavior.verifyBuildRequest, QuietFakeLogger())
202 self.assertEqual(
203 'Soyuz is not yet capable of building SECURITY uploads.',
204 str(e))
0205
=== modified file 'lib/lp/testing/factory.py'
--- lib/lp/testing/factory.py 2010-09-21 11:45:15 +0000
+++ lib/lp/testing/factory.py 2010-09-22 10:37:47 +0000
@@ -1944,6 +1944,9 @@
1944 processorfamily = ProcessorFamilySet().getByName('powerpc')1944 processorfamily = ProcessorFamilySet().getByName('powerpc')
1945 if owner is None:1945 if owner is None:
1946 owner = self.makePerson()1946 owner = self.makePerson()
1947 # XXX: architecturetag & processerfamily are tightly coupled. It's
1948 # wrong to just make a fresh architecture tag without also making a
1949 # processor family to go with it (ideally with processors!)
1947 if architecturetag is None:1950 if architecturetag is None:
1948 architecturetag = self.getUniqueString('arch')1951 architecturetag = self.getUniqueString('arch')
1949 return distroseries.newArch(1952 return distroseries.newArch(
@@ -2625,7 +2628,7 @@
26252628
2626 def makeBinaryPackageBuild(self, source_package_release=None,2629 def makeBinaryPackageBuild(self, source_package_release=None,
2627 distroarchseries=None, archive=None, builder=None,2630 distroarchseries=None, archive=None, builder=None,
2628 status=None):2631 status=None, pocket=None):
2629 """Create a BinaryPackageBuild.2632 """Create a BinaryPackageBuild.
26302633
2631 If archive is not supplied, the source_package_release is used2634 If archive is not supplied, the source_package_release is used
@@ -2656,13 +2659,15 @@
2656 processorfamily=processor.family)2659 processorfamily=processor.family)
2657 if status is None:2660 if status is None:
2658 status = BuildStatus.NEEDSBUILD2661 status = BuildStatus.NEEDSBUILD
2662 if pocket is None:
2663 pocket = PackagePublishingPocket.RELEASE
2659 binary_package_build = getUtility(IBinaryPackageBuildSet).new(2664 binary_package_build = getUtility(IBinaryPackageBuildSet).new(
2660 source_package_release=source_package_release,2665 source_package_release=source_package_release,
2661 processor=processor,2666 processor=processor,
2662 distro_arch_series=distroarchseries,2667 distro_arch_series=distroarchseries,
2663 status=status,2668 status=status,
2664 archive=archive,2669 archive=archive,
2665 pocket=PackagePublishingPocket.RELEASE,2670 pocket=pocket,
2666 date_created=self.getUniqueDate())2671 date_created=self.getUniqueDate())
2667 naked_build = removeSecurityProxy(binary_package_build)2672 naked_build = removeSecurityProxy(binary_package_build)
2668 naked_build.builder = builder2673 naked_build.builder = builder
26692674
=== modified file 'lib/lp/testing/tests/test_factory.py'
--- lib/lp/testing/tests/test_factory.py 2010-09-21 11:08:26 +0000
+++ lib/lp/testing/tests/test_factory.py 2010-09-22 10:37:47 +0000
@@ -113,6 +113,11 @@
113 status=BuildStatus.FULLYBUILT)113 status=BuildStatus.FULLYBUILT)
114 self.assertEqual(BuildStatus.FULLYBUILT, bpb.status)114 self.assertEqual(BuildStatus.FULLYBUILT, bpb.status)
115115
116 def test_makeBinaryPackageBuild_uses_pocket(self):
117 bpb = self.factory.makeBinaryPackageBuild(
118 pocket=PackagePublishingPocket.UPDATES)
119 self.assertEqual(PackagePublishingPocket.UPDATES, bpb.pocket)
120
116 def test_makeBinaryPackageBuild_can_be_queued(self):121 def test_makeBinaryPackageBuild_can_be_queued(self):
117 build = self.factory.makeBinaryPackageBuild()122 build = self.factory.makeBinaryPackageBuild()
118 # Just check that makeBinaryPackageBuild returns a build that can be123 # Just check that makeBinaryPackageBuild returns a build that can be