Merge lp:~michael.nelson/launchpad/include-binary-size into lp:launchpad

Proposed by Michael Nelson
Status: Merged
Merged at revision: 16515
Proposed branch: lp:~michael.nelson/launchpad/include-binary-size
Merge into: lp:launchpad
Diff against target: 218 lines (+102/-37)
4 files modified
lib/lp/soyuz/browser/tests/test_publishing_webservice.py (+40/-7)
lib/lp/soyuz/interfaces/publishing.py (+5/-1)
lib/lp/soyuz/model/publishing.py (+8/-1)
lib/lp/soyuz/tests/test_publishing_models.py (+49/-28)
To merge this branch: bzr merge lp:~michael.nelson/launchpad/include-binary-size
Reviewer Review Type Date Requested Status
William Grant code Approve
Launchpad code reviewers Pending
Review via email: mp+150831@code.launchpad.net

Commit message

Add optional include_sizes kwarg to BinaryPackagePublishingHistory.binaryFileUrls() and expose on API.

Description of the change

Add an optional include_sizes kwarg option to BPPH.binaryFileUrls(), defaulting to False to preserve current behaviour.

Brief pre-imp with wgrant discussed on bug 1088527.

./bin/test -vvct TestBinaryPackagePublishingHistory -t BinaryPackagePublishingHistoryWebserviceTests

I'll start the full test run on my instance.

To post a comment you must log in.
Revision history for this message
Robert Collins (lifeless) wrote :

18 bpph_url = api_url(bpph)
19 +
20 + return bpph_url

I would just do
18 return api_url(bpph)

and skip the temporary variable and spurious VWS.

Line 27 has more spurious VWS. As does 33. I'll stop listing the spurious VWS here :). Please imagine it throughout the rest of the diff.

36 + self.assertEqual(1, len(urls))
37 + self.assertTrue(type(urls[0]) == unicode)
Would be better as
    self.assertThat(urls, HasLength(1))
    self.assertThat(urls[0], IsInstance(unicode))

ditto at 51

Other than that it looks ok to me.

Revision history for this message
Michael Nelson (michael.nelson) wrote :

r16523 adds functionality requested by cjwatson (including the sha1).

08:59 < cjwatson> I know wgrant said that adding hashes would be "probably overcomplicated", but cf. bug 1088527
08:59 < noodles775> Wow - 40mins from 6hrs.
08:59 < noodles775> Looking
08:59 < _mup_> Bug #1088527: Needlessly asks for exact package name, file size, uploaded version <ca-escalated> <Developer registration portal:New for michael.nelson> <Launchpad itself:In Progress by michael.nelson> < https://launchpad.net/bugs/1088527 >
09:00 < cjwatson> Err, sorry
09:00 < cjwatson> cf. bug 1007195
09:01 < cjwatson> is what I meant to say
09:01 < _mup_> Bug #1007195: Librarian-backed HostedFile objects do not expose SHA-1 hash <soyuz-build> <Launchpad itself:Triaged> < https://launchpad.net/bugs/1007195 >
09:01 < cjwatson> (Doesn't specifically have to be the SHA-1 of course; I think that was just what the librarian keyed off at the time or something
09:01 < cjwatson> )
09:02 < cjwatson> Anyway, don't let me get in the way by expanding the scope of your work, it was just in case it was trivial to allow for it
09:03 < noodles775> cjwatson: sure - it should be trivial. So s/include_sizes/include_meta/ and add the the sha1 to the dict?
09:07 < cjwatson> I guess something like that

Revision history for this message
Michael Nelson (michael.nelson) wrote :

Robert,

I removed the useless vars, and updated to use the IsInstance matcher, but although I see HasLength on the testtools docs, I don't see it in the LP code or the version currently used by LP:

http://paste.ubuntu.com/5572967/

so I've gone with assertThat(len(urls), Equals(1)) instead.

Thanks!

Revision history for this message
William Grant (wgrant) wrote :

