~didrocks/unity/altf10

« back to all changes in this revision

Viewing changes to grackle/tests/test_client.py

  • Committer: Curtis Hovey
  • Date: 2012-03-17 22:45:15 UTC
  • Revision ID: curtis.hovey@canonical.com-20120317224515-r2n23tqc8cx7cul4
Only store the unique information needed by grackle.

Show diffs side-by-side

added added

removed removed

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