← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~wgrant/launchpad/max-heat-too-hot into lp:launchpad

 

William Grant has proposed merging lp:~wgrant/launchpad/max-heat-too-hot into lp:launchpad.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)
Related bugs:
  Bug #915267 in Launchpad itself: "bug heat flames are expensive to calculate"
  https://bugs.launchpad.net/launchpad/+bug/915267

For more details, see:
https://code.launchpad.net/~wgrant/launchpad/max-heat-too-hot/+merge/91778

08:54:33 < lifeless> wgrant: hey
08:54:40 < lifeless> wgrant: whats the status of the heat plumbing
08:59:26 < wgrant> lifeless: I was planning on waiting for a few days of insufficient complaints before ripping it out.
09:00:19 < lifeless> wgrant: doit
09:00:39 < lifeless> or at least, lets get the branch ready to troll
09:02:07 < wgrant> lifeless: Disable the max heat update code, and the aging job?
09:02:12 < wgrant> s/Disable/Delete/
09:02:24 < lifeless> yeah, and remove the flag

With max_bug_heat usage now disabled on production, we can stop calling recalculateBugHeatCache. This prevents late evaluation, repeated updates, and write conflicts when altering bugs.
-- 
https://code.launchpad.net/~wgrant/launchpad/max-heat-too-hot/+merge/91778
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~wgrant/launchpad/max-heat-too-hot into lp:launchpad.
=== modified file 'lib/lp/bugs/doc/bug-heat.txt'
--- lib/lp/bugs/doc/bug-heat.txt	2011-09-30 16:05:20 +0000
+++ lib/lp/bugs/doc/bug-heat.txt	2012-02-07 08:23:31 +0000
@@ -300,85 +300,3 @@
 
     >>> getUtility(IBugSet).getBugsWithOutdatedHeat(1).count()
     0
-
-
-Caculating the maximum heat for a target
-----------------------------------------
-
-When we update the heat value for a bug, the maximum heat value for the
-targets for all of its tasks is calculated and cached.
-
-    >>> product = factory.makeProduct()
-    >>> bug = factory.makeBug(product=product)
-    >>> bug.setHeat(123)
-    >>> print product.max_bug_heat
-    123
-
-The maximum heat for a project is the value for tasks on all its products.
-
-    >>> project = factory.makeProject()
-    >>> product.project = project
-    >>> bug.setHeat(123)
-    >>> print project.max_bug_heat
-    123
-
-A DistributionSourcePackage has its own maximum heat.
-
-    >>> dsp = factory.makeDistributionSourcePackage()
-    >>> dsp_task = bug.addTask(bug.owner, dsp)
-    >>> print dsp.max_bug_heat
-    123
-
-A DistributionSourcePackage also has a cached value for bug_count and
-total_bug_heat.
-
-    >>> print dsp.bug_count
-    1
-    >>> print dsp.total_bug_heat
-    123
-    >>> dsp_task2 = factory.makeBugTask(target=dsp)
-    >>> dsp_task2.bug.setHeat(7)
-    >>> print dsp.bug_count
-    2
-    >>> print dsp.total_bug_heat
-    130
-
-Transitioning from one target to another, calculates the value for the new
-target.
-
-    >>> another_product = factory.makeProduct()
-    >>> transaction.commit()
-    >>> bug.bugtasks[0].transitionToTarget(another_product)
-    >>> print another_product.max_bug_heat
-    123
-
-ProductSeries and DistroSeries simply delegate to their corresponding Product
-or Distribution.
-
-    >>> product_series = factory.makeProductSeries()
-    >>> ps_task = bug.addTask(bug.owner, product_series)
-    >>> print product_series.max_bug_heat
-    123
-    >>> print product_series.product.max_bug_heat
-    123
-
-    >>> distro_series = factory.makeDistroSeries()
-    >>> ds_task = bug.addTask(bug.owner, distro_series)
-    >>> print distro_series.max_bug_heat
-    123
-    >>> print distro_series.distribution.max_bug_heat
-    123
-
-Maximum heat is limited to bugs of a specific target.
-
-    >>> product = factory.makeProduct()
-    >>> product_bug = factory.makeBug(product=product)
-    >>> product_bug.setHeat(123)
-    >>> distro = factory.makeDistribution()
-    >>> distro_bug = factory.makeBug()
-    >>> distro_task = distro_bug.addTask(bug.owner, distro)
-    >>> distro_bug.setHeat(456)
-    >>> print product.max_bug_heat
-    123
-    >>> print distro.max_bug_heat
-    456

