← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~wgrant/launchpad/xref-buglinks-cleanup into lp:launchpad

 

William Grant has proposed merging lp:~wgrant/launchpad/xref-buglinks-cleanup into lp:launchpad with lp:~wgrant/launchpad/xref-buglinks as a prerequisite.

Commit message:
BugCve/QuestionBug/SpecificationBug -> XRef, part 2: Delete old model.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~wgrant/launchpad/xref-buglinks-cleanup/+merge/272592

BugCve/QuestionBug/SpecificationBug -> XRef, part 2: Delete old model.

All the new feature flags die, and the old IBugLink implementations are gone.
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~wgrant/launchpad/xref-buglinks-cleanup into lp:launchpad.
=== modified file 'database/sampledata/current-dev.sql'
--- database/sampledata/current-dev.sql	2015-08-24 12:25:10 +0000
+++ database/sampledata/current-dev.sql	2015-09-28 12:57:18 +0000
@@ -11421,3 +11421,16 @@
 
 
 
+ALTER TABLE xref DISABLE TRIGGER ALL;
+
+INSERT INTO xref (from_type, from_id, from_id_int, to_type, to_id, to_id_int, creator, date_created, metadata) VALUES ('bug', '1', 1, 'cve', '1999-8979', NULL, NULL, '2015-09-28 04:56:11.203306', NULL);
+INSERT INTO xref (from_type, from_id, from_id_int, to_type, to_id, to_id_int, creator, date_created, metadata) VALUES ('bug', '1', 1, 'specification', '3', 3, NULL, '2015-09-28 04:56:11.203306', NULL);
+INSERT INTO xref (from_type, from_id, from_id_int, to_type, to_id, to_id_int, creator, date_created, metadata) VALUES ('bug', '2', 2, 'cve', '1999-2345', NULL, NULL, '2015-09-28 04:56:11.212965', NULL);
+INSERT INTO xref (from_type, from_id, from_id_int, to_type, to_id, to_id_int, creator, date_created, metadata) VALUES ('cve', '1999-2345', NULL, 'bug', '2', 2, NULL, '2015-09-28 04:56:11.212965', NULL);
+INSERT INTO xref (from_type, from_id, from_id_int, to_type, to_id, to_id_int, creator, date_created, metadata) VALUES ('cve', '1999-8979', NULL, 'bug', '1', 1, NULL, '2015-09-28 04:56:11.203306', NULL);
+INSERT INTO xref (from_type, from_id, from_id_int, to_type, to_id, to_id_int, creator, date_created, metadata) VALUES ('specification', '3', 3, 'bug', '1', 1, NULL, '2015-09-28 04:56:11.203306', NULL);
+
+
+ALTER TABLE xref ENABLE TRIGGER ALL;
+
+

=== modified file 'database/sampledata/current.sql'
--- database/sampledata/current.sql	2015-08-24 12:25:10 +0000
+++ database/sampledata/current.sql	2015-09-28 12:57:18 +0000
@@ -11336,3 +11336,16 @@
 
 
 
+ALTER TABLE xref DISABLE TRIGGER ALL;
+
+INSERT INTO xref (from_type, from_id, from_id_int, to_type, to_id, to_id_int, creator, date_created, metadata) VALUES ('bug', '1', 1, 'cve', '1999-8979', NULL, NULL, '2015-09-28 04:55:28.528879', NULL);
+INSERT INTO xref (from_type, from_id, from_id_int, to_type, to_id, to_id_int, creator, date_created, metadata) VALUES ('bug', '1', 1, 'specification', '3', 3, NULL, '2015-09-28 04:55:28.528879', NULL);
+INSERT INTO xref (from_type, from_id, from_id_int, to_type, to_id, to_id_int, creator, date_created, metadata) VALUES ('bug', '2', 2, 'cve', '1999-2345', NULL, NULL, '2015-09-28 04:55:28.540059', NULL);
+INSERT INTO xref (from_type, from_id, from_id_int, to_type, to_id, to_id_int, creator, date_created, metadata) VALUES ('cve', '1999-2345', NULL, 'bug', '2', 2, NULL, '2015-09-28 04:55:28.540059', NULL);
+INSERT INTO xref (from_type, from_id, from_id_int, to_type, to_id, to_id_int, creator, date_created, metadata) VALUES ('cve', '1999-8979', NULL, 'bug', '1', 1, NULL, '2015-09-28 04:55:28.528879', NULL);
+INSERT INTO xref (from_type, from_id, from_id_int, to_type, to_id, to_id_int, creator, date_created, metadata) VALUES ('specification', '3', 3, 'bug', '1', 1, NULL, '2015-09-28 04:55:28.528879', NULL);
+
+
+ALTER TABLE xref ENABLE TRIGGER ALL;
+
+

=== modified file 'database/schema/security.cfg'
--- database/schema/security.cfg	2015-09-28 12:57:18 +0000
+++ database/schema/security.cfg	2015-09-28 12:57:18 +0000
@@ -144,7 +144,6 @@
 public.bugaffectsperson                 = SELECT, INSERT, UPDATE, DELETE
 public.bugattachment                    = SELECT, INSERT, UPDATE, DELETE
 public.bugbranch                        = SELECT, INSERT, UPDATE, DELETE
-public.bugcve                           = SELECT, INSERT, DELETE
 public.bugnomination                    = SELECT, UPDATE
 public.bugnotification                  = SELECT, INSERT, UPDATE, DELETE
 public.bugnotificationattachment        = SELECT, INSERT
@@ -277,7 +276,6 @@
 public.project                          = SELECT
 public.publisherconfig                  = SELECT, INSERT, UPDATE, DELETE
 public.question                         = SELECT, INSERT, UPDATE
-public.questionbug                      = SELECT, INSERT, DELETE
 public.questionjob                      = SELECT, INSERT, UPDATE, DELETE
 public.questionmessage                  = SELECT, INSERT
 public.questionreopening                = SELECT, INSERT, UPDATE
@@ -302,7 +300,6 @@
 public.sourcepackagerecipedistroseries  = SELECT, INSERT, DELETE
 public.specification                    = SELECT, INSERT, UPDATE
 public.specificationbranch              = SELECT, INSERT, UPDATE, DELETE
-public.specificationbug                 = SELECT, INSERT, DELETE
 public.specificationdependency          = SELECT, INSERT, DELETE
 public.specificationmessage             = SELECT, INSERT
 public.specificationsubscription        = SELECT, INSERT, UPDATE, DELETE
