浏览代码

- Use rich comparison methods rather than __cmp__ to sort process
configs and process group configs to better straddle Python
versions. (thanks to Jonathan Riboux for identifying the problem
and supplying an initial patch).

- Fixed test_supervisorctl.test_maintail_dashf test for Python 2.7.
(thanks to Jonathan Riboux for identifying the problem and
supplying an initial patch).

- Fixed the way that supervisor.datatypes.url computes a "good" URL
for compatibility with Python 2.7 and Python >= 2.6.5. URLs with
bogus "schemes://" will now be accepted as a version-straddling
compromise (before they were rejected before supervisor would
start). (thanks to Jonathan Riboux for identifying the problem
and supplying an initial patch).

Chris McDonough 15 年之前
父节点
当前提交
0c5547b03c

+ 16 - 0
CHANGES.txt

@@ -1,5 +1,21 @@
 Next release
 
+  - Use rich comparison methods rather than __cmp__ to sort process
+    configs and process group configs to better straddle Python
+    versions.  (thanks to Jonathan Riboux for identifying the problem
+    and supplying an initial patch).
+
+  - Fixed test_supervisorctl.test_maintail_dashf test for Python 2.7.
+    (thanks to Jonathan Riboux for identifying the problem and
+    supplying an initial patch).
+
+  - Fixed the way that supervisor.datatypes.url computes a "good" URL
+    for compatibility with Python 2.7 and Python >= 2.6.5.  URLs with
+    bogus "schemes://" will now be accepted as a version-straddling
+    compromise (before they were rejected before supervisor would
+    start).  (thanks to Jonathan Riboux for identifying the problem
+    and supplying an initial patch).
+
   - Add a ``-v`` / ``--version`` option to supervisord: Print the
     supervisord version number out to stdout and exit.  (Roger Hoover)
 

+ 2 - 0
setup.cfg

@@ -2,6 +2,8 @@
 zip_ok = false
 
 [nosetests]
+exclude=medusa
+where=src/supervisor
 nocapture=1
 cover-package=supervisor
 with-coverage=1

+ 5 - 4
src/supervisor/datatypes.py

