~didrocks/unity/altf10

« back to all changes in this revision

Viewing changes to grackle/tests/test_client.py

  • Committer: Aaron Bentley
  • Date: 2012-01-16 16:42:59 UTC
  • Revision ID: aaron@canonical.com-20120116164259-qcx32bgzhabmopnc
Cleaner logging switch.

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
6
import logging
10
7
import os
20
17
 
21
18
from grackle.client import (
22
19
    GrackleClient,
23
 
    UnparsableDateRange,
24
 
    UnsupportedDisplayType,
25
20
    UnsupportedOrder,
26
21
    )
27
22
 
28
23
 
29
 
def make_message(message_id, body='body', headers=None, hidden=False):
30
 
    if headers is None:
31
 
        headers = {}
32
 
    headers['Message-Id'] = message_id
33
 
    message = {
34
 
        'message_id': message_id,
35
 
        'headers': headers,
36
 
        'thread_id': message_id,
37
 
        'date': headers.get('date', '2005-01-01'),
38
 
        'subject': headers.get('subject', 'subject'),
39
 
        'author': headers.get('author', 'author'),
40
 
        'hidden': hidden,
41
 
        'attachments': [],
42
 
        'replies': headers.get('in-reply-to', None),
43
 
        'body': body,
44
 
        }
45
 
    return message
46
 
 
47
 
 
48
 
def make_mime_message(message_id, body='body', headers=None, hidden=False,
49
 
                      attachment_type=None):
50
 
    message = MIMEMultipart()
51
 
    message.attach(MIMEText(body))
52
 
    if attachment_type is not None:
53
 
        attachment = Message()
54
 
        attachment.set_payload('attactment data.')
55
 
        attachment['Content-Type'] = attachment_type
56
 
        attachment['Content-Disposition'] = 'attachment; filename="file.ext"'
57
 
        message.attach(attachment)
58
 
    return make_message(message_id, message.get_payload(), headers, hidden)
59
 
 
60
 
 
61
24
def threaded_messages(messages):
62
25
    threads = {}
63
26
    count = 0
64
27
    pending = []
65
28
    for message in messages:
66
 
        if message.get('replies') is None:
 
29
        if message.get('in_reply_to') is None:
67
30
            threads[message['message_id']] = [message]
68
31
            count += 1
69
32
        else:
70
33
            pending.append(message)
71
34
    for message in pending:
72
 
        threads[message['replies']].append(message)
 
35
        threads[message['in_reply_to']].append(message)
73
36
    return threads.values()
74
37
 
75
38
 
76
39
class GrackleStore:
77
 
    """A memory-backed message store."""
78
40
 
79
41
    def __init__(self, messages):
80
 
        """Constructor."""
81
42
        self.messages = messages
82
43
 
83
 
    @staticmethod
84
 
    def is_multipart(message):
85
 
        return isinstance(message['body'], list)
86
 
 
87
44
    def get_messages(self, archive_id, query_string):
88
 
        """Return matching messages.
89
 
 
90
 
        :param archive_id: The archive to retrieve from.
91
 
        :param query_string: Contains 'parameters', which is a JSON-format
92
 
            string describing parameters.
93
 
        """
94
45
        query = parse_qs(query_string)
95
46
        parameters = simplejson.loads(query['parameters'][0])
96
47
        order = parameters.get('order')
97
48
        messages = self.messages[archive_id]
98
 
        if order is not None:
 
49
        if order is not None :
99
50
            if order not in SUPPORTED_ORDERS:
100
51
                raise UnsupportedOrder
101
52
            elif order.startswith('thread_'):
111
62
                    messages.extend(thread)
112
63
            else:
113
64
                messages.sort(key=lambda m: m[order])
114
 
        display_type = parameters.get('display_type', 'all')
115
 
        if display_type not in SUPPORTED_DISPLAY_TYPES:
116
 
            raise UnsupportedDisplayType
117
 
        if 'date_range' in parameters:
118
 
            try:
119
 
                start_date, end_date = parameters['date_range'].split('..')
120
 
                if not start_date or not end_date:
121
 
                    raise UnparsableDateRange
122
 
            except ValueError:
123
 
                raise UnparsableDateRange
124
65
        new_messages = []
125
66
        for message in messages:
126
 
            if (not parameters['include_hidden'] and message['hidden']):
127
 
                continue
128
 
            if ('message_ids' in parameters
129
 
                and message['message_id'] not in parameters['message_ids']):