@@ -598,7 +595,6 @@
 public.bug                              = SELECT, INSERT, UPDATE
 public.bugactivity                      = SELECT, INSERT
 public.bugaffectsperson                 = SELECT, INSERT, UPDATE, DELETE
-public.bugcve                           = SELECT, INSERT
 public.bugmessage                       = SELECT, INSERT, UPDATE
 public.bugmute                          = SELECT
 public.bugnomination                    = SELECT
@@ -642,7 +638,6 @@
 public.project                          = SELECT, UPDATE
 public.question                         = SELECT
 public.questionjob                      = SELECT, INSERT
-public.questionbug                      = SELECT
 public.questionsubscription             = SELECT
 public.section                          = SELECT
 public.sourcepackagename                = SELECT
@@ -890,7 +885,6 @@
 public.bug                              = SELECT, UPDATE
 public.bugactivity                      = SELECT, INSERT
 public.bugaffectsperson                 = SELECT, INSERT, UPDATE, DELETE
-public.bugcve                           = SELECT, INSERT
 public.bugmessage                       = SELECT, INSERT
 public.bugnomination                    = SELECT
 public.bugnotification                  = SELECT, INSERT
@@ -937,7 +931,6 @@
 public.project                          = SELECT
 public.publisherconfig                  = SELECT, INSERT
 public.question                         = SELECT
-public.questionbug                      = SELECT
 public.questionjob                      = SELECT, INSERT
 public.questionsubscription             = SELECT
 public.sourcepackagepublishinghistory   = SELECT, INSERT, UPDATE, DELETE
@@ -1288,7 +1281,6 @@
 public.personlanguage                   = SELECT
 public.product                          = SELECT
 public.question                         = SELECT, UPDATE
-public.questionbug                      = SELECT
 public.questionjob                      = SELECT, INSERT
 public.questionmessage                  = SELECT, INSERT
 public.questionsubscription             = SELECT
@@ -1347,7 +1339,6 @@
 public.bug                              = SELECT, UPDATE
 public.bugactivity                      = SELECT, INSERT
 public.bugaffectsperson                 = SELECT, INSERT, UPDATE, DELETE
-public.bugcve                           = SELECT, INSERT
 public.bugmessage                       = SELECT, INSERT
 public.bugmute                          = SELECT
 public.bugnomination                    = SELECT
@@ -1414,7 +1405,6 @@
 public.productseries                    = SELECT
 public.project                          = SELECT, UPDATE
 public.question                         = SELECT
-public.questionbug                      = SELECT
 public.questionjob                      = SELECT, INSERT
 public.questionsubscription             = SELECT
 public.section                          = SELECT, INSERT
@@ -1461,7 +1451,6 @@
 public.bug                              = SELECT, UPDATE
 public.bugactivity                      = SELECT, INSERT
 public.bugaffectsperson                 = SELECT, INSERT, UPDATE, DELETE
-public.bugcve                           = SELECT, INSERT
 public.bugmessage                       = SELECT, INSERT
 public.bugmute                          = SELECT
 public.bugnomination                    = SELECT
@@ -1530,7 +1519,6 @@
 public.project                          = SELECT, UPDATE
 public.publisherconfig                  = SELECT
 public.question                         = SELECT
-public.questionbug                      = SELECT
 public.questionjob                      = SELECT, INSERT
 public.questionsubscription             = SELECT
 public.section                          = SELECT
@@ -1617,7 +1605,6 @@
 public.productseries                    = SELECT
 public.project                          = SELECT, UPDATE
 public.question                         = SELECT
-public.questionbug                      = SELECT
 public.questionjob                      = SELECT, INSERT
 public.questionsubscription             = SELECT
 public.section                          = SELECT
@@ -1765,7 +1752,6 @@
 public.bugaffectsperson                 = SELECT, INSERT, UPDATE, DELETE
 public.bugattachment                    = SELECT, INSERT
 public.bugbranch                        = SELECT
-public.bugcve                           = SELECT, INSERT
 public.bugmessage                       = SELECT, INSERT
 public.bugmute                          = SELECT
 public.bugnomination                    = SELECT, INSERT, UPDATE
@@ -1824,7 +1810,6 @@
 public.productseries                    = SELECT
 public.project                          = SELECT, UPDATE
 public.question                         = SELECT, UPDATE
-public.questionbug                      = SELECT
 public.questionjob                      = SELECT, INSERT
 public.questionmessage                  = SELECT, INSERT
 public.questionsubscription             = SELECT

=== modified file 'lib/lp/answers/model/question.py'
--- lib/lp/answers/model/question.py	2015-09-28 12:57:18 +0000
+++ lib/lp/answers/model/question.py	2015-09-28 12:57:18 +0000
@@ -77,7 +77,6 @@
 from lp.bugs.interfaces.buglink import IBugLinkTarget
 from lp.bugs.interfaces.bugtask import BugTaskStatus
 from lp.bugs.model.buglinktarget import BugLinkTargetMixin
-from lp.coop.answersbugs.model import QuestionBug
 from lp.registry.interfaces.distribution import (
     IDistribution,
     IDistributionSet,
@@ -101,7 +100,6 @@
     )
 from lp.services.database.datetimecol import UtcDateTimeCol
 from lp.services.database.enumcol import EnumCol
-from lp.services.database.interfaces import IStore
 from lp.services.database.nl_search import nl_phrase_search
 from lp.services.database.sqlbase import (
     cursor,
@@ -110,7 +108,6 @@
     sqlvalues,
     )
 from lp.services.database.stormexpr import rank_by_fti
