~unity-2d-team/unity-2d/Shell-MultiMonitor

« back to all changes in this revision

Viewing changes to grackle/tests/test_client.py

  • Committer: Curtis Hovey
  • Date: 2012-03-16 19:38:35 UTC
  • mto: This revision was merged to the branch mainline in revision 45.
  • Revision ID: curtis.hovey@canonical.com-20120316193835-egu5tc1n0xlr5udj
Rename args to be honest about what is expected.

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