Code review comment for lp:~intellectronica/launchpad/heat-decay-complete

Revision history for this message
Edwin Grubbs (edwin-grubbs) wrote :

Hi Tom,

This is a nice branch. I have a few comments below, and there are some
lint errors.

merge-conditional

-Edwin

== Pyflakes notices ==

lib/lp/bugs/scripts/bugheat.py
    13: 'getUtility' imported but unused
    14: 'implements' imported but unused
    16: 'ITunableLoop' imported but unused
    17: 'DBLoopTuner' imported but unused

lib/lp/bugs/scripts/tests/test_bugheat.py
    10: 'datetime' imported but unused

>=== modified file 'lib/lp/bugs/scripts/bugheat.py'
>--- lib/lp/bugs/scripts/bugheat.py 2010-01-26 20:31:13 +0000
>+++ lib/lp/bugs/scripts/bugheat.py 2010-02-26 21:30:36 +0000
>@@ -8,6 +8,7 @@
> 'BugHeatCalculator',
> ]
>
>+from datetime import datetime
>
> from zope.component import getUtility
> from zope.interface import implements
>@@ -15,6 +16,8 @@
> from canonical.launchpad.interfaces.looptuner import ITunableLoop
> from canonical.launchpad.utilities.looptuner import DBLoopTuner
>
>+from lp.bugs.interfaces.bugtask import RESOLVED_BUGTASK_STATUSES
>+
>
> class BugHeatConstants:
>
>@@ -63,8 +66,16 @@
> len(direct_subscribers) + len(subscribers_from_dupes))
> return subscriber_count * BugHeatConstants.SUBSCRIBER
>
>+ def _bugIsComplete(self):
>+ """Are all the tasks for this bug resolved?"""
>+ return all([(task.status in RESOLVED_BUGTASK_STATUSES)
>+ for task in self.bug.bugtasks])
>+
> def getBugHeat(self):
> """Return the total heat for the current bug."""
>+ if self._bugIsComplete():
>+ return 0
>+
> total_heat = sum([
> self._getHeatFromAffectedUsers(),
> self._getHeatFromDuplicates(),
>@@ -73,5 +84,15 @@
> self._getHeatFromSubscribers(),
> ])
>
>+ # Bugs decay over time. Every month the bug isn't touched its heat
>+ # decreeses by 5%.

s/decreeses/decreases/

The comment says 5%, but the test says 10%. Which is it?

>+ months = (
>+ datetime.utcnow() -
>+ self.bug.date_last_updated.replace(tzinfo=None)).days / 30
>+ for i in range(months):
>+ total_heat = total_heat * 0.95

This could be simplified as:
    total_heat *= 0.95 ** months

>+
>+ total_heat = int(total_heat)
>+
> return total_heat
>
>
>=== modified file 'lib/lp/bugs/scripts/tests/test_bugheat.py'
>--- lib/lp/bugs/scripts/tests/test_bugheat.py 2010-01-12 16:41:23 +0000
>+++ lib/lp/bugs/scripts/tests/test_bugheat.py 2010-02-26 21:30:36 +0000
>@@ -1,4 +1,3 @@
>-
> # Copyright 2010 Canonical Ltd. This software is licensed under the
> # GNU Affero General Public License version 3 (see the file LICENSE).
>
>@@ -8,12 +7,14 @@
>
> import unittest
>
>+from datetime import datetime, timedelta
>+
> from canonical.testing import LaunchpadZopelessLayer
>
>+from lp.bugs.interfaces.bugtask import BugTaskStatus
> from lp.bugs.scripts.bugheat import BugHeatCalculator, BugHeatConstants
> from lp.testing import TestCaseWithFactory
>
>-
> class TestBugHeatCalculator(TestCaseWithFactory):
> """Tests for the BugHeatCalculator class."""
>
>@@ -177,6 +178,35 @@
> "Expected bug heat did not match actual bug heat. "
> "Expected %s, got %s" % (expected_heat, actual_heat))
>
>+ def test_getBugHeat_complete_bugs(self):
>+ # Bug which are in a resolved status don't have heat at all.
>+ complete_bug = self.factory.makeBug()
>+ heat = BugHeatCalculator(complete_bug).getBugHeat()
>+ self.assertNotEqual(
>+ 0, heat,
>+ "Expected bug heat did not match actual bug heat. "
>+ "Expected a positive value, got 0")
>+ complete_bug.bugtasks[0].transitionToStatus(
>+ BugTaskStatus.INVALID, complete_bug.owner)
>+ heat = BugHeatCalculator(complete_bug).getBugHeat()
>+ self.assertEqual(
>+ 0, heat,
>+ "Expected bug heat did not match actual bug heat. "
>+ "Expected %s, got %s" % (0, heat))
>+
>+ def test_getBugHeat_decay(self):
>+ # Every month, a bug that wasn't touched has its heat reduced by 10%.

10% or 5% ?

>+ aging_bug = self.factory.makeBug()
>+ aging_bug.date_last_updated = (
>+ aging_bug.date_last_updated - timedelta(days=32))
>+ expected = int((
>+ BugHeatConstants.AFFECTED_USER + BugHeatConstants.SUBSCRIBER) * 0.9)
>+ heat = BugHeatCalculator(aging_bug).getBugHeat()

This test might not notice corner cases. Can you run getBugHeat()
before and after setting the date_last_updated and assert that
old_heat * 0.9 == new_heat

>+ self.assertEqual(
>+ expected, heat,
>+ "Expected bug heat did not match actual bug heat. "
>+ "Expected %s, got %s" % (expected, heat))
>+
>
> def test_suite():
> return unittest.TestLoader().loadTestsFromName(__name__)
>

review: Approve (code)

« Back to merge proposal