Merge lp:~cjwatson/launchpad/explicit-proxy-roundup into lp:launchpad
- explicit-proxy-roundup
- Merge into devel
Proposed by
Colin Watson
Status: | Merged |
---|---|
Merged at revision: | 18695 |
Proposed branch: | lp:~cjwatson/launchpad/explicit-proxy-roundup |
Merge into: | lp:launchpad |
Prerequisite: | lp:~cjwatson/launchpad/explicit-proxy-github |
Diff against target: |
359 lines (+105/-74) 5 files modified
lib/lp/bugs/doc/bugwatch.txt (+3/-1) lib/lp/bugs/doc/checkwatches.txt (+28/-28) lib/lp/bugs/doc/externalbugtracker-roundup.txt (+21/-19) lib/lp/bugs/externalbugtracker/roundup.py (+5/-5) lib/lp/bugs/tests/externalbugtracker.py (+48/-21) |
To merge this branch: | bzr merge lp:~cjwatson/launchpad/explicit-proxy-roundup |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
William Grant | code | Approve | |
Review via email: mp+348428@code.launchpad.net |
Commit message
Convert the Roundup external bug tracker to urlfetch.
Description of the change
I experimented with a couple of different approaches to converting the doctests, and eventually decided that the most readable option was to keep TestRoundup and add some responses-based helper code to it. This is done in such a way that it can be reused for the other test tracker subclasses.
To post a comment you must log in.
Revision history for this message
William Grant (wgrant) : | # |
review:
Approve
(code)
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'lib/lp/bugs/doc/bugwatch.txt' | |||
2 | --- lib/lp/bugs/doc/bugwatch.txt 2013-04-11 04:50:27 +0000 | |||
3 | +++ lib/lp/bugs/doc/bugwatch.txt 2018-06-23 00:01:05 +0000 | |||
4 | @@ -465,7 +465,9 @@ | |||
5 | 465 | >>> from lp.bugs.scripts.checkwatches import CheckwatchesMaster | 465 | >>> from lp.bugs.scripts.checkwatches import CheckwatchesMaster |
6 | 466 | >>> bug_watch_updater = CheckwatchesMaster(transaction, FakeLogger()) | 466 | >>> bug_watch_updater = CheckwatchesMaster(transaction, FakeLogger()) |
7 | 467 | >>> external_bugtracker = TestRoundup(bug_tracker.baseurl) | 467 | >>> external_bugtracker = TestRoundup(bug_tracker.baseurl) |
9 | 468 | >>> bug_watch_updater.updateBugWatches(external_bugtracker, [bug_watch]) | 468 | >>> with external_bugtracker.responses(): |
10 | 469 | ... bug_watch_updater.updateBugWatches( | ||
11 | 470 | ... external_bugtracker, [bug_watch]) | ||
12 | 469 | INFO Updating 1 watches for 1 bugs on http://some.where | 471 | INFO Updating 1 watches for 1 bugs on http://some.where |
13 | 470 | 472 | ||
14 | 471 | >>> bug.bugtasks[0].status.title | 473 | >>> bug.bugtasks[0].status.title |
15 | 472 | 474 | ||
16 | === modified file 'lib/lp/bugs/doc/checkwatches.txt' | |||
17 | --- lib/lp/bugs/doc/checkwatches.txt 2016-12-22 16:32:38 +0000 | |||
18 | +++ lib/lp/bugs/doc/checkwatches.txt 2018-06-23 00:01:05 +0000 | |||
19 | @@ -15,8 +15,8 @@ | |||
20 | 15 | >>> transaction.commit() | 15 | >>> transaction.commit() |
21 | 16 | 16 | ||
22 | 17 | We set a default timeout on checkwatches to 30 seconds. In order to test | 17 | We set a default timeout on checkwatches to 30 seconds. In order to test |
25 | 18 | this, we can monkey-patch urllib2.urlopen so that it always raises a | 18 | this, we can inject a mock timeout using `responses` and call the |
26 | 19 | timeout and call the checkwatches cronscript machinery directly. | 19 | checkwatches cronscript machinery directly. |
27 | 20 | 20 | ||
28 | 21 | First, we create some bug watches to test with: | 21 | First, we create some bug watches to test with: |
29 | 22 | 22 | ||
30 | @@ -51,30 +51,31 @@ | |||
31 | 51 | 51 | ||
32 | 52 | >>> login('no-priv@canonical.com') | 52 | >>> login('no-priv@canonical.com') |
33 | 53 | 53 | ||
35 | 54 | Next, we monkey-patch urllib2.urlopen so that it always times out. | 54 | Next, we ensure that the request always times out. |
36 | 55 | 55 | ||
37 | 56 | The timeout will not produce an OOPS report; they happen routinely and | 56 | The timeout will not produce an OOPS report; they happen routinely and |
38 | 57 | require no action from the Launchpad end. | 57 | require no action from the Launchpad end. |
39 | 58 | 58 | ||
40 | 59 | >>> from contextlib import contextmanager | ||
41 | 60 | >>> import re | ||
42 | 59 | >>> import socket | 61 | >>> import socket |
46 | 60 | >>> import urllib2 | 62 | >>> import responses |
44 | 61 | >>> urlopen = urllib2.urlopen | ||
45 | 62 | |||
47 | 63 | >>> from lp.testing.fixture import CaptureOops | 63 | >>> from lp.testing.fixture import CaptureOops |
54 | 64 | >>> capture = CaptureOops() | 64 | |
55 | 65 | >>> capture.setUp() | 65 | >>> @contextmanager |
56 | 66 | >>> def do_not_urlopen(url=None, data=None, timeout=None): | 66 | ... def timeout_requests(): |
57 | 67 | ... raise socket.timeout("Connection timed out.") | 67 | ... with responses.RequestsMock() as requests_mock: |
58 | 68 | >>> try: | 68 | ... requests_mock.add( |
59 | 69 | ... urllib2.urlopen = do_not_urlopen | 69 | ... 'GET', re.compile(r'.*'), |
60 | 70 | ... body=socket.timeout('Connection timed out.')) | ||
61 | 71 | ... yield | ||
62 | 72 | |||
63 | 73 | >>> with CaptureOops() as capture, timeout_requests(): | ||
64 | 70 | ... updater = CheckwatchesMaster(transaction.manager) | 74 | ... updater = CheckwatchesMaster(transaction.manager) |
65 | 71 | ... updater.updateBugTrackers( | 75 | ... updater.updateBugTrackers( |
66 | 72 | ... bug_tracker_names=[example_bug_tracker_name]) | 76 | ... bug_tracker_names=[example_bug_tracker_name]) |
70 | 73 | ... finally: | 77 | ... print(capture.oopses) |
68 | 74 | ... urllib2.urlopen = urlopen | ||
69 | 75 | >>> capture.oopses | ||
71 | 76 | [] | 78 | [] |
72 | 77 | >>> capture.cleanUp() | ||
73 | 78 | 79 | ||
74 | 79 | Errors that occur when updating a bug watch are recorded against that | 80 | Errors that occur when updating a bug watch are recorded against that |
75 | 80 | bug watch. The timeout will be recorded against the bug watch we just | 81 | bug watch. The timeout will be recorded against the bug watch we just |
76 | @@ -146,8 +147,8 @@ | |||
77 | 146 | 147 | ||
78 | 147 | Since our example bug tracker is a Roundup bug tracker we can | 148 | Since our example bug tracker is a Roundup bug tracker we can |
79 | 148 | monkey-patch the Roundup ExternalBugTrackerClass in order to set its | 149 | monkey-patch the Roundup ExternalBugTrackerClass in order to set its |
82 | 149 | batch size. We will also monkey-patch urllib2.urlopen again so that no | 150 | batch size. We will also insert a mock response again so that no requests |
83 | 150 | requests are actually made. | 151 | are actually made. |
84 | 151 | 152 | ||
85 | 152 | >>> from lp.services.log.logger import FakeLogger | 153 | >>> from lp.services.log.logger import FakeLogger |
86 | 153 | >>> from lp.bugs import externalbugtracker | 154 | >>> from lp.bugs import externalbugtracker |
87 | @@ -156,16 +157,15 @@ | |||
88 | 156 | >>> updater = CheckwatchesMaster(transaction.manager) | 157 | >>> updater = CheckwatchesMaster(transaction.manager) |
89 | 157 | >>> original_log = updater.logger | 158 | >>> original_log = updater.logger |
90 | 158 | >>> batch_size = externalbugtracker.Roundup.batch_size | 159 | >>> batch_size = externalbugtracker.Roundup.batch_size |
101 | 159 | >>> try: | 160 | >>> with timeout_requests(): |
102 | 160 | ... urllib2.urlopen = do_not_urlopen | 161 | ... try: |
103 | 161 | ... externalbugtracker.Roundup.batch_size = 5 | 162 | ... externalbugtracker.Roundup.batch_size = 5 |
104 | 162 | ... transaction.commit() | 163 | ... transaction.commit() |
105 | 163 | ... updater.logger = FakeLogger() | 164 | ... updater.logger = FakeLogger() |
106 | 164 | ... updater.updateBugTrackers([example_bug_tracker_name]) | 165 | ... updater.updateBugTrackers([example_bug_tracker_name]) |
107 | 165 | ... finally: | 166 | ... finally: |
108 | 166 | ... updater.logger = original_log | 167 | ... updater.logger = original_log |
109 | 167 | ... externalbugtracker.Roundup.batch_size = batch_size | 168 | ... externalbugtracker.Roundup.batch_size = batch_size |
100 | 168 | ... urllib2.urlopen = urlopen | ||
110 | 169 | DEBUG No global batch size specified. | 169 | DEBUG No global batch size specified. |
111 | 170 | INFO Updating 5 watches for 5 bugs on http://bugs.example.com | 170 | INFO Updating 5 watches for 5 bugs on http://bugs.example.com |
112 | 171 | INFO Connection timed out when updating ... | 171 | INFO Connection timed out when updating ... |
113 | 172 | 172 | ||
114 | === modified file 'lib/lp/bugs/doc/externalbugtracker-roundup.txt' | |||
115 | --- lib/lp/bugs/doc/externalbugtracker-roundup.txt 2012-12-26 01:32:19 +0000 | |||
116 | +++ lib/lp/bugs/doc/externalbugtracker-roundup.txt 2018-06-23 00:01:05 +0000 | |||
117 | @@ -75,13 +75,13 @@ | |||
118 | 75 | local variable for later use. | 75 | local variable for later use. |
119 | 76 | 76 | ||
120 | 77 | We use a test-oriented implementation for the purposes of these tests, which | 77 | We use a test-oriented implementation for the purposes of these tests, which |
123 | 78 | overrides ExternalBugTracker.urlopen() so that we don't have to rely on a | 78 | avoids relying on a working network connection. |
122 | 79 | working network connection. | ||
124 | 80 | 79 | ||
125 | 81 | >>> from lp.bugs.tests.externalbugtracker import ( | 80 | >>> from lp.bugs.tests.externalbugtracker import ( |
126 | 82 | ... TestRoundup, print_bugwatches) | 81 | ... TestRoundup, print_bugwatches) |
127 | 83 | >>> roundup = TestRoundup(u'http://test.roundup/') | 82 | >>> roundup = TestRoundup(u'http://test.roundup/') |
129 | 84 | >>> roundup.initializeRemoteBugDB([1]) | 83 | >>> with roundup.responses(): |
130 | 84 | ... roundup.initializeRemoteBugDB([1]) | ||
131 | 85 | >>> sorted(roundup.bugs.keys()) | 85 | >>> sorted(roundup.bugs.keys()) |
132 | 86 | [1] | 86 | [1] |
133 | 87 | 87 | ||
134 | @@ -90,26 +90,27 @@ | |||
135 | 90 | 90 | ||
136 | 91 | There are two means by which we can export Roundup bug statuses: on a | 91 | There are two means by which we can export Roundup bug statuses: on a |
137 | 92 | bug-by-bug basis and as a batch. When the number of bugs that need updating is | 92 | bug-by-bug basis and as a batch. When the number of bugs that need updating is |
139 | 93 | less than a given bug roundupker's batch_query_threshold the bugs will be | 93 | less than a given bug tracker's batch_query_threshold the bugs will be |
140 | 94 | fetched one-at-a-time: | 94 | fetched one-at-a-time: |
141 | 95 | 95 | ||
142 | 96 | >>> roundup.batch_query_threshold | 96 | >>> roundup.batch_query_threshold |
143 | 97 | 10 | 97 | 10 |
144 | 98 | 98 | ||
152 | 99 | >>> roundup.trace_calls = True | 99 | >>> with roundup.responses(trace_calls=True): |
153 | 100 | >>> roundup.initializeRemoteBugDB([6, 7, 8, 9, 10]) | 100 | ... roundup.initializeRemoteBugDB([6, 7, 8, 9, 10]) |
154 | 101 | CALLED urlopen(u'http://test.roundup/issue?...&id=6') | 101 | GET http://test.roundup/issue?...&id=6 |
155 | 102 | CALLED urlopen(u'http://test.roundup/issue?...&id=7') | 102 | GET http://test.roundup/issue?...&id=7 |
156 | 103 | CALLED urlopen(u'http://test.roundup/issue?...&id=8') | 103 | GET http://test.roundup/issue?...&id=8 |
157 | 104 | CALLED urlopen(u'http://test.roundup/issue?...&id=9') | 104 | GET http://test.roundup/issue?...&id=9 |
158 | 105 | CALLED urlopen(u'http://test.roundup/issue?...&id=10') | 105 | GET http://test.roundup/issue?...&id=10 |
159 | 106 | 106 | ||
160 | 107 | If there are more than batch_query_threshold bugs to update then they are | 107 | If there are more than batch_query_threshold bugs to update then they are |
161 | 108 | fetched as a batch: | 108 | fetched as a batch: |
162 | 109 | 109 | ||
163 | 110 | >>> roundup.batch_query_threshold = 4 | 110 | >>> roundup.batch_query_threshold = 4 |
166 | 111 | >>> roundup.initializeRemoteBugDB([6, 7, 8, 9, 10]) | 111 | >>> with roundup.responses(trace_calls=True): |
167 | 112 | CALLED urlopen(u'http://test.roundup/issue?...@startwith=0') | 112 | ... roundup.initializeRemoteBugDB([6, 7, 8, 9, 10]) |
168 | 113 | GET http://test.roundup/issue?...@startwith=0 | ||
169 | 113 | 114 | ||
170 | 114 | 115 | ||
171 | 115 | == Updating Bug Watches == | 116 | == Updating Bug Watches == |
172 | @@ -145,8 +146,9 @@ | |||
173 | 145 | >>> bug_watch_updater = CheckwatchesMaster( | 146 | >>> bug_watch_updater = CheckwatchesMaster( |
174 | 146 | ... txn, logger=FakeLogger()) | 147 | ... txn, logger=FakeLogger()) |
175 | 147 | >>> roundup = TestRoundup(example_bug_tracker.baseurl) | 148 | >>> roundup = TestRoundup(example_bug_tracker.baseurl) |
178 | 148 | >>> bug_watch_updater.updateBugWatches( | 149 | >>> with roundup.responses(): |
179 | 149 | ... roundup, example_bug_tracker.watches) | 150 | ... bug_watch_updater.updateBugWatches( |
180 | 151 | ... roundup, example_bug_tracker.watches) | ||
181 | 150 | INFO Updating 1 watches for 1 bugs on http://bugs.some.where | 152 | INFO Updating 1 watches for 1 bugs on http://bugs.some.where |
182 | 151 | >>> print_bugwatches(example_bug_tracker.watches) | 153 | >>> print_bugwatches(example_bug_tracker.watches) |
183 | 152 | Remote bug 1: 1 | 154 | Remote bug 1: 1 |
184 | @@ -178,11 +180,11 @@ | |||
185 | 178 | ... bugtracker=example_bug_tracker, | 180 | ... bugtracker=example_bug_tracker, |
186 | 179 | ... remotebug=str(remote_bug_id)) | 181 | ... remotebug=str(remote_bug_id)) |
187 | 180 | 182 | ||
191 | 181 | >>> roundup.trace_calls = True | 183 | >>> with roundup.responses(trace_calls=True): |
192 | 182 | >>> bug_watch_updater.updateBugWatches( | 184 | ... bug_watch_updater.updateBugWatches( |
193 | 183 | ... roundup, example_bug_tracker.watches) | 185 | ... roundup, example_bug_tracker.watches) |
194 | 184 | INFO Updating 11 watches for 11 bugs on http://bugs.some.where | 186 | INFO Updating 11 watches for 11 bugs on http://bugs.some.where |
196 | 185 | CALLED urlopen(u'http://.../issue?...@startwith=0') | 187 | GET http://.../issue?...@startwith=0 |
197 | 186 | 188 | ||
198 | 187 | >>> print_bugwatches(example_bug_tracker.watches, | 189 | >>> print_bugwatches(example_bug_tracker.watches, |
199 | 188 | ... roundup.convertRemoteStatus) | 190 | ... roundup.convertRemoteStatus) |
200 | 189 | 191 | ||
201 | === modified file 'lib/lp/bugs/externalbugtracker/roundup.py' | |||
202 | --- lib/lp/bugs/externalbugtracker/roundup.py 2015-10-15 14:09:50 +0000 | |||
203 | +++ lib/lp/bugs/externalbugtracker/roundup.py 2018-06-23 00:01:05 +0000 | |||
204 | @@ -1,4 +1,4 @@ | |||
206 | 1 | # Copyright 2009-2011 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2009-2018 Canonical Ltd. This software is licensed under the |
207 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
208 | 3 | 3 | ||
209 | 4 | """Round ExternalBugTracker utility.""" | 4 | """Round ExternalBugTracker utility.""" |
210 | @@ -13,7 +13,7 @@ | |||
211 | 13 | 13 | ||
212 | 14 | from lp.bugs.externalbugtracker import ( | 14 | from lp.bugs.externalbugtracker import ( |
213 | 15 | BugNotFound, | 15 | BugNotFound, |
215 | 16 | ExternalBugTracker, | 16 | ExternalBugTrackerRequests, |
216 | 17 | InvalidBugId, | 17 | InvalidBugId, |
217 | 18 | LookupTree, | 18 | LookupTree, |
218 | 19 | UnknownRemoteStatusError, | 19 | UnknownRemoteStatusError, |
219 | @@ -42,7 +42,7 @@ | |||
220 | 42 | for (key, value) in items) | 42 | for (key, value) in items) |
221 | 43 | 43 | ||
222 | 44 | 44 | ||
224 | 45 | class Roundup(ExternalBugTracker): | 45 | class Roundup(ExternalBugTrackerRequests): |
225 | 46 | """An ExternalBugTracker descendant for handling Roundup bug trackers.""" | 46 | """An ExternalBugTracker descendant for handling Roundup bug trackers.""" |
226 | 47 | 47 | ||
227 | 48 | _status_fields_map = { | 48 | _status_fields_map = { |
228 | @@ -218,7 +218,7 @@ | |||
229 | 218 | """See `ExternalBugTracker`.""" | 218 | """See `ExternalBugTracker`.""" |
230 | 219 | bug_id = int(bug_id) | 219 | bug_id = int(bug_id) |
231 | 220 | query_url = self.getSingleBugExportURL(bug_id) | 220 | query_url = self.getSingleBugExportURL(bug_id) |
233 | 221 | reader = csv.DictReader(self._fetchPage(query_url)) | 221 | reader = csv.DictReader(self._getPage(query_url).iter_lines()) |
234 | 222 | return (bug_id, reader.next()) | 222 | return (bug_id, reader.next()) |
235 | 223 | 223 | ||
236 | 224 | def getRemoteBugBatch(self, bug_ids): | 224 | def getRemoteBugBatch(self, bug_ids): |
237 | @@ -230,7 +230,7 @@ | |||
238 | 230 | # export the bug ids needed rather than hitting the remote | 230 | # export the bug ids needed rather than hitting the remote |
239 | 231 | # tracker for a potentially massive number of bugs. | 231 | # tracker for a potentially massive number of bugs. |
240 | 232 | query_url = self.getBatchBugExportURL() | 232 | query_url = self.getBatchBugExportURL() |
242 | 233 | remote_bugs = csv.DictReader(self._fetchPage(query_url)) | 233 | remote_bugs = csv.DictReader(self._getPage(query_url).iter_lines()) |
243 | 234 | bugs = {} | 234 | bugs = {} |
244 | 235 | for remote_bug in remote_bugs: | 235 | for remote_bug in remote_bugs: |
245 | 236 | # We're only interested in the bug if it's one of the ones in | 236 | # We're only interested in the bug if it's one of the ones in |
246 | 237 | 237 | ||
247 | === modified file 'lib/lp/bugs/tests/externalbugtracker.py' | |||
248 | --- lib/lp/bugs/tests/externalbugtracker.py 2018-06-05 12:18:58 +0000 | |||
249 | +++ lib/lp/bugs/tests/externalbugtracker.py 2018-06-23 00:01:05 +0000 | |||
250 | @@ -5,6 +5,7 @@ | |||
251 | 5 | 5 | ||
252 | 6 | __metaclass__ = type | 6 | __metaclass__ = type |
253 | 7 | 7 | ||
254 | 8 | from contextlib import contextmanager | ||
255 | 8 | from copy import deepcopy | 9 | from copy import deepcopy |
256 | 9 | from datetime import ( | 10 | from datetime import ( |
257 | 10 | datetime, | 11 | datetime, |
258 | @@ -20,9 +21,15 @@ | |||
259 | 20 | BaseHandler, | 21 | BaseHandler, |
260 | 21 | Request, | 22 | Request, |
261 | 22 | ) | 23 | ) |
262 | 23 | import urlparse | ||
263 | 24 | import xmlrpclib | 24 | import xmlrpclib |
264 | 25 | 25 | ||
265 | 26 | import responses | ||
266 | 27 | from six.moves.urllib_parse import ( | ||
267 | 28 | parse_qs, | ||
268 | 29 | urljoin, | ||
269 | 30 | urlparse, | ||
270 | 31 | urlsplit, | ||
271 | 32 | ) | ||
272 | 26 | from zope.component import getUtility | 33 | from zope.component import getUtility |
273 | 27 | from zope.security.proxy import removeSecurityProxy | 34 | from zope.security.proxy import removeSecurityProxy |
274 | 28 | 35 | ||
275 | @@ -158,6 +165,30 @@ | |||
276 | 158 | naked.updateStatus(UNKNOWN_REMOTE_STATUS, BugTaskStatus.UNKNOWN) | 165 | naked.updateStatus(UNKNOWN_REMOTE_STATUS, BugTaskStatus.UNKNOWN) |
277 | 159 | 166 | ||
278 | 160 | 167 | ||
279 | 168 | class BugTrackerResponsesMixin: | ||
280 | 169 | """A responses-based test mixin for bug trackers. | ||
281 | 170 | |||
282 | 171 | The simplest way to use this is as a context manager: | ||
283 | 172 | |||
284 | 173 | with bug_tracker.responses(): | ||
285 | 174 | ... | ||
286 | 175 | |||
287 | 176 | Classes using this mixin should implement `addResponses`. | ||
288 | 177 | """ | ||
289 | 178 | |||
290 | 179 | def addResponses(self, requests_mock, **kwargs): | ||
291 | 180 | """Add test responses.""" | ||
292 | 181 | |||
293 | 182 | @contextmanager | ||
294 | 183 | def responses(self, trace_calls=False, **kwargs): | ||
295 | 184 | with responses.RequestsMock() as requests_mock: | ||
296 | 185 | self.addResponses(requests_mock, **kwargs) | ||
297 | 186 | yield requests_mock | ||
298 | 187 | if trace_calls: | ||
299 | 188 | for call in requests_mock.calls: | ||
300 | 189 | print call.request.method, call.request.url | ||
301 | 190 | |||
302 | 191 | |||
303 | 161 | class TestExternalBugTracker(ExternalBugTracker): | 192 | class TestExternalBugTracker(ExternalBugTracker): |
304 | 162 | """A test version of `ExternalBugTracker`. | 193 | """A test version of `ExternalBugTracker`. |
305 | 163 | 194 | ||
306 | @@ -1522,30 +1553,26 @@ | |||
307 | 1522 | return [self.utc_time] | 1553 | return [self.utc_time] |
308 | 1523 | 1554 | ||
309 | 1524 | 1555 | ||
316 | 1525 | class TestRoundup(Roundup): | 1556 | class TestRoundup(BugTrackerResponsesMixin, Roundup): |
317 | 1526 | """Roundup ExternalBugTracker for testing purposes. | 1557 | """Roundup ExternalBugTracker for testing purposes.""" |
312 | 1527 | |||
313 | 1528 | It overrides urlopen, so that access to a real Roundup instance isn't | ||
314 | 1529 | needed. | ||
315 | 1530 | """ | ||
318 | 1531 | 1558 | ||
319 | 1532 | # We remove the batch_size limit for the purposes of the tests so | 1559 | # We remove the batch_size limit for the purposes of the tests so |
320 | 1533 | # that we can test batching and not batching correctly. | 1560 | # that we can test batching and not batching correctly. |
321 | 1534 | batch_size = None | 1561 | batch_size = None |
333 | 1535 | trace_calls = False | 1562 | |
334 | 1536 | 1563 | @staticmethod | |
335 | 1537 | def urlopen(self, url, data=None): | 1564 | def _getCallback(request): |
336 | 1538 | if self.trace_calls: | 1565 | url = urlsplit(request.url) |
337 | 1539 | print "CALLED urlopen(%r)" % (url.get_full_url()) | 1566 | if url.netloc == 'bugs.python.org': |
338 | 1540 | 1567 | body = read_test_file('python_example_ticket_export.csv') | |
328 | 1541 | file_path = os.path.join(os.path.dirname(__file__), 'testfiles') | ||
329 | 1542 | |||
330 | 1543 | if self.host == 'bugs.python.org': | ||
331 | 1544 | return open( | ||
332 | 1545 | file_path + '/' + 'python_example_ticket_export.csv', 'r') | ||
339 | 1546 | else: | 1568 | else: |
342 | 1547 | return open( | 1569 | body = read_test_file('roundup_example_ticket_export.csv') |
343 | 1548 | file_path + '/' + 'roundup_example_ticket_export.csv', 'r') | 1570 | return 200, {}, body |
344 | 1571 | |||
345 | 1572 | def addResponses(self, requests_mock): | ||
346 | 1573 | """Add test responses.""" | ||
347 | 1574 | requests_mock.add_callback( | ||
348 | 1575 | 'GET', re.compile(re.escape(self.baseurl)), self._getCallback) | ||
349 | 1549 | 1576 | ||
350 | 1550 | 1577 | ||
351 | 1551 | class TestRequestTracker(RequestTracker): | 1578 | class TestRequestTracker(RequestTracker): |
352 | @@ -1559,7 +1586,7 @@ | |||
353 | 1559 | 1586 | ||
354 | 1560 | def urlopen(self, page, data=None): | 1587 | def urlopen(self, page, data=None): |
355 | 1561 | file_path = os.path.join(os.path.dirname(__file__), 'testfiles') | 1588 | file_path = os.path.join(os.path.dirname(__file__), 'testfiles') |
357 | 1562 | path = urlparse.urlparse(page)[2].lstrip('/') | 1589 | path = urlparse(page)[2].lstrip('/') |
358 | 1563 | if self.trace_calls: | 1590 | if self.trace_calls: |
359 | 1564 | print "CALLED urlopen(%r)" % path | 1591 | print "CALLED urlopen(%r)" % path |
360 | 1565 | 1592 |