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