~didrocks/unity/altf10

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