Merge lp:~gmb/launchpad/remove-calculatebugheatjob-bug-588186 into lp:launchpad/db-devel

Proposed by Graham Binns
Status: Merged
Approved by: Graham Binns
Approved revision: no longer in the source branch.
Merged at revision: 9421
Proposed branch: lp:~gmb/launchpad/remove-calculatebugheatjob-bug-588186
Merge into: lp:launchpad/db-devel
Diff against target: 670 lines (+2/-578)
9 files modified
cronscripts/calculate-bug-heat.py (+0/-33)
lib/canonical/launchpad/scripts/garbo.py (+0/-1)
lib/lp/bugs/configure.zcml (+0/-12)
lib/lp/bugs/interfaces/bugjob.py (+1/-11)
lib/lp/bugs/model/bug.py (+0/-1)
lib/lp/bugs/model/bugheat.py (+0/-54)
lib/lp/bugs/scripts/bugheat.py (+0/-108)
lib/lp/bugs/scripts/tests/test_bugheat.py (+0/-256)
lib/lp/bugs/tests/test_bugheat.py (+1/-102)
To merge this branch: bzr merge lp:~gmb/launchpad/remove-calculatebugheatjob-bug-588186
Reviewer Review Type Date Requested Status
Michael Nelson (community) Approve
Jelmer Vernooij (community) code* Approve
Review via email: mp+26684@code.launchpad.net

Commit message

All CalculateBugHeatJob code has been removed since it is not longer used.

Description of the change

This branch removes all the CalculateBugHeatJob code since we no longer use it (bug heat calculation is now done by a stored procedure in the database).

