~didrocks/unity/altf10

« back to all changes in this revision

Viewing changes to grackle/tests/test_client.py

  • Committer: Curtis Hovey
  • Date: 2012-03-16 19:38:35 UTC
  • Revision ID: curtis.hovey@canonical.com-20120316193835-egu5tc1n0xlr5udj
Rename args to be honest about what is expected.

Show diffs side-by-side

added added

removed removed

Lines of Context:
24
24
    UnsupportedOrder,
25
25
    )
26
26
from grackle.store import (
 
27
    make_json_message,
27
28
    MemoryStore,
28
29
    )
29
30
 
31
32
def make_message(message_id, body='body', headers=None, hidden=False):
32
33
    if headers is None:
33
34
        headers = {}
34
 
    headers['Message-Id'] = message_id
35
 
    message = {
36
 
        'message_id': message_id,
37
 
        'headers': headers,
38
 
        'thread_id': message_id,
39
 
        'date': headers.get('date', '2005-01-01'),
40
 
        'subject': headers.get('subject', 'subject'),
41
 
        'author': headers.get('author', 'author'),
42
 
        'hidden': hidden,
43
 
        'attachments': [],
44
 
        'replies': headers.get('in-reply-to', None),
45
 
        'body': body,
 
35
    message_headers = {
 
36
        'Message-Id': message_id,
 
37
        'date': '2005-01-01',
 
38
        'subject': 'subject',
 
39
        'from': 'author',
 
40
        'replies': '',
46
41
        }
47
 
    return message
 
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)
48
48
 
49
49
 
50
50
def make_mime_message(message_id, body='body', headers=None, hidden=False,
51
51
                      attachment_type=None):
52
 
    message = MIMEMultipart()
53
 
    message.attach(MIMEText(body))
 
52
    parts = MIMEMultipart()
 
53
    parts.attach(MIMEText(body))
54
54
    if attachment_type is not None:
55
55
        attachment = Message()
56
56
        attachment.set_payload('attactment data.')
57
57
        attachment['Content-Type'] = attachment_type
58
58
        attachment['Content-Disposition'] = 'attachment; filename="file.ext"'
59
 
        message.attach(attachment)
60
 
    return make_message(message_id, message.get_payload(), headers, hidden)
 
59
        parts.attach(attachment)
 
60
    return make_message(message_id, parts.as_string(), headers, hidden)
61
61
 
62
62
 
63
63
class ForkedFakeService:
64
64
    """A Grackle service fake, as a ContextManager."""
65
65
 
66
 
    def __init__(self, port, messages=None, write_logs=False):
 
66
    def __init__(self, port, message_archives=None, write_logs=False):
67
67
        """Constructor.
68
68
 
69
69
        :param port: The tcp port to use.
70
 
        :param messages: A dict of lists of dicts representing messages.  The
71
 
            outer dict represents the archive, the list represents the list of
72
 
            messages for that archive.
 
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.
73
73
        :param write_logs: If true, log messages will be written to stdout.
74
74
        """
75
75
        self.pid = None
76
76
        self.port = port
77
 
        if messages is None:
78
 
            self.messages = {}
 
77
        if message_archives is None:
 
78
            self.message_archives = {}
79
79
        else:
80
 
            self.messages = messages
 
80
            self.message_archives = message_archives
81
81
        self.read_end, self.write_end = os.pipe()
82
82
        self.write_logs = write_logs
83
83
 
84
84
    @staticmethod
85
 
    def from_client(client, messages=None):
 
85
    def from_client(client, message_archives=None):
86
86
        """Instantiate a ForkedFakeService from the client.
87
87
 
88
88
        :param port: The client to provide service for.
89
 
        :param messages: A dict of lists of dicts representing messages.  The
90
 
            outer dict represents the archive, the list represents the list of
91
 
            messages for that archive.
 
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.
92
92
        """
93
 
        return ForkedFakeService(client.port, messages)
 
93
        return ForkedFakeService(client.port, message_archives)
94
94
 
95
95
    def is_ready(self):
96
96
        """Tell the parent process that the server is ready for writes."""
111
111
    def start_server(self):
112
112
        """Start the HTTP server."""
113
113
        service = HTTPServer(('', self.port), FakeGrackleRequestHandler)
114
 
        service.store = MemoryStore(self.messages)
115
 
        for archive_id, messages in service.store.messages.iteritems():
 
114
        service.store = MemoryStore(self.message_archives)
 
115
        for archive_id, messages in service.store.message_archives.iteritems():
116
116
            for message in messages:
117
117
                message.setdefault('headers', {})
118
118
        self.is_ready()
135
135
 
136
136
    def do_POST(self):
137
137
        """Create a message on POST."""
138
 
        message = self.rfile.read(int(self.headers['content-length']))
139
 
        if message == 'This is a message':
140
 
            self.send_response(httplib.CREATED)
141
 
            self.end_headers()
142
 
            self.wfile.close()
 
138
        scheme, netloc, path, params, query_string, fragments = (
 
139
            urlparse(self.path))
 
140
        parts = path.split('/')
 
141
        if parts[1] != 'archive':
 
142
            # This is an unknonwn operation?
 
143
            return
 
144
        if 'content-length' in self.headers:
 
145
            operation = 'put_message'
143
146
        else:
144
 
            self.send_error(httplib.BAD_REQUEST)
 
147
            operation = 'hide_message'
 
148
        if operation == 'put_message':
 
149
            message = self.rfile.read(int(self.headers['content-length']))
 
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)
 
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)
145
168
 
146
169
    def do_GET(self):
147
170
        """Retrieve a list of messages on GET."""
171
194
 
172
195
    def test_put_message(self):
173
196
        client = GrackleClient('localhost', 8420)
174
 
        with ForkedFakeService.from_client(client):
175
 
            client.put_message('arch1', 'asdf', StringIO('This is a message'))
 
197
        message_archives = {'arch1': []}
 
198
        with ForkedFakeService.from_client(client, message_archives):
 
199
            client.put_message('arch1', 'id1', StringIO('This is a message'))
 
200
            response = client.get_messages('arch1')
 
201
        self.assertEqual(1, len(response['messages']))
 
202
        message = response['messages'][0]
 
203
        self.assertEqual('id1', message['message_id'])
 
204
 
 
205
    def test_put_message_without_archive(self):
 
206
        client = GrackleClient('localhost', 8421)
 
207
        message_archives = {'arch1': []}
 
208
        with ForkedFakeService.from_client(client, message_archives):
176
209
            with ExpectedException(Exception, 'wtf'):
177
 
                client.put_message('arch1', 'asdf',
178
 
                    StringIO('This is not a message'))
 
210
                client.put_message('no-archive', 'id1', StringIO('message'))
179
211
 
180
212
 
181
213
class TestGetMessages(TestCase):
222
254
 
223
255
    def get_messages_member_order_test(self, key):
224
256
        client = GrackleClient('localhost', 8439)
 
257
        if key == 'author':
 
258
            header_name = 'from'
 
259
        else:
 
260
            header_name = key
225
261
        archive = {
226
262
            'baz': [
227
 
                make_message('foo', headers={key: '2011-03-25'}),
228
 
                make_message('bar', headers={key: '2011-03-24'}),
 
263
                make_message('foo', headers={header_name: '2011-03-25'}),
 
264
                make_message('bar', headers={header_name: '2011-03-24'}),
229
265
             ]}
230
266
        with ForkedFakeService.from_client(client, archive):
231
267
            response = client.get_messages('baz')
378
414
        first_message = response['messages'][0]
379
415
        self.assertEqual('foo', first_message['message_id'])
380
416
        self.assertEqual(
381
 
            {'From': 'me', 'Message-Id': 'foo', 'To': 'you'},
382
 
            first_message['headers'])
 
417
            archive['baz'][0]['headers'], first_message['headers'])
383
418
        self.assertNotIn('body', first_message)
384
419
 
385
420
    def test_display_type_text_only(self):
396
431
        self.assertEqual('foo', first_message['message_id'])
397
432
        self.assertEqual('me', first_message['headers']['From'])
398
433
        self.assertEqual('you', first_message['headers']['To'])
399
 
        self.assertEqual('abcdefghi', first_message['body'])
 
434
        self.assertEqual(archive['baz'][0]['body'], first_message['body'])
400
435
 
401
436
    def test_display_type_all(self):
402
437
        client = GrackleClient('localhost', 8447)
412
447
        self.assertEqual('foo', first_message['message_id'])
413
448
        self.assertEqual('me', first_message['headers']['From'])
414
449
        self.assertEqual('you', first_message['headers']['To'])
415
 
        self.assertEqual(
416
 
            'abcdefghi\n\nattactment data.', first_message['body'])
 
450
        self.assertEqual(archive['baz'][0]['body'], first_message['body'])
417
451
 
418
452
    def test_date_range(self):
419
453
        client = GrackleClient('localhost', 8448)
456
490
        with ForkedFakeService.from_client(client, archive):
457
491
            with ExpectedException(UnparsableDateRange, ''):
458
492
                client.get_messages('baz', date_range='2012-01..12-02..12-03')
 
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'])