=== modified file 'lib/lp/bugs/interfaces/bug.py'
--- lib/lp/bugs/interfaces/bug.py	2012-01-03 10:34:20 +0000
+++ lib/lp/bugs/interfaces/bug.py	2012-02-07 08:23:31 +0000
@@ -994,10 +994,10 @@
         if the user is the owner or an admin.
         """
 
-    def setHeat(heat, timestamp=None, affected_targets=None):
+    def setHeat(heat, timestamp=None):
         """Set the heat for the bug."""
 
-    def updateHeat(affected_targets=None):
+    def updateHeat():
         """Update the heat for the bug."""
 
     @operation_parameters(

=== modified file 'lib/lp/bugs/model/bug.py'
--- lib/lp/bugs/model/bug.py	2012-01-04 17:41:01 +0000
+++ lib/lp/bugs/model/bug.py	2012-02-07 08:23:31 +0000
@@ -1229,13 +1229,7 @@
 
     def addTask(self, owner, target):
         """See `IBug`."""
-        new_task = getUtility(IBugTaskSet).createTask(self, owner, target)
-
-        # When a new task is added the bug's heat becomes relevant to the
-        # target's max_bug_heat.
-        target.recalculateBugHeatCache()
-
-        return new_task
+        return getUtility(IBugTaskSet).createTask(self, owner, target)
 
     def addWatch(self, bugtracker, remotebug, owner):
         """See `IBug`."""
@@ -2064,15 +2058,12 @@
     def _markAsDuplicate(self, duplicate_of):
         """Mark this bug as a duplicate of another.
 