-from lp.services.features import getFeatureFlag
 from lp.services.mail.notificationrecipientset import NotificationRecipientSet
 from lp.services.messages.interfaces.message import IMessage
 from lp.services.messages.model.message import (
@@ -665,14 +662,9 @@
     @property
     def bugs(self):
         from lp.bugs.model.bug import Bug
-        if getFeatureFlag('bugs.xref_buglinks.query'):
-            bug_ids = [
-                int(id) for _, id in getUtility(IXRefSet).findFrom(
-                    (u'question', unicode(self.id)), types=[u'bug'])]
-        else:
-            bug_ids = list(IStore(QuestionBug).find(
-                QuestionBug,
-                QuestionBug.question == self).values(QuestionBug.bugID))
+        bug_ids = [
+            int(id) for _, id in getUtility(IXRefSet).findFrom(
+                (u'question', unicode(self.id)), types=[u'bug'])]
         return list(sorted(
             bulk.load(Bug, bug_ids), key=operator.attrgetter('id')))
 
@@ -693,16 +685,12 @@
 
     def createBugLink(self, bug):
         """See BugLinkTargetMixin."""
-        if not getFeatureFlag('bugs.xref_buglinks.write_old.disabled'):
-            QuestionBug(question=self, bug=bug)
         # XXX: Should set creator.
         getUtility(IXRefSet).create(
             {(u'question', unicode(self.id)): {(u'bug', unicode(bug.id)): {}}})
 
     def deleteBugLink(self, bug):
         """See BugLinkTargetMixin."""
-        if not getFeatureFlag('bugs.xref_buglinks.write_old.disabled'):
-            Store.of(self).find(QuestionBug, question=self, bug=bug).remove()
         getUtility(IXRefSet).delete(
             {(u'question', unicode(self.id)): [(u'bug', unicode(bug.id))]})
 
@@ -730,38 +718,26 @@
         # This query joins to bugtasks that are not BugTaskStatus.INVALID
         # because there are many bugtasks to one question. A question is
         # included when BugTask.status IS NULL.
-        if getFeatureFlag('bugs.xref_buglinks.query'):
-            bugtask_join = """
-                    LEFT OUTER JOIN XRef ON (
-                        XRef.from_type = 'question'
-                        AND XRef.from_id_int = Question.id
-                        AND XRef.to_type = 'bug')
-                    LEFT OUTER JOIN BugTask ON (
-                        BugTask.bug = XRef.to_id_int
-                        AND BugTask.status != %s)
-                """
-        else:
-            bugtask_join = """
-                    LEFT OUTER JOIN QuestionBug
-                        ON Question.id = QuestionBug.question
-                    LEFT OUTER JOIN BugTask ON (
-                        BugTask.bug = QuestionBug.bug
-                        AND BugTask.status != %s)
-                """
-        return Question.select(("""
+        return Question.select("""
             id in (SELECT Question.id
                 FROM Question
-                    %s
+                LEFT OUTER JOIN XRef ON (
+                    XRef.from_type = 'question'
+                    AND XRef.from_id_int = Question.id
+                    AND XRef.to_type = 'bug')
+                LEFT OUTER JOIN BugTask ON (
+                    BugTask.bug = XRef.to_id_int
+                    AND BugTask.status != %s)
                 WHERE
-                    Question.status IN (%%s, %%s)
+                    Question.status IN (%s, %s)
                     AND (Question.datelastresponse IS NULL
                          OR Question.datelastresponse < (CURRENT_TIMESTAMP
-                            AT TIME ZONE 'UTC' - interval '%%s days'))
+                            AT TIME ZONE 'UTC' - interval '%s days'))
                     AND Question.datelastquery < (CURRENT_TIMESTAMP
-                            AT TIME ZONE 'UTC' - interval '%%s days')
+                            AT TIME ZONE 'UTC' - interval '%s days')
                     AND Question.assignee IS NULL
                     AND BugTask.status IS NULL)
-            """ % bugtask_join) % sqlvalues(
+            """ % sqlvalues(
                 BugTaskStatus.INVALID,
                 QuestionStatus.OPEN, QuestionStatus.NEEDSINFO,
                 days_before_expiration, days_before_expiration))

=== modified file 'lib/lp/blueprints/model/specification.py'
--- lib/lp/blueprints/model/specification.py	2015-09-28 12:57:18 +0000
+++ lib/lp/blueprints/model/specification.py	2015-09-28 12:57:18 +0000
@@ -64,7 +64,6 @@
     ISpecificationSet,
     )
 from lp.blueprints.model.specificationbranch import SpecificationBranch
-from lp.blueprints.model.specificationbug import SpecificationBug
 from lp.blueprints.model.specificationdependency import (
     SpecificationDependency,
     )
@@ -102,7 +101,6 @@
     SQLBase,
     sqlvalues,
     )
