Rev 31: Add lighttpd-dav. Make the lighttpd start detection more robust. in http://bazaar.launchpad.net/%7Evila/bzr/local-test-server

Vincent Ladeuil v.ladeuil+lp at free.fr
Sat Jun 7 14:51:52 BST 2008


At http://bazaar.launchpad.net/%7Evila/bzr/local-test-server

------------------------------------------------------------
revno: 31
revision-id: v.ladeuil+lp at free.fr-20080607135150-q54tpjz6vxloydd2
parent: v.ladeuil+lp at free.fr-20080605074333-e7mhc533cplu1a9i
committer: Vincent Ladeuil <v.ladeuil+lp at free.fr>
branch nick: local_test_server
timestamp: Sat 2008-06-07 15:51:50 +0200
message:
  Add lighttpd-dav. Make the lighttpd start detection more robust.
  
  * tests/test_utils.py:
  (ServerAdapter.__init__): Add lighttpd-dav.
  
  * test_server.py:
  (LighttpdDAVFeature): New class.
  (LighttpdDAV): New class.
  
  * server.py:
  (Server.start): Delete the previous log file, if any, when
  starting.
  (Server._get_log_content, Server._print_error_log,
  Server._find_in_log): Move more previously apache2 specific
  methods in Server.
  (Lighttpd._start): When errors occurs at start, the only reliable
  way to detect server start (or not) is polling the log file. Since
  this can be a bit fragile, we do that in addition to detecting the
  pid file creation.
  (Lighttpd._wait_for_server_start_in_log): Search for a predefined
  regexp, taken into account that the log file may not  yet exist.
  (LighttpdDAV): New class.
  
  * configs/lighttpd-dav.conf: 
  New file.
  
  * configs/apache2-dav.conf: 
  (DAVLockDB): Oops, put that under var_lock_dir, not www_dir.
  
  * config.py:
  (LighttpdDAV): New class.
added:
  configs/lighttpd-dav.conf      lighttpddav.conf-20080606163133-imyg87zvcmugxs4p-1
modified:
  TODO                           todo-20080526134120-eibvvebw74t8j2xh-1
  config.py                      __init__.py-20080523170713-0c8mnxio9r41iyhk-1
  configs/apache2-dav.conf       apache2dav.conf-20080604211810-6j1dwqo255dl2bc6-1
  server.py                      server.py-20080524160639-rqhbexqatjqbwypw-1
  test_server.py                 test_server.py-20080530070615-f555godexnk7frms-1
  tests/test_utils.py            test_utils.py-20080603162150-w01001l902j0gu95-1
-------------- next part --------------
=== modified file 'TODO'
--- a/TODO	2008-06-05 07:43:33 +0000
+++ b/TODO	2008-06-07 13:51:50 +0000
@@ -18,10 +18,15 @@
 ** give better error messages for wrongly written config files
    (in expand, apache itself gives meaningul lines numbers)
 
+* tests/test_utils.py
+
+** get rid of the adapter class
+
+** look at creating matryoshka doll dicts (test_server (feature
+   (server (config)))) since we use always the same scenario key but with
+   dicts containing more items.
+
 * add support for
 
-** webdav (for all supporting servers, preferably by using
-   dedicated servers)
-
 ** https (for all supporting servers, preferably by using
    dedicated servers)

=== modified file 'config.py'
--- a/config.py	2008-06-05 07:43:33 +0000
+++ b/config.py	2008-06-07 13:51:50 +0000
@@ -131,3 +131,13 @@
     def __init__(self, _base_dir=None):
         super(Lighttpd, self).__init__('lighttpd',
                                       _base_dir=_base_dir)
+
+
+class LighttpdDAV(Lighttpd):
+
+    def __init__(self, _base_dir=None):
+        # FIXME: jumping over Lighttpd >-/
+        Config.__init__(self, 'lighttpd-dav',
+                        _base_dir=_base_dir)
+
+

=== modified file 'configs/apache2-dav.conf'
--- a/configs/apache2-dav.conf	2008-06-05 07:43:33 +0000
+++ b/configs/apache2-dav.conf	2008-06-07 13:51:50 +0000
@@ -47,7 +47,7 @@
 LoadModule dav_module /usr/lib/apache2/modules/mod_dav.so
 LoadModule dav_fs_module /usr/lib/apache2/modules/mod_dav_fs.so
 
-DAVLockDB %(www_dir)s/DAVLock
+DAVLockDB %(var_lock_dir)s/DAVLock
 <Directory %(www_dir)s>
 	DAV On
 	# DirectorySlash tells apache to reply with redirections if

=== added file 'configs/lighttpd-dav.conf'
--- a/configs/lighttpd-dav.conf	1970-01-01 00:00:00 +0000
+++ b/configs/lighttpd-dav.conf	2008-06-07 13:51:50 +0000
@@ -0,0 +1,37 @@
+#
+# Based on /etc/lighttpd/lighttpd.conf in Ubuntu Gusty
+#
+# Debian lighttpd configuration file
+# 
+
+server.modules              = ( 
+            "mod_accesslog",
+)
+
+## where to send error-messages to
+server.errorlog            = "%(log_file)s"
+accesslog.filename         = "%(var_log_dir)s/access.log"
+
+## bind to port (default: 80)
+server.port               = %(port)s
+
+## bind to localhost only (default: all interfaces)
+server.bind                = "%(host)s"
+
+server.pid-file            = "%(pid_file)s"
+
+# Tests will create symlinks in that directory to point to the
+# appropriate location
+server.document-root       = "%(www_dir)s"
+
+# required for
+#bzrlib.tests.test_transport_implementations.TransportTests.test_has_root_works
+dir-listing.activate = "enable"
+
+server.modules += ( "mod_webdav" )
+
+## The full path to the file you would like to use as your db file.  This
+## is required for webdav props and locks.
+webdav.sqlite-db-name = "%(var_run_dir)s/webdav_lock.db"
+
+webdav.activate = "enable"

=== modified file 'server.py'
--- a/server.py	2008-06-05 07:43:33 +0000
+++ b/server.py	2008-06-07 13:51:50 +0000
@@ -114,6 +114,11 @@
         finally:
             infile.close()
             outfile.close()
+        # Some servers *requires* the log file to be empty to reliably detect
+        # starting or stopping. Having only the last server session in the log
+        # doesn't seem a bad idea either for a test server. So all servers
+        # start with a fresh log.
+        self._delete_log_file()
         # Delegate the real start to daughter classes
         self._start()
 
@@ -195,7 +200,7 @@
 
         fibo = fibonacci()
         wait_time = fibo.next() # 0 ;-) Just to initialize the generator
-        waited = 0
+        waited = 0.0
         while waited < delay:
             if verified():
                 return True
@@ -241,10 +246,49 @@
             if pid is None:
                 return True
             else:
-                return self._kill_server_with_SIGTERM(pid)
+                killed = self._kill_server_with_SIGTERM(pid)
+                return killed
 
         return self._hk_poll(server_is_dead, interval=500.0)
 
+    def _get_log_content(self):
+        return self._get_file_content(self.get_config_value('log_file'))
+
+    def _print_error_log(self, when):
+        print '%s error.log is: [' % when,
+        print self._get_log_content(),
+        print ']'
+
+    def _find_in_log(self, expected):
+        """Search a regexp in a log file.
+
+        :param expected: The searched for regexp
+
+        :returns: True if one line matches the regexp, False otherwise.
+
+        Soem servers returns early when started (or stopped thru specialized
+        commands, apache2 for one). This doesn't guarantee that the server is
+        started/stopped. We need to rely on some predefined patterns to appear
+        in the log file. Hackish :-( This also impose deleting the log file
+        before attempting to start the server.
+        """
+        log_file_path = self.get_config_value('log_file')
+        try:
+            f = open(log_file_path)
+        except IOError, e:
+            if e.errno == errno.ENOENT:
+                raise errors.NoSuchFile(log_file_path)
+            else:
+                raise
+        try:
+            for line in f:
+                if expected.search(line) is not None:
+                    return True
+        finally:
+            f.close()
+
+        return False
+
 
 class Apache2(Server):
 
@@ -261,7 +305,6 @@
         self.output_config_path = self.config.abspath('etc/apache2.conf')
 
     def _start(self):
-        self._delete_log_file()
         try:
             subprocess.check_call(['apache2', '-k', 'start',
                                    '-f', self.output_config_path])
@@ -281,34 +324,6 @@
         except subprocess.CalledProcessError, e:
             raise LTSCantStopError(self, extra=e)
 