-        Marking a bug as a duplicate requires a recalculation
-        of the heat of this bug and of the master bug, and it
-        requires a recalulation of the heat cache of the
-        affected bug targets. None of this is done here in order
-        to avoid unnecessary repetitions in recursive calls
-        for duplicates of this bug, which also become duplicates
+        Marking a bug as a duplicate requires a recalculation of the
+        heat of this bug and of the master bug. None of this is done
+        here in order to avoid unnecessary repetitions in recursive
+        calls for duplicates of this bug, which also become duplicates
         of the new master bug.
         """
-        affected_targets = set()
         field = DuplicateBug()
         field.context = self
         current_duplicateof = self.duplicateof
@@ -2083,9 +2074,7 @@
                 user = getUtility(ILaunchBag).user
                 for duplicate in self.duplicates:
                     old_value = duplicate.duplicateof
-                    affected_targets.update(
-                        duplicate._markAsDuplicate(duplicate_of))
-
+                    duplicate._markAsDuplicate(duplicate_of)
                     # Put an entry into the BugNotification table for
                     # later processing.
                     change = BugDuplicateChange(
@@ -2104,7 +2093,7 @@
             # Update the heat of the master bug and set this bug's heat
             # to 0 (since it's a duplicate, it shouldn't have any heat
             # at all).
-            self.setHeat(0, affected_targets=affected_targets)
+            self.setHeat(0)
             # Maybe confirm bug tasks, now that more people might be affected
             # by this bug from the duplicates.
             duplicate_of.maybeConfirmBugtasks()
@@ -2112,18 +2101,15 @@
             # Otherwise, recalculate this bug's heat, since it will be 0
             # from having been a duplicate. We also update the bug that
             # was previously duplicated.
-            self.updateHeat(affected_targets)
+            self.updateHeat()
             if current_duplicateof is not None:
-                current_duplicateof.updateHeat(affected_targets)
-        return affected_targets
+                current_duplicateof.updateHeat()
 
     def markAsDuplicate(self, duplicate_of):
         """See `IBug`."""
-        affected_targets = self._markAsDuplicate(duplicate_of)
+        self._markAsDuplicate(duplicate_of)
         if duplicate_of is not None:
-            duplicate_of.updateHeat(affected_targets)
-        for target in affected_targets:
-            target.recalculateBugHeatCache()
+            duplicate_of.updateHeat()
 
     def setCommentVisibility(self, user, comment_number, visible):
         """See `IBug`."""
@@ -2274,7 +2260,7 @@
 
         return not subscriptions_from_dupes.is_empty()
 
-    def setHeat(self, heat, timestamp=None, affected_targets=None):
+    def setHeat(self, heat, timestamp=None):
         """See `IBug`."""
         """See `IBug`."""
         if timestamp is None:
@@ -2285,13 +2271,8 @@
 
         self.heat = heat
         self.heat_last_updated = timestamp
-        if affected_targets is None:
-            for task in self.bugtasks:
-                task.target.recalculateBugHeatCache()
-        else:
-            affected_targets.update(task.target for task in self.bugtasks)
 
-    def updateHeat(self, affected_targets=None):
+    def updateHeat(self):
         """See `IBug`."""
         if self.duplicateof is not None:
             # If this bug is a duplicate we don't try to calculate its
@@ -2305,11 +2286,6 @@
 
         self.heat = SQL("calculate_bug_heat(%s)" % sqlvalues(self))
         self.heat_last_updated = UTC_NOW
-        if affected_targets is None:
-            for task in self.bugtasks:
-                task.target.recalculateBugHeatCache()
-        else:
-            affected_targets.update(task.target for task in self.bugtasks)
         store.flush()
 
     def _attachments_query(self):

=== modified file 'lib/lp/bugs/model/bugtask.py'
--- lib/lp/bugs/model/bugtask.py	2012-02-02 14:52:48 +0000
+++ lib/lp/bugs/model/bugtask.py	2012-02-07 08:23:31 +0000
@@ -693,9 +693,6 @@
             # We don't care if there isn't a nomination
             pass
 
-        # When a task is deleted the bug's heat needs to be recalculated.
-        target.recalculateBugHeatCache()
-
     def findSimilarBugs(self, user, limit=10):
         """See `IBugTask`."""
         if self.product is not None:
@@ -1246,17 +1243,13 @@
             self.bug.access_policy.pillar != target.pillar):
             self.bug.setAccessPolicy(self.bug.access_policy.type)
 
-        # After the target has changed, we need to recalculate the maximum bug
-        # heat for the new and old targets.
-        if self.target != target_before_change:
-            target_before_change.recalculateBugHeatCache()
-            self.target.recalculateBugHeatCache()
-            # START TEMPORARY BIT FOR BUGTASK AUTOCONFIRM FEATURE FLAG.
-            # We also should see if we ought to auto-transition to the
-            # CONFIRMED status.
-            if self.bug.shouldConfirmBugtasks():
-                self.maybeConfirm()
-            # END TEMPORARY BIT FOR BUGTASK AUTOCONFIRM FEATURE FLAG.
+        # START TEMPORARY BIT FOR BUGTASK AUTOCONFIRM FEATURE FLAG.
+        # We also should see if we ought to auto-transition to the
+        # CONFIRMED status.
+        if (self.target != target_before_change and
+            self.bug.shouldConfirmBugtasks()):
+            self.maybeConfirm()
+        # END TEMPORARY BIT FOR BUGTASK AUTOCONFIRM FEATURE FLAG.
 
     def updateTargetNameCache(self, newtarget=None):
         """See `IBugTask`."""

=== removed file 'lib/lp/bugs/tests/test_bugheat.py'
--- lib/lp/bugs/tests/test_bugheat.py	2012-01-01 02:58:52 +0000
+++ lib/lp/bugs/tests/test_bugheat.py	1970-01-01 00:00:00 +0000
@@ -1,220 +0,0 @@
-# Copyright 2010 Canonical Ltd.  This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
-
-"""Tests for BugJobs."""
-
-__metaclass__ = type
-
-import unittest
-
-from lazr.delegates import delegates
-from storm.store import Store
-from zope.interface import implements
-
-from lp.bugs.interfaces.bugtask import BugTaskStatus
-from lp.registry.interfaces.distributionsourcepackage import (
-    IDistributionSourcePackage,
-    )
-from lp.testing import TestCaseWithFactory
-from lp.testing.factory import LaunchpadObjectFactory
-from lp.testing.layers import LaunchpadZopelessLayer
-
-
-class BugUpdateHeat(TestCaseWithFactory):
-
-    layer = LaunchpadZopelessLayer
-
-    def test_updateHeat_calls_recalculateBugHeatCache(self):
-        # This requires some instrumentation. The updateHeat() method is
-        # called by many methods that may be involved in setting up a bug
-        # target.
-        class TestTarget:
-            implements(IDistributionSourcePackage)
-            delegates(IDistributionSourcePackage, context='target')
-
-            def __init__(self, target):
-                self.target = target
-                self.called = False
-
-            def recalculateBugHeatCache(self):
-                self.called = True
-
-        distro = self.factory.makeDistribution()
-        target = TestTarget(
-            self.factory.makeDistributionSourcePackage(
-                distribution=distro, with_db=True))
-        dsp = self.factory.makeDistributionSourcePackage(distribution=distro)
-        bugtask = self.factory.makeBugTask(target=dsp)
-        another_task = bugtask.bug.addTask(bugtask.bug.owner, target)
-        another_task.bug.updateHeat()
-        self.assertTrue(target.called)
-
-
-class MaxHeatByTargetBase:
-    """Base class for testing a bug target's max_bug_heat attribute."""
-
-    layer = LaunchpadZopelessLayer
-
-    factory = LaunchpadObjectFactory()
-
-    # The target to test.
-    target = None
-
-    # Does the target have a set method?
-    delegates_setter = False
-
-    def test_target_max_bug_heat_default(self):
-        self.assertEqual(self.target.max_bug_heat, None)
-
-    def test_set_target_max_bug_heat(self):
-        if self.delegates_setter:
-            self.assertRaises(
-                NotImplementedError, self.target.setMaxBugHeat, 1000)
-        else:
-            self.target.setMaxBugHeat(1000)
-            self.assertEqual(self.target.max_bug_heat, 1000)
-
-
-class ProjectMaxHeatByTargetTest(MaxHeatByTargetBase, unittest.TestCase):
-    """Ensure a project has a max_bug_heat value that can be set."""
-
-    def setUp(self):
-        self.target = self.factory.makeProduct()
-
-
-class DistributionMaxHeatByTargetTest(MaxHeatByTargetBase, unittest.TestCase):
-    """Ensure a distribution has a max_bug_heat value that can be set."""
-
-    def setUp(self):
-        self.target = self.factory.makeDistribution()
-
-
-class DistributionSourcePackageMaxHeatByTargetTest(
-    MaxHeatByTargetBase, unittest.TestCase):
-    """Ensure distro source package has max_bug_heat value that can be set."""
-
-    def setUp(self):
-        self.target = self.factory.makeDistributionSourcePackage()
-
-
-class DistributionSourcePackageNullBugHeatCacheTest(TestCaseWithFactory):
-    """Ensure distro source package cache values start at None."""
-
-    layer = LaunchpadZopelessLayer
-
-    def setUp(self):
-        TestCaseWithFactory.setUp(self)
-        self.target = self.factory.makeDistributionSourcePackage()
-
-    def test_null_max_bug_heat(self):
-        self.assertEqual(None, self.target.max_bug_heat)
-
-    def test_null_total_bug_heat(self):
-        self.assertEqual(None, self.target.total_bug_heat)
-
-    def test_null_bug_count(self):
-        self.assertEqual(None, self.target.bug_count)
-
-
-class DistributionSourcePackageZeroRecalculateBugHeatCacheTest(
-    TestCaseWithFactory):
-    """Ensure distro source package cache values become zero properly."""
-
-    layer = LaunchpadZopelessLayer
-
-    def setUp(self):
-        TestCaseWithFactory.setUp(self)
-        self.target = self.factory.makeDistributionSourcePackage()
-        self.target.recalculateBugHeatCache()
-
-    def test_zero_max_bug_heat(self):
-        self.assertEqual(0, self.target.max_bug_heat)
-
-    def test_zero_total_bug_heat(self):
-        self.assertEqual(0, self.target.total_bug_heat)
-
-    def test_zero_bug_count(self):
-        self.assertEqual(0, self.target.bug_count)
-
-
-class DistributionSourcePackageMultipleBugsRecalculateBugHeatCacheTest(
-    TestCaseWithFactory):
-    """Ensure distro source package cache values are set properly."""
-
-    layer = LaunchpadZopelessLayer
-
-    def setUp(self):
-        TestCaseWithFactory.setUp(self)
-        self.target = self.factory.makeDistributionSourcePackage(with_db=True)
-        self.bugtask1 = self.factory.makeBugTask(target=self.target)
-        self.bugtask2 = self.factory.makeBugTask(target=self.target)
-        self.bugtask3 = self.factory.makeBugTask(target=self.target)
-        self.bugtask4 = self.factory.makeBugTask(target=self.target)
-        # A closed bug is not include in DSP bug heat calculations.
-        self.bugtask3.transitionToStatus(
-            BugTaskStatus.FIXRELEASED, self.target.distribution.owner)
-        # A duplicate bug is not include in DSP bug heat calculations.
-        self.bugtask4.bug.markAsDuplicate(self.bugtask1.bug)
-        # 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.
-        # target.recalculateBugHeatCache() should be called
-        # automatically by bug.setHeat().
-        bug1 = self.bugtask1.bug
-        bug2 = self.bugtask2.bug
-        bug3 = self.bugtask3.bug
-        bug1.setHeat(7)
-        bug2.setHeat(19)
-        bug3.setHeat(11)
-        Store.of(bug1).flush()
-        self.max_heat = max(bug1.heat, bug2.heat)
-        self.total_heat = sum([bug1.heat, bug2.heat])
-
-    def test_max_bug_heat(self):
-        self.assertEqual(self.max_heat, self.target.max_bug_heat)
-
-    def test_total_bug_heat(self):
-        self.assertEqual(self.total_heat, self.target.total_bug_heat)
-        self.failUnless(
-            self.target.total_bug_heat > self.target.max_bug_heat,
-            "Total bug heat should be more than the max bug heat, "
-            "since we know that multiple bugs have nonzero heat.")
-
-    def test_bug_count(self):
-        self.assertEqual(2, self.target.bug_count)
-
-
-class SourcePackageMaxHeatByTargetTest(
-    MaxHeatByTargetBase, unittest.TestCase):
-    """Ensure a source package has a max_bug_heat value that can be set."""
-
-    def setUp(self):
-        self.target = self.factory.makeSourcePackage()
-        self.delegates_setter = True
-
-
-class ProductSeriesMaxHeatByTargetTest(
-    MaxHeatByTargetBase, unittest.TestCase):
-    """Ensure a product series has a max_bug_heat value that can be set."""
-
-    def setUp(self):
-        self.target = self.factory.makeProductSeries()
-        self.delegates_setter = True
-
-
-class DistroSeriesMaxHeatByTargetTest(
-    MaxHeatByTargetBase, unittest.TestCase):
-    """Ensure a distro series has a max_bug_heat value that can be set."""
-
-    def setUp(self):
-        self.target = self.factory.makeDistroSeries()
-        self.delegates_setter = True
-
-
-class ProjectGroupMaxHeatByTargetTest(
-    MaxHeatByTargetBase, unittest.TestCase):
-    """Ensure a project group has a max_bug_heat value that can be set."""
-
-    def setUp(self):
-        self.target = self.factory.makeProject()

