~didrocks/unity/altf10

« back to all changes in this revision

Viewing changes to grackle/tests/test_client.py

  • Committer: Aaron Bentley
  • Date: 2012-01-13 15:41:11 UTC
  • Revision ID: aaron@canonical.com-20120113154111-3vs12qvejtwgrlh3
RemoveĀ uselessĀ code.

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
    HTTPServer,
3
3
    BaseHTTPRequestHandler,
4
4
    )
5
 
from email.message import Message
6
 
from email.mime.multipart import MIMEMultipart
7
 
from email.mime.text import MIMEText
8
5
import httplib
9
 
import logging
10
6
import os
11
7
from signal import SIGKILL
12
8
import simplejson
13
9
from StringIO import StringIO
14
 
import sys
15
10
from unittest import TestCase
16
11
from urlparse import urlparse
 
12
from urlparse import parse_qs
17
13
 
18
14
from testtools import ExpectedException
19
15
 
20
16
from grackle.client import (
21
17
    GrackleClient,
22
 
    UnparsableDateRange,
23
 
    UnsupportedDisplayType,
24
18
    UnsupportedOrder,
25
19
    )
26
 
from grackle.store import (
27
 
    MemoryStore,
28
 
    )
29
 
 
30
 
 
31
 
def make_message(message_id, body='body', headers=None, hidden=False):
32
 
    if headers is None:
33
 
        headers = {}
34
 
    headers['Message-Id'] = message_id
35
 
    message = {
36
 
        'message_id': message_id,
37
 
        'headers': headers,
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'),
42
 
        'hidden': hidden,
43
 
        'attachments': [],
44
 
        'replies': headers.get('in-reply-to', None),
45
 
        'body': body,
46
 
        }
47
 
    return message
48
 
 
49
 
 
50
 
def make_mime_message(message_id, body='body', headers=None, hidden=False,
51
 
                      attachment_type=None):
52
 
    message = MIMEMultipart()
53
 
    message.attach(MIMEText(body))
54
 
    if attachment_type is not None:
55
 
        attachment = Message()
56
 
        attachment.set_payload('attactment data.')
57
 
        attachment['Content-Type'] = attachment_type
58
 
        attachment['Content-Disposition'] = 'attachment; filename="file.ext"'
59
 
        message.attach(attachment)
60
 
    return make_message(message_id, message.get_payload(), headers, hidden)
61
 
 
62
 
 
63
 
class ForkedFakeService:
64
 
    """A Grackle service fake, as a ContextManager."""
65
 
 
66
 
    def __init__(self, port, message_archives=None, write_logs=False):
67
 
        """Constructor.
68
 
 
69
 
        :param port: The tcp port to use.
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
 
        :param write_logs: If true, log messages will be written to stdout.
74
 
        """
 
20
 
 
21
 
 
22
def threaded_messages(messages):
 
23
    threads = {}
 
24
    count = 0
 
25
    pending = []
 
26
    for message in messages:
 
27
        if message.get('in_reply_to') is None:
 
28
            threads[message['message_id']] = [message]
 
29
            count += 1
 
30
        else:
 
31
            pending.append(message)
 
32
    for message in pending:
 
33
        threads[message['in_reply_to']].append(message)
 
34
    return threads.values()
 
35
 
 
36
 
 
37
class GrackleStore:
 
38
 
 
39
    def __init__(self, messages):
 
40
        self.messages = messages
 
41
 
 
42
    def get_messages(self, archive_id, query_string):
 
43
        query = parse_qs(query_string)
 
44
        parameters = simplejson.loads(query['parameters'][0])
 
45
        order = parameters.get('order')
 
46
        messages = self.messages[archive_id]
 
47
        if order is not None :
 
48
            if order not in SUPPORTED_ORDERS:
 
49
                raise UnsupportedOrder
 
50
            elif order.startswith('thread_'):
 
51
                threaded = threaded_messages(messages)
 
52
                messages = []
 
53
                if order == 'thread_subject':
 
54
                    threaded.sort(key=lambda t: t[0]['subject'])
 
