diff options
| -rw-r--r-- | eventmq/conf.py | 2 | ||||
| -rw-r--r-- | eventmq/tests/test_utils.py | 151 | ||||
| -rw-r--r-- | eventmq/utils/settings.py | 12 |
3 files changed, 110 insertions, 55 deletions
diff --git a/eventmq/conf.py b/eventmq/conf.py index 87aa675..f15a1ef 100644 --- a/eventmq/conf.py +++ b/eventmq/conf.py | |||
| @@ -88,6 +88,8 @@ RQ_HOST = 'localhost' | |||
| 88 | RQ_PORT = 6379 | 88 | RQ_PORT = 6379 |
| 89 | RQ_DB = 0 | 89 | RQ_DB = 0 |
| 90 | RQ_PASSWORD = '' | 90 | RQ_PASSWORD = '' |
| 91 | REDIS_CLIENT_CLASS = 'redis.StrictRedis' | ||
| 92 | REDIS_CLIENT_CLASS_KWARGS = {} | ||
| 91 | 93 | ||
| 92 | MAX_JOB_COUNT = 1024 | 94 | MAX_JOB_COUNT = 1024 |
| 93 | 95 | ||
diff --git a/eventmq/tests/test_utils.py b/eventmq/tests/test_utils.py index 03da18a..2937085 100644 --- a/eventmq/tests/test_utils.py +++ b/eventmq/tests/test_utils.py | |||
| @@ -12,52 +12,62 @@ | |||
| 12 | # | 12 | # |
| 13 | # You should have received a copy of the GNU Lesser General Public License | 13 | # You should have received a copy of the GNU Lesser General Public License |
| 14 | # along with eventmq. If not, see <http://www.gnu.org/licenses/>. | 14 | # along with eventmq. If not, see <http://www.gnu.org/licenses/>. |
| 15 | from configparser import ConfigParser | ||
| 15 | from imp import reload | 16 | from imp import reload |
| 16 | import io | 17 | import io |
| 18 | import os | ||
| 17 | import random | 19 | import random |
| 18 | import sys | 20 | import sys |
| 19 | import unittest | 21 | import unittest |
| 20 | 22 | ||
| 21 | import mock | 23 | import mock |
| 22 | 24 | ||
| 25 | from .. import conf | ||
| 23 | from .. import constants | 26 | from .. import constants |
| 24 | from .. import exceptions | 27 | from .. import exceptions |
| 25 | from ..utils import classes, messages, settings | 28 | from ..utils import classes, messages, settings |
| 26 | 29 | ||
| 27 | 30 | ||
| 28 | class SettingsTestCase(unittest.TestCase): | 31 | class SettingsTestCase(unittest.TestCase): |
| 29 | settings_ini = "\n".join( | 32 | settings_ini = '\n'.join( |
| 30 | ("[global]", | 33 | ('[global]', |
| 31 | "super_debug=TRuE", | 34 | 'super_debug=TRuE', |
| 32 | "frontend_addr=tcp://0.0.0.0:47291", | 35 | 'frontend_addr=tcp://0.0.0.0:47291', |
| 33 | "", | 36 | '', |
| 34 | "[jobmanager]", | 37 | '[jobmanager]', |
| 35 | "super_debug=FalSe", | 38 | 'super_debug=FalSe', |
| 36 | 'queues=[[50,"google"], [40,"pushes"], [10,"default"]]', | 39 | 'queues=[[50,"google"], [40,"pushes"], [10,"default"]]', |
| 37 | "worker_addr=tcp://160.254.23.88:47290", | 40 | 'worker_addr=tcp://160.254.23.88:47290', |
| 38 | "concurrent_jobs=9283",)) | 41 | 'concurrent_jobs=9283', |
| 42 | '', | ||
| 43 | '[scheduler]', | ||
| 44 | 'redis_client_class_kwargs={"test_kwarg": true}', | ||
| 45 | '', | ||
| 46 | '[section_with_bad_list]', | ||
| 47 | 'queues=[[10,asdf],]', | ||
| 48 | '', | ||
| 49 | '[section_with_bad_dict]', | ||
| 50 | 'redis_client_class_kwargs={asdf, 39}')) | ||
| 51 | |||
| 52 | def setUp(self): | ||
| 53 | self._config = ConfigParser() | ||
| 54 | |||
| 55 | if sys.version_info[0] == 3: | ||
| 56 | self._config.read_string(self.settings_ini) | ||
| 57 | else: | ||
| 58 | self._config.readfp(io.BytesIO(self.settings_ini)) | ||
| 39 | 59 | ||
| 40 | @mock.patch('eventmq.utils.settings.os.path.exists') | ||
| 41 | def test_import_settings_default(self, pathexists_mock): | ||
| 42 | from configparser import ConfigParser | ||
| 43 | from .. import conf | ||
| 44 | # sometimes the tests step on each other with this module. reloading | 60 | # sometimes the tests step on each other with this module. reloading |
| 45 | # ensures fresh test data | 61 | # ensures fresh test data |
| 46 | reload(conf) | 62 | reload(conf) |
| 47 | pathexists_mock.return_value = True | ||
| 48 | 63 | ||
| 49 | _config = ConfigParser() | 64 | @mock.patch('eventmq.utils.settings.os.path.exists') |
| 50 | 65 | def test_import_settings_default(self, pathexists_mock): | |
| 51 | if sys.version_info[0] == 3: | 66 | pathexists_mock.return_value = True |
| 52 | _config.read_string(self.settings_ini) | ||
| 53 | else: | ||
| 54 | _config.readfp(io.BytesIO(self.settings_ini)) | ||
| 55 | 67 | ||
| 56 | # Global section | ||
| 57 | # -------------- | ||
| 58 | with mock.patch('eventmq.utils.settings.ConfigParser', | 68 | with mock.patch('eventmq.utils.settings.ConfigParser', |
| 59 | return_value=_config): | 69 | return_value=self._config): |
| 60 | with mock.patch.object(_config, 'read'): | 70 | with mock.patch.object(self._config, 'read'): |
| 61 | settings.import_settings() | 71 | settings.import_settings() |
| 62 | 72 | ||
| 63 | # Changed. Default is false | 73 | # Changed. Default is false |
| @@ -75,25 +85,19 @@ class SettingsTestCase(unittest.TestCase): | |||
| 75 | # Default is (10, 'default') | 85 | # Default is (10, 'default') |
| 76 | self.assertEqual(conf.QUEUES, [(10, conf.DEFAULT_QUEUE_NAME), ]) | 86 | self.assertEqual(conf.QUEUES, [(10, conf.DEFAULT_QUEUE_NAME), ]) |
| 77 | 87 | ||
| 78 | # Job Manager Section | 88 | @mock.patch('eventmq.utils.settings.os.path.exists') |
| 79 | # ------------------- | 89 | def test_import_settings_jobmanager(self, pathexists_mock): |
| 80 | from configparser import ConfigParser | 90 | pathexists_mock.return_value = True |
| 81 | _config = ConfigParser() | ||
| 82 | if sys.version_info[0] == 3: | ||
| 83 | _config.read_string(self.settings_ini) | ||
| 84 | else: | ||
| 85 | _config.readfp(io.BytesIO(self.settings_ini)) | ||
| 86 | 91 | ||
| 87 | # Global section | ||
| 88 | # -------------- | ||
| 89 | with mock.patch('eventmq.utils.settings.ConfigParser', | 92 | with mock.patch('eventmq.utils.settings.ConfigParser', |
| 90 | return_value=_config): | 93 | return_value=self._config): |
| 91 | with mock.patch.object(ConfigParser, 'read'): | 94 | with mock.patch.object(self._config, 'read'): |
| 95 | settings.import_settings() | ||
| 92 | settings.import_settings('jobmanager') | 96 | settings.import_settings('jobmanager') |
| 93 | 97 | ||
| 94 | # Changed | 98 | # Changed from True (in global) to False |
| 95 | self.assertFalse(conf.SUPER_DEBUG) | 99 | self.assertFalse(conf.SUPER_DEBUG) |
| 96 | # Changed | 100 | # Override default value |
| 97 | self.assertEqual(conf.CONCURRENT_JOBS, 9283) | 101 | self.assertEqual(conf.CONCURRENT_JOBS, 9283) |
| 98 | 102 | ||
| 99 | # Changed | 103 | # Changed |
| @@ -102,21 +106,14 @@ class SettingsTestCase(unittest.TestCase): | |||
| 102 | 106 | ||
| 103 | self.assertEqual(conf.WORKER_ADDR, 'tcp://160.254.23.88:47290') | 107 | self.assertEqual(conf.WORKER_ADDR, 'tcp://160.254.23.88:47290') |
| 104 | 108 | ||
| 105 | # Invalid section | 109 | @mock.patch('eventmq.utils.settings.os.path.exists') |
| 106 | # --------------- | 110 | def test_load_invalid_section_uses_defaults(self, pathexists_mock): |
| 107 | # This shouldn't fail, and nothing should change | 111 | pathexists_mock.return_value = True |
| 108 | _config = ConfigParser() | ||
| 109 | |||
| 110 | if sys.version_info[0] == 3: | ||
| 111 | _config.read_string(self.settings_ini) | ||
| 112 | else: | ||
| 113 | _config.readfp(io.BytesIO(self.settings_ini)) | ||
| 114 | 112 | ||
| 115 | # Global section | ||
| 116 | # -------------- | ||
| 117 | with mock.patch('eventmq.utils.settings.ConfigParser', | 113 | with mock.patch('eventmq.utils.settings.ConfigParser', |
| 118 | return_value=_config): | 114 | return_value=self._config): |
| 119 | with mock.patch.object(ConfigParser, 'read'): | 115 | with mock.patch.object(self._config, 'read'): |
| 116 | settings.import_settings('jobmanager') | ||
| 120 | settings.import_settings('nonexistent_section') | 117 | settings.import_settings('nonexistent_section') |
| 121 | 118 | ||
| 122 | self.assertEqual(conf.CONCURRENT_JOBS, 9283) | 119 | self.assertEqual(conf.CONCURRENT_JOBS, 9283) |
| @@ -124,6 +121,58 @@ class SettingsTestCase(unittest.TestCase): | |||
| 124 | [(50, 'google'), (40, 'pushes'), (10, 'default')]) | 121 | [(50, 'google'), (40, 'pushes'), (10, 'default')]) |
| 125 | self.assertEqual(conf.WORKER_ADDR, 'tcp://160.254.23.88:47290') | 122 | self.assertEqual(conf.WORKER_ADDR, 'tcp://160.254.23.88:47290') |
| 126 | 123 | ||
| 124 | @mock.patch('eventmq.utils.settings.os.path.exists') | ||
| 125 | def test_dictionary(self, pathexists_mock): | ||
| 126 | pathexists_mock.return_value = True | ||
| 127 | |||
| 128 | with mock.patch('eventmq.utils.settings.ConfigParser', | ||
| 129 | return_value=self._config): | ||
| 130 | with mock.patch.object(self._config, 'read'): | ||
| 131 | settings.import_settings('scheduler') | ||
| 132 | |||
| 133 | # Dictionary should be dictionary | ||
| 134 | self.assertTrue(isinstance(conf.REDIS_CLIENT_CLASS_KWARGS, dict)) | ||
| 135 | # Dictionary should be dictionary | ||
| 136 | self.assertTrue(conf.REDIS_CLIENT_CLASS_KWARGS['test_kwarg']) | ||
| 137 | |||
| 138 | @mock.patch('eventmq.utils.settings.os.path.exists') | ||
| 139 | def test_favor_environment_variables(self, pathexists_mock): | ||
| 140 | pathexists_mock.return_value = True | ||
| 141 | |||
| 142 | # frontend_addr has been defined in global, but should be the following | ||
| 143 | # value | ||
| 144 | value = 'from environment variable' | ||
| 145 | os.environ['EVENTMQ_FRONTEND_ADDR'] = value | ||
| 146 | try: | ||
| 147 | with mock.patch('eventmq.utils.settings.ConfigParser', | ||
| 148 | return_value=self._config): | ||
| 149 | with mock.patch.object(self._config, 'read'): | ||
| 150 | settings.import_settings() | ||
| 151 | finally: | ||
| 152 | del os.environ['EVENTMQ_FRONTEND_ADDR'] | ||
| 153 | |||
| 154 | self.assertEqual(conf.FRONTEND_ADDR, value) | ||
| 155 | |||
| 156 | @mock.patch('eventmq.utils.settings.os.path.exists') | ||
| 157 | def test_valueerror_on_invalid_json_list(self, pathexists_mock): | ||
| 158 | pathexists_mock.return_value = True | ||
| 159 | |||
| 160 | with mock.patch('eventmq.utils.settings.ConfigParser', | ||
| 161 | return_value=self._config): | ||
| 162 | with mock.patch.object(self._config, 'read'): | ||
| 163 | with self.assertRaises(ValueError): | ||
| 164 | settings.import_settings('section_with_bad_list') | ||
| 165 | |||
| 166 | @mock.patch('eventmq.utils.settings.os.path.exists') | ||
| 167 | def test_valueerror_on_invalid_json_dict(self, pathexists_mock): | ||
| 168 | pathexists_mock.return_value = True | ||
| 169 | |||
| 170 | with mock.patch('eventmq.utils.settings.ConfigParser', | ||
| 171 | return_value=self._config): | ||
| 172 | with mock.patch.object(self._config, 'read'): | ||
| 173 | with self.assertRaises(ValueError): | ||
| 174 | settings.import_settings('section_with_bad_dict') | ||
| 175 | |||
| 127 | 176 | ||
| 128 | class EMQPServiceTestCase(unittest.TestCase): | 177 | class EMQPServiceTestCase(unittest.TestCase): |
| 129 | 178 | ||
diff --git a/eventmq/utils/settings.py b/eventmq/utils/settings.py index 3999e39..7a91858 100644 --- a/eventmq/utils/settings.py +++ b/eventmq/utils/settings.py | |||
| @@ -79,7 +79,7 @@ def import_settings(section='global'): | |||
| 79 | value = t(json.loads(value)) | 79 | value = t(json.loads(value)) |
| 80 | except ValueError: | 80 | except ValueError: |
| 81 | raise ValueError( | 81 | raise ValueError( |
| 82 | "Invalid JSON syntax for {} setting".format(name)) | 82 | 'Invalid JSON syntax for {} setting'.format(name)) |
| 83 | # json.loads coverts all arrays to lists, but if the first | 83 | # json.loads coverts all arrays to lists, but if the first |
| 84 | # element in the default is a tuple (like in QUEUES) then | 84 | # element in the default is a tuple (like in QUEUES) then |
| 85 | # convert those elements, otherwise whatever it's type is | 85 | # convert those elements, otherwise whatever it's type is |
| @@ -91,8 +91,12 @@ def import_settings(section='global'): | |||
| 91 | elif isinstance(default_value, bool): | 91 | elif isinstance(default_value, bool): |
| 92 | setattr(conf, name, | 92 | setattr(conf, name, |
| 93 | True if 't' in value.lower() else False) | 93 | True if 't' in value.lower() else False) |
| 94 | elif t == dict: | ||
| 95 | try: | ||
| 96 | value = json.loads(value) | ||
| 97 | except ValueError: | ||
| 98 | raise ValueError( | ||
| 99 | 'Invalid JSON syntax for {} setting'.format(name)) | ||
| 100 | setattr(conf, name, value) | ||
| 94 | else: | 101 | else: |
| 95 | setattr(conf, name, t(value)) | 102 | setattr(conf, name, t(value)) |
| 96 | |||
| 97 | logger.debug("Setting conf.{} to {}".format( | ||
| 98 | name, getattr(conf, name))) | ||