------------------------------------------------------------
revno: 6726
committer: Barry Warsaw <[email protected]>
branch nick: rest
timestamp: Sun 2009-05-10 16:13:02 -0400
message:
More tests for the REST server, this time, for the queue runner.
Add logging to the RESTRunner.
Also, use pkg_resources.resource_stream() instead of .resource_string() where
appropriate.
Add a bunch of XXX comments for things I need to figure out about the Zope-ish
parts of the lazr.restful implementation. Change __getitem__() api to
_lookup().
added:
src/mailman/queue/docs/rest.txt
modified:
src/mailman/bin/qrunner.py
src/mailman/config/config.py
src/mailman/queue/rest.py
src/mailman/rest/configuration.py
src/mailman/rest/urls.py
src/mailman/testing/helpers.py
=== modified file 'src/mailman/bin/qrunner.py'
--- src/mailman/bin/qrunner.py 2009-05-03 19:35:29 +0000
+++ src/mailman/bin/qrunner.py 2009-05-10 20:13:02 +0000
@@ -214,7 +214,7 @@
print _('$name runs $classname')
sys.exit(0)
- # Fast track for one infinite runner
+ # Fast track for one infinite runner.
if len(options.options.runners) == 1 and not options.options.once:
qrunner = make_qrunner(*options.options.runners[0])
class Loop:
@@ -233,7 +233,7 @@
qrunner.run()
log.info('%s qrunner exiting.', loop.name())
else:
- # Anything else we have to handle a bit more specially
+ # Anything else we have to handle a bit more specially.
qrunners = []
for runner, rslice, rrange in options.options.runners:
qrunner = make_qrunner(runner, rslice, rrange, once=True)
=== modified file 'src/mailman/config/config.py'
--- src/mailman/config/config.py 2009-02-13 01:36:21 +0000
+++ src/mailman/config/config.py 2009-05-10 20:13:02 +0000
@@ -30,9 +30,8 @@
import errno
import logging
-from StringIO import StringIO
from lazr.config import ConfigSchema, as_boolean
-from pkg_resources import resource_string
+from pkg_resources import resource_stream
from mailman import version
from mailman.core import errors
@@ -76,17 +75,24 @@
def load(self, filename=None):
"""Load the configuration from the schema and config files."""
- schema_string = resource_string('mailman.config', 'schema.cfg')
- schema = ConfigSchema('schema.cfg', StringIO(schema_string))
- # If a configuration file was given, load it now too. First, load the
- # absolute minimum default configuration, then if a configuration
- # filename was given by the user, push it.
- config_string = resource_string('mailman.config', 'mailman.cfg')
- self._config = schema.loadFile(StringIO(config_string), 'mailman.cfg')
- if filename is not None:
- self.filename = filename
- with open(filename) as user_config:
- self._config.push(filename, user_config.read())
+ schema_file = config_file = None
+ try:
+ schema_file = resource_stream('mailman.config', 'schema.cfg')
+ schema = ConfigSchema('schema.cfg', schema_file)
+ # If a configuration file was given, load it now too. First, load
+ # the absolute minimum default configuration, then if a
+ # configuration filename was given by the user, push it.
+ config_file = resource_stream('mailman.config', 'mailman.cfg')
+ self._config = schema.loadFile(config_file, 'mailman.cfg')
+ if filename is not None:
+ self.filename = filename
+ with open(filename) as user_config:
+ self._config.push(filename, user_config.read())
+ finally:
+ if schema_file:
+ schema_file.close()
+ if config_file:
+ config_file.close()
self._post_process()
def push(self, config_name, config_string):
=== added file 'src/mailman/queue/docs/rest.txt'
--- src/mailman/queue/docs/rest.txt 1970-01-01 00:00:00 +0000
+++ src/mailman/queue/docs/rest.txt 2009-05-10 20:13:02 +0000
@@ -0,0 +1,23 @@
+REST server
+===========
+
+Mailman is controllable through an administrative RESTful HTTP server.
+
+ >>> from mailman.testing import helpers
+ >>> master = helpers.TestableMaster(helpers.wait_for_webservice)
+ >>> master.start('rest')
+
+The RESTful server can be used to access basic version information.
+
+ >>> dump_json('http://localhost:8001/3.0/system')
+ http_etag: "..."
+ mailman_version: GNU Mailman 3.0... (...)
+ python_version: ...
+ resource_type_link: https://localhost:8001/3.0/#system
+ self_link: https://localhost:8001/3.0/system
+
+
+Clean up
+--------
+
+ >>> master.stop()
=== modified file 'src/mailman/queue/rest.py'
--- src/mailman/queue/rest.py 2009-05-07 02:07:35 +0000
+++ src/mailman/queue/rest.py 2009-05-10 20:13:02 +0000
@@ -35,15 +35,21 @@
from mailman.rest.webservice import make_server
+log = logging.getLogger('mailman.http')
+
+
class RESTRunner(Runner):
def run(self):
+ log.info('Starting REST server')
try:
make_server().serve_forever()
except KeyboardInterrupt:
+ log.info('REST server interrupted')
sys.exit(signal.SIGTERM)
except select.error as (errcode, message):
if errcode == errno.EINTR:
+ log.info('REST server exiting')
sys.exit(signal.SIGTERM)
raise
except:
=== modified file 'src/mailman/rest/configuration.py'
--- src/mailman/rest/configuration.py 2009-05-02 22:07:38 +0000
+++ src/mailman/rest/configuration.py 2009-05-10 20:13:02 +0000
@@ -63,6 +63,7 @@
default_batch_size = 50
max_batch_size = 300
+ # XXX What's this for?
def createRequest(self, body_instream, environ):
"""See `IWebServiceConfiguration`."""
request = AdminWebServiceRequest(body_instream, environ)
=== modified file 'src/mailman/rest/urls.py'
--- src/mailman/rest/urls.py 2009-05-04 15:33:10 +0000
+++ src/mailman/rest/urls.py 2009-05-10 20:13:02 +0000
@@ -45,6 +45,7 @@
"""Initialize with respect to a context and request."""
self.context = context
self.request = request
+ # XXX Is this strictly necessary?
self.webservice_config = AdminWebServiceConfiguration()
self.version = self.webservice_config.service_version_uri_prefix
self.schema = ('https' if self.webservice_config.use_https else 'http')
@@ -53,13 +54,14 @@
def __str__(self):
"""Return the semi-hard-coded URL to the service root."""
- path = self[self.context]
+ path = self._lookup(self.context)
return '{0.schema}://{0.hostname}:{0.port}/{0.version}/{1}'.format(
self, path)
+ # XXX Is this strictly necessary?
__call__ = __str__
- def __getitem__(self, ob):
+ def _lookup(self, ob):
"""Return the path component for the object.
:param ob: The object we're looking for.
=== modified file 'src/mailman/testing/helpers.py'
--- src/mailman/testing/helpers.py 2009-03-06 00:25:34 +0000
+++ src/mailman/testing/helpers.py 2009-05-10 20:13:02 +0000
@@ -26,6 +26,7 @@
'get_lmtp_client',
'get_queue_messages',
'make_testable_runner',
+ 'wait_for_webservice',
]
@@ -122,9 +123,18 @@
class TestableMaster(Master):
"""A testable master loop watcher."""
- def __init__(self):
+ def __init__(self, start_check=None):
+ """Create a testable master loop watcher.
+
+ :param start_check: Optional callable used to check whether everything
+ is running as the test expects. Called in `loop()` in the
+ subthread before the event is set. The callback should block
+ until the pass condition is set.
+ :type start_check: Callable taking no arguments, returning nothing.
+ """
super(TestableMaster, self).__init__(
restartable=False, config_file=config.filename)
+ self.start_check = start_check
self.event = threading.Event()
self.thread = threading.Thread(target=self.loop)
self._started_kids = None
@@ -159,6 +169,9 @@
# Keeping a copy of all the started child processes for use by the
# testing environment, even after all have exited.
self._started_kids = set(self._kids)
+ # If there are extra conditions to check, do it now.
+ if self.start_check is not None:
+ self.start_check()
# Let the blocking thread know everything's running.
self.event.set()
super(TestableMaster, self).loop()
@@ -255,3 +268,17 @@
raise
else:
raise RuntimeError('Connection refused')
+
+
+
+def wait_for_webservice():
+ """Wait for the REST server to start serving requests."""
+ # Time out after approximately 3 seconds.
+ for count in range(30):
+ try:
+ socket.socket().connect((config.webservice.hostname,
+ int(config.webservice.port)))
+ except socket.error:
+ time.sleep(0.1)
+ else:
+ break
--
Primary development focus
https://code.launchpad.net/~mailman-coders/mailman/3.0
Your team Mailman Checkins is subscribed to branch lp:mailman.
To unsubscribe from this branch go to
https://code.launchpad.net/~mailman-coders/mailman/3.0/+edit-subscription.
_______________________________________________
Mailman-checkins mailing list
[email protected]
Unsubscribe:
http://mail.python.org/mailman/options/mailman-checkins/archive%40jab.org