-from lp.services.features import getFeatureFlag
 from lp.services.mail.helpers import get_contact_email_addresses
 from lp.services.propertycache import (
     cachedproperty,
@@ -796,22 +794,14 @@
     @property
     def bugs(self):
         from lp.bugs.model.bug import Bug
-        if getFeatureFlag('bugs.xref_buglinks.query'):
-            bug_ids = [
-                int(id) for _, id in getUtility(IXRefSet).findFrom(
-                    (u'specification', unicode(self.id)), types=[u'bug'])]
-        else:
-            bug_ids = list(IStore(SpecificationBug).find(
-                SpecificationBug,
-                SpecificationBug.specification == self).values(
-                    SpecificationBug.bugID))
+        bug_ids = [
+            int(id) for _, id in getUtility(IXRefSet).findFrom(
+                (u'specification', unicode(self.id)), types=[u'bug'])]
         return list(sorted(
             bulk.load(Bug, bug_ids), key=operator.attrgetter('id')))
 
     def createBugLink(self, bug):
         """See BugLinkTargetMixin."""
-        if not getFeatureFlag('bugs.xref_buglinks.write_old.disabled'):
-            SpecificationBug(specification=self, bug=bug)
         # XXX: Should set creator.
         getUtility(IXRefSet).create(
             {(u'specification', unicode(self.id)):
@@ -819,9 +809,6 @@
 
     def deleteBugLink(self, bug):
         """See BugLinkTargetMixin."""
-        if not getFeatureFlag('bugs.xref_buglinks.write_old.disabled'):
-            Store.of(self).find(
-                SpecificationBug, specification=self, bug=bug).remove()
         getUtility(IXRefSet).delete(
             {(u'specification', unicode(self.id)):
                 [(u'bug', unicode(bug.id))]})

=== modified file 'lib/lp/blueprints/tests/test_specification.py'
--- lib/lp/blueprints/tests/test_specification.py	2015-09-28 12:57:18 +0000
+++ lib/lp/blueprints/tests/test_specification.py	2015-09-28 12:57:18 +0000
@@ -59,7 +59,6 @@
     EditSpecificationByRelatedPeople,
     ViewSpecification,
     )
-from lp.services.features.testing import FeatureFixture
 from lp.services.propertycache import get_property_cache
 from lp.services.webapp.authorization import check_permission
 from lp.services.webapp.interaction import ANONYMOUS
@@ -877,19 +876,3 @@
         self.assertContentEqual([bug1], spec2.bugs)
         self.assertContentEqual([spec2], bug1.specifications)
         self.assertContentEqual([], bug2.specifications)
-
-
-class TestBugLinksWithXRef(TestBugLinks):
-
-    def setUp(self):
-        super(TestBugLinksWithXRef, self).setUp()
-        self.useFixture(FeatureFixture({'bugs.xref_buglinks.query': 'true'}))
-
-
-class TestBugLinksWithXRefAndNoOld(TestBugLinks):
-
-    def setUp(self):
-        super(TestBugLinksWithXRefAndNoOld, self).setUp()
-        self.useFixture(FeatureFixture({
-            'bugs.xref_buglinks.query': 'true',
-            'bugs.xref_buglinks.write_old.disabled': 'true'}))

=== modified file 'lib/lp/bugs/model/bug.py'
--- lib/lp/bugs/model/bug.py	2015-09-28 12:57:18 +0000
+++ lib/lp/bugs/model/bug.py	2015-09-28 12:57:18 +0000
@@ -204,7 +204,6 @@
     sqlvalues,
     )
 from lp.services.database.stormbase import StormBase
-from lp.services.features import getFeatureFlag
 from lp.services.fields import DuplicateBug
 from lp.services.helpers import shortlist
 from lp.services.librarian.interfaces import ILibraryFileAliasSet
@@ -375,49 +374,29 @@
 
     @property
     def cves(self):
-        from lp.bugs.model.bugcve import BugCve
         from lp.bugs.model.cve import Cve
-        if getFeatureFlag('bugs.xref_buglinks.query'):
-            xref_cve_sequences = [
-                sequence for _, sequence in getUtility(IXRefSet).findFrom(
-                    (u'bug', unicode(self.id)), types=[u'cve'])]
-            expr = Cve.sequence.is_in(xref_cve_sequences)
-        else:
-            old_cve_ids = list(IStore(BugCve).find(
-                BugCve,
-                BugCve.bug == self).values(BugCve.cveID))
-            expr = Cve.id.is_in(old_cve_ids)
+        xref_cve_sequences = [
+            sequence for _, sequence in getUtility(IXRefSet).findFrom(
+                (u'bug', unicode(self.id)), types=[u'cve'])]
+        expr = Cve.sequence.is_in(xref_cve_sequences)
         return list(sorted(
             IStore(Cve).find(Cve, expr), key=operator.attrgetter('sequence')))
 
     @property
     def questions(self):
         from lp.answers.model.question import Question
-        from lp.coop.answersbugs.model import QuestionBug
-        if getFeatureFlag('bugs.xref_buglinks.query'):
-            question_ids = [
-                int(id) for _, id in getUtility(IXRefSet).findFrom(
-                    (u'bug', unicode(self.id)), types=[u'question'])]
-        else:
-            question_ids = list(IStore(QuestionBug).find(
-                QuestionBug,
-                QuestionBug.bug == self).values(QuestionBug.questionID))
+        question_ids = [
+            int(id) for _, id in getUtility(IXRefSet).findFrom(
+                (u'bug', unicode(self.id)), types=[u'question'])]
         return list(sorted(
             bulk.load(Question, question_ids), key=operator.attrgetter('id')))
 
     @property
     def specifications(self):
         from lp.blueprints.model.specification import Specification
-        from lp.blueprints.model.specificationbug import SpecificationBug
-        if getFeatureFlag('bugs.xref_buglinks.query'):
-            spec_ids = [
-                int(id) for _, id in getUtility(IXRefSet).findFrom(
-                    (u'bug', unicode(self.id)), types=[u'specification'])]
-        else:
-            spec_ids = list(IStore(SpecificationBug).find(
-                SpecificationBug,
-                SpecificationBug.bug == self).values(
-                    SpecificationBug.specificationID))
+        spec_ids = [
+            int(id) for _, id in getUtility(IXRefSet).findFrom(
+                (u'bug', unicode(self.id)), types=[u'specification'])]
         return list(sorted(
             bulk.load(Specification, spec_ids), key=operator.attrgetter('id')))
 

=== removed file 'lib/lp/bugs/model/bugcve.py'
--- lib/lp/bugs/model/bugcve.py	2015-09-28 12:57:18 +0000
+++ lib/lp/bugs/model/bugcve.py	1970-01-01 00:00:00 +0000
@@ -1,22 +0,0 @@
-# Copyright 2009 Canonical Ltd.  This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
-
-__metaclass__ = type
-__all__ = ['BugCve']
-
-from sqlobject import ForeignKey
-
-from lp.services.database.constants import UTC_NOW
-from lp.services.database.datetimecol import UtcDateTimeCol
-from lp.services.database.sqlbase import SQLBase
-
-
-class BugCve(SQLBase):
-    """A table linking bugs and CVE entries."""
-
-    _table = 'BugCve'
-
-    # db field names
-    bug = ForeignKey(dbName='bug', foreignKey='Bug', notNull=True)
-    cve = ForeignKey(dbName='cve', foreignKey='Cve', notNull=True)
-    date_created = UtcDateTimeCol(notNull=True, default=UTC_NOW)

=== modified file 'lib/lp/bugs/model/bugtask.py'
--- lib/lp/bugs/model/bugtask.py	2015-09-28 12:57:18 +0000
+++ lib/lp/bugs/model/bugtask.py	2015-09-28 12:57:18 +0000
@@ -139,7 +139,6 @@
     SQLBase,
     sqlvalues,
     )
-from lp.services.features import getFeatureFlag
 from lp.services.helpers import shortlist
 from lp.services.propertycache import get_property_cache
 from lp.services.searchbuilder import any
@@ -879,7 +878,7 @@
                 new_status = BugTaskStatusSearch.INCOMPLETE_WITH_RESPONSE
 
         self._setStatusDateProperties(self.status, new_status, when=when)
-        
+
     def _setStatusDateProperties(self, old_status, new_status, when=None):
         if old_status == new_status:
             # No change in the status, so nothing to do.
@@ -1385,20 +1384,14 @@
     def getBugTaskBadgeProperties(self, bugtasks):
         """See `IBugTaskSet`."""
         # Import locally to avoid circular imports.