130
 
                continue
131
 
            if ('date_range' in parameters
132
 
                and (message['date'] < start_date
133
 
                     or message['date'] > end_date)):
 
67
            if (
 
68
                not parameters['include_hidden']
 
69
                and message.get('hidden', False)):
 
70
                continue
 
71
 
 
72
            if ('message_ids' in parameters and
 
73
                message['message_id'] not in parameters['message_ids']):
134
74
                continue
135
75
            message = dict(message)
136
76
            if 'headers' in parameters:
138
78
                    (k, v) for k, v in message['headers'].iteritems()
139
79
                    if k in parameters['headers'])
140
80
                message['headers'] = headers
141
 
            if display_type == 'headers-only':
142
 
                del message['body']
143
 
            elif display_type == 'text-only' and self.is_multipart(message):
144
 
                text_parts = [
145
 
                    part.get_payload() for part in message['body']
146
 
                    if part.get_content_type() == 'text/plain']
147
 
                message['body'] = '\n\n'.join(text_parts)
148
 
            elif display_type == 'all' and self.is_multipart(message):
149
 
                parts = [str(part.get_payload()) for part in message['body']]
150
 
                message['body'] = '\n\n'.join(parts)
151
81
            max_body = parameters.get('max_body_length')
152
 
            if max_body is not None and display_type != 'headers-only':
 
82
            if max_body is not None:
153
83
                message['body'] = message['body'][:max_body]
154
84
            new_messages.append(message)
155
85
        messages = new_messages
180
110
        return response
181
111
 
182
112
 
183
 
class ForkedFakeService:
184
 
    """A Grackle service fake, as a ContextManager."""
 
113
 
 
114
class ForkedFake:
185
115
 
186
116
    def __init__(self, port, messages=None, write_logs=False):
187
 
        """Constructor.
188
 
 
189
 
        :param port: The tcp port to use.
190
 
        :param messages: A dict of lists of dicts representing messages.  The
191
 
            outer dict represents the archive, the list represents the list of
192
 
            messages for that archive.
193
 
        :param write_logs: If true, log messages will be written to stdout.
194
 
        """
195
117
        self.pid = None
196
118
        self.port = port
197
119
        if messages is None:
203
125
 
204
126
    @staticmethod
205
127
    def from_client(client, messages=None):
206
 
        """Instantiate a ForkedFakeService from the client.
207
 
 
208
 
        :param port: The client to provide service for.
209
 
        :param messages: A dict of lists of dicts representing messages.  The
210
 
            outer dict represents the archive, the list represents the list of
211
 
            messages for that archive.
212
 
        """
213
 
        return ForkedFakeService(client.port, messages)
 
128
        return ForkedFake(client.port, messages)
214
129
 
215
130
    def is_ready(self):
216
 
        """Tell the parent process that the server is ready for writes."""
217
131
        os.write(self.write_end, 'asdf')
218
132
 
219
133
    def __enter__(self):
220
 
        """Run the service.
221
 
 
222
 
        Fork and start a server in the child.  Return when the server is ready
223
 
        for use."""
224
134
        pid = os.fork()
225
135
        if pid == 0:
226
136
            self.start_server()
229
139
        return
230
140
 
231
141
    def start_server(self):
232
 
        """Start the HTTP server."""
233
142
        service = HTTPServer(('', self.port), FakeGrackleRequestHandler)
234
143
        service.store = GrackleStore(self.messages)
235
144
        for archive_id, messages in service.store.messages.iteritems():
245
154
        os.kill(self.pid, SIGKILL)
246
155
 
247
156
 
248
 
SUPPORTED_DISPLAY_TYPES = set(['all', 'text-only', 'headers-only'])
249
 
 
250
 
 
251
157
SUPPORTED_ORDERS = set(
252
158
    ['date', 'author', 'subject', 'thread_newest', 'thread_oldest',
253
159
     'thread_subject'])
254
160
 
255
161
 
256
162
class FakeGrackleRequestHandler(BaseHTTPRequestHandler):
257
 
    """A request handler that forwards to server.store."""
258
163
 
259
164
    def __init__(self, *args, **kwargs):
260
 
        """Constructor.  Sets up logging."""
261
165
        self.logger = logging.getLogger('http')
262
166
        BaseHTTPRequestHandler.__init__(self, *args, **kwargs)
263
167
 
264
168
    def do_POST(self):
