~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:29:12 UTC
  • Revision ID: aaron@canonical.com-20120116162912-cc760p6gn7q5qdwr
Switch test HTTP server to standard Python logging.

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
14
11
import sys
15
12
from unittest import TestCase
16
13
from urlparse import urlparse
 
14
from urlparse import parse_qs
17
15
 
18
16
from testtools import ExpectedException
19
17
 
20
18
from grackle.client import (
21
19
    GrackleClient,
22
 
    UnparsableDateRange,
23
 
    UnsupportedDisplayType,
24
20
    UnsupportedOrder,
25
21
    )
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
 
        """
 
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
 
 
41
    def __init__(self, messages):
 
42
        self.messages = messages
 
43
 
 
44
    def get_messages(self, archive_id, query_string):
 
45
        query = parse_qs(query_string)
 
46
        parameters = simplejson.loads(query['parameters'][0])
 
47
        order = parameters.get('order')
 
48
        messages = self.messages[archive_id]
 
49
        if order is not None :
 
50
            if order not in SUPPORTED_ORDERS:
 
51
                raise UnsupportedOrder
 
52
            elif order.startswith('thread_'):
 
53
                threaded = threaded_messages(messages)
 
54
                messages = []
 
55
                if order == 'thread_subject':
 
56
                    threaded.sort(key=lambda t: t[0]['subject'])
 
57
                if order == 'thread_oldest':
 
58
                    threaded.sort(key=lambda t: min(m['date'] for m in t))
 
59
                if order == 'thread_newest':
 
60
                    threaded.sort(key=lambda t: max(m['date'] for m in t))
 
61
                for thread in threaded:
 
62
                    messages.extend(thread)
 
63
            else:
 
64
                messages.sort(key=lambda m: m[order])
 
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):
75
117
        self.pid = None
76
118
        self.port = port
77
 
        if message_archives is None:
78
 
            self.message_archives = {}
 
119
        if messages is None:
 
120
            self.messages = {}
79
121
        else:
80
 
            self.message_archives = message_archives
 
122
            self.messages = messages
81
123
        self.read_end, self.write_end = os.pipe()
82
 
        self.write_logs = write_logs
83
124
 
84
125
    @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)
 
126
    def from_client(client, messages=None):
 
127
        return ForkedFake(client.port, messages)
94
128
 
95
129
    def is_ready(self):
96
 
        """Tell the parent process that the server is ready for writes."""
97
130
        os.write(self.write_end, 'asdf')
98
131
 
99
132
    def __enter__(self):
100
 
        """Run the service.
101
 
 
102
 
        Fork and start a server in the child.  Return when the server is ready
