~didrocks/unity/altf10

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