=== modified file 'lib/lp/bugs/tests/test_bugnomination.py'
--- lib/lp/bugs/tests/test_bugnomination.py	2011-12-30 06:14:56 +0000
+++ lib/lp/bugs/tests/test_bugnomination.py	2012-02-07 08:23:31 +0000
@@ -235,55 +235,3 @@
         self.assertFalse(nomination.canApprove(self.factory.makePerson()))
         self.assertTrue(nomination.canApprove(package_perm.person))
         self.assertTrue(nomination.canApprove(comp_perm.person))
-
-
-class TestApprovePerformance(TestCaseWithFactory):
-    """Test the performance of `BugNomination.approve`."""
-
-    layer = DatabaseFunctionalLayer
-
-    def check_heat_queries(self, nomination):
-        self.assertFalse(nomination.isApproved())
-        # Statement patterns we're looking for:
-        pattern = "^(SELECT Bug.heat|UPDATE .* max_bug_heat)"
-        matcher = re.compile(pattern, re.DOTALL | re.I).match
-        queries_heat = lambda statement: matcher(statement) is not None
-        with person_logged_in(nomination.target.owner):
-            flush_database_updates()
-            with StormStatementRecorder(queries_heat) as recorder:
-                nomination.approve(nomination.target.owner)
-        # Post-process the recorder to only have heat-related statements.
-        recorder.query_data = [
-            data for statement, data in izip(
-                recorder.statements, recorder.query_data)
-            if queries_heat(statement)]
-        self.addDetail(
-            "query_data", Content(UTF8_TEXT, lambda: [str(recorder)]))
-        # If there isn't at least one update to max_bug_heat it may mean that
-        # this test is no longer relevant.
-        self.assertThat(recorder, HasQueryCount(Not(Equals(0))))
-        # At present there are two updates to max_bug_heat because
-        # recalculateBugHeatCache is called twice, and, even though it is
-        # lazily evaluated, there are both explicit and implicit flushes in
-        # bugtask subscriber code.
-        self.assertThat(recorder, HasQueryCount(LessThan(3)))
-
-    def test_heat_queries_for_productseries(self):
-        # The number of heat-related queries when approving a product series
-        # nomination is as low as reasonably possible.
-        series = self.factory.makeProductSeries()
-        bug = self.factory.makeBug(product=series.product)
-        with person_logged_in(series.owner):
-            nomination = bug.addNomination(
-                target=series, owner=series.owner)
-        self.check_heat_queries(nomination)
-
-    def test_heat_queries_for_distroseries(self):
-        # The number of heat-related queries when approving a distro series
-        # nomination is as low as reasonably possible.
-        series = self.factory.makeDistroSeries()
-        bug = self.factory.makeBug(distribution=series.distribution)
-        with person_logged_in(series.owner):
-            nomination = bug.addNomination(
-                target=series, owner=series.owner)
-        self.check_heat_queries(nomination)