-        from lp.blueprints.model.specificationbug import SpecificationBug
         from lp.bugs.model.bug import Bug
         from lp.bugs.model.bugbranch import BugBranch
 
         bug_ids = set(bugtask.bugID for bugtask in bugtasks)
-        if getFeatureFlag('bugs.xref_buglinks.query'):
-            bug_ids_with_specifications = set(
-                int(id) for _, id in getUtility(IXRefSet).findFromMany(
-                    [(u'bug', unicode(bug_id)) for bug_id in bug_ids],
-                    types=[u'specification']).keys())
-        else:
-            bug_ids_with_specifications = set(IStore(SpecificationBug).find(
-                SpecificationBug.bugID,
-                SpecificationBug.bugID.is_in(bug_ids)))
+        bug_ids_with_specifications = set(
+            int(id) for _, id in getUtility(IXRefSet).findFromMany(
+                [(u'bug', unicode(bug_id)) for bug_id in bug_ids],
+                types=[u'specification']).keys())
         bug_ids_with_branches = set(IStore(BugBranch).find(
                 BugBranch.bugID, BugBranch.bugID.is_in(bug_ids)))
         # Badging looks up milestones too : eager load into the storm cache.

=== modified file 'lib/lp/bugs/model/bugtasksearch.py'
--- lib/lp/bugs/model/bugtasksearch.py	2015-09-28 12:57:18 +0000
+++ lib/lp/bugs/model/bugtasksearch.py	2015-09-28 12:57:18 +0000
@@ -39,7 +39,6 @@
 
 from lp.app.enums import PUBLIC_INFORMATION_TYPES
 from lp.app.interfaces.launchpad import ILaunchpadCelebrities
-from lp.blueprints.model.specificationbug import SpecificationBug
 from lp.bugs.errors import InvalidSearchParameters
 from lp.bugs.interfaces.bugattachment import BugAttachmentType
 from lp.bugs.interfaces.bugnomination import BugNominationStatus
@@ -60,7 +59,6 @@
     )
 from lp.bugs.model.bugattachment import BugAttachment
 from lp.bugs.model.bugbranch import BugBranch
-from lp.bugs.model.bugcve import BugCve
 from lp.bugs.model.bugmessage import BugMessage
 from lp.bugs.model.bugnomination import BugNomination
 from lp.bugs.model.bugsubscription import BugSubscription
@@ -95,7 +93,6 @@
     rank_by_fti,
     Unnest,
     )
-from lp.services.features import getFeatureFlag
 from lp.services.propertycache import get_property_cache
 from lp.services.searchbuilder import (
     all,
@@ -423,18 +420,13 @@
             BugTaskFlat.productseries == None))
 
     if params.has_cve:
-        if getFeatureFlag('bugs.xref_buglinks.query'):
-            where = [
-                XRef.from_type == u'bug',
-                XRef.from_id_int == BugTaskFlat.bug_id,
-                XRef.to_type == u'cve',
-                ]
-            extra_clauses.append(Exists(Select(
-                1, tables=[XRef], where=And(*where))))
-        else:
-            extra_clauses.append(
-                BugTaskFlat.bug_id.is_in(
-                    Select(BugCve.bugID, tables=[BugCve])))
+        where = [
+            XRef.from_type == u'bug',
+            XRef.from_id_int == BugTaskFlat.bug_id,
+            XRef.to_type == u'cve',
+            ]
+        extra_clauses.append(Exists(Select(
+            1, tables=[XRef], where=And(*where))))
 
     if params.attachmenttype is not None:
         if params.attachmenttype == BugAttachmentType.PATCH:
@@ -1024,26 +1016,17 @@
     linked_blueprints = params.linked_blueprints
 
     def make_clause(blueprints=None):
-        if getFeatureFlag('bugs.xref_buglinks.query'):
-            where = [
-                XRef.from_type == u'bug',
-                XRef.from_id_int == BugTaskFlat.bug_id,
-                XRef.to_type == u'specification',
-                ]
-            if blueprints is not None:
-                where.append(
-                    search_value_to_storm_where_condition(
-                        XRef.to_id_int, blueprints))
-            return Exists(Select(
-                1, tables=[XRef], where=And(*where)))
-        else:
-            where = [SpecificationBug.bugID == BugTaskFlat.bug_id]
-            if blueprints is not None:
-                where.append(
-                    search_value_to_storm_where_condition(
-                        SpecificationBug.specificationID, blueprints))
-            return Exists(Select(
-                1, tables=[SpecificationBug], where=And(*where)))
+        where = [
+            XRef.from_type == u'bug',
+            XRef.from_id_int == BugTaskFlat.bug_id,
+            XRef.to_type == u'specification',
+            ]
+        if blueprints is not None:
+            where.append(
+                search_value_to_storm_where_condition(
+                    XRef.to_id_int, blueprints))
+        return Exists(Select(
+            1, tables=[XRef], where=And(*where)))
 
     if linked_blueprints is None:
         return None

=== modified file 'lib/lp/bugs/model/cve.py'
--- lib/lp/bugs/model/cve.py	2015-09-28 12:57:18 +0000
+++ lib/lp/bugs/model/cve.py	2015-09-28 12:57:18 +0000
@@ -31,7 +31,6 @@
     ICveSet,
     )
 from lp.bugs.model.bug import Bug
-from lp.bugs.model.bugcve import BugCve
 from lp.bugs.model.buglinktarget import BugLinkTargetMixin
 from lp.bugs.model.cvereference import CveReference
 from lp.services.database import bulk
@@ -41,7 +40,6 @@
 from lp.services.database.interfaces import IStore
 from lp.services.database.sqlbase import SQLBase
 from lp.services.database.stormexpr import fti_search
-from lp.services.features import getFeatureFlag
 from lp.services.xref.interfaces import IXRefSet
 from lp.services.xref.model import XRef
 
@@ -77,14 +75,9 @@
 
     @property
     def bugs(self):
-        if getFeatureFlag('bugs.xref_buglinks.query'):
-            bug_ids = [
-                int(id) for _, id in getUtility(IXRefSet).findFrom(
-                    (u'cve', self.sequence), types=[u'bug'])]
-        else:
-            bug_ids = list(IStore(BugCve).find(
-                BugCve,
-                BugCve.cve == self).values(BugCve.bugID))
+        bug_ids = [
+            int(id) for _, id in getUtility(IXRefSet).findFrom(
+                (u'cve', self.sequence), types=[u'bug'])]
         return list(sorted(
             bulk.load(Bug, bug_ids), key=operator.attrgetter('id')))
 
