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