~unity-2d-team/unity-2d/Shell-MultiMonitor

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