265
 
        """Create a message on POST."""
266
169
        message = self.rfile.read(int(self.headers['content-length']))
267
170
        if message == 'This is a message':
268
171
            self.send_response(httplib.CREATED)
272
175
            self.send_error(httplib.BAD_REQUEST)
273
176
 
274
177
    def do_GET(self):
275
 
        """Retrieve a list of messages on GET."""
276
178
        scheme, netloc, path, params, query_string, fragments = (
277
179
            urlparse(self.path))
278
180
        parts = path.split('/')
283
185
                self.send_response(httplib.OK)
284
186
                self.end_headers()
285
187
                self.wfile.write(simplejson.dumps(response))
286
 
            except Exception, error:
287
 
                self.send_response(
288
 
                    httplib.BAD_REQUEST, error.__doc__)
 
188
            except UnsupportedOrder:
 
189
                self.send_response(httplib.BAD_REQUEST)
 
190
                self.wfile.write('Unsupported order')
289
191
                return
290
192
 
291
193
    def log_message(self, format, *args):
292
 
        """Override log_message to use standard Python logging."""
293
194
        message = "%s - - [%s] %s\n" % (
294
 
            self.address_string(), self.log_date_time_string(), format % args)
 
195
            self.address_string(), self.log_date_time_string(), format%args)
295
196
        self.logger.info(message)
296
197
 
297
198
 
299
200
 
300
201
    def test_put_message(self):
301
202
        client = GrackleClient('localhost', 8436)
302
 
        with ForkedFakeService.from_client(client):
 
203
        with ForkedFake.from_client(client):
303
204
            client.put_message('arch1', 'asdf', StringIO('This is a message'))
304
205
            with ExpectedException(Exception, 'wtf'):
305
206
                client.put_message('arch1', 'asdf',
313
214
 
314
215
    def assertMessageIDs(self, ids, messages):
315
216
        self.assertIDOrder(
316
 
            sorted(ids), sorted(messages, key=lambda m: m['message_id']))
 
217
            sorted(ids), sorted(messages, key=lambda m:m['message_id']))
317
218
 
318
219
    def test_get_messages(self):
319
220
        client = GrackleClient('localhost', 8435)
320
 
        archive = {
321
 
            'baz': [make_message('foo'), make_message('bar')]}
322
 
        with ForkedFakeService.from_client(client, archive):
 
221
        with ForkedFake.from_client(client,
 
222
            {'baz':
 
223
            [{'message_id': 'foo'},
 
224
             {'message_id': 'bar'}]}):
323
225
            response = client.get_messages('baz')
324
226
        self.assertEqual(['bar', 'foo'], sorted(m['message_id'] for m in
325
227
            response['messages']))
328
230
 
329
231
    def test_get_messages_by_id(self):
330
232
        client = GrackleClient('localhost', 8437)
331
 
        archive = {
332
 
            'baz': [make_message('foo'), make_message('bar')]}
333
 
        with ForkedFakeService.from_client(client, archive):
 
233
        with ForkedFake.from_client(client,
 
234
            {'baz':
 
235
            [{'message_id': 'foo'},
 
236
             {'message_id': 'bar'}]}):
334
237
            response = client.get_messages('baz', message_ids=['foo'])
335
238
        message, = response['messages']
336
239
        self.assertEqual('foo', message['message_id'])
337
240
 
338
241
    def test_get_messages_batching(self):
339
242
        client = GrackleClient('localhost', 8438)
340
 
        archive = {'baz': [make_message('foo'), make_message('bar')]}
341
 
        with ForkedFakeService.from_client(client, archive):
 
243
        with ForkedFake.from_client(client,
 
244
            {'baz':
 
245
            [{'message_id': 'foo'},
 
246
             {'message_id': 'bar'}]}):
342
247
            response = client.get_messages('baz', limit=1)
343
248
            self.assertEqual(1, len(response['messages']))
344
249
            messages = response['messages']
350
255
 
351
256
    def get_messages_member_order_test(self, key):
352
257
        client = GrackleClient('localhost', 8439)
353
 
        archive = {
354
 
            'baz': [
355
 
                make_message('foo', headers={key: '2011-03-25'}),
356
 
                make_message('bar', headers={key: '2011-03-24'}),
357
 
             ]}
358
 
        with ForkedFakeService.from_client(client, archive):
 
