Merge lp:~cjwatson/launchpad/queue-copy-archive-links into lp:launchpad

Proposed by Colin Watson
Status: Merged
Approved by: William Grant
Approved revision: no longer in the source branch.
Merged at revision: 16570
Proposed branch: lp:~cjwatson/launchpad/queue-copy-archive-links
Merge into: lp:launchpad
Diff against target: 452 lines (+152/-38)
14 files modified
lib/lp/_schema_circular_imports.py (+1/-0)
lib/lp/app/browser/configure.zcml (+3/-6)
lib/lp/app/browser/tales.py (+28/-6)
lib/lp/app/doc/tales.txt (+29/-2)
lib/lp/soyuz/browser/queue.py (+7/-3)
lib/lp/soyuz/browser/tests/test_queue.py (+26/-2)
lib/lp/soyuz/configure.zcml (+1/-0)
lib/lp/soyuz/interfaces/queue.py (+8/-0)
lib/lp/soyuz/model/queue.py (+8/-0)
lib/lp/soyuz/templates/build-index.pt (+1/-8)
lib/lp/soyuz/templates/distroseries-queue.pt (+7/-7)
lib/lp/soyuz/tests/test_packageupload.py (+25/-0)
lib/lp/testing/factory.py (+3/-2)
lib/lp/testing/tests/test_factory.py (+5/-2)
To merge this branch: bzr merge lp:~cjwatson/launchpad/queue-copy-archive-links
Reviewer Review Type Date Requested Status
William Grant code Approve
Review via email: mp+159250@code.launchpad.net

Commit message

Show link to source archive for copies from PPAs in DistroSeries:+queue; add PackageUpload.copy_source_archive property.

Description of the change

== Summary ==

When reviewing copies in DistroSeries:+queue, it's a pain to figure out where they came from in order to accurately review the change.

== Proposed fix ==

Linkify the archive displayname, at least for PPAs (archive URLs aren't very useful for primary archives). Add an exported copy_source_archive property to PackageUpload. Between them, these changes will make it easier to track things down by hand and should make it possible to teach our "queue" script to follow the breadcrumb trail automatically.

== LOC Rationale ==

+78. I think this is worth it to eliminate a barrier to review for ~ubuntu-release, particularly in the run-up to 13.04 release; and I should have lots of credit from past changes.

== Tests ==

bin/test -vvct lp.soyuz.browser.tests.test_queue -t lp.soyuz.tests.test_packageupload -t lp.testing.tests.test_factory

== Demo and Q/A ==

Copy a package to a frozen series from (a) Debian and (b) a PPA on dogfood, if there isn't one of each available already. Run the PCJ processor. Check that both render reasonably in the DistroSeries:+queue UI, and that the copy_source_archive property in the API is correct.

To post a comment you must log in.
Revision history for this message
William Grant (wgrant) wrote :

Did you consider just using fmt:link for the archive? It's probably not worth special casing PPAs, as non-primary archives have informative URLs that at worst just redirect to the distribution, still making the origin clearer.

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/_schema_circular_imports.py'
--- lib/lp/_schema_circular_imports.py 2013-04-03 03:09:04 +0000
+++ lib/lp/_schema_circular_imports.py 2013-04-17 11:10:37 +0000
@@ -591,6 +591,7 @@
591IPackageUpload['pocket'].vocabulary = PackagePublishingPocket591IPackageUpload['pocket'].vocabulary = PackagePublishingPocket
592patch_reference_property(IPackageUpload, 'distroseries', IDistroSeries)592patch_reference_property(IPackageUpload, 'distroseries', IDistroSeries)
593patch_reference_property(IPackageUpload, 'archive', IArchive)593patch_reference_property(IPackageUpload, 'archive', IArchive)
594patch_reference_property(IPackageUpload, 'copy_source_archive', IArchive)
594595
595# IStructuralSubscription596# IStructuralSubscription
596patch_collection_property(597patch_collection_property(
597598
=== modified file 'lib/lp/app/browser/configure.zcml'
--- lib/lp/app/browser/configure.zcml 2013-04-10 07:42:31 +0000
+++ lib/lp/app/browser/configure.zcml 2013-04-17 11:10:37 +0000
@@ -1,4 +1,4 @@
1<!-- Copyright 2009-2011 Canonical Ltd. This software is licensed under the1<!-- Copyright 2009-2013 Canonical Ltd. This software is licensed under the
2 GNU Affero General Public License version 3 (see the file LICENSE).2 GNU Affero General Public License version 3 (see the file LICENSE).
3-->3-->
44
@@ -596,13 +596,10 @@
596 />596 />
597 <!-- TALES fmt: namespace -->597 <!-- TALES fmt: namespace -->
598598
599 <!-- The next directive is registered for all dicts, but we really only
600 want it to apply to the page template's CONTEXTS dict.
601 -->
602 <adapter599 <adapter
603 for="lp.soyuz.interfaces.archive.IPPA"600 for="lp.soyuz.interfaces.archive.IArchive"
604 provides="zope.traversing.interfaces.IPathAdapter"601 provides="zope.traversing.interfaces.IPathAdapter"
605 factory="lp.app.browser.tales.PPAFormatterAPI"602 factory="lp.app.browser.tales.ArchiveFormatterAPI"
606 name="fmt"603 name="fmt"
607 />604 />
608605
609606
=== modified file 'lib/lp/app/browser/tales.py'
--- lib/lp/app/browser/tales.py 2013-04-09 08:29:04 +0000
+++ lib/lp/app/browser/tales.py 2013-04-17 11:10:37 +0000
@@ -98,7 +98,10 @@
98from lp.services.webapp.session import get_cookie_domain98from lp.services.webapp.session import get_cookie_domain
99from lp.services.webapp.url import urlappend99from lp.services.webapp.url import urlappend
100from lp.soyuz.enums import ArchivePurpose100from lp.soyuz.enums import ArchivePurpose
101from lp.soyuz.interfaces.archive import IPPA101from lp.soyuz.interfaces.archive import (
102 IArchive,
103 IPPA,
104 )
102from lp.soyuz.interfaces.binarypackagename import IBinaryAndSourcePackageName105from lp.soyuz.interfaces.binarypackagename import IBinaryAndSourcePackageName
103106
104107
@@ -760,6 +763,8 @@
760 sprite_string = 'ppa-icon'763 sprite_string = 'ppa-icon'
761 else:764 else:
762 sprite_string = 'ppa-icon-inactive'765 sprite_string = 'ppa-icon-inactive'
766 elif IArchive.providedBy(context):
767 sprite_string = 'distribution'
763 elif IBranch.providedBy(context):768 elif IBranch.providedBy(context):
764 sprite_string = 'branch'769 sprite_string = 'branch'
765 elif ISpecification.providedBy(context):770 elif ISpecification.providedBy(context):
@@ -1847,8 +1852,8 @@
1847 return {'author': self._context.message.owner.displayname}1852 return {'author': self._context.message.owner.displayname}
18481853
18491854
1850class PPAFormatterAPI(CustomizableFormatter):1855class ArchiveFormatterAPI(CustomizableFormatter):
1851 """Adapter providing fmt support for `IPPA` objects."""1856 """Adapter providing fmt support for `IArchive` objects."""
18521857
1853 _link_summary_template = '%(display_name)s'1858 _link_summary_template = '%(display_name)s'
1854 _link_permission = 'launchpad.View'1859 _link_permission = 'launchpad.View'
@@ -1859,19 +1864,32 @@
1859 final_traversable_names.update(1864 final_traversable_names.update(
1860 CustomizableFormatter.final_traversable_names)1865 CustomizableFormatter.final_traversable_names)
18611866
1867 def url(self, view_name=None, rootsite='mainsite'):
1868 """See `ObjectFormatterAPI`.
1869
1870 The default URL for a distribution main archive is the URL of the
1871 distribution. Other archive URLs are constructed as normal.
1872 """
1873 if self._context.is_main:
1874 return queryAdapter(
1875 self._context.distribution, IPathAdapter, 'fmt').url(
1876 view_name, rootsite)
1877 else:
1878 return super(ArchiveFormatterAPI, self).url(view_name, rootsite)
1879
1862 def _link_summary_values(self):1880 def _link_summary_values(self):
1863 """See CustomizableFormatter._link_summary_values."""1881 """See CustomizableFormatter._link_summary_values."""
1864 return {'display_name': self._context.displayname}1882 return {'display_name': self._context.displayname}
18651883
1866 def link(self, view_name):1884 def link(self, view_name):
1867 """Return html including a link for the context PPA.1885 """Return html including a link for the context archive.
18681886
1869 Render a link using CSS sprites for users with permission to view1887 Render a link using CSS sprites for users with permission to view
1870 the PPA.1888 the archive.
18711889
1872 Disabled PPAs are listed with sprites but not linkified.1890 Disabled PPAs are listed with sprites but not linkified.
18731891
1874 Unaccessible private PPA are not rendered at all (empty string1892 Inaccessible private PPAs are not rendered at all (empty string
1875 is returned).1893 is returned).
1876 """1894 """
1877 summary = self._make_link_summary()1895 summary = self._make_link_summary()
@@ -1887,6 +1905,10 @@
18871905
1888 def reference(self, view_name=None, rootsite=None):1906 def reference(self, view_name=None, rootsite=None):
1889 """Return the text PPA reference for a PPA."""1907 """Return the text PPA reference for a PPA."""
1908 if not IPPA.providedBy(self._context):
1909 raise NotImplementedError(
1910 "No reference implementation for non-PPA archive %r." %
1911 self._context)
1890 if not check_permission(self._reference_permission, self._context):1912 if not check_permission(self._reference_permission, self._context):
1891 return ''1913 return ''
1892 return self._reference_template % {1914 return self._reference_template % {
18931915
=== modified file 'lib/lp/app/doc/tales.txt'
--- lib/lp/app/doc/tales.txt 2013-01-24 05:50:23 +0000
+++ lib/lp/app/doc/tales.txt 2013-04-17 11:10:37 +0000
@@ -160,8 +160,8 @@
160 ... name='pppa', private=True, owner=owner)160 ... name='pppa', private=True, owner=owner)
161161
162 >>> print test_tales("ppa/fmt:link", ppa=private_ppa)162 >>> print test_tales("ppa/fmt:link", ppa=private_ppa)
163 <a href="/~joe/+archive/pppa" class="sprite ppa-icon private">PPA named pppa163 <a href="/~joe/+archive/pppa" class="sprite ppa-icon private">PPA named
164 for Joe Smith</a>164 pppa for Joe Smith</a>
165165
166 >>> login(ANONYMOUS)166 >>> login(ANONYMOUS)
167167
@@ -180,6 +180,33 @@
180 >>> print test_tales("ppa/fmt:reference", ppa=private_ppa)180 >>> print test_tales("ppa/fmt:reference", ppa=private_ppa)
181 ppa:joe/pppa181 ppa:joe/pppa
182182
183The same 'link' formatter works for distribution archives, with a different
184sprite. The link target for main archives (primary, partner, and debug) is
185the distribution rather than the archive, as the archives would just
186redirect anyway.
187
188 >>> print test_tales("archive/fmt:link", archive=primary)
189 <a href="/ubuntu" class="sprite distribution">Primary Archive for Ubuntu
190 Linux</a>
191
192 >>> print test_tales("archive/fmt:link", archive=partner)
193 <a href="/ubuntu" class="sprite distribution">Partner Archive for Ubuntu
194 Linux</a>
195
196 >>> print test_tales("archive/fmt:link", archive=debug)
197 <a href="/ubuntu" class="sprite distribution">Ubuntu DEBUG archive</a>
198
199 >>> print test_tales("archive/fmt:link", archive=copy)
200 <a href="/ubuntu/+archive/rebuild" class="sprite distribution">Copy
201 archive rebuild for Mark Shuttleworth</a>
202
203The 'reference' formatter is meaningless for non-PPA archives.
204
205 >>> test_tales("archive/fmt:reference", archive=primary)
206 Traceback (most recent call last):
207 ...
208 NotImplementedError: No reference implementation for non-PPA archive ...
209
183We also have icons for builds which may have different dimensions.210We also have icons for builds which may have different dimensions.
184211
185 >>> login('admin@canonical.com')212 >>> login('admin@canonical.com')
186213
=== modified file 'lib/lp/soyuz/browser/queue.py'
--- lib/lp/soyuz/browser/queue.py 2013-01-08 05:45:26 +0000
+++ lib/lp/soyuz/browser/queue.py 2013-04-17 11:10:37 +0000
@@ -21,6 +21,7 @@
21 UnexpectedFormData,21 UnexpectedFormData,
22 )22 )
23from lp.registry.interfaces.person import IPersonSet23from lp.registry.interfaces.person import IPersonSet
24from lp.registry.model.distribution import Distribution
24from lp.services.database.bulk import (25from lp.services.database.bulk import (
25 load_referencing,26 load_referencing,
26 load_related,27 load_related,
@@ -196,11 +197,14 @@
196 """Batch-load `PackageCopyJob`s and related information."""197 """Batch-load `PackageCopyJob`s and related information."""
197 package_copy_jobs = load_related(198 package_copy_jobs = load_related(
198 PackageCopyJob, uploads, ['package_copy_job_id'])199 PackageCopyJob, uploads, ['package_copy_job_id'])
199 load_related(Archive, package_copy_jobs, ['source_archive_id'])200 archives = load_related(
201 Archive, package_copy_jobs, ['source_archive_id'])
202 load_related(Distribution, archives, ['distributionID'])
203 person_ids = map(attrgetter('ownerID'), archives)
200 jobs = load_related(Job, package_copy_jobs, ['job_id'])204 jobs = load_related(Job, package_copy_jobs, ['job_id'])
201 person_ids = map(attrgetter('requester_id'), jobs)205 person_ids.extend(map(attrgetter('requester_id'), jobs))
202 list(getUtility(IPersonSet).getPrecachedPersonsFromIDs(206 list(getUtility(IPersonSet).getPrecachedPersonsFromIDs(
203 person_ids, need_validity=True))207 person_ids, need_validity=True, need_icon=True))
204208
205 def decoratedQueueBatch(self):209 def decoratedQueueBatch(self):
206 """Return the current batch, converted to decorated objects.210 """Return the current batch, converted to decorated objects.
207211
=== modified file 'lib/lp/soyuz/browser/tests/test_queue.py'
--- lib/lp/soyuz/browser/tests/test_queue.py 2013-01-31 02:02:37 +0000
+++ lib/lp/soyuz/browser/tests/test_queue.py 2013-04-17 11:10:37 +0000
@@ -6,6 +6,7 @@
6__metaclass__ = type6__metaclass__ = type
77
8from lxml import html8from lxml import html
9import soupmatchers
9from storm.store import Store10from storm.store import Store
10from testtools.matchers import Equals11from testtools.matchers import Equals
11import transaction12import transaction
@@ -17,6 +18,7 @@
17from lp.archiveuploader.tests import datadir18from lp.archiveuploader.tests import datadir
18from lp.registry.interfaces.pocket import PackagePublishingPocket19from lp.registry.interfaces.pocket import PackagePublishingPocket
19from lp.services.webapp.escaping import html_escape20from lp.services.webapp.escaping import html_escape
21from lp.services.webapp.publisher import canonical_url
20from lp.services.webapp.servers import LaunchpadTestRequest22from lp.services.webapp.servers import LaunchpadTestRequest
21from lp.soyuz.browser.queue import CompletePackageUpload23from lp.soyuz.browser.queue import CompletePackageUpload
22from lp.soyuz.enums import PackageUploadStatus24from lp.soyuz.enums import PackageUploadStatus
@@ -360,8 +362,28 @@
360 html_text = view()362 html_text = view()
361 self.assertIn(upload.package_name, html_text)363 self.assertIn(upload.package_name, html_text)
362 # The details section states the sync's origin and requester.364 # The details section states the sync's origin and requester.
365 archive = upload.package_copy_job.source_archive
366 url = canonical_url(archive.distribution, path_only_if_possible=True)
367 self.assertThat(html_text, soupmatchers.HTMLContains(
368 soupmatchers.Tag(
369 "link", "a", text=archive.displayname, attrs={"href": url}),
370 ))
363 self.assertIn(371 self.assertIn(
364 upload.package_copy_job.source_archive.displayname, html_text)372 upload.package_copy_job.job.requester.displayname, html_text)
373
374 def test_view_renders_copy_upload_from_private_archive(self):
375 login(ADMIN_EMAIL)
376 p3a = self.factory.makeArchive(private=True)
377 upload = self.factory.makeCopyJobPackageUpload(source_archive=p3a)
378 queue_admin = self.factory.makeArchiveAdmin(
379 upload.distroseries.main_archive)
380 with person_logged_in(queue_admin):
381 view = self.makeView(upload.distroseries, queue_admin)
382 html_text = view()
383 self.assertIn(upload.package_name, html_text)
384 # The details section states the sync's origin and requester.
385 self.assertTextMatchesExpressionIgnoreWhitespace(
386 "Sync from <span>private archive</span>,", html_text)
365 self.assertIn(387 self.assertIn(
366 upload.package_copy_job.job.requester.displayname, html_text)388 upload.package_copy_job.job.requester.displayname, html_text)
367389
@@ -379,6 +401,8 @@
379 sprs[-1].addFile(dsc)401 sprs[-1].addFile(dsc)
380 uploads.append(self.factory.makeCustomPackageUpload(distroseries))402 uploads.append(self.factory.makeCustomPackageUpload(distroseries))
381 uploads.append(self.factory.makeCopyJobPackageUpload(distroseries))403 uploads.append(self.factory.makeCopyJobPackageUpload(distroseries))
404 uploads.append(self.factory.makeCopyJobPackageUpload(
405 distroseries, source_archive=self.factory.makeArchive()))
382 self.factory.makePackageset(406 self.factory.makePackageset(
383 packages=(sprs[0].sourcepackagename, sprs[2].sourcepackagename,407 packages=(sprs[0].sourcepackagename, sprs[2].sourcepackagename,
384 sprs[4].sourcepackagename),408 sprs[4].sourcepackagename),
@@ -398,7 +422,7 @@
398 with StormStatementRecorder() as recorder:422 with StormStatementRecorder() as recorder:
399 view = self.makeView(distroseries, queue_admin)423 view = self.makeView(distroseries, queue_admin)
400 view()424 view()
401 self.assertThat(recorder, HasQueryCount(Equals(54)))425 self.assertThat(recorder, HasQueryCount(Equals(56)))
402426
403427
404class TestCompletePackageUpload(TestCaseWithFactory):428class TestCompletePackageUpload(TestCaseWithFactory):
405429
=== modified file 'lib/lp/soyuz/configure.zcml'
--- lib/lp/soyuz/configure.zcml 2013-02-18 03:47:21 +0000
+++ lib/lp/soyuz/configure.zcml 2013-04-17 11:10:37 +0000
@@ -168,6 +168,7 @@
168 custom_file_urls168 custom_file_urls
169 customFileUrls169 customFileUrls
170 getBinaryProperties170 getBinaryProperties
171 copy_source_archive
171 getFileByName172 getFileByName
172 date_created173 date_created
173 sourcepackagerelease174 sourcepackagerelease
174175
=== modified file 'lib/lp/soyuz/interfaces/queue.py'
--- lib/lp/soyuz/interfaces/queue.py 2013-01-08 01:10:35 +0000
+++ lib/lp/soyuz/interfaces/queue.py 2013-04-17 11:10:37 +0000
@@ -193,6 +193,14 @@
193 readonly=True),193 readonly=True),
194 ("devel", dict(exported=False)), exported=True)194 ("devel", dict(exported=False)), exported=True)
195195
196 copy_source_archive = exported(
197 Reference(
198 # Really IArchive, patched in _schema_circular_imports.py
199 schema=Interface,
200 description=_("The archive from which this package was copied, if "
201 "any."),
202 title=_("Copy source archive"), required=False, readonly=True))
203
196 displayname = exported(204 displayname = exported(
197 TextLine(205 TextLine(
198 title=_("Generic displayname for a queue item"), readonly=True),206 title=_("Generic displayname for a queue item"), readonly=True),
199207
=== modified file 'lib/lp/soyuz/model/queue.py'
--- lib/lp/soyuz/model/queue.py 2013-02-06 08:20:13 +0000
+++ lib/lp/soyuz/model/queue.py 2013-04-17 11:10:37 +0000
@@ -295,6 +295,14 @@
295 })295 })
296 return properties296 return properties
297297
298 @property
299 def copy_source_archive(self):
300 """See `IPackageUpload`."""
301 if self.package_copy_job_id is not None:
302 return self.package_copy_job.source_archive
303 else:
304 return None
305
298 def getFileByName(self, filename):306 def getFileByName(self, filename):
299 """See `IPackageUpload`."""307 """See `IPackageUpload`."""
300 if (self.changesfile is not None and308 if (self.changesfile is not None and
301309
=== modified file 'lib/lp/soyuz/templates/build-index.pt'
--- lib/lp/soyuz/templates/build-index.pt 2012-03-01 18:17:56 +0000
+++ lib/lp/soyuz/templates/build-index.pt 2013-04-17 11:10:37 +0000
@@ -86,14 +86,7 @@
86 <dl>86 <dl>
87 <dt>Archive:</dt>87 <dt>Archive:</dt>
88 <dd>88 <dd>
89 <span tal:condition="view/is_ppa"89 <a tal:replace="structure context/archive/fmt:link" />
90 tal:replace="structure context/archive/fmt:link"
91 >Celso PPA</span>
92 <a class="sprite distribution"
93 tal:condition="not: view/is_ppa"
94 tal:attributes="href context/archive/fmt:url"
95 tal:content="context/archive/displayname"
96 >Ubuntu Primary Archive</a>
97 </dd>90 </dd>
98 </dl>91 </dl>
99 <dl>92 <dl>
10093
=== modified file 'lib/lp/soyuz/templates/distroseries-queue.pt'
--- lib/lp/soyuz/templates/distroseries-queue.pt 2012-11-15 01:41:14 +0000
+++ lib/lp/soyuz/templates/distroseries-queue.pt 2013-04-17 11:10:37 +0000
@@ -224,15 +224,15 @@
224 <tr>224 <tr>
225 <td />225 <td />
226 <td tal:condition="view/availableActions" />226 <td tal:condition="view/availableActions" />
227 <td colspan="7">227 <td colspan="7"
228 tal:define="pcj packageupload/package_copy_job;
229 visible pcj/source_archive/required:launchpad.View">
228 Sync from230 Sync from
229 <tal:archive231 <a tal:condition="visible"
230 content="packageupload/package_copy_job/source_archive/displayname">232 tal:replace="structure pcj/source_archive/fmt:link" />
231 Primary Archive for Ubuntu233 <span tal:condition="not:visible">private archive</span>,
232 </tal:archive>,
233 requested by234 requested by
234 <tal:requester235 <tal:requester content="structure pcj/job/requester/fmt:link" />
235 content="structure packageupload/package_copy_job/job/requester/fmt:link" />
236 </td>236 </td>
237 </tr>237 </tr>
238 </tal:sync>238 </tal:sync>
239239
=== modified file 'lib/lp/soyuz/tests/test_packageupload.py'
--- lib/lp/soyuz/tests/test_packageupload.py 2013-01-31 02:02:37 +0000
+++ lib/lp/soyuz/tests/test_packageupload.py 2013-04-17 11:10:37 +0000
@@ -902,6 +902,13 @@
902 transaction.commit()902 transaction.commit()
903 return upload, self.load(upload, person)903 return upload, self.load(upload, person)
904904
905 def makeCopyJobPackageUpload(self, person, **kwargs):
906 with person_logged_in(person):
907 upload = self.factory.makeCopyJobPackageUpload(
908 distroseries=self.distroseries, **kwargs)
909 transaction.commit()
910 return upload, self.load(upload, person)
911
905 def makeBinaryPackageUpload(self, person, binarypackagename=None,912 def makeBinaryPackageUpload(self, person, binarypackagename=None,
906 component=None):913 component=None):
907 with person_logged_in(person):914 with person_logged_in(person):
@@ -1293,6 +1300,24 @@
1293 }1300 }
1294 self.assertEqual(expected_custom, ws_binaries[-1])1301 self.assertEqual(expected_custom, ws_binaries[-1])
12951302
1303 def test_copy_info(self):
1304 # API clients can inspect properties of copies, including the source
1305 # archive.
1306 person = self.makeQueueAdmin([self.universe])
1307 archive = self.factory.makeArchive()
1308 upload, ws_upload = self.makeCopyJobPackageUpload(
1309 person, sourcepackagename="hello", source_archive=archive)
1310
1311 self.assertFalse(ws_upload.contains_source)
1312 self.assertFalse(ws_upload.contains_build)
1313 self.assertTrue(ws_upload.contains_copy)
1314 self.assertEqual("hello", ws_upload.display_name)
1315 self.assertEqual("sync", ws_upload.display_arches)
1316 self.assertEqual("hello", ws_upload.package_name)
1317 with person_logged_in(person):
1318 archive_url = api_url(archive)
1319 self.assertEndsWith(ws_upload.copy_source_archive_link, archive_url)
1320
1296 def test_getPackageUploads_query_count(self):1321 def test_getPackageUploads_query_count(self):
1297 person = self.makeQueueAdmin([self.universe])1322 person = self.makeQueueAdmin([self.universe])
1298 uploads = []1323 uploads = []
12991324
=== modified file 'lib/lp/testing/factory.py'
--- lib/lp/testing/factory.py 2013-03-08 22:17:31 +0000
+++ lib/lp/testing/factory.py 2013-04-17 11:10:37 +0000
@@ -3460,12 +3460,13 @@
3460 return upload3460 return upload
34613461
3462 def makeCopyJobPackageUpload(self, distroseries=None,3462 def makeCopyJobPackageUpload(self, distroseries=None,
3463 sourcepackagename=None, target_pocket=None):3463 sourcepackagename=None, source_archive=None,
3464 target_pocket=None):
3464 """Make a `PackageUpload` with a `PackageCopyJob` attached."""3465 """Make a `PackageUpload` with a `PackageCopyJob` attached."""
3465 if distroseries is None:3466 if distroseries is None:
3466 distroseries = self.makeDistroSeries()3467 distroseries = self.makeDistroSeries()
3467 spph = self.makeSourcePackagePublishingHistory(3468 spph = self.makeSourcePackagePublishingHistory(
3468 sourcepackagename=sourcepackagename)3469 archive=source_archive, sourcepackagename=sourcepackagename)
3469 spr = spph.sourcepackagerelease3470 spr = spph.sourcepackagerelease
3470 job = self.makePlainPackageCopyJob(3471 job = self.makePlainPackageCopyJob(
3471 package_name=spr.sourcepackagename.name,3472 package_name=spr.sourcepackagename.name,
34723473
=== modified file 'lib/lp/testing/tests/test_factory.py'
--- lib/lp/testing/tests/test_factory.py 2012-09-22 23:58:54 +0000
+++ lib/lp/testing/tests/test_factory.py 2013-04-17 11:10:37 +0000
@@ -1,4 +1,4 @@
1# Copyright 2010-2012 Canonical Ltd. This software is licensed under the1# Copyright 2010-2013 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4"""Tests for the Launchpad object factory."""4"""Tests for the Launchpad object factory."""
@@ -833,11 +833,14 @@
833 def test_makeCopyJobPackageUpload_passes_on_args(self):833 def test_makeCopyJobPackageUpload_passes_on_args(self):
834 distroseries = self.factory.makeDistroSeries()834 distroseries = self.factory.makeDistroSeries()
835 spn = self.factory.makeSourcePackageName()835 spn = self.factory.makeSourcePackageName()
836 source_archive = self.factory.makeArchive()
836 pu = self.factory.makeCopyJobPackageUpload(837 pu = self.factory.makeCopyJobPackageUpload(
837 distroseries=distroseries, sourcepackagename=spn)838 distroseries=distroseries, sourcepackagename=spn,
839 source_archive=source_archive)
838 job = removeSecurityProxy(pu.package_copy_job)840 job = removeSecurityProxy(pu.package_copy_job)
839 self.assertEqual(distroseries, pu.distroseries)841 self.assertEqual(distroseries, pu.distroseries)
840 self.assertEqual(distroseries.distribution, pu.archive.distribution)842 self.assertEqual(distroseries.distribution, pu.archive.distribution)
843 self.assertEqual(source_archive, job.source_archive)
841 self.assertEqual(distroseries, job.target_distroseries)844 self.assertEqual(distroseries, job.target_distroseries)
842 self.assertEqual(spn.name, job.package_name)845 self.assertEqual(spn.name, job.package_name)
843846