Merge lp:~james-w/launchpad/move-soyuz-test-publisher into lp:launchpad

Proposed by James Westby on 2010-08-09
Status: Work in progress
Proposed branch: lp:~james-w/launchpad/move-soyuz-test-publisher
Merge into: lp:launchpad
Prerequisite: lp:~james-w/launchpad/more-matchers
Diff against target: 1673 lines (+1213/-251)
6 files modified
lib/lp/archivepublisher/config.py (+19/-0)
lib/lp/archivepublisher/tests/test_config.py (+50/-23)
lib/lp/registry/browser/tests/test_person_view.py (+3/-1)
lib/lp/registry/tests/test_distributionsourcepackage.py (+2/-1)
lib/lp/soyuz/testing/publisher.py (+1049/-0)
lib/lp/soyuz/tests/test_publishing.py (+90/-226)
To merge this branch: bzr merge lp:~james-w/launchpad/move-soyuz-test-publisher
Reviewer Review Type Date Requested Status
Launchpad code reviewers 2010-08-09 Pending
Review via email: mp+32157@code.launchpad.net

Commit message

Add lp.soyuz.testing.publisher to replace SoyuzTestPublisher and TestNativePublishingBase from lp.soyuz.tests.test_publishing.

Description of the change

Hi,

This branch moves SoyuzTestPublisher and the associated
TestNativePublishingBase to lp.soyuz.testing.publisher,
and also changes the API somewhat.

The main thrust of this change is to get tests away from
sampledata, but there are far to many using these classes
to do it in one go. Therefore I created a new class that
can be transitioned to gradually.

In addition to this I changed the API somewhat to be what
I consider to be cleaner. This way mainly a taste thing,
but some of the changes will also stop tests being too
tightly bound to the implementation of these classes, giving
us more freedom to change things in future. Some of the changes
were a little more than that though, such as removing lots
of commits from the tests using TestNativePublishingBase.
If there are lots of tests that need that many commits then
we can add it back as an opt-in thing, we should punish
every test with it.

In addition I also documented the new interface with docstrings,
and a module docstring to help with porting.

This branch clocks in a bit heavy, but I hope you will forgive
me as quite a lot of that is added docstrings, and there is
quite a lot of moved code.

Thanks,

James

To post a comment you must log in.
11349. By James Westby on 2010-08-10

Inherit the binary publication component from the source.

11350. By James Westby on 2010-08-10

Use removeSecurityProxy to change an upload_archive.

Jonathan Lange (jml) wrote :
Download full text (5.4 KiB)

On Mon, Aug 9, 2010 at 11:39 PM, James Westby <email address hidden> wrote:
> James Westby has proposed merging lp:~james-w/launchpad/move-soyuz-test-publisher into lp:launchpad/devel with lp:~james-w/launchpad/more-matchers as a prerequisite.
>
> Requested reviews:
>  Launchpad code reviewers (launchpad-reviewers)
>
>
> Hi,
>
> This branch moves SoyuzTestPublisher and the associated
> TestNativePublishingBase to lp.soyuz.testing.publisher,
> and also changes the API somewhat.
>

Thanks!

FWIW, code reviews are much simpler if simple code moves are separated
from API changes. However, I do not wish to look a gift horse in the
mouth, so...

> The main thrust of this change is to get tests away from
> sampledata, but there are far to many using these classes
> to do it in one go. Therefore I created a new class that
> can be transitioned to gradually.
>

Seems sensible.

> In addition to this I changed the API somewhat to be what
> I consider to be cleaner. This way mainly a taste thing,
> but some of the changes will also stop tests being too
> tightly bound to the implementation of these classes, giving
> us more freedom to change things in future.

That's ok, I have excellent taste.

> Some of the changes
> were a little more than that though, such as removing lots
> of commits from the tests using TestNativePublishingBase.
> If there are lots of tests that need that many commits then
> we can add it back as an opt-in thing, we should punish
> every test with it.
>

+1

> In addition I also documented the new interface with docstrings,
> and a module docstring to help with porting.
>

Sweet!

Only typos noticed below, along with a couple of small nitpicks. Feel
free to land without getting another review.

...
> === added file 'lib/lp/soyuz/testing/__init__.py'
> === renamed file 'lib/lp/soyuz/testing/__init__.py' => 'lib/lp/soyuz/testing/publisher.py'
> --- lib/lp/soyuz/testing/__init__.py    2010-08-09 22:38:48 +0000
> +++ lib/lp/soyuz/testing/publisher.py   2010-08-09 22:38:53 +0000
> @@ -0,0 +1,1059 @@
> +# Copyright 2010 Canonical Ltd.  This software is licensed under the
> +# GNU Affero General Public License version 3 (see the file LICENSE).
> +
> +"""Testing helpers for publishing.
> +
> +Porting from TestNativePublishingBase to PublishingTestCase:
> +
...
> +
> +Porting from `lp.soyuz.tests.test_publishing.SoyuzTestPublisher` to
> +`lp.soyuz.testing.publisher.SoyuzTestPublisher`:
> +
...
> +"""
> +
> +__metaclass__ = type
> +
> +__all__ = [
> +    'makeDistributionLucilleconfig',
> +    'makeDistroSeriesLucilleconfig',
> +    'PublishingTestCase',
> +    'SoyuzTestPublisher',
> +]
> +
...
> +
> +class SoyuzTestPublisher:
> +    """Helper class able to publish source and binary packages.
> +
...
> +
> +    Each method has a number of paramters that can be used to control

"parameters"

...
> +    def addFile(self, filename, filecontent=None, restricted=False,
> +                expires=None):
> +        """Add a file to the Librarian.
> +
> +        :param filename: the filename to add.
> +        :param filecontent: the content of the file, or None to generate
> +            some content.
> +        :param restricted: whether t...

Read more...

Unmerged revisions

11350. By James Westby on 2010-08-10

Use removeSecurityProxy to change an upload_archive.

11349. By James Westby on 2010-08-10

Inherit the binary publication component from the source.

11348. By James Westby on 2010-08-09

Some adjustments to fix test fallout.

11347. By James Westby on 2010-08-09

Write some porting documentation.

11346. By James Westby on 2010-08-09

Have the PublishingTestCase clean up the created directories.

11345. By James Westby on 2010-08-09

Port test_config from sampledata.

11344. By James Westby on 2010-08-09

Finish documenting the new interface.

11343. By James Westby on 2010-08-09

Revert test cleanups for moving to a subsequent branch.

11342. By James Westby on 2010-08-09

Revert change of layer as it is no longer necessary.

11341. By James Westby on 2010-08-09