55
                if order == 'thread_oldest':
 
56
                    threaded.sort(key=lambda t: min(m['date'] for m in t))
 
57
                if order == 'thread_newest':
 
58
                    threaded.sort(key=lambda t: max(m['date'] for m in t))
 
59
                for thread in threaded:
 
60
                    messages.extend(thread)
 
61
            else:
 
62
                messages.sort(key=lambda m: m[order])
 
63
        new_messages = []
 
64
        for message in messages:
 
65
            if (
 
66
                not parameters['include_hidden']
 
67
                and message.get('hidden', False)):
 
68
                continue
 
69
 
 
70
            if ('message_ids' in parameters and
 
71
                message['message_id'] not in parameters['message_ids']):
 
72
                continue
 
73
            message = dict(message)
 
74
            if 'headers' in parameters:
 
75
                headers = dict(
 
76
                    (k, v) for k, v in message['headers'].iteritems()
 
77
                    if k in parameters['headers'])
 
78
                message['headers'] = headers
 
79
            max_body = parameters.get('max_body_length')
 
80
            if max_body is not None:
 
81
                message['body'] = message['body'][:max_body]
 
82
            new_messages.append(message)
 
83
        messages = new_messages
 
84
        limit = parameters.get('limit', 100)
 
85
        memo = parameters.get('memo')
 
86
        message_id_indices = dict(
 
87
            (m['message_id'], idx) for idx, m in enumerate(messages))
 
88
        if memo is None:
 
89
            start = 0
 
90
        else:
 
91
            start = message_id_indices[memo.encode('rot13')]
 
92
        if start > 0:
 
93
            previous_memo = messages[start - 1]['message_id'].encode('rot13')
 
94
        else:
 
95
            previous_memo = None
 
96
        end = min(start + limit, len(messages))
 
97
        if end < len(messages):
 
98
            next_memo = messages[end]['message_id'].encode('rot13')
 
99
        else:
 
100
            next_memo = None
 
101
        messages = messages[start:end]
 
102
 
 
103
        response = {
 
104
            'messages': messages,
 
105
            'next_memo': next_memo,
 
106
            'previous_memo': previous_memo
 
107
            }
 
108
        return response
 
109
 
 
110
 
 
111
 
 
112
class ForkedFake:
 
113
 
 
114
    def __init__(self, port, messages=None):
75
115
        self.pid = None
76
116
        self.port = port
77
 
        if message_archives is None:
78
 
            self.message_archives = {}
79
 
        else:
80
 
            self.message_archives = message_archives
 
117
        self.messages = messages
81
118
        self.read_end, self.write_end = os.pipe()
82
 
        self.write_logs = write_logs
83
 
 
84
 
    @staticmethod
85
 
    def from_client(client, message_archives=None):
86
 
        """Instantiate a ForkedFakeService from the client.
87
 
 
88
 
        :param port: The client to provide service for.
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.
92
 
        """
93
 
        return ForkedFakeService(client.port, message_archives)
94
119
 
95
120
    def is_ready(self):
96
 
        """Tell the parent process that the server is ready for writes."""
97
121
        os.write(self.write_end, 'asdf')
98
122
 
99
123
    def __enter__(self):
100
 
        """Run the service.
101
 
 
102
 
        Fork and start a server in the child.  Return when the server is ready
103
 
        for use."""
104
124
        pid = os.fork()
105
125
        if pid == 0:
106
126
            self.start_server()
109
129
        return
110
130
 
111
131
    def start_server(self):
112
 
        """Start the HTTP server."""
113
132
        service = HTTPServer(('', self.port), FakeGrackleRequestHandler)
114
 
        service.store = MemoryStore(self.message_archives)
115
 
        for archive_id, messages in service.store.message_archives.iteritems():
 
133
        service.store = GrackleStore(self.messages)
 
134
        for archive_id, messages in service.store.messages.iteritems():
116
135
            for message in messages:
117
136
                message.setdefault('headers', {})
118
137
        self.is_ready()
119
 
        if self.write_logs:
120
 
            logging.basicConfig(
121
 
                stream=sys.stderr, level=logging.INFO)
122
138
        service.serve_forever()
123
139
 
124
140
    def __exit__(self, exc_type, exc_val, traceback):
125
141
        os.kill(self.pid, SIGKILL)
126
142
 
127
143
 
 
144
SUPPORTED_ORDERS = set(
 
145
    ['date', 'author', 'subject', 'thread_newest', 'thread_oldest',
 
146
     'thread_subject'])
 
147
 
 
148
 
128
149
class FakeGrackleRequestHandler(BaseHTTPRequestHandler):
129
 
    """A request handler that forwards to server.store."""
130
 
 
131
 
    def __init__(self, *args, **kwargs):
132
 
        """Constructor.  Sets up logging."""
133
 
        self.logger = logging.getLogger('http')
134
 
        BaseHTTPRequestHandler.__init__(self, *args, **kwargs)
135
150
 
136
151
    def do_POST(self):
137
 
        """Create a message on POST."""
138
152
        message = self.rfile.read(int(self.headers['content-length']))
139
 
        scheme, netloc, path, params, query_string, fragments = (
140
 
            urlparse(self.path))
141
 
        parts = path.split('/')
142
 
        if parts[1] == 'archive' and len(parts) == 4:
143
 
            try:
144
 
                # This expected path is /archive/archive_id/message_id.
145
 
                self.server.store.put_message(parts[2], parts[3], message)
146
 
                self.send_response(httplib.CREATED)
147
 
                self.end_headers()
148
 
                self.wfile.close()
149
 
            except:
150
 
                self.send_error(httplib.BAD_REQUEST)
 
153
        if message == 'This is a message':
 
154
            self.send_response(httplib.CREATED)
 
155
            self.end_headers()
 
156
            self.wfile.close()
 
157
        else:
 
158
            self.send_error(httplib.BAD_REQUEST)
151
159
 
152
160
    def do_GET(self):
153
 
        """Retrieve a list of messages on GET."""
154
161
        scheme, netloc, path, params, query_string, fragments = (
155
162
            urlparse(self.path))
156
163
        parts = path.split('/')
161
168
                self.send_response(httplib.OK)
162
169
                self.end_headers()
163
170
                self.wfile.write(simplejson.dumps(response))
164
 
            except Exception, error:
165
 
                self.send_response(
166
 
                    httplib.BAD_REQUEST, error.__doc__)
 
171
            except UnsupportedOrder:
 
172
                self.send_response(httplib.BAD_REQUEST)
 
173
                self.wfile.write('Unsupported order')
167
174
                return
168
175
 
169
 
    def log_message(self, format, *args):
170
 
        """Override log_message to use standard Python logging."""
171
 
        message = "%s - - [%s] %s\n" % (
172
 
            self.address_string(), self.log_date_time_string(), format % args)
173
 
        self.logger.info(message)
 
176
 
 
177
def fake_grackle_service(client, messages=None):
 
178
    if messages is None:
 
179
        messages = {}
 
180
    return ForkedFake(client.port, messages)
174
181
 
175
182
 
176
183
class TestPutMessage(TestCase):
177
184
 
178
185
    def test_put_message(self):
179
 
        client = GrackleClient('localhost', 8420)
180
 
        message_archives = {'arch1': []}
181
 
        with ForkedFakeService.from_client(client, message_archives):
182
 
            client.put_message('arch1', 'id1', StringIO('This is a message'))
183
 
            response = client.get_messages('arch1')
184
 
        self.assertEqual(1, len(response['messages']))
185
 
        message = response['messages'][0]
186
 
        self.assertEqual('id1', message['message_id'])
187
 
 
188
 
    def test_put_message_without_archive(self):
189
 
        client = GrackleClient('localhost', 8421)
190
 
        message_archives = {'arch1': []}
191
 
        with ForkedFakeService.from_client(client, message_archives):
 
186
        client = GrackleClient('localhost', 8436)
 
187
        with fake_grackle_service(client):
 
188
            client.put_message('arch1', 'asdf', StringIO('This is a message'))