To post a comment you must log in.
Revision history for this message
Jelmer Vernooij (jelmer) :
review: Approve (code*)
Revision history for this message
Michael Nelson (michael.nelson) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== removed file 'cronscripts/calculate-bug-heat.py'
2--- cronscripts/calculate-bug-heat.py 2010-04-22 17:30:35 +0000
3+++ cronscripts/calculate-bug-heat.py 1970-01-01 00:00:00 +0000
4@@ -1,33 +0,0 @@
5-#!/usr/bin/python2.5 -S
6-#
7-# Copyright 2010 Canonical Ltd. This software is licensed under the
8-# GNU Affero General Public License version 3 (see the file LICENSE).
9-
10-# pylint: disable-msg=W0403
11-
12-"""Calculate bug heat."""
13-
14-__metaclass__ = type
15-
16-import _pythonpath
17-
18-from canonical.launchpad.webapp import errorlog
19-
20-from lp.services.job.runner import JobCronScript
21-from lp.bugs.interfaces.bugjob import ICalculateBugHeatJobSource
22-
23-
24-class RunCalculateBugHeat(JobCronScript):
25- """Run BranchScanJob jobs."""
26-
27- config_name = 'calculate_bug_heat'
28- source_interface = ICalculateBugHeatJobSource
29-
30- def main(self):
31- errorlog.globalErrorUtility.configure(self.config_name)
32- return super(RunCalculateBugHeat, self).main()
33-
34-
35-if __name__ == '__main__':
36- script = RunCalculateBugHeat()
37- script.lock_and_run()
38
39=== modified file 'lib/canonical/launchpad/scripts/garbo.py'
40--- lib/canonical/launchpad/scripts/garbo.py 2010-05-27 16:49:09 +0000
41+++ lib/canonical/launchpad/scripts/garbo.py 2010-06-03 10:55:38 +0000
42@@ -33,7 +33,6 @@
43 from lp.bugs.interfaces.bug import IBugSet
44 from lp.bugs.model.bug import Bug
45 from lp.bugs.model.bugattachment import BugAttachment
46-from lp.bugs.interfaces.bugjob import ICalculateBugHeatJobSource
47 from lp.bugs.model.bugnotification import BugNotification
48 from lp.bugs.model.bugwatch import BugWatch
49 from lp.bugs.scripts.checkwatches.scheduler import (
50
51=== modified file 'lib/lp/bugs/configure.zcml'
52--- lib/lp/bugs/configure.zcml 2010-05-26 15:24:23 +0000
53+++ lib/lp/bugs/configure.zcml 2010-06-03 10:55:38 +0000
54@@ -967,18 +967,6 @@
55 factory="lp.bugs.browser.bugtarget.BugsVHostBreadcrumb"
56 permission="zope.Public"/>
57
58- <!-- CalculateBugHeatJobs -->
59- <class class="lp.bugs.model.bugheat.CalculateBugHeatJob">
60- <allow interface="lp.bugs.interfaces.bugjob.IBugJob" />
61- <allow interface="lp.bugs.interfaces.bugjob.ICalculateBugHeatJob"/>
62- </class>
63- <securedutility
64- component="lp.bugs.model.bugheat.CalculateBugHeatJob"
65- provides="lp.bugs.interfaces.bugjob.ICalculateBugHeatJobSource">
66- <allow
67- interface="lp.bugs.interfaces.bugjob.ICalculateBugHeatJobSource"/>
68- </securedutility>
69-
70 <!-- ProcessApportBlobJobs -->
71 <class class="lp.bugs.model.apportjob.ProcessApportBlobJob">
72 <allow interface="lp.bugs.interfaces.apportjob.IApportJob" />
73
74=== modified file 'lib/lp/bugs/interfaces/bugjob.py'
75--- lib/lp/bugs/interfaces/bugjob.py 2010-01-22 21:44:19 +0000
76+++ lib/lp/bugs/interfaces/bugjob.py 2010-06-03 10:55:38 +0000
77@@ -8,8 +8,6 @@
78 'BugJobType',
79 'IBugJob',
80 'IBugJobSource',
81- 'ICalculateBugHeatJob',
82- 'ICalculateBugHeatJobSource',
83 ]
84
85 from zope.interface import Attribute, Interface
86@@ -19,7 +17,7 @@
87
88 from lazr.enum import DBEnumeratedType, DBItem
89 from lp.bugs.interfaces.bug import IBug
90-from lp.services.job.interfaces.job import IJob, IJobSource, IRunnableJob
91+from lp.services.job.interfaces.job import IJob, IJobSource
92
93
94 class BugJobType(DBEnumeratedType):
95@@ -57,11 +55,3 @@
96
97 def create(bug):
98 """Create a new IBugJob for a bug."""
99-
100-
101-class ICalculateBugHeatJob(IRunnableJob):
102- """A Job to calculate bug heat."""
103-
104-
105-class ICalculateBugHeatJobSource(IBugJobSource):
106- """Interface for acquiring CalculateBugHeatJobs."""
107
108=== modified file 'lib/lp/bugs/model/bug.py'
109--- lib/lp/bugs/model/bug.py 2010-05-30 04:06:48 +0000
110+++ lib/lp/bugs/model/bug.py 2010-06-03 10:55:38 +0000
111@@ -83,7 +83,6 @@
112 from lp.bugs.interfaces.bugtracker import BugTrackerType
113 from lp.bugs.interfaces.bugwatch import IBugWatchSet
114 from lp.bugs.interfaces.cve import ICveSet
115-from lp.bugs.scripts.bugheat import BugHeatConstants
116 from lp.bugs.model.bugattachment import BugAttachment
117 from lp.bugs.model.bugbranch import BugBranch
118 from lp.bugs.model.bugcve import BugCve
119
120=== removed file 'lib/lp/bugs/model/bugheat.py'
121--- lib/lp/bugs/model/bugheat.py 2010-01-21 20:46:03 +0000
122+++ lib/lp/bugs/model/bugheat.py 1970-01-01 00:00:00 +0000
123@@ -1,54 +0,0 @@
124-# Copyright 2010 Canonical Ltd. This software is licensed under the
125-# GNU Affero General Public License version 3 (see the file LICENSE).
126-
127-"""Job classes related to BugJobs are in here."""
128-
129-__metaclass__ = type
130-__all__ = [
131- 'CalculateBugHeatJob',
132- ]
133-
134-from zope.component import getUtility
135-from zope.interface import classProvides, implements
136-
137-from canonical.launchpad.webapp.interfaces import (
138- DEFAULT_FLAVOR, IStoreSelector, MAIN_STORE)
139-
140-from lp.bugs.interfaces.bugjob import (
141- BugJobType, ICalculateBugHeatJob, ICalculateBugHeatJobSource)
142-from lp.bugs.model.bugjob import BugJob, BugJobDerived
143-from lp.bugs.scripts.bugheat import BugHeatCalculator
144-from lp.services.job.model.job import Job
145-
146-
147-class CalculateBugHeatJob(BugJobDerived):
148- """A Job to calculate bug heat."""
149- implements(ICalculateBugHeatJob)
150-
151- class_job_type = BugJobType.UPDATE_HEAT
152- classProvides(ICalculateBugHeatJobSource)
153-
154- def run(self):
155- """See `IRunnableJob`."""
156- calculator = BugHeatCalculator(self.bug)
157- calculated_heat = calculator.getBugHeat()
158- self.bug.setHeat(calculated_heat)
159-
160- @classmethod
161- def create(cls, bug):
162- """See `ICalculateBugHeatJobSource`."""
163- # If there's already a job for the bug, don't create a new one.
164- store = getUtility(IStoreSelector).get(MAIN_STORE, DEFAULT_FLAVOR)
165- job_for_bug = store.find(
166- BugJob,
167- BugJob.bug == bug,
168- BugJob.job_type == cls.class_job_type,
169- BugJob.job == Job.id,
170- Job.id.is_in(Job.ready_jobs)
171- ).any()
172-
173- if job_for_bug is not None:
174- return cls(job_for_bug)
175- else:
176- return super(CalculateBugHeatJob, cls).create(bug)
177-
178
179=== removed file 'lib/lp/bugs/scripts/bugheat.py'
180--- lib/lp/bugs/scripts/bugheat.py 2010-04-29 11:31:49 +0000
181+++ lib/lp/bugs/scripts/bugheat.py 1970-01-01 00:00:00 +0000
182@@ -1,108 +0,0 @@
183-# Copyright 2010 Canonical Ltd. This software is licensed under the
184-# GNU Affero General Public License version 3 (see the file LICENSE).
185-
186-"""The innards of the Bug Heat cronscript."""
187-
188-__metaclass__ = type
189-__all__ = [
190- 'BugHeatCalculator',
191- 'BugHeatConstants',
192- ]
193-
194-from datetime import datetime
195-
196-from lp.bugs.interfaces.bugtask import RESOLVED_BUGTASK_STATUSES
197-
198-class BugHeatConstants:
199-
200- PRIVACY = 150
201- SECURITY = 250
202- DUPLICATE = 6
203- AFFECTED_USER = 4
204- SUBSCRIBER = 2
205-
206-
207-class BugHeatCalculator:
208- """A class to calculate the heat for a bug."""
209- # If you change the way that bug heat is calculated, remember to update
210- # the description of how it is calculated at
211- # /lib/lp/bugs/help/bug-heat.html and
212- # https://help.launchpad.net/Bugs/BugHeat
213-
214- def __init__(self, bug):
215- self.bug = bug
216-
217- def _getHeatFromPrivacy(self):
218- """Return the heat generated by the bug's `private` attribute."""
219- if self.bug.private:
220- return BugHeatConstants.PRIVACY
221- else:
222- return 0
223-
224- def _getHeatFromSecurity(self):
225- """Return the heat generated if the bug is security related."""
226- if self.bug.security_related:
227- return BugHeatConstants.SECURITY
228- else:
229- return 0
230-
231- def _getHeatFromDuplicates(self):
232- """Return the heat generated by the bug's duplicates."""
233- return self.bug.duplicates.count() * BugHeatConstants.DUPLICATE
234-
235- def _getHeatFromAffectedUsers(self):
236- """Return the heat generated by the bug's affected users."""
237- return (
238- self.bug.users_affected_count_with_dupes *
239- BugHeatConstants.AFFECTED_USER)
240-
241- def _getHeatFromSubscribers(self):
242- """Return the heat generated by the bug's subscribers."""
243- direct_subscribers = self.bug.getDirectSubscribers()
244- subscribers_from_dupes = self.bug.getSubscribersFromDuplicates()
245-
246- subscriber_count = (
247- len(direct_subscribers) + len(subscribers_from_dupes))
248- return subscriber_count * BugHeatConstants.SUBSCRIBER
249-
250- def _bugIsComplete(self):
251- """Are all the tasks for this bug resolved?"""
252- return all([(task.status in RESOLVED_BUGTASK_STATUSES)
253- for task in self.bug.bugtasks])
254-
255- def getBugHeat(self):
256- """Return the total heat for the current bug."""
257- if self._bugIsComplete():
258- return 0
259-
260- total_heat = sum([
261- self._getHeatFromAffectedUsers(),
262- self._getHeatFromDuplicates(),
263- self._getHeatFromPrivacy(),
264- self._getHeatFromSecurity(),
265- self._getHeatFromSubscribers(),
266- ])
267-
268- # Bugs decay over time. Every day the bug isn't touched its heat
269- # decreases by 1%.
270- days = (
271- datetime.utcnow() -
272- self.bug.date_last_updated.replace(tzinfo=None)).days
273- total_heat = int(total_heat * (0.99 ** days))
274-
275- if days > 0:
276- # Bug heat increases by a quarter of the maximum bug heat divided
277- # by the number of days since the bug's creation date.
278- days_since_last_activity = (
279- datetime.utcnow() -
280- max(self.bug.date_last_updated.replace(tzinfo=None),
281- self.bug.date_last_message.replace(tzinfo=None))).days
282- days_since_created = (
283- datetime.utcnow() - self.bug.datecreated.replace(tzinfo=None)).days
284- max_heat = max(
285- task.target.max_bug_heat for task in self.bug.bugtasks)
286- if max_heat is not None and days_since_created > 0:
287- total_heat = total_heat + (max_heat * 0.25 / days_since_created)
288-
289- return int(total_heat)
290-
291
292=== removed file 'lib/lp/bugs/scripts/tests/test_bugheat.py'
293--- lib/lp/bugs/scripts/tests/test_bugheat.py 2010-04-29 11:31:49 +0000
294+++ lib/lp/bugs/scripts/tests/test_bugheat.py 1970-01-01 00:00:00 +0000
295@@ -1,256 +0,0 @@
296-# Copyright 2010 Canonical Ltd. This software is licensed under the
297-# GNU Affero General Public License version 3 (see the file LICENSE).
298-
299-"""Module docstring goes here."""
300-
301-__metaclass__ = type
302-
303-import unittest
304-
305-from datetime import datetime, timedelta
306-
307-from canonical.testing import LaunchpadZopelessLayer
308-
309-from lp.bugs.interfaces.bugtask import BugTaskStatus
310-from lp.bugs.scripts.bugheat import BugHeatCalculator, BugHeatConstants
311-from lp.testing import TestCaseWithFactory
312-
313-from zope.security.proxy import removeSecurityProxy
314-
315-
316-class TestBugHeatCalculator(TestCaseWithFactory):
317- """Tests for the BugHeatCalculator class."""
318- # If you change the way that bug heat is calculated, remember to update
319- # the description of how it is calculated at
320- # /lib/lp/bugs/help/bug-heat.html and
321- # https://help.launchpad.net/Bugs/BugHeat
322-
323- layer = LaunchpadZopelessLayer
324-
325- def setUp(self):
326- super(TestBugHeatCalculator, self).setUp()
327- self.bug = self.factory.makeBug()
328- self.calculator = BugHeatCalculator(self.bug)
329-
330- def test__getHeatFromDuplicates(self):
331- # BugHeatCalculator._getHeatFromDuplicates() returns the bug
332- # heat generated by duplicates of a bug.
333- # By default, the bug has no heat from dupes
334- self.assertEqual(0, self.calculator._getHeatFromDuplicates())
335-
336- # If adding duplicates, the heat generated by them will be n *
337- # BugHeatConstants.DUPLICATE, where n is the number of
338- # duplicates.
339- for i in range(5):
340- dupe = self.factory.makeBug()
341- dupe.duplicateof = self.bug
342-
343- expected_heat = BugHeatConstants.DUPLICATE * 5
344- actual_heat = self.calculator._getHeatFromDuplicates()
345- self.assertEqual(
346- expected_heat, actual_heat,
347- "Heat from duplicates does not match expected heat. "
348- "Expected %s, got %s" % (expected_heat, actual_heat))
349-
350- def test__getHeatFromAffectedUsers(self):
351- # BugHeatCalculator._getHeatFromAffectedUsers() returns the bug
352- # heat generated by users affected by the bug and by duplicate bugs.
353- # By default, the heat will be BugHeatConstants.AFFECTED_USER, since
354- # there will be one affected user (the user who filed the bug).
355- self.assertEqual(
356- BugHeatConstants.AFFECTED_USER,
357- self.calculator._getHeatFromAffectedUsers())
358-
359- # As the number of affected users increases, the heat generated
360- # will be n * BugHeatConstants.AFFECTED_USER, where n is the number
361- # of affected users.
362- for i in range(5):
363- person = self.factory.makePerson()
364- self.bug.markUserAffected(person)
365-
366- expected_heat = BugHeatConstants.AFFECTED_USER * 6
367- actual_heat = self.calculator._getHeatFromAffectedUsers()
368- self.assertEqual(
369- expected_heat, actual_heat,
370- "Heat from affected users does not match expected heat. "
371- "Expected %s, got %s" % (expected_heat, actual_heat))
372-
373- # When our bug has duplicates, users affected by these duplicates
374- # are included in _getHeatFromAffectedUsers() of the main bug.
375- for i in range(3):
376- dupe = self.factory.makeBug()
377- dupe.duplicateof = self.bug
378- # Each bug reporter is by default also marked as being affected
379- # by the bug, so we have three additional affected users.
380- expected_heat += BugHeatConstants.AFFECTED_USER * 3
381-
382- person = self.factory.makePerson()
383- dupe.markUserAffected(person)
384- expected_heat += BugHeatConstants.AFFECTED_USER
385- actual_heat = self.calculator._getHeatFromAffectedUsers()
386- self.assertEqual(
387- expected_heat, actual_heat,
388- "Heat from users affected by duplicate bugs does not match "
389- "expected heat. Expected %s, got %s"
390- % (expected_heat, actual_heat))
391-
392- def test__getHeatFromSubscribers(self):
393- # BugHeatCalculator._getHeatFromSubscribers() returns the bug
394- # heat generated by users subscribed tothe bug.
395- # By default, the heat will be BugHeatConstants.SUBSCRIBER,
396- # since there will be one direct subscriber (the user who filed
397- # the bug).
398- self.assertEqual(
399- BugHeatConstants.SUBSCRIBER,
400- self.calculator._getHeatFromSubscribers())
401-
402- # As the number of subscribers increases, the heat generated
403- # will be n * BugHeatConstants.SUBSCRIBER, where n is the number
404- # of subscribers.
405- for i in range(5):
406- person = self.factory.makePerson()
407- self.bug.subscribe(person, person)
408-
409- expected_heat = BugHeatConstants.SUBSCRIBER * 6
410- actual_heat = self.calculator._getHeatFromSubscribers()
411- self.assertEqual(
412- expected_heat, actual_heat,
413- "Heat from subscribers does not match expected heat. "
414- "Expected %s, got %s" % (expected_heat, actual_heat))
415-
416- # Subscribers from duplicates are included in the heat returned
417- # by _getHeatFromSubscribers()
418- dupe = self.factory.makeBug()
419- dupe.duplicateof = self.bug
420- expected_heat = BugHeatConstants.SUBSCRIBER * 7
421- actual_heat = self.calculator._getHeatFromSubscribers()
422- self.assertEqual(
423- expected_heat, actual_heat,
424- "Heat from subscribers (including duplicate-subscribers) "
425- "does not match expected heat. Expected %s, got %s" %
426- (expected_heat, actual_heat))
427-
428- # Seting the bug to private will increase its heat from
429- # subscribers by 1 * BugHeatConstants.SUBSCRIBER, as the project
430- # owner will now be directly subscribed to it.
431- self.bug.setPrivate(True, self.bug.owner)
432- expected_heat = BugHeatConstants.SUBSCRIBER * 8
433- actual_heat = self.calculator._getHeatFromSubscribers()
434- self.assertEqual(
435- expected_heat, actual_heat,
436- "Heat from subscribers to private bug does not match expected "
437- "heat. Expected %s, got %s" % (expected_heat, actual_heat))
438-
439- def test__getHeatFromPrivacy(self):
440- # BugHeatCalculator._getHeatFromPrivacy() returns the heat
441- # generated by the bug's private attribute. If the bug is
442- # public, this will be 0.
443- self.assertEqual(0, self.calculator._getHeatFromPrivacy())
444-
445- # However, if the bug is private, _getHeatFromPrivacy() will
446- # return BugHeatConstants.PRIVACY.
447- self.bug.setPrivate(True, self.bug.owner)
448- self.assertEqual(
449- BugHeatConstants.PRIVACY, self.calculator._getHeatFromPrivacy())
450-
451- def test__getHeatFromSecurity(self):
452- # BugHeatCalculator._getHeatFromSecurity() returns the heat
453- # generated by the bug's security_related attribute. If the bug
454- # is not security related, _getHeatFromSecurity() will return 0.
455- self.assertEqual(0, self.calculator._getHeatFromPrivacy())
456-
457-
458- # If, on the other hand, the bug is security_related,
459- # _getHeatFromSecurity() will return BugHeatConstants.SECURITY
460- self.bug.setSecurityRelated(True)
461- self.assertEqual(
462- BugHeatConstants.SECURITY, self.calculator._getHeatFromSecurity())
463-
464- def test_getBugHeat(self):
465- # BugHeatCalculator.getBugHeat() returns the total heat for a
466- # given bug as the sum of the results of all _getHeatFrom*()
467- # methods.
468- # By default this will be (BugHeatConstants.AFFECTED_USER +
469- # BugHeatConstants.SUBSCRIBER) since there will be one
470- # subscriber and one affected user only.
471- expected_heat = (
472- BugHeatConstants.AFFECTED_USER + BugHeatConstants.SUBSCRIBER)
473- actual_heat = self.calculator.getBugHeat()
474- self.assertEqual(
475- expected_heat, actual_heat,
476- "Expected bug heat did not match actual bug heat. "
477- "Expected %s, got %s" % (expected_heat, actual_heat))
478-
479- # Adding a duplicate and making the bug private and security
480- # related will increase its heat.
481- dupe = self.factory.makeBug()
482- dupe.duplicateof = self.bug
483- self.bug.setPrivate(True, self.bug.owner)
484- self.bug.setSecurityRelated(True)
485-
486- expected_heat += (
487- BugHeatConstants.DUPLICATE +
488- BugHeatConstants.PRIVACY +
489- BugHeatConstants.SECURITY +
490- BugHeatConstants.AFFECTED_USER
491- )
492-
493- # Adding the duplicate and making the bug private means it gets
494- # two new subscribers, the project owner and the duplicate's
495- # direct subscriber.
496- expected_heat += BugHeatConstants.SUBSCRIBER * 2
497- actual_heat = self.calculator.getBugHeat()
498- self.assertEqual(
499- expected_heat, actual_heat,
500- "Expected bug heat did not match actual bug heat. "
501- "Expected %s, got %s" % (expected_heat, actual_heat))
502-
503- def test_getBugHeat_complete_bugs(self):
504- # Bug which are in a resolved status don't have heat at all.
505- complete_bug = self.factory.makeBug()
506- heat = BugHeatCalculator(complete_bug).getBugHeat()
507- self.assertNotEqual(
508- 0, heat,
509- "Expected bug heat did not match actual bug heat. "
510- "Expected a positive value, got 0")
511- complete_bug.bugtasks[0].transitionToStatus(
512- BugTaskStatus.INVALID, complete_bug.owner)
513- heat = BugHeatCalculator(complete_bug).getBugHeat()
514- self.assertEqual(
515- 0, heat,
516- "Expected bug heat did not match actual bug heat. "
517- "Expected %s, got %s" % (0, heat))
518-
519- def test_getBugHeat_decay(self):
520- # Every day, a bug that wasn't touched has its heat reduced by 1%.
521- aging_bug = self.factory.makeBug()
522- fresh_heat = BugHeatCalculator(aging_bug).getBugHeat()
523- aging_bug.date_last_updated = (
524- aging_bug.date_last_updated - timedelta(days=1))
525- expected = int(fresh_heat * 0.99)
526- heat = BugHeatCalculator(aging_bug).getBugHeat()
527- self.assertEqual(
528- expected, heat,
529- "Expected bug heat did not match actual bug heat. "
530- "Expected %s, got %s" % (expected, heat))
531-
532- def test_getBugHeat_activity(self):
533- # Bug heat increases by a quarter of the maximum bug heat divided by
534- # the number of days between the bug's creating and its last activity.
535- active_bug = removeSecurityProxy(self.factory.makeBug())
536- fresh_heat = BugHeatCalculator(active_bug).getBugHeat()
537- active_bug.date_last_updated = (
538- active_bug.date_last_updated - timedelta(days=10))
539- active_bug.datecreated = (active_bug.datecreated - timedelta(days=20))
540- active_bug.default_bugtask.target.setMaxBugHeat(100)
541- expected = int((fresh_heat * (0.99 ** 20)) + (100 * 0.25 / 20))
542- heat = BugHeatCalculator(active_bug).getBugHeat()
543- self.assertEqual(
544- expected, heat,
545- "Expected bug heat did not match actual bug heat. "
546- "Expected %s, got %s" % (expected, heat))
547-
548-
549-
550-def test_suite():
551- return unittest.TestLoader().loadTestsFromName(__name__)
552
553=== modified file 'lib/lp/bugs/tests/test_bugheat.py'
554--- lib/lp/bugs/tests/test_bugheat.py 2010-05-27 13:56:03 +0000
555+++ lib/lp/bugs/tests/test_bugheat.py 2010-06-03 10:55:38 +0000
556@@ -5,114 +5,13 @@
557
558 __metaclass__ = type
559
560-import pytz
561-import transaction
562 import unittest
563-from datetime import datetime
564-
565-from zope.component import getUtility
566-
567-from canonical.launchpad.scripts.tests import run_script
568+
569 from canonical.testing import LaunchpadZopelessLayer
570
571-from lp.bugs.adapters.bugchange import BugDescriptionChange
572-from lp.bugs.interfaces.bugjob import ICalculateBugHeatJobSource
573-from lp.bugs.model.bugheat import CalculateBugHeatJob
574-from lp.bugs.scripts.bugheat import BugHeatCalculator
575-from lp.testing import TestCaseWithFactory
576 from lp.testing.factory import LaunchpadObjectFactory
577
578
579-class CalculateBugHeatJobTestCase(TestCaseWithFactory):
580- """Test case for CalculateBugHeatJob."""
581-
582- layer = LaunchpadZopelessLayer
583-
584- def setUp(self):
585- super(CalculateBugHeatJobTestCase, self).setUp()
586- self.bug = self.factory.makeBug()
587-
588- # NB: This looks like it should go in the teardown, however
589- # creating the bug causes a job to be added for it. We clear
590- # this out so that our tests are consistent.
591- self._completeJobsAndAssertQueueEmpty()
592-
593- def _completeJobsAndAssertQueueEmpty(self):
594- """Make sure that all the CalculateBugHeatJobs are completed."""
595- for bug_job in getUtility(ICalculateBugHeatJobSource).iterReady():
596- bug_job.job.start()
597- bug_job.job.complete()
598- self.assertEqual(0, self._getJobCount())
599-
600- def _getJobCount(self):
601- """Return the number of CalculateBugHeatJobs in the queue."""
602- return len(self._getJobs())
603-
604- def _getJobs(self):
605- """Return the pending CalculateBugHeatJobs as a list."""
606- return list(CalculateBugHeatJob.iterReady())
607-
608- def test_run(self):
609- # CalculateBugHeatJob.run() sets calculates and sets the heat
610- # for a bug.
611- job = CalculateBugHeatJob.create(self.bug)
612- bug_heat_calculator = BugHeatCalculator(self.bug)
613-
614- job.run()
615- self.assertEqual(
616- bug_heat_calculator.getBugHeat(), self.bug.heat)
617-
618- def test_utility(self):
619- # CalculateBugHeatJobSource is a utility for acquiring
620- # CalculateBugHeatJobs.
621- utility = getUtility(ICalculateBugHeatJobSource)
622- self.assertTrue(
623- ICalculateBugHeatJobSource.providedBy(utility))
624-
625- def test_create_only_creates_one(self):
626- # If there's already a CalculateBugHeatJob for a bug,
627- # CalculateBugHeatJob.create() won't create a new one.
628- job = CalculateBugHeatJob.create(self.bug)
629-
630- # There will now be one job in the queue.
631- self.assertEqual(1, self._getJobCount())
632-
633- new_job = CalculateBugHeatJob.create(self.bug)
634-
635- # The two jobs will in fact be the same job.
636- self.assertEqual(job, new_job)
637-
638- # And the queue will still have a length of 1.
639- self.assertEqual(1, self._getJobCount())
640-
641- def test_cronscript_succeeds(self):
642- # The calculate-bug-heat cronscript will run all pending
643- # CalculateBugHeatJobs.
644- CalculateBugHeatJob.create(self.bug)
645- transaction.commit()
646-
647- retcode, stdout, stderr = run_script(
648- 'cronscripts/calculate-bug-heat.py', [],
649- expect_returncode=0)
650- self.assertEqual('', stdout)
651- self.assertIn(
652- 'INFO Ran 1 CalculateBugHeatJob jobs.\n', stderr)
653-
654- def test_getOopsVars(self):
655- # BugJobDerived.getOopsVars() returns the variables to be used
656- # when logging an OOPS for a bug job. We test this using
657- # CalculateBugHeatJob because BugJobDerived doesn't let us
658- # create() jobs.
659- job = CalculateBugHeatJob.create(self.bug)
660- vars = job.getOopsVars()
661-
662- # The Bug ID, BugJob ID and BugJob type will be returned by
663- # getOopsVars().
664- self.assertIn(('bug_id', self.bug.id), vars)
665- self.assertIn(('bug_job_id', job.context.id), vars)
666- self.assertIn(('bug_job_type', job.context.job_type.title), vars)
667-
668-
669 class MaxHeatByTargetBase:
670 """Base class for testing a bug target's max_bug_heat attribute."""
671

Subscribers

People subscribed via source and target branches

to status/vote changes: