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

« back to all changes in this revision

Viewing changes to grackle/tests/test_client.py

  • Committer: Curtis Hovey
  • Date: 2012-03-16 20:41:54 UTC
  • mto: This revision was merged to the branch mainline in revision 45.
  • Revision ID: curtis.hovey@canonical.com-20120316204154-nz50ae66odaqvnb4
Remove hack now that the tests use a helper that makes real messages.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
from BaseHTTPServer import (
 
2
    HTTPServer,
 
3
    BaseHTTPRequestHandler,
 
4
    )
1
5
from email.message import Message
2
6
from email.mime.multipart import MIMEMultipart
3
7
from email.mime.text import MIMEText
 
8
import httplib
 
9
import logging
 
10
import os
 
11
from signal import SIGKILL
 
12
import simplejson
4
13
from StringIO import StringIO
 
14
import sys
5
15
from unittest import TestCase
 
16
from urlparse import urlparse
6
17
 
7
18
from testtools import ExpectedException
8
19
 
13
24
    UnsupportedDisplayType,
14
25
    UnsupportedOrder,
15
26
    )
16
 
from grackle.service import ForkedFakeService
17
27
from grackle.store import (
18
28
    make_json_message,
 
29
    MemoryStore,
19
30
    )
20
31
 
21
32
 
50
61
    return make_message(message_id, parts.as_string(), headers, hidden)
51
62
 
52
63
 
 
64
class ForkedFakeService:
 
65
    """A Grackle service fake, as a ContextManager."""
 
66
 
 
67
    def __init__(self, port, message_archives=None, write_logs=False):
 
68
        """Constructor.
 
69
 
 
70
        :param port: The tcp port to use.
 
71
        :param message_archives: A dict of lists of dicts representing
 
72
            archives of messages. The outer dict represents the archive,
 
73
            the list represents the list of messages for that archive.
 
74
        :param write_logs: If true, log messages will be written to stdout.
 
75
        """
 
76
        self.pid = None
 
77
        self.port = port
 
78
        if message_archives is None:
 
79
            self.message_archives = {}
 
80
        else:
 
81
            self.message_archives = message_archives
 
82
        self.read_end, self.write_end = os.pipe()
 
83
        self.write_logs = write_logs
 
84
 
 
85
    @staticmethod
 
86
    def from_client(client, message_archives=None):
 
87
        """Instantiate a ForkedFakeService from the client.
 
88
 
 
89
        :param port: The client to provide service for.
 
90
        :param message_archives: A dict of lists of dicts representing
 
91
            archives of messages. The outer dict represents the archive,
 
92
            the list represents the list of messages for that archive.
 
93
        """
 
94
        return ForkedFakeService(client.port, message_archives)
 
95
 
 
96
    def is_ready(self):
 
97
        """Tell the parent process that the server is ready for writes."""
 
98
        os.write(self.write_end, 'asdf')
 
99
 
 
100
    def __enter__(self):
 
101
        """Run the service.
 
102
 
 
103
        Fork and start a server in the child.  Return when the server is ready
 
104
        for use."""
 
105
        pid = os.fork()
 
106
        if pid == 0:
 
107
            self.start_server()
 
108
        self.pid = pid
 
109
        os.read(self.read_end, 1)
 
110
        return
 
111
 
 
112
    def start_server(self):
 
113
        """Start the HTTP server."""
 
114
        service = HTTPServer(('', self.port), FakeGrackleRequestHandler)
 
115
        service.store = MemoryStore(self.message_archives)
 
116
        self.is_ready()
 
117
        if self.write_logs:
 
118
            logging.basicConfig(
 
119
                stream=sys.stderr, level=logging.INFO)
 
120
        service.serve_forever()
 
121
 
 
122
    def __exit__(self, exc_type, exc_val, traceback):
 
123
        os.kill(self.pid, SIGKILL)
 
124
 
 
125
 
 
126
class FakeGrackleRequestHandler(BaseHTTPRequestHandler):
 
127
    """A request handler that forwards to server.store."""
 
128
 
 
129
    def __init__(self, *args, **kwargs):
 
130
        """Constructor.  Sets up logging."""
 
131
        self.logger = logging.getLogger('http')
 
132
        BaseHTTPRequestHandler.__init__(self, *args, **kwargs)
 
133
 
 
134
    def do_PUT(self):
 
135
        """Create an archive or message on PUT."""
 
136
        scheme, netloc, path, params, query_string, fragments = (
 
137
            urlparse(self.path))
 
138
        parts = path.split('/')
 
139
        if parts[1] != 'archive':
 
140
            # This is an unknonwn operation?
 
141
            return
 
142
        if len(parts) == 3:
 
143
            # This expected path is /archive/archive_id.
 
144
            try:
 
145
                self.server.store.put_archive(parts[2])
 
146
                self.send_response(httplib.CREATED)
 
147
                self.end_headers()
 
148
                self.wfile.close()
 
149
            except Exception, error:
 
150
                self.send_response(
 
151
                    httplib.BAD_REQUEST, error.__doc__)
 
152
        if len(parts) == 4:
 
153
            # This expected path is /archive/archive_id/message_id.
 
154
            try:
 
155
                message = self.rfile.read(int(self.headers['content-length']))
 
156
                self.server.store.put_message(parts[2], parts[3], message)
 
157
                self.send_response(httplib.CREATED)
 
158
                self.end_headers()
 
159
                self.wfile.close()
 
160
            except:
 
161
                self.send_error(httplib.BAD_REQUEST)
 
162
 
 
163
    def do_POST(self):
 
164
        """Change a message on POST."""
 
165
        scheme, netloc, path, params, query_string, fragments = (
 
166
            urlparse(self.path))
 
167
        parts = path.split('/')
 
168
        if parts[1] != 'archive':
 
169
            # This is an unknonwn operation?
 
170
            return
 
171
        if len(parts) == 4:
 
172
            # This expected path is /archive/archive_id/message_id.
 
173
            try:
 
174
                # This expected path is /archive/archive_id/message_id.
 
175
                response = self.server.store.hide_message(
 
176
                    parts[2], parts[3], query_string)
 
177
                self.send_response(httplib.OK)
 
178
                self.end_headers()
 
179
                self.wfile.write(simplejson.dumps(response))
 
180
            except:
 
181
                self.send_error(httplib.BAD_REQUEST)
 
182
 
 
183
    def do_GET(self):
 
184
        """Retrieve a list of messages on GET."""
 
185
        scheme, netloc, path, params, query_string, fragments = (
 
186
            urlparse(self.path))
 
187
        parts = path.split('/')
 
188
        if parts[1] == 'archive':
 
189
            try:
 
190
                response = self.server.store.get_messages(
 
191
                    parts[2], query_string)
 
192
                self.send_response(httplib.OK)
 
193
                self.end_headers()
 
194
                self.wfile.write(simplejson.dumps(response))
 
195
            except Exception, error:
 
196
                self.send_response(
 
197
                    httplib.BAD_REQUEST, error.__doc__)
 
198
                return
 
199
 
 
200
    def log_message(self, format, *args):
 
201
        """Override log_message to use standard Python logging."""
 
202
        message = "%s - - [%s] %s\n" % (
 
203
            self.address_string(), self.log_date_time_string(), format % args)
 
204
        self.logger.info(message)
 
205
 
 
206
 
53
207
class TestPutArchive(TestCase):
54
208
 
55
209
    def test_put_archive(self):