103
 
        for use."""
104
133
        pid = os.fork()
105
134
        if pid == 0:
106
135
            self.start_server()
109
138
        return
110
139
 
111
140
    def start_server(self):
112
 
        """Start the HTTP server."""
113
141
        service = HTTPServer(('', self.port), FakeGrackleRequestHandler)
114
 
        service.store = MemoryStore(self.message_archives)
115
 
        for archive_id, messages in service.store.message_archives.iteritems():
 
142
        service.store = GrackleStore(self.messages)
 
143
        for archive_id, messages in service.store.messages.iteritems():
116
144
            for message in messages:
117
145
                message.setdefault('headers', {})
118
146
        self.is_ready()
119
 
        if self.write_logs:
120
 
            logging.basicConfig(
121
 
                stream=sys.stderr, level=logging.INFO)
 
147
#        logging.basicConfig(
 
148
#            stream=sys.stderr, level=logging.INFO)
122
149
        service.serve_forever()
123
150
 
124
151
    def __exit__(self, exc_type, exc_val, traceback):
125
152
        os.kill(self.pid, SIGKILL)
126
153
 
127
154
 
 
155
SUPPORTED_ORDERS = set(
 
156
    ['date', 'author', 'subject', 'thread_newest', 'thread_oldest',
 
157
     'thread_subject'])
 
158
 
 
159
 
128
160
class FakeGrackleRequestHandler(BaseHTTPRequestHandler):
129
 
    """A request handler that forwards to server.store."""
130
161
 
131
162
    def __init__(self, *args, **kwargs):
132
 
        """Constructor.  Sets up logging."""
133
163
        self.logger = logging.getLogger('http')
134
164
        BaseHTTPRequestHandler.__init__(self, *args, **kwargs)
135
165
 
136
166
    def do_POST(self):
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'
 
167
        message = self.rfile.read(int(self.headers['content-length']))
 
168
        if message == 'This is a message':
 
169
            self.send_response(httplib.CREATED)
 
170
            self.end_headers()
 
171
            self.wfile.close()
146
172
        else:
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)
 
173
            self.send_error(httplib.BAD_REQUEST)
168
174
 
169
175
    def do_GET(self):
170
 
        """Retrieve a list of messages on GET."""
171
176
        scheme, netloc, path, params, query_string, fragments = (
172
177
            urlparse(self.path))
173
178
        parts = path.split('/')
178
183
                self.send_response(httplib.OK)
179
184
                self.end_headers()
180
185
                self.wfile.write(simplejson.dumps(response))
181
 
            except Exception, error:
182
 
                self.send_response(
183
 
                    httplib.BAD_REQUEST, error.__doc__)
 
186
            except UnsupportedOrder:
 
187
                self.send_response(httplib.BAD_REQUEST)
 
188
                self.wfile.write('Unsupported order')
184
189
                return
185
190
 
186
191
    def log_message(self, format, *args):
187
 
        """Override log_message to use standard Python logging."""
188
192
        message = "%s - - [%s] %s\n" % (
189
 
            self.address_string(), self.log_date_time_string(), format % args)
 
193
            self.address_string(), self.log_date_time_string(), format%args)
190
194
        self.logger.info(message)
191
195
 
192
196
 
193
197
class TestPutMessage(TestCase):
194
198
 
195
199
    def test_put_message(self):
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):
 
200
        client = GrackleClient('localhost', 8436)
 
201
        with ForkedFake.from_client(client):
 
202
            client.put_message('arch1', 'asdf', StringIO('This is a message'))
209
203
            with ExpectedException(Exception, 'wtf'):
210
 
                client.put_message('no-archive', 'id1', StringIO('message'))
 
204
                client.put_message('arch1', 'asdf',
 
205
                    StringIO('This is not a message'))
211
206
 
212
207
 
213
208
class TestGetMessages(TestCase):
217
212
 
218
213
    def assertMessageIDs(self, ids, messages):
219
214
        self.assertIDOrder(
220
 
            sorted(ids), sorted(messages, key=lambda m: m['message_id']))
 
215
            sorted(ids), sorted(messages, key=lambda m:m['message_id']))
221
216
 
222
217
    def test_get_messages(self):
223
 
        client = GrackleClient('localhost', 8430)
224
 
        archive = {
225
 
            'baz': [make_message('foo'), make_message('bar')]}
226
 
        with ForkedFakeService.from_client(client, archive):
 
218
        client = GrackleClient('localhost', 8435)
 
219
        with ForkedFake.from_client(client,
 
220
            {'baz':
 
221
            [{'message_id': 'foo'},
 
222
             {'message_id': 'bar'}]}):
227
223
            response = client.get_messages('baz')
228
224
        self.assertEqual(['bar', 'foo'], sorted(m['message_id'] for m in
229
225
            response['messages']))
232
228
 
233
229
    def test_get_messages_by_id(self):
234
230
        client = GrackleClient('localhost', 8437)
235
 
        archive = {
236
 
            'baz': [make_message('foo'), make_message('bar')]}
237
 
        with ForkedFakeService.from_client(client, archive):
 
231
        with ForkedFake.from_client(client,
 
232
            {'baz':
 
233
            [{'message_id': 'foo'},
 
234
             {'message_id': 'bar'}]}):
238
235
            response = client.get_messages('baz', message_ids=['foo'])
239
236
        message, = response['messages']
240
237
        self.assertEqual('foo', message['message_id'])
241
238
 
242
239
    def test_get_messages_batching(self):
243
240
        client = GrackleClient('localhost', 8438)
244
 
        archive = {'baz': [make_message('foo'), make_message('bar')]}
245
 
        with ForkedFakeService.from_client(client, archive):
 
241
        with ForkedFake.from_client(client,
 
242
            {'baz':
 
243
            [{'message_id': 'foo'},
 
244
             {'message_id': 'bar'}]}):
246
245
            response = client.get_messages('baz', limit=1)
247
246
            self.assertEqual(1, len(response['messages']))
248
247
            messages = response['messages']
254
253
 
255
254
    def get_messages_member_order_test(self, key):
256
255
        client = GrackleClient('localhost', 8439)
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):
 
256
        with ForkedFake.from_client(client,
 
257
                {'baz': [{'message_id': 'foo', key: '2011-03-25'},
 
258
                 {'message_id': 'bar', key: '2011-03-24'}]}):
267
259
            response = client.get_messages('baz')
268
260
            self.assertIDOrder(['foo', 'bar'], response['messages'])
269
261
            response = client.get_messages('baz', order=key)
279
271
        self.get_messages_member_order_test('subject')
280
272
 
281
273
    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
 
             ]}
289
274
        client = GrackleClient('localhost', 8439)
290
 
        with ForkedFakeService.from_client(client, archive):
 
275
        with ForkedFake.from_client(client, {'baz': [
 
276
            {'message_id': 'bar', 'subject': 'y'},
 
277
            {'message_id': 'qux', 'subject': 'z'},
 
278
            {'message_id': 'foo', 'subject': 'x', 'in_reply_to': 'qux'},
 
279
            ]}):
291
280
            response = client.get_messages('baz')
292
281
            self.assertIDOrder(['bar', 'qux', 'foo'], response['messages'])
293
282
            response = client.get_messages('baz', order='subject')
297
286
 
298
287
    def test_get_messages_thread_oldest_order(self):
299
288
        client = GrackleClient('localhost', 8439)
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):
 
289
        with ForkedFake.from_client(client, {'baz': [
 
290
            {'message_id': 'bar', 'date': 'x'},
 
291
            {'message_id': 'qux', 'date': 'z'},
 
292
            {'message_id': 'foo', 'date': 'y', 'in_reply_to': 'qux'},
 
293
            ]}):
308
294
            response = client.get_messages('baz')
309
295
            self.assertIDOrder(['bar', 'qux', 'foo'], response['messages'])
310
296
            response = client.get_messages('baz', order='date')
314
300
 
315
301
    def test_get_messages_thread_newest_order(self):
316
302
        client = GrackleClient('localhost', 8439)
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):
 
303
        with ForkedFake.from_client(client, {'baz': [
 
304
            {'message_id': 'bar', 'date': 'x'},
 
305
            {'message_id': 'qux', 'date': 'w'},
 
306
            {'message_id': 'foo', 'date': 'y', 'in_reply_to': 'bar'},
 
307
            {'message_id': 'baz', 'date': 'z', 'in_reply_to': 'qux'},
 
308
            ]}):
327
309
            response = client.get_messages('baz', order='date')
328
310
            self.assertIDOrder(
329
311
                ['qux', 'bar', 'foo', 'baz'], response['messages'])
333
315
 
334
316
    def test_get_messages_unsupported_order(self):
335
317
        client = GrackleClient('localhost', 8439)
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, ''):
 
318
        with ForkedFake.from_client(client,
 
319
                {'baz': [{'message_id': 'foo', 'date': '2011-03-25'},
 
320
                 {'message_id': 'bar', 'date': '2011-03-24'}]}):
 
321
            with ExpectedException(UnsupportedOrder):
343
322
                client.get_messages('baz', order='nonsense')
344
323
 
345
324
    def test_get_messages_headers_no_headers(self):
346
325
        client = GrackleClient('localhost', 8440)
347
 
        archive = {'baz': [make_message('foo')]}
348
 
        with ForkedFakeService.from_client(client, archive):
 
326
        with ForkedFake.from_client(client,
 
327
            {'baz': [
 
328
                {'message_id': 'foo'}
 
329
            ]}):
349
330
            response = client.get_messages('baz', headers=[
350
331
                'Subject', 'Date', 'X-Launchpad-Message-Rationale'])
351
332
        first_message = response['messages'][0]
354
335
 
355
336
    def test_get_messages_headers_exclude_headers(self):
356
337
        client = GrackleClient('localhost', 8441)
357
 
        archive = {
358
 
            'baz': [make_message('foo', headers={'From': 'me'})]}
359
 
        with ForkedFakeService.from_client(client, archive):
 
338
        with ForkedFake.from_client(client,
 
339
            {'baz': [
 
340
                {'message_id': 'foo', 'headers': {'From': 'me'}}
 
341
            ]}):
360
342
            response = client.get_messages('baz', headers=[
361
343
                'Subject', 'Date', 'X-Launchpad-Message-Rationale'])
362
344
        first_message = response['messages'][0]
365
347
 
366
348
    def test_get_messages_headers_include_headers(self):
367
349
        client = GrackleClient('localhost', 8442)
368
 
        archive = {
369
 
            'baz': [
370
 
                make_message('foo', headers={'From': 'me', 'To': 'you'})]}
371
 
        with ForkedFakeService.from_client(client, archive):
 
350
        with ForkedFake.from_client(client,
 
351
            {'baz': [
 
352
                {'message_id': 'foo', 'headers': {'From': 'me', 'To': 'you'}}
 
353
            ]}):
372
354
            response = client.get_messages('baz', headers=[
373
355
                'From', 'To'])
374
356
        first_message = response['messages'][0]
377
359
 
378
360
    def test_get_messages_max_body_length(self):
379
361
        client = GrackleClient('localhost', 8443)
380
 
        archive = {'baz': [make_message('foo', body=u'abcdefghi')]}
381
 
        with ForkedFakeService.from_client(client, archive):
 
362
        with ForkedFake.from_client(client,
 
363
            {'baz': [
 
364
                {'message_id': 'foo', 'body': u'abcdefghi'}
 
365
            ]}):
382
366
            response = client.get_messages('baz', max_body_length=3)
383
367
        first_message = response['messages'][0]
384
368
        self.assertEqual('abc', first_message['body'])
385
369
 
386
370
    def test_include_hidden(self):
387
371
        client = GrackleClient('localhost', 8444)
388
 
        archive = {
389
 
            'baz': [
390
 
                make_message('foo', hidden=True),
391
 
                make_message('bar', hidden=False),
392
 
            ]}
393
 
        with ForkedFakeService.from_client(client, archive):
 
372
        with ForkedFake.from_client(client,
 
373
            {'baz': [
 
374
                {'message_id': 'foo', 'hidden': True},
 
375
                {'message_id': 'bar', 'hidden': False}
 
376
            ]}):
394
377
            response = client.get_messages('baz', include_hidden=True)
395
378
            self.assertMessageIDs(['bar', 'foo'], response['messages'])
396
379
            response = client.get_messages('baz', include_hidden=False)
397
380
            self.assertMessageIDs(['bar'], response['messages'])
398
381
 
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'])