~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
56 by Curtis Hovey
Use PUT for creating messages.
144
        if len(parts) == 4:
145
            # 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.
146
            try:
56 by Curtis Hovey
Use PUT for creating messages.
147
                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.
148
                self.server.store.put_message(parts[2], parts[3], message)
149
                self.send_response(httplib.CREATED)
150
                self.end_headers()
151
                self.wfile.close()
152
            except:
153
                self.send_error(httplib.BAD_REQUEST)
56 by Curtis Hovey
Use PUT for creating messages.
154
155
    def do_POST(self):
156
        """Change a message on POST."""
157
        scheme, netloc, path, params, query_string, fragments = (
158
            urlparse(self.path))
159
        parts = path.split('/')
160
        if parts[1] != 'archive':
161
            # This is an unknonwn operation?
162
            return
163
        if len(parts) == 4:
164
            # This expected path is /archive/archive_id/message_id.
52 by Curtis Hovey
Added support for hide_message.
165
            try:
166
                # This expected path is /archive/archive_id/message_id.
167
                response = self.server.store.hide_message(
168
                    parts[2], parts[3], query_string)
169
                self.send_response(httplib.OK)
170
                self.end_headers()
171
                self.wfile.write(simplejson.dumps(response))
172
            except:
173
                self.send_error(httplib.BAD_REQUEST)
28 by Aaron Bentley
Extract GrackleStore.
174
175
    def do_GET(self):
34 by Aaron Bentley
Cleanup
176
        """Retrieve a list of messages on GET."""
28 by Aaron Bentley
Extract GrackleStore.
177
        scheme, netloc, path, params, query_string, fragments = (
178
            urlparse(self.path))
179
        parts = path.split('/')
180
        if parts[1] == 'archive':
181
            try:
182
                response = self.server.store.get_messages(
183
                    parts[2], query_string)
184
                self.send_response(httplib.OK)
185
                self.end_headers()
186
                self.wfile.write(simplejson.dumps(response))
39 by Curtis Hovey
Raise UnparsableDateRange when the date cannot be parsed.
187
            except Exception, error:
188
                self.send_response(
189
                    httplib.BAD_REQUEST, error.__doc__)
28 by Aaron Bentley
Extract GrackleStore.
190
                return
13 by Aaron Bentley
Retrieve messages.
191
32 by Aaron Bentley
Switch test HTTP server to standard Python logging.
192
    def log_message(self, format, *args):
34 by Aaron Bentley
Cleanup
193
        """Override log_message to use standard Python logging."""
32 by Aaron Bentley
Switch test HTTP server to standard Python logging.
194
        message = "%s - - [%s] %s\n" % (
35.1.1 by Curtis Hovey
Hush lint.
195
            self.address_string(), self.log_date_time_string(), format % args)
32 by Aaron Bentley
Switch test HTTP server to standard Python logging.
196
        self.logger.info(message)
197
5 by Aaron Bentley
Actual fake service working.
198
3 by Aaron Bentley
Add test framework.
199
class TestPutMessage(TestCase):
200
201
    def test_put_message(self):
42 by Curtis Hovey
Separate gracle MemoryStore to its own module.
202
        client = GrackleClient('localhost', 8420)
46 by Curtis Hovey
Implemented a partial put into the MemoryStore.
203
        message_archives = {'arch1': []}
47 by Curtis Hovey
Raise ArchiveIdNotFound if the client puts a message into an unknown archive.
204
        with ForkedFakeService.from_client(client, message_archives):
46 by Curtis Hovey
Implemented a partial put into the MemoryStore.
205
            client.put_message('arch1', 'id1', StringIO('This is a message'))
206
            response = client.get_messages('arch1')
47 by Curtis Hovey
Raise ArchiveIdNotFound if the client puts a message into an unknown archive.
207
        self.assertEqual(1, len(response['messages']))
208
        message = response['messages'][0]
209
        self.assertEqual('id1', message['message_id'])
46 by Curtis Hovey
Implemented a partial put into the MemoryStore.
210
47 by Curtis Hovey
Raise ArchiveIdNotFound if the client puts a message into an unknown archive.
211
    def test_put_message_without_archive(self):
46 by Curtis Hovey
Implemented a partial put into the MemoryStore.
212
        client = GrackleClient('localhost', 8421)