258
        with ForkedFake.from_client(client,
 
259
                {'baz': [{'message_id': 'foo', key: '2011-03-25'},
 
260
                 {'message_id': 'bar', key: '2011-03-24'}]}):
359
261
            response = client.get_messages('baz')
360
262
            self.assertIDOrder(['foo', 'bar'], response['messages'])
361
263
            response = client.get_messages('baz', order=key)
371
273
        self.get_messages_member_order_test('subject')
372
274
 
373
275
    def test_get_messages_thread_subject_order(self):
374
 
        archive = {
375
 
            'baz': [
376
 
                make_message('bar', headers={'subject': 'y'}),
377
 
                make_message('qux', headers={'subject': 'z'}),
378
 
                make_message('foo', headers={'subject': 'x',
379
 
                                             'in-reply-to': 'qux'}),
380
 
             ]}
381
276
        client = GrackleClient('localhost', 8439)
382
 
        with ForkedFakeService.from_client(client, archive):
 
277
        with ForkedFake.from_client(client, {'baz': [
 
278
            {'message_id': 'bar', 'subject': 'y'},
 
279
            {'message_id': 'qux', 'subject': 'z'},
 
280
            {'message_id': 'foo', 'subject': 'x', 'in_reply_to': 'qux'},
 
281
            ]}):
383
282
            response = client.get_messages('baz')
384
283
            self.assertIDOrder(['bar', 'qux', 'foo'], response['messages'])
385
284
            response = client.get_messages('baz', order='subject')
389
288
 
390
289
    def test_get_messages_thread_oldest_order(self):
391
290
        client = GrackleClient('localhost', 8439)
392
 
        archive = {
393
 
            'baz': [
394
 
                make_message('bar', headers={'date': 'x'}),
395
 
                make_message('qux', headers={'date': 'z'}),
396
 
                make_message('foo', headers={'date': 'y',
397
 
                                             'in-reply-to': 'qux'}),
398
 
            ]}
399
 
        with ForkedFakeService.from_client(client, archive):
 
291
        with ForkedFake.from_client(client, {'baz': [
 
292
            {'message_id': 'bar', 'date': 'x'},
 
293
            {'message_id': 'qux', 'date': 'z'},
 
294
            {'message_id': 'foo', 'date': 'y', 'in_reply_to': 'qux'},
 
295
            ]}):
400
296
            response = client.get_messages('baz')
401
297
            self.assertIDOrder(['bar', 'qux', 'foo'], response['messages'])
402
298
            response = client.get_messages('baz', order='date')
406
302
 
407
303
    def test_get_messages_thread_newest_order(self):
408
304
        client = GrackleClient('localhost', 8439)
409
 
        archive = {
410
 
            'baz': [
411
 
                make_message('bar', headers={'date': 'x'}),
412
 
                make_message('qux', headers={'date': 'w'}),
413
 
                make_message('foo', headers={'date': 'y',
414
 
                                             'in-reply-to': 'bar'}),
415
 
                make_message('baz', headers={'date': 'z',
416
 
                                             'in-reply-to': 'qux'}),
417
 
            ]}
418
 
        with ForkedFakeService.from_client(client, archive):
 
305
        with ForkedFake.from_client(client, {'baz': [
 
306
            {'message_id': 'bar', 'date': 'x'},
 
307
            {'message_id': 'qux', 'date': 'w'},
 
308
            {'message_id': 'foo', 'date': 'y', 'in_reply_to': 'bar'},
 
309
            {'message_id': 'baz', 'date': 'z', 'in_reply_to': 'qux'},
 
310
            ]}):
419
311
            response = client.get_messages('baz', order='date')
420
312
            self.assertIDOrder(
421
313
                ['qux', 'bar', 'foo', 'baz'], response['messages'])
425
317
 
426
318
    def test_get_messages_unsupported_order(self):
427
319
        client = GrackleClient('localhost', 8439)
428
 
        archive = {
429
 
            'baz': [
430
 
                make_message('foo', headers={'date': '2011-03-25'}),
431
 
                make_message('foo', headers={'date': '2011-03-24'}),
432
 
            ]}
433
 
        with ForkedFakeService.from_client(client, archive):
434
 
            with ExpectedException(UnsupportedOrder, ''):
 
320
        with ForkedFake.from_client(client,
 
321
                {'baz': [{'message_id': 'foo', 'date': '2011-03-25'},
 
322
                 {'message_id': 'bar', 'date': '2011-03-24'}]}):
 
323
            with ExpectedException(UnsupportedOrder):