@@ -401,10 +401,11 @@ byte_size = SuffixMultiplier({'kb': 1024,
 
 def url(value):
     import urlparse
-    scheme, netloc, path, params, query, fragment = urlparse.urlparse(value)
-    if scheme and netloc:
-        return value     
-    if scheme == 'unix' and path.startswith('//') and len(path) > 2:
+    # earlier Python 2.6 urlparse (2.6.4 and under) can't parse unix:// URLs,
+    # later ones can but we need to straddle
+    uri = value.replace('unix://', 'http://', 1).strip()
+    scheme, netloc, path, params, query, fragment = urlparse.urlparse(uri)
+    if scheme and (netloc or path):
         return value
     raise ValueError("value %s is not a URL" % value)
 

+ 37 - 8
src/supervisor/options.py

@@ -694,7 +694,6 @@ class ServerOptions(Options):
                 FastCGIGroupConfig(self, program_name, priority, processes,
                                    socket_config)
                 )
-        
 
         groups.sort()
         return groups
@@ -1508,14 +1507,38 @@ class UnhosedConfigParser(ConfigParser.RawConfigParser):
             else:
                 return default
 
-class Config:
-    def __cmp__(self, other):
-        return cmp(self.priority, other.priority)
+class Config(object):
+    def __ne__(self, other):
+        return not self.__eq__(other)
+
+    def __lt__(self, other):
+        if self.priority == other.priority:
+            return self.name < other.name
+            
+        return self.priority < other.priority
+
+    def __le__(self, other):
+        if self.priority == other.priority:
+            return self.name <= other.name
+            
+        return self.priority <= other.priority
+
+    def __gt__(self, other):
+        if self.priority == other.priority:
+            return self.name > other.name
+            
+        return self.priority > other.priority
+
+    def __ge__(self, other):
+        if self.priority == other.priority:
+            return self.name >= other.name
+            
+        return self.priority >= other.priority
 
     def __repr__(self):
         return '<%s instance at %s named %s>' % (self.__class__, id(self),
                                                  self.name)
-    
+
 class ProcessConfig(Config):
     req_param_names = [
         'name', 'uid', 'command', 'directory', 'umask', 'priority',
@@ -1642,9 +1665,6 @@ class ProcessGroupConfig(Config):
 
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
     def after_setuid(self):
         for config in self.process_configs:
             config.create_autochildlogs()
@@ -1664,6 +1684,15 @@ class EventListenerPoolConfig(Config):
         self.pool_events = pool_events
         self.result_handler = result_handler
 
+    def __eq__(self, other):
+        if not isinstance(other, EventListenerPoolConfig):
+            return False
+        
+        if (self.name == other.name) and (self.priority == other.priority):
+            return True
+
+        return False
+            
     def after_setuid(self):
         for config in self.process_configs:
             config.create_autochildlogs()

+ 0 - 4
src/supervisor/tests/test_datatypes.py

@@ -198,10 +198,6 @@ class DatatypesTest(unittest.TestCase):
         bad_url = "unix://"
         self.assertRaises(ValueError, datatypes.url, bad_url)   
     
-    def test_url_rejects_urlparse_unrecognized_scheme_with_path(self):
-        bad_url = "bad://path"
-        self.assertRaises(ValueError, datatypes.url, bad_url)
-
 class InetStreamSocketConfigTests(unittest.TestCase):
     def _getTargetClass(self):
         return datatypes.InetStreamSocketConfig

+ 35 - 15
src/supervisor/tests/test_options.py

@@ -403,8 +403,13 @@ class ServerOptionsTests(unittest.TestCase):
         instance.realize(args=[])
 
         section = instance.configroot.supervisord
+
         self.assertEqual(len(section.process_group_configs), 2)
+
         cat = section.process_group_configs[0]
+        self.assertEqual(len(cat.process_configs), 1)
+
+        cat = section.process_group_configs[1]
         self.assertEqual(len(cat.process_configs), 2)
         self.assertTrue(section.process_group_configs is
                         instance.process_group_configs)
@@ -426,14 +431,10 @@ class ServerOptionsTests(unittest.TestCase):
         instance.process_config_file()
 
         section = instance.configroot.supervisord
+
         self.assertEqual(len(section.process_group_configs), 2)
-        cat = section.process_group_configs[0]
-        self.assertEqual(len(cat.process_configs), 1)
-        proc = cat.process_configs[0]
-        self.assertEqual(proc.name, 'three')
-        self.assertEqual(proc.command, '/bin/pig')
 
-        cat = section.process_group_configs[1]
+        cat = section.process_group_configs[0]
         self.assertEqual(len(cat.process_configs), 1)
         proc = cat.process_configs[0]
         self.assertEqual(proc.name, 'one')
@@ -441,6 +442,12 @@ class ServerOptionsTests(unittest.TestCase):
         self.assertTrue(section.process_group_configs is
                         instance.process_group_configs)
 
+        cat = section.process_group_configs[1]
+        self.assertEqual(len(cat.process_configs), 1)
+        proc = cat.process_configs[0]
+        self.assertEqual(proc.name, 'three')
+        self.assertEqual(proc.command, '/bin/pig')
+
     def test_readFile_failed(self):
         from supervisor.options import readFile
         try:
@@ -725,6 +732,12 @@ class ServerOptionsTests(unittest.TestCase):
         process_name = %(program_name)s_%(process_num)s
         command = /bin/cat
         numprocs = 3
+
+        [eventlistener:biz]
+        events=PROCESS_COMMUNICATION
+        process_name = %(program_name)s_%(process_num)s
+        command = /bin/biz
+        numprocs = 2
         """)
         from supervisor.options import UnhosedConfigParser
         from supervisor.dispatchers import default_handler
@@ -732,15 +745,20 @@ class ServerOptionsTests(unittest.TestCase):
         config.read_string(text)
         instance = self._makeOne()
         gconfigs = instance.process_groups_from_parser(config)
-        self.assertEqual(len(gconfigs), 2)
+        self.assertEqual(len(gconfigs), 3)
 
         gconfig1 = gconfigs[0]
+        self.assertEqual(gconfig1.name, 'biz')
+        self.assertEqual(gconfig1.result_handler, default_handler)
+        self.assertEqual(len(gconfig1.process_configs), 2)
+
+        gconfig1 = gconfigs[1]
         self.assertEqual(gconfig1.name, 'cat')
         self.assertEqual(gconfig1.priority, -1)
         self.assertEqual(gconfig1.result_handler, default_handler)
         self.assertEqual(len(gconfig1.process_configs), 3)
 
-        gconfig1 = gconfigs[1]
+        gconfig1 = gconfigs[2]
         self.assertEqual(gconfig1.name, 'dog')
         self.assertEqual(gconfig1.priority, 1)
         self.assertEqual(gconfig1.result_handler, default_handler)
@@ -840,6 +858,7 @@ class ServerOptionsTests(unittest.TestCase):
             return instance.process_groups_from_parser(config)
 
         gconfigs = get_process_groups(instance, config)
+        
         exp_owner = (sentinel.uid, sentinel.gid)
 
         self.assertEqual(len(gconfigs), 4)
@@ -856,7 +875,7 @@ class ServerOptionsTests(unittest.TestCase):
         pconfig_foo = gconf_foo.process_configs[0]
         self.assertEqual(pconfig_foo.__class__, FastCGIProcessConfig)
         
-        gconf_bar = gconfigs[2]
+        gconf_bar = gconfigs[1]
         self.assertEqual(gconf_bar.name, 'bar')
         self.assertEqual(gconf_bar.priority, 999)
         self.assertEqual(gconf_bar.socket_config.url,
@@ -865,7 +884,13 @@ class ServerOptionsTests(unittest.TestCase):
         self.assertEqual(0700, gconf_bar.socket_config.get_mode())
         self.assertEqual(len(gconf_bar.process_configs), 3)
         
-        gconf_flub = gconfigs[1]
+        gconf_cub = gconfigs[2]
+        self.assertEqual(gconf_cub.name, 'cub')
+        self.assertEqual(gconf_cub.socket_config.url,
+                         'tcp://localhost:6000')
+        self.assertEqual(len(gconf_cub.process_configs), 1)
+
+        gconf_flub = gconfigs[3]
         self.assertEqual(gconf_flub.name, 'flub')
         self.assertEqual(gconf_flub.socket_config.url,
                          'unix:///tmp/flub.sock')
@@ -873,11 +898,6 @@ class ServerOptionsTests(unittest.TestCase):
         self.assertEqual(0700, gconf_flub.socket_config.get_mode())
         self.assertEqual(len(gconf_flub.process_configs), 1)
         
-        gconf_cub = gconfigs[3]
-        self.assertEqual(gconf_cub.name, 'cub')
-        self.assertEqual(gconf_cub.socket_config.url,
-                         'tcp://localhost:6000')
-        self.assertEqual(len(gconf_cub.process_configs), 1)
         
 
     def test_fcgi_program_no_socket(self):

+ 3 - 3
src/supervisor/tests/test_supervisorctl.py

@@ -867,9 +867,9 @@ class TestDefaultControllerPlugin(unittest.TestCase):
         self.assertEqual(len(errors), 1)
         error = errors[0]
         self.assertEqual(plugin.listener.closed,
-                         'http://localhost:92491/mainlogtail')
+                         'http://localhost:65532/mainlogtail')
         self.assertEqual(error[0],
-                         'http://localhost:92491/mainlogtail')
+                         'http://localhost:65532/mainlogtail')
         for msg in ('Cannot connect', 'socket.error'):
             self.assertTrue(msg in error[1])
 
@@ -951,7 +951,7 @@ class DummyPluginFactory:
 class DummyClientOptions:
     def __init__(self):
         self.prompt = 'supervisor'
-        self.serverurl = 'http://localhost:92491' # should be uncontactable
+        self.serverurl = 'http://localhost:65532'
         self.username = 'chrism'
         self.password = '123'
         self.history_file = None