Merge lp:~edwin-grubbs/launchpad/bug-535430-needspackaging-timeout-part2 into lp:launchpad/db-devel
- bug-535430-needspackaging-timeout-part2
- Merge into db-devel
Status: | Merged | ||||
---|---|---|---|---|---|
Merged at revision: | 9449 | ||||
Proposed branch: | lp:~edwin-grubbs/launchpad/bug-535430-needspackaging-timeout-part2 | ||||
Merge into: | lp:launchpad/db-devel | ||||
Diff against target: |
636 lines (+296/-94) 12 files modified
database/schema/comments.sql (+5/-1) database/schema/patch-2207-56-0.sql (+24/-0) database/schema/security.cfg (+5/-1) lib/lp/bugs/doc/bug-heat.txt (+14/-0) lib/lp/bugs/interfaces/bugtarget.py (+7/-2) lib/lp/bugs/model/bug.py (+2/-2) lib/lp/bugs/model/bugtarget.py (+8/-12) lib/lp/bugs/model/bugtask.py (+2/-2) lib/lp/bugs/tests/test_bugheat.py (+82/-0) lib/lp/registry/interfaces/distributionsourcepackage.py (+17/-1) lib/lp/registry/model/distributionsourcepackage.py (+125/-71) lib/lp/soyuz/model/publishing.py (+5/-2) |
||||
To merge this branch: | bzr merge lp:~edwin-grubbs/launchpad/bug-535430-needspackaging-timeout-part2 | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Björn Tillenius (community) | db | Abstain | |
Brad Crittenden (community) | code | Approve | |
Review via email: mp+26830@code.launchpad.net |
Commit message
Description of the change
Summary
-------
This branch is a follow-up to
lp:~edwin-grubbs/launchpad/bug-535430-needspackaging-timeout-part2
It adds the attributes to the DistributionSou
DistributionSou
DistributionSou
DistributionSou
classes is deferred, since it is not certain yet whether errors would
occur if a DSP object required a SPPH row to be created first. I added
code to report a silent oops if there is an unexpected creation of a
DSP.
This branch also popuplates total_bug_heat and bug_count columns in the
DistributionSou
po_message_count column will be populated in a later branch.
Implementation details
-------
Allow db users 'lucille', 'uploader', and 'queued' to create a DSP entry
when a SPPH record is created. Allow db user 'processmail' to read the
section table, since that is necessary to check the foreign key on the
DSP table.
database/
Added tests.
lib/
lib/
Automatically insert into DistributionSou
SourcePackagePu
Renamed recalculateMaxB
overrode it in the model's DistributionSou
total_bug_heat and bug_count in addition to max_bug_heat, which it was
already setting.
lib/
lib/
lib/
lib/
lib/
lib/
lib/
Tests
-----
./bin/test -vv -t 'bug-heat.
Edwin Grubbs (edwin-grubbs) wrote : | # |
I assume the changes to database/
I forgot to create this merge proposal with the previous branch as the dependency, so you will see the same schema changes that have already been reviewed.
Björn Tillenius (bjornt) wrote : | # |
Changes to security.cfg don't need a DB review, just make sure they are tested.
Preview Diff
1 | === modified file 'database/schema/comments.sql' | |||
2 | --- database/schema/comments.sql 2010-06-03 22:21:24 +0000 | |||
3 | +++ database/schema/comments.sql 2010-06-10 01:43:25 +0000 | |||
4 | @@ -472,7 +472,11 @@ | |||
5 | 472 | 472 | ||
6 | 473 | COMMENT ON TABLE DistributionSourcePackage IS 'Representing a sourcepackage in a distribution across all distribution series.'; | 473 | COMMENT ON TABLE DistributionSourcePackage IS 'Representing a sourcepackage in a distribution across all distribution series.'; |
7 | 474 | COMMENT ON COLUMN DistributionSourcePackage.bug_reporting_guidelines IS 'Guidelines to the end user for reporting bugs on a particular a source package in a distribution.'; | 474 | COMMENT ON COLUMN DistributionSourcePackage.bug_reporting_guidelines IS 'Guidelines to the end user for reporting bugs on a particular a source package in a distribution.'; |
9 | 475 | COMMENT ON COLUMN DistributionSourcePackage.max_bug_heat IS 'The highest heat value across bugs for this source package.'; | 475 | COMMENT ON COLUMN DistributionSourcePackage.max_bug_heat IS 'The highest heat value across bugs for this source package. NULL means it has not yet been calculated.'; |
10 | 476 | COMMENT ON COLUMN DistributionSourcePackage.total_bug_heat IS 'Sum of bug heat matching the package distribution and sourcepackagename. NULL means it has not yet been calculated.'; | ||
11 | 477 | COMMENT ON COLUMN DistributionSourcePackage.bug_count IS 'Number of bugs matching the package distribution and sourcepackagename. NULL means it has not yet been calculated.'; | ||
12 | 478 | COMMENT ON COLUMN DistributionSourcePackage.po_message_count IS 'Number of translations matching the package distribution and sourcepackagename. NULL means it has not yet been calculated.'; | ||
13 | 479 | COMMENT ON COLUMN DistributionSourcePackage.section IS 'Cached section matching the latest SourcePackagePublishingHistory record by distribution and sourcepackagename whose archive purpose is PRIMARY and whose distroseries releasestatus is CURRENT.'; | ||
14 | 476 | COMMENT ON COLUMN DistributionSourcePackage.bug_reported_acknowledgement IS 'A message of acknowledgement to display to a bug reporter after they\'ve reported a new bug.'; | 480 | COMMENT ON COLUMN DistributionSourcePackage.bug_reported_acknowledgement IS 'A message of acknowledgement to display to a bug reporter after they\'ve reported a new bug.'; |
15 | 477 | 481 | ||
16 | 478 | -- DistributionSourcePackageCache | 482 | -- DistributionSourcePackageCache |
17 | 479 | 483 | ||
18 | === added file 'database/schema/patch-2207-56-0.sql' | |||
19 | --- database/schema/patch-2207-56-0.sql 1970-01-01 00:00:00 +0000 | |||
20 | +++ database/schema/patch-2207-56-0.sql 2010-06-10 01:43:25 +0000 | |||
21 | @@ -0,0 +1,24 @@ | |||
22 | 1 | -- Copyright 2010 Canonical Ltd. This software is licensed under the | ||
23 | 2 | -- GNU Affero General Public License version 3 (see the file LICENSE). | ||
24 | 3 | |||
25 | 4 | SET client_min_messages=ERROR; | ||
26 | 5 | |||
27 | 6 | INSERT INTO LaunchpadDatabaseRevision VALUES (2207, 56, 0); | ||
28 | 7 | |||
29 | 8 | /* | ||
30 | 9 | Existing Schema: | ||
31 | 10 | |||
32 | 11 | CREATE TABLE distributionsourcepackage ( | ||
33 | 12 | id integer NOT NULL, | ||
34 | 13 | distribution integer NOT NULL, | ||
35 | 14 | sourcepackagename integer NOT NULL, | ||
36 | 15 | bug_reporting_guidelines text, | ||
37 | 16 | max_bug_heat integer | ||
38 | 17 | ); | ||
39 | 18 | */ | ||
40 | 19 | |||
41 | 20 | ALTER TABLE DistributionSourcePackage ADD COLUMN total_bug_heat INTEGER; | ||
42 | 21 | ALTER TABLE DistributionSourcePackage ADD COLUMN bug_count INTEGER; | ||
43 | 22 | ALTER TABLE DistributionSourcePackage ADD COLUMN po_message_count INTEGER; | ||
44 | 23 | ALTER TABLE DistributionSourcePackage | ||
45 | 24 | ADD COLUMN section INTEGER NOT NULL REFERENCES section(id); | ||
46 | 0 | 25 | ||
47 | === modified file 'database/schema/security.cfg' | |||
48 | --- database/schema/security.cfg 2010-06-07 10:24:03 +0000 | |||
49 | +++ database/schema/security.cfg 2010-06-10 01:43:25 +0000 | |||
50 | @@ -746,6 +746,7 @@ | |||
51 | 746 | public.binarypackagepublishinghistory = SELECT, INSERT, UPDATE, DELETE | 746 | public.binarypackagepublishinghistory = SELECT, INSERT, UPDATE, DELETE |
52 | 747 | public.sourcepackagepublishinghistory = SELECT, INSERT, UPDATE, DELETE | 747 | public.sourcepackagepublishinghistory = SELECT, INSERT, UPDATE, DELETE |
53 | 748 | public.sourcepackagepublishinghistory = SELECT | 748 | public.sourcepackagepublishinghistory = SELECT |
54 | 749 | public.distributionsourcepackage = SELECT, INSERT, UPDATE | ||
55 | 749 | 750 | ||
56 | 750 | # Closing bugs for publication copies. | 751 | # Closing bugs for publication copies. |
57 | 751 | public.bug = SELECT, UPDATE | 752 | public.bug = SELECT, UPDATE |
58 | @@ -1051,6 +1052,7 @@ | |||
59 | 1051 | public.distroseries = SELECT, UPDATE | 1052 | public.distroseries = SELECT, UPDATE |
60 | 1052 | public.distroarchseries = SELECT | 1053 | public.distroarchseries = SELECT |
61 | 1053 | public.sourcepackagepublishinghistory = SELECT | 1054 | public.sourcepackagepublishinghistory = SELECT |
62 | 1055 | public.distributionsourcepackage = SELECT, INSERT, UPDATE | ||
63 | 1054 | public.sourcepackagefilepublishing = SELECT | 1056 | public.sourcepackagefilepublishing = SELECT |
64 | 1055 | public.binarypackagefilepublishing = SELECT | 1057 | public.binarypackagefilepublishing = SELECT |
65 | 1056 | public.binarypackagepublishinghistory = SELECT | 1058 | public.binarypackagepublishinghistory = SELECT |
66 | @@ -1175,8 +1177,9 @@ | |||
67 | 1175 | public.sourcepackagefilepublishing = SELECT | 1177 | public.sourcepackagefilepublishing = SELECT |
68 | 1176 | public.binarypackagefilepublishing = SELECT | 1178 | public.binarypackagefilepublishing = SELECT |
69 | 1177 | public.sourcepackagepublishinghistory = SELECT, INSERT, UPDATE | 1179 | public.sourcepackagepublishinghistory = SELECT, INSERT, UPDATE |
70 | 1180 | public.distributionsourcepackage = SELECT, INSERT, UPDATE | ||
71 | 1178 | public.binarypackagepublishinghistory = SELECT, INSERT, UPDATE | 1181 | public.binarypackagepublishinghistory = SELECT, INSERT, UPDATE |
73 | 1179 | public.sourcepackagerecipebuildjob = SELECT, INSERT, UPDATE | 1182 | public.sourcepackagerecipebuildjob = SELECT, INSERT, UPDATE |
74 | 1180 | public.component = SELECT | 1183 | public.component = SELECT |
75 | 1181 | public.section = SELECT | 1184 | public.section = SELECT |
76 | 1182 | public.componentselection = SELECT | 1185 | public.componentselection = SELECT |
77 | @@ -1464,6 +1467,7 @@ | |||
78 | 1464 | public.sourcepackagerelease = SELECT | 1467 | public.sourcepackagerelease = SELECT |
79 | 1465 | public.sourcepackagepublishinghistory = SELECT | 1468 | public.sourcepackagepublishinghistory = SELECT |
80 | 1466 | public.structuralsubscription = SELECT | 1469 | public.structuralsubscription = SELECT |
81 | 1470 | public.section = SELECT | ||
82 | 1467 | 1471 | ||
83 | 1468 | # Karma | 1472 | # Karma |
84 | 1469 | public.karma = SELECT, INSERT | 1473 | public.karma = SELECT, INSERT |
85 | 1470 | 1474 | ||
86 | === modified file 'lib/lp/bugs/doc/bug-heat.txt' | |||
87 | --- lib/lp/bugs/doc/bug-heat.txt 2010-05-27 16:40:54 +0000 | |||
88 | +++ lib/lp/bugs/doc/bug-heat.txt 2010-06-10 01:43:25 +0000 | |||
89 | @@ -308,6 +308,20 @@ | |||
90 | 308 | >>> print dsp.max_bug_heat | 308 | >>> print dsp.max_bug_heat |
91 | 309 | 123 | 309 | 123 |
92 | 310 | 310 | ||
93 | 311 | A DistributionSourcePackage also has a cached value for bug_count and | ||
94 | 312 | total_bug_heat. | ||
95 | 313 | |||
96 | 314 | >>> print dsp.bug_count | ||
97 | 315 | 1 | ||
98 | 316 | >>> print dsp.total_bug_heat | ||
99 | 317 | 123 | ||
100 | 318 | >>> dsp_task2 = factory.makeBugTask(target=dsp) | ||
101 | 319 | >>> dsp_task2.bug.setHeat(7) | ||
102 | 320 | >>> print dsp.bug_count | ||
103 | 321 | 2 | ||
104 | 322 | >>> print dsp.total_bug_heat | ||
105 | 323 | 130 | ||
106 | 324 | |||
107 | 311 | Transitioning from one target to another, calculates the value for the new | 325 | Transitioning from one target to another, calculates the value for the new |
108 | 312 | target. | 326 | target. |
109 | 313 | 327 | ||
110 | 314 | 328 | ||
111 | === modified file 'lib/lp/bugs/interfaces/bugtarget.py' | |||
112 | --- lib/lp/bugs/interfaces/bugtarget.py 2010-06-09 08:26:26 +0000 | |||
113 | +++ lib/lp/bugs/interfaces/bugtarget.py 2010-06-10 01:43:25 +0000 | |||
114 | @@ -272,8 +272,13 @@ | |||
115 | 272 | def setMaxBugHeat(heat): | 272 | def setMaxBugHeat(heat): |
116 | 273 | """Set the max_bug_heat for this context.""" | 273 | """Set the max_bug_heat for this context.""" |
117 | 274 | 274 | ||
120 | 275 | def recalculateMaxBugHeat(): | 275 | def recalculateBugHeatCache(): |
121 | 276 | """Recalculate and set the max_bug_heat for this context.""" | 276 | """Recalculate and set the various bug heat values for this context. |
122 | 277 | |||
123 | 278 | Several different objects cache max_bug_heat. | ||
124 | 279 | When DistributionSourcePackage is the target, the total_bug_heat | ||
125 | 280 | and bug_count are also cached. | ||
126 | 281 | """ | ||
127 | 277 | 282 | ||
128 | 278 | 283 | ||
129 | 279 | class BugDistroSeriesTargetDetails: | 284 | class BugDistroSeriesTargetDetails: |
130 | 280 | 285 | ||
131 | === modified file 'lib/lp/bugs/model/bug.py' | |||
132 | --- lib/lp/bugs/model/bug.py 2010-06-04 09:12:26 +0000 | |||
133 | +++ lib/lp/bugs/model/bug.py 2010-06-10 01:43:25 +0000 | |||
134 | @@ -887,7 +887,7 @@ | |||
135 | 887 | 887 | ||
136 | 888 | # When a new task is added the bug's heat becomes relevant to the | 888 | # When a new task is added the bug's heat becomes relevant to the |
137 | 889 | # target's max_bug_heat. | 889 | # target's max_bug_heat. |
139 | 890 | target.recalculateMaxBugHeat() | 890 | target.recalculateBugHeatCache() |
140 | 891 | 891 | ||
141 | 892 | return new_task | 892 | return new_task |
142 | 893 | 893 | ||
143 | @@ -1569,7 +1569,7 @@ | |||
144 | 1569 | self.heat = heat | 1569 | self.heat = heat |
145 | 1570 | self.heat_last_updated = timestamp | 1570 | self.heat_last_updated = timestamp |
146 | 1571 | for task in self.bugtasks: | 1571 | for task in self.bugtasks: |
148 | 1572 | task.target.recalculateMaxBugHeat() | 1572 | task.target.recalculateBugHeatCache() |
149 | 1573 | 1573 | ||
150 | 1574 | def updateHeat(self): | 1574 | def updateHeat(self): |
151 | 1575 | """See `IBug`.""" | 1575 | """See `IBug`.""" |
152 | 1576 | 1576 | ||
153 | === modified file 'lib/lp/bugs/model/bugtarget.py' | |||
154 | --- lib/lp/bugs/model/bugtarget.py 2010-05-21 04:38:42 +0000 | |||
155 | +++ lib/lp/bugs/model/bugtarget.py 2010-06-10 01:43:25 +0000 | |||
156 | @@ -235,12 +235,15 @@ | |||
157 | 235 | else: | 235 | else: |
158 | 236 | raise NotImplementedError | 236 | raise NotImplementedError |
159 | 237 | 237 | ||
162 | 238 | def recalculateMaxBugHeat(self): | 238 | def recalculateBugHeatCache(self): |
163 | 239 | """See `IHasBugHeat`.""" | 239 | """See `IHasBugHeat`. |
164 | 240 | |||
165 | 241 | DistributionSourcePackage overrides this method. | ||
166 | 242 | """ | ||
167 | 240 | if IProductSeries.providedBy(self): | 243 | if IProductSeries.providedBy(self): |
169 | 241 | return self.product.recalculateMaxBugHeat() | 244 | return self.product.recalculateBugHeatCache() |
170 | 242 | if IDistroSeries.providedBy(self): | 245 | if IDistroSeries.providedBy(self): |
172 | 243 | return self.distribution.recalculateMaxBugHeat() | 246 | return self.distribution.recalculateBugHeatCache() |
173 | 244 | if ISourcePackage.providedBy(self): | 247 | if ISourcePackage.providedBy(self): |
174 | 245 | # Should only happen for nominations, so we can safely skip | 248 | # Should only happen for nominations, so we can safely skip |
175 | 246 | # recalculating max_heat. | 249 | # recalculating max_heat. |
176 | @@ -276,13 +279,6 @@ | |||
177 | 276 | WHERE Bugtask.bug = Bug.id AND | 279 | WHERE Bugtask.bug = Bug.id AND |
178 | 277 | Bugtask.product = Product.id AND | 280 | Bugtask.product = Product.id AND |
179 | 278 | Product.project = %s""" % sqlvalues(self)] | 281 | Product.project = %s""" % sqlvalues(self)] |
180 | 279 | elif IDistributionSourcePackage.providedBy(self): | ||
181 | 280 | sql = ["""SELECT MAX(heat) | ||
182 | 281 | FROM Bug, Bugtask | ||
183 | 282 | WHERE Bugtask.bug = Bug.id AND | ||
184 | 283 | Bugtask.distribution = %s AND | ||
185 | 284 | Bugtask.sourcepackagename = %s""" % sqlvalues( | ||
186 | 285 | self.distribution, self.sourcepackagename)] | ||
187 | 286 | else: | 282 | else: |
188 | 287 | raise NotImplementedError | 283 | raise NotImplementedError |
189 | 288 | 284 | ||
190 | @@ -299,7 +295,7 @@ | |||
191 | 299 | # If the product is part of a project group we calculate the maximum | 295 | # If the product is part of a project group we calculate the maximum |
192 | 300 | # heat for the project group too. | 296 | # heat for the project group too. |
193 | 301 | if IProduct.providedBy(self) and self.project is not None: | 297 | if IProduct.providedBy(self) and self.project is not None: |
195 | 302 | self.project.recalculateMaxBugHeat() | 298 | self.project.recalculateBugHeatCache() |
196 | 303 | 299 | ||
197 | 304 | 300 | ||
198 | 305 | 301 | ||
199 | 306 | 302 | ||
200 | === modified file 'lib/lp/bugs/model/bugtask.py' | |||
201 | --- lib/lp/bugs/model/bugtask.py 2010-06-07 18:11:08 +0000 | |||
202 | +++ lib/lp/bugs/model/bugtask.py 2010-06-10 01:43:25 +0000 | |||
203 | @@ -1045,8 +1045,8 @@ | |||
204 | 1045 | # After the target has changed, we need to recalculate the maximum bug | 1045 | # After the target has changed, we need to recalculate the maximum bug |
205 | 1046 | # heat for the new and old targets. | 1046 | # heat for the new and old targets. |
206 | 1047 | if self.target != target_before_change: | 1047 | if self.target != target_before_change: |
209 | 1048 | target_before_change.recalculateMaxBugHeat() | 1048 | target_before_change.recalculateBugHeatCache() |
210 | 1049 | self.target.recalculateMaxBugHeat() | 1049 | self.target.recalculateBugHeatCache() |
211 | 1050 | 1050 | ||
212 | 1051 | def updateTargetNameCache(self, newtarget=None): | 1051 | def updateTargetNameCache(self, newtarget=None): |
213 | 1052 | """See `IBugTask`.""" | 1052 | """See `IBugTask`.""" |
214 | 1053 | 1053 | ||
215 | === modified file 'lib/lp/bugs/tests/test_bugheat.py' | |||
216 | --- lib/lp/bugs/tests/test_bugheat.py 2010-06-01 09:21:32 +0000 | |||
217 | +++ lib/lp/bugs/tests/test_bugheat.py 2010-06-10 01:43:25 +0000 | |||
218 | @@ -7,8 +7,11 @@ | |||
219 | 7 | 7 | ||
220 | 8 | import unittest | 8 | import unittest |
221 | 9 | 9 | ||
222 | 10 | from storm.store import Store | ||
223 | 11 | |||
224 | 10 | from canonical.testing import LaunchpadZopelessLayer | 12 | from canonical.testing import LaunchpadZopelessLayer |
225 | 11 | 13 | ||
226 | 14 | from lp.testing import TestCaseWithFactory | ||
227 | 12 | from lp.testing.factory import LaunchpadObjectFactory | 15 | from lp.testing.factory import LaunchpadObjectFactory |
228 | 13 | 16 | ||
229 | 14 | 17 | ||
230 | @@ -58,6 +61,85 @@ | |||
231 | 58 | def setUp(self): | 61 | def setUp(self): |
232 | 59 | self.target = self.factory.makeDistributionSourcePackage() | 62 | self.target = self.factory.makeDistributionSourcePackage() |
233 | 60 | 63 | ||
234 | 64 | class DistributionSourcePackageNullBugHeatCacheTest( | ||
235 | 65 | TestCaseWithFactory): | ||
236 | 66 | """Ensure distro source package cache values start at None.""" | ||
237 | 67 | |||
238 | 68 | layer = LaunchpadZopelessLayer | ||
239 | 69 | |||
240 | 70 | def setUp(self): | ||
241 | 71 | TestCaseWithFactory.setUp(self) | ||
242 | 72 | self.target = self.factory.makeDistributionSourcePackage() | ||
243 | 73 | |||
244 | 74 | def test_null_max_bug_heat(self): | ||
245 | 75 | self.assertEqual(None, self.target.max_bug_heat) | ||
246 | 76 | |||
247 | 77 | def test_null_total_bug_heat(self): | ||
248 | 78 | self.assertEqual(None, self.target.total_bug_heat) | ||
249 | 79 | |||
250 | 80 | def test_null_bug_count(self): | ||
251 | 81 | self.assertEqual(None, self.target.bug_count) | ||
252 | 82 | |||
253 | 83 | |||
254 | 84 | class DistributionSourcePackageZeroRecalculateBugHeatCacheTest( | ||
255 | 85 | TestCaseWithFactory): | ||
256 | 86 | """Ensure distro source package cache values become zero properly.""" | ||
257 | 87 | |||
258 | 88 | layer = LaunchpadZopelessLayer | ||
259 | 89 | |||
260 | 90 | def setUp(self): | ||
261 | 91 | TestCaseWithFactory.setUp(self) | ||
262 | 92 | self.target = self.factory.makeDistributionSourcePackage() | ||
263 | 93 | self.target.recalculateBugHeatCache() | ||
264 | 94 | |||
265 | 95 | def test_zero_max_bug_heat(self): | ||
266 | 96 | self.assertEqual(0, self.target.max_bug_heat) | ||
267 | 97 | |||
268 | 98 | def test_zero_total_bug_heat(self): | ||
269 | 99 | self.assertEqual(0, self.target.total_bug_heat) | ||
270 | 100 | |||
271 | 101 | def test_zero_bug_count(self): | ||
272 | 102 | self.assertEqual(0, self.target.bug_count) | ||
273 | 103 | |||
274 | 104 | |||
275 | 105 | class DistributionSourcePackageMultipleBugsRecalculateBugHeatCacheTest( | ||
276 | 106 | TestCaseWithFactory): | ||
277 | 107 | """Ensure distro source package cache values are set properly.""" | ||
278 | 108 | |||
279 | 109 | layer = LaunchpadZopelessLayer | ||
280 | 110 | |||
281 | 111 | def setUp(self): | ||
282 | 112 | TestCaseWithFactory.setUp(self) | ||
283 | 113 | self.target = self.factory.makeDistributionSourcePackage() | ||
284 | 114 | self.bugtask1 = self.factory.makeBugTask(target=self.target) | ||
285 | 115 | self.bugtask2 = self.factory.makeBugTask(target=self.target) | ||
286 | 116 | # Bug heat gets calculated by complicated rules in a db | ||
287 | 117 | # stored procedure. We will override them here to avoid | ||
288 | 118 | # testing inconsitencies if those values are calculated | ||
289 | 119 | # differently in the future. | ||
290 | 120 | # target.recalculateBugHeatCache() should be called | ||
291 | 121 | # automatically by bug.setHeat(). | ||
292 | 122 | bug1 = self.bugtask1.bug | ||
293 | 123 | bug2 = self.bugtask2.bug | ||
294 | 124 | bug1.setHeat(7) | ||
295 | 125 | bug2.setHeat(19) | ||
296 | 126 | Store.of(bug1).flush() | ||
297 | 127 | self.max_heat = max(bug1.heat, bug2.heat) | ||
298 | 128 | self.total_heat = sum([bug1.heat, bug2.heat]) | ||
299 | 129 | |||
300 | 130 | def test_max_bug_heat(self): | ||
301 | 131 | self.assertEqual(self.max_heat, self.target.max_bug_heat) | ||
302 | 132 | |||
303 | 133 | def test_total_bug_heat(self): | ||
304 | 134 | self.assertEqual(self.total_heat, self.target.total_bug_heat) | ||
305 | 135 | self.failUnless( | ||
306 | 136 | self.target.total_bug_heat > self.target.max_bug_heat, | ||
307 | 137 | "Total bug heat should be more than the max bug heat, " | ||
308 | 138 | "since we know that multiple bugs have nonzero heat.") | ||
309 | 139 | |||
310 | 140 | def test_bug_count(self): | ||
311 | 141 | self.assertEqual(2, self.target.bug_count) | ||
312 | 142 | |||
313 | 61 | 143 | ||
314 | 62 | class SourcePackageMaxHeatByTargetTest( | 144 | class SourcePackageMaxHeatByTargetTest( |
315 | 63 | MaxHeatByTargetBase, unittest.TestCase): | 145 | MaxHeatByTargetBase, unittest.TestCase): |
316 | 64 | 146 | ||
317 | === modified file 'lib/lp/registry/interfaces/distributionsourcepackage.py' | |||
318 | --- lib/lp/registry/interfaces/distributionsourcepackage.py 2010-02-12 13:39:56 +0000 | |||
319 | +++ lib/lp/registry/interfaces/distributionsourcepackage.py 2010-06-10 01:43:25 +0000 | |||
320 | @@ -78,9 +78,25 @@ | |||
321 | 78 | "no such package -- this occurs when there is no current series for " | 78 | "no such package -- this occurs when there is no current series for " |
322 | 79 | "the distribution.") | 79 | "the distribution.") |
323 | 80 | 80 | ||
324 | 81 | total_bug_heat = Attribute( | ||
325 | 82 | "Sum of the bug heat for all the bugs matching the distribution " | ||
326 | 83 | "and sourcepackagename of the IDistributionSourcePackage.") | ||
327 | 84 | |||
328 | 85 | max_bug_heat = Attribute( | ||
329 | 86 | "Maximum bug heat for a single bug matching the distribution " | ||
330 | 87 | "and sourcepackagename of the IDistributionSourcePackage.") | ||
331 | 88 | |||
332 | 89 | bug_count = Attribute( | ||
333 | 90 | "Number of bugs matching the distribution and sourcepackagename " | ||
334 | 91 | "of the IDistributionSourcePackage.") | ||
335 | 92 | |||
336 | 93 | po_message_count = Attribute( | ||
337 | 94 | "Number of translations matching the distribution and " | ||
338 | 95 | "sourcepackagename of the IDistributionSourcePackage.") | ||
339 | 96 | |||
340 | 81 | def getReleasesAndPublishingHistory(): | 97 | def getReleasesAndPublishingHistory(): |
341 | 82 | """Return a list of all releases of this source package in this | 98 | """Return a list of all releases of this source package in this |
343 | 83 | distribution and their correspodning publishing history. | 99 | distribution and their corresponding publishing history. |
344 | 84 | 100 | ||
345 | 85 | Items in the list are tuples comprised of a | 101 | Items in the list are tuples comprised of a |
346 | 86 | DistributionSourcePackage and a list of | 102 | DistributionSourcePackage and a list of |
347 | 87 | 103 | ||
348 | === modified file 'lib/lp/registry/model/distributionsourcepackage.py' | |||
349 | --- lib/lp/registry/model/distributionsourcepackage.py 2010-06-08 13:07:44 +0000 | |||
350 | +++ lib/lp/registry/model/distributionsourcepackage.py 2010-06-10 01:43:25 +0000 | |||
351 | @@ -15,13 +15,17 @@ | |||
352 | 15 | import operator | 15 | import operator |
353 | 16 | 16 | ||
354 | 17 | from sqlobject.sqlbuilder import SQLConstant | 17 | from sqlobject.sqlbuilder import SQLConstant |
356 | 18 | from storm.expr import And, Desc, In, Join, Lower | 18 | from storm.expr import And, Count, Desc, In, Join, Lower, Max, Sum |
357 | 19 | from storm.store import EmptyResultSet | 19 | from storm.store import EmptyResultSet |
358 | 20 | from storm.locals import Int, Reference, Store, Storm, Unicode | 20 | from storm.locals import Int, Reference, Store, Storm, Unicode |
359 | 21 | from zope.component import getUtility | ||
360 | 22 | from zope.error.interfaces import IErrorReportingUtility | ||
361 | 21 | from zope.interface import implements | 23 | from zope.interface import implements |
362 | 22 | 24 | ||
363 | 25 | |||
364 | 23 | from canonical.database.sqlbase import sqlvalues | 26 | from canonical.database.sqlbase import sqlvalues |
365 | 24 | from canonical.launchpad.database.emailaddress import EmailAddress | 27 | from canonical.launchpad.database.emailaddress import EmailAddress |
366 | 28 | from lp.registry.interfaces.series import SeriesStatus | ||
367 | 25 | from lp.registry.model.distroseries import DistroSeries | 29 | from lp.registry.model.distroseries import DistroSeries |
368 | 26 | from lp.registry.model.packaging import Packaging | 30 | from lp.registry.model.packaging import Packaging |
369 | 27 | from lp.registry.model.structuralsubscription import ( | 31 | from lp.registry.model.structuralsubscription import ( |
370 | @@ -30,7 +34,7 @@ | |||
371 | 30 | from canonical.lazr.utils import smartquote | 34 | from canonical.lazr.utils import smartquote |
372 | 31 | from lp.answers.interfaces.questiontarget import IQuestionTarget | 35 | from lp.answers.interfaces.questiontarget import IQuestionTarget |
373 | 32 | from lp.bugs.interfaces.bugtarget import IHasBugHeat | 36 | from lp.bugs.interfaces.bugtarget import IHasBugHeat |
375 | 33 | from lp.bugs.model.bug import BugSet, get_bug_tags_open_count | 37 | from lp.bugs.model.bug import Bug, BugSet, get_bug_tags_open_count |
376 | 34 | from lp.bugs.model.bugtarget import BugTargetBase, HasBugHeatMixin | 38 | from lp.bugs.model.bugtarget import BugTargetBase, HasBugHeatMixin |
377 | 35 | from lp.bugs.model.bugtask import BugTask | 39 | from lp.bugs.model.bugtask import BugTask |
378 | 36 | from lp.code.model.hasbranches import HasBranchesMixin, HasMergeProposalsMixin | 40 | from lp.code.model.hasbranches import HasBranchesMixin, HasMergeProposalsMixin |
379 | @@ -43,6 +47,7 @@ | |||
380 | 43 | SourcePackage, SourcePackageQuestionTargetMixin) | 47 | SourcePackage, SourcePackageQuestionTargetMixin) |
381 | 44 | from lp.soyuz.interfaces.archive import ArchivePurpose | 48 | from lp.soyuz.interfaces.archive import ArchivePurpose |
382 | 45 | from lp.soyuz.interfaces.publishing import PackagePublishingStatus | 49 | from lp.soyuz.interfaces.publishing import PackagePublishingStatus |
383 | 50 | from lp.soyuz.interfaces.section import ISectionSet | ||
384 | 46 | from lp.soyuz.model.archive import Archive | 51 | from lp.soyuz.model.archive import Archive |
385 | 47 | from lp.soyuz.model.distributionsourcepackagerelease import ( | 52 | from lp.soyuz.model.distributionsourcepackagerelease import ( |
386 | 48 | DistributionSourcePackageRelease) | 53 | DistributionSourcePackageRelease) |
387 | @@ -54,6 +59,40 @@ | |||
388 | 54 | CustomLanguageCode, HasCustomLanguageCodesMixin) | 59 | CustomLanguageCode, HasCustomLanguageCodesMixin) |
389 | 55 | 60 | ||
390 | 56 | 61 | ||
391 | 62 | class DistributionSourcePackageProperty: | ||
392 | 63 | def __init__(self, attrname): | ||
393 | 64 | self.attrname = attrname | ||
394 | 65 | |||
395 | 66 | def __get__(self, obj, class_): | ||
396 | 67 | return getattr(obj._self_in_database, self.attrname, None) | ||
397 | 68 | |||
398 | 69 | def __set__(self, obj, value): | ||
399 | 70 | if obj._self_in_database is None: | ||
400 | 71 | # Log an oops without raising an error. | ||
401 | 72 | exception = AssertionError( | ||
402 | 73 | "DistributionSourcePackage record should have been created " | ||
403 | 74 | "earlier in the database for distro=%s, sourcepackagename=%s" | ||
404 | 75 | % (obj.distribution.name, obj.sourcepackagename.name)) | ||
405 | 76 | getUtility(IErrorReportingUtility).raising( | ||
406 | 77 | (exception.__class__, exception, None)) | ||
407 | 78 | spph = Store.of(obj.distribution).find( | ||
408 | 79 | SourcePackagePublishingHistory, | ||
409 | 80 | SourcePackagePublishingHistory.distroseriesID == | ||
410 | 81 | DistroSeries.id, | ||
411 | 82 | DistroSeries.distributionID == obj.distribution.id, | ||
412 | 83 | SourcePackagePublishingHistory.sourcepackagereleaseID == | ||
413 | 84 | SourcePackageRelease.id, | ||
414 | 85 | SourcePackageRelease.sourcepackagenameID == | ||
415 | 86 | obj.sourcepackagename.id | ||
416 | 87 | ).order_by(Desc(SourcePackagePublishingHistory.id)).first() | ||
417 | 88 | if spph is None: | ||
418 | 89 | section = getUtility(ISectionSet)['misc'] | ||
419 | 90 | else: | ||
420 | 91 | section = spph.section | ||
421 | 92 | obj._new(obj.distribution, obj.sourcepackagename, section) | ||
422 | 93 | setattr(obj._self_in_database, self.attrname, value) | ||
423 | 94 | |||
424 | 95 | |||
425 | 57 | class DistributionSourcePackage(BugTargetBase, | 96 | class DistributionSourcePackage(BugTargetBase, |
426 | 58 | SourcePackageQuestionTargetMixin, | 97 | SourcePackageQuestionTargetMixin, |
427 | 59 | StructuralSubscriptionTargetMixin, | 98 | StructuralSubscriptionTargetMixin, |
428 | @@ -72,6 +111,16 @@ | |||
429 | 72 | IDistributionSourcePackage, IHasBugHeat, IHasCustomLanguageCodes, | 111 | IDistributionSourcePackage, IHasBugHeat, IHasCustomLanguageCodes, |
430 | 73 | IQuestionTarget) | 112 | IQuestionTarget) |
431 | 74 | 113 | ||
432 | 114 | bug_reporting_guidelines = DistributionSourcePackageProperty( | ||
433 | 115 | 'bug_reporting_guidelines') | ||
434 | 116 | bug_reported_acknowledgement = DistributionSourcePackageProperty( | ||
435 | 117 | 'bug_reported_acknowledgement') | ||
436 | 118 | max_bug_heat = DistributionSourcePackageProperty('max_bug_heat') | ||
437 | 119 | total_bug_heat = DistributionSourcePackageProperty('total_bug_heat') | ||
438 | 120 | bug_count = DistributionSourcePackageProperty('bug_count') | ||
439 | 121 | po_message_count = DistributionSourcePackageProperty('po_message_count') | ||
440 | 122 | section = DistributionSourcePackageProperty('section') | ||
441 | 123 | |||
442 | 75 | def __init__(self, distribution, sourcepackagename): | 124 | def __init__(self, distribution, sourcepackagename): |
443 | 76 | self.distribution = distribution | 125 | self.distribution = distribution |
444 | 77 | self.sourcepackagename = sourcepackagename | 126 | self.sourcepackagename = sourcepackagename |
445 | @@ -118,75 +167,34 @@ | |||
446 | 118 | # measure while DistributionSourcePackage is not yet hooked | 167 | # measure while DistributionSourcePackage is not yet hooked |
447 | 119 | # into the database but we need access to some of the fields | 168 | # into the database but we need access to some of the fields |
448 | 120 | # in the database. | 169 | # in the database. |
518 | 121 | return Store.of(self.distribution).find( | 170 | return self._get(self.distribution, self.sourcepackagename) |
519 | 122 | DistributionSourcePackageInDatabase, | 171 | |
520 | 123 | DistributionSourcePackageInDatabase.sourcepackagename == ( | 172 | def recalculateBugHeatCache(self): |
521 | 124 | self.sourcepackagename), | 173 | """See `IHasBugHeat`.""" |
522 | 125 | DistributionSourcePackageInDatabase.distribution == ( | 174 | self.max_bug_heat = IStore(Bug).find( |
523 | 126 | self.distribution) | 175 | Max(Bug.heat), |
524 | 127 | ).one() | 176 | BugTask.bug == Bug.id, |
525 | 128 | 177 | BugTask.distributionID == self.distribution.id, | |
526 | 129 | def _get_bug_reporting_guidelines(self): | 178 | BugTask.sourcepackagenameID == self.sourcepackagename.id).one() |
527 | 130 | """See `IBugTarget`.""" | 179 | if self.max_bug_heat is None: |
528 | 131 | dsp_in_db = self._self_in_database | 180 | # SELECT MAX(Bug.heat) returns NULL if zero rows match. |
529 | 132 | if dsp_in_db is not None: | 181 | self.max_bug_heat = 0 |
530 | 133 | return dsp_in_db.bug_reporting_guidelines | 182 | |
531 | 134 | return None | 183 | self.total_bug_heat = IStore(Bug).find( |
532 | 135 | 184 | Sum(Bug.heat), | |
533 | 136 | def _set_bug_reporting_guidelines(self, value): | 185 | BugTask.bug == Bug.id, |
534 | 137 | """See `IBugTarget`.""" | 186 | BugTask.distributionID == self.distribution.id, |
535 | 138 | dsp_in_db = self._self_in_database | 187 | BugTask.sourcepackagenameID == self.sourcepackagename.id).one() |
536 | 139 | if dsp_in_db is None: | 188 | if self.total_bug_heat is None: |
537 | 140 | dsp_in_db = DistributionSourcePackageInDatabase() | 189 | self.total_bug_heat = 0 |
538 | 141 | dsp_in_db.sourcepackagename = self.sourcepackagename | 190 | |
539 | 142 | dsp_in_db.distribution = self.distribution | 191 | self.bug_count = IStore(Bug).find( |
540 | 143 | Store.of(self.distribution).add(dsp_in_db) | 192 | Count(Bug.heat), |
541 | 144 | dsp_in_db.bug_reporting_guidelines = value | 193 | BugTask.bug == Bug.id, |
542 | 145 | 194 | BugTask.distributionID == self.distribution.id, | |
543 | 146 | bug_reporting_guidelines = property( | 195 | BugTask.sourcepackagenameID == self.sourcepackagename.id).one() |
544 | 147 | _get_bug_reporting_guidelines, | 196 | if self.bug_count is None: |
545 | 148 | _set_bug_reporting_guidelines) | 197 | self.bug_count = 0 |
477 | 149 | |||
478 | 150 | def _get_bug_reported_acknowledgement(self): | ||
479 | 151 | """See `IBugTarget`.""" | ||
480 | 152 | dsp_in_db = self._self_in_database | ||
481 | 153 | if dsp_in_db is not None: | ||
482 | 154 | return dsp_in_db.bug_reported_acknowledgement | ||
483 | 155 | return None | ||
484 | 156 | |||
485 | 157 | def _set_bug_reported_acknowledgement(self, value): | ||
486 | 158 | """See `IBugTarget`.""" | ||
487 | 159 | dsp_in_db = self._self_in_database | ||
488 | 160 | if dsp_in_db is None: | ||
489 | 161 | dsp_in_db = DistributionSourcePackageInDatabase() | ||
490 | 162 | dsp_in_db.sourcepackagename = self.sourcepackagename | ||
491 | 163 | dsp_in_db.distribution = self.distribution | ||
492 | 164 | Store.of(self.distribution).add(dsp_in_db) | ||
493 | 165 | dsp_in_db.bug_reported_acknowledgement = value | ||
494 | 166 | |||
495 | 167 | bug_reported_acknowledgement = property( | ||
496 | 168 | _get_bug_reported_acknowledgement, | ||
497 | 169 | _set_bug_reported_acknowledgement) | ||
498 | 170 | |||
499 | 171 | def _get_max_bug_heat(self): | ||
500 | 172 | """See `IHasBugs`.""" | ||
501 | 173 | dsp_in_db = self._self_in_database | ||
502 | 174 | if dsp_in_db is None: | ||
503 | 175 | return None | ||
504 | 176 | else: | ||
505 | 177 | return dsp_in_db.max_bug_heat | ||
506 | 178 | |||
507 | 179 | def _set_max_bug_heat(self, value): | ||
508 | 180 | """See `IHasBugs`.""" | ||
509 | 181 | dsp_in_db = self._self_in_database | ||
510 | 182 | if dsp_in_db is None: | ||
511 | 183 | dsp_in_db = DistributionSourcePackageInDatabase() | ||
512 | 184 | dsp_in_db.sourcepackagename = self.sourcepackagename | ||
513 | 185 | dsp_in_db.distribution = self.distribution | ||
514 | 186 | Store.of(self.distribution).add(dsp_in_db) | ||
515 | 187 | dsp_in_db.max_bug_heat = value | ||
516 | 188 | |||
517 | 189 | max_bug_heat = property(_get_max_bug_heat, _set_max_bug_heat) | ||
546 | 190 | 198 | ||
547 | 191 | @property | 199 | @property |
548 | 192 | def latest_overall_publication(self): | 200 | def latest_overall_publication(self): |
549 | @@ -504,6 +512,47 @@ | |||
550 | 504 | In(Lower(EmailAddress.email), email_addresses)) | 512 | In(Lower(EmailAddress.email), email_addresses)) |
551 | 505 | return result_set | 513 | return result_set |
552 | 506 | 514 | ||
553 | 515 | @classmethod | ||
554 | 516 | def _get(cls, distribution, sourcepackagename): | ||
555 | 517 | return Store.of(distribution).find( | ||
556 | 518 | DistributionSourcePackageInDatabase, | ||
557 | 519 | DistributionSourcePackageInDatabase.sourcepackagename == | ||
558 | 520 | sourcepackagename, | ||
559 | 521 | DistributionSourcePackageInDatabase.distribution == | ||
560 | 522 | distribution | ||
561 | 523 | ).one() | ||
562 | 524 | |||
563 | 525 | @classmethod | ||
564 | 526 | def _new(cls, distribution, sourcepackagename, section): | ||
565 | 527 | dsp = DistributionSourcePackageInDatabase() | ||
566 | 528 | dsp.distribution = distribution | ||
567 | 529 | dsp.sourcepackagename = sourcepackagename | ||
568 | 530 | dsp.section = section | ||
569 | 531 | Store.of(distribution).add(dsp) | ||
570 | 532 | return dsp | ||
571 | 533 | |||
572 | 534 | @classmethod | ||
573 | 535 | def ensure(cls, spph): | ||
574 | 536 | """Create DistributionSourcePackage record, if necessary. | ||
575 | 537 | |||
576 | 538 | Only create a record for primary archives (i.e. not for PPAs). | ||
577 | 539 | If it already exists, update the section attribute. | ||
578 | 540 | """ | ||
579 | 541 | # Import here to avoid import loop. | ||
580 | 542 | sourcepackagename = spph.sourcepackagerelease.sourcepackagename | ||
581 | 543 | distribution = spph.distroseries.distribution | ||
582 | 544 | section = spph.section | ||
583 | 545 | |||
584 | 546 | if spph.archive.purpose == ArchivePurpose.PRIMARY: | ||
585 | 547 | dsp = cls._get(distribution, sourcepackagename) | ||
586 | 548 | if dsp is None: | ||
587 | 549 | dsp = cls._new(distribution, sourcepackagename, section) | ||
588 | 550 | elif spph.distroseries.status == SeriesStatus.CURRENT: | ||
589 | 551 | # If the distroseries.status is not CURRENT, it should | ||
590 | 552 | # not override the section from a previously created | ||
591 | 553 | # SourcePackagePublishingHistory. | ||
592 | 554 | dsp.section = section | ||
593 | 555 | |||
594 | 507 | 556 | ||
595 | 508 | class DistributionSourcePackageInDatabase(Storm): | 557 | class DistributionSourcePackageInDatabase(Storm): |
596 | 509 | """Temporary class to allow access to the database.""" | 558 | """Temporary class to allow access to the database.""" |
597 | @@ -529,4 +578,9 @@ | |||
598 | 529 | bug_reported_acknowledgement = Unicode() | 578 | bug_reported_acknowledgement = Unicode() |
599 | 530 | 579 | ||
600 | 531 | max_bug_heat = Int() | 580 | max_bug_heat = Int() |
601 | 581 | total_bug_heat = Int() | ||
602 | 582 | bug_count = Int() | ||
603 | 583 | po_message_count = Int() | ||
604 | 532 | 584 | ||
605 | 585 | section_id = Int(name='section') | ||
606 | 586 | section = Reference(section_id, 'Section.id') | ||
607 | 533 | 587 | ||
608 | === modified file 'lib/lp/soyuz/model/publishing.py' | |||
609 | --- lib/lp/soyuz/model/publishing.py 2010-05-21 12:25:51 +0000 | |||
610 | +++ lib/lp/soyuz/model/publishing.py 2010-06-10 01:43:25 +0000 | |||
611 | @@ -49,12 +49,12 @@ | |||
612 | 49 | from lp.soyuz.model.binarypackagename import BinaryPackageName | 49 | from lp.soyuz.model.binarypackagename import BinaryPackageName |
613 | 50 | from lp.soyuz.model.binarypackagerelease import (BinaryPackageRelease, | 50 | from lp.soyuz.model.binarypackagerelease import (BinaryPackageRelease, |
614 | 51 | BinaryPackageReleaseDownloadCount) | 51 | BinaryPackageReleaseDownloadCount) |
615 | 52 | from lp.soyuz.interfaces.archive import ArchivePurpose | ||
616 | 52 | from lp.soyuz.model.files import ( | 53 | from lp.soyuz.model.files import ( |
617 | 53 | BinaryPackageFile, SourcePackageReleaseFile) | 54 | BinaryPackageFile, SourcePackageReleaseFile) |
618 | 54 | from canonical.launchpad.database.librarian import ( | 55 | from canonical.launchpad.database.librarian import ( |
619 | 55 | LibraryFileAlias, LibraryFileContent) | 56 | LibraryFileAlias, LibraryFileContent) |
620 | 56 | from lp.soyuz.model.packagediff import PackageDiff | 57 | from lp.soyuz.model.packagediff import PackageDiff |
621 | 57 | from lp.soyuz.interfaces.archive import ArchivePurpose | ||
622 | 58 | from lp.soyuz.interfaces.archivearch import IArchiveArchSet | 58 | from lp.soyuz.interfaces.archivearch import IArchiveArchSet |
623 | 59 | from lp.soyuz.interfaces.binarypackagebuild import ( | 59 | from lp.soyuz.interfaces.binarypackagebuild import ( |
624 | 60 | BuildSetStatus, IBinaryPackageBuildSet) | 60 | BuildSetStatus, IBinaryPackageBuildSet) |
625 | @@ -1162,7 +1162,10 @@ | |||
626 | 1162 | section=section, | 1162 | section=section, |
627 | 1163 | status=PackagePublishingStatus.PENDING, | 1163 | status=PackagePublishingStatus.PENDING, |
628 | 1164 | datecreated=UTC_NOW) | 1164 | datecreated=UTC_NOW) |
630 | 1165 | 1165 | # Import here to prevent import loop. | |
631 | 1166 | from lp.registry.model.distributionsourcepackage import ( | ||
632 | 1167 | DistributionSourcePackage) | ||
633 | 1168 | DistributionSourcePackage.ensure(pub) | ||
634 | 1166 | return pub | 1169 | return pub |
635 | 1167 | 1170 | ||
636 | 1168 | def getBuildsForSourceIds( | 1171 | def getBuildsForSourceIds( |
Hi Edwin,
This change looks great. I marked a couple of niggly bits but that's
all.
--bac
> === added file 'database/ schema/ patch-2207- 56-0.sql' schema/ patch-2207- 56-0.sql 1970-01-01 00:00:00 +0000 schema/ patch-2207- 56-0.sql 2010-06-04 18:48:29 +0000
> --- database/
> +++ database/
> @@ -0,0 +1,24 @@
> +-- Copyright 2009 Canonical Ltd. This software is licensed under the
2010
(The contents of the patch are left for a db review.)
> === modified file 'lib/lp/ bugs/tests/ test_bugheat. py' bugs/tests/ test_bugheat. py 2010-06-01 09:21:32 +0000 bugs/tests/ test_bugheat. py 2010-06-04 18:48:29 +0000
> --- lib/lp/
> +++ lib/lp/
> @@ -7,8 +7,11 @@
Edwin this test is really readable and easy to follow. Good job.
> import unittest ssLayer Factory makeDistributio nSourcePackage( ) rcePackageNullB ugHeatCacheTest ( tory): ssLayer tory.setUp( self) makeDistributio nSourcePackage( ) max_bug_ heat(self) : l(None, self.target. max_bug_ heat) total_bug_ heat(self) : l(None, self.target. total_bug_ heat) bug_count( self): l(None, self.target. bug_count) rcePackageZeroR ecalculateBugHe atCacheTest( tory): ssLayer tory.setUp( self) makeDistributio nSourcePackage( ) recalculateBugH eatCache( ) max_bug_ heat(self) : max_bug_ heat) total_bug_ heat(self) : total_bug_ heat) bug_count( self): bug_count) rcePackageMulti pleBugsRecalcul ateBugHeatCache Test( tory): ssLayer tory.setUp( self) makeDistributio nSourcePackage( ) makeBugTask( target= self.target) makeBugTask( target= self.target)
>
> +from storm.store import Store
> +
> from canonical.testing import LaunchpadZopele
>
> +from lp.testing import TestCaseWithFactory
> from lp.testing.factory import LaunchpadObject
>
>
> @@ -58,6 +61,85 @@
> def setUp(self):
> self.target = self.factory.
>
> +class DistributionSou
> + TestCaseWithFac
> + """Ensure distro source package cache values start at None."""
> +
> + layer = LaunchpadZopele
> +
> + def setUp(self):
> + TestCaseWithFac
> + self.target = self.factory.
> +
> + def test_null_
> + self.assertEqua
> +
> + def test_null_
> + self.assertEqua
> +
> + def test_null_
> + self.assertEqua
> +
> +
> +class DistributionSou
> + TestCaseWithFac
> + """Ensure distro source package cache values become zero properly."""
> +
> + layer = LaunchpadZopele
> +
> + def setUp(self):
> + TestCaseWithFac
> + self.target = self.factory.
> + self.target.
> +
> + def test_zero_
> + self.assertEqual(0, self.target.
> +
> + def test_zero_
> + self.assertEqual(0, self.target.
> +
> + def test_zero_
> + self.assertEqual(0, self.target.
> +
> +
> +class DistributionSou
> + TestCaseWithFac
> + """Ensure distro source package cache values are set properly."""
> +
> + layer = LaunchpadZopele
> +
> + def setUp(self):
> + TestCaseWithFac
> + self.target = self.factory.
> + self.bugtask1 = self.factory.
> + self.bugtask2 = self.factory.
> + # Bug heat gets calculated by complicated rules in a db
> + # stored procedure. We will override them here to avoid
> + # testing inconsitencies if those values are calculated
> + # differently in the future.
> + #...