31
32
def make_message(message_id, body='body', headers=None, hidden=False):
32
33
if headers is None:
34
headers['Message-Id'] = message_id
36
'message_id': message_id,
38
'thread_id': message_id,
39
'date': headers.get('date', '2005-01-01'),
40
'subject': headers.get('subject', 'subject'),
41
'author': headers.get('author', 'author'),
44
'replies': headers.get('in-reply-to', None),
36
'Message-Id': message_id,
42
message_headers.update(headers.items())
44
message.set_payload(body)
45
for key, value in message_headers.items():
47
return make_json_message(message_id, message.as_string(), hidden)
50
50
def make_mime_message(message_id, body='body', headers=None, hidden=False,
51
51
attachment_type=None):
52
message = MIMEMultipart()
53
message.attach(MIMEText(body))
52
parts = MIMEMultipart()
53
parts.attach(MIMEText(body))
54
54
if attachment_type is not None:
55
55
attachment = Message()
56
56
attachment.set_payload('attactment data.')
57
57
attachment['Content-Type'] = attachment_type
58
58
attachment['Content-Disposition'] = 'attachment; filename="file.ext"'
59
message.attach(attachment)
60
return make_message(message_id, message.get_payload(), headers, hidden)
59
parts.attach(attachment)
60
return make_message(message_id, parts.as_string(), headers, hidden)
63
63
class ForkedFakeService:
64
64
"""A Grackle service fake, as a ContextManager."""
66
def __init__(self, port, messages=None, write_logs=False):
66
def __init__(self, port, message_archives=None, write_logs=False):
69
69
:param port: The tcp port to use.
70
:param messages: A dict of lists of dicts representing messages. The
71
outer dict represents the archive, the list represents the list of
72
messages for that archive.
70
:param message_archives: A dict of lists of dicts representing
71
archives of messages. The outer dict represents the archive,
72
the list represents the list of messages for that archive.
73
73
:param write_logs: If true, log messages will be written to stdout.
77
if message_archives is None:
78
self.message_archives = {}
80
self.messages = messages
80
self.message_archives = message_archives
81
81
self.read_end, self.write_end = os.pipe()
82
82
self.write_logs = write_logs
85
def from_client(client, messages=None):
85
def from_client(client, message_archives=None):
86
86
"""Instantiate a ForkedFakeService from the client.
88
88
:param port: The client to provide service for.
89
:param messages: A dict of lists of dicts representing messages. The
90
outer dict represents the archive, the list represents the list of
91
messages for that archive.
89
:param message_archives: A dict of lists of dicts representing
90
archives of messages. The outer dict represents the archive,
91
the list represents the list of messages for that archive.
93
return ForkedFakeService(client.port, messages)
93
return ForkedFakeService(client.port, message_archives)
95
95
def is_ready(self):
96
96
"""Tell the parent process that the server is ready for writes."""
136
136
def do_POST(self):
137
137
"""Create a message on POST."""
138
message = self.rfile.read(int(self.headers['content-length']))
139
if message == 'This is a message':
140
self.send_response(httplib.CREATED)
138
scheme, netloc, path, params, query_string, fragments = (
140
parts = path.split('/')
141
if parts[1] != 'archive':
142
# This is an unknonwn operation?
144
if 'content-length' in self.headers:
145
operation = 'put_message'
144
self.send_error(httplib.BAD_REQUEST)
147
operation = 'hide_message'
148
if operation == 'put_message':
149
message = self.rfile.read(int(self.headers['content-length']))
151
# This expected path is /archive/archive_id/message_id.
152
self.server.store.put_message(parts[2], parts[3], message)
153
self.send_response(httplib.CREATED)
157
self.send_error(httplib.BAD_REQUEST)
158
elif operation == 'hide_message':
160
# This expected path is /archive/archive_id/message_id.
161
response = self.server.store.hide_message(
162
parts[2], parts[3], query_string)
163
self.send_response(httplib.OK)
165
self.wfile.write(simplejson.dumps(response))
167
self.send_error(httplib.BAD_REQUEST)
146
169
def do_GET(self):
147
170
"""Retrieve a list of messages on GET."""
172
195
def test_put_message(self):
173
196
client = GrackleClient('localhost', 8420)
174
with ForkedFakeService.from_client(client):
175
client.put_message('arch1', 'asdf', StringIO('This is a message'))
197
message_archives = {'arch1': []}
198
with ForkedFakeService.from_client(client, message_archives):
199
client.put_message('arch1', 'id1', StringIO('This is a message'))
200
response = client.get_messages('arch1')
201
self.assertEqual(1, len(response['messages']))
202
message = response['messages'][0]
203
self.assertEqual('id1', message['message_id'])
205
def test_put_message_without_archive(self):
206
client = GrackleClient('localhost', 8421)
207
message_archives = {'arch1': []}
208
with ForkedFakeService.from_client(client, message_archives):
176
209
with ExpectedException(Exception, 'wtf'):
177
client.put_message('arch1', 'asdf',
178
StringIO('This is not a message'))
210
client.put_message('no-archive', 'id1', StringIO('message'))
181
213
class TestGetMessages(TestCase):
223
255
def get_messages_member_order_test(self, key):
224
256
client = GrackleClient('localhost', 8439)
227
make_message('foo', headers={key: '2011-03-25'}),
228
make_message('bar', headers={key: '2011-03-24'}),
263
make_message('foo', headers={header_name: '2011-03-25'}),
264
make_message('bar', headers={header_name: '2011-03-24'}),
230
266
with ForkedFakeService.from_client(client, archive):
231
267
response = client.get_messages('baz')
456
490
with ForkedFakeService.from_client(client, archive):
457
491
with ExpectedException(UnparsableDateRange, ''):
458
492
client.get_messages('baz', date_range='2012-01..12-02..12-03')
495
class TestHideMessages(TestCase):
497
def test_hide_message_true(self):
498
client = GrackleClient('localhost', 8470)
501
make_message('foo', hidden=False),
503
with ForkedFakeService.from_client(client, archive):
504
response = client.hide_message('baz', 'foo', hidden=True)
505
self.assertEqual('foo', response['message_id'])
506
self.assertIs(True, response['hidden'])
508
def test_hide_message_false(self):
509
client = GrackleClient('localhost', 8470)
512
make_message('foo', hidden=True),
514
with ForkedFakeService.from_client(client, archive):
515
response = client.hide_message('baz', 'foo', hidden=False)
516
self.assertEqual('foo', response['message_id'])
517
self.assertIs(False, response['hidden'])