Merge lp:~stevenk/launchpad/generic-overrides into lp:launchpad
- generic-overrides
- Merge into devel
Status: | Merged |
---|---|
Approved by: | Steve Kowalik |
Approved revision: | no longer in the source branch. |
Merged at revision: | 13041 |
Proposed branch: | lp:~stevenk/launchpad/generic-overrides |
Merge into: | lp:launchpad |
Diff against target: |
469 lines (+438/-6) 3 files modified
lib/lp/soyuz/adapters/overrides.py (+215/-0) lib/lp/soyuz/adapters/tests/test_overrides.py (+223/-0) lib/lp/soyuz/adapters/tests/test_packagelocation.py (+0/-6) |
To merge this branch: | bzr merge lp:~stevenk/launchpad/generic-overrides |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Gavin Panella (community) | Approve | ||
Review via email: mp+60730@code.launchpad.net |
Commit message
[r=allenap][no-qa] Add three generic override support classes.
Description of the change
Add a generic overrides support class.
In this context, overrides are a description of which component, section and priority a source or binary package should be stored in. This is most used in sync'ing from Debian, where the component in Debian is 'main', but Ubuntu has the source in 'universe'. It also allows further copies or uploads to the same archive/
Nothing makes use of it in this branch, but it sets up the ground work. The package copier will make use of this framework in a future branch, and the plan is to have the publisher and the upload processor also make use of this framework.
I have also done two drive-bys in this branch, I moved a test into adapters/tests, and I deleted the test harness stuff from another test.
Gavin Panella (allenap) wrote : | # |
> [4]
> ...
> Also, see [2].
Actually, see [3].
Steve Kowalik (stevenk) wrote : | # |
[1]: Both done, thanks.
[2]: After thinking about this for a while, I JFDI'd, and I think you'll agree it looks cleaner.
[3]: Mainly because {Source,
[4]: Nice catch! Missing ORDER BY added.
[5]: Shifted around, and switched to bulk.load().
[6]: There is, so I can call them directly from inside UbuntuOverrideP
[7]: Indeed, it was masking the failure in the eager loading functions, thanks. It also pointed out that both source and binary query counts were wrong -- I was wondering why the source call only issued two queries when I was expecting four.
[8]: We may as well materialize them, since the caller is just going to loop over it anyway.
Steve Kowalik (stevenk) wrote : | # |
[3]: Further, lots of the components and section will be the same, so we gain a large penalty by having to construct lots of similar objects inside Storm.
Gavin Panella (allenap) wrote : | # |
Tip top, land it :)
Preview Diff
1 | === added file 'lib/lp/soyuz/adapters/overrides.py' |
2 | --- lib/lp/soyuz/adapters/overrides.py 1970-01-01 00:00:00 +0000 |
3 | +++ lib/lp/soyuz/adapters/overrides.py 2011-05-13 08:32:29 +0000 |
4 | @@ -0,0 +1,215 @@ |
5 | +# Copyright 2011 Canonical Ltd. This software is licensed under the |
6 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
7 | + |
8 | +"""Generic Override Policy classes. |
9 | +""" |
10 | + |
11 | +__metaclass__ = type |
12 | + |
13 | +__all__ = [ |
14 | + 'FromExistingOverridePolicy', |
15 | + 'UbuntuOverridePolicy', |
16 | + 'UnknownOverridePolicy', |
17 | + ] |
18 | + |
19 | + |
20 | +from storm.expr import ( |
21 | + And, |
22 | + Desc, |
23 | + Or, |
24 | + SQL, |
25 | + ) |
26 | + |
27 | +from canonical.launchpad.components.decoratedresultset import ( |
28 | + DecoratedResultSet, |
29 | + ) |
30 | +from canonical.launchpad.interfaces.lpstorm import IStore |
31 | +from lp.registry.model.sourcepackagename import SourcePackageName |
32 | +from lp.services.database import bulk |
33 | +from lp.soyuz.interfaces.publishing import active_publishing_status |
34 | +from lp.soyuz.model.binarypackagename import BinaryPackageName |
35 | +from lp.soyuz.model.binarypackagerelease import BinaryPackageRelease |
36 | +from lp.soyuz.model.component import Component |
37 | +from lp.soyuz.model.distroarchseries import DistroArchSeries |
38 | +from lp.soyuz.model.publishing import ( |
39 | + BinaryPackagePublishingHistory, |
40 | + SourcePackagePublishingHistory, |
41 | + ) |
42 | +from lp.soyuz.model.section import Section |
43 | +from lp.soyuz.model.sourcepackagerelease import SourcePackageRelease |
44 | + |
45 | + |
46 | +class BaseOverridePolicy: |
47 | + |
48 | + def calculateSourceOverrides(self, archive, distroseries, pocket, |
49 | + sources): |
50 | + raise NotImplementedError() |
51 | + |
52 | + def calculateBinaryOverrides(self, archive, distroseries, pocket, |
53 | + binaries): |
54 | + raise NotImplementedError() |
55 | + |
56 | + |
57 | +class FromExistingOverridePolicy(BaseOverridePolicy): |
58 | + """Override policy that only searches for existing publications. |
59 | + |
60 | + Override policy that returns the SourcePackageName, component and |
61 | + section for the latest published source publication, or the |
62 | + BinaryPackageName, DistroArchSeries, component, section and priority |
63 | + for the latest published binary publication. |
64 | + """ |
65 | + |
66 | + def calculateSourceOverrides(self, archive, distroseries, pocket, spns): |
67 | + store = IStore(SourcePackagePublishingHistory) |
68 | + def eager_load(rows): |
69 | + bulk.load(Component, (row[2] for row in rows)) |
70 | + bulk.load(Section, (row[3] for row in rows)) |
71 | + already_published = DecoratedResultSet( |
72 | + store.find( |
73 | + (SQL("""DISTINCT ON ( |
74 | + SourcePackageRelease.sourcepackagename) 0 AS ignore"""), |
75 | + SourcePackageRelease.sourcepackagenameID, |
76 | + SourcePackagePublishingHistory.componentID, |
77 | + SourcePackagePublishingHistory.sectionID), |
78 | + SourcePackagePublishingHistory.pocket == pocket, |
79 | + SourcePackagePublishingHistory.archiveID == archive.id, |
80 | + SourcePackagePublishingHistory.distroseriesID == |
81 | + distroseries.id, |
82 | + SourcePackagePublishingHistory.status.is_in( |
83 | + active_publishing_status), |
84 | + SourcePackageRelease.id == |
85 | + SourcePackagePublishingHistory.sourcepackagereleaseID, |
86 | + SourcePackageRelease.sourcepackagenameID.is_in( |
87 | + spn.id for spn in spns)).order_by( |
88 | + SourcePackageRelease.sourcepackagenameID, |
89 | + Desc(SourcePackagePublishingHistory.datecreated), |
90 | + Desc(SourcePackagePublishingHistory.id)), |
91 | + id_resolver( |
92 | + (SourcePackageName, Component, Section), slice(1, None)), |
93 | + pre_iter_hook=eager_load) |
94 | + return list(already_published) |
95 | + |
96 | + def calculateBinaryOverrides(self, archive, distroseries, pocket, |
97 | + binaries): |
98 | + store = IStore(BinaryPackagePublishingHistory) |
99 | + def eager_load(rows): |
100 | + bulk.load(Component, (row[3] for row in rows)) |
101 | + bulk.load(Section, (row[4] for row in rows)) |
102 | + expanded = calculate_target_das(distroseries, binaries) |
103 | + candidates = ( |
104 | + make_package_condition(archive, das, bpn) |
105 | + for bpn, das in expanded) |
106 | + already_published = DecoratedResultSet( |
107 | + store.find( |
108 | + (SQL("""DISTINCT ON ( |
109 | + BinaryPackagePublishingHistory.distroarchseries, |
110 | + BinaryPackageRelease.binarypackagename) 0 |
111 | + AS ignore"""), |
112 | + BinaryPackageRelease.binarypackagenameID, |
113 | + BinaryPackagePublishingHistory.distroarchseriesID, |
114 | + BinaryPackagePublishingHistory.componentID, |
115 | + BinaryPackagePublishingHistory.sectionID, |
116 | + BinaryPackagePublishingHistory.priority), |
117 | + BinaryPackagePublishingHistory.pocket == pocket, |
118 | + BinaryPackagePublishingHistory.status.is_in( |
119 | + active_publishing_status), |
120 | + BinaryPackageRelease.id == |
121 | + BinaryPackagePublishingHistory.binarypackagereleaseID, |
122 | + Or(*candidates)).order_by( |
123 | + BinaryPackagePublishingHistory.distroarchseriesID, |
124 | + BinaryPackageRelease.binarypackagenameID, |
125 | + Desc(BinaryPackagePublishingHistory.datecreated), |
126 | + Desc(BinaryPackagePublishingHistory.id)), |
127 | + id_resolver( |
128 | + (BinaryPackageName, DistroArchSeries, Component, Section, |
129 | + None), |
130 | + slice(1, None)), |
131 | + pre_iter_hook=eager_load) |
132 | + return list(already_published) |
133 | + |
134 | + |
135 | +class UnknownOverridePolicy(BaseOverridePolicy): |
136 | + """Override policy that returns defaults. |
137 | + |
138 | + Override policy that assumes everything passed in doesn't exist, so |
139 | + returns the defaults. |
140 | + """ |
141 | + |
142 | + def calculateSourceOverrides(self, archive, distroseries, pocket, |
143 | + sources): |
144 | + default_component = archive.default_component or 'universe' |
145 | + return [(source, default_component, None) for source in sources] |
146 | + |
147 | + def calculateBinaryOverrides(self, archive, distroseries, pocket, |
148 | + binaries): |
149 | + default_component = archive.default_component or 'universe' |
150 | + return [ |
151 | + (binary, das, default_component, None, None) |
152 | + for binary, das in calculate_target_das(distroseries, binaries)] |
153 | + |
154 | + |
155 | +class UbuntuOverridePolicy(FromExistingOverridePolicy, |
156 | + UnknownOverridePolicy): |
157 | + """Override policy for Ubuntu. |
158 | + |
159 | + An override policy that incorporates both the from existing policy |
160 | + and the unknown policy. |
161 | + """ |
162 | + |
163 | + def calculateSourceOverrides(self, archive, distroseries, pocket, |
164 | + sources): |
165 | + total = set(sources) |
166 | + overrides = FromExistingOverridePolicy.calculateSourceOverrides( |
167 | + self, archive, distroseries, pocket, sources) |
168 | + existing = set(override[0] for override in overrides) |
169 | + missing = total.difference(existing) |
170 | + if missing: |
171 | + unknown = UnknownOverridePolicy.calculateSourceOverrides( |
172 | + self, archive, distroseries, pocket, missing) |
173 | + overrides.extend(unknown) |
174 | + return overrides |
175 | + |
176 | + def calculateBinaryOverrides(self, archive, distroseries, pocket, |
177 | + binaries): |
178 | + total = set(binaries) |
179 | + overrides = FromExistingOverridePolicy.calculateBinaryOverrides( |
180 | + self, archive, distroseries, pocket, binaries) |
181 | + existing = set(( |
182 | + overide[0], overide[1].architecturetag) |
183 | + for overide in overrides) |
184 | + missing = total.difference(existing) |
185 | + if missing: |
186 | + unknown = UnknownOverridePolicy.calculateBinaryOverrides( |
187 | + self, archive, distroseries, pocket, missing) |
188 | + overrides.extend(unknown) |
189 | + return overrides |
190 | + |
191 | + |
192 | +def calculate_target_das(distroseries, binaries): |
193 | + arch_map = dict( |
194 | + (arch.architecturetag, arch) |
195 | + for arch in distroseries.enabled_architectures) |
196 | + |
197 | + with_das = [] |
198 | + for bpn, archtag in binaries: |
199 | + if archtag is not None: |
200 | + with_das.append((bpn, arch_map.get(archtag))) |
201 | + else: |
202 | + with_das.append((bpn, distroseries.nominatedarchindep)) |
203 | + return with_das |
204 | + |
205 | + |
206 | +def make_package_condition(archive, das, bpn): |
207 | + return And( |
208 | + BinaryPackagePublishingHistory.archiveID == archive.id, |
209 | + BinaryPackagePublishingHistory.distroarchseriesID == das.id, |
210 | + BinaryPackageRelease.binarypackagenameID == bpn.id) |
211 | + |
212 | + |
213 | +def id_resolver(lookups, slice): |
214 | + def _resolve(row): |
215 | + store = IStore(SourcePackagePublishingHistory) |
216 | + return tuple( |
217 | + (value if cls is None else store.get(cls, value)) |
218 | + for value, cls in zip(row[slice], lookups)) |
219 | + return _resolve |
220 | |
221 | === renamed file 'lib/lp/soyuz/tests/test_copypolicy.py' => 'lib/lp/soyuz/adapters/tests/test_copypolicy.py' |
222 | === added file 'lib/lp/soyuz/adapters/tests/test_overrides.py' |
223 | --- lib/lp/soyuz/adapters/tests/test_overrides.py 1970-01-01 00:00:00 +0000 |
224 | +++ lib/lp/soyuz/adapters/tests/test_overrides.py 2011-05-13 08:32:29 +0000 |
225 | @@ -0,0 +1,223 @@ |
226 | +# Copyright 2011 Canonical Ltd. This software is licensed under the |
227 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
228 | + |
229 | +"""Test generic override policy classes.""" |
230 | + |
231 | +from testtools.matchers import Equals |
232 | + |
233 | +from canonical.database.sqlbase import flush_database_caches |
234 | +from canonical.testing.layers import LaunchpadZopelessLayer |
235 | +from lp.services.database import bulk |
236 | +from lp.soyuz.adapters.overrides import ( |
237 | + FromExistingOverridePolicy, |
238 | + UbuntuOverridePolicy, |
239 | + UnknownOverridePolicy, |
240 | + ) |
241 | +from lp.soyuz.enums import PackagePublishingStatus |
242 | +from lp.testing import ( |
243 | + StormStatementRecorder, |
244 | + TestCaseWithFactory, |
245 | + ) |
246 | +from lp.testing.matchers import HasQueryCount |
247 | + |
248 | + |
249 | +class TestOverrides(TestCaseWithFactory): |
250 | + |
251 | + layer = LaunchpadZopelessLayer |
252 | + |
253 | + def test_no_source_overrides(self): |
254 | + # If the spn is not published in the given archive/distroseries, an |
255 | + # empty list is returned. |
256 | + spn = self.factory.makeSourcePackageName() |
257 | + distroseries = self.factory.makeDistroSeries() |
258 | + pocket = self.factory.getAnyPocket() |
259 | + policy = FromExistingOverridePolicy() |
260 | + overrides = policy.calculateSourceOverrides( |
261 | + distroseries.main_archive, distroseries, pocket, (spn,)) |
262 | + self.assertEqual([], overrides) |
263 | + |
264 | + def test_source_overrides(self): |
265 | + # When the spn is published in the given archive/distroseries, the |
266 | + # overrides for that archive/distroseries are returned. |
267 | + spph = self.factory.makeSourcePackagePublishingHistory() |
268 | + policy = FromExistingOverridePolicy() |
269 | + overrides = policy.calculateSourceOverrides( |
270 | + spph.distroseries.main_archive, spph.distroseries, spph.pocket, |
271 | + (spph.sourcepackagerelease.sourcepackagename,)) |
272 | + expected = [( |
273 | + spph.sourcepackagerelease.sourcepackagename, |
274 | + spph.component, spph.section)] |
275 | + self.assertEqual(expected, overrides) |
276 | + |
277 | + def test_source_overrides_latest_only_is_returned(self): |
278 | + # When the spn is published multiple times in the given |
279 | + # archive/distroseries, the latest publication's overrides are |
280 | + # returned. |
281 | + spn = self.factory.makeSourcePackageName() |
282 | + distroseries = self.factory.makeDistroSeries() |
283 | + published_spr = self.factory.makeSourcePackageRelease( |
284 | + sourcepackagename=spn) |
285 | + self.factory.makeSourcePackagePublishingHistory( |
286 | + sourcepackagerelease=published_spr, distroseries=distroseries, |
287 | + status=PackagePublishingStatus.PUBLISHED) |
288 | + spr = self.factory.makeSourcePackageRelease( |
289 | + sourcepackagename=spn) |
290 | + spph = self.factory.makeSourcePackagePublishingHistory( |
291 | + sourcepackagerelease=spr, distroseries=distroseries) |
292 | + policy = FromExistingOverridePolicy() |
293 | + overrides = policy.calculateSourceOverrides( |
294 | + distroseries.main_archive, distroseries, spph.pocket, (spn,)) |
295 | + self.assertEqual([(spn, spph.component, spph.section)], overrides) |
296 | + |
297 | + def test_source_overrides_constant_query_count(self): |
298 | + # The query count is constant, no matter how many sources are |
299 | + # checked. |
300 | + spns = [] |
301 | + distroseries = self.factory.makeDistroSeries() |
302 | + pocket = self.factory.getAnyPocket() |
303 | + for i in xrange(10): |
304 | + spph = self.factory.makeSourcePackagePublishingHistory( |
305 | + distroseries=distroseries, archive=distroseries.main_archive, |
306 | + pocket=pocket) |
307 | + spns.append(spph.sourcepackagerelease.sourcepackagename) |
308 | + flush_database_caches() |
309 | + distroseries.main_archive |
310 | + bulk.reload(spns) |
311 | + policy = FromExistingOverridePolicy() |
312 | + with StormStatementRecorder() as recorder: |
313 | + policy.calculateSourceOverrides( |
314 | + spph.distroseries.main_archive, spph.distroseries, |
315 | + spph.pocket, spns) |
316 | + self.assertThat(recorder, HasQueryCount(Equals(4))) |
317 | + |
318 | + def test_no_binary_overrides(self): |
319 | + # if the given binary is not published in the given distroarchseries, |
320 | + # an empty list is returned. |
321 | + distroseries = self.factory.makeDistroSeries() |
322 | + das = self.factory.makeDistroArchSeries(distroseries=distroseries) |
323 | + distroseries.nominatedarchindep = das |
324 | + bpn = self.factory.makeBinaryPackageName() |
325 | + pocket = self.factory.getAnyPocket() |
326 | + policy = FromExistingOverridePolicy() |
327 | + overrides = policy.calculateBinaryOverrides( |
328 | + distroseries.main_archive, distroseries, pocket, ((bpn, None),)) |
329 | + self.assertEqual([], overrides) |
330 | + |
331 | + def test_binary_overrides(self): |
332 | + # When a binary is published in the given distroarchseries, the |
333 | + # overrides are returned. |
334 | + bpph = self.factory.makeBinaryPackagePublishingHistory() |
335 | + distroseries = bpph.distroarchseries.distroseries |
336 | + distroseries.nominatedarchindep = bpph.distroarchseries |
337 | + policy = FromExistingOverridePolicy() |
338 | + overrides = policy.calculateBinaryOverrides( |
339 | + distroseries.main_archive, distroseries, bpph.pocket, |
340 | + ((bpph.binarypackagerelease.binarypackagename, None),)) |
341 | + expected = [( |
342 | + bpph.binarypackagerelease.binarypackagename, |
343 | + bpph.distroarchseries, bpph.component, bpph.section, |
344 | + bpph.priority)] |
345 | + self.assertEqual(expected, overrides) |
346 | + |
347 | + def test_binary_overrides_constant_query_count(self): |
348 | + # The query count is constant, no matter how many bpn-das pairs are |
349 | + # checked. |
350 | + bpns = [] |
351 | + distroarchseries = self.factory.makeDistroArchSeries() |
352 | + distroseries = distroarchseries.distroseries |
353 | + distroseries.nominatedarchindep = distroarchseries |
354 | + pocket = self.factory.getAnyPocket() |
355 | + for i in xrange(10): |
356 | + bpph = self.factory.makeBinaryPackagePublishingHistory( |
357 | + distroarchseries=distroarchseries, |
358 | + archive=distroseries.main_archive, pocket=pocket) |
359 | + bpns.append((bpph.binarypackagerelease.binarypackagename, None)) |
360 | + flush_database_caches() |
361 | + distroseries.main_archive |
362 | + bulk.reload(bpn[0] for bpn in bpns) |
363 | + policy = FromExistingOverridePolicy() |
364 | + with StormStatementRecorder() as recorder: |
365 | + policy.calculateBinaryOverrides( |
366 | + distroseries.main_archive, distroseries, pocket, bpns) |
367 | + self.assertThat(recorder, HasQueryCount(Equals(4))) |
368 | + |
369 | + def test_unknown_sources(self): |
370 | + # If the unknown policy is used, it does no checks, just returns the |
371 | + # defaults. |
372 | + spph = self.factory.makeSourcePackagePublishingHistory() |
373 | + policy = UnknownOverridePolicy() |
374 | + overrides = policy.calculateSourceOverrides( |
375 | + spph.distroseries.main_archive, spph.distroseries, spph.pocket, |
376 | + (spph.sourcepackagerelease.sourcepackagename,)) |
377 | + expected = [(spph.sourcepackagerelease.sourcepackagename, 'universe', |
378 | + None)] |
379 | + self.assertEqual(expected, overrides) |
380 | + |
381 | + def test_unknown_binaries(self): |
382 | + # If the unknown policy is used, it does no checks, just returns the |
383 | + # defaults. |
384 | + bpph = self.factory.makeBinaryPackagePublishingHistory() |
385 | + distroseries = bpph.distroarchseries.distroseries |
386 | + distroseries.nominatedarchindep = bpph.distroarchseries |
387 | + policy = UnknownOverridePolicy() |
388 | + overrides = policy.calculateBinaryOverrides( |
389 | + distroseries.main_archive, distroseries, bpph.pocket, |
390 | + ((bpph.binarypackagerelease.binarypackagename, None),)) |
391 | + expected = [(bpph.binarypackagerelease.binarypackagename, |
392 | + bpph.distroarchseries, 'universe', None, None)] |
393 | + self.assertEqual(expected, overrides) |
394 | + |
395 | + def test_ubuntu_override_policy_sources(self): |
396 | + # The Ubuntu policy incorporates both the existing and the unknown |
397 | + # policy. |
398 | + spns = [self.factory.makeSourcePackageName()] |
399 | + expected = [(spns[0], 'universe', None)] |
400 | + distroseries = self.factory.makeDistroSeries() |
401 | + pocket = self.factory.getAnyPocket() |
402 | + for i in xrange(8): |
403 | + spph = self.factory.makeSourcePackagePublishingHistory( |
404 | + distroseries=distroseries, archive=distroseries.main_archive, |
405 | + pocket=pocket) |
406 | + spns.append(spph.sourcepackagerelease.sourcepackagename) |
407 | + expected.append(( |
408 | + spph.sourcepackagerelease.sourcepackagename, spph.component, |
409 | + spph.section)) |
410 | + spns.append(self.factory.makeSourcePackageName()) |
411 | + expected.append((spns[-1], 'universe', None)) |
412 | + policy = UbuntuOverridePolicy() |
413 | + overrides = policy.calculateSourceOverrides( |
414 | + distroseries.main_archive, distroseries, pocket, spns) |
415 | + self.assertEqual(10, len(overrides)) |
416 | + self.assertContentEqual(expected, overrides) |
417 | + |
418 | + def test_ubuntu_override_policy_binaries(self): |
419 | + # The Ubuntu policy incorporates both the existing and the unknown |
420 | + # policy. |
421 | + distroseries = self.factory.makeDistroSeries() |
422 | + pocket = self.factory.getAnyPocket() |
423 | + bpn = self.factory.makeBinaryPackageName() |
424 | + bpns = [] |
425 | + expected = [] |
426 | + for i in xrange(3): |
427 | + distroarchseries = self.factory.makeDistroArchSeries( |
428 | + distroseries=distroseries) |
429 | + bpr = self.factory.makeBinaryPackageRelease( |
430 | + binarypackagename=bpn) |
431 | + bpph = self.factory.makeBinaryPackagePublishingHistory( |
432 | + binarypackagerelease=bpr, distroarchseries=distroarchseries, |
433 | + archive=distroseries.main_archive, pocket=pocket) |
434 | + bpns.append((bpn, distroarchseries.architecturetag)) |
435 | + expected.append(( |
436 | + bpn, distroarchseries, bpph.component, bpph.section, |
437 | + bpph.priority)) |
438 | + for i in xrange(2): |
439 | + distroarchseries = self.factory.makeDistroArchSeries( |
440 | + distroseries=distroseries) |
441 | + bpns.append((bpn, distroarchseries.architecturetag)) |
442 | + expected.append((bpn, distroarchseries, 'universe', None, None)) |
443 | + distroseries.nominatedarchindep = distroarchseries |
444 | + policy = UbuntuOverridePolicy() |
445 | + overrides = policy.calculateBinaryOverrides( |
446 | + distroseries.main_archive, distroseries, pocket, bpns) |
447 | + self.assertEqual(5, len(overrides)) |
448 | + self.assertContentEqual(expected, overrides) |
449 | |
450 | === modified file 'lib/lp/soyuz/adapters/tests/test_packagelocation.py' |
451 | --- lib/lp/soyuz/adapters/tests/test_packagelocation.py 2010-10-04 19:50:45 +0000 |
452 | +++ lib/lp/soyuz/adapters/tests/test_packagelocation.py 2011-05-13 08:32:29 +0000 |
453 | @@ -3,8 +3,6 @@ |
454 | |
455 | """Test PackageLocation class.""" |
456 | |
457 | -import unittest |
458 | - |
459 | from zope.component import getUtility |
460 | |
461 | from canonical.testing.layers import LaunchpadZopelessLayer |
462 | @@ -260,7 +258,3 @@ |
463 | str(location_ubuntu_packageset), |
464 | 'Primary Archive for Ubuntu Linux: ' |
465 | 'hoary-RELEASE [foo-packageset]') |
466 | - |
467 | - |
468 | -def test_suite(): |
469 | - return unittest.TestLoader().loadTestsFromName(__name__) |
Looks good, but I have some comments about the choice of API. There
are also some problems in the way you're measuring query counts which
means that the tests have missed some problems. So, the meaty bits of
this branch are good, but it still needs some attention before
landing.
[1]
+ """Override policy that returns the SPN, component and section for
+ the latest published source publication, or the BPN, DAS, component,
+ section and priority for the latest published binary publication.
+ """
For the sake of our future selves and our children, please can you
write out SPN, BPN, etc. in full?
Also, the docstring policy is meant to be something like:
"""Short, single-line summary.
Longer explanation.
"""
I assume it's like this so that it looks good in autogenerated
documentation, but I don't know how many people use it. I certainly
only look at the code.
[2]
+class BaseOverridePolicy: des(self, archive, distroseries, pocket, sources=None, rror("Must be implemented by sub-class.")
+
+ def calculateOverri
+ binaries=None):
+ raise NotImplementedE
Looking at the implementations - none of which want to be passed both Overrides( ) and calculateBinary Overrides( ).
sources and binaries - I wonder why not split this into two methods,
calculateSource
[3]
+ def findSourceOverr ides(self, archive, distroseries, pocket, spns): SourcePackagePu blishingHistory ) lease.sourcepac kagename) 0 AS ignore"""), lease.sourcepac kagenameID, blishingHistory .componentID, blishingHistory .sectionID) , blishingHistory .pocket == pocket, blishingHistory .archiveID == archive.id, blishingHistory .distroseriesID == blishingHistory .status. is_in( publishing_ status) , lease.id == blishingHistory .sourcepackager eleaseID, lease.sourcepac kagenameID. is_in( lease.sourcepac kagenameID, agePublishingHi story.datecreat ed), agePublishingHi story.id) ), hook=source_ eager_load) published)
+ store = IStore(
+ already_published = DecoratedResultSet(
+ store.find(
+ (SQL("""DISTINCT ON (
+ SourcePackageRe
+ SourcePackageRe
+ SourcePackagePu
+ SourcePackagePu
+ SourcePackagePu
+ SourcePackagePu
+ SourcePackagePu
+ distroseries.id,
+ SourcePackagePu
+ active_
+ SourcePackageRe
+ SourcePackagePu
+ SourcePackageRe
+ spn.id for spn in spns)).order_by(
+ SourcePackageRe
+ Desc(SourcePack
+ Desc(SourcePack
+ source_resolve_ids, pre_iter_
+ return list(already_
Why not join directly to SourcePackageName, Component and Section? resolve_ ids() and ides() too).
That would save the confusing dance with source_
source_eager_load() (both of which might be better off defined in
findSourceOverr
I tested it to see if I was missing something, but it seems not. The
following definition passes the tests:
def findSourceOverr ides(self, archive, distroseries, pocket, spns): SourcePacka. ..
store = IStore(