Fix a test.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/archivepublisher/config.py'
2--- lib/lp/archivepublisher/config.py 2010-07-07 06:28:03 +0000
3+++ lib/lp/archivepublisher/config.py 2010-08-10 01:42:59 +0000
4@@ -7,6 +7,7 @@
5 # distribution and distroseries tables
6
7 import os
8+import shutil
9 from StringIO import StringIO
10 from ConfigParser import ConfigParser
11
12@@ -192,3 +193,21 @@
13 continue
14 if not os.path.exists(directory):
15 os.makedirs(directory, 0755)
16+
17+ def removeArchiveDirs(self):
18+ required_directories = [
19+ self.distroroot,
20+ self.poolroot,
21+ self.distsroot,
22+ self.archiveroot,
23+ self.cacheroot,
24+ self.overrideroot,
25+ self.miscroot,
26+ self.temproot,
27+ ]
28+
29+ for directory in required_directories:
30+ if directory is None:
31+ continue
32+ if os.path.exists(directory):
33+ shutil.rmtree(directory)
34
35=== modified file 'lib/lp/archivepublisher/tests/test_config.py'
36--- lib/lp/archivepublisher/tests/test_config.py 2010-07-18 00:24:06 +0000
37+++ lib/lp/archivepublisher/tests/test_config.py 2010-08-10 01:42:59 +0000
38@@ -5,52 +5,79 @@
39
40 __metaclass__ = type
41
42-import unittest
43-
44-from zope.component import getUtility
45+import os
46
47 from canonical.config import config
48-from canonical.launchpad.interfaces import IDistributionSet
49 from canonical.testing import LaunchpadZopelessLayer
50-
51-
52-class TestConfig(unittest.TestCase):
53+from lp.archivepublisher.config import Config
54+from lp.soyuz.testing.publisher import (
55+ makeDistributionLucilleconfig, makeDistroSeriesLucilleconfig)
56+from lp.testing import TestCaseWithFactory
57+
58+
59+class TestConfig(TestCaseWithFactory):
60 layer = LaunchpadZopelessLayer
61
62 def setUp(self):
63+ super(TestConfig, self).setUp()
64 self.layer.switchDbUser(config.archivepublisher.dbuser)
65- self.ubuntutest = getUtility(IDistributionSet)['ubuntutest']
66+ self.distribution = self.factory.makeDistribution()
67+ makeDistributionLucilleconfig(self.distribution)
68+ series1 = self.factory.makeDistroSeries(
69+ distribution=self.distribution)
70+ makeDistroSeriesLucilleconfig(series1)
71+ series2 = self.factory.makeDistroSeries(
72+ distribution=self.distribution)
73+ makeDistroSeriesLucilleconfig(series2)
74+ for series in (series1, series2):
75+ for i in range(2):
76+ self.factory.makeDistroArchSeries(distroseries=series)
77+
78+ def getConfig(self):
79+ return Config(self.distribution)
80
81 def testInstantiate(self):
82 """Config should instantiate"""
83- from lp.archivepublisher.config import Config
84- d = Config(self.ubuntutest)
85+ d = self.getConfig()
86
87 def testDistroName(self):
88 """Config should be able to return the distroName"""
89- from lp.archivepublisher.config import Config
90- d = Config(self.ubuntutest)
91- self.assertEqual(d.distroName, "ubuntutest")
92+ d = self.getConfig()
93+ self.assertEqual(self.distribution.name, d.distroName)
94
95 def testDistroSeriesNames(self):
96 """Config should return two distroseries names"""
97- from lp.archivepublisher.config import Config
98- d = Config(self.ubuntutest)
99+ d = self.getConfig()
100 dsns = d.distroSeriesNames()
101- self.assertEquals(len(dsns), 2)
102- self.assertEquals(dsns[0], "breezy-autotest")
103- self.assertEquals(dsns[1], "hoary-test")
104+ self.assertEqual(
105+ sorted([ds.name for ds in self.distribution.series]),
106+ sorted(dsns))
107
108 def testArchTagsForSeries(self):
109 """Config should have the arch tags for the drs"""
110- from lp.archivepublisher.config import Config
111- d = Config(self.ubuntutest)
112- archs = d.archTagsForSeries("hoary-test")
113+ d = self.getConfig()
114+ archs = d.archTagsForSeries(self.distribution.series[0].name)
115 self.assertEquals(len(archs), 2)
116
117 def testDistroConfig(self):
118 """Config should have parsed a distro config"""
119- from lp.archivepublisher.config import Config
120- d = Config(self.ubuntutest)
121+ d = self.getConfig()
122 # NOTE: Add checks here when you add stuff in util.py
123 self.assertEquals(d.stayofexecution, 5)
124+
125+ def test_removeArchiveDirs(self):
126+ d = self.getConfig()
127+ d.setupArchiveDirs()
128+ d.removeArchiveDirs()
129+ for directory in [
130+ d.distroroot,
131+ d.poolroot,
132+ d.distsroot,
133+ d.archiveroot,
134+ d.cacheroot,
135+ d.overrideroot,
136+ d.miscroot,
137+ d.temproot,
138+ ]:
139+ self.assertFalse(
140+ os.path.exists(directory), "%s was not deleted" % directory)
141
142=== modified file 'lib/lp/registry/browser/tests/test_person_view.py'
143--- lib/lp/registry/browser/tests/test_person_view.py 2010-08-02 02:13:52 +0000
144+++ lib/lp/registry/browser/tests/test_person_view.py 2010-08-10 01:42:59 +0000
145@@ -7,6 +7,7 @@
146
147 import transaction
148 from zope.component import getUtility
149+from zope.security.proxy import removeSecurityProxy
150
151 from canonical.config import config
152 from canonical.launchpad.ftests import ANONYMOUS, login
153@@ -528,7 +529,8 @@
154 pub_source=src_pub)
155 self.build = binaries[0].binarypackagerelease.build
156 self.build.status = BuildStatus.FAILEDTOBUILD
157- self.build.archive = publisher.distroseries.main_archive
158+ removeSecurityProxy(
159+ self.build).archive = publisher.distroseries.main_archive
160 login(ANONYMOUS)
161
162 def test_related_software_with_failed_build(self):
163
164=== modified file 'lib/lp/registry/tests/test_distributionsourcepackage.py'
165--- lib/lp/registry/tests/test_distributionsourcepackage.py 2009-07-19 23:17:34 +0000
166+++ lib/lp/registry/tests/test_distributionsourcepackage.py 2010-08-10 01:42:59 +0000
167@@ -9,6 +9,7 @@
168 import unittest
169
170 from zope.component import getUtility
171+from zope.security.proxy import removeSecurityProxy
172
173 from canonical.testing import LaunchpadZopelessLayer
174
175@@ -136,7 +137,7 @@
176 # Ensure that the gedit package in gedit-nightly was originally
177 # uploaded to gedit-beta (ie. copied from there).
178 gedit_release = self.gedit_nightly_src_hist.sourcepackagerelease
179- gedit_release.upload_archive = self.archives['gedit-beta']
180+ removeSecurityProxy(gedit_release).upload_archive = self.archives['gedit-beta']
181
182 related_archives = self.source_package.findRelatedArchives()
183 related_archive_names = [
184
185=== added file 'lib/lp/soyuz/testing/__init__.py'
186=== renamed file 'lib/lp/soyuz/testing/__init__.py' => 'lib/lp/soyuz/testing/publisher.py'
187--- lib/lp/soyuz/testing/__init__.py 2010-08-10 01:42:55 +0000
188+++ lib/lp/soyuz/testing/publisher.py 2010-08-10 01:42:59 +0000
189@@ -0,0 +1,1049 @@
190+# Copyright 2010 Canonical Ltd. This software is licensed under the
191+# GNU Affero General Public License version 3 (see the file LICENSE).
192+
193+"""Testing helpers for publishing.
194+
195+Porting from TestNativePublishingBase to PublishingTestCase:
196+
197+ * The publisher methods are no longer available on `self`. Use the
198+ instance variable `publisher` now.
199+ * `self.pool_dir` and `self.temp_dir` are now not available by
200+ default, either use `self.config.poolroot` and `self.config.temproot`,
201+ or create a subclass with a setUp that sets them if you access them
202+ a lot.
203+ * The archive directories on disk will be removed at `tearDown` time.
204+ * `checkPublication`, `checkPublications`, `checkPastDate` and
205+ `checkSuperseded` are now not available by default, replaced by
206+ matchers.
207+ - `self.checkPublication(pub, status)` is now
208+ `self.assertThat(pub, PublishedStateIs(status))`
209+ - `self.checkPublications(pubs, status)` is now
210+ `self.assertThat(pubs, PublishedStateIs(status))`
211+ - `self.checkPastDate(date, lag=lag)` is now
212+ `self.assertThat(date, DateIsInPast(lag=lag))`
213+ - `self.checkSuperseded(pubs, supersededby=supersededby)` is now
214+ `self.assertThat(pubs, IsSupersededBy(supersededby))`
215+ Where `PublishedStateIs` and `IsSupersededBy` can be imported from
216+ `lp.soyuz.testing.matchers`, and `DateIsInPast` can be imported
217+ from `lp.testing.matchers`.
218+ * As `self.getPubSource` and `self.getPubBinaries` are no more they
219+ no longer commit after they are called.
220+ * See below for changed usage of `SoyuzTestPublisher` as well.
221+
222+Porting from `lp.soyuz.tests.test_publishing.SoyuzTestPublisher` to
223+`lp.soyuz.testing.publisher.SoyuzTestPublisher`:
224+
225+ * `prepareBreezyAutotest` is removed, in favour of using the
226+ factory. Replace calls by `prepare`, or `prepareForBinaryPublications`
227+ depending on whether you plan to publish binaries.
228+ * The `ubuntutest` attribute is replaced by `distribution` and now
229+ could be any distribution.
230+ * The `breezy_autotest` attribute has been replaced by `distroseries`,
231+ and now could be any distroseries of `distribution`.
232+ * The `person` attribute has been removed, and uploads are now
233+ attributed to arbitrary people.
234+ * The `breezy_autotest_i386` and `breezy_autotest_hppa` attributes
235+ have been removed.
236+ * The `SourcePackageName` for the default package name isn't created
237+ until it is needed.
238+ * Some methods may have different defaults for some less important
239+ parameters. These should be specified explicitly if needed.
240+ * The following methods have been replaced,
241+ - `getPubSource` is replaced by `publishSource`
242+ - `getPubBinaries` is replaced by `publishBinaries`
243+ - `addPackageUpload` is replaced by `makePackageUpload`
244+ - `addMockFile` is replaced by `addFile`
245+"""
246+
247+__metaclass__ = type
248+
249+__all__ = [
250+ 'makeDistributionLucilleconfig',
251+ 'makeDistroSeriesLucilleconfig',
252+ 'PublishingTestCase',
253+ 'SoyuzTestPublisher',
254+]
255+
256+import datetime
257+import operator
258+import os
259+
260+import pytz
261+from zope.security.proxy import removeSecurityProxy
262+
263+from canonical.config import config
264+from canonical.database.constants import UTC_NOW
265+from canonical.launchpad.scripts import QuietFakeLogger
266+from canonical.testing import LaunchpadZopelessLayer
267+from lp.archivepublisher.config import Config
268+from lp.archivepublisher.diskpool import DiskPool
269+from lp.buildmaster.interfaces.buildbase import BuildStatus
270+from lp.registry.interfaces.pocket import PackagePublishingPocket
271+from lp.soyuz.interfaces.binarypackagerelease import BinaryPackageFormat
272+from lp.soyuz.interfaces.publishing import (
273+ PackagePublishingPriority, PackagePublishingStatus)
274+from lp.testing import TestCaseWithFactory
275+from lp.testing.factory import LaunchpadObjectFactory
276+
277+
278+class SoyuzTestPublisher:
279+ """Helper class able to publish source and binary packages.
280+
281+ Once you have a test publisher you can use it to publish packages,
282+ either source only, or source and binary, with all required
283+ links between them. This can ease complicated test setup where lots
284+ of coherent objects are required. Where your needs are more simple,
285+ you may be better served by using the LaunchpadObjectFactory directly,
286+ to avoid coupling your tests with aspects that aren't important to it.
287+
288+ To create a SoyuzTestPublisher, simply instantiate the class. If you
289+ already have an instance of the LaunchpadObjectFactory you should
290+ pass this to the constructor, but if you don't you can omit it and
291+ one will be created for you.
292+
293+ publisher = SoyuzTestPublisher(factory=factory)
294+
295+ The test publisher has a distribution and a distroseries within
296+ that distribution which are the default targets of the packages
297+ that it publishes. It is required to set these up by calling
298+
299+ publisher.prepare()
300+
301+ or if you are going to publish binary packages
302+
303+ publisher.prepareForBinaryPublications()
304+
305+ At any time you can change the default distroseries, for instance
306+ if you wish to publish packages to two distroseries during the course
307+ of your tests. You can do this by calling
308+
309+ publisher.setDefaultDistroSeries(distroseries=distroseries)
310+
311+ or alternatively omit the distroseries parameter to have a new
312+ distroseries created in the default distribution.
313+
314+ You are then ready to publish packages. For this use the publish
315+ methods. To publish a source package call
316+
317+ source_publishing = publisher.publishSource()
318+
319+ which will publish a new source package in to the default distroseries,
320+ and return the publishing record to you.
321+
322+ To publish binary packages call
323+
324+ binary_publishings = publisher.publishBinaries()
325+
326+ which will create you a source package, and then a binary package for
327+ each architecture in the default distroseries, with the associated
328+ build records, and return you a list of the binary publishing records
329+ that it created.
330+
331+ Each method has a number of paramters that can be used to control
332+ various aspects of the packages that are published, such as the name,
333+ version, pocket, status, etc. You should specify all of the parameters
334+ that are germane to your test, to decouple your tests from the defaults
335+ of the test publisher.
336+
337+ There are additional methods that may be of use in certain situations,
338+ as they allow you to create subsets of the objects created by the
339+ above methods, or supplemental objects that are required by some tests.
340+ """
341+
342+ def __init__(self, factory=None):
343+ """Create a `SoyuzTestPublisher`
344+
345+ :param factory: the `LaunchpadObjectFactory` to use for creating
346+ objects, or None to create one.
347+ """
348+ self.factory = factory
349+ if self.factory is None:
350+ self.factory = LaunchpadObjectFactory()
351+ self.default_package_name = 'foo'
352+
353+ def prepare(self):
354+ """Setup the instance with a standard skeleton.
355+
356+ See `setUpForBinaryPublications` if you wish to publish binaries.
357+ """
358+ self.distribution = self.factory.makeDistribution()
359+ self.setDefaultDistroSeries()
360+
361+ def prepareForBinaryPublications(self):
362+ """Setup this instance for publishing binary packages."""
363+ self.prepare()
364+ distroarchseries1 = self.factory.makeDistroArchSeries(
365+ distroseries=self.distroseries, supports_virtualized=True)
366+ distroarchseries2 = self.factory.makeDistroArchSeries(
367+ distroseries=self.distroseries, supports_virtualized=True)
368+ removeSecurityProxy(self.distroseries).nominatedarchindep = (
369+ distroarchseries1)
370+ self.addFakeChroots(distroseries=self.distroseries)
371+
372+ def setDefaultDistroSeries(self, distroseries=None):
373+ """Set the default series for publishing packages.
374+
375+ If you don't specify a distroseries as a target in other method
376+ calls then the distroseries set as default by the last call
377+ to this method will be used.
378+
379+ :param distroseries: The `IDistroSeries` to use as default. If
380+ it's None, one will be created.
381+ :return: The default `IDistroSeries`.
382+ """
383+ if distroseries is None:
384+ distroseries = self.factory.makeDistroRelease(
385+ distribution=self.distribution)
386+ self.distroseries = distroseries
387+ return self.distroseries
388+
389+ def addFakeChroots(self, distroseries=None):
390+ """Add fake chroots for all the architectures in distroseries.
391+
392+ This creates files on the librarian for each `IDistroArchSeries`
393+ in the distroseries. The chroots aren't suitable for actually
394+ building packages, but are sufficient for other methods to
395+ believe it would be worth trying.
396+
397+ :param distroseries: the `IDistroSeries` for which each architecture
398+ will get a chroot, this can be None to use the default
399+ distroseries.
400+ """
401+ if distroseries is None:
402+ distroseries = self.distroseries
403+ fake_chroot = self.addFile('fake_chroot.tar.gz')
404+ for arch in distroseries.architectures:
405+ arch.addOrUpdateChroot(fake_chroot)
406+
407+ def addFile(self, filename, filecontent=None, restricted=False,
408+ expires=None):
409+ """Add a file to the Librarian.
410+
411+ :param filename: the filename to add.
412+ :param filecontent: the content of the file, or None to generate
413+ some content.
414+ :param restricted: whether the file should be on the restricted
415+ librarian.
416+ :param exipres: a `datetime.datetime` at which the file should
417+ expire, or None to not have the file expire.
418+ :return: an `ILibraryFileAlias` corresponding to the file uploaded.
419+ """
420+ return self.factory.makeLibraryFileAlias(
421+ filename=filename, content=filecontent, restricted=restricted,
422+ content_type='application/text', expires=expires)
423+
424+ # backwards compatibility for the old interface.
425+ addMockFile = addFile
426+
427+ def makePackageUpload(self, archive=None, distroseries=None,
428+ pocket=None, changes_file_name=None,
429+ changes_file_content=None, signing_key=None,
430+ status=None):
431+ """Make a `PackageUpload`.
432+
433+ :param archive: the archive to upload to, or None to use
434+ the default archive.
435+ :param distroseries: the distroseries to upload to, or
436+ None to use the default.
437+ :param pocket: the `PackagePublishingPocket` to upload to,
438+ or None for the default pocket, RELEASE.
439+ :param changes_file_name: the filename of the changes file
440+ to create, or None for an arbitrary name.
441+ :param changes_file_content: the content of the changes
442+ file, or None to generate some.
443+ :param signing_key: the key with which to sign the upload,
444+ or None to have an unsigned upload.
445+ :param status: the `PackageUploadStatus` of the upload, or
446+ None for an arbitrary status.
447+ :return: the created `PackageUpload`.
448+ """
449+ if distroseries is None:
450+ distroseries = self.distroseries
451+ if archive is None:
452+ archive = distroseries.distribution.main_archive
453+ if pocket is None:
454+ pocket = PackagePublishingPocket.RELEASE
455+ package_upload = self.factory.makePackageUpload(
456+ archive=archive, distroseries=distroseries, pocket=pocket,
457+ changes_filename=changes_file_name,
458+ changes_file_content=changes_file_content,
459+ signing_key=signing_key, status=status)
460+ return package_upload
461+
462+ def makeSourcePackageRelease(self, distroseries=None, sourcename=None,
463+ archive=None, version=None, urgency=None,
464+ component_name=None, section_name=None,
465+ maintainer=None, creator=None,
466+ builddepends=None, builddependsindep=None,
467+ build_conflicts=None,
468+ build_conflicts_indep=None,
469+ architecturehintlist=None,
470+ dsc_signing_key=None,
471+ dsc_maintainer_rfc822=None,
472+ dsc_standards_version=None,
473+ dsc_format=None, dsc_binaries=None,
474+ date_uploaded=None, changelog_entry=None):
475+ """Make a `SourcePackageRelease`.
476+
477+ :param distroseries: the distroseries that the package should
478+ be targered to, or None to use the default.
479+ :param archive: the archive that should be targeted, or
480+ None to use the default.
481+ :param sourcename: the (string) source package name to create
482+ a package for, or None to use the default.
483+ :param version: the (string) version of the package to create,
484+ or None to use an arbitrary version.
485+ :param component_name: the name of the component the package
486+ should be targeted at, or None to use an arbitrary component.
487+ :param section_name: the name of the section the package
488+ should be targeted to, or None to use an arbitrary section.
489+ :param urgency: the `SourcePackageUrgency` that should be used for
490+ the created `SourcePackageRelease`, or None to use an arbitrary
491+ urgency.
492+ :param builddepends: the build depends that should be recorded
493+ for the source package.
494+ :type builddepends: str or None
495+ :param builddependsindep: the Build-Depends-Indep that should
496+ be recorded for the source package.
497+ :type builddependsindep: str or None
498+ :param buildconflicts: the build conflicts that should be recorded
499+ for the source package.
500+ :type buildconflicts: str or None
501+ :param buildconflictsindep: the Build-Conflicts-Indep that should
502+ be recorded for the source package.
503+ :type buildconflictsindep: str or None
504+ :param architecturehintlist: the list of architectures the
505+ source should state it should be built for, either 'all',
506+ 'any', a list of architectures, or None for an arbitrary
507+ hint list.
508+ :type architecturehintlist: str or None
509+ :param dsc_standards_version: the standards version that should
510+ be recorded as having come from the uploaded .dsc, or None
511+ for an arbitrary standards version.
512+ :type dsc_standards_version: str or None
513+ :param dsc_format: the dsc formath that sould be recorded
514+ as having come from the uploaded .dsc, or None for an
515+ arbitrary format.
516+ :type dsc_standards_version: str or None
517+ :param dsc_binaries: the list of binary packages that
518+ should be recorded has having come from the uploaded
519+ .dsc, or None for an arbitrary list.
520+ :type dsc_binaries: str or None
521+ :param dsc_maintainer_rfc822: the string containing the
522+ name and email address of the person that changed the
523+ package, in rfc822 format, or None for an arbitrary
524+ person's details.
525+ :param maintainer: the `IPerson` that should be recorded as
526+ the maintainer of the package, or None for an arbitrary
527+ person.
528+ :param creator: the `IPerson` that should be recorded as
529+ the uploader of the package, or None for an arbitrary
530+ person.
531+ :param date_uploaded: the datetime that the package should
532+ appear to have been uploaded at, or None for an arbitrary
533+ date.
534+ :param changelog_entry: the changelog entry of the upload, or
535+ None for no entry.
536+ :return: the created `SourcePackageRelease`.
537+ """
538+ if distroseries is None:
539+ distroseries = self.distroseries
540+ if archive is None:
541+ archive = distroseries.distribution.main_archive
542+ if sourcename is None:
543+ sourcename = self.default_package_name
544+ spn = self.factory.getOrMakeSourcePackageName(name=sourcename)
545+ component = self.factory.makeComponent(name=component_name)
546+ if dsc_binaries is None:
547+ dsc_binaries = '%s-bin' % sourcename
548+ if architecturehintlist is None:
549+ architecturehintlist = 'all'
550+ if dsc_standards_version is None:
551+ dsc_standards_version = '3.6.2'
552+ if dsc_format is None:
553+ dsc_format = '1.0'
554+ if date_uploaded is None:
555+ date_uploaded = UTC_NOW
556+ return self.factory.makeSourcePackageRelease(
557+ distroseries=distroseries,
558+ sourcepackagename=spn,
559+ maintainer=maintainer,
560+ creator=creator,
561+ component=component,
562+ section_name=section_name,
563+ urgency=urgency,
564+ version=version,
565+ builddepends=builddepends,
566+ builddependsindep=builddependsindep,
567+ build_conflicts=build_conflicts,
568+ build_conflicts_indep=build_conflicts_indep,
569+ architecturehintlist=architecturehintlist,
570+ dscsigningkey=dsc_signing_key,
571+ dsc_maintainer_rfc822=dsc_maintainer_rfc822,
572+ dsc_standards_version=dsc_standards_version,
573+ dsc_format=dsc_format,
574+ dsc_binaries=dsc_binaries,
575+ archive=archive,
576+ date_uploaded=date_uploaded,
577+ changelog_entry=changelog_entry,
578+ )
579+
580+ def publishSource(self, sourcename=None, version=None,
581+ component_name=None, section_name=None,
582+ filename=None, filecontent=None,
583+ changes_file_content=None, status=None, pocket=None,
584+ urgency=None, scheduleddeletiondate=None,
585+ dateremoved=None, distroseries=None, archive=None,
586+ builddepends=None, builddependsindep=None,
587+ build_conflicts=None, build_conflicts_indep=None,
588+ architecturehintlist=None, dsc_standards_version=None,
589+ dsc_format=None, dsc_binaries=None,
590+ dsc_maintainer_rfc822=None, maintainer=None,
591+ creator=None, date_uploaded=None,
592+ files_expire=None, changelog_entry=None):
593+ """Publish a source package.
594+
595+ Publishes a source package and returns the resulting
596+ `SourcePackagePublishingHistory`.
597+
598+ :param sourcename: the (string) source package name to publish
599+ a package for, or None to use the default.
600+ :param version: the (string) version of the package to publish,
601+ or None to use an arbitrary version.
602+ :param component_name: the name of the component to publish to,
603+ or None to use an arbitrary component.
604+ :param section_name: the name of the section to publish to,
605+ or None to use an arbitrary section.
606+ :param filename: the filename of the file making up the
607+ `SourcePackageRelease`, or None to use a name based
608+ on sourcename and version.
609+ :param filecontent: the content of the file making up the
610+ `SourcePackageRelease`, or None to use arbitrary content.
611+ :param changes_file_content: the content of the changes
612+ file for the upload, or None to use arbitrary content.
613+ :param status: the `PackagePublishingStatus` that should be used
614+ for the created publishing record, or None for the default
615+ status, PUBLISHED.
616+ :param pocket: the `PackagePublishingPocket` that should be
617+ used for the created publishing record and the associated
618+ `PackageUpload`, or None for teh default pocket, RELEASE.
619+ :param urgency: the `SourcePackageUrgency` that should be used for
620+ the created `SourcePackageRelease`, or None to use an arbitrary
621+ urgency.
622+ :param scheduleddeletiondate: the scheduled deletion date that
623+ should be set on the created publishing record, or None
624+ to have no scheduled deletion date.
625+ :type scheduleddeletiondate: `datetime.datetime`
626+ :param dateremoved: the date that should be recorded as being
627+ the date the package was removed on the created publishing
628+ record, or None if it hasn't been removed.
629+ :type dateremoved: `datetime.datetime`
630+ :param distroseries: the distroseries that should be
631+ published to, or None to use the default.
632+ :param archive: the archive that should be published to, or
633+ None to use the default.
634+ :param builddepends: the build depends that should be recorded
635+ for the source package.
636+ :type builddepends: str or None
637+ :param builddependsindep: the Build-Depends-Indep that should
638+ be recorded for the source package.
639+ :type builddependsindep: str or None
640+ :param buildconflicts: the build conflicts that should be recorded
641+ for the source package.
642+ :type buildconflicts: str or None
643+ :param buildconflictsindep: the Build-Conflicts-Indep that should
644+ be recorded for the source package.
645+ :type buildconflictsindep: str or None
646+ :param architecturehintlist: the list of architectures the
647+ source should state it should be built for, either 'all',
648+ 'any', a list of architectures, or None for an arbitrary
649+ hint list.
650+ :type architecturehintlist: str or None
651+ :param dsc_standards_version: the standards version that should
652+ be recorded as having come from the uploaded .dsc, or None
653+ for an arbitrary standards version.
654+ :type dsc_standards_version: str or None
655+ :param dsc_format: the dsc formath that sould be recorded
656+ as having come from the uploaded .dsc, or None for an
657+ arbitrary format.
658+ :type dsc_standards_version: str or None
659+ :param dsc_binaries: the list of binary packages that
660+ should be recorded has having come from the uploaded
661+ .dsc, or None for an arbitrary list.
662+ :type dsc_binaries: str or None
663+ :param dsc_maintainer_rfc822: the string containing the
664+ name and email address of the person that changed the
665+ package, in rfc822 format, or None for an arbitrary
666+ person's details.
667+ :param maintainer: the `IPerson` that should be recorded as
668+ the maintainer of the package, or None for an arbitrary
669+ person.
670+ :param creator: the `IPerson` that should be recorded as
671+ the uploader of the package, or None for an arbitrary
672+ person.
673+ :param date_uploaded: the datetime that the package should
674+ appear to have been uploaded at, or None for an arbitrary
675+ date.
676+ :param files_expire: the date at which the librarian files
677+ for the package should expire, or None for no expiry.
678+ :param changelog_entry: the changelog entry of the upload, or
679+ None for no entry.
680+ :return: the created `SourcePackagePublishingHistory`.
681+ """
682+ spr = self.makeSourcePackageRelease(
683+ distroseries=distroseries,
684+ sourcename=sourcename,
685+ archive=archive,
686+ version=version,
687+ urgency=urgency,
688+ component_name=component_name,
689+ section_name=section_name,
690+ maintainer=maintainer,
691+ creator=creator,
692+ builddepends=builddepends,
693+ builddependsindep=builddependsindep,
694+ build_conflicts=build_conflicts,
695+ build_conflicts_indep=build_conflicts_indep,
696+ architecturehintlist=architecturehintlist,
697+ dsc_maintainer_rfc822=dsc_maintainer_rfc822,
698+ dsc_standards_version=dsc_standards_version,
699+ dsc_format=dsc_format,
700+ dsc_binaries=dsc_binaries,
701+ date_uploaded=date_uploaded,
702+ changelog_entry=changelog_entry,
703+ )
704+ changes_file_name = "%s_%s_source.changes" % (
705+ spr.sourcepackagename.name, spr.version)
706+ package_upload = self.makePackageUpload(
707+ archive=spr.upload_archive,
708+ distroseries=spr.upload_distroseries,
709+ pocket=pocket,
710+ changes_file_name=changes_file_name,
711+ changes_file_content=changes_file_content,
712+ )
713+ removeSecurityProxy(package_upload).addSource(spr)
714+
715+ if filename is None:
716+ filename = "%s_%s.dsc" % (
717+ spr.sourcepackagename.name, spr.version)
718+ alias = self.addFile(
719+ filename, filecontent=filecontent,
720+ restricted=spr.upload_archive.private, expires=files_expire)
721+ spr.addFile(alias)
722+
723+ if status is None:
724+ status = PackagePublishingStatus.PUBLISHED
725+ if date_uploaded is None:
726+ date_uploaded = UTC_NOW
727+ spph = self.factory.makeSourcePackagePublishingHistory(
728+ distroseries=spr.upload_distroseries,
729+ archive=spr.upload_archive,
730+ sourcepackagerelease=spr,
731+ status=status,
732+ date_uploaded=date_uploaded,
733+ dateremoved=dateremoved,
734+ scheduleddeletiondate=scheduleddeletiondate,
735+ pocket=package_upload.pocket,
736+ )
737+ return spph
738+
739+ def publishBinaries(self, binaryname=None, summary=None,
740+ description=None, shlibdep=None, depends=None,
741+ recommends=None, suggests=None, conflicts=None,
742+ replaces=None, provides=None, pre_depends=None,
743+ enhances=None, breaks=None, filecontent=None,
744+ changes_file_content=None, status=None,
745+ pocket=None, format=None, scheduleddeletiondate=None,
746+ dateremoved=None, distroseries=None, archive=None,
747+ pub_source=None, version=None,
748+ architecturespecific=False, builder=None,
749+ component_name=None, section_name=None,
750+ priority=None, installed_size=None,
751+ files_expire=None):
752+ """Publish some binary packages.
753+
754+ Publishes a number of binary packages and returns a list of the
755+ resulting `BinaryPackagePublishingHistory` objects.
756+
757+ :param binaryname: the binary package name to use, or None
758+ for a name derived from the default package name.
759+ :type binaryname: str or None
760+ :param summary: the summary (first line) of the package description.
761+ :type summary: str or None.
762+ :param description: the continuation lines of the package
763+ description.
764+ :type description: str or None
765+ :param shlibdep: the shared library dependencies the binary packages
766+ should have.
767+ :type shlibdep: str or None
768+ :param depends: the string containing the package dependencies the
769+ binary packages should have.
770+ :type depends: str or None
771+ :param recommends: the string containing the package recommendations
772+ the binary packages should have.
773+ :type recommends: str or None
774+ :param suggests: the string containing the package suggestions
775+ the binary packages should have.
776+ :type suggests: str or None
777+ :param conflicts: the string containing the package conflicts
778+ the binary packages should have.
779+ :type conflicts: str or None
780+ :param replaces: the string containing the package replaces
781+ relationships the binary packages should have.
782+ :type replaces: str or None
783+ :param provides: the string containing the package provides
784+ relationships the binary packages should have.
785+ :type provides: str or None
786+ :param pre_depends: the string containing the package
787+ pre-dependencies the binary packages should have.
788+ :type pre_depends: str or None
789+ :param enhances: the string containing the package enhances
790+ relationships the binary packages should have.
791+ :type enhances: str or None
792+ :param breaks: the string containing the package breaks
793+ relationships the binary packages should have.
794+ :type breaks: str or None
795+ :param filecontent: the content that the files associated with
796+ the binary packages should have.
797+ :type filecontent: str or None
798+ :param changes_file_content: the content that the uploaded changes
799+ file associated with the binary packages should have.
800+ :type changes_file_content: str or None
801+ :param status: the `PackagePublishingStatus` that the binary
802+ packages should have, or None for the default,
803+ `PackagePublishingStatus.PUBLISHED`.
804+ :type status: `PackagePublishingStatus` or None
805+ :param pocket: the `PackagePublishingPocket` that the binary
806+ packages should be published to, or None for the default,
807+ `PackagePublishingPocket.RELEASE`.
808+ :type pocket: `PackagePublishingPocket` or None
809+ :param format: the `BinaryPackageFormat` that the binary packages
810+ should be, or None for the default, `BinaryPackageFormat.DEB`.
811+ :type format: `BinaryPackageFormat` or None
812+ :param scheduleddeletiondate: the date that the packages should
813+ be scheduled for deletion, or None if it should not
814+ be.
815+ :type scheduleddeletiondate: `datetime.datetime` or None
816+ :param dateremoved: the date that the packages should
817+ be recorded as having been deleted, or None for packages
818+ that haven't been deleted.
819+ :type dateremoved: `datetime.datetime` or None
820+ :param distroseries: the distroseries that the packages should
821+ be published to, or None for the default distroseries.
822+ :type distroseries: `IDistroSeries` or None
823+ :param archive: the archive that the packages should be published
824+ to, or None for the default archive.
825+ :type archive: `IArchive` or None
826+ :param pub_source: the `SourcePackagePublishingHistory` that
827+ the builds and binaries should be associated with, or
828+ None to create a new one.
829+ :type pub_source: `SourcePackagePublishingHistory` or None
830+ :param version: the version that the binary packages should
831+ have, or None for an arbitrary version.
832+ :type version: str or None
833+ :param architecturespecific: whether the binary packages
834+ should be architecturespecific, default is False.
835+ :type architecturespecific: bool
836+ :param builder: the builder that the builds should state they
837+ were built by, or None.
838+ :type builder: `IBuilder` or None
839+ :param component_name: the name of the component that the packages
840+ should be published to, or None for an arbitrary component.
841+ :type component_name: str or None
842+ :param section_name: the name of the section that the packages
843+ should be published to, or None for an arbitrary section.
844+ :type section_name: str or None
845+ :param priority: the `PackagePublishingPriority` that the packages
846+ should be published with, or None for an arbitrary priority.
847+ :type priority: `PackagePublishingPriority` or None
848+ :param installed_size: the size that the packages should report
849+ that they take up when installed, or None for an arbitrary
850+ size.
851+ :type installed_size: int or None
852+ :param files_expire: when the files associated with the packages
853+ should expire, or None to not expire.
854+ :type files_expire: `datetime.datetime` or None
855+ :return: the binary publishing records that were created.
856+ :rtype: an iterable of `BinaryPackagePublishingHistory`.
857+ """
858+ if binaryname is None:
859+ binaryname = "%s-bin" % self.default_package_name
860+ if distroseries is None:
861+ distroseries = self.distroseries
862+
863+ if distroseries.nominatedarchindep is None:
864+ raise AssertionError(
865+ "distroseries not set up for binary publishing. If you "
866+ "are using the default you should use "
867+ "setUpForBinaryPublications() rather than setUp().")
868+
869+ if archive is None:
870+ archive = distroseries.main_archive
871+
872+ if pub_source is None:
873+ sourcename = "%s" % binaryname.split('-')[0]
874+ if architecturespecific:
875+ architecturehintlist = 'any'
876+ else:
877+ architecturehintlist = 'all'
878+
879+ pub_source = self.publishSource(
880+ sourcename=sourcename, status=status, pocket=pocket,
881+ archive=archive, distroseries=distroseries,
882+ version=version, architecturehintlist=architecturehintlist,
883+ component_name=component_name, files_expire=files_expire)
884+ else:
885+ archive = pub_source.archive
886+
887+ builds = pub_source.createMissingBuilds()
888+ published_binaries = []
889+ for build in builds:
890+ build.builder = builder
891+ binarypackagerelease = self.uploadBinaryForBuild(
892+ build, binaryname, filecontent=filecontent, summary=summary,
893+ description=description, shlibdep=shlibdep,
894+ depends=depends, recommends=recommends, suggests=suggests,
895+ conflicts=conflicts, replaces=replaces,
896+ provides=provides, pre_depends=pre_depends,
897+ enhances=enhances, breaks=breaks, format=format,
898+ installed_size=installed_size, priority=priority,
899+ files_expire=files_expire)
900+ pub_binaries = self.publishBinaryInArchive(
901+ binarypackagerelease, archive, status=status, pocket=pocket,
902+ scheduleddeletiondate=scheduleddeletiondate,
903+ dateremoved=dateremoved)
904+ published_binaries.extend(pub_binaries)
905+ package_upload = self.makePackageUpload(
906+ archive=archive, distroseries=distroseries, pocket=pocket,
907+ changes_file_content=changes_file_content,
908+ changes_file_name='%s_%s_%s.changes' %
909+ (binaryname, binarypackagerelease.version,
910+ build.arch_tag))
911+ package_upload.addBuild(build)
912+
913+ return sorted(
914+ published_binaries, key=operator.attrgetter('id'), reverse=True)
915+
916+ def uploadBinaryForBuild(self, build, binaryname, filecontent=None,
917+ summary=None, description=None, shlibdep=None,
918+ depends=None, recommends=None, suggests=None,
919+ conflicts=None, replaces=None, provides=None,
920+ pre_depends=None, enhances=None, breaks=None,
921+ format=None, installed_size=None,
922+ version=None, files_expire=None, priority=None):
923+ """Create a `BinaryPackageRelease` for a `PackageBuild`.
924+
925+ Given a build this method will create a `BinaryPackageRelease`
926+ for a package that results from the build. It will also
927+ add a file that represents the contents of that binary package,
928+ and will adjust the build to look like it has completed.
929+
930+ :param build: the build that the binary should be associated with.
931+ :type build: `PackageBuild`
932+ :param binaryname: the name of the binary package that should
933+ be created.
934+ :type binaryname: str
935+ :param filecontent: the content that the file associated with
936+ the binary package should have.
937+ :type filecontent: str or None
938+ :param summary: the summary (first line) of the package description.
939+ :type summary: str or None.
940+ :param description: the continuation lines of the package
941+ description.
942+ :type description: str or None
943+ :param shlibdep: the shared library dependencies the binary package
944+ should have.
945+ :type shlibdep: str or None
946+ :param depends: the string containing the package dependencies the
947+ binary package should have.
948+ :type depends: str or None
949+ :param recommends: the string containing the package recommendations
950+ the binary package should have.
951+ :type recommends: str or None
952+ :param suggests: the string containing the package suggestions
953+ the binary package should have.
954+ :type suggests: str or None
955+ :param conflicts: the string containing the package conflicts
956+ the binary package should have.
957+ :type conflicts: str or None
958+ :param replaces: the string containing the package replaces
959+ relationships the binary package should have.
960+ :type replaces: str or None
961+ :param provides: the string containing the package provides
962+ relationships the binary package should have.
963+ :type provides: str or None
964+ :param pre_depends: the string containing the package
965+ pre-dependencies the binary package should have.
966+ :type pre_depends: str or None
967+ :param enhances: the string containing the package enhances
968+ relationships the binary package should have.
969+ :type enhances: str or None
970+ :param breaks: the string containing the package breaks
971+ relationships the binary package should have.
972+ :type breaks: str or None
973+ :param format: the `BinaryPackageFormat` that the binary package
974+ should be, or None for the default, `BinaryPackageFormat.DEB`.
975+ :type format: `BinaryPackageFormat` or None
976+ :param installed_size: the size that the package should report
977+ that it takes up when installed, or None for an arbitrary
978+ size.
979+ :type installed_size: int or None
980+ :param version: the version that the binary package should
981+ have, or None for an arbitrary version.
982+ :type version: str or None
983+ :param files_expire: when the file associated with the package
984+ should expire, or None to not expire.
985+ :type files_expire: `datetime.datetime` or None
986+ :param priority: the priority the package should state, or None
987+ for an arbitrary priority.
988+ :type priority: `PackagePublishingPriority` or None
989+ :return: the created binary package
990+ :rtype: `BinaryPackageRelease`
991+ """
992+ sourcepackagerelease = build.source_package_release
993+ distroarchseries = build.distro_arch_series
994+ architecturespecific = (
995+ not sourcepackagerelease.architecturehintlist == 'all')
996+ binarypackagename = self.factory.getOrMakeBinaryPackageName(
997+ name=binaryname)
998+ if format is None:
999+ format = BinaryPackageFormat.DEB
1000+
1001+ binarypackagerelease = self.factory.makeBinaryPackageRelease(
1002+ build=build,
1003+ binarypackagename=binarypackagename,
1004+ summary=summary,
1005+ description=description,
1006+ shlibdeps=shlibdep,
1007+ depends=depends,
1008+ recommends=recommends,
1009+ suggests=suggests,
1010+ conflicts=conflicts,
1011+ replaces=replaces,
1012+ provides=provides,
1013+ pre_depends=pre_depends,
1014+ enhances=enhances,
1015+ breaks=breaks,
1016+ essential=False,
1017+ architecturespecific=architecturespecific,
1018+ binpackageformat=format,
1019+ priority=priority,
1020+ installed_size=installed_size,
1021+ component=sourcepackagerelease.component,
1022+ version=version,
1023+ )
1024+
1025+ # Create the corresponding binary file.
1026+ if architecturespecific:
1027+ filearchtag = distroarchseries.architecturetag
1028+ else:
1029+ filearchtag = 'all'
1030+ filename = '%s_%s_%s.%s' % (binaryname, sourcepackagerelease.version,
1031+ filearchtag, format.name.lower())
1032+ alias = self.addFile(
1033+ filename, filecontent=filecontent,
1034+ restricted=build.archive.private, expires=files_expire)
1035+ binarypackagerelease.addFile(alias)
1036+
1037+ # Adjust the build record in way it looks complete.
1038+ naked_build = removeSecurityProxy(build)
1039+ naked_build.status = BuildStatus.FULLYBUILT
1040+ naked_build.date_finished = datetime.datetime(
1041+ 2008, 1, 1, 0, 5, 0, tzinfo=pytz.UTC)
1042+ naked_build.date_started = (
1043+ build.date_finished - datetime.timedelta(minutes=5))
1044+ buildlog_filename = 'buildlog_%s-%s-%s.%s_%s_%s.txt.gz' % (
1045+ build.distribution.name,
1046+ build.distro_series.name,
1047+ build.distro_arch_series.architecturetag,
1048+ build.source_package_release.name,
1049+ build.source_package_release.version,
1050+ build.status.name)
1051+ naked_build.log = self.addFile(
1052+ buildlog_filename, filecontent='Built!',
1053+ restricted=build.archive.private)
1054+
1055+ return binarypackagerelease
1056+
1057+ def publishBinaryInArchive(self, binarypackagerelease, archive,
1058+ status=None, pocket=None,
1059+ scheduleddeletiondate=None,
1060+ dateremoved=None):
1061+ """Publish a `BinaryPackageRelease` in to an archive.
1062+
1063+ Returns the created `BinaryPackagePublishingHistory`.
1064+
1065+ :param binarypackagerelease: the binary package to publish.
1066+ :type binarypackagerelease: `BinaryPackageRelease`
1067+ :param archive: the archive to publish to.
1068+ :type archive: `IArchive`
1069+ :param status: the status that the created publishing record
1070+ should have, or None for the default of
1071+ `PackagePublishingStatus.PENDING`.
1072+ :type status: `PackagePublishingStatus` or None
1073+ :param pocket: the pocket to publish to, or None for the
1074+ default pocket of `PackagePublishingPocket.RELEASE`.
1075+ :type pocket: `PackagePublishingPocket` or None
1076+ :param scheduleddeletiondate: the date at which the record should
1077+ be scheduled for deletion, or None to not schedule for
1078+ deletion.
1079+ :type scheduleddeletiondate: `datetime.datetime` or None
1080+ :param dateremoved: the date that the publishing should
1081+ be recorded as having been deleted, or None to not set it.
1082+ :type dateremoved: `datetime.datetime` or None
1083+ :return: the created publishing record.
1084+ :rtype: `BinaryPackagePublishingHistory`
1085+ """
1086+ distroarchseries = binarypackagerelease.build.distro_arch_series
1087+
1088+ # Publish the binary.
1089+ if binarypackagerelease.architecturespecific:
1090+ archs = [distroarchseries]
1091+ else:
1092+ archs = distroarchseries.distroseries.architectures
1093+
1094+ if status is None:
1095+ status = PackagePublishingStatus.PENDING
1096+ if pocket is None:
1097+ pocket = PackagePublishingPocket.RELEASE
1098+
1099+ pub_binaries = []
1100+ for arch in archs:
1101+ pub = self.factory.makeBinaryPackagePublishingHistory(
1102+ distroarchseries=arch,
1103+ binarypackagerelease=binarypackagerelease,
1104+ status=status,
1105+ scheduleddeletiondate=scheduleddeletiondate,
1106+ dateremoved=dateremoved,
1107+ pocket=pocket,
1108+ archive=archive,
1109+ section_name=binarypackagerelease.section.name,
1110+ priority=binarypackagerelease.priority,
1111+ component=binarypackagerelease.component,
1112+ )
1113+ pub_binaries.append(pub)
1114+
1115+ return pub_binaries
1116+
1117+ def _findChangesFile(self, top, name_fragment):
1118+ """File with given name fragment in directory tree starting at top."""
1119+ for root, dirs, files in os.walk(top, topdown=False):
1120+ for name in files:
1121+ if (name.endswith('.changes') and
1122+ name.find(name_fragment) > -1):
1123+ return os.path.join(root, name)
1124+ return None
1125+
1126+ def createSource(self, sourcename, version, archive=None,
1127+ distroseries=None, new_version=None,
1128+ component_name=None):
1129+ """Create source with meaningful '.changes' file.
1130+
1131+ :param sourcename: the source package name that the changes
1132+ file should reference.
1133+ :type sourcename: str
1134+ :param version: the version of the changes file that should
1135+ be used.
1136+ :type version: str
1137+ :param archive: the archive that should be uploaded to, or None
1138+ for the default archive.
1139+ :type archive: `IArchive` or None
1140+ :param distroseries: the distroseries to publish to, or None
1141+ for the default.
1142+ :type distroseries: `IDistroSeries` or None
1143+ :param new_version: the version of the package to publish,
1144+ or None to use the found version.
1145+ :type new_version: str or None
1146+ :param component_name: the name of the component to upload
1147+ and publish to, or None for an arbitrary component.
1148+ :type component_name: str
1149+ :return: the created `SourcePackagePublishingHistory`, or
1150+ None if the changes file wasn't found.
1151+ :rtype: `SourcePackagePublishingHistory` or None
1152+ """
1153+ top = 'lib/lp/archiveuploader/tests/data/suite'
1154+ name_fragment = '%s_%s' % (sourcename, version)
1155+ changesfile_path = self._findChangesFile(top, name_fragment)
1156+
1157+ source = None
1158+
1159+ if changesfile_path is not None:
1160+ if new_version is None:
1161+ new_version = version
1162+ changesfile_content = ''
1163+ handle = open(changesfile_path, 'r')
1164+ try:
1165+ changesfile_content = handle.read()
1166+ finally:
1167+ handle.close()
1168+
1169+ source = self.publishSource(
1170+ sourcename=sourcename, archive=archive, version=new_version,
1171+ changes_file_content=changesfile_content,
1172+ distroseries=distroseries, component_name=component_name)
1173+
1174+ return source
1175+
1176+
1177+def makeDistributionLucilleconfig(distribution):
1178+ """Create a lucille config for the distribution."""
1179+ removeSecurityProxy(distribution).lucilleconfig = """[publishing]
1180+pendingremovalduration=5
1181+root=/var/tmp/archive
1182+archiveroot=/var/tmp/archive/%(name)s
1183+poolroot=/var/tmp/archive/%(name)s/pool
1184+distsroot=/var/tmp/archive/%(name)s/dists
1185+overrideroot=/var/tmp/archive/%(name)s-overrides
1186+cacheroot=/var/tmp/archive/%(name)s-cache
1187+miscroot=/var/tmp/archive/%(name)s-misc
1188+""" % dict(name=distribution.name)
1189+
1190+
1191+def makeDistroSeriesLucilleconfig(distroseries):
1192+ """Create a lucille config for the distroseries."""
1193+ removeSecurityProxy(distroseries).lucilleconfig = """[publishing]
1194+components = %(components)s
1195+""" % dict(components=[c.name for c in distroseries.components])
1196+
1197+
1198+class PublishingTestCase(TestCaseWithFactory):
1199+ """A test case that has access to a `SoyuzTestPublisher`.
1200+
1201+ In addition:
1202+
1203+ * the default distribution and distroseries of
1204+ the publisher will have lucille configurations, so that they
1205+ can be used with the publisher.
1206+ * the publisher configuration will have been asked to create
1207+ the directories necessary for publishing the default
1208+ distribution.
1209+
1210+ :ivar publisher: a `SoyuzTestPublisher` instance, prepared for
1211+ binary uploads.
1212+ :type publisher: `SoyuzTestPublisher`
1213+ :ivar config: the publisher configuration for the default
1214+ distribution of `publisher`.
1215+ :type config: `lp.archivepublisher.config.Config`
1216+ :ivar logger: a logger that the publisher will use.
1217+ :type logger: `canonical.launchpad.scripts.QuietFakeLogger`
1218+ :ivar disk_pool: a `DiskPool` for the default distribution
1219+ of `publisher`.
1220+ :type disk_pool: `lp.archivepublisher.diskpool.DiskPool`
1221+ """
1222+
1223+ layer = LaunchpadZopelessLayer
1224+ dbuser = config.archivepublisher.dbuser
1225+
1226+ def setUp(self):
1227+ super(PublishingTestCase, self).setUp()
1228+ self.layer.switchDbUser(self.dbuser)
1229+ self.publisher = SoyuzTestPublisher(factory=self.factory)
1230+ self.publisher.prepareForBinaryPublications()
1231+ makeDistributionLucilleconfig(self.publisher.distribution)
1232+ makeDistroSeriesLucilleconfig(self.publisher.distroseries)
1233+ self.config = Config(self.publisher.distribution)
1234+ self.addCleanup(self.config.removeArchiveDirs)
1235+ self.config.setupArchiveDirs()
1236+ self.logger = QuietFakeLogger()
1237+ self.disk_pool = DiskPool(
1238+ self.config.poolroot, self.config.temproot, self.logger)
1239
1240=== modified file 'lib/lp/soyuz/tests/test_publishing.py'
1241--- lib/lp/soyuz/tests/test_publishing.py 2010-08-10 01:42:55 +0000
1242+++ lib/lp/soyuz/tests/test_publishing.py 2010-08-10 01:42:59 +0000
1243@@ -22,7 +22,6 @@
1244 from lp.app.errors import NotFoundError
1245 from lp.archivepublisher.config import Config
1246 from lp.archivepublisher.diskpool import DiskPool
1247-from lp.buildmaster.interfaces.buildbase import BuildStatus
1248 from lp.registry.interfaces.distribution import IDistributionSet
1249 from lp.registry.interfaces.person import IPersonSet
1250 from lp.registry.interfaces.pocket import PackagePublishingPocket
1251@@ -37,20 +36,50 @@
1252 IPublishingSet, PackagePublishingPriority, PackagePublishingStatus)
1253 from lp.soyuz.interfaces.queue import PackageUploadStatus
1254 from lp.soyuz.testing.matchers import IsSupersededBy, PublishedStateIs
1255+from lp.soyuz.testing.publisher import (
1256+ SoyuzTestPublisher as _SoyuzTestPublisher)
1257 from canonical.launchpad.scripts import FakeLogger
1258 from lp.testing import TestCaseWithFactory
1259 from lp.testing.matchers import DateIsInPast
1260-from lp.testing.factory import LaunchpadObjectFactory
1261 from lp.testing.sampledata import UBUNTU_DEVELOPER_ADMIN_NAME
1262 from lp.testing.fakemethod import FakeMethod
1263
1264
1265-class SoyuzTestPublisher:
1266- """Helper class able to publish coherent source and binaries in Soyuz."""
1267-
1268- def __init__(self):
1269- self.factory = LaunchpadObjectFactory()
1270- self.default_package_name = 'foo'
1271+class SoyuzTestPublisher(_SoyuzTestPublisher):
1272+
1273+ def regetBreezyAutotest(self):
1274+ self.ubuntutest = getUtility(IDistributionSet)['ubuntutest']
1275+ self.breezy_autotest = self.ubuntutest['breezy-autotest']
1276+ self.person = getUtility(IPersonSet).getByName('name16')
1277+ self.breezy_autotest_i386 = self.breezy_autotest['i386']
1278+ self.breezy_autotest_hppa = self.breezy_autotest['hppa']
1279+
1280+ def prepareBreezyAutotest(self):
1281+ """Prepare ubuntutest/breezy-autotest for publications.
1282+
1283+ It's also called during the normal test-case setUp.
1284+ """
1285+ self.ubuntutest = getUtility(IDistributionSet)['ubuntutest']
1286+ self.breezy_autotest = self.ubuntutest['breezy-autotest']
1287+ self.setUpDefaultDistroSeries(self.breezy_autotest)
1288+ # Only create the DistroArchSeries needed if they do not exist yet.
1289+ # This makes it easier to experiment at the python command line
1290+ # (using "make harness").
1291+ try:
1292+ self.breezy_autotest_i386 = self.breezy_autotest['i386']
1293+ except NotFoundError:
1294+ self.breezy_autotest_i386 = self.breezy_autotest.newArch(
1295+ 'i386', ProcessorFamily.get(1), False, self.person,
1296+ supports_virtualized=True)
1297+ try:
1298+ self.breezy_autotest_hppa = self.breezy_autotest['hppa']
1299+ except NotFoundError:
1300+ self.breezy_autotest_hppa = self.breezy_autotest.newArch(
1301+ 'hppa', ProcessorFamily.get(4), False, self.person)
1302+ self.breezy_autotest.nominatedarchindep = self.breezy_autotest_i386
1303+ fake_chroot = self.addMockFile('fake_chroot.tar.gz')
1304+ self.breezy_autotest_i386.addOrUpdateChroot(fake_chroot)
1305+ self.breezy_autotest_hppa.addOrUpdateChroot(fake_chroot)
1306
1307 def setUpDefaultDistroSeries(self, distroseries=None):
1308 """Set up a distroseries that will be used by default.
1309@@ -67,8 +96,8 @@
1310 :return: The `IDistroSeries` that got set as default.
1311 """
1312 if distroseries is None:
1313- distroseries = self.factory.makeDistroRelease()
1314- self.distroseries = distroseries
1315+ distroseries = self.factory.makeDistroSeries()
1316+ distroseries = self.setDefaultDistroSeries(distroseries=distroseries)
1317 # Set up a person that has a GPG key.
1318 self.person = getUtility(IPersonSet).getByName(
1319 UBUNTU_DEVELOPER_ADMIN_NAME)
1320@@ -78,58 +107,6 @@
1321 name_set.getOrCreateByName(self.default_package_name)
1322 return self.distroseries
1323
1324- def prepareBreezyAutotest(self):
1325- """Prepare ubuntutest/breezy-autotest for publications.
1326-
1327- It's also called during the normal test-case setUp.
1328- """
1329- self.ubuntutest = getUtility(IDistributionSet)['ubuntutest']
1330- self.breezy_autotest = self.ubuntutest['breezy-autotest']
1331- self.setUpDefaultDistroSeries(self.breezy_autotest)
1332- # Only create the DistroArchSeries needed if they do not exist yet.
1333- # This makes it easier to experiment at the python command line
1334- # (using "make harness").
1335- try:
1336- self.breezy_autotest_i386 = self.breezy_autotest['i386']
1337- except NotFoundError:
1338- self.breezy_autotest_i386 = self.breezy_autotest.newArch(
1339- 'i386', ProcessorFamily.get(1), False, self.person,
1340- supports_virtualized=True)
1341- try:
1342- self.breezy_autotest_hppa = self.breezy_autotest['hppa']
1343- except NotFoundError:
1344- self.breezy_autotest_hppa = self.breezy_autotest.newArch(
1345- 'hppa', ProcessorFamily.get(4), False, self.person)
1346- self.breezy_autotest.nominatedarchindep = self.breezy_autotest_i386
1347- fake_chroot = self.addMockFile('fake_chroot.tar.gz')
1348- self.breezy_autotest_i386.addOrUpdateChroot(fake_chroot)
1349- self.breezy_autotest_hppa.addOrUpdateChroot(fake_chroot)
1350-
1351- def addFakeChroots(self, distroseries=None):
1352- """Add fake chroots for all the architectures in distroseries."""
1353- if distroseries is None:
1354- distroseries = self.distroseries
1355- fake_chroot = self.addMockFile('fake_chroot.tar.gz')
1356- for arch in distroseries.architectures:
1357- arch.addOrUpdateChroot(fake_chroot)
1358-
1359- def regetBreezyAutotest(self):
1360- self.ubuntutest = getUtility(IDistributionSet)['ubuntutest']
1361- self.breezy_autotest = self.ubuntutest['breezy-autotest']
1362- self.person = getUtility(IPersonSet).getByName('name16')
1363- self.breezy_autotest_i386 = self.breezy_autotest['i386']
1364- self.breezy_autotest_hppa = self.breezy_autotest['hppa']
1365-
1366- def addMockFile(self, filename, filecontent='nothing', restricted=False,
1367- expires=None):
1368- """Add a mock file in Librarian.
1369-
1370- Returns a ILibraryFileAlias corresponding to the file uploaded.
1371- """
1372- return self.factory.makeLibraryFileAlias(
1373- filename=filename, content=filecontent, restricted=restricted,
1374- content_type='application/text', expires=expires)
1375-
1376 def addPackageUpload(self, archive, distroseries,
1377 pocket=PackagePublishingPocket.RELEASE,
1378 changes_file_name="foo_666_source.changes",
1379@@ -137,12 +114,11 @@
1380 upload_status=PackageUploadStatus.DONE):
1381 person = self.factory.makePerson()
1382 signing_key = self.factory.makeGPGKey(person)
1383- package_upload = self.factory.makePackageUpload(
1384- archive=archive, distroseries=distroseries, pocket=pocket,
1385- changes_filename=changes_file_name,
1386+ return self.makePackageUpload(
1387+ archive=archive, distroseries=distroseries,
1388+ pocket=pocket, changes_file_name=changes_file_name,
1389 changes_file_content=changes_file_content,
1390 signing_key=signing_key, status=upload_status)
1391- return package_upload
1392
1393 def getPubSource(self, sourcename=None, version='666', component='main',
1394 filename=None, section='base',
1395@@ -161,23 +137,16 @@
1396 maintainer=None, creator=None, date_uploaded=UTC_NOW,
1397 spr_only=False, files_expire=None,
1398 changelog_entry=None):
1399- """Return a mock source publishing record.
1400-
1401- if spr_only is specified, the source is not published and the
1402- sourcepackagerelease object is returned instead.
1403- """
1404 if sourcename is None:
1405 sourcename = self.default_package_name
1406 spn = self.factory.getOrMakeSourcePackageName(name=sourcename)
1407 component = self.factory.makeComponent(name=component)
1408-
1409- if distroseries is None:
1410- distroseries = self.distroseries
1411- if archive is None:
1412- archive = distroseries.main_archive
1413 if creator is None:
1414 creator = self.factory.makePerson()
1415- self.factory.makeGPGKey(creator)
1416+ if not creator.gpg_keys:
1417+ dscsigningkey = self.factory.makeGPGKey(creator)
1418+ else:
1419+ dscsigningkey = creator.gpg_keys[0]
1420
1421 changes_file_name = "%s_%s_source.changes" % (sourcename, version)
1422 if spr_only:
1423@@ -191,7 +160,7 @@
1424 upload_status=upload_status)
1425
1426 spr = self.factory.makeSourcePackageRelease(
1427- distroseries=distroseries,
1428+ distroseries=package_upload.distroseries,
1429 sourcepackagename=spn,
1430 maintainer=maintainer,
1431 creator=creator,
1432@@ -204,12 +173,12 @@
1433 build_conflicts=build_conflicts,
1434 build_conflicts_indep=build_conflicts_indep,
1435 architecturehintlist=architecturehintlist,
1436- dscsigningkey=creator.gpg_keys[0],
1437+ dscsigningkey=dscsigningkey,
1438 dsc_maintainer_rfc822=dsc_maintainer_rfc822,
1439 dsc_standards_version=dsc_standards_version,
1440 dsc_format=dsc_format,
1441 dsc_binaries=dsc_binaries,
1442- archive=archive,
1443+ archive=package_upload.archive,
1444 date_uploaded=date_uploaded,
1445 changelog_entry=changelog_entry,
1446 )
1447@@ -217,8 +186,8 @@
1448
1449 if filename is None:
1450 filename = "%s_%s.dsc" % (sourcename, version)
1451- alias = self.addMockFile(
1452- filename, filecontent, restricted=archive.private,
1453+ alias = self.addFile(
1454+ filename, filecontent, restricted=package_upload.archive.private,
1455 expires=files_expire)
1456 spr.addFile(alias)
1457
1458@@ -226,7 +195,7 @@
1459 return spr
1460
1461 spph = self.factory.makeSourcePackagePublishingHistory(
1462- distroseries=distroseries,
1463+ distroseries=package_upload.distroseries,
1464 sourcepackagerelease=spr,
1465 component=spr.component,
1466 section_name=spr.section.name,
1467@@ -234,8 +203,8 @@
1468 date_uploaded=date_uploaded,
1469 dateremoved=dateremoved,
1470 scheduleddeletiondate=scheduleddeletiondate,
1471- pocket=pocket,
1472- archive=archive,
1473+ pocket=package_upload.pocket,
1474+ archive=package_upload.archive,
1475 )
1476 return spph
1477
1478@@ -290,11 +259,11 @@
1479 build, binaryname, filecontent, summary, description,
1480 shlibdep, depends, recommends, suggests, conflicts, replaces,
1481 provides, pre_depends, enhances, breaks, format,
1482- installed_size=installed_size, component=component,
1483- files_expire=files_expire)
1484+ installed_size=installed_size, files_expire=files_expire)
1485 pub_binaries = self.publishBinaryInArchive(
1486 binarypackagerelease, archive, status, pocket,
1487- scheduleddeletiondate, dateremoved, section, priority)
1488+ scheduleddeletiondate, dateremoved, section, priority,
1489+ component_name=component)
1490 published_binaries.extend(pub_binaries)
1491 package_upload = self.addPackageUpload(
1492 archive, distroseries, pocket,
1493@@ -307,147 +276,42 @@
1494 return sorted(
1495 published_binaries, key=operator.attrgetter('id'), reverse=True)
1496
1497- def uploadBinaryForBuild(
1498- self, build, binaryname, filecontent="anything",
1499- summary="summary", description="description", shlibdep=None,
1500- depends=None, recommends=None, suggests=None, conflicts=None,
1501- replaces=None, provides=None, pre_depends=None, enhances=None,
1502- breaks=None, format=BinaryPackageFormat.DEB, installed_size=None,
1503- component=None, version=None, files_expire=None):
1504+ def uploadBinaryForBuild(self, build, binaryname, filecontent="anything",
1505+ summary="summary", description="description",
1506+ shlibdep=None, depends=None, recommends=None,
1507+ suggests=None, conflicts=None, replaces=None,
1508+ provides=None, pre_depends=None, enhances=None,
1509+ breaks=None, format=BinaryPackageFormat.DEB,
1510+ installed_size=None, version=None,
1511+ files_expire=None, priority=None):
1512 """Return the corresponding `BinaryPackageRelease`."""
1513- sourcepackagerelease = build.source_package_release
1514- distroarchseries = build.distro_arch_series
1515- architecturespecific = (
1516- not sourcepackagerelease.architecturehintlist == 'all')
1517- if component is not None:
1518- component = self.factory.makeComponent(name=component)
1519-
1520- binarypackagename = self.factory.getOrMakeBinaryPackageName(
1521- name=binaryname)
1522-
1523- binarypackagerelease = self.factory.makeBinaryPackageRelease(
1524- build=build,
1525- binarypackagename=binarypackagename,
1526- summary=summary,
1527- description=description,
1528- shlibdeps=shlibdep,
1529- depends=depends,
1530- recommends=recommends,
1531- suggests=suggests,
1532- conflicts=conflicts,
1533- replaces=replaces,
1534- provides=provides,
1535- pre_depends=pre_depends,
1536- enhances=enhances,
1537- breaks=breaks,
1538- essential=False,
1539- architecturespecific=architecturespecific,
1540- binpackageformat=format,
1541- priority=PackagePublishingPriority.STANDARD,
1542- installed_size=installed_size,
1543- component=component,
1544- version=version,
1545- )
1546-
1547- # Create the corresponding binary file.
1548- if architecturespecific:
1549- filearchtag = distroarchseries.architecturetag
1550- else:
1551- filearchtag = 'all'
1552- filename = '%s_%s_%s.%s' % (binaryname, sourcepackagerelease.version,
1553- filearchtag, format.name.lower())
1554- alias = self.addMockFile(
1555- filename, filecontent=filecontent,
1556- restricted=build.archive.private, expires=files_expire)
1557- binarypackagerelease.addFile(alias)
1558-
1559- # Adjust the build record in way it looks complete.
1560- naked_build = removeSecurityProxy(build)
1561- naked_build.status = BuildStatus.FULLYBUILT
1562- naked_build.date_finished = datetime.datetime(
1563- 2008, 1, 1, 0, 5, 0, tzinfo=pytz.UTC)
1564- naked_build.date_started = (
1565- build.date_finished - datetime.timedelta(minutes=5))
1566- buildlog_filename = 'buildlog_%s-%s-%s.%s_%s_%s.txt.gz' % (
1567- build.distribution.name,
1568- build.distro_series.name,
1569- build.distro_arch_series.architecturetag,
1570- build.source_package_release.name,
1571- build.source_package_release.version,
1572- build.status.name)
1573- naked_build.log = self.addMockFile(
1574- buildlog_filename, filecontent='Built!',
1575- restricted=build.archive.private)
1576-
1577- return binarypackagerelease
1578-
1579- def publishBinaryInArchive(
1580- self, binarypackagerelease, archive,
1581- status=PackagePublishingStatus.PENDING,
1582- pocket=PackagePublishingPocket.RELEASE,
1583- scheduleddeletiondate=None, dateremoved=None, section=None,
1584- priority=None):
1585+ return super(SoyuzTestPublisher, self).uploadBinaryForBuild(
1586+ build, binaryname, filecontent=filecontent, summary=summary,
1587+ description=description, shlibdep=shlibdep, depends=depends,
1588+ recommends=recommends, suggests=suggests, conflicts=conflicts,
1589+ replaces=replaces, provides=provides, pre_depends=pre_depends,
1590+ enhances=enhances, breaks=breaks, format=format,
1591+ installed_size=installed_size, version=version,
1592+ files_expire=files_expire, priority=priority)
1593+
1594+ def publishBinaryInArchive(self, binarypackagerelease, archive,
1595+ status=PackagePublishingStatus.PENDING,
1596+ pocket=PackagePublishingPocket.RELEASE,
1597+ scheduleddeletiondate=None, dateremoved=None,
1598+ section=None, priority=None,
1599+ component_name=None):
1600 """Return the corresponding BinaryPackagePublishingHistory."""
1601- distroarchseries = binarypackagerelease.build.distro_arch_series
1602-
1603- # Publish the binary.
1604- if binarypackagerelease.architecturespecific:
1605- archs = [distroarchseries]
1606- else:
1607- archs = distroarchseries.distroseries.architectures
1608-
1609- pub_binaries = []
1610- for arch in archs:
1611- pub = self.factory.makeBinaryPackagePublishingHistory(
1612- distroarchseries=arch,
1613- binarypackagerelease=binarypackagerelease,
1614- status=status,
1615- scheduleddeletiondate=scheduleddeletiondate,
1616- dateremoved=dateremoved,
1617- pocket=pocket,
1618- archive=archive,
1619- section_name=section,
1620- priority=priority,
1621- )
1622- pub_binaries.append(pub)
1623-
1624- return pub_binaries
1625-
1626- def _findChangesFile(self, top, name_fragment):
1627- """File with given name fragment in directory tree starting at top."""
1628- for root, dirs, files in os.walk(top, topdown=False):
1629- for name in files:
1630- if (name.endswith('.changes') and
1631- name.find(name_fragment) > -1):
1632- return os.path.join(root, name)
1633- return None
1634-
1635- def createSource(
1636- self, archive, sourcename, version, distroseries=None,
1637- new_version=None, component='main'):
1638+ return super(SoyuzTestPublisher, self).publishBinaryInArchive(
1639+ binarypackagerelease, archive, status=status, pocket=pocket,
1640+ scheduleddeletiondate=scheduleddeletiondate,
1641+ dateremoved=dateremoved)
1642+
1643+ def createSource(self, archive, sourcename, version, distroseries=None,
1644+ new_version=None, component='main'):
1645 """Create source with meaningful '.changes' file."""
1646- top = 'lib/lp/archiveuploader/tests/data/suite'
1647- name_fragment = '%s_%s' % (sourcename, version)
1648- changesfile_path = self._findChangesFile(top, name_fragment)
1649-
1650- source = None
1651-
1652- if changesfile_path is not None:
1653- if new_version is None:
1654- new_version = version
1655- changesfile_content = ''
1656- handle = open(changesfile_path, 'r')
1657- try:
1658- changesfile_content = handle.read()
1659- finally:
1660- handle.close()
1661-
1662- source = self.getPubSource(
1663- sourcename=sourcename, archive=archive, version=new_version,
1664- changes_file_content=changesfile_content,
1665- distroseries=distroseries, component=component)
1666-
1667- return source
1668+ return super(SoyuzTestPublisher, self).createSource(
1669+ sourcename, version, archive=archive, distroseries=distroseries,
1670+ new_version=new_version, component_name=component)
1671
1672
1673 class TestNativePublishingBase(TestCaseWithFactory, SoyuzTestPublisher):