435
324
                client.get_messages('baz', order='nonsense')
436
325
 
437
326
    def test_get_messages_headers_no_headers(self):
438
327
        client = GrackleClient('localhost', 8440)
439
 
        archive = {'baz': [make_message('foo')]}
440
 
        with ForkedFakeService.from_client(client, archive):
 
328
        with ForkedFake.from_client(client,
 
329
            {'baz': [
 
330
                {'message_id': 'foo'}
 
331
            ]}):
441
332
            response = client.get_messages('baz', headers=[
442
333
                'Subject', 'Date', 'X-Launchpad-Message-Rationale'])
443
334
        first_message = response['messages'][0]
446
337
 
447
338
    def test_get_messages_headers_exclude_headers(self):
448
339
        client = GrackleClient('localhost', 8441)
449
 
        archive = {
450
 
            'baz': [make_message('foo', headers={'From': 'me'})]}
451
 
        with ForkedFakeService.from_client(client, archive):
 
340
        with ForkedFake.from_client(client,
 
341
            {'baz': [
 
342
                {'message_id': 'foo', 'headers': {'From': 'me'}}
 
343
            ]}):
452
344
            response = client.get_messages('baz', headers=[
453
345
                'Subject', 'Date', 'X-Launchpad-Message-Rationale'])
454
346
        first_message = response['messages'][0]
457
349
 
458
350
    def test_get_messages_headers_include_headers(self):
459
351
        client = GrackleClient('localhost', 8442)
460
 
        archive = {
461
 
            'baz': [
462
 
                make_message('foo', headers={'From': 'me', 'To': 'you'})]}
463
 
        with ForkedFakeService.from_client(client, archive):
 
352
        with ForkedFake.from_client(client,
 
353
            {'baz': [
 
354
                {'message_id': 'foo', 'headers': {'From': 'me', 'To': 'you'}}
 
355
            ]}):
464
356
            response = client.get_messages('baz', headers=[
465
357
                'From', 'To'])
466
358
        first_message = response['messages'][0]
469
361
 
470
362
    def test_get_messages_max_body_length(self):
471
363
        client = GrackleClient('localhost', 8443)
472
 
        archive = {'baz': [make_message('foo', body=u'abcdefghi')]}
473
 
        with ForkedFakeService.from_client(client, archive):
 
364
        with ForkedFake.from_client(client,
 
365
            {'baz': [
 
366
                {'message_id': 'foo', 'body': u'abcdefghi'}
 
367
            ]}):
474
368
            response = client.get_messages('baz', max_body_length=3)
475
369
        first_message = response['messages'][0]
476
370
        self.assertEqual('abc', first_message['body'])
477
371
 
478
372
    def test_include_hidden(self):
479
373
        client = GrackleClient('localhost', 8444)
480
 
        archive = {
481
 
            'baz': [
482
 
                make_message('foo', hidden=True),
483
 
                make_message('bar', hidden=False),
484
 
            ]}
485
 
        with ForkedFakeService.from_client(client, archive):
 
374
        with ForkedFake.from_client(client,
 
375
            {'baz': [
 
376
                {'message_id': 'foo', 'hidden': True},
 
377
                {'message_id': 'bar', 'hidden': False}
 
378
            ]}):
486
379
            response = client.get_messages('baz', include_hidden=True)
487
380
            self.assertMessageIDs(['bar', 'foo'], response['messages'])
488
381
            response = client.get_messages('baz', include_hidden=False)
489
382
            self.assertMessageIDs(['bar'], response['messages'])
490
383
 
491
 
    def test_display_type_unknown_value(self):
492
 
        client = GrackleClient('localhost', 8445)
493
 
        archive = {'baz': [make_message('foo', body=u'abcdefghi')]}
494
 
        with ForkedFakeService.from_client(client, archive):
495
 
            with ExpectedException(UnsupportedDisplayType, ''):
496
 
                client.get_messages('baz', display_type='unknown')
497
 
 
498
 
    def test_display_type_headers_only(self):
499
 
        client = GrackleClient('localhost', 8446)
500
 
        archive = {
501
 
            'baz': [
502
 
                make_message('foo', body=u'abcdefghi',
503
 
                             headers={'From': 'me', 'To': 'you'})]}
504
 
        with ForkedFakeService.from_client(client, archive):
505
 
            response = client.get_messages('baz', display_type='headers-only')
506
 
        first_message = response['messages'][0]
