7
7
from signal import SIGKILL
8
9
from StringIO import StringIO
9
10
from unittest import TestCase
11
from urlparse import urlparse
12
from urlparse import parse_qs
11
14
from testtools import ExpectedException
13
from grackle import client
18
def __init__(self, func_or_method):
19
self.func_or_method = func_or_method
16
from grackle.client import (
22
def threaded_messages(messages):
26
for message in messages:
27
if message.get('in_reply_to') is None:
28
threads[message['message_id']] = [message]
31
pending.append(message)
32
for message in pending:
33
threads[message['in_reply_to']].append(message)
34
return threads.values()
39
def __init__(self, port, messages=None):
42
self.messages = messages
43
self.read_end, self.write_end = os.pipe()
46
os.write(self.write_end, 'asdf')
22
48
def __enter__(self):
53
os.read(self.read_end, 1)
56
def start_server(self):
57
service = HTTPServer(('', self.port), FakeGrackleRequestHandler)
58
service.messages = self.messages
60
service.serve_forever()
30
62
def __exit__(self, exc_type, exc_val, traceback):
31
63
os.kill(self.pid, SIGKILL)
66
SUPPORTED_ORDERS = set(['date', 'author', 'subject', 'thread_subject'])
34
69
class FakeGrackleRequestHandler(BaseHTTPRequestHandler):
43
78
self.send_error(httplib.BAD_REQUEST)
47
service = HTTPServer(('', 8435), FakeGrackleRequestHandler)
48
service.serve_forever()
81
scheme, netloc, path, params, query_string, fragments = (
83
archive = os.path.split(path)[1]
84
query = parse_qs(query_string)
85
parameters = simplejson.loads(query['parameters'][0])
86
order = parameters.get('order')
87
messages = self.server.messages[archive]
88
if order is not None :
89
if order not in SUPPORTED_ORDERS:
90
self.send_response(httplib.BAD_REQUEST)
91
self.wfile.write('Unsupported order')
93
elif order == 'thread_subject':
94
threaded = threaded_messages(messages)
96
threaded.sort(key=lambda t: t[0]['subject'])
97
for thread in threaded:
98
messages.extend(thread)
101
self.server.messages[archive], key=lambda m: m[order])
102
messages = [m for m in messages
103
if 'message_ids' not in parameters or
104
m['message_id'] in parameters['message_ids']]
105
self.send_response(httplib.OK)
107
limit = parameters.get('limit', 100)
108
memo = parameters.get('memo')
109
message_id_indices = dict(
110
(m['message_id'], idx) for idx, m in enumerate(messages))
114
start = message_id_indices[memo.encode('rot13')]
116
previous_memo = messages[start - 1]['message_id'].encode('rot13')
119
end = min(start + limit, len(messages))
120
if end < len(messages):
121
next_memo = messages[end]['message_id'].encode('rot13')
124
messages = messages[start:end]
126
'messages': messages,
127
'next_memo': next_memo,
128
'previous_memo': previous_memo
130
self.wfile.write(simplejson.dumps(response))
133
def fake_grackle_service(client, messages=None):
136
return ForkedFake(client.port, messages)
52
139
class TestPutMessage(TestCase):
54
141
def test_put_message(self):
55
with Forked(run_service):
56
client.put_message('arch1', StringIO('This is a message'))
142
client = GrackleClient('localhost', 8436)
143
with fake_grackle_service(client):
144
client.put_message('arch1', 'asdf', StringIO('This is a message'))
57
145
with ExpectedException(Exception, 'wtf'):
58
client.put_message('arch1', StringIO('This is not a message'))
146
client.put_message('arch1', 'asdf',
147
StringIO('This is not a message'))
150
class TestGetMessages(TestCase):
152
def assertIDOrder(self, ids, messages):
153
self.assertEqual(ids, [m['message_id'] for m in messages])
155
def assertMessageIDs(self, ids, messages):
157
sorted(ids), sorted(messages, key=lambda m:m['message_id']))
159
def test_get_messages(self):
160
client = GrackleClient('localhost', 8435)
161
with fake_grackle_service(client,
163
[{'message_id': 'foo'},
164
{'message_id': 'bar'}]}):
165
response = client.get_messages('baz')
166
self.assertEqual(['bar', 'foo'], sorted(m['message_id'] for m in
167
response['messages']))
168
self.assertIs(None, response['next_memo'])
169
self.assertIs(None, response['previous_memo'])
171
def test_get_messages_by_id(self):
172
client = GrackleClient('localhost', 8437)
173
with fake_grackle_service(client,
175
[{'message_id': 'foo'},
176
{'message_id': 'bar'}]}):
177
response = client.get_messages('baz', message_ids=['foo'])
178
message, = response['messages']
179
self.assertEqual('foo', message['message_id'])
181
def test_get_messages_batching(self):
182
client = GrackleClient('localhost', 8438)
183
with fake_grackle_service(client,
185
[{'message_id': 'foo'},
186
{'message_id': 'bar'}]}):
187
response = client.get_messages('baz', limit=1)
188
self.assertEqual(1, len(response['messages']))
189
messages = response['messages']
190
response = client.get_messages(
191
'baz', limit=1, memo=response['next_memo'])
192
self.assertEqual(1, len(response['messages']))
193
messages.extend(response['messages'])
194
self.assertMessageIDs(['foo', 'bar'], messages)
196
def get_messages_member_order_test(self, key):
197
client = GrackleClient('localhost', 8439)
198
with fake_grackle_service(client,
199
{'baz': [{'message_id': 'foo', key: '2011-03-25'},
200
{'message_id': 'bar', key: '2011-03-24'}]}):
201
response = client.get_messages('baz')
202
self.assertIDOrder(['foo', 'bar'], response['messages'])
203
response = client.get_messages('baz', order=key)
204
self.assertIDOrder(['bar', 'foo'], response['messages'])
206
def test_get_messages_date_order(self):
207
self.get_messages_member_order_test('date')
209
def test_get_messages_author_order(self):
210
self.get_messages_member_order_test('author')
212
def test_get_messages_subject_order(self):
213
self.get_messages_member_order_test('subject')
215
def test_get_messages_thread_subject_order(self):
216
client = GrackleClient('localhost', 8439)
217
with fake_grackle_service(client, {'baz': [
218
{'message_id': 'bar', 'subject': 'y'},
219
{'message_id': 'qux', 'subject': 'z'},
220
{'message_id': 'foo', 'subject': 'x', 'in_reply_to': 'qux'},
222
response = client.get_messages('baz')
223
self.assertIDOrder(['bar', 'qux', 'foo'], response['messages'])
224
response = client.get_messages('baz', order='subject')
225
self.assertIDOrder(['foo', 'bar', 'qux'], response['messages'])
226
response = client.get_messages('baz', order='thread_subject')
227
self.assertIDOrder(['bar', 'qux', 'foo'], response['messages'])
229
def test_get_messages_unsupported_order(self):
230
client = GrackleClient('localhost', 8439)
231
with fake_grackle_service(client,
232
{'baz': [{'message_id': 'foo', 'date': '2011-03-25'},
233
{'message_id': 'bar', 'date': '2011-03-24'}]}):
234
with ExpectedException(UnsupportedOrder):
235
client.get_messages('baz', order='nonsense')