@@ -100,16 +93,12 @@
 
     def createBugLink(self, bug):
         """See BugLinkTargetMixin."""
-        if not getFeatureFlag('bugs.xref_buglinks.write_old.disabled'):
-            BugCve(cve=self, bug=bug)
         # XXX: Should set creator.
         getUtility(IXRefSet).create(
             {(u'cve', self.sequence): {(u'bug', unicode(bug.id)): {}}})
 
     def deleteBugLink(self, bug):
         """See BugLinkTargetMixin."""
-        if not getFeatureFlag('bugs.xref_buglinks.write_old.disabled'):
-            Store.of(self).find(BugCve, cve=self, bug=bug).remove()
         getUtility(IXRefSet).delete(
             {(u'cve', self.sequence): [(u'bug', unicode(bug.id))]})
 
@@ -202,27 +191,12 @@
             return []
         store = Store.of(bugtasks[0])
 
-        if getFeatureFlag('bugs.xref_buglinks.query'):
-            xrefs = getUtility(IXRefSet).findFromMany(
-                [(u'bug', unicode(bug.id)) for bug in bugs], types=[u'cve'])
-            bugcve_ids = set()
-            for bug_key in xrefs:
-                for cve_key in xrefs[bug_key]:
-                    bugcve_ids.add((int(bug_key[1]), cve_key[1]))
-        else:
-            # Do not use BugCve instances: Storm may need a very long time
-            # to look up the bugs and CVEs referenced by a BugCve instance
-            # when the +cve view of a distroseries is rendered: There may
-            # be a few thousand (bug, CVE) tuples, while the number of bugs
-            # and CVEs is in the order of hundred. It is much more efficient
-            # to retrieve just (Bug.id, Cve.sequence) from the BugCve
-            # table and to map this to (Bug, CVE) here, instead of
-            # letting Storm look up the CVE and bug for a BugCve
-            # instance, even if bugs and CVEs are bulk loaded.
-            bug_ids = [bug.id for bug in bugs]
-            bugcve_ids = store.find(
-                (BugCve.bugID, Cve.sequence),
-                Cve.id == BugCve.cveID, In(BugCve.bugID, bug_ids))
+        xrefs = getUtility(IXRefSet).findFromMany(
+            [(u'bug', unicode(bug.id)) for bug in bugs], types=[u'cve'])
+        bugcve_ids = set()
+        for bug_key in xrefs:
+            for cve_key in xrefs[bug_key]:
+                bugcve_ids.add((int(bug_key[1]), cve_key[1]))
 
         bugcve_ids = list(sorted(bugcve_ids))
 
@@ -241,8 +215,5 @@
 
     def getBugCveCount(self):
         """See ICveSet."""
-        if getFeatureFlag('bugs.xref_buglinks.query'):
-            return IStore(XRef).find(
-                XRef, XRef.from_type == u'bug', XRef.to_type == u'cve').count()
-        else:
-            return BugCve.select().count()
+        return IStore(XRef).find(
+            XRef, XRef.from_type == u'bug', XRef.to_type == u'cve').count()

=== modified file 'lib/lp/bugs/model/tests/test_bugtask.py'
--- lib/lp/bugs/model/tests/test_bugtask.py	2015-09-28 12:57:18 +0000
+++ lib/lp/bugs/model/tests/test_bugtask.py	2014-07-08 09:53:50 +0000
@@ -526,22 +526,6 @@
         ])
 
 
