Rev 8: Create a dedicated hierarchy by server at start time. Use test ports for in file:///v/home/vila/.bazaar/plugins/local_test_server/

Vincent Ladeuil v.ladeuil+lp at free.fr
Wed May 28 20:10:59 BST 2008


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

------------------------------------------------------------
revno: 8
revision-id: v.ladeuil+lp at free.fr-20080528191059-gq4r5s90t7y3lm93
parent: v.ladeuil+lp at free.fr-20080528111938-d0spqs2co7r2m03c
committer: Vincent Ladeuil <v.ladeuil+lp at free.fr>
branch nick: local_test_server
timestamp: Wed 2008-05-28 21:10:59 +0200
message:
  Create a dedicated hierarchy by server at start time. Use test ports for
  tests.
  
  * tests/test_server.py:
  (TestServer): Define a base class with some helpers.
  
  * tests/test_config.py:
  (TestConfig): Define a base class with some helpers.
  (TestBaseConfig.test_ensure_required_dirs_exist): New test.
  (TestBaseConfig.test_config_defines_keywords): Simplified.
  (TestBaseConfig.test_expand_keywords): Simplified.
  (TestConfigApache2.test_config_defines_keywords): New test.
  
  * server.py:
  (Apache2.__init__): Add a _conf parameter for tests.
  (Apache2.start): Ensures required dirs exist before opening output
  file.
  (Apache2.stop): Use the correct generated configuration file.
  
  * configs/apache2.conf: 
  Reference host and port.
  
  * config.py:
  (Config.__init__): Add required_dirs and _base_dir
  parameters. Calculate paths.
  (Config.abspath): New method.
  (Config.ensure_required_dirs_exist): New method.
  (Apache2): Declare specific required subdirs.
removed:
  etc/                           etc-20080523170706-tosxlttyvwvutu4s-1
  var/                           var-20080523170708-nkpjg07oorui519n-1
  var/lock/                      lock-20080523170716-vl523z7to322eg8a-1
  var/run/                       run-20080523170717-jvc42ynv6ghppmnk-1
modified:
  TODO                           todo-20080526134120-eibvvebw74t8j2xh-1
  commands.py                    commands.py-20080524160638-76gsirgigzamza15-1
  config.py                      __init__.py-20080523170713-0c8mnxio9r41iyhk-1
  configs/apache2.conf           apache2.conf-20080522095851-6eixwo2qv9brec67-1
  server.py                      server.py-20080524160639-rqhbexqatjqbwypw-1
  tests/test_config.py           test_config.py-20080523170715-clr6vz0qdzefftob-1
  tests/test_server.py           test_server.py-20080524160641-lco15o23ub9mac33-1
-------------- next part --------------
=== modified file 'TODO'
--- a/TODO	2008-05-28 10:57:57 +0000
+++ b/TODO	2008-05-28 19:10:59 +0000
@@ -1,13 +1,5 @@
 * server.py
 
-- 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
+* plug the server if the corresponding feature is available.

=== modified file 'commands.py'
--- a/commands.py	2008-05-28 08:27:12 +0000
+++ b/commands.py	2008-05-28 19:10:59 +0000
@@ -36,7 +36,7 @@
             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))
+                        % (name, s.get_pid(), s.port))
 
 
 class cmd_lts_stop(bzrlib.commands.Command):

=== modified file 'config.py'
--- a/config.py	2008-05-28 11:19:38 +0000
+++ b/config.py	2008-05-28 19:10:59 +0000
@@ -14,7 +14,11 @@
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
-"""configs -- provides access to server configurations."""
+"""configs -- generates server configurations."""
+
+import errno
+import os
+
 
 from bzrlib import (
     osutils,
@@ -30,50 +34,76 @@
                             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
-configs_dir = get_lts_path('configs')
-
-
 class Config(object):
 
-    def __init__(self, name):
+    def __init__(self, name, required_dirs=None, _base_dir=None):
+        """Constructor.
+
+        :param name: The name of the server, also used to build various dirs.
+        :param required_dirs: A dict where keys are the name to use in config
+            files and values the path relative to server work directory.
+        :param _base_dir: An alternate base directory to use instead of the
+            default 'work'
+
+        Each server gets its own directory under the 'work/<server_name>'
+        subdir of the plugin. This helps administration and debugging by
+        grouping all server files in the same place.
+        """
         self.name = name
+        if _base_dir is None:
+            _base_dir = get_lts_path('work/%s' % name)
+        self.base_dir = _base_dir
         self.values = dict(server_name=name,
-                           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,
                             # Will be updated at server creation
                            host='example.com' ,port=0,
-                          )
+                           )
+        # We need at least a place to put the generated configuration file and
+        # the pidfile.
+        self.required_dirs = dict(etc_dir='etc', var_run_dir='var/run')
+        if required_dirs is not None:
+            self.required_dirs.update(required_dirs)
+
+        for name, relpath in self.required_dirs.items():
+                self.values[name] = self.abspath(relpath)
+
+        self.values['base_dir'] = self.base_dir
+        self.values['pid_file'] = self.abspath('var/run/%s.pid' % self.name)
+
+    def abspath(self, relpath=None):
+        return osutils.pathjoin(self.base_dir, relpath)
 
     def expand(self, infile, outfile):
         """Expand all the config keywords.
 
-        :param infile: A file containing the kwywords to be expanded
+        :param infile: A file containing the keywords to be expanded
         :param outfile: A opened file where the expansion result is written
         """
         for line in infile.readlines():
             outfile.write(line % self.values)
 
