Rev 3: Diry commit. This is not going as it should *at all*. But it kinda works. in file:///v/home/vila/.bazaar/plugins/local_test_server/

Vincent Ladeuil v.ladeuil+lp at free.fr
Mon May 26 20:42:08 BST 2008


At file:///v/home/vila/.bazaar/plugins/local_test_server/

------------------------------------------------------------
revno: 3
revision-id: v.ladeuil+lp at free.fr-20080526194208-9eqqggi0hi421yg0
parent: v.ladeuil+lp at free.fr-20080523171036-0oimydn77kxknddm
committer: Vincent Ladeuil <v.ladeuil+lp at free.fr>
branch nick: local_test_server
timestamp: Mon 2008-05-26 21:42:08 +0200
message:
  Diry commit. This is not going as it should *at all*. But it kinda works.
added:
  TODO                           todo-20080526134120-eibvvebw74t8j2xh-1
  commands.py                    commands.py-20080524160638-76gsirgigzamza15-1
  server.py                      server.py-20080524160639-rqhbexqatjqbwypw-1
  tests/test_commands.py         test_commands.py-20080524160640-bfduau8g3hsg83sa-1
  tests/test_server.py           test_server.py-20080524160641-lco15o23ub9mac33-1
renamed:
  configs/__init__.py => config.py __init__.py-20080523170713-0c8mnxio9r41iyhk-1
modified:
  __init__.py                    __init__.py-20080521133755-h9wimitytocyyxyv-1
  configs/apache2.conf           apache2.conf-20080522095851-6eixwo2qv9brec67-1
  tests/__init__.py              __init__.py-20080522095852-86lozt5jrpmajiqg-1
  tests/test_config.py           test_config.py-20080523170715-clr6vz0qdzefftob-1
  config.py                      __init__.py-20080523170713-0c8mnxio9r41iyhk-1
-------------- next part --------------
=== added file 'TODO'
--- a/TODO	1970-01-01 00:00:00 +0000
+++ b/TODO	2008-05-26 19:42:08 +0000
@@ -0,0 +1,15 @@
+* server.py
+
+- test stop
+
+- create a hierarchy by server at start time (making more obvious
+  what server is used and the requirements for each server)
+
+- make port a constructor parameter
+
+- make tests use different ports or the servers will not be
+   usable during selftest (doh !).
+
+* create a bzrlib.tests.Feature by server
+
+* plug the server if the corresponding feature is available.
\ No newline at end of file

=== modified file '__init__.py'
--- a/__init__.py	2008-05-23 17:10:36 +0000
+++ b/__init__.py	2008-05-26 19:42:08 +0000
@@ -69,24 +69,8 @@
     osutils,
     )
 
-# Directory containing all server configuration files
-base_dir = osutils.dirname(osutils.realpath(__file__))
-
-def get_lts_path(name, subdirs=None, mod=None):
-    """Build and return a path in the local_test_server hierarchy."""
-    if mod is None:
-        mod = osutils.dirname(osutils.realpath(__file__))
-    if subdirs is not None:
-        mod = osutils.pathjoin(mod, *subdirs)
-    return osutils.pathjoin(mod, name)
-
-
-etc_dir = get_lts_path('etc')
-
-# Run-time directories
-var_dir = get_lts_path('var')
-var_run_dir = get_lts_path('run', ['var'])
-var_lock_dir = get_lts_path('lock', ['var'])
+from bzrlib.plugins.local_test_server import commands
+
 
 def load_tests(basic_tests, module, loader):
     # This module shouldn't define any tests but I don't know how to report

=== added file 'commands.py'
--- a/commands.py	1970-01-01 00:00:00 +0000
+++ b/commands.py	2008-05-26 19:42:08 +0000
@@ -0,0 +1,60 @@
+# Copyright (C) 2008 Canonical Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+"""Commands to manage local test servers."""
+
+
+from bzrlib import (
+    errors,
+    )
+import bzrlib.commands
+
+
+from bzrlib.plugins.local_test_server import (
+    server,
+    )
+
+class cmd_lts_start(bzrlib.commands.Command):
+    """Start a test server."""
+
+    takes_args = ['name']
+
+    @bzrlib.commands.display_command
+    def run(self, name=None):
+        s = server.get_server(name)
+        if server is None:
+            raise errors.BzrCommandError('Server %s is unknown')
+        s.start()
+        self.outf.write('Server %s started with pid %s on port %s\n'
+                        % (name, s.pid, s.port))
+
+
+class cmd_lts_stop(bzrlib.commands.Command):
+    """Stop a test server."""
+
+    takes_args = ['name']
+
+    @bzrlib.commands.display_command
+    def run(self, name=None):
+        s = server.get_server(name)
+        if server is None:
+            raise errors.BzrCommandError('Server %s is unknown')
+        s.stop()
+        self.outf.write('Server %s stopped\n' % name)
+
+
+bzrlib.commands.register_command(cmd_lts_start)
+bzrlib.commands.register_command(cmd_lts_stop)
+

=== renamed file 'configs/__init__.py' => 'config.py'
--- a/configs/__init__.py	2008-05-23 17:10:36 +0000
+++ b/config.py	2008-05-26 19:42:08 +0000
@@ -21,11 +21,26 @@
     )
 
 
-import bzrlib.plugins.local_test_server as lts
+# Base directory containing all other interesting directories
+base_dir = osutils.dirname(osutils.realpath(__file__))
+
+def get_lts_path(relpath):
+    """Build and return a path in the local_test_server hierarchy."""
+    return osutils.pathjoin(osutils.dirname(osutils.realpath(__file__)),
+                            relpath)
+
+
+etc_dir = get_lts_path('etc')
+
+# Run-time directories
+var_dir = get_lts_path('var')
+var_run_dir = get_lts_path('var/run')
+var_lock_dir = get_lts_path('var/lock')
+var_log_dir = get_lts_path('var/log')
 
 
 # Directory containing all server configuration files
-base_dir = lts.get_lts_path('configs')
+configs_dir = get_lts_path('configs')
 
 
 class Config(object):
@@ -33,10 +48,12 @@
     def __init__(self, name):
         self.name = name
         self.values = dict(server_name=name,
-                           etc_dir=lts.etc_dir,
-                           var_dir=lts.var_dir,
-                           var_run_dir=lts.var_run_dir,
-                           var_lock_dir=lts.var_lock_dir)
+                           root_dir=base_dir,
+                           etc_dir=etc_dir,
+                           var_dir=var_dir,
+                           var_run_dir=var_run_dir,
+                           var_lock_dir=var_lock_dir,
+                           var_log_dir=var_log_dir)
 
     def expand(self, infile, outfile):
         """Expand all the config keywords.
@@ -46,3 +63,14 @@
         """
         for line in infile.readlines():
             outfile.write(line % self.values)
+
+    def get_value(self, name, default=None):
+        return self.values.get(name, default)
+
+
+class Apache2(Config):
+
+    def __init__(self):
+        super(Apache2, self).__init__('apache2')
+        self.values['pid_file'] = get_lts_path('var/run/%s.pid' % self.name)
+        self.config_path = get_lts_path('configs/apache2.conf')

=== modified file 'configs/apache2.conf'
--- a/configs/apache2.conf	2008-05-23 17:10:36 +0000
+++ b/configs/apache2.conf	2008-05-26 19:42:08 +0000
@@ -2,14 +2,14 @@
 # Based on apache2.conf in ubuntu Gusty
 #
 
-# This file will be processed with python '%' operator see plugin
-# source for details.
+# This file will be interpolated by python see plugin source for
+# details.
 
 # Note that most of the directories below are usually owned by
 # root. We want directories writable by the user running the
 # tests.
 
-ServerRoot "%(server_root_dir)s"
+ServerRoot "%(root_dir)s"
 
 LockFile "%(var_lock_dir)s/accept.lock
 
@@ -43,3 +43,17 @@
 #
 KeepAliveTimeout 5
 
+ErrorLog %(var_log_dir)s/apache2/error.log
+LogLevel warn
+CustomLog %(var_log_dir)s/apache2/access.log combined
+
+ServerName localhost
+Listen 8080
+
+# The following directives seems to activate the smallest apache2
+# server possible. If you know better, comments are very welcome.
+# More info at
+# http://localhost/doc/apache2-doc/manual/mod/worker.html
+StartServers         1
+MaxClients           5
+ThreadsPerChild      5