192
189
            with ExpectedException(Exception, 'wtf'):
193
 
                client.put_message('no-archive', 'id1', StringIO('message'))
 
190
                client.put_message('arch1', 'asdf',
 
191
                    StringIO('This is not a message'))
194
192
 
195
193
 
196
194
class TestGetMessages(TestCase):
200
198
 
201
199
    def assertMessageIDs(self, ids, messages):
202
200
        self.assertIDOrder(
203
 
            sorted(ids), sorted(messages, key=lambda m: m['message_id']))
 
201
            sorted(ids), sorted(messages, key=lambda m:m['message_id']))
204
202
 
205
203
    def test_get_messages(self):
206
 
        client = GrackleClient('localhost', 8430)
207
 
        archive = {
208
 
            'baz': [make_message('foo'), make_message('bar')]}
209
 
        with ForkedFakeService.from_client(client, archive):
 
204
        client = GrackleClient('localhost', 8435)
 
205
        with fake_grackle_service(client,
 
206
            {'baz':
 
207
            [{'message_id': 'foo'},
 
208
             {'message_id': 'bar'}]}):
210
209
            response = client.get_messages('baz')
211
210
        self.assertEqual(['bar', 'foo'], sorted(m['message_id'] for m in
212
211
            response['messages']))
215
214
 
216
215
    def test_get_messages_by_id(self):
217
216
        client = GrackleClient('localhost', 8437)
218
 
        archive = {
219
 
            'baz': [make_message('foo'), make_message('bar')]}
220
 
        with ForkedFakeService.from_client(client, archive):
 
217
        with fake_grackle_service(client,
 
218
            {'baz':
 
219
            [{'message_id': 'foo'},
 
220
             {'message_id': 'bar'}]}):
221
221
            response = client.get_messages('baz', message_ids=['foo'])
222
222
        message, = response['messages']
223
223
        self.assertEqual('foo', message['message_id'])
224
224
 
225
225
    def test_get_messages_batching(self):
226
226
        client = GrackleClient('localhost', 8438)
227
 
        archive = {'baz': [make_message('foo'), make_message('bar')]}
228
 
        with ForkedFakeService.from_client(client, archive):
 
227
        with fake_grackle_service(client,
 
228
            {'baz':
 
229
            [{'message_id': 'foo'},
 
230
             {'message_id': 'bar'}]}):
229
231
            response = client.get_messages('baz', limit=1)
230
232
            self.assertEqual(1, len(response['messages']))
231
233
            messages = response['messages']
237
239
 
238
240
    def get_messages_member_order_test(self, key):
239
241
        client = GrackleClient('localhost', 8439)
240
 
        archive = {
241
 
            'baz': [
242
 
                make_message('foo', headers={key: '2011-03-25'}),
243
 
                make_message('bar', headers={key: '2011-03-24'}),
244
 
             ]}
245
 
        with ForkedFakeService.from_client(client, archive):
 
242
        with fake_grackle_service(client,
 
243
                {'baz': [{'message_id': 'foo', key: '2011-03-25'},
 
244
                 {'message_id': 'bar', key: '2011-03-24'}]}):
246
245
            response = client.get_messages('baz')
247
246
            self.assertIDOrder(['foo', 'bar'], response['messages'])
248
247
            response = client.get_messages('baz', order=key)
258
257
        self.get_messages_member_order_test('subject')
259
258
 
260
259
    def test_get_messages_thread_subject_order(self):
261
 
        archive = {
262
 
            'baz': [
263
 
                make_message('bar', headers={'subject': 'y'}),
264
 
                make_message('qux', headers={'subject': 'z'}),
265
 
                make_message('foo', headers={'subject': 'x',
266
 
                                             'in-reply-to': 'qux'}),
267
 
             ]}
268
260
        client = GrackleClient('localhost', 8439)
269
 
        with ForkedFakeService.from_client(client, archive):
 
261
        with fake_grackle_service(client, {'baz': [
 
262
            {'message_id': 'bar', 'subject': 'y'},
 
263
            {'message_id': 'qux', 'subject': 'z'},
 
264
            {'message_id': 'foo', 'subject': 'x', 'in_reply_to': 'qux'},
 
265
            ]}):
270
266
            response = client.get_messages('baz')
271
267
            self.assertIDOrder(['bar', 'qux', 'foo'], response['messages'])
272
268
            response = client.get_messages('baz', order='subject')
276
272
 
277
273
    def test_get_messages_thread_oldest_order(self):
278
274
        client = GrackleClient('localhost', 8439)
279
 
        archive = {
280
 
            'baz': [
281
 
                make_message('bar', headers={'date': 'x'}),
282
 
                make_message('qux', headers={'date': 'z'}),
283
 
                make_message('foo', headers={'date': 'y',
284
 
                                             'in-reply-to': 'qux'}),
285
 
            ]}
286
 
        with ForkedFakeService.from_client(client, archive):
 
275
        with fake_grackle_service(client, {'baz': [
 
276
            {'message_id': 'bar', 'date': 'x'},
 
277
            {'message_id': 'qux', 'date': 'z'},
 
278
            {'message_id': 'foo', 'date': 'y', 'in_reply_to': 'qux'},
 
279
            ]}):
287
280
            response = client.get_messages('baz')
288
281
            self.assertIDOrder(['bar', 'qux', 'foo'], response['messages'])
289
282
            response = client.get_messages('baz', order='date')
293
286
 
294
287
    def test_get_messages_thread_newest_order(self):
295
288
        client = GrackleClient('localhost', 8439)
296
 
        archive = {
297
 
            'baz': [
298
 
                make_message('bar', headers={'date': 'x'}),
299
 
                make_message('qux', headers={'date': 'w'}),
300
 
                make_message('foo', headers={'date': 'y',
301
 
                                             'in-reply-to': 'bar'}),
302
 
                make_message('baz', headers={'date': 'z',
303
 
                                             'in-reply-to': 'qux'}),
304
 
            ]}
305
 
        with ForkedFakeService.from_client(client, archive):
 
289
        with fake_grackle_service(client, {'baz': [
 
290
            {'message_id': 'bar', 'date': 'x'},
 
291
            {'message_id': 'qux', 'date': 'w'},
 
292
            {'message_id': 'foo', 'date': 'y', 'in_reply_to': 'bar'},
 
293
            {'message_id': 'baz', 'date': 'z', 'in_reply_to': 'qux'},
 
294
            ]}):
306
295
            response = client.get_messages('baz', order='date')
307
296
            self.assertIDOrder(
308
297
                ['qux', 'bar', 'foo', 'baz'], response['messages'])
312
301
 
313
302
    def test_get_messages_unsupported_order(self):
314
303
        client = GrackleClient('localhost', 8439)
315
 
        archive = {
316
 
            'baz': [
317
 
                make_message('foo', headers={'date': '2011-03-25'}),
318
 
                make_message('foo', headers={'date': '2011-03-24'}),
319
 
            ]}
320
 
        with ForkedFakeService.from_client(client, archive):
321
 
            with ExpectedException(UnsupportedOrder, ''):
 
304
        with fake_grackle_service(client,
 
305
                {'baz': [{'message_id': 'foo', 'date': '2011-03-25'},
 
306
                 {'message_id': 'bar', 'date': '2011-03-24'}]}):
 
307
            with ExpectedException(UnsupportedOrder):
322
308
                client.get_messages('baz', order='nonsense')
323
309
 
324
310
    def test_get_messages_headers_no_headers(self):
325
311
        client = GrackleClient('localhost', 8440)
326
 
        archive = {'baz': [make_message('foo')]}
327
 
        with ForkedFakeService.from_client(client, archive):
 
312
        with fake_grackle_service(client,
 
313
            {'baz': [
 
314
                {'message_id': 'foo'}
 
315
            ]}):
328
316
            response = client.get_messages('baz', headers=[
329
317
                'Subject', 'Date', 'X-Launchpad-Message-Rationale'])
330
318
        first_message = response['messages'][0]
333
321
 