+    def ensure_required_dirs_exist(self):
+        for dir in self.required_dirs.keys():
+            try:
+                os.makedirs(self.get_value(dir))
+            except OSError, e:
+                if e.errno == errno.EEXIST:
+                    # Better ask for forgiveness
+                    pass
+                else:
+                    raise
+
     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)
+    _required_dirs = dict(var_lock_dir='var/lock',
+                          var_log_dir='var/log')
+
+
+    def __init__(self, _base_dir=None):
+        super(Apache2, self).__init__('apache2',
+                                      required_dirs=self._required_dirs,
+                                      _base_dir=_base_dir)
         self.config_path = get_lts_path('configs/apache2.conf')

=== modified file 'configs/apache2.conf'
--- a/configs/apache2.conf	2008-05-26 19:42:08 +0000
+++ b/configs/apache2.conf	2008-05-28 19:10:59 +0000
@@ -9,7 +9,7 @@
 # root. We want directories writable by the user running the
 # tests.
 
-ServerRoot "%(root_dir)s"
+ServerRoot "%(base_dir)s"
 
 LockFile "%(var_lock_dir)s/accept.lock
 
@@ -43,12 +43,10 @@
 #
 KeepAliveTimeout 5
 
-ErrorLog %(var_log_dir)s/apache2/error.log
-LogLevel warn
-CustomLog %(var_log_dir)s/apache2/access.log combined
+ErrorLog %(var_log_dir)s/error.log
 
-ServerName localhost
-Listen 8080
+ServerName %(host)s
+Listen %(port)s
 
 # The following directives seems to activate the smallest apache2
 # server possible. If you know better, comments are very welcome.

=== removed directory 'etc'
=== modified file 'server.py'
--- a/server.py	2008-05-28 11:19:38 +0000
+++ b/server.py	2008-05-28 19:10:59 +0000
@@ -32,11 +32,11 @@
 
     def __init__(self, config, port=-1):
         self.host = 'localhost'
-        if port != -1:
-            self.port = port
-        else:
+        if port == -1:
             # For tests only
             self.port = _get_available_port()
+        else:
+            self.port = port
         config.values.update(host=self.host, port=self.port)
         self.config = config
 
@@ -79,26 +79,32 @@
     # alternative
     _hk_interval = 10.0 # in miliseconds
 
-    def __init__(self, port):
-        super(Apache2, self).__init__(config.Apache2(), port)
+    def __init__(self, port, _conf=None):
+        if _conf is None:
+            _conf = config.Apache2()
+        super(Apache2, self).__init__(_conf, port)
 
     def start(self):
         infile = open(self.config.config_path)
-        config_filename = config.get_lts_path('etc/apache2.conf')
+        config_filename = self.config.abspath('etc/apache2.conf')
+        self.config.ensure_required_dirs_exist()
         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 ])
+        try:
+            subprocess.check_call(['apache2', '-k', 'start',
+                                   '-f', config_filename ])
+        except subprocess.CalledProcessError, e:
+            raise errors.BzrCommandError('apache2 cannot be started')
         if not self._wait_for_pidfile_to_be_created():
-            raise errors.BzrCommandError('apache2 cannot be atarted')
+            raise errors.BzrCommandError('apache2 pidfile not created')
 
 
     def stop(self):