=== modified file 'lib/lp/bugs/tests/test_duplicate_handling.py'
--- lib/lp/bugs/tests/test_duplicate_handling.py	2012-01-01 02:58:52 +0000
+++ lib/lp/bugs/tests/test_duplicate_handling.py	2012-02-07 08:23:31 +0000
@@ -97,67 +97,3 @@
         self.assertEqual(bug.duplicateof, new_bug)
         self.assertEqual(dupe_one.duplicateof, new_bug)
         self.assertEqual(dupe_two.duplicateof, new_bug)
-
-    def makeBugForDistributionSourcePackage(self, sourcepackage,
-                                            with_random_target):
-        bug = self.factory.makeBug(
-            distribution=sourcepackage.distribution,
-            sourcepackagename=sourcepackage.sourcepackagename)
-        if with_random_target:
-            bug.addTask(
-                self.factory.makePerson(),
-                self.factory.makeDistributionSourcePackage())
-        return bug
-
-    def moveDuplicates(self, number_of_dupes, with_random_target):
-        # Create a bug with the given number of duplicates and
-        # then mark the bug as a duplicate of another bug.
-        # Return the number of SQL statements executed to
-        # update the target's bug heat cache
-        # (IBugTarget.recalculateBugHeatCache())
-        #
-        # We use a distributionsourcepackage as the bug target
-        # because we filter the recorded SQL statements by
-        # string.startswith(...), and the implementation of
-        # DistributionSourcePackage.recalculateBugHeatCache()
-        # is the only one that issues a "SELECT MAX(Bug.heat)..."
-        # query, making it more reliable to detect in the
-        # numerous recorded statements compared with the
-        # statements issued by BugTarget.recalculateBugHeatCache().
-        dsp = self.factory.makeDistributionSourcePackage()
-        master_bug = self.makeBugForDistributionSourcePackage(
-            dsp, with_random_target)
-        for count in xrange(number_of_dupes):
-            dupe = self.makeBugForDistributionSourcePackage(
-                dsp, with_random_target)
-            dupe.markAsDuplicate(master_bug)
-        new_master_bug = self.makeBugForDistributionSourcePackage(
-            dsp, with_random_target)
-        with StormStatementRecorder() as recorder:
-            master_bug.markAsDuplicate(new_master_bug)
-        target_heat_cache_statements = [
-            statement for statement in recorder.statements
-            if statement.startswith(
-                "SELECT MAX(Bug.heat), SUM(Bug.heat), COUNT(Bug.id)")]
-        return len(target_heat_cache_statements)
-
-    def test_move_duplicates_efficient_target_heat_cache_calculation(self):
-        # When bug A is marked as a duplicate of bug B, bug A's
-        # duplicates become duplicates of bug B too. This requires
-        # to set the heat of the duplicates to 0, and to recalculate
-        # the heat cache of each target. Ensure that the heat cache
-        # is computed only once per target.
-        #
-        # The query to retrieve the hottest bug for a target is quite
-        # slow (ca 200 msec) and should be executed exactly once per
-        # target.
-        self.assertEqual(1, self.moveDuplicates(2, with_random_target=False))
-        self.assertEqual(1, self.moveDuplicates(4, with_random_target=False))
-
-        # If each bug has two targets, one of them common, the other
-        # distinct for each bug, we still get one call for each target.
-        # For N duplicates, we have N distinct targets, we have
-        # the targets for the old master bug and for the new master bug,
-        # and one common target, i.e., N+3 targets for N duplicates.
-        self.assertEqual(5, self.moveDuplicates(2, with_random_target=True))
-        self.assertEqual(7, self.moveDuplicates(4, with_random_target=True))

=== modified file 'lib/lp/codehosting/scanner/tests/test_buglinks.py'
--- lib/lp/codehosting/scanner/tests/test_buglinks.py	2012-01-20 15:42:44 +0000
+++ lib/lp/codehosting/scanner/tests/test_buglinks.py	2012-02-07 08:23:31 +0000
@@ -128,8 +128,6 @@
         self.bug1.addTask(self.bug1.owner, distro)
         self.bug2 = self.factory.makeBug()
         self.new_db_branch = self.factory.makeAnyBranch()
-        removeSecurityProxy(distro).max_bug_heat = 0
-        removeSecurityProxy(dsp).max_bug_heat = 0
         self.layer.txn.commit()
 
     def getBugURL(self, bug):