Rev 41: Avoid false positives in the test suite. in http://bazaar.launchpad.net/%7Evila/bzr/local-test-server

Vincent Ladeuil v.ladeuil+lp at free.fr
Thu Jun 26 16:35:40 BST 2008


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

------------------------------------------------------------
revno: 41
revision-id: v.ladeuil+lp at free.fr-20080626153537-jgg7h9xzs6n34xl1
parent: v.ladeuil+lp at free.fr-20080625183646-drh2cl7zn42hazwc
committer: Vincent Ladeuil <v.ladeuil+lp at free.fr>
branch nick: local_test_server
timestamp: Thu 2008-06-26 17:35:37 +0200
message:
  Avoid false positives in the test suite.
  
  * tests/test_utils.py:
  (TestLocalServer._get_server): If the server can't be launched, it
  can't be tested.
  
  * tests/test_server.py:
  (TestLocateProgram): New tests.
  
  * server.py:
  (locate_program): New helper to check executable availability. We
  don't want the test suite to fail when some servers are not
  installed.
modified:
  TODO                           todo-20080526134120-eibvvebw74t8j2xh-1
  server.py                      server.py-20080524160639-rqhbexqatjqbwypw-1
  tests/test_server.py           test_server.py-20080524160641-lco15o23ub9mac33-1
  tests/test_utils.py            test_utils.py-20080603162150-w01001l902j0gu95-1
-------------- next part --------------
=== modified file 'TODO'
--- a/TODO	2008-06-24 16:38:28 +0000
+++ b/TODO	2008-06-26 15:35:37 +0000
@@ -33,5 +33,16 @@
 
 * add support for
 
+** ftp
+
+*** file bugs against conflicting ftp servers packages
+
+*** investigate dpkg --force-depends to be able to force the
+   installation of conflicting servers
+
 ** https (for all supporting servers, preferably by using
    dedicated servers)
+
+** various http authentication schemes (including multiple ones)
+
+** http proxies

=== modified file 'server.py'
--- a/server.py	2008-06-24 20:06:35 +0000
+++ b/server.py	2008-06-26 15:35:37 +0000
@@ -15,7 +15,7 @@
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 """The local test servers interfaces.
 
-The classes described here interface with the real servers.
+The classes described here provide an interface with the real servers.
 """
 
 from bzrlib.lazy_import import lazy_import
@@ -24,6 +24,7 @@
 import os
 import re
 import signal
+import stat
 import subprocess
 import time
 
@@ -89,9 +90,37 @@
         else:
             self.extra = ''
 
+def locate_program(name, PATH=None):
+    """Locates a program in PATH.
+
+    :param name: The program searched
+    :param PATH: A list of directories to search into
+
+    :returns: None if not found, completed PATH otherwise.
+    """
+    full_path = None
+    if PATH is None:
+        PATH = os.getenv('PATH', '')
+    for dir in PATH.split(os.pathsep):
+        if not dir:
+            continue
+        full_path = osutils.joinpath([dir, name])
+        try:
+            st = os.stat(full_path)
+        except OSError, e:
+            if e.errno == errno.ENOENT:
+                continue
+            else:
+                raise
+        if bool(stat.S_IEXEC & st.st_mode):
+            return full_path
+    return None
 
 class Server(object):
 
+    # The command used to start the server
+    _server_command_name = None
+
     def __init__(self, config, port=-1):
         self.host = 'localhost'
         if port == -1:
@@ -303,6 +332,8 @@
 
 class Apache2(Server):
 
+    _server_command_name = 'apache2'
+
     _started_re = re.compile("\[notice\] Apache/2.*configured --"
                              " resuming normal operations$")
 
@@ -317,7 +348,8 @@
 
     def _start(self):
         try:
-            subprocess.check_call(['apache2', '-k', 'start',
+            subprocess.check_call([self._server_command_name,
+                                   '-k', 'start',
                                    '-f', self.output_config_path])
         except subprocess.CalledProcessError, e:
             raise LTSCantStartError(self, extra=e)
@@ -330,7 +362,8 @@
 
     def _stop_apache2(self):
         try:
-            subprocess.check_call(['apache2', '-k', 'stop',
+            subprocess.check_call([self._server_command_name,
+                                   '-k', 'stop',
                                    '-f', self.output_config_path ])
         except subprocess.CalledProcessError, e:
             raise LTSCantStopError(self, extra=e)
@@ -383,6 +416,8 @@
 
 class Cherokee(Server):
 
+    _server_command_name = 'cherokee'
+
     def __init__(self, port, _conf=None):
         if _conf is None:
             _conf = config.Cherokee()
@@ -392,8 +427,8 @@
 
     def _start(self):
         try:
-            subprocess.check_call(['cherokee', '-b',
-                                   '-C', self.output_config_path])
+            subprocess.check_call([self._server_command_name,
+                                   '-b', '-C', self.output_config_path])
         except subprocess.CalledProcessError, e:
             raise LTSCantStartError(self, extra=e)
         if not self._wait_for_pidfile_to_be_created():
@@ -410,6 +445,8 @@
 
 class Lighttpd(Server):
 
+    _server_command_name = 'lighttpd'
+
     _started_re = re.compile("server started $") # Note the final space...
 
     def __init__(self, port, _conf=None):
@@ -421,7 +458,8 @@
 
     def _start(self):
         try:
-            subprocess.check_call(['lighttpd', '-f', self.output_config_path])
+            subprocess.check_call([self._server_command_name,
+                                   '-f', self.output_config_path])
         except subprocess.CalledProcessError, e:
             raise LTSCantStartError(self, extra=e)
         # Since lighttpd deamonize itself early, the return code is useless,
@@ -469,6 +507,8 @@
 
 class Vsftpd(Server):
 
+    _server_command_name = 'vsftpd'
+
     def __init__(self, port, _conf=None):
         if _conf is None:
             _conf = config.Vsftpd()
@@ -481,7 +521,8 @@
         # goes wrong during server launch... There is nothing in the log to get
         # confirmation that the start went right, the log file itself is not
         # created before the first connection :-/
-        proc = subprocess.Popen(['vsftpd', self.output_config_path])
+        proc = subprocess.Popen([self._server_command_name,
+                                 self.output_config_path])
         if proc.returncode is not None:
             raise LTSCantStartError(self, 'return code: %s' % proc.returncode)
         f = open(self.get_config_value('pid_file'), 'w')

=== modified file 'tests/test_server.py'
--- a/tests/test_server.py	2008-06-04 13:33:54 +0000
+++ b/tests/test_server.py	2008-06-26 15:35:37 +0000
@@ -71,6 +71,20 @@
         self.assertRaises(ValueError, server._get_available_port)
 
 
+class TestLocateProgram(tests.TestCase):
+
+    def test_locate_existing(self):
+        p = server.locate_program('python')
+        self.assertTrue(p is not None)
+
+    def test_locate_unknown(self):
+        # Whatever silly name we can imagine, the day we distribute this
+        # plugin, someone will just manage to get a nifty program distributed
+        # on the whole planet. So we just search in a empty PATH.
+        p = server.locate_program('foobar', '')
+        self.assertTrue(p is None)
+
+
 class TestServer(tests.TestCaseInTempDir, test_utils.TestLocalServer):
 
     def test_server_doesn_t_run(self):

=== modified file 'tests/test_utils.py'
--- a/tests/test_utils.py	2008-06-24 20:06:35 +0000
+++ b/tests/test_utils.py	2008-06-26 15:35:37 +0000
@@ -49,8 +49,11 @@
         return self._config_class(*args,**kwargs)
 
     def _get_server(self):
-        return self._server_class(server._get_available_port(),
-                                  self._get_config())
+        klass = self._server_class
+        if klass._server_command_name is not None:
+            if server.locate_program(klass._server_command_name) is None:
+                raise tests.UnavailableFeature(klass)
+        return klass(server._get_available_port(), self._get_config())
 
     def _get_server_feature(self):
         feature = self._server_feature_class()



More information about the bazaar-commits mailing list