334
322
    def test_get_messages_headers_exclude_headers(self):
335
323
        client = GrackleClient('localhost', 8441)
336
 
        archive = {
337
 
            'baz': [make_message('foo', headers={'From': 'me'})]}
338
 
        with ForkedFakeService.from_client(client, archive):
 
324
        with fake_grackle_service(client,
 
325
            {'baz': [
 
326
                {'message_id': 'foo', 'headers': {'From': 'me'}}
 
327
            ]}):
339
328
            response = client.get_messages('baz', headers=[
340
329
                'Subject', 'Date', 'X-Launchpad-Message-Rationale'])
341
330
        first_message = response['messages'][0]
344
333
 
345
334
    def test_get_messages_headers_include_headers(self):
346
335
        client = GrackleClient('localhost', 8442)
347
 
        archive = {
348
 
            'baz': [
349
 
                make_message('foo', headers={'From': 'me', 'To': 'you'})]}
350
 
        with ForkedFakeService.from_client(client, archive):
 
336
        with fake_grackle_service(client,
 
337
            {'baz': [
 
338
                {'message_id': 'foo', 'headers': {'From': 'me', 'To': 'you'}}
 
339
            ]}):
351
340
            response = client.get_messages('baz', headers=[
352
341
                'From', 'To'])
353
342
        first_message = response['messages'][0]
356
345
 
357
346
    def test_get_messages_max_body_length(self):
358
347
        client = GrackleClient('localhost', 8443)
359
 
        archive = {'baz': [make_message('foo', body=u'abcdefghi')]}
360
 
        with ForkedFakeService.from_client(client, archive):
 
348
        with fake_grackle_service(client,
 
349
            {'baz': [
 
350
                {'message_id': 'foo', 'body': u'abcdefghi'}
 
351
            ]}):
361
352
            response = client.get_messages('baz', max_body_length=3)
362
353
        first_message = response['messages'][0]
363
354
        self.assertEqual('abc', first_message['body'])
364
355
 
365
356
    def test_include_hidden(self):
366
357
        client = GrackleClient('localhost', 8444)
367
 
        archive = {
368
 
            'baz': [
369
 
                make_message('foo', hidden=True),
370
 
                make_message('bar', hidden=False),
371
 
            ]}
372
 
        with ForkedFakeService.from_client(client, archive):
 
358
        with fake_grackle_service(client,
 
359
            {'baz': [
 
360
                {'message_id': 'foo', 'hidden': True},
 
361
                {'message_id': 'bar', 'hidden': False}
 
362
            ]}):
373
363
            response = client.get_messages('baz', include_hidden=True)
374
364
            self.assertMessageIDs(['bar', 'foo'], response['messages'])
375
365
            response = client.get_messages('baz', include_hidden=False)
376
366
            self.assertMessageIDs(['bar'], response['messages'])
377
367
 
378
 
    def test_display_type_unknown_value(self):
379
 
        client = GrackleClient('localhost', 8445)
380
 
        archive = {'baz': [make_message('foo', body=u'abcdefghi')]}
381
 
        with ForkedFakeService.from_client(client, archive):
382
 
            with ExpectedException(UnsupportedDisplayType, ''):
383
 
                client.get_messages('baz', display_type='unknown')
384
 
 
385
 
    def test_display_type_headers_only(self):
386
 
        client = GrackleClient('localhost', 8446)
387
 
        archive = {
388
 
            'baz': [
389
 
                make_message('foo', body=u'abcdefghi',
390
 
                             headers={'From': 'me', 'To': 'you'})]}
391
 
        with ForkedFakeService.from_client(client, archive):
392
 
            response = client.get_messages('baz', display_type='headers-only')
393
 
        first_message = response['messages'][0]
394
 
        self.assertEqual('foo', first_message['message_id'])
395
 
        self.assertEqual(
396
 
            {'From': 'me', 'Message-Id': 'foo', 'To': 'you'},
397
 
            first_message['headers'])
398
 
        self.assertNotIn('body', first_message)
399
 
 
400
 
    def test_display_type_text_only(self):