=== added file 'server.py'
--- a/server.py	1970-01-01 00:00:00 +0000
+++ b/server.py	2008-05-26 19:42:08 +0000
@@ -0,0 +1,135 @@
+# Copyright (C) 2008 Canonical Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+"""The local test servers interfaces."""
+
+import errno
+import subprocess
+import time
+
+
+from bzrlib import (
+    errors,
+    )
+
+
+from bzrlib.plugins.local_test_server import (
+    config,
+    )
+
+
+class Server(object):
+
+    def __init__(self, conf):
+        self.config = conf
+
+    def start(self):
+        raise NotImplementedError(self.start)
+
+    def stop(self):
+        raise NotImplementedError(self.stop)
+
+    def is_running(self):
+        raise NotImplementedError(self.is_running)
+
+    @property
+    def pid(self):
+        raise NotImplementedError(self.pid)
+
+    def get_config_value(self, name, default=None):
+        return self.config.get_value(name, default)
+
+    def _get_file_content(self, relpath):
+        abspath = relpath
+        content = None
+        try:
+            f = open(abspath)
+        except IOError, e:
+            if e.errno == errno.ENOENT:
+                content = None
+                raise errors.NoSuchFile(abspath)
+            else:
+                raise
+        try:
+            content = f.read()
+        finally:
+            f.close()
+        return content
+
+class Apache2(Server):
+
+    def __init__(self):
+        super(Apache2, self).__init__(config.Apache2())
+        self.port = None
+
+    def start(self):
+        infile = open(self.config.config_path)
+        config_filename = config.get_lts_path('etc/apache2.conf')
+        outfile = open(config_filename, 'wt')
+        try:
+            self.config.expand(infile, outfile)
+        finally:
+            infile.close()
+            outfile.close()
+        subprocess.check_call(['apache2', '-k', 'start',
+                               '-f', config_filename ])
+        self._wait_for_pidfile_to_be_created()
+
+    def stop(self):
+        config_filename = config.get_lts_path('etc/apache2.conf')
+        retcode = subprocess.check_call(['apache2', '-k', 'stop',
+                                         '-f', config_filename ])
+
+    def _wait_for_pidfile_to_be_created(self):
+        # I couldn't find a a way/command/parameter to start apache2 to that
+        # pidfile file is created when the command returns. Then, if the server
+        # fails to start no pidfile is ever created. Damn if you wait, damn if
+        # you wait too long ;-)
+        started = False
+        delay = 0.001 # 10 ms
+        # total delay to wait in seconds, if you experienced a longer start
+        # time, well, increase.
+        total_delay = 2
+        for i in range(0, int(total_delay * (1  / delay))):
+            if self.is_running():
+                break
+            else:
+                time.sleep(delay)
+
+    def is_running(self):
+        return bool(self.pid is not None)
+
+    @property
+    def pid(self):
+        try:
+            content = self._get_file_content(self.get_config_value('pid_file'))
+        except errors.NoSuchFile:
+            pid = None
+        else:
+            try:
+                pid = int(content)
+            except (TypeError, ValueError):
+                pid = None
+        return pid
+
+
+_servers = dict(apache2=Apache2)
+
+def get_server(name):
+    klass = _servers.get(name, None)
+    if klass is None:
+        return None
+    else:
+        return klass()

=== modified file 'tests/__init__.py'
--- a/tests/__init__.py	2008-05-23 17:10:36 +0000
+++ b/tests/__init__.py	2008-05-26 19:42:08 +0000
@@ -16,7 +16,9 @@
 
 def load_tests(basic_tests, module, loader):
     testmod_names = [
+        'test_commands',
         'test_config',
+        'test_server',
         ]
     basic_tests.addTest(loader.loadTestsFromModuleNames(
             ["%s.%s" % (__name__, tmn) for tmn in testmod_names]))

=== added file 'tests/test_commands.py'
--- a/tests/test_commands.py	1970-01-01 00:00:00 +0000
+++ b/tests/test_commands.py	2008-05-26 19:42:08 +0000
@@ -0,0 +1,18 @@
+# Copyright (C) 2008 Canonical Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+"""Test the commands to start and stop local test servers."""
+

=== modified file 'tests/test_config.py'
--- a/tests/test_config.py	2008-05-23 17:10:36 +0000
+++ b/tests/test_config.py	2008-05-26 19:42:08 +0000
@@ -25,44 +25,48 @@
 
 import bzrlib.plugins.local_test_server as lts
 from bzrlib.plugins.local_test_server import (
-    configs
+    config
     )
 
 
 class TestConfigEnv(tests.TestCase):
 
     def test_etc_exists(self):
