launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #06263
[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):