401
 
        client = GrackleClient('localhost', 8446)
402
 
        archive = {
403
 
            'baz': [
404
 
                make_mime_message(
405
 
                    'foo', 'abcdefghi',
406
 
                    headers={'From': 'me', 'To': 'you'},
407
 
                    attachment_type='text/x-diff')]}
408
 
        with ForkedFakeService.from_client(client, archive):
409
 
            response = client.get_messages('baz', display_type='text-only')
410
 
        first_message = response['messages'][0]
411
 
        self.assertEqual('foo', first_message['message_id'])
412
 
        self.assertEqual('me', first_message['headers']['From'])
413
 
        self.assertEqual('you', first_message['headers']['To'])
414
 
        self.assertEqual('abcdefghi', first_message['body'])
415
 
 
416
 
    def test_display_type_all(self):
417
 
        client = GrackleClient('localhost', 8447)
418
 
        archive = {
419
 
            'baz': [
420
 
                make_mime_message(
421
 
                    'foo', 'abcdefghi',
422
 
                    headers={'From': 'me', 'To': 'you'},
423
 
                    attachment_type='text/x-diff')]}
424
 
        with ForkedFakeService.from_client(client, archive):
425
 
            response = client.get_messages('baz', display_type='all')
426
 
        first_message = response['messages'][0]
427
 
        self.assertEqual('foo', first_message['message_id'])
428
 
        self.assertEqual('me', first_message['headers']['From'])
429
 
        self.assertEqual('you', first_message['headers']['To'])
430
 
        self.assertEqual(
431
 
            'abcdefghi\n\nattactment data.', first_message['body'])
432
 
 
433
 
    def test_date_range(self):
434
 
        client = GrackleClient('localhost', 8448)
435
 
        archive = {
436
 
            'baz': [
437
 
                make_mime_message(
438
 
                    'foo', 'abcdefghi', headers={'date': '2011-12-31'}),
439
 
                make_mime_message(
440
 
                    'bar', 'abcdefghi', headers={'date': '2012-01-01'}),
441
 
                make_mime_message(
442
 
                    'qux', 'abcdefghi', headers={'date': '2012-01-15'}),
443
 
                make_mime_message(
444
 
                    'naf', 'abcdefghi', headers={'date': '2012-01-31'}),
445
 
                make_mime_message(
446
 
                    'doh', 'abcdefghi', headers={'date': '2012-02-01'}),
447
 
                    ]}
448
 
        with ForkedFakeService.from_client(client, archive):
449
 
            response = client.get_messages(
450
 
                'baz', date_range='2012-01-01..2012-01-31')
451
 
        ids = sorted(m['message_id'] for m in response['messages'])
452
 
        self.assertEqual(['bar', 'naf', 'qux'], ids)
453
 
 
454
 
    def test_date_range_unparsabledaterange(self):
455
 
        client = GrackleClient('localhost', 8449)
456
 
        archive = {'baz': [make_message('foo', body=u'abcdefghi')]}
457
 
        with ForkedFakeService.from_client(client, archive):
458
 
            with ExpectedException(UnparsableDateRange, ''):
459
 
                client.get_messages('baz', date_range='2012-01-01')
460
 
 
461
 
    def test_date_range_unparsabledaterange_missing_part(self):
462
 
        client = GrackleClient('localhost', 8450)
463
 
        archive = {'baz': [make_message('foo', body=u'abcdefghi')]}
464
 
        with ForkedFakeService.from_client(client, archive):
465
 
            with ExpectedException(UnparsableDateRange, ''):
466
 
                client.get_messages('baz', date_range='2012-01-01..')
467
 
 
468
 
    def test_date_range_unparsabledaterange_extra_part(self):
469
 
        client = GrackleClient('localhost', 8451)
470
 
        archive = {'baz': [make_message('foo', body=u'abcdefghi')]}
471
 
        with ForkedFakeService.from_client(client, archive):
472
 
            with ExpectedException(UnparsableDateRange, ''):
473
 
                client.get_messages('baz', date_range='2012-01..12-02..12-03')