213
        message_archives = {'arch1': []}
214
        with ForkedFakeService.from_client(client, message_archives):
5 by Aaron Bentley
Actual fake service working.
215
            with ExpectedException(Exception, 'wtf'):
47 by Curtis Hovey
Raise ArchiveIdNotFound if the client puts a message into an unknown archive.
216
                client.put_message('no-archive', 'id1', StringIO('message'))
11 by Aaron Bentley
Start working on GET.
217
218
219
class TestGetMessages(TestCase):
220
20 by Aaron Bentley
Support order by date
221
    def assertIDOrder(self, ids, messages):
222
        self.assertEqual(ids, [m['message_id'] for m in messages])
223
19 by Aaron Bentley
Implement memo/limit support.
224
    def assertMessageIDs(self, ids, messages):
20 by Aaron Bentley
Support order by date
225
        self.assertIDOrder(
35.1.1 by Curtis Hovey
Hush lint.
226
            sorted(ids), sorted(messages, key=lambda m: m['message_id']))
19 by Aaron Bentley
Implement memo/limit support.
227
11 by Aaron Bentley
Start working on GET.
228
    def test_get_messages(self):
42 by Curtis Hovey
Separate gracle MemoryStore to its own module.
229
        client = GrackleClient('localhost', 8430)
35.1.14 by Curtis Hovey
Create the archive outside of the call to create the server.
230
        archive = {
231
            'baz': [make_message('foo'), make_message('bar')]}
232
        with ForkedFakeService.from_client(client, archive):
15 by Aaron Bentley
Test filtering by message-id.
233
            response = client.get_messages('baz')
17 by Aaron Bentley
Switch hyphens to underscores.
234
        self.assertEqual(['bar', 'foo'], sorted(m['message_id'] for m in
16 by Aaron Bentley
Include next_memo, previous_memo in get_messages response.
235
            response['messages']))
236
        self.assertIs(None, response['next_memo'])
237
        self.assertIs(None, response['previous_memo'])
15 by Aaron Bentley
Test filtering by message-id.
238
239
    def test_get_messages_by_id(self):
240
        client = GrackleClient('localhost', 8437)
35.1.14 by Curtis Hovey
Create the archive outside of the call to create the server.
241
        archive = {
242
            'baz': [make_message('foo'), make_message('bar')]}
243
        with ForkedFakeService.from_client(client, archive):
16 by Aaron Bentley
Include next_memo, previous_memo in get_messages response.
244
            response = client.get_messages('baz', message_ids=['foo'])
245
        message, = response['messages']
17 by Aaron Bentley
Switch hyphens to underscores.
246
        self.assertEqual('foo', message['message_id'])
19 by Aaron Bentley
Implement memo/limit support.
247
248
    def test_get_messages_batching(self):
20 by Aaron Bentley
Support order by date
249
        client = GrackleClient('localhost', 8438)
35.1.14 by Curtis Hovey
Create the archive outside of the call to create the server.
250
        archive = {'baz': [make_message('foo'), make_message('bar')]}
251
        with ForkedFakeService.from_client(client, archive):
19 by Aaron Bentley
Implement memo/limit support.
252
            response = client.get_messages('baz', limit=1)
253
            self.assertEqual(1, len(response['messages']))
254
            messages = response['messages']
255
            response = client.get_messages(
256
                'baz', limit=1, memo=response['next_memo'])
257
            self.assertEqual(1, len(response['messages']))
258
            messages.extend(response['messages'])
259
            self.assertMessageIDs(['foo', 'bar'], messages)
20 by Aaron Bentley
Support order by date
260
22 by Aaron Bentley
Order by thread subject.
261
    def get_messages_member_order_test(self, key):
20 by Aaron Bentley
Support order by date
262
        client = GrackleClient('localhost', 8439)
51 by Curtis Hovey
Always use an rfc822 message in tests.
263
        if key == 'author':
264
            header_name = 'from'
265
        else:
266
            header_name = key
35.1.14 by Curtis Hovey
Create the archive outside of the call to create the server.
267
        archive = {
268
            'baz': [
51 by Curtis Hovey
Always use an rfc822 message in tests.
269
                make_message('foo', headers={header_name: '2011-03-25'}),
270
                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.
271
             ]}
