Merge lp:~eday/burrow/backend-unittests into lp:burrow
- backend-unittests
- Merge into trunk
Proposed by
Eric Day
Status: | Merged |
---|---|
Approved by: | Eric Day |
Approved revision: | 39 |
Merged at revision: | 32 |
Proposed branch: | lp:~eday/burrow/backend-unittests |
Merge into: | lp:burrow |
Diff against target: |
425 lines (+170/-63) 6 files modified
.bzrignore (+1/-1) burrow/backend/__init__.py (+3/-3) burrow/backend/http.py (+47/-19) burrow/frontend/wsgi.py (+28/-26) test/backend/test_http.py (+77/-0) test/backend/test_memory.py (+14/-14) |
To merge this branch: | bzr merge lp:~eday/burrow/backend-unittests |
Related bugs: | |
Related blueprints: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Burrow Core Team | Pending | ||
Review via email: mp+70990@code.launchpad.net |
Commit message
Description of the change
Added HTTP backend unit tests that work against a running server (auto started/killed with test).
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file '.bzrignore' |
2 | --- .bzrignore 2011-04-20 18:21:51 +0000 |
3 | +++ .bzrignore 2011-08-10 05:42:35 +0000 |
4 | @@ -1,4 +1,4 @@ |
5 | -.coverage |
6 | +.coverage* |
7 | burrow.egg-info |
8 | ChangeLog |
9 | coverage |
10 | |
11 | === modified file 'burrow/backend/__init__.py' |
12 | --- burrow/backend/__init__.py 2011-08-09 19:43:03 +0000 |
13 | +++ burrow/backend/__init__.py 2011-08-10 05:42:35 +0000 |
14 | @@ -112,7 +112,7 @@ |
15 | if detail == 'none': |
16 | detail = None |
17 | elif detail is not None and detail not in ['id', 'all']: |
18 | - raise burrow.backend.BadDetail(detail) |
19 | + raise burrow.backend.InvalidArguments(detail) |
20 | return detail |
21 | |
22 | def _get_message_detail(self, filters, default=None): |
23 | @@ -121,7 +121,7 @@ |
24 | if detail == 'none': |
25 | detail = None |
26 | elif detail is not None and detail not in options: |
27 | - raise burrow.backend.BadDetail(detail) |
28 | + raise burrow.backend.InvalidArguments(detail) |
29 | return detail |
30 | |
31 | |
32 | @@ -129,5 +129,5 @@ |
33 | pass |
34 | |
35 | |
36 | -class BadDetail(Exception): |
37 | +class InvalidArguments(Exception): |
38 | pass |
39 | |
40 | === modified file 'burrow/backend/http.py' |
41 | --- burrow/backend/http.py 2011-04-22 02:18:26 +0000 |
42 | +++ burrow/backend/http.py 2011-08-10 05:42:35 +0000 |
43 | @@ -67,7 +67,7 @@ |
44 | url = self._add_parameters(url, filters=filters) |
45 | return self._request('GET', url) |
46 | |
47 | - def update_messages(self, account, queue, attributes={}, filters={}): |
48 | + def update_messages(self, account, queue, attributes, filters={}): |
49 | url = '/%s/%s' % (account, queue) |
50 | url = self._add_parameters(url, attributes, filters) |
51 | return self._request('POST', url) |
52 | @@ -75,20 +75,34 @@ |
53 | def create_message(self, account, queue, message, body, attributes={}): |
54 | url = '/%s/%s/%s' % (account, queue, message) |
55 | url = self._add_parameters(url, attributes) |
56 | - return self._request('PUT', url, body=body) |
57 | - |
58 | - def delete_message(self, account, queue, message): |
59 | - url = '/%s/%s/%s' % (account, queue, message) |
60 | - return self._request('DELETE', url) |
61 | - |
62 | - def get_message(self, account, queue, message): |
63 | - url = '/%s/%s/%s' % (account, queue, message) |
64 | - return self._request('GET', url) |
65 | - |
66 | - def update_message(self, account, queue, message, attributes={}): |
67 | - url = '/%s/%s/%s' % (account, queue, message) |
68 | - url = self._add_parameters(url, attributes) |
69 | - return self._request('POST', url) |
70 | + try: |
71 | + return self._request('PUT', url, body=body).next() |
72 | + except StopIteration: |
73 | + return False |
74 | + |
75 | + def delete_message(self, account, queue, message, filters={}): |
76 | + url = '/%s/%s/%s' % (account, queue, message) |
77 | + url = self._add_parameters(url, filters=filters) |
78 | + try: |
79 | + return self._request('DELETE', url).next() |
80 | + except StopIteration: |
81 | + return None |
82 | + |
83 | + def get_message(self, account, queue, message, filters={}): |
84 | + url = '/%s/%s/%s' % (account, queue, message) |
85 | + url = self._add_parameters(url, filters=filters) |
86 | + try: |
87 | + return self._request('GET', url).next() |
88 | + except StopIteration: |
89 | + return None |
90 | + |
91 | + def update_message(self, account, queue, message, attributes, filters={}): |
92 | + url = '/%s/%s/%s' % (account, queue, message) |
93 | + url = self._add_parameters(url, attributes, filters) |
94 | + try: |
95 | + return self._request('POST', url).next() |
96 | + except StopIteration: |
97 | + return None |
98 | |
99 | def clean(self): |
100 | pass |
101 | @@ -111,7 +125,21 @@ |
102 | connection = httplib.HTTPConnection(*self.server) |
103 | connection.request(method, '/v1.0' + url, *args, **kwargs) |
104 | response = connection.getresponse() |
105 | - if response.status == 200: |
106 | - return json.loads(response.read()) |
107 | - if response.status >= 400: |
108 | - raise Exception(response.reason) |
109 | + if response.status >= 200 and response.status < 300: |
110 | + if int(response.getheader('content-length')) == 0: |
111 | + if response.status == 201: |
112 | + yield True |
113 | + return |
114 | + body = response.read() |
115 | + if response.getheader('content-type')[:16] == 'application/json': |
116 | + body = json.loads(body) |
117 | + if isinstance(body, list): |
118 | + for item in body: |
119 | + yield item |
120 | + return |
121 | + yield body |
122 | + if response.status == 400: |
123 | + raise burrow.backend.InvalidArguments() |
124 | + if response.status == 404: |
125 | + raise burrow.backend.NotFound() |
126 | + raise Exception(response.reason) |
127 | |
128 | === modified file 'burrow/frontend/wsgi.py' |
129 | --- burrow/frontend/wsgi.py 2011-08-09 17:22:31 +0000 |
130 | +++ burrow/frontend/wsgi.py 2011-08-10 05:42:35 +0000 |
131 | @@ -173,33 +173,24 @@ |
132 | @webob.dec.wsgify |
133 | def _delete_message(self, req, account, queue, message): |
134 | filters = self._parse_filters(req) |
135 | - try: |
136 | - message = self.backend.delete_message(account, queue, message, |
137 | - filters) |
138 | - except burrow.backend.NotFound: |
139 | - return self._response(status=404) |
140 | - return self._response(body=message) |
141 | + body = lambda: self.backend.delete_message(account, queue, message, |
142 | + filters) |
143 | + return self._response(body=body) |
144 | |
145 | @webob.dec.wsgify |
146 | def _get_message(self, req, account, queue, message): |
147 | filters = self._parse_filters(req) |
148 | - try: |
149 | - message = self.backend.get_message(account, queue, message, |
150 | - filters) |
151 | - except burrow.backend.NotFound: |
152 | - return self._response(status=404) |
153 | - return self._response(body=message) |
154 | + body = lambda: self.backend.get_message(account, queue, message, |
155 | + filters) |
156 | + return self._response(body=body) |
157 | |
158 | @webob.dec.wsgify |
159 | def _post_message(self, req, account, queue, message): |
160 | attributes = self._parse_attributes(req) |
161 | filters = self._parse_filters(req) |
162 | - try: |
163 | - message = self.backend.update_message(account, queue, message, |
164 | - attributes, filters) |
165 | - except burrow.backend.NotFound: |
166 | - return self._response(status=404) |
167 | - return self._response(body=message) |
168 | + body = lambda: self.backend.update_message(account, queue, message, |
169 | + attributes, filters) |
170 | + return self._response(body=body) |
171 | |
172 | @webob.dec.wsgify |
173 | def _put_message(self, req, account, queue, message): |
174 | @@ -241,12 +232,17 @@ |
175 | return attributes |
176 | |
177 | def _response(self, status=200, body=None, content_type=None): |
178 | - if isinstance(body, types.GeneratorType): |
179 | - try: |
180 | + try: |
181 | + if isinstance(body, types.GeneratorType): |
182 | body = list(body) |
183 | - except burrow.backend.NotFound: |
184 | - body = None |
185 | - status = 404 |
186 | + if isinstance(body, types.FunctionType): |
187 | + body = body() |
188 | + except burrow.backend.InvalidArguments: |
189 | + status = 400 |
190 | + body = None |
191 | + except burrow.backend.NotFound: |
192 | + status = 404 |
193 | + body = None |
194 | if body == []: |
195 | body = None |
196 | if body is None: |
197 | @@ -258,11 +254,17 @@ |
198 | if isinstance(body, list) or isinstance(body, dict): |
199 | content_type = 'application/json' |
200 | else: |
201 | - content_type = "application/octet-stream" |
202 | + content_type = 'application/octet-stream' |
203 | if content_type == 'application/json': |
204 | body = json.dumps(body, indent=2) |
205 | - return webob.Response(status=status, body=body, |
206 | - content_type=content_type) |
207 | + response = webob.Response(status=status) |
208 | + if body is not None: |
209 | + response.content_type = content_type |
210 | + if isinstance(body, unicode): |
211 | + response.unicode_body = body |
212 | + else: |
213 | + response.body = body |
214 | + return response |
215 | |
216 | |
217 | class WSGILog(object): |
218 | |
219 | === added file 'test/backend/test_http.py' |
220 | --- test/backend/test_http.py 1970-01-01 00:00:00 +0000 |
221 | +++ test/backend/test_http.py 2011-08-10 05:42:35 +0000 |
222 | @@ -0,0 +1,77 @@ |
223 | +# Copyright (C) 2011 OpenStack LLC. |
224 | +# |
225 | +# Licensed under the Apache License, Version 2.0 (the "License"); |
226 | +# you may not use this file except in compliance with the License. |
227 | +# You may obtain a copy of the License at |
228 | +# |
229 | +# http://www.apache.org/licenses/LICENSE-2.0 |
230 | +# |
231 | +# Unless required by applicable law or agreed to in writing, software |
232 | +# distributed under the License is distributed on an "AS IS" BASIS, |
233 | +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
234 | +# See the License for the specific language governing permissions and |
235 | +# limitations under the License. |
236 | + |
237 | +import atexit |
238 | +import ConfigParser |
239 | +import os |
240 | +import signal |
241 | +import time |
242 | + |
243 | +import burrow.server |
244 | +import burrow.backend.http |
245 | +import test.backend.test_memory |
246 | + |
247 | + |
248 | +class TestHTTP(test.backend.test_memory.TestMemory): |
249 | + '''Unittests for the HTTP backend.''' |
250 | + |
251 | + def setUp(self): |
252 | + config = (ConfigParser.ConfigParser(), 'test') |
253 | + self.backend = burrow.backend.http.Backend(config) |
254 | + self.check_empty() |
255 | + |
256 | + |
257 | +def kill_server(): |
258 | + try: |
259 | + pid_file = open('server.pid', 'r') |
260 | + pid = pid_file.read() |
261 | + pid_file.close() |
262 | + try: |
263 | + os.kill(int(pid), signal.SIGUSR1) |
264 | + time.sleep(1) |
265 | + os.kill(int(pid), signal.SIGTERM) |
266 | + except OSError: |
267 | + pass |
268 | + os.unlink('server.pid') |
269 | + except IOError: |
270 | + pass |
271 | + |
272 | + |
273 | +def start_server(): |
274 | + pid = os.fork() |
275 | + if pid == 0: |
276 | + try: |
277 | + import coverage |
278 | + cov = coverage.coverage(data_suffix=True) |
279 | + cov.start() |
280 | + |
281 | + def save_coverage(signum, frame): |
282 | + cov.save() |
283 | + |
284 | + signal.signal(signal.SIGUSR1, save_coverage) |
285 | + except: |
286 | + pass |
287 | + server = burrow.server.Server(add_default_log_handler=False) |
288 | + server.frontends[0].default_ttl = 0 |
289 | + server.run() |
290 | + os.exit(0) |
291 | + pid_file = open('server.pid', 'w') |
292 | + pid_file.write(str(pid)) |
293 | + pid_file.close() |
294 | + time.sleep(1) |
295 | + |
296 | + |
297 | +kill_server() |
298 | +start_server() |
299 | +atexit.register(kill_server) |
300 | |
301 | === modified file 'test/backend/test_memory.py' |
302 | --- test/backend/test_memory.py 2011-08-09 22:53:44 +0000 |
303 | +++ test/backend/test_memory.py 2011-08-10 05:42:35 +0000 |
304 | @@ -75,7 +75,7 @@ |
305 | self.backend.create_message('a', 'q', 'm', 'test') |
306 | filters = dict(detail='bad') |
307 | accounts = self.backend.delete_accounts(filters) |
308 | - self.assertRaises(burrow.backend.BadDetail, list, accounts) |
309 | + self.assertRaises(burrow.backend.InvalidArguments, list, accounts) |
310 | self.assertEquals([], list(self.backend.delete_accounts())) |
311 | |
312 | def test_accounts_delete_marker(self): |
313 | @@ -145,7 +145,7 @@ |
314 | self.backend.create_message('a', 'q', 'm', 'test') |
315 | filters = dict(detail='bad') |
316 | accounts = self.backend.get_accounts(filters) |
317 | - self.assertRaises(burrow.backend.BadDetail, list, accounts) |
318 | + self.assertRaises(burrow.backend.InvalidArguments, list, accounts) |
319 | self.assertEquals([], list(self.backend.delete_accounts())) |
320 | |
321 | def test_accounts_get_marker(self): |
322 | @@ -237,7 +237,7 @@ |
323 | self.backend.create_message('a', 'q', 'm', 'test') |
324 | filters = dict(detail='bad') |
325 | queues = self.backend.delete_queues('a', filters) |
326 | - self.assertRaises(burrow.backend.BadDetail, list, queues) |
327 | + self.assertRaises(burrow.backend.InvalidArguments, list, queues) |
328 | self.assertEquals([], list(self.backend.delete_queues('a'))) |
329 | |
330 | def test_queues_delete_marker(self): |
331 | @@ -307,7 +307,7 @@ |
332 | self.backend.create_message('a', 'q', 'm', 'test') |
333 | filters = dict(detail='bad') |
334 | queues = self.backend.get_queues('a', filters) |
335 | - self.assertRaises(burrow.backend.BadDetail, list, queues) |
336 | + self.assertRaises(burrow.backend.InvalidArguments, list, queues) |
337 | self.assertEquals([], list(self.backend.delete_queues('a'))) |
338 | |
339 | def test_queues_get_marker(self): |
340 | @@ -428,7 +428,7 @@ |
341 | self.backend.create_message('a', 'q', 'm', 'test') |
342 | filters = dict(detail='bad') |
343 | messages = self.backend.delete_messages('a', 'q', filters) |
344 | - self.assertRaises(burrow.backend.BadDetail, list, messages) |
345 | + self.assertRaises(burrow.backend.InvalidArguments, list, messages) |
346 | self.assertEquals([], list(self.backend.delete_messages('a', 'q'))) |
347 | |
348 | def test_messages_delete_marker(self): |
349 | @@ -514,7 +514,7 @@ |
350 | self.backend.create_message('a', 'q', 'm', 'test') |
351 | filters = dict(detail='bad') |
352 | messages = self.backend.get_messages('a', 'q', filters) |
353 | - self.assertRaises(burrow.backend.BadDetail, list, messages) |
354 | + self.assertRaises(burrow.backend.InvalidArguments, list, messages) |
355 | self.delete_messages() |
356 | |
357 | def test_messages_get_marker(self): |
358 | @@ -618,7 +618,7 @@ |
359 | attributes = dict(ttl=100, hide=200) |
360 | filters = dict(detail='bad') |
361 | messages = self.backend.update_messages('a', 'q', attributes, filters) |
362 | - self.assertRaises(burrow.backend.BadDetail, list, messages) |
363 | + self.assertRaises(burrow.backend.InvalidArguments, list, messages) |
364 | self.delete_messages() |
365 | |
366 | def test_messages_update_marker(self): |
367 | @@ -752,7 +752,7 @@ |
368 | def test_message_delete_detail_bad(self): |
369 | self.backend.create_message('a', 'q', 'm', 'test') |
370 | filters = dict(detail='bad') |
371 | - self.assertRaises(burrow.backend.BadDetail, |
372 | + self.assertRaises(burrow.backend.InvalidArguments, |
373 | self.backend.delete_message, 'a', 'q', 'm', filters) |
374 | self.delete_messages() |
375 | |
376 | @@ -794,7 +794,7 @@ |
377 | def test_message_get_detail_bad(self): |
378 | self.backend.create_message('a', 'q', 'm', 'test') |
379 | filters = dict(detail='bad') |
380 | - self.assertRaises(burrow.backend.BadDetail, |
381 | + self.assertRaises(burrow.backend.InvalidArguments, |
382 | self.backend.get_message, 'a', 'q', 'm', filters) |
383 | self.delete_messages() |
384 | |
385 | @@ -848,27 +848,27 @@ |
386 | self.backend.create_message('a', 'q', 'm', 'test') |
387 | attributes = dict(ttl=100, hide=200) |
388 | filters = dict(detail='bad') |
389 | - self.assertRaises(burrow.backend.BadDetail, |
390 | + self.assertRaises(burrow.backend.InvalidArguments, |
391 | self.backend.update_message, 'a', 'q', 'm', attributes, filters) |
392 | self.delete_messages() |
393 | |
394 | def test_message_ttl(self): |
395 | attributes = dict(ttl=1) |
396 | self.backend.create_message('a', 'q', 'm', 'test', attributes) |
397 | - time.sleep(1) |
398 | + time.sleep(2) |
399 | self.backend.clean() |
400 | |
401 | def test_message_ttl_large(self): |
402 | attributes = dict(ttl=1) |
403 | for x in xrange(0, 1000): |
404 | self.backend.create_message('a', 'q', str(x), str(x), attributes) |
405 | - time.sleep(1) |
406 | + time.sleep(2) |
407 | self.backend.clean() |
408 | |
409 | def test_message_hide(self): |
410 | attributes = dict(hide=1) |
411 | self.backend.create_message('a', 'q', 'm', 'test', attributes) |
412 | - time.sleep(1) |
413 | + time.sleep(2) |
414 | self.backend.clean() |
415 | message = self.backend.get_message('a', 'q', 'm') |
416 | self.assertEquals(dict(id='m', ttl=0, hide=0, body='test'), message) |
417 | @@ -878,7 +878,7 @@ |
418 | attributes = dict(hide=1) |
419 | for x in xrange(0, 1000): |
420 | self.backend.create_message('a', 'q', str(x), str(x), attributes) |
421 | - time.sleep(1) |
422 | + time.sleep(2) |
423 | self.backend.clean() |
424 | message = self.backend.get_message('a', 'q', '0') |
425 | self.assertEquals(dict(id='0', ttl=0, hide=0, body='0'), message) |