~didrocks/unity/altf10

« back to all changes in this revision

Viewing changes to grackle/tests/test_client.py

  • Committer: Aaron Bentley
  • Date: 2012-01-12 09:37:51 UTC
  • Revision ID: aaron@canonical.com-20120112093751-ltzymm8dbk34vixq
ImplementĀ memo/limitĀ support.

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