272
        with ForkedFakeService.from_client(client, archive):
20 by Aaron Bentley
Support order by date
273
            response = client.get_messages('baz')
274
            self.assertIDOrder(['foo', 'bar'], response['messages'])
22 by Aaron Bentley
Order by thread subject.
275
            response = client.get_messages('baz', order=key)
20 by Aaron Bentley
Support order by date
276
            self.assertIDOrder(['bar', 'foo'], response['messages'])
21 by Aaron Bentley
Test unsupported orders.
277
22 by Aaron Bentley
Order by thread subject.
278
    def test_get_messages_date_order(self):
279
        self.get_messages_member_order_test('date')
280
281
    def test_get_messages_author_order(self):
282
        self.get_messages_member_order_test('author')
283
284
    def test_get_messages_subject_order(self):
285
        self.get_messages_member_order_test('subject')
286
287
    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.
288
        archive = {
289
            'baz': [
290
                make_message('bar', headers={'subject': 'y'}),
291
                make_message('qux', headers={'subject': 'z'}),
292
                make_message('foo', headers={'subject': 'x',
293
                                             'in-reply-to': 'qux'}),
294
             ]}
22 by Aaron Bentley
Order by thread subject.
295
        client = GrackleClient('localhost', 8439)
35.1.13 by Curtis Hovey
Use make_message() to make test data consistent.
296
        with ForkedFakeService.from_client(client, archive):
22 by Aaron Bentley
Order by thread subject.
297
            response = client.get_messages('baz')
298
            self.assertIDOrder(['bar', 'qux', 'foo'], response['messages'])
299
            response = client.get_messages('baz', order='subject')
300
            self.assertIDOrder(['foo', 'bar', 'qux'], response['messages'])
301
            response = client.get_messages('baz', order='thread_subject')
302
            self.assertIDOrder(['bar', 'qux', 'foo'], response['messages'])
303
23 by Aaron Bentley
Support thread_oldest order.
304
    def test_get_messages_thread_oldest_order(self):
305
        client = GrackleClient('localhost', 8439)
35.1.14 by Curtis Hovey
Create the archive outside of the call to create the server.
306
        archive = {
307
            'baz': [
308
                make_message('bar', headers={'date': 'x'}),
309
                make_message('qux', headers={'date': 'z'}),
310
                make_message('foo', headers={'date': 'y',
311
                                             'in-reply-to': 'qux'}),
35.1.13 by Curtis Hovey
Use make_message() to make test data consistent.
312
            ]}
313
        with ForkedFakeService.from_client(client, archive):
23 by Aaron Bentley
Support thread_oldest order.
314
            response = client.get_messages('baz')
315
            self.assertIDOrder(['bar', 'qux', 'foo'], response['messages'])
316
            response = client.get_messages('baz', order='date')
317
            self.assertIDOrder(['bar', 'foo', 'qux'], response['messages'])
318
            response = client.get_messages('baz', order='thread_oldest')
319
            self.assertIDOrder(['bar', 'qux', 'foo'], response['messages'])
320
24 by Aaron Bentley
Support thread_newest threading.
321
    def test_get_messages_thread_newest_order(self):
322
        client = GrackleClient('localhost', 8439)
35.1.14 by Curtis Hovey
Create the archive outside of the call to create the server.
323
        archive = {
324
            'baz': [
325
                make_message('bar', headers={'date': 'x'}),
326
                make_message('qux', headers={'date': 'w'}),
327
                make_message('foo', headers={'date': 'y',
328
                                             'in-reply-to': 'bar'}),
329
                make_message('baz', headers={'date': 'z',
330
                                             'in-reply-to': 'qux'}),
331
            ]}
332
        with ForkedFakeService.from_client(client, archive):
24 by Aaron Bentley
Support thread_newest threading.
333
            response = client.get_messages('baz', order='date')
334
            self.assertIDOrder(
335
                ['qux', 'bar', 'foo', 'baz'], response['messages'])
336
            response = client.get_messages('baz', order='thread_newest')
337
            self.assertIDOrder(
338
                ['bar', 'foo', 'qux', 'baz'], response['messages'])
339
21 by Aaron Bentley
Test unsupported orders.
340
    def test_get_messages_unsupported_order(self):
