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