I'd like to see a query count test, since you're now accessing more subordinate objects. It happens to be OK now because BPPH.files prejoins LFA/LFC, but a test like http://pastebin.ubuntu.com/5574906/ will ensure that performance doesn't regress.

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/soyuz/browser/tests/test_publishing_webservice.py'
2--- lib/lp/soyuz/browser/tests/test_publishing_webservice.py 2012-01-01 02:58:52 +0000
3+++ lib/lp/soyuz/browser/tests/test_publishing_webservice.py 2013-03-01 08:07:23 +0000
4@@ -3,6 +3,7 @@
5
6 """Test webservice methods related to the publisher."""
7
8+from lp.services.database.sqlbase import flush_database_caches
9 from lp.services.webapp.interfaces import OAuthPermission
10 from lp.testing import (
11 api_url,
12@@ -11,24 +12,56 @@
13 )
14 from lp.testing.layers import LaunchpadFunctionalLayer
15 from lp.testing.pages import webservice_for_person
16+from lp.testing._webservice import QueryCollector
17+from testtools.matchers import IsInstance
18
19
20 class BinaryPackagePublishingHistoryWebserviceTests(TestCaseWithFactory):
21
22 layer = LaunchpadFunctionalLayer
23
24+ def make_bpph_for(self, person):
25+ with person_logged_in(person):
26+ bpr = self.factory.makeBinaryPackageRelease()
27+ self.factory.makeBinaryPackageFile(binarypackagerelease=bpr)
28+ bpph = self.factory.makeBinaryPackagePublishingHistory(
29+ binarypackagerelease=bpr)
30+ return bpph, api_url(bpph)
31+
32 def test_binaryFileUrls(self):
33- bpr = self.factory.makeBinaryPackageRelease()
34- self.factory.makeBinaryPackageFile(binarypackagerelease=bpr)
35- bpph = self.factory.makeBinaryPackagePublishingHistory(
36- binarypackagerelease=bpr)
37 person = self.factory.makePerson()
38 webservice = webservice_for_person(
39 person, permission=OAuthPermission.READ_PUBLIC)
40- with person_logged_in(person):
41- bpph_url = api_url(bpph)
42+
43 response = webservice.named_get(
44- bpph_url, 'binaryFileUrls', api_version='devel')
45+ self.make_bpph_for(person)[1], 'binaryFileUrls',
46+ api_version='devel')
47+
48 self.assertEqual(200, response.status)
49 urls = response.jsonBody()
50 self.assertEqual(1, len(urls))
51+ self.assertTrue(urls[0], IsInstance(unicode))
52+
53+ def test_binaryFileUrls_include_meta(self):
54+ person = self.factory.makePerson()
55+ webservice = webservice_for_person(
56+ person, permission=OAuthPermission.READ_PUBLIC)
57+
58+ bpph, url = self.make_bpph_for(person)
59+ query_counts = []
60+ for i in range(3):
61+ flush_database_caches()
62+ with QueryCollector() as collector:
63+ response = webservice.named_get(
64+ url, 'binaryFileUrls', include_meta=True,
65+ api_version='devel')
66+ query_counts.append(collector.count)
67+ with person_logged_in(person):
68+ self.factory.makeBinaryPackageFile(
69+ binarypackagerelease=bpph.binarypackagerelease)
70+ self.assertEqual(query_counts[0] - 1, query_counts[-1])
71+
72+ self.assertEqual(200, response.status)
73+ urls = response.jsonBody()
74+ self.assertEqual(3, len(urls))
75+ self.assertThat(urls[0], IsInstance(dict))
76
77=== modified file 'lib/lp/soyuz/interfaces/publishing.py'
78--- lib/lp/soyuz/interfaces/publishing.py 2013-02-20 12:28:38 +0000
79+++ lib/lp/soyuz/interfaces/publishing.py 2013-03-01 08:07:23 +0000
80@@ -946,10 +946,14 @@
81 """
82
83 @export_read_operation()
84+ @operation_parameters(
85+ include_meta=Bool(title=_("Include Metadata"), required=False))
86 @operation_for_version("devel")
87- def binaryFileUrls():
88+ def binaryFileUrls(include_meta=False):
89 """URLs for this binary publication's binary files.
90
91+ :param include_meta: Return a list of dicts with keys url, size
92+ and sha1 for each url instead of a simple list.
93 :return: A collection of URLs for this binary.
94 """
95
96
97=== modified file 'lib/lp/soyuz/model/publishing.py'
98--- lib/lp/soyuz/model/publishing.py 2013-02-20 12:30:47 +0000
99+++ lib/lp/soyuz/model/publishing.py 2013-03-01 08:07:23 +0000
100@@ -1375,10 +1375,17 @@
101 """See `IPublishing`."""
102 self.setDeleted(removed_by, removal_comment)
103
104- def binaryFileUrls(self):
105+ def binaryFileUrls(self, include_meta=False):
106 """See `IBinaryPackagePublishingHistory`."""
107 binary_urls = proxied_urls(
108 [f.libraryfilealias for f in self.files], self.archive)
109+ if include_meta:
110+ meta = [(
111+ f.libraryfilealias.content.filesize,
112+ f.libraryfilealias.content.sha1,
113+ ) for f in self.files]
114+ return [dict(url=url, size=size, sha1=sha1)
115+ for url, (size, sha1) in zip(binary_urls, meta)]
116 return binary_urls
117
118
119
120=== modified file 'lib/lp/soyuz/tests/test_publishing_models.py'
121--- lib/lp/soyuz/tests/test_publishing_models.py 2013-01-24 01:09:04 +0000
122+++ lib/lp/soyuz/tests/test_publishing_models.py 2013-03-01 08:07:23 +0000
123@@ -4,11 +4,9 @@
124 """Test model and set utilities used for publishing."""
125
126 from zope.component import getUtility
127-from zope.security.proxy import removeSecurityProxy
128
129 from lp.app.errors import NotFoundError
130 from lp.buildmaster.enums import BuildStatus
131-from lp.services.database.constants import UTC_NOW
132 from lp.services.librarian.browser import ProxiedLibraryFileAlias
133 from lp.services.webapp.publisher import canonical_url
134 from lp.soyuz.enums import BinaryPackageFileType
135@@ -154,34 +152,57 @@
136
137 layer = LaunchpadFunctionalLayer
138
139+ def get_urls_for_bpph(self, bpph, include_meta=False):
140+ bpr = bpph.binarypackagerelease
141+ archive = bpph.archive
142+ urls = [ProxiedLibraryFileAlias(f.libraryfile, archive).http_url
143+ for f in bpr.files]
144+
145+ if include_meta:
146+ meta = [(
147+ f.libraryfile.content.filesize,
148+ f.libraryfile.content.sha1,
149+ ) for f in bpr.files]
150+
151+ return [dict(url=url, size=size, sha1=sha1)
152+ for url, (size, sha1) in zip(urls, meta)]
153+ return urls
154+
155+ def make_bpph(self, num_binaries=1):
156+ archive = self.factory.makeArchive(private=False)
157+ bpr = self.factory.makeBinaryPackageRelease()
158+ filetypes = [BinaryPackageFileType.DEB, BinaryPackageFileType.DDEB]
159+ for count in range(num_binaries):
160+ self.factory.makeBinaryPackageFile(binarypackagerelease=bpr,
161+ filetype=filetypes[count % 2])
162+ return self.factory.makeBinaryPackagePublishingHistory(
163+ binarypackagerelease=bpr, archive=archive)
164+
165 def test_binaryFileUrls_no_binaries(self):
166- bpr = self.factory.makeBinaryPackageRelease()
167- bpph = self.factory.makeBinaryPackagePublishingHistory(
168- binarypackagerelease=bpr)
169- expected_urls = []
170- self.assertContentEqual(expected_urls, bpph.binaryFileUrls())
171-
172- def get_urls_for_binarypackagerelease(self, bpr, archive):
173- return [ProxiedLibraryFileAlias(f.libraryfile, archive).http_url
174- for f in bpr.files]
175+ bpph = self.make_bpph(num_binaries=0)
176+
177+ urls = bpph.binaryFileUrls()
178+
179+ self.assertContentEqual([], urls)
180
181 def test_binaryFileUrls_one_binary(self):
182- archive = self.factory.makeArchive(private=False)
183- bpr = self.factory.makeBinaryPackageRelease()
184- self.factory.makeBinaryPackageFile(binarypackagerelease=bpr)
185- bpph = self.factory.makeBinaryPackagePublishingHistory(
186- binarypackagerelease=bpr, archive=archive)
187- expected_urls = self.get_urls_for_binarypackagerelease(bpr, archive)
188- self.assertContentEqual(expected_urls, bpph.binaryFileUrls())
189+ bpph = self.make_bpph(num_binaries=1)
190+
191+ urls = bpph.binaryFileUrls()
192+
193+ self.assertContentEqual(self.get_urls_for_bpph(bpph), urls)
194
195 def test_binaryFileUrls_two_binaries(self):
196- archive = self.factory.makeArchive(private=False)
197- bpr = self.factory.makeBinaryPackageRelease()
198- self.factory.makeBinaryPackageFile(
199- binarypackagerelease=bpr, filetype=BinaryPackageFileType.DEB)
200- self.factory.makeBinaryPackageFile(
201- binarypackagerelease=bpr, filetype=BinaryPackageFileType.DDEB)
202- bpph = self.factory.makeBinaryPackagePublishingHistory(
203- binarypackagerelease=bpr, archive=archive)
204- expected_urls = self.get_urls_for_binarypackagerelease(bpr, archive)
205- self.assertContentEqual(expected_urls, bpph.binaryFileUrls())
206+ bpph = self.make_bpph(num_binaries=2)
207+
208+ urls = bpph.binaryFileUrls()
209+
210+ self.assertContentEqual(self.get_urls_for_bpph(bpph), urls)
211+
212+ def test_binaryFileUrls_include_meta(self):
213+ bpph = self.make_bpph(num_binaries=2)
214+
215+ urls = bpph.binaryFileUrls(include_meta=True)
216+
217+ self.assertContentEqual(
218+ self.get_urls_for_bpph(bpph, include_meta=True), urls)