-        self.failUnlessExists(lts.etc_dir)
+        self.failUnlessExists(config.etc_dir)
 
     def test_var_exists(self):
-        self.failUnlessExists(lts.var_dir)
-
-    def test_var_exists_run(self):
-        self.failUnlessExists(lts.var_run_dir)
-
-    def test_var_exists_lock(self):
-        self.failUnlessExists(lts.var_lock_dir)
+        self.failUnlessExists(config.var_dir)
+
+    def test_var_run_exists(self):
+        self.failUnlessExists(config.var_run_dir)
+
+    def test_var_lock_exists(self):
+        self.failUnlessExists(config.var_lock_dir)
+
+    def test_var_log_exists(self):
+        self.failUnlessExists(config.var_log_dir)
 
 
 class TestConfig(tests.TestCase):
 
     def test_build_path(self):
-        path = lts.get_lts_path('foo', ['configs'])
+        path = config.get_lts_path('configs/foo')
         self.assertTrue(path.endswith('local_test_server/configs/foo'))
-        path = lts.get_lts_path('foo', ['var', 'run'])
+        path = config.get_lts_path('var/run/foo')
         self.assertTrue(path.endswith('local_test_server/var/run/foo'))
 
 
     def test_config_defines_keywords(self):
-        conf = configs.Config('foo')
+        conf = config.Config('foo')
         self.assertEquals('foo', conf.values.get('server_name'))
-        self.assertEquals(lts.etc_dir, conf.values.get('etc_dir'))
-        self.assertEquals(lts.var_dir, conf.values.get('var_dir'))
-        self.assertEquals(lts.var_run_dir, conf.values.get('var_run_dir'))
-        self.assertEquals(lts.var_lock_dir, conf.values.get('var_lock_dir'))
+        self.assertEquals(config.etc_dir, conf.values.get('etc_dir'))
+        self.assertEquals(config.var_dir, conf.values.get('var_dir'))
+        self.assertEquals(config.var_run_dir, conf.values.get('var_run_dir'))
+        self.assertEquals(config.var_lock_dir, conf.values.get('var_lock_dir'))
+        self.assertEquals(config.var_log_dir, conf.values.get('var_log_dir'))
 
     def test_expand_no_keywords(self):
-        conf = configs.Config('foo')
+        conf = config.Config('foo')
         content = 'nearly_empty'
         inf = StringIO(content)
         outf = StringIO()
@@ -70,12 +74,13 @@
         self.assertEqual(content, outf.getvalue())
 
     def test_expand_keywords(self):
-        conf = configs.Config('foo')
+        conf = config.Config('foo')
         content = '''
 my name is %(server_name)s
 my config is generated under %(etc_dir)s
 my pid is somewhere below %(var_run_dir)s
 I use some lock mechanism which needs something under %(var_lock_dir)s
+My log files will be under %(var_log_dir)s
 '''
         inf = StringIO(content)
         outf = StringIO()
@@ -90,3 +95,11 @@
             expanded, 'I use some lock mechanism which needs something under'
             ' .*var/lock\n')
 
+        self.assertContainsRe(
+            expanded, 'My log files will be under .*var/log\n')
+
+
+class TestConfigEnvApache2(tests.TestCase):
+
+    def test_var_log_apache2_exists(self):
+        self.failUnlessExists(config.get_lts_path('var/log/apache2'))

=== added file 'tests/test_server.py'
--- a/tests/test_server.py	1970-01-01 00:00:00 +0000
+++ b/tests/test_server.py	2008-05-26 19:42:08 +0000
@@ -0,0 +1,46 @@
+# Copyright (C) 2008 Canonical Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+"""Test local test server interfaces."""
+
+
+from bzrlib import (
+    errors,
+    tests,
+    )
+
+from bzrlib.plugins.local_test_server import (
+    server,
+    )
+
+class TestApache2(tests.TestCase):
+
+    def test_server_doesn_t_run(self):
+        s = server.get_server('apache2')
+        self.assertFalse(s.is_running())
+
+    def test_server_start(self):
+        s = server.get_server('apache2')
+        s.start()
+        self.addCleanup(s.stop)
+        self.assertTrue(s.is_running())
+
+    def test_server_stop(self):
+        s = server.get_server('apache2')
+        s.start()
+        self.assertTrue(s.is_running())
+        s.stop()
+        self.assertFalse(s.is_running())



More information about the bazaar-commits mailing list