Explorar o código

Add 'runforever' tests.

Chris McDonough %!s(int64=18) %!d(string=hai) anos
pai
achega
f59afa652f

+ 4 - 0
src/supervisor/options.py

@@ -31,6 +31,7 @@ import grp
 import resource
 import stat
 import pkg_resources
+import select
 
 from fcntl import fcntl
 from fcntl import F_SETFL, F_GETFL
@@ -982,6 +983,9 @@ class ServerOptions(Options):
             except os.error:
                 pass
 
+    def select(self, r, w, x, timeout):
+        return select.select(r, w, x, timeout)
+
     def kill(self, pid, signal):
         os.kill(pid, signal)
 

+ 8 - 6
src/supervisor/supervisord.py

@@ -119,22 +119,24 @@ class Supervisor:
         socket_map = self.options.get_socket_map()
 
         while 1:
+            pgroups = self.process_groups.values()
+
             if self.mood > 0:
-                for group in self.process_groups.values():
+                for group in pgroups:
                     group.start_necessary()
 
             r, w, x = [], [], []
 
             if self.mood < 1:
                 if not self.stopping:
-                    for group in self.process_groups.values():
+                    for group in pgroups:
                         group.stop_all()
                     self.stopping = True
 
                 # if there are no delayed processes (we're done killing
                 # everything), it's OK to stop or reload
                 delayprocs = []
-                for group in self.process_groups.values():
+                for group in pgroups:
                     delayprocs.extend(group.get_delay_processes())
 
                 if delayprocs:
@@ -151,7 +153,7 @@ class Supervisor:
             process_callbacks = {}
 
             # subprocess input and output
-            for group in self.process_groups.values():
+            for group in pgroups:
                 callbacks, group_r, group_w, group_x = group.select()
                 r.extend(group_r)
                 w.extend(group_w)
@@ -166,7 +168,7 @@ class Supervisor:
                     w.append(fd)
 
             try:
-                r, w, x = select.select(r, w, x, timeout)
+                r, w, x = self.options.select(r, w, x, timeout)
             except select.error, err:
                 r = w = x = []
                 if err[0] == errno.EINTR:
@@ -202,7 +204,7 @@ class Supervisor:
                     except:
                         socket_map[fd].handle_error()
 
-            for group in self.process_groups.values():
+            for group in pgroups:
                 group.transition()
 
             self.reap()

+ 18 - 1
src/supervisor/tests/base.py

@@ -56,6 +56,8 @@ class DummyOptions:
         self.write_accept = None
         self.write_error = None
         self.tempfile_name = '/foo/bar'
+        self.select_result = [], [], []
+        self.select_error = None
 
     def getLogger(self, *args, **kw):
         logger = DummyLogger()
@@ -203,6 +205,12 @@ class DummyOptions:
     def mktempfile(self, prefix, suffix, dir):
         return self.tempfile_name
 
+    def select(self, r, w, x, timeout):
+        import select
+        if self.select_error:
+            raise select.error(self.select_error)
+        return self.select_result
+
 class DummyLogger:
     def __init__(self):
         self.reopened = False
@@ -603,15 +611,24 @@ class DummyProcessGroup:
         self.config = config
         self.necessary_started = False
         self.transitioned = False
+        self.all_stopped = False
+        self.delay_processes = []
+        self.select_result = {}, [], [], []
 
     def start_necessary(self):
         self.necessary_started = True
 
     def select(self):
-        return {}, [], [], []
+        return self.select_result
 
     def transition(self):
         self.transitioned = True
+
+    def stop_all(self):
+        self.all_stopped = True
+
+    def get_delay_processes(self):
+        return self.delay_processes
         
 
 def lstrip(s):

+ 43 - 0
src/supervisor/tests/test_supervisord.py

@@ -7,6 +7,7 @@ from supervisor.tests.base import DummyOptions
 from supervisor.tests.base import DummyPConfig
 from supervisor.tests.base import DummyPGroupConfig
 from supervisor.tests.base import DummyProcess
+from supervisor.tests.base import DummyProcessGroup
 
 class SupervisordTests(unittest.TestCase):
     def _getTargetClass(self):
@@ -126,6 +127,48 @@ class SupervisordTests(unittest.TestCase):
         self.assertEqual(options.logger.data[0],
                          'received SIGUSR1 indicating nothing')
 
+    def test_runforever_select_eintr(self):
+        options = DummyOptions()
+        import errno
+        options.select_error = errno.EINTR
+        supervisord = self._makeOne(options)
+        supervisord.runforever(test=True)
+        self.assertEqual(options.logger.data[0], 5)
+        self.assertEqual(options.logger.data[1], 'EINTR encountered in select')
+
+    def test_one_process_group_select(self):
+        options = DummyOptions()
+        supervisord = self._makeOne(options)
+        pconfig = DummyPConfig(options, 'foo', '/bin/foo',)
+        process = DummyProcess(pconfig)
+        gconfig = DummyPGroupConfig(options, pconfigs=[pconfig])
+        pgroup = DummyProcessGroup(gconfig)
+        L = []
+        def callback():
+            L.append(1)
+        pgroup.select_result = {6:callback, 7:callback}, [6], [7], []
+        supervisord.process_groups = {'foo': pgroup}
+        options.select_result = [6], [7], []
+        supervisord.runforever(test=True)
+        self.assertEqual(pgroup.necessary_started, True)
+        self.assertEqual(pgroup.transitioned, True)
+        self.assertEqual(L, [1, 1])
+        
+    def test_exit(self):
+        options = DummyOptions()
+        supervisord = self._makeOne(options)
+        pconfig = DummyPConfig(options, 'foo', '/bin/foo',)
+        process = DummyProcess(pconfig)
+        gconfig = DummyPGroupConfig(options, pconfigs=[pconfig])
+        pgroup = DummyProcessGroup(gconfig)
+        L = []
+        def callback():
+            L.append(1)
+        supervisord.process_groups = {'foo': pgroup}
+        supervisord.mood = 0
+        import asyncore
+        self.assertRaises(asyncore.ExitNow, supervisord.runforever, test=True)
+
 def test_suite():
     return unittest.findTestCases(sys.modules[__name__])