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: | 40 |
Merged at revision: | 33 |
Proposed branch: | lp:~eday/burrow/backend-unittests |
Merge into: | lp:burrow |
Diff against target: |
719 lines (+120/-365) 8 files modified
burrow/backend/__init__.py (+54/-20) burrow/backend/http.py (+1/-1) burrow/backend/memory.py (+7/-4) burrow/backend/sqlite.py (+7/-4) burrow/frontend/wsgi.py (+2/-28) test/backend/test_http.py (+5/-5) test/backend/test_memory.py (+44/-0) test/frontend/test_wsgi.py (+0/-303) |
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+71000@code.launchpad.net |
Commit message
Description of the change
Pushed wait functionality down into backend, removed frontend tests since this is replaced with HTTP backend test now.
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 'burrow/backend/__init__.py' |
2 | --- burrow/backend/__init__.py 2011-08-10 05:22:20 +0000 |
3 | +++ burrow/backend/__init__.py 2011-08-10 07:23:26 +0000 |
4 | @@ -66,26 +66,6 @@ |
5 | def update_message(self, account, queue, message, attributes, filters={}): |
6 | return None |
7 | |
8 | - def notify(self, account, queue): |
9 | - '''Notify any waiting callers that the account/queue has |
10 | - a visible message.''' |
11 | - queue = '%s/%s' % (account, queue) |
12 | - if queue in self.queues: |
13 | - for count in xrange(0, self.queues[queue].getting()): |
14 | - self.queues[queue].put(0) |
15 | - |
16 | - def wait(self, account, queue, seconds): |
17 | - '''Wait for a message to appear in the account/queue.''' |
18 | - queue = '%s/%s' % (account, queue) |
19 | - if queue not in self.queues: |
20 | - self.queues[queue] = eventlet.Queue() |
21 | - try: |
22 | - self.queues[queue].get(timeout=seconds) |
23 | - except Exception: |
24 | - pass |
25 | - if self.queues[queue].getting() == 0: |
26 | - del self.queues[queue] |
27 | - |
28 | def clean(self): |
29 | '''This method should remove all messages with an expired |
30 | TTL and make hidden messages that have an expired hide time |
31 | @@ -124,6 +104,60 @@ |
32 | raise burrow.backend.InvalidArguments(detail) |
33 | return detail |
34 | |
35 | + def _notify(self, account, queue): |
36 | + '''Notify any waiting callers that the account/queue has |
37 | + a visible message.''' |
38 | + queue = '%s/%s' % (account, queue) |
39 | + if queue in self.queues: |
40 | + for count in xrange(0, self.queues[queue].getting()): |
41 | + self.queues[queue].put(0) |
42 | + |
43 | + def _wait(self, account, queue, seconds): |
44 | + '''Wait for a message to appear in the account/queue.''' |
45 | + queue = '%s/%s' % (account, queue) |
46 | + if queue not in self.queues: |
47 | + self.queues[queue] = eventlet.Queue() |
48 | + try: |
49 | + self.queues[queue].get(timeout=seconds) |
50 | + except Exception: |
51 | + pass |
52 | + if self.queues[queue].getting() == 0: |
53 | + del self.queues[queue] |
54 | + |
55 | + |
56 | +def wait_without_attributes(method): |
57 | + def wrapper(self, account, queue, filters={}): |
58 | + original = lambda: method(self, account, queue, filters) |
59 | + return wait(self, account, queue, filters, original) |
60 | + return wrapper |
61 | + |
62 | + |
63 | +def wait_with_attributes(method): |
64 | + def wrapper(self, account, queue, attributes, filters={}): |
65 | + original = lambda: method(self, account, queue, attributes, filters) |
66 | + return wait(self, account, queue, filters, original) |
67 | + return wrapper |
68 | + |
69 | + |
70 | +def wait(self, account, queue, filters, method): |
71 | + '''Decorator to wait on a queue if the wait option is given. This |
72 | + will block until a message in the queue is ready or the timeout |
73 | + expires.''' |
74 | + wait = filters.get('wait', 0) |
75 | + if wait > 0: |
76 | + wait += time.time() |
77 | + while True: |
78 | + try: |
79 | + for message in method(): |
80 | + yield message |
81 | + return |
82 | + except burrow.backend.NotFound, e: |
83 | + now = time.time() |
84 | + if wait - now > 0: |
85 | + self._wait(account, queue, wait - now) |
86 | + if wait < time.time(): |
87 | + raise e |
88 | + |
89 | |
90 | class NotFound(Exception): |
91 | pass |
92 | |
93 | === modified file 'burrow/backend/http.py' |
94 | --- burrow/backend/http.py 2011-08-10 05:22:20 +0000 |
95 | +++ burrow/backend/http.py 2011-08-10 07:23:26 +0000 |
96 | @@ -139,7 +139,7 @@ |
97 | return |
98 | yield body |
99 | if response.status == 400: |
100 | - raise burrow.backend.InvalidArguments() |
101 | + raise burrow.backend.InvalidArguments(response.reason) |
102 | if response.status == 404: |
103 | raise burrow.backend.NotFound() |
104 | raise Exception(response.reason) |
105 | |
106 | === modified file 'burrow/backend/memory.py' |
107 | --- burrow/backend/memory.py 2011-08-09 19:43:03 +0000 |
108 | +++ burrow/backend/memory.py 2011-08-10 07:23:26 +0000 |
109 | @@ -67,6 +67,7 @@ |
110 | if detail is not None: |
111 | yield queue.detail(detail) |
112 | |
113 | + @burrow.backend.wait_without_attributes |
114 | def delete_messages(self, account, queue, filters={}): |
115 | account, queue = self.accounts.get_queue(account, queue) |
116 | detail = self._get_message_detail(filters) |
117 | @@ -77,6 +78,7 @@ |
118 | if queue.messages.count() == 0: |
119 | self.accounts.delete_queue(account.id, queue.id) |
120 | |
121 | + @burrow.backend.wait_without_attributes |
122 | def get_messages(self, account, queue, filters={}): |
123 | account, queue = self.accounts.get_queue(account, queue) |
124 | detail = self._get_message_detail(filters, 'all') |
125 | @@ -84,6 +86,7 @@ |
126 | if detail is not None: |
127 | yield message.detail(detail) |
128 | |
129 | + @burrow.backend.wait_with_attributes |
130 | def update_messages(self, account, queue, attributes, filters={}): |
131 | account, queue = self.accounts.get_queue(account, queue) |
132 | notify = False |
133 | @@ -99,7 +102,7 @@ |
134 | if detail is not None: |
135 | yield message.detail(detail) |
136 | if notify: |
137 | - self.notify(account.id, queue.id) |
138 | + self._notify(account.id, queue.id) |
139 | |
140 | def create_message(self, account, queue, message, body, attributes={}): |
141 | account, queue = self.accounts.get_queue(account, queue, True) |
142 | @@ -114,7 +117,7 @@ |
143 | message.hide = hide |
144 | message.body = body |
145 | if created or hide == 0: |
146 | - self.notify(account.id, queue.id) |
147 | + self._notify(account.id, queue.id) |
148 | return created |
149 | |
150 | def delete_message(self, account, queue, message, filters={}): |
151 | @@ -142,7 +145,7 @@ |
152 | if hide is not None: |
153 | message.hide = hide |
154 | if hide == 0: |
155 | - self.notify(account.id, queue.id) |
156 | + self._notify(account.id, queue.id) |
157 | return message.detail(detail) |
158 | |
159 | def clean(self): |
160 | @@ -157,7 +160,7 @@ |
161 | message.hide = 0 |
162 | notify = True |
163 | if notify: |
164 | - self.notify(account.id, queue.id) |
165 | + self._notify(account.id, queue.id) |
166 | if queue.messages.count() == 0: |
167 | self.accounts.delete_queue(account.id, queue.id) |
168 | |
169 | |
170 | === modified file 'burrow/backend/sqlite.py' |
171 | --- burrow/backend/sqlite.py 2011-08-09 23:04:39 +0000 |
172 | +++ burrow/backend/sqlite.py 2011-08-10 07:23:26 +0000 |
173 | @@ -211,6 +211,7 @@ |
174 | raise burrow.backend.NotFound() |
175 | return rows[0][0] |
176 | |
177 | + @burrow.backend.wait_without_attributes |
178 | def delete_messages(self, account, queue, filters={}): |
179 | account_rowid = self._get_account(account) |
180 | queue_rowid = self._get_queue(account_rowid, queue) |
181 | @@ -257,6 +258,7 @@ |
182 | return dict(id=row[0], ttl=ttl, hide=hide, body=str(row[3])) |
183 | return None |
184 | |
185 | + @burrow.backend.wait_without_attributes |
186 | def get_messages(self, account, queue, filters={}): |
187 | account_rowid = self._get_account(account) |
188 | queue_rowid = self._get_queue(account_rowid, queue) |
189 | @@ -304,6 +306,7 @@ |
190 | return rows[0] |
191 | return rows[0][0] |
192 | |
193 | + @burrow.backend.wait_with_attributes |
194 | def update_messages(self, account, queue, attributes, filters={}): |
195 | account_rowid = self._get_account(account) |
196 | queue_rowid = self._get_queue(account_rowid, queue) |
197 | @@ -329,7 +332,7 @@ |
198 | if self._update_messages(ttl, hide, ids): |
199 | notify = True |
200 | if notify: |
201 | - self.notify(account, queue) |
202 | + self._notify(account, queue) |
203 | |
204 | def _update_messages(self, ttl, hide, ids): |
205 | query = 'UPDATE messages SET ' |
206 | @@ -372,7 +375,7 @@ |
207 | self.db.execute(query, (queue_rowid, message, ttl, hide, body)) |
208 | created = True |
209 | if created or hide == 0: |
210 | - self.notify(account, queue) |
211 | + self._notify(account, queue) |
212 | return created |
213 | |
214 | def delete_message(self, account, queue, message, filters={}): |
215 | @@ -396,7 +399,7 @@ |
216 | detail = self._get_message_detail(filters) |
217 | ttl, hide = self._get_attributes(attributes) |
218 | if self._update_messages(ttl, hide, [row[0]]): |
219 | - self.notify(account, queue) |
220 | + self._notify(account, queue) |
221 | row = list(row) |
222 | if ttl is not None: |
223 | row[2] = ttl |
224 | @@ -444,4 +447,4 @@ |
225 | 'ON queues.account=accounts.rowid ' \ |
226 | 'WHERE queues.rowid=?' |
227 | result = self.db.execute(query, (queue,)).fetchall()[0] |
228 | - self.notify(result[0], result[1]) |
229 | + self._notify(result[0], result[1]) |
230 | |
231 | === modified file 'burrow/frontend/wsgi.py' |
232 | --- burrow/frontend/wsgi.py 2011-08-10 05:22:20 +0000 |
233 | +++ burrow/frontend/wsgi.py 2011-08-10 07:23:26 +0000 |
234 | @@ -15,7 +15,6 @@ |
235 | '''WSGI frontend for the burrow server.''' |
236 | |
237 | import json |
238 | -import time |
239 | import types |
240 | |
241 | import eventlet |
242 | @@ -39,30 +38,6 @@ |
243 | DEFAULT_HIDE = 0 |
244 | |
245 | |
246 | -def wait_on_queue(method): |
247 | - '''Decorator to wait on an account/queue if the wait option is |
248 | - given. This will block until a message in the queue is ready or |
249 | - the timeout expires.''' |
250 | - def wrapper(self, req, account, queue, *args, **kwargs): |
251 | - '''Wrapper method for wait_on_queue.''' |
252 | - wait = 0 |
253 | - if 'wait' in req.params: |
254 | - wait = int(req.params['wait']) |
255 | - if wait > 0: |
256 | - wait += time.time() |
257 | - while True: |
258 | - res = method(self, req, account, queue, *args, **kwargs) |
259 | - if wait == 0 or res.status_int != 404: |
260 | - break |
261 | - now = time.time() |
262 | - if wait - now > 0: |
263 | - self.backend.wait(account, queue, wait - now) |
264 | - if wait < time.time(): |
265 | - break |
266 | - return res |
267 | - return wrapper |
268 | - |
269 | - |
270 | class Frontend(burrow.frontend.Frontend): |
271 | '''Frontend implementation that implements the Burrow v1.0 protocol |
272 | using WSGI.''' |
273 | @@ -148,21 +123,18 @@ |
274 | return self._response(body=self.backend.get_queues(account, filters)) |
275 | |
276 | @webob.dec.wsgify |
277 | - @wait_on_queue |
278 | def _delete_messages(self, req, account, queue): |
279 | filters = self._parse_filters(req) |
280 | messages = self.backend.delete_messages(account, queue, filters) |
281 | return self._response(body=messages) |
282 | |
283 | @webob.dec.wsgify |
284 | - @wait_on_queue |
285 | def _get_messages(self, req, account, queue): |
286 | filters = self._parse_filters(req) |
287 | messages = self.backend.get_messages(account, queue, filters) |
288 | return self._response(body=messages) |
289 | |
290 | @webob.dec.wsgify |
291 | - @wait_on_queue |
292 | def _post_messages(self, req, account, queue): |
293 | attributes = self._parse_attributes(req) |
294 | filters = self._parse_filters(req) |
295 | @@ -215,6 +187,8 @@ |
296 | filters['match_hidden'] = True |
297 | if 'detail' in req.params: |
298 | filters['detail'] = req.params['detail'] |
299 | + if 'wait' in req.params: |
300 | + filters['wait'] = int(req.params['wait']) |
301 | return filters |
302 | |
303 | def _parse_attributes(self, req, default_ttl=None, default_hide=None): |
304 | |
305 | === modified file 'test/backend/test_http.py' |
306 | --- test/backend/test_http.py 2011-08-10 05:22:20 +0000 |
307 | +++ test/backend/test_http.py 2011-08-10 07:23:26 +0000 |
308 | @@ -34,7 +34,7 @@ |
309 | |
310 | def kill_server(): |
311 | try: |
312 | - pid_file = open('server.pid', 'r') |
313 | + pid_file = open('TestHTTP.pid', 'r') |
314 | pid = pid_file.read() |
315 | pid_file.close() |
316 | try: |
317 | @@ -43,12 +43,13 @@ |
318 | os.kill(int(pid), signal.SIGTERM) |
319 | except OSError: |
320 | pass |
321 | - os.unlink('server.pid') |
322 | + os.unlink('TestHTTP.pid') |
323 | except IOError: |
324 | pass |
325 | |
326 | |
327 | def start_server(): |
328 | + kill_server() |
329 | pid = os.fork() |
330 | if pid == 0: |
331 | try: |
332 | @@ -66,12 +67,11 @@ |
333 | server.frontends[0].default_ttl = 0 |
334 | server.run() |
335 | os.exit(0) |
336 | - pid_file = open('server.pid', 'w') |
337 | + pid_file = open('TestHTTP.pid', 'w') |
338 | pid_file.write(str(pid)) |
339 | pid_file.close() |
340 | + atexit.register(kill_server) |
341 | time.sleep(1) |
342 | |
343 | |
344 | -kill_server() |
345 | start_server() |
346 | -atexit.register(kill_server) |
347 | |
348 | === modified file 'test/backend/test_memory.py' |
349 | --- test/backend/test_memory.py 2011-08-10 05:22:20 +0000 |
350 | +++ test/backend/test_memory.py 2011-08-10 07:23:26 +0000 |
351 | @@ -16,6 +16,9 @@ |
352 | import time |
353 | import unittest |
354 | |
355 | +import eventlet |
356 | +eventlet.monkey_patch(socket=True) |
357 | + |
358 | import burrow.backend |
359 | import burrow.backend.memory |
360 | |
361 | @@ -884,7 +887,48 @@ |
362 | self.assertEquals(dict(id='0', ttl=0, hide=0, body='0'), message) |
363 | self.delete_messages() |
364 | |
365 | + def test_message_create_wait(self): |
366 | + self.success = False |
367 | + thread = eventlet.spawn(self.get_messages) |
368 | + eventlet.spawn_after(0.2, |
369 | + self.backend.create_message, 'a', 'q', 'm', 'test') |
370 | + thread.wait() |
371 | + self.assertTrue(self.success) |
372 | + self.delete_messages() |
373 | + |
374 | + def test_message_update_wait(self): |
375 | + attributes = dict(hide=100) |
376 | + self.backend.create_message('a', 'q', 'm', 'test', attributes) |
377 | + self.success = False |
378 | + thread = eventlet.spawn(self.get_messages) |
379 | + attributes = dict(hide=0) |
380 | + eventlet.spawn_after(0.2, |
381 | + self.backend.update_message, 'a', 'q', 'm', attributes) |
382 | + thread.wait() |
383 | + self.assertTrue(self.success) |
384 | + self.delete_messages() |
385 | + |
386 | + def test_messages_update_wait(self): |
387 | + attributes = dict(hide=100) |
388 | + self.backend.create_message('a', 'q', 'm', 'test', attributes) |
389 | + self.success = False |
390 | + thread = eventlet.spawn(self.get_messages) |
391 | + attributes = dict(hide=0) |
392 | + filters = dict(match_hidden=True) |
393 | + messages = self.backend.update_messages('a', 'q', attributes, filters) |
394 | + eventlet.spawn_after(0.2, list, messages) |
395 | + thread.wait() |
396 | + self.assertTrue(self.success) |
397 | + self.delete_messages() |
398 | + |
399 | def delete_messages(self): |
400 | filters = dict(match_hidden=True) |
401 | messages = list(self.backend.delete_messages('a', 'q', filters)) |
402 | self.assertEquals([], messages) |
403 | + |
404 | + def get_messages(self): |
405 | + message = dict(id='m', ttl=0, hide=0, body='test') |
406 | + filters = dict(wait=2) |
407 | + messages = list(self.backend.get_messages('a', 'q', filters)) |
408 | + self.assertEquals([message], messages) |
409 | + self.success = True |
410 | |
411 | === removed directory 'test/frontend' |
412 | === removed file 'test/frontend/__init__.py' |
413 | === removed file 'test/frontend/test_wsgi.py' |
414 | --- test/frontend/test_wsgi.py 2011-08-09 17:22:31 +0000 |
415 | +++ test/frontend/test_wsgi.py 1970-01-01 00:00:00 +0000 |
416 | @@ -1,303 +0,0 @@ |
417 | -# Copyright (C) 2011 OpenStack LLC. |
418 | -# |
419 | -# Licensed under the Apache License, Version 2.0 (the "License"); |
420 | -# you may not use this file except in compliance with the License. |
421 | -# You may obtain a copy of the License at |
422 | -# |
423 | -# http://www.apache.org/licenses/LICENSE-2.0 |
424 | -# |
425 | -# Unless required by applicable law or agreed to in writing, software |
426 | -# distributed under the License is distributed on an "AS IS" BASIS, |
427 | -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
428 | -# See the License for the specific language governing permissions and |
429 | -# limitations under the License. |
430 | - |
431 | -import ConfigParser |
432 | -import json |
433 | -import time |
434 | -import unittest |
435 | - |
436 | -import eventlet |
437 | -import webob |
438 | - |
439 | -import burrow.backend.memory |
440 | -import burrow.backend.sqlite |
441 | -import burrow.frontend.wsgi |
442 | - |
443 | - |
444 | -class TestWSGIMemory(unittest.TestCase): |
445 | - '''Unittests for the WSGI frontend to SQLite backend.''' |
446 | - backend_class = burrow.backend.memory.Backend |
447 | - |
448 | - def setUp(self): |
449 | - config = (ConfigParser.ConfigParser(), 'test') |
450 | - self.backend = self.backend_class(config) |
451 | - self.frontend = burrow.frontend.wsgi.Frontend(config, self.backend) |
452 | - self.frontend.default_ttl = 0 |
453 | - self._get_url('', status=404) |
454 | - self._get_url('/a', status=404) |
455 | - self._get_url('/a/q', status=404) |
456 | - |
457 | - def tearDown(self): |
458 | - self._get_url('/a/q', status=404) |
459 | - self._get_url('/a', status=404) |
460 | - self._get_url('', status=404) |
461 | - |
462 | - def test_account(self): |
463 | - self._put_url('/a/q/1') |
464 | - result = self._get_url('') |
465 | - self.assertEquals(result, ['a']) |
466 | - self._delete_url('/a') |
467 | - |
468 | - def test_queue(self): |
469 | - self._put_url('/a/q/1') |
470 | - result = self._get_url('/a') |
471 | - self.assertEquals(result, ['q']) |
472 | - self._delete_url('/a/q') |
473 | - |
474 | - def test_message(self): |
475 | - self._put_url('/a/q/1', body='b') |
476 | - result = self._get_url('/a/q') |
477 | - self.assertMessages(result, [self.message('1', body='b')]) |
478 | - self._delete_url('/a/q/1') |
479 | - |
480 | - def test_message_post(self): |
481 | - self._put_url('/a/q/1', body='b') |
482 | - for x in range(0, 3): |
483 | - self._post_url('/a/q/1?ttl=%d&hide=%d' % (x, x), status=204) |
484 | - result = self._get_url('/a/q?match_hidden=true') |
485 | - message = self.message('1', x, x, body='b') |
486 | - self.assertMessages(result, [message]) |
487 | - self._delete_url('/a/q/1') |
488 | - |
489 | - def test_message_put(self): |
490 | - for x in range(0, 3): |
491 | - url = '/a/q/1?ttl=%d&hide=%d' % (x, x) |
492 | - status = 201 if x == 0 else 204 |
493 | - self._put_url(url, body=str(x), status=status) |
494 | - result = self._get_url('/a/q?match_hidden=true') |
495 | - message = self.message('1', x, x, body=str(x)) |
496 | - self.assertMessages(result, [message]) |
497 | - self._delete_url('/a/q/1') |
498 | - |
499 | - def test_message_delete_limit(self): |
500 | - [self._put_url('/a/q/%d' % x) for x in range(1, 5)] |
501 | - result = self._delete_url('/a/q?limit=3&detail=all', status=200) |
502 | - messages = [] |
503 | - messages.append(self.message('1')) |
504 | - messages.append(self.message('2')) |
505 | - messages.append(self.message('3')) |
506 | - self.assertMessages(result, messages) |
507 | - result = self._delete_url('/a/q?limit=3&detail=all', status=200) |
508 | - message = self.message('4') |
509 | - self.assertMessages(result, [message]) |
510 | - |
511 | - def test_message_get_limit(self): |
512 | - [self._put_url('/a/q/%d' % x) for x in range(1, 5)] |
513 | - for x in range(0, 4): |
514 | - result = self._get_url('/a/q?limit=3') |
515 | - messages = [] |
516 | - for y in range(x, 4)[:3]: |
517 | - messages.append(self.message(str(y + 1))) |
518 | - self.assertMessages(result, messages) |
519 | - self._delete_url('/a/q/%d' % (x + 1)) |
520 | - |
521 | - def test_message_post_limit(self): |
522 | - [self._put_url('/a/q/%d' % x) for x in range(1, 5)] |
523 | - for x in range(0, 4): |
524 | - result = self._post_url('/a/q?limit=3&ttl=%d&detail=all' % x) |
525 | - messages = [] |
526 | - for y in range(x, 4)[:3]: |
527 | - messages.append(self.message(str(y + 1), x)) |
528 | - self.assertMessages(result, messages) |
529 | - self._delete_url('/a/q/%d' % (x + 1)) |
530 | - |
531 | - def test_message_delete_marker(self): |
532 | - [self._put_url('/a/q/%d' % x) for x in range(1, 5)] |
533 | - result = self._delete_url('/a/q?marker=2&detail=all', status=200) |
534 | - messages = [] |
535 | - messages.append(self.message('3')) |
536 | - messages.append(self.message('4')) |
537 | - self.assertMessages(result, messages) |
538 | - result = self._delete_url('/a/q?marker=5&detail=all', status=200) |
539 | - messages = [] |
540 | - messages.append(self.message('1')) |
541 | - messages.append(self.message('2')) |
542 | - self.assertMessages(result, messages) |
543 | - |
544 | - def test_message_get_marker(self): |
545 | - [self._put_url('/a/q/%d' % x) for x in range(1, 5)] |
546 | - for x in range(0, 4): |
547 | - result = self._get_url('/a/q?marker=%d' % x) |
548 | - messages = [] |
549 | - for y in range(x, 4): |
550 | - messages.append(self.message(str(y + 1))) |
551 | - self.assertMessages(result, messages) |
552 | - self._delete_url('/a/q/%d' % (x + 1)) |
553 | - |
554 | - def test_message_post_marker(self): |
555 | - [self._put_url('/a/q/%d' % x) for x in range(1, 5)] |
556 | - for x in range(0, 4): |
557 | - url = '/a/q?marker=%d&ttl=%d&detail=all' % (x, x) |
558 | - result = self._post_url(url) |
559 | - messages = [] |
560 | - for y in range(x, 4): |
561 | - messages.append(self.message(str(y + 1), x)) |
562 | - self.assertMessages(result, messages) |
563 | - self._delete_url('/a/q/%d' % (x + 1)) |
564 | - |
565 | - def test_message_delete_limit_marker(self): |
566 | - [self._put_url('/a/q/%d' % x) for x in range(1, 5)] |
567 | - url = '/a/q?limit=2&marker=1&detail=all' |
568 | - result = self._delete_url(url, status=200) |
569 | - messages = [] |
570 | - messages.append(self.message('2')) |
571 | - messages.append(self.message('3')) |
572 | - self.assertMessages(result, messages) |
573 | - url = '/a/q?limit=2&marker=5&detail=all' |
574 | - result = self._delete_url(url, status=200) |
575 | - messages = [] |
576 | - messages.append(self.message('1')) |
577 | - messages.append(self.message('4')) |
578 | - self.assertMessages(result, messages) |
579 | - |
580 | - def test_message_get_limit_marker(self): |
581 | - [self._put_url('/a/q/%d' % x) for x in range(1, 5)] |
582 | - for x in range(0, 4): |
583 | - result = self._get_url('/a/q?limit=2&marker=%d' % x) |
584 | - messages = [] |
585 | - for y in range(x, 4)[:2]: |
586 | - messages.append(self.message(str(y + 1))) |
587 | - self.assertMessages(result, messages) |
588 | - self._delete_url('/a/q/%d' % (x + 1)) |
589 | - |
590 | - def test_message_post_limit_marker(self): |
591 | - [self._put_url('/a/q/%d' % x) for x in range(1, 5)] |
592 | - for x in range(0, 4): |
593 | - url = '/a/q?limit=2&marker=%d&ttl=%d&detail=all' % (x, x) |
594 | - result = self._post_url(url) |
595 | - messages = [] |
596 | - for y in range(x, 4)[:2]: |
597 | - messages.append(self.message(str(y + 1), x)) |
598 | - self.assertMessages(result, messages) |
599 | - self._delete_url('/a/q/%d' % (x + 1)) |
600 | - |
601 | - def test_message_ttl(self): |
602 | - self._put_url('/a/q/1?ttl=1') |
603 | - result = self._get_url('/a/q/1') |
604 | - self.assertMessages([result], [self.message('1', 1)]) |
605 | - time.sleep(1) |
606 | - self.backend.clean() |
607 | - self._get_url('/a/q/1', status=404) |
608 | - self._put_url('/a/q/1') |
609 | - result = self._get_url('/a/q/1') |
610 | - self.assertMessages([result], [self.message('1')]) |
611 | - self._post_url('/a/q/1?ttl=1', status=204) |
612 | - result = self._get_url('/a/q/1') |
613 | - self.assertMessages([result], [self.message('1', 1)]) |
614 | - time.sleep(1) |
615 | - self.backend.clean() |
616 | - self._get_url('/a/q/1', status=404) |
617 | - |
618 | - def test_message_hide(self): |
619 | - self._put_url('/a/q/1?hide=1') |
620 | - result = self._get_url('/a/q/1') |
621 | - self.assertMessages([result], [self.message('1', hide=1)]) |
622 | - time.sleep(1) |
623 | - self.backend.clean() |
624 | - result = self._get_url('/a/q/1') |
625 | - self.assertMessages([result], [self.message('1')]) |
626 | - self._post_url('/a/q/1?hide=1', status=204) |
627 | - result = self._get_url('/a/q/1') |
628 | - self.assertMessages([result], [self.message('1', hide=1)]) |
629 | - time.sleep(1) |
630 | - self.backend.clean() |
631 | - result = self._get_url('/a/q/1') |
632 | - self.assertMessages([result], [self.message('1')]) |
633 | - self._delete_url('/a/q/1') |
634 | - |
635 | - def _message_wait(self): |
636 | - result = self._get_url('/a/q?wait=2') |
637 | - self.assertMessages(result, [self.message('1')]) |
638 | - self.success = True |
639 | - |
640 | - def test_message_put_wait(self): |
641 | - self.success = False |
642 | - thread = eventlet.spawn(self._message_wait) |
643 | - eventlet.spawn_after(0.2, self._put_url, '/a/q/1') |
644 | - thread.wait() |
645 | - self.assertTrue(self.success) |
646 | - self._delete_url('/a/q/1') |
647 | - |
648 | - def test_message_put_wait_overwrite(self): |
649 | - self.success = False |
650 | - self._put_url('/a/q/1?hide=10') |
651 | - thread = eventlet.spawn(self._message_wait) |
652 | - eventlet.spawn_after(0.2, self._put_url, '/a/q/1?hide=0', status=204) |
653 | - thread.wait() |
654 | - self.assertTrue(self.success) |
655 | - self._delete_url('/a/q/1') |
656 | - |
657 | - def test_message_put_wait_cleanup(self): |
658 | - self.success = False |
659 | - self._put_url('/a/q/1?hide=1') |
660 | - thread = eventlet.spawn(self._message_wait) |
661 | - eventlet.spawn_after(1, self.backend.clean) |
662 | - thread.wait() |
663 | - self.assertTrue(self.success) |
664 | - self._delete_url('/a/q/1') |
665 | - |
666 | - def test_message_post_wait(self): |
667 | - self.success = False |
668 | - self._put_url('/a/q/1?hide=10') |
669 | - thread = eventlet.spawn(self._message_wait) |
670 | - eventlet.spawn_after(0.2, self._post_url, '/a/q/1?hide=0', status=204) |
671 | - thread.wait() |
672 | - self.assertTrue(self.success) |
673 | - self._delete_url('/a/q/1') |
674 | - |
675 | - def test_message_post_wait_queue(self): |
676 | - self.success = False |
677 | - self._put_url('/a/q/1?hide=10') |
678 | - thread = eventlet.spawn(self._message_wait) |
679 | - url = '/a/q?hide=0&match_hidden=true' |
680 | - eventlet.spawn_after(0.2, self._post_url, url, status=204) |
681 | - thread.wait() |
682 | - self.assertTrue(self.success) |
683 | - self._delete_url('/a/q/1') |
684 | - |
685 | - def message(self, id, ttl=0, hide=0, body=''): |
686 | - return dict(id=id, ttl=ttl, hide=hide, body=body) |
687 | - |
688 | - def assertMessages(self, first, second): |
689 | - self.assertEquals(len(first), len(second)) |
690 | - for x in xrange(0, len(second)): |
691 | - self.assertEquals(first[x]['id'], second[x]['id']) |
692 | - self.assertAlmostEquals(first[x]['ttl'], second[x]['ttl']) |
693 | - self.assertAlmostEquals(first[x]['hide'], second[x]['hide']) |
694 | - self.assertEquals(first[x]['body'], second[x]['body']) |
695 | - |
696 | - def _delete_url(self, url, status=204, **kwargs): |
697 | - return self._url('DELETE', url, status=status, **kwargs) |
698 | - |
699 | - def _get_url(self, url, **kwargs): |
700 | - return self._url('GET', url, **kwargs) |
701 | - |
702 | - def _post_url(self, url, **kwargs): |
703 | - return self._url('POST', url, **kwargs) |
704 | - |
705 | - def _put_url(self, url, status=201, **kwargs): |
706 | - return self._url('PUT', url, status=status, **kwargs) |
707 | - |
708 | - def _url(self, method, url, body='', status=200): |
709 | - req = webob.Request.blank('/v1.0' + url, method=method, body=body) |
710 | - res = req.get_response(self.frontend) |
711 | - self.assertEquals(res.status_int, status) |
712 | - if status == 200: |
713 | - return json.loads(res.body) |
714 | - return None |
715 | - |
716 | - |
717 | -class TestWSGISQLite(TestWSGIMemory): |
718 | - '''Unittests for the WSGI frontend to SQLite backend.''' |
719 | - backend_class = burrow.backend.sqlite.Backend |