-class TestBugTaskBadgesWithXRef(TestBugTaskBadges):
-
-    def setUp(self):
-        super(TestBugTaskBadges, self).setUp()
-        self.useFixture(FeatureFixture({'bugs.xref_buglinks.query': 'true'}))
-
-
-class TestBugTaskBadgesWithXRefAndNoOld(TestBugTaskBadges):
-
-    def setUp(self):
-        super(TestBugTaskBadges, self).setUp()
-        self.useFixture(FeatureFixture({
-            'bugs.xref_buglinks.query': 'true',
-            'bugs.xref_buglinks.write_old.disabled': 'true'}))
-
-
 class TestBugTaskPrivacy(TestCaseWithFactory):
     """Verify that the bug is either private or public.
 

=== modified file 'lib/lp/bugs/model/tests/test_bugtasksearch.py'
--- lib/lp/bugs/model/tests/test_bugtasksearch.py	2015-09-28 12:57:18 +0000
+++ lib/lp/bugs/model/tests/test_bugtasksearch.py	2015-09-28 12:57:18 +0000
@@ -67,7 +67,6 @@
 from lp.registry.model.person import Person
 from lp.services.database.interfaces import IStore
 from lp.services.database.sqlbase import convert_storm_clause_to_string
-from lp.services.features.testing import FeatureFixture
 from lp.services.searchbuilder import (
     all,
     any,
@@ -420,16 +419,6 @@
                 BugBlueprintSearch.BUGS_WITHOUT_BLUEPRINTS))
         self.assertSearchFinds(params, self.bugtasks[1:])
 
-    def test_blueprints_linked_with_xref(self):
-        self.useFixture(FeatureFixture({'bugs.xref_buglinks.query': 'true'}))
-        self.test_blueprints_linked()
-
-    def test_blueprints_linked_with_xref_and_no_old(self):
-        self.useFixture(FeatureFixture({
-            'bugs.xref_buglinks.query': 'true',
-            'bugs.xref_buglinks.write_old.disabled': 'true'}))
-        self.test_blueprints_linked()
-
     def test_limit_search_to_one_bug(self):
         # Search results can be limited to a given bug.
         params = self.getBugTaskSearchParams(
@@ -503,16 +492,6 @@
         params = self.getBugTaskSearchParams(user=None, has_cve=True)
         self.assertSearchFinds(params, self.bugtasks[:1])
 
-    def test_has_cve_with_xref(self):
-        self.useFixture(FeatureFixture({'bugs.xref_buglinks.query': 'true'}))
-        self.test_has_cve()
-
-    def test_has_cve_with_xref_and_no_old(self):
-        self.useFixture(FeatureFixture({
-            'bugs.xref_buglinks.query': 'true',
-            'bugs.xref_buglinks.write_old.disabled': 'true'}))
-        self.test_has_cve()
-
     def test_sort_by_milestone_name(self):
         expected = self.setUpMilestoneSorting()
         params = self.getBugTaskSearchParams(

=== modified file 'lib/lp/bugs/tests/test_cve.py'
--- lib/lp/bugs/tests/test_cve.py	2015-09-28 12:57:18 +0000
+++ lib/lp/bugs/tests/test_cve.py	2015-09-28 12:57:18 +0000
@@ -7,7 +7,6 @@
 
 from lp.bugs.interfaces.bugtasksearch import BugTaskSearchParams
 from lp.bugs.interfaces.cve import ICveSet
-from lp.services.features.testing import FeatureFixture
 from lp.testing import (
     login_person,
     person_logged_in,
@@ -99,22 +98,6 @@
         self.assertEqual(base, getUtility(ICveSet).getBugCveCount())
 
 
-class TestCveSetWithXRef(TestCveSet):
-
-    def setUp(self):
-        self.useFixture(FeatureFixture({'bugs.xref_buglinks.query': 'true'}))
-        super(TestCveSetWithXRef, self).setUp()
-
-
-class TestCveSetWithXRefAndNoOld(TestCveSet):
-
-    def setUp(self):
-        self.useFixture(FeatureFixture({
-            'bugs.xref_buglinks.query': 'true',
-            'bugs.xref_buglinks.write_old.disabled': 'true'}))
-        super(TestCveSetWithXRefAndNoOld, self).setUp()
-
-
 class TestBugLinks(TestCaseWithFactory):
 
     layer = DatabaseFunctionalLayer
@@ -150,19 +133,3 @@
         self.assertContentEqual([bug1], cve2.bugs)
         self.assertContentEqual([cve2], bug1.cves)
         self.assertContentEqual([], bug2.cves)
-
-
-class TestBugLinksWithXRef(TestBugLinks):
-
-    def setUp(self):
-        super(TestBugLinksWithXRef, self).setUp()
-        self.useFixture(FeatureFixture({'bugs.xref_buglinks.query': 'true'}))
-
-
-class TestBugLinksWithXRefAndNoOld(TestBugLinks):
-
-    def setUp(self):
-        super(TestBugLinksWithXRefAndNoOld, self).setUp()
-        self.useFixture(FeatureFixture({
-            'bugs.xref_buglinks.query': 'true',
-            'bugs.xref_buglinks.write_old.disabled': 'true'}))

=== removed file 'lib/lp/coop/answersbugs/model.py'
--- lib/lp/coop/answersbugs/model.py	2015-09-28 12:57:18 +0000
+++ lib/lp/coop/answersbugs/model.py	1970-01-01 00:00:00 +0000
@@ -1,25 +0,0 @@
-# Copyright 2009-2010 Canonical Ltd.  This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
-
-"""SQLBase implementation of IQuestionBug."""
-
-__metaclass__ = type
-
-__all__ = ['QuestionBug']
-
-from sqlobject import ForeignKey
-
-from lp.services.database.constants import UTC_NOW
-from lp.services.database.datetimecol import UtcDateTimeCol
-from lp.services.database.sqlbase import SQLBase
-
-
-class QuestionBug(SQLBase):
-    """A link between a question and a bug."""
-
-    _table = 'QuestionBug'
-
-    question = ForeignKey(
-        dbName='question', foreignKey='Question', notNull=True)
-    bug = ForeignKey(dbName='bug', foreignKey='Bug', notNull=True)
-    date_created = UtcDateTimeCol(notNull=True, default=UTC_NOW)

=== modified file 'lib/lp/coop/answersbugs/tests/test_questionbug.py'
--- lib/lp/coop/answersbugs/tests/test_questionbug.py	2015-09-28 12:57:18 +0000
+++ lib/lp/coop/answersbugs/tests/test_questionbug.py	2015-09-28 12:57:18 +0000
@@ -1,7 +1,6 @@
 # Copyright 2015 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
-from lp.services.features.testing import FeatureFixture
 from lp.testing import (
     login_person,
     TestCaseWithFactory,
@@ -44,19 +43,3 @@
         self.assertContentEqual([bug1], question2.bugs)
         self.assertContentEqual([question2], bug1.questions)
         self.assertContentEqual([], bug2.questions)
-
-
-class TestQuestionBugLinksWithXRef(TestQuestionBugLinks):
-
-    def setUp(self):
-        super(TestQuestionBugLinksWithXRef, self).setUp()
-        self.useFixture(FeatureFixture({'bugs.xref_buglinks.query': 'true'}))
-
-
-class TestQuestionBugLinksWithXRefAndNoOld(TestQuestionBugLinks):
-
-    def setUp(self):
-        super(TestQuestionBugLinksWithXRefAndNoOld, self).setUp()
-        self.useFixture(FeatureFixture({
-            'bugs.xref_buglinks.query': 'true',
-            'bugs.xref_buglinks.write_old.disabled': 'true'}))

=== modified file 'lib/lp/scripts/garbo.py'
--- lib/lp/scripts/garbo.py	2015-09-28 12:57:18 +0000
+++ lib/lp/scripts/garbo.py	2015-07-22 07:09:12 +0000
@@ -81,7 +81,6 @@
 from lp.services.database.bulk import (
     create,
     dbify_value,
-    load_related,
     )
 from lp.services.database.constants import UTC_NOW
 from lp.services.database.interfaces import IMasterStore
@@ -1679,66 +1678,6 @@
                 transaction.abort()
 
 
-class BugXRefMigrator(TunableLoop):
-    """Creates an XRef record for each former IBugLink."""
-
-    maximum_chunk_size = 5000
-
-    def __init__(self, log, abort_time=None):
-        super(BugXRefMigrator, self).__init__(log, abort_time)
-        self.start_at = 1
-        self.store = IMasterStore(Bug)
-
-    def findBugs(self):
-        if not getFeatureFlag('bugs.xref_buglinks.garbo.enabled'):
-            return EmptyResultSet()
-        return self.store.find(
-            Bug, Bug.id >= self.start_at).order_by(Bug.id)
-
-    def isDone(self):
-        return self.findBugs().is_empty()
-
-    def __call__(self, chunk_size):
-        # Grab a chunk of Bug IDs.
-        # Find all QuestionBugs, SpecificationBugs and BugCves for each
-        # of those bugs.
-        # Compose a list of link IDs that should exist.
-        # Perform a bulk XRef find for all of those.
-        # Delete any extras, create any missing.
-        from lp.blueprints.model.specificationbug import SpecificationBug
-        from lp.bugs.model.bugcve import BugCve
-        from lp.bugs.model.cve import Cve
-        from lp.coop.answersbugs.model import QuestionBug
-        from lp.services.xref.interfaces import IXRefSet
-        bug_ids = list(self.findBugs()[:chunk_size].values(Bug.id))
-        qbs = list(self.store.find(
-            QuestionBug, QuestionBug.bugID.is_in(bug_ids)))
-        sbs = list(self.store.find(
-            SpecificationBug, SpecificationBug.bugID.is_in(bug_ids)))
-        bcs = list(self.store.find(BugCve, BugCve.bugID.is_in(bug_ids)))
-        wanted = {(u'bug', unicode(bug_id)): {} for bug_id in bug_ids}
-        for qb in qbs:
-            wanted[(u'bug', unicode(qb.bugID))][
-                (u'question', unicode(qb.questionID))] = {
-                    'date_created': qb.date_created}
-        for sb in sbs:
-            wanted[(u'bug', unicode(sb.bugID))][
-                (u'specification', unicode(sb.specificationID))] = {}
-        load_related(Cve, bcs, ['cveID'])
-        for bc in bcs:
-            wanted[(u'bug', unicode(bc.bugID))][
-                (u'cve', unicode(bc.cve.sequence))] = {}
-        existing = getUtility(IXRefSet).findFromMany(wanted.keys())
-        needed = {
-            bug: {
-                other: meta for other, meta in others.iteritems()
-                if other not in existing.get(bug, {})}
-            for bug, others in wanted.iteritems() if others}
-        getUtility(IXRefSet).create(needed)
-        self.start_at = bug_ids[-1] + 1
-        transaction.commit()
-
-
 class FrequentDatabaseGarbageCollector(BaseDatabaseGarbageCollector):
     """Run every 5 minutes.
 
