瀏覽代碼

Don't require config file for supervisorctl

 * Adding require_configfile parameter to options.Options to be able to
   disable config file check for options.ClientOptions.
 * Refactored out searchpaths to become a member of options.Options.
   This made it possible to 1) test for the content of it and 2) disable
   automatic config file detection from within tests (and thus evade
   external side effects that might vary from developer to developer).
 * Adding an additional test of options.ServerOptions to make sure it
   still exits if it can't find a valid configuration file.

This is an initial commit that tries to fix issue #62.

All tests passes on my workstation. However, both `supervisord` and
`supervisorctl` crashed when executed. I will have to look into this.
Jens Rantil 13 年之前
父節點
當前提交
3385f17a9c
共有 2 個文件被更改,包括 75 次插入12 次删除
  1. 21 12
      supervisor/options.py
  2. 54 0
      supervisor/tests/test_options.py

+ 21 - 12
supervisor/options.py

@@ -77,7 +77,12 @@ class Options:
     # If you want positional arguments, set this to 1 in your subclass.
     positional_args_allowed = 0
 
-    def __init__(self):
+    def __init__(self, require_configfile=True):
+        """Constructor.
+
+        Params:
+        require_configfile -- whether we should fail on no config file.
+        """
         self.names_list = []
         self.short_options = []
         self.long_options = []
@@ -86,25 +91,28 @@ class Options:
         self.required_map = {}
         self.environ_map = {}
         self.attr_priorities = {}
+        self.require_configfile = require_configfile
         self.add(None, None, "h", "help", self.help)
         self.add("configfile", None, "c:", "configuration=")
 
-    def default_configfile(self):
-        """Return the name of the found config file or raise. """
         here = os.path.dirname(os.path.dirname(sys.argv[0]))
-        paths = [os.path.join(here, 'etc', 'supervisord.conf'),
-                 os.path.join(here, 'supervisord.conf'),
-                 'supervisord.conf', 'etc/supervisord.conf',
-                 '/etc/supervisord.conf']
+        searchpaths = [os.path.join(here, 'etc', 'supervisord.conf'),
+                       os.path.join(here, 'supervisord.conf'),
+                       'supervisord.conf', 'etc/supervisord.conf',
+                       '/etc/supervisord.conf']
+        self.searchpaths = searchpaths
+
+    def default_configfile(self):
+        """Return the name of the found config file or print usage/exit."""
         config = None
-        for path in paths:
+        for path in self.searchpaths:
             if os.path.exists(path):
                 config = path
                 break
-        if config is None:
+        if config is None and self.require_configfile:
             self.usage('No config file found at default paths (%s); '
                        'use the -c option to specify a config file '
-                       'at a different path' % ', '.join(paths))
+                       'at a different path' % ', '.join(self.searchpaths))
         return config
 
     def help(self, dummy):
@@ -281,7 +289,8 @@ class Options:
         if self.configfile is None:
             self.configfile = self.default_configfile()
 
-        self.process_config_file()
+        if self.configfile:
+            self.process_config_file()
 
     def process_config_file(self, do_usage=True):
         """Process config file."""
@@ -1402,7 +1411,7 @@ class ClientOptions(Options):
     history_file = None
 
     def __init__(self):
-        Options.__init__(self)
+        Options.__init__(self, require_configfile=False)
         self.configroot = Dummy()
         self.configroot.supervisorctl = Dummy()
         self.configroot.supervisorctl.interactive = None

+ 54 - 0
supervisor/tests/test_options.py

@@ -49,6 +49,13 @@ class OptionTests(unittest.TestCase):
                     short='p:', long='other=', handler=integer)
         return options
 
+    def test_searchpaths(self):
+        options = self._makeOptions()
+        self.assertEquals(len(options.searchpaths), 5)
+        self.assertTrue('supervisord.conf' in options.searchpaths)
+        self.assertTrue('etc/supervisord.conf' in options.searchpaths)
+        self.assertTrue('/etc/supervisord.conf' in options.searchpaths)
+
     def test_options_and_args_order(self):
         # Only config file exists
         options = self._makeOptions()
@@ -117,6 +124,28 @@ class ClientOptionsTests(unittest.TestCase):
     def _makeOne(self):
         return self._getTargetClass()()
 
+    def test_no_config_file(self):
+        """Making sure config file is not required."""
+        instance = self._makeOne()
+
+        # No default config file search in case they would exist
+        self.assertTrue(len(instance.searchpaths) > 0)
+        instance.searchpaths = []
+
+        class DummyException(Exception):
+            pass
+        def dummy_exit(self, _exitcode=0):
+            raise DummyException()
+        instance.exit = dummy_exit
+
+        instance.realize(args=['-s', 'http://localhost:9001', '-u', 'chris',
+                               '-p', '123'])
+
+        self.assertEquals(instance.interactive, 1)
+        self.assertEqual(instance.serverurl, 'http://localhost:9001')
+        self.assertEqual(instance.username, 'chris')
+        self.assertEqual(instance.password, '123')
+
     def test_options(self):
         tempdir = tempfile.gettempdir()
         s = lstrip("""[supervisorctl]
@@ -388,6 +417,31 @@ class ServerOptionsTests(unittest.TestCase):
         self.assertEqual(instance.minfds, 2048)
         self.assertEqual(instance.minprocs, 300)
 
+    def test_no_config_file_exits(self):
+        instance = self._makeOne()
+
+        # No default config file search in case they would exist
+        self.assertTrue(len(instance.searchpaths) > 0)
+        instance.searchpaths = []
+
+        class DummyException(Exception):
+            def __init__(self, exitcode):
+                self.exitcode = exitcode
+        def dummy_exit(exitcode=2):
+            # Important default exitcode=2 like sys.exit.
+            raise DummyException(exitcode)
+        instance.exit = dummy_exit
+
+        try:
+            instance.realize()
+        except DummyException, e:
+            print "Caught expected exception: %s" % e
+            import traceback
+            self.assertEquals(e.exitcode, 2,
+                              "Wrong exitcode for: %s" % traceback.format_exc(e))
+        else:
+            self.fail("Did not get a DummyException.")
+
     def test_reload(self):
         from cStringIO import StringIO
         text = lstrip("""\