-        config_filename = config.get_lts_path('etc/apache2.conf')
+        config_filename = self.config.abspath('etc/apache2.conf')
         pid = self.get_pid()
         # Tell it to stop
         subprocess.call(['apache2', '-k', 'stop',

=== modified file 'tests/test_config.py'
--- a/tests/test_config.py	2008-05-28 11:19:38 +0000
+++ b/tests/test_config.py	2008-05-28 19:10:59 +0000
@@ -19,6 +19,7 @@
 from cStringIO import StringIO
 
 from bzrlib import (
+    osutils,
     tests,
     )
 
@@ -29,44 +30,42 @@
     )
 
 
-class TestConfigEnv(tests.TestCase):
-
-    def test_etc_exists(self):
-        self.failUnlessExists(config.etc_dir)
-
-    def test_var_exists(self):
-        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):
+class TestConfig(tests.TestCaseInTempDir):
+
+    def _get_config(self, klass, *args, **kwargs):
+        kwargs['_base_dir'] = self.test_dir
+        return klass(*args,**kwargs)
+
+    def _abspath(self, relpath):
+        return osutils.pathjoin(self.test_dir, relpath)
+
+    def _check_conf_path(self, conf, name, expected_path):
+        self.assertEqual(self._abspath(expected_path), conf.get_value(name))
+
+
+class TestBaseConfig(TestConfig):
+
+    def test_lts_path(self):
         path = config.get_lts_path('configs/foo')
         self.assertTrue(path.endswith('local_test_server/configs/foo'))
         path = config.get_lts_path('var/run/foo')
         self.assertTrue(path.endswith('local_test_server/var/run/foo'))
 
+    def test_ensure_required_dirs_exist(self):
+        req_dirs = dict(bar='bar', baz='baz')
+        c = self._get_config(config.Config, 'foo', req_dirs)
+        c.ensure_required_dirs_exist()
+        self.failUnlessExists(self._abspath('bar'))
+        self.failUnlessExists(self._abspath('baz'))
 
     def test_config_defines_keywords(self):
-        conf = config.Config('foo')
+        conf = self._get_config(config.Config, 'foo')
         self.assertEquals('foo', conf.values.get('server_name'))
-        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'))
+        self._check_conf_path(conf, 'etc_dir', 'etc')
+        self._check_conf_path(conf, 'var_run_dir', 'var/run')
 
     def test_expand_no_keywords(self):
-        conf = config.Config('foo')
+        conf = self._get_config(config.Config, 'foo')
         content = 'nearly_empty'
         inf = StringIO(content)
         outf = StringIO()
@@ -74,14 +73,12 @@
         self.assertEqual(content, outf.getvalue())
 
     def test_expand_keywords(self):
-        conf = config.Config('foo')
+        conf = self._get_config(config.Config, 'foo')
         content = '''
 my name is %(server_name)s
 my address is %(host)s:%(port)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()
@@ -93,15 +90,14 @@
             expanded, 'my config is generated under .*/etc\n')
         self.assertContainsRe(
             expanded, 'my pid is somewhere below .*/var/run\n')
-        self.assertContainsRe(
-            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'))
+
+
+class TestConfigApache2(TestConfig):
+
+    def test_config_defines_keywords(self):
+        conf = self._get_config(config.Apache2)
+        self.assertEquals('apache2', conf.get_value('server_name'))
+        self._check_conf_path(conf, 'etc_dir', 'etc')
+        self._check_conf_path(conf, 'var_run_dir', 'var/run')
+        self._check_conf_path(conf, 'var_lock_dir', 'var/lock')
+        self._check_conf_path(conf, 'var_log_dir', 'var/log')

=== modified file 'tests/test_server.py'
--- a/tests/test_server.py	2008-05-28 10:57:57 +0000
+++ b/tests/test_server.py	2008-05-28 19:10:59 +0000
@@ -24,6 +24,7 @@
 
 
 from bzrlib.plugins.local_test_server import (
+    config,
     server,
     )
 
@@ -51,20 +52,34 @@
         self.assertRaises(ValueError, server._get_available_port)
 
 
-class TestApache2(tests.TestCase):
+class TestServer(tests.TestCaseInTempDir):
+
+    def _get_config(self, klass, *args, **kwargs):
+        kwargs['_base_dir'] = self.test_dir
+        return klass(*args,**kwargs)
+
+    def _get_server(self, klass, config):
+        return klass(server._get_available_port(), config)
+
+
+class TestApache2(TestServer):
+
+    def _get_server(self):
+        conf = self._get_config(config.Apache2)
+        return super(TestApache2, self)._get_server(server.Apache2, conf)
 
     def test_server_doesn_t_run(self):
-        s = server.get_server('apache2')
+        s = self._get_server()
         self.assertFalse(s.is_running())
 
     def test_server_start(self):
-        s = server.get_server('apache2')
+        s = self._get_server()
         s.start()
         self.addCleanup(s.stop)
         self.assertTrue(s.is_running())
 
     def test_server_stop(self):
-        s = server.get_server('apache2')
+        s = self._get_server()
         s.start()
         self.assertTrue(s.is_running())
         s.stop()

=== removed directory 'var'
=== removed directory 'var/lock'
=== removed directory 'var/run'


More information about the bazaar-commits mailing list