507
 
        self.assertEqual('foo', first_message['message_id'])
508
 
        self.assertEqual(
509
 
            {'From': 'me', 'Message-Id': 'foo', 'To': 'you'},
510
 
            first_message['headers'])
511
 
        self.assertNotIn('body', first_message)
512
 
 
513
 
    def test_display_type_text_only(self):
514
 
        client = GrackleClient('localhost', 8446)
515
 
        archive = {
516
 
            'baz': [
517
 
                make_mime_message(
518
 
                    'foo', 'abcdefghi',
519
 
                    headers={'From': 'me', 'To': 'you'},
520
 
                    attachment_type='text/x-diff')]}
521
 
        with ForkedFakeService.from_client(client, archive):
522
 
            response = client.get_messages('baz', display_type='text-only')
523
 
        first_message = response['messages'][0]
524
 
        self.assertEqual('foo', first_message['message_id'])
525
 
        self.assertEqual('me', first_message['headers']['From'])
526
 
        self.assertEqual('you', first_message['headers']['To'])
527
 
        self.assertEqual('abcdefghi', first_message['body'])
528
 
 
529
 
    def test_display_type_all(self):
530
 
        client = GrackleClient('localhost', 8447)
531
 
        archive = {
532
 
            'baz': [
533
 
                make_mime_message(
534
 
                    'foo', 'abcdefghi',
535
 
                    headers={'From': 'me', 'To': 'you'},
536
 
                    attachment_type='text/x-diff')]}
537
 
        with ForkedFakeService.from_client(client, archive):
538
 
            response = client.get_messages('baz', display_type='all')
539
 
        first_message = response['messages'][0]
540
 
        self.assertEqual('foo', first_message['message_id'])
541
 
        self.assertEqual('me', first_message['headers']['From'])
542
 
        self.assertEqual('you', first_message['headers']['To'])
543
 
        self.assertEqual(
544
 
            'abcdefghi\n\nattactment data.', first_message['body'])
545
 
 
546
 
    def test_date_range(self):
547
 
        client = GrackleClient('localhost', 8448)
548
 
        archive = {
549
 
            'baz': [
550
 
                make_mime_message(
551
 
                    'foo', 'abcdefghi', headers={'date': '2011-12-31'}),
552
 
                make_mime_message(
553
 
                    'bar', 'abcdefghi', headers={'date': '2012-01-01'}),
554
 
                make_mime_message(
555
 
                    'qux', 'abcdefghi', headers={'date': '2012-01-15'}),
556
 
                make_mime_message(
557
 
                    'naf', 'abcdefghi', headers={'date': '2012-01-31'}),
558
 
                make_mime_message(
559
 
                    'doh', 'abcdefghi', headers={'date': '2012-02-01'}),
560
 
                    ]}
561
 
        with ForkedFakeService.from_client(client, archive):
562
 
            response = client.get_messages(
563
 
                'baz', date_range='2012-01-01..2012-01-31')
564
 
        ids = sorted(m['message_id'] for m in response['messages'])
565
 
        self.assertEqual(['bar', 'naf', 'qux'], ids)
566
 
 
567
 
    def test_date_range_unparsabledaterange(self):
568
 
        client = GrackleClient('localhost', 8449)
569
 
        archive = {'baz': [make_message('foo', body=u'abcdefghi')]}
570
 
        with ForkedFakeService.from_client(client, archive):
571
 
            with ExpectedException(UnparsableDateRange, ''):
572
 
                client.get_messages('baz', date_range='2012-01-01')
573
 
 
574
 
    def test_date_range_unparsabledaterange_missing_part(self):
575
 
        client = GrackleClient('localhost', 8450)
576
 
        archive = {'baz': [make_message('foo', body=u'abcdefghi')]}
577
 
        with ForkedFakeService.from_client(client, archive):
578
 
            with ExpectedException(UnparsableDateRange, ''):
579
 
                client.get_messages('baz', date_range='2012-01-01..')
580
 
 
581
 
    def test_date_range_unparsabledaterange_extra_part(self):
582
 
        client = GrackleClient('localhost', 8451)
583
 
        archive = {'baz': [make_message('foo', body=u'abcdefghi')]}
584
 
        with ForkedFakeService.from_client(client, archive):
585
 
            with ExpectedException(UnparsableDateRange, ''):
586
 
                client.get_messages('baz', date_range='2012-01..12-02..12-03')