@@ -1775,7 +1714,6 @@
         DuplicateSessionPruner,
         RevisionCachePruner,
         UnusedSessionPruner,
-        BugXRefMigrator,
         ]
     experimental_tunable_loops = []
 

=== modified file 'lib/lp/scripts/tests/test_garbo.py'
--- lib/lp/scripts/tests/test_garbo.py	2015-09-28 12:57:18 +0000
+++ lib/lp/scripts/tests/test_garbo.py	2015-07-22 07:09:12 +0000
@@ -1433,94 +1433,6 @@
         for person in people_enf_true:
             _assert_enf_by_person(person, True)
 
-    def test_BugXRefMigrator(self):
-        from testtools.matchers import (
-            Equals,
-            Is,
-            MatchesDict,
-            Not,
-            )
-
-        from lp.bugs.model.bug import Bug
-        from lp.bugs.model.bugcve import BugCve
-        from lp.blueprints.model.specificationbug import SpecificationBug
-        from lp.coop.answersbugs.model import QuestionBug
-        from lp.services.database.interfaces import IStore
-        from lp.services.xref.interfaces import IXRefSet
-
-        switch_dbuser('testadmin')
-        self.useFixture(FeatureFixture(
-            {'bugs.xref_buglinks.garbo.enabled': 'on'}))
-        store = IStore(Bug)
-
-        # The first bug has a spec and a question.
-        bug1 = self.factory.makeBug()
-        spec1 = self.factory.makeSpecification()
-        sb1 = SpecificationBug(specification=spec1, bug=bug1)
-        store.add(sb1)
-        question1 = self.factory.makeQuestion()
-        qb1 = QuestionBug(question=question1, bug=bug1)
-        store.add(qb1)
-
-        # A second bug has a question and a CVE.
-        bug2 = self.factory.makeBug()
-        question2 = self.factory.makeQuestion()
-        qb2 = QuestionBug(question=question2, bug=bug2)
-        store.add(qb2)
-        cve2 = self.factory.makeCVE(sequence='2099-1234')
-        bc2 = BugCve(bug=bug2, cve=cve2)
-        store.add(bc2)
-
-        # Bug the third is all alone.
-        bug3 = self.factory.makeBug()
-
-        # Bug four has just a spec.
-        bug4 = self.factory.makeBug()
-        spec4 = self.factory.makeSpecification()
-        sb4 = SpecificationBug(specification=spec4, bug=bug4)
-        store.add(sb4)
-
-        # Initially the new XRef table has no links for the bugs.
-        self.assertEqual(
-            {},
-            getUtility(IXRefSet).findFromMany(
-                (u'bug', unicode(bug.id)) for bug in (bug1, bug2, bug3, bug4)))
-
-        # Garbo fills in links for each QuestionBug, SpecificationBug
-        # and BugCve.
-        self.runHourly()
-        matches_expected = MatchesDict({
-            (u'bug', unicode(bug1.id)): MatchesDict({
-                (u'specification', unicode(spec1.id)): MatchesDict({
-                    'metadata': Is(None), 'creator': Is(None),
-                    'date_created': Not(Is(None))}),
-                (u'question', unicode(question1.id)): MatchesDict({
-                    'metadata': Is(None), 'creator': Is(None),
-                    'date_created': Equals(qb1.date_created)}),
-                }),
-            (u'bug', unicode(bug2.id)): MatchesDict({
-                (u'question', unicode(question2.id)): MatchesDict({
-                    'metadata': Is(None), 'creator': Is(None),
-                    'date_created': Equals(qb2.date_created)}),
-                (u'cve', cve2.sequence): MatchesDict({
-                    'metadata': Is(None), 'creator': Is(None),
-                    'date_created': Not(Is(None))}),
-                }),
-            (u'bug', unicode(bug4.id)): MatchesDict({
-                (u'specification', unicode(spec4.id)): MatchesDict({
-                    'metadata': Is(None), 'creator': Is(None),
-                    'date_created': Not(Is(None))}),
-                }),
-            })
-        self.assertThat(
-            getUtility(IXRefSet).findFromMany(
-                (u'bug', unicode(bug.id)) for bug in (bug1, bug2, bug3, bug4)),
-            matches_expected)
-
-        # A second run is harmless.
-        self.runHourly()
-
-
 
 class TestGarboTasks(TestCaseWithFactory):
     layer = LaunchpadZopelessLayer


Follow ups