Merge lp:~gmb/launchpad/another-checkwatches-keyerror-bug-497414 into lp:launchpad/db-devel

Proposed by Graham Binns
Status: Merged
Approved by: Gavin Panella
Approved revision: not available
Merged at revision: not available
Proposed branch: lp:~gmb/launchpad/another-checkwatches-keyerror-bug-497414
Merge into: lp:launchpad/db-devel
Diff against target: 128 lines (+93/-1)
2 files modified
lib/lp/bugs/scripts/checkwatches.py (+10/-1)
lib/lp/bugs/scripts/tests/test_checkwatches.py (+83/-0)
To merge this branch: bzr merge lp:~gmb/launchpad/another-checkwatches-keyerror-bug-497414
Reviewer Review Type Date Requested Status
Gavin Panella (community) Approve
Canonical Launchpad Engineering code Pending
Review via email: mp+16243@code.launchpad.net

Commit message

Catch another KeyError in checkwatches.

To post a comment you must log in.
Revision history for this message
Graham Binns (gmb) wrote :

This branch fixes bug 497414 by stopping a KeyError from being raised in checkwatches.

I've added a regression test for the bug and also a test to make sure that the new code logs an error appropriately.

Revision history for this message
Gavin Panella (allenap) wrote :

Lovely.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/bugs/scripts/checkwatches.py'
--- lib/lp/bugs/scripts/checkwatches.py 2009-12-15 16:28:20 +0000
+++ lib/lp/bugs/scripts/checkwatches.py 2010-01-04 11:41:16 +0000
@@ -789,7 +789,16 @@
789 )789 )
790790
791 for bug_id in all_remote_ids:791 for bug_id in all_remote_ids:
792 bug_watches = bug_watches_by_remote_bug[bug_id]792 try:
793 bug_watches = bug_watches_by_remote_bug[bug_id]
794 except KeyError:
795 # If there aren't any bug watches for this remote bug,
796 # just log a warning and carry on.
797 self.warning(
798 "Spurious remote bug ID: No watches found for "
799 "remote bug %s on %s" % (bug_id, remotesystem.baseurl))
800 continue
801
793 for bug_watch in bug_watches:802 for bug_watch in bug_watches:
794 bug_watch.lastchecked = UTC_NOW803 bug_watch.lastchecked = UTC_NOW
795 if bug_id in unmodified_remote_ids:804 if bug_id in unmodified_remote_ids:
796805
=== modified file 'lib/lp/bugs/scripts/tests/test_checkwatches.py'
--- lib/lp/bugs/scripts/tests/test_checkwatches.py 2009-12-21 16:08:35 +0000
+++ lib/lp/bugs/scripts/tests/test_checkwatches.py 2010-01-04 11:41:16 +0000
@@ -15,6 +15,8 @@
1515
16from lp.bugs.externalbugtracker.bugzilla import BugzillaAPI16from lp.bugs.externalbugtracker.bugzilla import BugzillaAPI
17from lp.bugs.scripts import checkwatches17from lp.bugs.scripts import checkwatches
18from lp.bugs.scripts.checkwatches import CheckWatchesErrorUtility
19from lp.bugs.tests.externalbugtracker import TestBugzillaAPIXMLRPCTransport
18from lp.testing import TestCaseWithFactory20from lp.testing import TestCaseWithFactory
1921
2022
@@ -23,6 +25,52 @@
23 return BugzillaAPI(bugtracker.baseurl)25 return BugzillaAPI(bugtracker.baseurl)
2426
2527
28class NonConnectingBugzillaAPI(BugzillaAPI):
29 """A non-connected version of the BugzillaAPI ExternalBugTracker."""
30
31 bugs = {
32 1: {'product': 'test-product'},
33 }
34
35 def getCurrentDBTime(self):
36 return None
37
38 def getExternalBugTrackerToUse(self):
39 return self
40
41 def getProductsForRemoteBugs(self, remote_bugs):
42 """Return the products for some remote bugs.
43
44 This method is basically the same as that of the superclass but
45 without the call to initializeRemoteBugDB().
46 """
47 bug_products = {}
48 for bug_id in bug_ids:
49 # If one of the bugs we're trying to get the product for
50 # doesn't exist, just skip it.
51 try:
52 actual_bug_id = self._getActualBugId(bug_id)
53 except BugNotFound:
54 continue
55
56 bug_dict = self._bugs[actual_bug_id]
57 bug_products[bug_id] = bug_dict['product']
58
59 return bug_products
60
61
62class NoBugWatchesByRemoteBugUpdater(checkwatches.BugWatchUpdater):
63 """A subclass of BugWatchUpdater with methods overridden for testing."""
64
65 def _getBugWatchesByRemoteBug(self, bug_watch_ids):
66 """Return an empty dict.
67
68 This method overrides _getBugWatchesByRemoteBug() so that bug
69 497141 can be regression-tested.
70 """
71 return {}
72
73
26class TestCheckwatchesWithSyncableGnomeProducts(TestCaseWithFactory):74class TestCheckwatchesWithSyncableGnomeProducts(TestCaseWithFactory):
2775
28 layer = LaunchpadZopelessLayer76 layer = LaunchpadZopelessLayer
@@ -63,5 +111,40 @@
63 gnome_bugzilla, [bug_watch_1, bug_watch_2])111 gnome_bugzilla, [bug_watch_1, bug_watch_2])
64112
65113
114class TestBugWatchUpdater(TestCaseWithFactory):
115
116 layer = LaunchpadZopelessLayer
117
118 def test_bug_497141(self):
119 # Regression test for bug 497141. KeyErrors raised in
120 # BugWatchUpdater.updateBugWatches() shouldn't cause
121 # checkwatches to abort.
122 updater = NoBugWatchesByRemoteBugUpdater(
123 transaction, QuietFakeLogger())
124
125 # Create a couple of bug watches for testing purposes.
126 bug_tracker = self.factory.makeBugTracker()
127 bug_watches = [
128 self.factory.makeBugWatch(bugtracker=bug_tracker)
129 for i in range(2)]
130
131 # Use a test XML-RPC transport to ensure no connections happen.
132 test_transport = TestBugzillaAPIXMLRPCTransport(bug_tracker.baseurl)
133 remote_system = NonConnectingBugzillaAPI(
134 bug_tracker.baseurl, xmlrpc_transport=test_transport)
135
136 # Calling updateBugWatches() shouldn't raise a KeyError, even
137 # though with our broken updater _getExternalBugTrackersAndWatches()
138 # will return an empty dict.
139 updater.updateBugWatches(remote_system, bug_watches)
140
141 # An error will have been logged instead of the KeyError being
142 # raised.
143 error_utility = CheckWatchesErrorUtility()
144 last_oops = error_utility.getLastOopsReport()
145 self.assertTrue(
146 last_oops.value.startswith('Spurious remote bug ID'))
147
148
66def test_suite():149def test_suite():
67 return unittest.TestLoader().loadTestsFromName(__name__)150 return unittest.TestLoader().loadTestsFromName(__name__)

Subscribers

People subscribed via source and target branches

to status/vote changes: