~didrocks/unity/altf10

« back to all changes in this revision

Viewing changes to grackle/tests/test_client.py

  • Committer: Curtis Hovey
  • Date: 2012-03-17 21:01:26 UTC
  • Revision ID: curtis.hovey@canonical.com-20120317210126-tx0p2lg8qr1ch172
Remove old http request handler and fake service.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
from BaseHTTPServer import (
2
 
    HTTPServer,
3
 
    BaseHTTPRequestHandler,
4
 
    )
5
1
from email.message import Message
6
2
from email.mime.multipart import MIMEMultipart
7
3
from email.mime.text import MIMEText
8
 
import httplib
9
 
import logging
10
 
import os
11
 
from signal import SIGKILL
12
 
import simplejson
13
4
from StringIO import StringIO
14
 
import sys
15
5
from unittest import TestCase
16
 
from urlparse import urlparse
17
6
 
18
7
from testtools import ExpectedException
19
8
 
20
 
from grackle.client import (
21
 
    GrackleClient,
 
9
from grackle.client import GrackleClient
 
10
from grackle.error import (
 
11
    ArchiveIdExists,
22
12
    UnparsableDateRange,
23
13
    UnsupportedDisplayType,
24
14
    UnsupportedOrder,
25
15
    )
 
16
from grackle.service import ForkedFakeService
26
17
from grackle.store import (
27
18
    make_json_message,
28
 
    MemoryStore,
29
19
    )
30
20
 
31
21
 
60
50
    return make_message(message_id, parts.as_string(), headers, hidden)
61
51
 
62
52
 
63
 
class ForkedFakeService:
64
 
    """A Grackle service fake, as a ContextManager."""
65
 
 
66
 
    def __init__(self, port, message_archives=None, write_logs=False):
67
 
        """Constructor.
68
 
 
69
 
        :param port: The tcp port to use.
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
 
        :param write_logs: If true, log messages will be written to stdout.
74
 
        """
75
 
        self.pid = None
76
 
        self.port = port
77
 
        if message_archives is None:
78
 
            self.message_archives = {}
79
 
        else:
80
 
            self.message_archives = message_archives
81
 
        self.read_end, self.write_end = os.pipe()
82
 
        self.write_logs = write_logs
83
 
 
84
 
    @staticmethod
85
 
    def from_client(client, message_archives=None):
86
 
        """Instantiate a ForkedFakeService from the client.
87
 
 
88
 
        :param port: The client to provide service for.
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
 
        """
93
 
        return ForkedFakeService(client.port, message_archives)
94
 
 
95
 
    def is_ready(self):
96
 
        """Tell the parent process that the server is ready for writes."""
97
 
        os.write(self.write_end, 'asdf')
98
 
 
99
 
    def __enter__(self):
100
 
        """Run the service.
101
 
 
102
 
        Fork and start a server in the child.  Return when the server is ready
103
 
        for use."""
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):
112
 
        """Start the HTTP server."""
113
 
        service = HTTPServer(('', self.port), FakeGrackleRequestHandler)
114
 
        service.store = MemoryStore(self.message_archives)
115
 
        for archive_id, messages in service.store.message_archives.iteritems():
116
 
            for message in messages:
117
 
                message.setdefault('headers', {})
118
 
        self.is_ready()
119
 
        if self.write_logs:
120
 
            logging.basicConfig(
121
 
                stream=sys.stderr, level=logging.INFO)
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):
129
 
    """A request handler that forwards to server.store."""
130
 
 
131
 
    def __init__(self, *args, **kwargs):
132
 
        """Constructor.  Sets up logging."""
133
 
        self.logger = logging.getLogger('http')
134
 
        BaseHTTPRequestHandler.__init__(self, *args, **kwargs)
135
 
 
136
 
    def do_PUT(self):
137
 
        """Create an archive or message on PUT."""
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 len(parts) == 4:
145
 
            # This expected path is /archive/archive_id/message_id.
146
 
            try:
147
 
                message = self.rfile.read(int(self.headers['content-length']))
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)
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.
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)
174
 
 
175
 
    def do_GET(self):
176
 
        """Retrieve a list of messages on GET."""
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))
187
 
            except Exception, error:
188
 
                self.send_response(
189
 
                    httplib.BAD_REQUEST, error.__doc__)
190
 
                return
191
 
 
192
 
    def log_message(self, format, *args):
193
 
        """Override log_message to use standard Python logging."""
194
 
        message = "%s - - [%s] %s\n" % (
195
 
            self.address_string(), self.log_date_time_string(), format % args)
196
 
        self.logger.info(message)
 
53
class TestPutArchive(TestCase):
 
54
 
 
55
    def test_put_archive(self):
 
56
        client = GrackleClient('localhost', 8410)
 
57
        message_archives = {}
 
58
        with ForkedFakeService.from_client(client, message_archives):
 
59
            client.put_archive('arch1')
 
60
            response = client.get_messages('arch1')
 
61
        self.assertEqual(0, len(response['messages']))
 
62
 
 
63
    def test_put_archive_existing_archive(self):
 
64
        client = GrackleClient('localhost', 8411)
 
65
        message_archives = {'arch1': []}
 
66
        with ForkedFakeService.from_client(client, message_archives):
 
67
            with ExpectedException(ArchiveIdExists, ''):
 
68
                client.put_archive('arch1')
197
69
 
198
70
 
199
71
class TestPutMessage(TestCase):