Merge lp:~eday/burrow/backend-unittests into lp:burrow

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
Reviewer Review Type Date Requested Status
Burrow Core Team Pending
Review via email: mp+71000@code.launchpad.net

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
=== modified file 'burrow/backend/__init__.py'
--- burrow/backend/__init__.py 2011-08-10 05:22:20 +0000
+++ burrow/backend/__init__.py 2011-08-10 07:23:26 +0000
@@ -66,26 +66,6 @@
66 def update_message(self, account, queue, message, attributes, filters={}):66 def update_message(self, account, queue, message, attributes, filters={}):
67 return None67 return None
6868
69 def notify(self, account, queue):
70 '''Notify any waiting callers that the account/queue has
71 a visible message.'''
72 queue = '%s/%s' % (account, queue)
73 if queue in self.queues:
74 for count in xrange(0, self.queues[queue].getting()):
75 self.queues[queue].put(0)
76
77 def wait(self, account, queue, seconds):
78 '''Wait for a message to appear in the account/queue.'''
79 queue = '%s/%s' % (account, queue)
80 if queue not in self.queues:
81 self.queues[queue] = eventlet.Queue()
82 try:
83 self.queues[queue].get(timeout=seconds)
84 except Exception:
85 pass
86 if self.queues[queue].getting() == 0:
87 del self.queues[queue]
88
89 def clean(self):69 def clean(self):
90 '''This method should remove all messages with an expired70 '''This method should remove all messages with an expired
91 TTL and make hidden messages that have an expired hide time71 TTL and make hidden messages that have an expired hide time
@@ -124,6 +104,60 @@
124 raise burrow.backend.InvalidArguments(detail)104 raise burrow.backend.InvalidArguments(detail)
125 return detail105 return detail
126106
107 def _notify(self, account, queue):
108 '''Notify any waiting callers that the account/queue has
109 a visible message.'''
110 queue = '%s/%s' % (account, queue)
111 if queue in self.queues:
112 for count in xrange(0, self.queues[queue].getting()):
113 self.queues[queue].put(0)
114
115 def _wait(self, account, queue, seconds):
116 '''Wait for a message to appear in the account/queue.'''
117 queue = '%s/%s' % (account, queue)
118 if queue not in self.queues:
119 self.queues[queue] = eventlet.Queue()
120 try:
121 self.queues[queue].get(timeout=seconds)
122 except Exception:
123 pass
124 if self.queues[queue].getting() == 0:
125 del self.queues[queue]
126
127
128def wait_without_attributes(method):
129 def wrapper(self, account, queue, filters={}):
130 original = lambda: method(self, account, queue, filters)
131 return wait(self, account, queue, filters, original)
132 return wrapper
133
134
135def wait_with_attributes(method):
136 def wrapper(self, account, queue, attributes, filters={}):
137 original = lambda: method(self, account, queue, attributes, filters)
138 return wait(self, account, queue, filters, original)
139 return wrapper
140
141
142def wait(self, account, queue, filters, method):
143 '''Decorator to wait on a queue if the wait option is given. This
144 will block until a message in the queue is ready or the timeout
145 expires.'''
146 wait = filters.get('wait', 0)
147 if wait > 0:
148 wait += time.time()
149 while True:
150 try:
151 for message in method():
152 yield message
153 return
154 except burrow.backend.NotFound, e:
155 now = time.time()
156 if wait - now > 0:
157 self._wait(account, queue, wait - now)
158 if wait < time.time():
159 raise e
160
127161
128class NotFound(Exception):162class NotFound(Exception):
129 pass163 pass
130164
=== modified file 'burrow/backend/http.py'
--- burrow/backend/http.py 2011-08-10 05:22:20 +0000
+++ burrow/backend/http.py 2011-08-10 07:23:26 +0000
@@ -139,7 +139,7 @@
139 return139 return
140 yield body140 yield body
141 if response.status == 400:141 if response.status == 400:
142 raise burrow.backend.InvalidArguments()142 raise burrow.backend.InvalidArguments(response.reason)
143 if response.status == 404:143 if response.status == 404:
144 raise burrow.backend.NotFound()144 raise burrow.backend.NotFound()
145 raise Exception(response.reason)145 raise Exception(response.reason)
146146
=== modified file 'burrow/backend/memory.py'
--- burrow/backend/memory.py 2011-08-09 19:43:03 +0000
+++ burrow/backend/memory.py 2011-08-10 07:23:26 +0000
@@ -67,6 +67,7 @@
67 if detail is not None:67 if detail is not None:
68 yield queue.detail(detail)68 yield queue.detail(detail)
6969
70 @burrow.backend.wait_without_attributes
70 def delete_messages(self, account, queue, filters={}):71 def delete_messages(self, account, queue, filters={}):
71 account, queue = self.accounts.get_queue(account, queue)72 account, queue = self.accounts.get_queue(account, queue)
72 detail = self._get_message_detail(filters)73 detail = self._get_message_detail(filters)
@@ -77,6 +78,7 @@
77 if queue.messages.count() == 0:78 if queue.messages.count() == 0:
78 self.accounts.delete_queue(account.id, queue.id)79 self.accounts.delete_queue(account.id, queue.id)
7980
81 @burrow.backend.wait_without_attributes
80 def get_messages(self, account, queue, filters={}):82 def get_messages(self, account, queue, filters={}):
81 account, queue = self.accounts.get_queue(account, queue)83 account, queue = self.accounts.get_queue(account, queue)
82 detail = self._get_message_detail(filters, 'all')84 detail = self._get_message_detail(filters, 'all')
@@ -84,6 +86,7 @@
84 if detail is not None:86 if detail is not None:
85 yield message.detail(detail)87 yield message.detail(detail)
8688
89 @burrow.backend.wait_with_attributes
87 def update_messages(self, account, queue, attributes, filters={}):90 def update_messages(self, account, queue, attributes, filters={}):
88 account, queue = self.accounts.get_queue(account, queue)91 account, queue = self.accounts.get_queue(account, queue)
89 notify = False92 notify = False
@@ -99,7 +102,7 @@
99 if detail is not None:102 if detail is not None:
100 yield message.detail(detail)103 yield message.detail(detail)
101 if notify:104 if notify:
102 self.notify(account.id, queue.id)105 self._notify(account.id, queue.id)
103106
104 def create_message(self, account, queue, message, body, attributes={}):107 def create_message(self, account, queue, message, body, attributes={}):
105 account, queue = self.accounts.get_queue(account, queue, True)108 account, queue = self.accounts.get_queue(account, queue, True)
@@ -114,7 +117,7 @@
114 message.hide = hide117 message.hide = hide
115 message.body = body118 message.body = body
116 if created or hide == 0:119 if created or hide == 0:
117 self.notify(account.id, queue.id)120 self._notify(account.id, queue.id)
118 return created121 return created
119122
120 def delete_message(self, account, queue, message, filters={}):123 def delete_message(self, account, queue, message, filters={}):
@@ -142,7 +145,7 @@
142 if hide is not None:145 if hide is not None:
143 message.hide = hide146 message.hide = hide
144 if hide == 0:147 if hide == 0:
145 self.notify(account.id, queue.id)148 self._notify(account.id, queue.id)
146 return message.detail(detail)149 return message.detail(detail)
147150
148 def clean(self):151 def clean(self):
@@ -157,7 +160,7 @@
157 message.hide = 0160 message.hide = 0
158 notify = True161 notify = True
159 if notify:162 if notify:
160 self.notify(account.id, queue.id)163 self._notify(account.id, queue.id)
161 if queue.messages.count() == 0:164 if queue.messages.count() == 0:
162 self.accounts.delete_queue(account.id, queue.id)165 self.accounts.delete_queue(account.id, queue.id)
163166
164167
=== modified file 'burrow/backend/sqlite.py'
--- burrow/backend/sqlite.py 2011-08-09 23:04:39 +0000
+++ burrow/backend/sqlite.py 2011-08-10 07:23:26 +0000
@@ -211,6 +211,7 @@
211 raise burrow.backend.NotFound()211 raise burrow.backend.NotFound()
212 return rows[0][0]212 return rows[0][0]
213213
214 @burrow.backend.wait_without_attributes
214 def delete_messages(self, account, queue, filters={}):215 def delete_messages(self, account, queue, filters={}):
215 account_rowid = self._get_account(account)216 account_rowid = self._get_account(account)
216 queue_rowid = self._get_queue(account_rowid, queue)217 queue_rowid = self._get_queue(account_rowid, queue)
@@ -257,6 +258,7 @@
257 return dict(id=row[0], ttl=ttl, hide=hide, body=str(row[3]))258 return dict(id=row[0], ttl=ttl, hide=hide, body=str(row[3]))
258 return None259 return None
259260
261 @burrow.backend.wait_without_attributes
260 def get_messages(self, account, queue, filters={}):262 def get_messages(self, account, queue, filters={}):
261 account_rowid = self._get_account(account)263 account_rowid = self._get_account(account)
262 queue_rowid = self._get_queue(account_rowid, queue)264 queue_rowid = self._get_queue(account_rowid, queue)
@@ -304,6 +306,7 @@
304 return rows[0]306 return rows[0]
305 return rows[0][0]307 return rows[0][0]
306308
309 @burrow.backend.wait_with_attributes
307 def update_messages(self, account, queue, attributes, filters={}):310 def update_messages(self, account, queue, attributes, filters={}):
308 account_rowid = self._get_account(account)311 account_rowid = self._get_account(account)
309 queue_rowid = self._get_queue(account_rowid, queue)312 queue_rowid = self._get_queue(account_rowid, queue)
@@ -329,7 +332,7 @@
329 if self._update_messages(ttl, hide, ids):332 if self._update_messages(ttl, hide, ids):
330 notify = True333 notify = True
331 if notify:334 if notify:
332 self.notify(account, queue)335 self._notify(account, queue)
333336
334 def _update_messages(self, ttl, hide, ids):337 def _update_messages(self, ttl, hide, ids):
335 query = 'UPDATE messages SET '338 query = 'UPDATE messages SET '
@@ -372,7 +375,7 @@
372 self.db.execute(query, (queue_rowid, message, ttl, hide, body))375 self.db.execute(query, (queue_rowid, message, ttl, hide, body))
373 created = True376 created = True
374 if created or hide == 0:377 if created or hide == 0:
375 self.notify(account, queue)378 self._notify(account, queue)
376 return created379 return created
377380
378 def delete_message(self, account, queue, message, filters={}):381 def delete_message(self, account, queue, message, filters={}):
@@ -396,7 +399,7 @@
396 detail = self._get_message_detail(filters)399 detail = self._get_message_detail(filters)
397 ttl, hide = self._get_attributes(attributes)400 ttl, hide = self._get_attributes(attributes)
398 if self._update_messages(ttl, hide, [row[0]]):401 if self._update_messages(ttl, hide, [row[0]]):
399 self.notify(account, queue)402 self._notify(account, queue)
400 row = list(row)403 row = list(row)
401 if ttl is not None:404 if ttl is not None:
402 row[2] = ttl405 row[2] = ttl
@@ -444,4 +447,4 @@
444 'ON queues.account=accounts.rowid ' \447 'ON queues.account=accounts.rowid ' \
445 'WHERE queues.rowid=?'448 'WHERE queues.rowid=?'
446 result = self.db.execute(query, (queue,)).fetchall()[0]449 result = self.db.execute(query, (queue,)).fetchall()[0]
447 self.notify(result[0], result[1])450 self._notify(result[0], result[1])
448451
=== modified file 'burrow/frontend/wsgi.py'
--- burrow/frontend/wsgi.py 2011-08-10 05:22:20 +0000
+++ burrow/frontend/wsgi.py 2011-08-10 07:23:26 +0000
@@ -15,7 +15,6 @@
15'''WSGI frontend for the burrow server.'''15'''WSGI frontend for the burrow server.'''
1616
17import json17import json
18import time
19import types18import types
2019
21import eventlet20import eventlet
@@ -39,30 +38,6 @@
39DEFAULT_HIDE = 038DEFAULT_HIDE = 0
4039
4140
42def wait_on_queue(method):
43 '''Decorator to wait on an account/queue if the wait option is
44 given. This will block until a message in the queue is ready or
45 the timeout expires.'''
46 def wrapper(self, req, account, queue, *args, **kwargs):
47 '''Wrapper method for wait_on_queue.'''
48 wait = 0
49 if 'wait' in req.params:
50 wait = int(req.params['wait'])
51 if wait > 0:
52 wait += time.time()
53 while True:
54 res = method(self, req, account, queue, *args, **kwargs)
55 if wait == 0 or res.status_int != 404:
56 break
57 now = time.time()
58 if wait - now > 0:
59 self.backend.wait(account, queue, wait - now)
60 if wait < time.time():
61 break
62 return res
63 return wrapper
64
65
66class Frontend(burrow.frontend.Frontend):41class Frontend(burrow.frontend.Frontend):
67 '''Frontend implementation that implements the Burrow v1.0 protocol42 '''Frontend implementation that implements the Burrow v1.0 protocol
68 using WSGI.'''43 using WSGI.'''
@@ -148,21 +123,18 @@
148 return self._response(body=self.backend.get_queues(account, filters))123 return self._response(body=self.backend.get_queues(account, filters))
149124
150 @webob.dec.wsgify125 @webob.dec.wsgify
151 @wait_on_queue
152 def _delete_messages(self, req, account, queue):126 def _delete_messages(self, req, account, queue):
153 filters = self._parse_filters(req)127 filters = self._parse_filters(req)
154 messages = self.backend.delete_messages(account, queue, filters)128 messages = self.backend.delete_messages(account, queue, filters)
155 return self._response(body=messages)129 return self._response(body=messages)
156130
157 @webob.dec.wsgify131 @webob.dec.wsgify
158 @wait_on_queue
159 def _get_messages(self, req, account, queue):132 def _get_messages(self, req, account, queue):
160 filters = self._parse_filters(req)133 filters = self._parse_filters(req)
161 messages = self.backend.get_messages(account, queue, filters)134 messages = self.backend.get_messages(account, queue, filters)
162 return self._response(body=messages)135 return self._response(body=messages)
163136
164 @webob.dec.wsgify137 @webob.dec.wsgify
165 @wait_on_queue
166 def _post_messages(self, req, account, queue):138 def _post_messages(self, req, account, queue):
167 attributes = self._parse_attributes(req)139 attributes = self._parse_attributes(req)
168 filters = self._parse_filters(req)140 filters = self._parse_filters(req)
@@ -215,6 +187,8 @@
215 filters['match_hidden'] = True187 filters['match_hidden'] = True
216 if 'detail' in req.params:188 if 'detail' in req.params:
217 filters['detail'] = req.params['detail']189 filters['detail'] = req.params['detail']
190 if 'wait' in req.params:
191 filters['wait'] = int(req.params['wait'])
218 return filters192 return filters
219193
220 def _parse_attributes(self, req, default_ttl=None, default_hide=None):194 def _parse_attributes(self, req, default_ttl=None, default_hide=None):
221195
=== modified file 'test/backend/test_http.py'
--- test/backend/test_http.py 2011-08-10 05:22:20 +0000
+++ test/backend/test_http.py 2011-08-10 07:23:26 +0000
@@ -34,7 +34,7 @@
3434
35def kill_server():35def kill_server():
36 try:36 try:
37 pid_file = open('server.pid', 'r')37 pid_file = open('TestHTTP.pid', 'r')
38 pid = pid_file.read()38 pid = pid_file.read()
39 pid_file.close()39 pid_file.close()
40 try:40 try:
@@ -43,12 +43,13 @@
43 os.kill(int(pid), signal.SIGTERM)43 os.kill(int(pid), signal.SIGTERM)
44 except OSError:44 except OSError:
45 pass45 pass
46 os.unlink('server.pid')46 os.unlink('TestHTTP.pid')
47 except IOError:47 except IOError:
48 pass48 pass
4949
5050
51def start_server():51def start_server():
52 kill_server()
52 pid = os.fork()53 pid = os.fork()
53 if pid == 0:54 if pid == 0:
54 try:55 try:
@@ -66,12 +67,11 @@
66 server.frontends[0].default_ttl = 067 server.frontends[0].default_ttl = 0
67 server.run()68 server.run()
68 os.exit(0)69 os.exit(0)
69 pid_file = open('server.pid', 'w')70 pid_file = open('TestHTTP.pid', 'w')
70 pid_file.write(str(pid))71 pid_file.write(str(pid))
71 pid_file.close()72 pid_file.close()
73 atexit.register(kill_server)
72 time.sleep(1)74 time.sleep(1)
7375
7476
75kill_server()
76start_server()77start_server()
77atexit.register(kill_server)
7878
=== modified file 'test/backend/test_memory.py'
--- test/backend/test_memory.py 2011-08-10 05:22:20 +0000
+++ test/backend/test_memory.py 2011-08-10 07:23:26 +0000
@@ -16,6 +16,9 @@
16import time16import time
17import unittest17import unittest
1818
19import eventlet
20eventlet.monkey_patch(socket=True)
21
19import burrow.backend22import burrow.backend
20import burrow.backend.memory23import burrow.backend.memory
2124
@@ -884,7 +887,48 @@
884 self.assertEquals(dict(id='0', ttl=0, hide=0, body='0'), message)887 self.assertEquals(dict(id='0', ttl=0, hide=0, body='0'), message)
885 self.delete_messages()888 self.delete_messages()
886889
890 def test_message_create_wait(self):
891 self.success = False
892 thread = eventlet.spawn(self.get_messages)
893 eventlet.spawn_after(0.2,
894 self.backend.create_message, 'a', 'q', 'm', 'test')
895 thread.wait()
896 self.assertTrue(self.success)
897 self.delete_messages()
898
899 def test_message_update_wait(self):
900 attributes = dict(hide=100)
901 self.backend.create_message('a', 'q', 'm', 'test', attributes)
902 self.success = False
903 thread = eventlet.spawn(self.get_messages)
904 attributes = dict(hide=0)
905 eventlet.spawn_after(0.2,
906 self.backend.update_message, 'a', 'q', 'm', attributes)
907 thread.wait()
908 self.assertTrue(self.success)
909 self.delete_messages()
910
911 def test_messages_update_wait(self):
912 attributes = dict(hide=100)
913 self.backend.create_message('a', 'q', 'm', 'test', attributes)
914 self.success = False
915 thread = eventlet.spawn(self.get_messages)
916 attributes = dict(hide=0)
917 filters = dict(match_hidden=True)
918 messages = self.backend.update_messages('a', 'q', attributes, filters)
919 eventlet.spawn_after(0.2, list, messages)
920 thread.wait()
921 self.assertTrue(self.success)
922 self.delete_messages()
923
887 def delete_messages(self):924 def delete_messages(self):
888 filters = dict(match_hidden=True)925 filters = dict(match_hidden=True)
889 messages = list(self.backend.delete_messages('a', 'q', filters))926 messages = list(self.backend.delete_messages('a', 'q', filters))
890 self.assertEquals([], messages)927 self.assertEquals([], messages)
928
929 def get_messages(self):
930 message = dict(id='m', ttl=0, hide=0, body='test')
931 filters = dict(wait=2)
932 messages = list(self.backend.get_messages('a', 'q', filters))
933 self.assertEquals([message], messages)
934 self.success = True
891935
=== removed directory 'test/frontend'
=== removed file 'test/frontend/__init__.py'
=== removed file 'test/frontend/test_wsgi.py'
--- test/frontend/test_wsgi.py 2011-08-09 17:22:31 +0000
+++ test/frontend/test_wsgi.py 1970-01-01 00:00:00 +0000
@@ -1,303 +0,0 @@
1# Copyright (C) 2011 OpenStack LLC.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15import ConfigParser
16import json
17import time
18import unittest
19
20import eventlet
21import webob
22
23import burrow.backend.memory
24import burrow.backend.sqlite
25import burrow.frontend.wsgi
26
27
28class TestWSGIMemory(unittest.TestCase):
29 '''Unittests for the WSGI frontend to SQLite backend.'''
30 backend_class = burrow.backend.memory.Backend
31
32 def setUp(self):
33 config = (ConfigParser.ConfigParser(), 'test')
34 self.backend = self.backend_class(config)
35 self.frontend = burrow.frontend.wsgi.Frontend(config, self.backend)
36 self.frontend.default_ttl = 0
37 self._get_url('', status=404)
38 self._get_url('/a', status=404)
39 self._get_url('/a/q', status=404)
40
41 def tearDown(self):
42 self._get_url('/a/q', status=404)
43 self._get_url('/a', status=404)
44 self._get_url('', status=404)
45
46 def test_account(self):
47 self._put_url('/a/q/1')
48 result = self._get_url('')
49 self.assertEquals(result, ['a'])
50 self._delete_url('/a')
51
52 def test_queue(self):
53 self._put_url('/a/q/1')
54 result = self._get_url('/a')
55 self.assertEquals(result, ['q'])
56 self._delete_url('/a/q')
57
58 def test_message(self):
59 self._put_url('/a/q/1', body='b')
60 result = self._get_url('/a/q')
61 self.assertMessages(result, [self.message('1', body='b')])
62 self._delete_url('/a/q/1')
63
64 def test_message_post(self):
65 self._put_url('/a/q/1', body='b')
66 for x in range(0, 3):
67 self._post_url('/a/q/1?ttl=%d&hide=%d' % (x, x), status=204)
68 result = self._get_url('/a/q?match_hidden=true')
69 message = self.message('1', x, x, body='b')
70 self.assertMessages(result, [message])
71 self._delete_url('/a/q/1')
72
73 def test_message_put(self):
74 for x in range(0, 3):
75 url = '/a/q/1?ttl=%d&hide=%d' % (x, x)
76 status = 201 if x == 0 else 204
77 self._put_url(url, body=str(x), status=status)
78 result = self._get_url('/a/q?match_hidden=true')
79 message = self.message('1', x, x, body=str(x))
80 self.assertMessages(result, [message])
81 self._delete_url('/a/q/1')
82
83 def test_message_delete_limit(self):
84 [self._put_url('/a/q/%d' % x) for x in range(1, 5)]
85 result = self._delete_url('/a/q?limit=3&detail=all', status=200)
86 messages = []
87 messages.append(self.message('1'))
88 messages.append(self.message('2'))
89 messages.append(self.message('3'))
90 self.assertMessages(result, messages)
91 result = self._delete_url('/a/q?limit=3&detail=all', status=200)
92 message = self.message('4')
93 self.assertMessages(result, [message])
94
95 def test_message_get_limit(self):
96 [self._put_url('/a/q/%d' % x) for x in range(1, 5)]
97 for x in range(0, 4):
98 result = self._get_url('/a/q?limit=3')
99 messages = []
100 for y in range(x, 4)[:3]:
101 messages.append(self.message(str(y + 1)))
102 self.assertMessages(result, messages)
103 self._delete_url('/a/q/%d' % (x + 1))
104
105 def test_message_post_limit(self):
106 [self._put_url('/a/q/%d' % x) for x in range(1, 5)]
107 for x in range(0, 4):
108 result = self._post_url('/a/q?limit=3&ttl=%d&detail=all' % x)
109 messages = []
110 for y in range(x, 4)[:3]:
111 messages.append(self.message(str(y + 1), x))
112 self.assertMessages(result, messages)
113 self._delete_url('/a/q/%d' % (x + 1))
114
115 def test_message_delete_marker(self):
116 [self._put_url('/a/q/%d' % x) for x in range(1, 5)]
117 result = self._delete_url('/a/q?marker=2&detail=all', status=200)
118 messages = []
119 messages.append(self.message('3'))
120 messages.append(self.message('4'))
121 self.assertMessages(result, messages)
122 result = self._delete_url('/a/q?marker=5&detail=all', status=200)
123 messages = []
124 messages.append(self.message('1'))
125 messages.append(self.message('2'))
126 self.assertMessages(result, messages)
127
128 def test_message_get_marker(self):
129 [self._put_url('/a/q/%d' % x) for x in range(1, 5)]
130 for x in range(0, 4):
131 result = self._get_url('/a/q?marker=%d' % x)
132 messages = []
133 for y in range(x, 4):
134 messages.append(self.message(str(y + 1)))
135 self.assertMessages(result, messages)
136 self._delete_url('/a/q/%d' % (x + 1))
137
138 def test_message_post_marker(self):
139 [self._put_url('/a/q/%d' % x) for x in range(1, 5)]
140 for x in range(0, 4):
141 url = '/a/q?marker=%d&ttl=%d&detail=all' % (x, x)
142 result = self._post_url(url)
143 messages = []
144 for y in range(x, 4):
145 messages.append(self.message(str(y + 1), x))
146 self.assertMessages(result, messages)
147 self._delete_url('/a/q/%d' % (x + 1))
148
149 def test_message_delete_limit_marker(self):
150 [self._put_url('/a/q/%d' % x) for x in range(1, 5)]
151 url = '/a/q?limit=2&marker=1&detail=all'
152 result = self._delete_url(url, status=200)
153 messages = []
154 messages.append(self.message('2'))
155 messages.append(self.message('3'))
156 self.assertMessages(result, messages)
157 url = '/a/q?limit=2&marker=5&detail=all'
158 result = self._delete_url(url, status=200)
159 messages = []
160 messages.append(self.message('1'))
161 messages.append(self.message('4'))
162 self.assertMessages(result, messages)
163
164 def test_message_get_limit_marker(self):
165 [self._put_url('/a/q/%d' % x) for x in range(1, 5)]
166 for x in range(0, 4):
167 result = self._get_url('/a/q?limit=2&marker=%d' % x)
168 messages = []
169 for y in range(x, 4)[:2]:
170 messages.append(self.message(str(y + 1)))
171 self.assertMessages(result, messages)
172 self._delete_url('/a/q/%d' % (x + 1))
173
174 def test_message_post_limit_marker(self):
175 [self._put_url('/a/q/%d' % x) for x in range(1, 5)]
176 for x in range(0, 4):
177 url = '/a/q?limit=2&marker=%d&ttl=%d&detail=all' % (x, x)
178 result = self._post_url(url)
179 messages = []
180 for y in range(x, 4)[:2]:
181 messages.append(self.message(str(y + 1), x))
182 self.assertMessages(result, messages)
183 self._delete_url('/a/q/%d' % (x + 1))
184
185 def test_message_ttl(self):
186 self._put_url('/a/q/1?ttl=1')
187 result = self._get_url('/a/q/1')
188 self.assertMessages([result], [self.message('1', 1)])
189 time.sleep(1)
190 self.backend.clean()
191 self._get_url('/a/q/1', status=404)
192 self._put_url('/a/q/1')
193 result = self._get_url('/a/q/1')
194 self.assertMessages([result], [self.message('1')])
195 self._post_url('/a/q/1?ttl=1', status=204)
196 result = self._get_url('/a/q/1')
197 self.assertMessages([result], [self.message('1', 1)])
198 time.sleep(1)
199 self.backend.clean()
200 self._get_url('/a/q/1', status=404)
201
202 def test_message_hide(self):
203 self._put_url('/a/q/1?hide=1')
204 result = self._get_url('/a/q/1')
205 self.assertMessages([result], [self.message('1', hide=1)])
206 time.sleep(1)
207 self.backend.clean()
208 result = self._get_url('/a/q/1')
209 self.assertMessages([result], [self.message('1')])
210 self._post_url('/a/q/1?hide=1', status=204)
211 result = self._get_url('/a/q/1')
212 self.assertMessages([result], [self.message('1', hide=1)])
213 time.sleep(1)
214 self.backend.clean()
215 result = self._get_url('/a/q/1')
216 self.assertMessages([result], [self.message('1')])
217 self._delete_url('/a/q/1')
218
219 def _message_wait(self):
220 result = self._get_url('/a/q?wait=2')
221 self.assertMessages(result, [self.message('1')])
222 self.success = True
223
224 def test_message_put_wait(self):
225 self.success = False
226 thread = eventlet.spawn(self._message_wait)
227 eventlet.spawn_after(0.2, self._put_url, '/a/q/1')
228 thread.wait()
229 self.assertTrue(self.success)
230 self._delete_url('/a/q/1')
231
232 def test_message_put_wait_overwrite(self):
233 self.success = False
234 self._put_url('/a/q/1?hide=10')
235 thread = eventlet.spawn(self._message_wait)
236 eventlet.spawn_after(0.2, self._put_url, '/a/q/1?hide=0', status=204)
237 thread.wait()
238 self.assertTrue(self.success)
239 self._delete_url('/a/q/1')
240
241 def test_message_put_wait_cleanup(self):
242 self.success = False
243 self._put_url('/a/q/1?hide=1')
244 thread = eventlet.spawn(self._message_wait)
245 eventlet.spawn_after(1, self.backend.clean)
246 thread.wait()
247 self.assertTrue(self.success)
248 self._delete_url('/a/q/1')
249
250 def test_message_post_wait(self):
251 self.success = False
252 self._put_url('/a/q/1?hide=10')
253 thread = eventlet.spawn(self._message_wait)
254 eventlet.spawn_after(0.2, self._post_url, '/a/q/1?hide=0', status=204)
255 thread.wait()
256 self.assertTrue(self.success)
257 self._delete_url('/a/q/1')
258
259 def test_message_post_wait_queue(self):
260 self.success = False
261 self._put_url('/a/q/1?hide=10')
262 thread = eventlet.spawn(self._message_wait)
263 url = '/a/q?hide=0&match_hidden=true'
264 eventlet.spawn_after(0.2, self._post_url, url, status=204)
265 thread.wait()
266 self.assertTrue(self.success)
267 self._delete_url('/a/q/1')
268
269 def message(self, id, ttl=0, hide=0, body=''):
270 return dict(id=id, ttl=ttl, hide=hide, body=body)
271
272 def assertMessages(self, first, second):
273 self.assertEquals(len(first), len(second))
274 for x in xrange(0, len(second)):
275 self.assertEquals(first[x]['id'], second[x]['id'])
276 self.assertAlmostEquals(first[x]['ttl'], second[x]['ttl'])
277 self.assertAlmostEquals(first[x]['hide'], second[x]['hide'])
278 self.assertEquals(first[x]['body'], second[x]['body'])
279
280 def _delete_url(self, url, status=204, **kwargs):
281 return self._url('DELETE', url, status=status, **kwargs)
282
283 def _get_url(self, url, **kwargs):
284 return self._url('GET', url, **kwargs)
285
286 def _post_url(self, url, **kwargs):
287 return self._url('POST', url, **kwargs)
288
289 def _put_url(self, url, status=201, **kwargs):
290 return self._url('PUT', url, status=status, **kwargs)
291
292 def _url(self, method, url, body='', status=200):
293 req = webob.Request.blank('/v1.0' + url, method=method, body=body)
294 res = req.get_response(self.frontend)
295 self.assertEquals(res.status_int, status)
296 if status == 200:
297 return json.loads(res.body)
298 return None
299
300
301class TestWSGISQLite(TestWSGIMemory):
302 '''Unittests for the WSGI frontend to SQLite backend.'''
303 backend_class = burrow.backend.sqlite.Backend

Subscribers

People subscribed via source and target branches