341
        client = GrackleClient('localhost', 8439)
35.1.14 by Curtis Hovey
Create the archive outside of the call to create the server.
342
        archive = {
343
            'baz': [
35.1.13 by Curtis Hovey
Use make_message() to make test data consistent.
344
                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.
345
                make_message('foo', headers={'date': '2011-03-24'}),
346
            ]}
347
        with ForkedFakeService.from_client(client, archive):
35 by William Grant
Fix test.
348
            with ExpectedException(UnsupportedOrder, ''):
21 by Aaron Bentley
Test unsupported orders.
349
                client.get_messages('baz', order='nonsense')
27 by Aaron Bentley
get_messages supports header parameter.
350
351
    def test_get_messages_headers_no_headers(self):
352
        client = GrackleClient('localhost', 8440)
35.1.14 by Curtis Hovey
Create the archive outside of the call to create the server.
353
        archive = {'baz': [make_message('foo')]}
354
        with ForkedFakeService.from_client(client, archive):
27 by Aaron Bentley
get_messages supports header parameter.
355
            response = client.get_messages('baz', headers=[
356
                'Subject', 'Date', 'X-Launchpad-Message-Rationale'])
357
        first_message = response['messages'][0]
358
        self.assertEqual('foo', first_message['message_id'])
359
        self.assertEqual({}, first_message['headers'])
360
361
    def test_get_messages_headers_exclude_headers(self):
29 by Aaron Bentley
implement include_hidden.
362
        client = GrackleClient('localhost', 8441)
35.1.14 by Curtis Hovey
Create the archive outside of the call to create the server.
363
        archive = {
364
            'baz': [make_message('foo', headers={'From': 'me'})]}
365
        with ForkedFakeService.from_client(client, archive):
27 by Aaron Bentley
get_messages supports header parameter.
366
            response = client.get_messages('baz', headers=[
367
                'Subject', 'Date', 'X-Launchpad-Message-Rationale'])
368
        first_message = response['messages'][0]
369
        self.assertEqual('foo', first_message['message_id'])
370
        self.assertEqual({}, first_message['headers'])
371
372
    def test_get_messages_headers_include_headers(self):
29 by Aaron Bentley
implement include_hidden.
373
        client = GrackleClient('localhost', 8442)
35.1.14 by Curtis Hovey
Create the archive outside of the call to create the server.
374
        archive = {
375
            'baz': [
376
                make_message('foo', headers={'From': 'me', 'To': 'you'})]}
377
        with ForkedFakeService.from_client(client, archive):
27 by Aaron Bentley
get_messages supports header parameter.
378
            response = client.get_messages('baz', headers=[
379
                'From', 'To'])
380
        first_message = response['messages'][0]
381
        self.assertEqual('foo', first_message['message_id'])
382
        self.assertEqual({'From': 'me', 'To': 'you'}, first_message['headers'])
28 by Aaron Bentley
Extract GrackleStore.
383
384
    def test_get_messages_max_body_length(self):
29 by Aaron Bentley
implement include_hidden.
385
        client = GrackleClient('localhost', 8443)
35.1.14 by Curtis Hovey
Create the archive outside of the call to create the server.
386
        archive = {'baz': [make_message('foo', body=u'abcdefghi')]}
387
        with ForkedFakeService.from_client(client, archive):
28 by Aaron Bentley
Extract GrackleStore.
388
            response = client.get_messages('baz', max_body_length=3)
389
        first_message = response['messages'][0]
390
        self.assertEqual('abc', first_message['body'])
391
29 by Aaron Bentley
implement include_hidden.
392
    def test_include_hidden(self):
393
        client = GrackleClient('localhost', 8444)
35.1.14 by Curtis Hovey
Create the archive outside of the call to create the server.
394
        archive = {
395
            'baz': [
35.1.13 by Curtis Hovey
Use make_message() to make test data consistent.
396
                make_message('foo', hidden=True),
35.1.14 by Curtis Hovey
Create the archive outside of the call to create the server.
397
                make_message('bar', hidden=False),
398
            ]}
399
        with ForkedFakeService.from_client(client, archive):
29 by Aaron Bentley
implement include_hidden.
400
            response = client.get_messages('baz', include_hidden=True)
