------------------------------------------------------------
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

Reply via email to