-    def _find_in_log(self, expected):
-        """Search a regexp in a log file.
-
-        :param expected: The searched for regexp
-
-        :returns: True if one line matches the regexp, False otherwise.
-
-        apache2 returns early when running the '-k [start|stop]' command. This
-        doesn't guarantee that the server is started/stopped. We need to rely
-        on some predefined patterns to appear in the log file. Hackish :-(
-        """
-        log_file_path = self.get_config_value('log_file')
-        try:
-            f = open(log_file_path)
-        except IOError, e:
-            if e.errno == errno.ENOENT:
-                raise errors.NoSuchFile(log_file_path)
-            else:
-                raise
-        try:
-            for line in f:
-                if expected.search(line) is not None:
-                    return True
-        finally:
-            f.close()
-
-        return False
-
     def _wait_for_server_start_in_log(self):
         """Reliably check that the server is started.
 
@@ -336,13 +351,6 @@
                 return True
         return self._hk_poll(apache2_stopped, interval=50.0)
 
-    def _get_log_content(self):
-        return self._get_file_content(self.get_config_value('log_file'))
-
-    def _print_error_log(self, when):
-        print '%s error.log is:' % when
-        print self._get_log_content()
-
 
 class Apache2DAV(Apache2):
 
@@ -363,7 +371,6 @@
         self.output_config_path = self.config.abspath('etc/cherokee.conf')
 
     def _start(self):
-        self._delete_log_file()
         try:
             subprocess.check_call(['cherokee', '-b',
                                    '-C', self.output_config_path])
@@ -383,6 +390,8 @@
 
 class Lighttpd(Server):
 
+    _started_re = re.compile("server started $") # Note the final space...
+
     def __init__(self, port, _conf=None):
         if _conf is None:
             _conf = config.Lighttpd()
@@ -391,20 +400,53 @@
         self.output_config_path = self.config.abspath('etc/cherokee.conf')
 
     def _start(self):
-        self._delete_log_file()
         try:
             subprocess.check_call(['lighttpd', '-f', self.output_config_path])
         except subprocess.CalledProcessError, e:
             raise LTSCantStartError(self, extra=e)
+        # Since lighttpd deamonize itself early, the return code is useless,
+        # most starting errors happening after the fork. Resort to log polling
+        # for lack of better means :-/
+        if not self._wait_for_server_start_in_log():
+            raise LTSCantStartError(self, extra='logfile contains no start')
+        #  We continue to require that the pid file be created though.
         if not self._wait_for_pidfile_to_be_created():
             raise LTSCantStartError(
                 self, extra='Did not create pid file %s'
                 % self.get_config_value('pid_file'))
 
+
     def _stop(self):
         if not self._wait_for_server_process_death():
             raise LTSCantStopError(self)
 
+    def _wait_for_server_start_in_log(self):
+        """Reliably check that the server is started.
+
+        Since lighttpd deamonize itself early, the return code of the starting
+        command is useless, most starting errors happening after the fork. We
+        need to poll the logfile content for a predefined regexp to reliably
+        detect the start without errors.
+        """
+        def server_started():
+            try:
+                found = self._find_in_log(self._started_re)
+            except errors.NoSuchFile:
+                # Wee, the log file is not yet created, wait a bit
+                return False
+            return found
+        return self._hk_poll(server_started)
+
+
+class LighttpdDAV(Lighttpd):
+
+    def __init__(self, port, _conf=None):
+        if _conf is None:
+            _conf = config.LighttpdDAV()
+        super(LighttpdDAV, self).__init__(port, _conf=_conf)
+        self.output_config_path = self.config.abspath('etc/lighttpd-dav.conf')
+
+
 
 _next_available_port = 49000
 _max_available_port = 49151
@@ -438,6 +480,7 @@
                 lighttpd=Lighttpd(37002),
                 )
 _servers['apache2-dav']=Apache2DAV(37003)
+_servers['lighttpd-dav']=LighttpdDAV(37004)
 
 def get_server(name):
     return _servers.get(name, None)

=== modified file 'test_server.py'
--- a/test_server.py	2008-06-05 07:43:33 +0000
+++ b/test_server.py	2008-06-07 13:51:50 +0000
@@ -75,6 +75,11 @@
     _server_name = 'lighttpd'
 
 
+class LighttpdDAVFeature(LocalTestServerFeature):
+
+    _server_name = 'lighttpd-dav'
+
+
 class LocalHTTPTestServer(transport.Server):
 
     # Must be set by daughter classes
@@ -194,6 +199,12 @@
     _url_protocol = 'http+pycurl'
 
 
+class LighttpdDAV(Lighttpd):
+
+    _server_name = 'lighttpd-dav'
+    _url_protocol = 'http+webdav'
+
+
 # We have registered a transport for the purpose of adding new servers in the
 # test permutations. Registering a transport makes our module appears in the
 # list which is queried for a get_test_permutations function.
@@ -232,5 +243,7 @@
     if webdav_present:
         if Apache2DAVFeature().available():
             permutations.append((webdav.HttpDavTransport, Apache2DAV))
+        if LighttpdDAVFeature().available():
+            permutations.append((webdav.HttpDavTransport, LighttpdDAV))
 
     return permutations

=== modified file 'tests/test_utils.py'
--- a/tests/test_utils.py	2008-06-05 07:43:33 +0000
+++ b/tests/test_utils.py	2008-06-07 13:51:50 +0000
@@ -95,6 +95,13 @@
                     _server_feature_class=test_server.LighttpdFeature,
                     _test_server_class=test_server.Lighttpd,
                     )),
+            ('lighttpd-dav', dict(
+                    _server_name='lighttpd-dav',
+                    _config_class=config.LighttpdDAV,
+                    _server_class=server.LighttpdDAV,
+                    _server_feature_class=test_server.LighttpdDAVFeature,
+                    _test_server_class=test_server.LighttpdDAV,
+                    )),
             ]
         self.scenarios = server_scenarios
 



More information about the bazaar-commits mailing list