401
            self.assertMessageIDs(['bar', 'foo'], response['messages'])
402
            response = client.get_messages('baz', include_hidden=False)
403
            self.assertMessageIDs(['bar'], response['messages'])
35.1.4 by Curtis Hovey
Added SUPPORTED_DISPLAY_TYPES.
404
405
    def test_display_type_unknown_value(self):
35.1.5 by Curtis Hovey
Moved the display_type arg.
406
        client = GrackleClient('localhost', 8445)
35.1.14 by Curtis Hovey
Create the archive outside of the call to create the server.
407
        archive = {'baz': [make_message('foo', body=u'abcdefghi')]}
408
        with ForkedFakeService.from_client(client, archive):
35.1.4 by Curtis Hovey
Added SUPPORTED_DISPLAY_TYPES.
409
            with ExpectedException(UnsupportedDisplayType, ''):
410
                client.get_messages('baz', display_type='unknown')
35.1.6 by Curtis Hovey
Added display_type == 'headers-only' support.
411
412
    def test_display_type_headers_only(self):
35.1.9 by Curtis Hovey
Added support for display_type == 'text-only'.
413
        client = GrackleClient('localhost', 8446)
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', body=u'abcdefghi',
35.1.14 by Curtis Hovey
Create the archive outside of the call to create the server.
417
                             headers={'From': 'me', 'To': 'you'})]}
418
        with ForkedFakeService.from_client(client, archive):
35.1.6 by Curtis Hovey
Added display_type == 'headers-only' support.
419
            response = client.get_messages('baz', display_type='headers-only')
420
        first_message = response['messages'][0]
421
        self.assertEqual('foo', first_message['message_id'])
35.1.13 by Curtis Hovey
Use make_message() to make test data consistent.
422
        self.assertEqual(
51 by Curtis Hovey
Always use an rfc822 message in tests.
423
            archive['baz'][0]['headers'], first_message['headers'])
35.1.6 by Curtis Hovey
Added display_type == 'headers-only' support.
424
        self.assertNotIn('body', first_message)
35.1.9 by Curtis Hovey
Added support for display_type == 'text-only'.
425
426
    def test_display_type_text_only(self):
427
        client = GrackleClient('localhost', 8446)
35.1.14 by Curtis Hovey
Create the archive outside of the call to create the server.
428
        archive = {
429
            'baz': [
35.1.12 by Curtis Hovey
Renamed make_message => make_mime_message.
430
                make_mime_message(
35.1.11 by Curtis Hovey
Reanme make_json_message => make_message.
431
                    'foo', 'abcdefghi',
35.1.9 by Curtis Hovey
Added support for display_type == 'text-only'.
432
                    headers={'From': 'me', 'To': 'you'},
35.1.14 by Curtis Hovey
Create the archive outside of the call to create the server.
433
                    attachment_type='text/x-diff')]}
434
        with ForkedFakeService.from_client(client, archive):
35.1.9 by Curtis Hovey
Added support for display_type == 'text-only'.
435
            response = client.get_messages('baz', display_type='text-only')
436
        first_message = response['messages'][0]
437
        self.assertEqual('foo', first_message['message_id'])
438
        self.assertEqual('me', first_message['headers']['From'])
439
        self.assertEqual('you', first_message['headers']['To'])
48 by Curtis Hovey
Use a real rfc822 message for mime testing.
440
        self.assertEqual(archive['baz'][0]['body'], first_message['body'])
35.1.10 by Curtis Hovey
Added support for display_type == 'all'.
441
442
    def test_display_type_all(self):
443
        client = GrackleClient('localhost', 8447)
35.1.14 by Curtis Hovey
Create the archive outside of the call to create the server.
444
        archive = {
445
            'baz': [
35.1.12 by Curtis Hovey
Renamed make_message => make_mime_message.
446
                make_mime_message(
35.1.11 by Curtis Hovey
Reanme make_json_message => make_message.
447
                    'foo', 'abcdefghi',
35.1.10 by Curtis Hovey
Added support for display_type == 'all'.
448
                    headers={'From': 'me', 'To': 'you'},
35.1.14 by Curtis Hovey
Create the archive outside of the call to create the server.
449
                    attachment_type='text/x-diff')]}
450
        with ForkedFakeService.from_client(client, archive):
35.1.10 by Curtis Hovey
Added support for display_type == 'all'.
451
            response = client.get_messages('baz', display_type='all')
452
        first_message = response['messages'][0]
453
        self.assertEqual('foo', first_message['message_id'])
454
        self.assertEqual('me', first_message['headers']['From'])
455
        self.assertEqual('you', first_message['headers']['To'])
48 by Curtis Hovey
Use a real rfc822 message for mime testing.
456
        self.assertEqual(archive['baz'][0]['body'], first_message['body'])
38 by Curtis Hovey
Added basic handling of date_range.
457
458
    def test_date_range(self):
459
        client = GrackleClient('localhost', 8448)
460
        archive = {
461
            'baz': [
462
                make_mime_message(
463
                    'foo', 'abcdefghi', headers={'date': '2011-12-31'}),
464
                make_mime_message(
465
                    'bar', 'abcdefghi', headers={'date': '2012-01-01'}),
466
                make_mime_message(
467
                    'qux', 'abcdefghi', headers={'date': '2012-01-15'}),
468
                make_mime_message(
469
                    'naf', 'abcdefghi', headers={'date': '2012-01-31'}),
470
                make_mime_message(
471
                    'doh', 'abcdefghi', headers={'date': '2012-02-01'}),
472
                    ]}
473
        with ForkedFakeService.from_client(client, archive):
474
            response = client.get_messages(
475
                'baz', date_range='2012-01-01..2012-01-31')
476
        ids = sorted(m['message_id'] for m in response['messages'])
477
        self.assertEqual(['bar', 'naf', 'qux'], ids)
39 by Curtis Hovey
Raise UnparsableDateRange when the date cannot be parsed.
478
479
    def test_date_range_unparsabledaterange(self):
41 by Curtis Hovey
Added test for extra data argument.
480
        client = GrackleClient('localhost', 8449)
39 by Curtis Hovey
Raise UnparsableDateRange when the date cannot be parsed.
481
        archive = {'baz': [make_message('foo', body=u'abcdefghi')]}
482
        with ForkedFakeService.from_client(client, archive):
483
            with ExpectedException(UnparsableDateRange, ''):
484
                client.get_messages('baz', date_range='2012-01-01')
40 by Curtis Hovey
Dates must be a value.
485
486
    def test_date_range_unparsabledaterange_missing_part(self):
41 by Curtis Hovey
Added test for extra data argument.
487
        client = GrackleClient('localhost', 8450)
40 by Curtis Hovey
Dates must be a value.
488
        archive = {'baz': [make_message('foo', body=u'abcdefghi')]}
489
        with ForkedFakeService.from_client(client, archive):
490
            with ExpectedException(UnparsableDateRange, ''):
491
                client.get_messages('baz', date_range='2012-01-01..')
41 by Curtis Hovey
Added test for extra data argument.
492
493
    def test_date_range_unparsabledaterange_extra_part(self):
494
        client = GrackleClient('localhost', 8451)
495
        archive = {'baz': [make_message('foo', body=u'abcdefghi')]}
496
        with ForkedFakeService.from_client(client, archive):
497
            with ExpectedException(UnparsableDateRange, ''):
498
                client.get_messages('baz', date_range='2012-01..12-02..12-03')
52 by Curtis Hovey
Added support for hide_message.
499
500
501
class TestHideMessages(TestCase):
502
503
    def test_hide_message_true(self):
504
        client = GrackleClient('localhost', 8470)
505
        archive = {
506
            'baz': [
507
                make_message('foo', hidden=False),
508
            ]}
509
        with ForkedFakeService.from_client(client, archive):
510
            response = client.hide_message('baz', 'foo', hidden=True)
511
        self.assertEqual('foo', response['message_id'])
512
        self.assertIs(True, response['hidden'])
513
514
    def test_hide_message_false(self):
515
        client = GrackleClient('localhost', 8470)
516
        archive = {
517
            'baz': [
518
                make_message('foo', hidden=True),
519
            ]}
520
        with ForkedFakeService.from_client(client, archive):
521
            response = client.hide_message('baz', 'foo', hidden=False)
522
        self.assertEqual('foo', response['message_id'])
523
        self.assertIs(False, response['hidden'])