aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mailman_pgp/config/converter.py66
-rw-r--r--src/mailman_pgp/config/tests/test_converter.py97
-rw-r--r--src/mailman_pgp/config/tests/test_validator.py62
-rw-r--r--src/mailman_pgp/config/validator.py51
4 files changed, 209 insertions, 67 deletions
diff --git a/src/mailman_pgp/config/converter.py b/src/mailman_pgp/config/converter.py
new file mode 100644
index 0000000..6f458d9
--- /dev/null
+++ b/src/mailman_pgp/config/converter.py
@@ -0,0 +1,66 @@
+# Copyright (C) 2017 Jan Jancar
+#
+# This file is a part of the Mailman PGP plugin.
+#
+# This program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free
+# Software Foundation, either version 3 of the License, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program. If not, see <http://www.gnu.org/licenses/>.
+
+""""""
+import builtins
+import re
+from configparser import ConfigParser
+
+from mailman.utilities.modules import find_name
+
+
+class ConfigConverter:
+ """Converts a ConfigParser object values according to a schema."""
+
+ def __init__(self, schema):
+ self.schema = ConfigParser()
+ self.schema.read_string(schema)
+
+ def convert(self, cfg):
+ """
+
+ :param cfg:
+ :type cfg: ConfigParser
+ """
+ out = dict()
+ for section in self.schema.sections():
+ out[section] = dict()
+ for option in self.schema.options(section):
+ out[section][option] = self._transform_option(
+ cfg.get(section, option),
+ self.schema.get(section, option))
+ return out
+
+ def _transform_option(self, value, schema):
+ call = None
+ try:
+ call = getattr(builtins, schema)
+ except:
+ try:
+ call = find_name(schema)
+ except:
+ if len(schema) != 0:
+ def call(value):
+ match = re.search(schema, value)
+ if match is None:
+ raise ValueError
+ return match
+
+ if call is None:
+ raise ValueError
+ else:
+ return call(value)
diff --git a/src/mailman_pgp/config/tests/test_converter.py b/src/mailman_pgp/config/tests/test_converter.py
new file mode 100644
index 0000000..0509a44
--- /dev/null
+++ b/src/mailman_pgp/config/tests/test_converter.py
@@ -0,0 +1,97 @@
+# Copyright (C) 2017 Jan Jancar
+#
+# This file is a part of the Mailman PGP plugin.
+#
+# This program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free
+# Software Foundation, either version 3 of the License, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program. If not, see <http://www.gnu.org/licenses/>.
+
+""""""
+from unittest import TestCase
+
+from mailman_pgp.config import Config
+from mailman_pgp.config.converter import ConfigConverter
+from mailman_pgp.testing.layers import PGPLayer
+
+
+class TestConverter(TestCase):
+ layer = PGPLayer
+
+ def test_builtins(self):
+ schema = """\
+ [test]
+ test_option: int
+ """
+ validator = ConfigConverter(schema)
+ valid = Config()
+ valid.read_string("""\
+ [test]
+ test_option: 5
+ """)
+ invalid = Config()
+ invalid.read_string("""\
+ [test]
+ test_option: xyz
+ """)
+ validator.convert(valid)
+ self.assertRaises(ValueError, validator.convert, invalid)
+
+ def test_callable(self):
+ schema = """\
+ [test]
+ test_option: lazr.config.as_boolean
+ """
+ validator = ConfigConverter(schema)
+ valid = Config()
+ valid.read_string("""\
+ [test]
+ test_option: yes
+ """)
+ invalid = Config()
+ invalid.read_string("""\
+ [test]
+ test_option: xyz
+ """)
+ validator.convert(valid)
+ self.assertRaises(ValueError, validator.convert, invalid)
+
+ def test_regex(self):
+ schema = """\
+ [test]
+ test_option: 29*4
+ """
+ validator = ConfigConverter(schema)
+ valid = Config()
+ valid.read_string("""\
+ [test]
+ test_option: 2999999994
+ """)
+ invalid = Config()
+ invalid.read_string("""\
+ [test]
+ test_option: xyz
+ """)
+ validator.convert(valid)
+ self.assertRaises(ValueError, validator.convert, invalid)
+
+ def test_none(self):
+ schema = """\
+ [test]
+ test_option:
+ """
+ validator = ConfigConverter(schema)
+ cfg = Config()
+ cfg.read_string("""\
+ [test]
+ test_option: something
+ """)
+ self.assertRaises(ValueError, validator.convert, cfg)
diff --git a/src/mailman_pgp/config/tests/test_validator.py b/src/mailman_pgp/config/tests/test_validator.py
index d24dfc7..51570c3 100644
--- a/src/mailman_pgp/config/tests/test_validator.py
+++ b/src/mailman_pgp/config/tests/test_validator.py
@@ -46,72 +46,56 @@ class TestConfigs(TestCase):
class TestValidator(TestCase):
layer = PGPLayer
- def test_builtins(self):
+ def test_missing_section(self):
schema = """\
[test]
- test_option: int
+ test_option: something
"""
validator = ConfigValidator(schema)
- valid = Config()
- valid.read_string("""\
- [test]
- test_option: 5
- """)
- invalid = Config()
- invalid.read_string("""\
- [test]
- test_option: xyz
+ cfg = Config()
+ cfg.read_string("""\
+ [other_section]
+ some_option: something else
""")
- validator.validate(valid)
- self.assertRaises(ValueError, validator.validate, invalid)
+ self.assertRaises(ValueError, validator.validate, cfg)
- def test_callable(self):
+ def test_additional_section(self):
schema = """\
[test]
- test_option: lazr.config.as_boolean
+ test_option: something
"""
validator = ConfigValidator(schema)
- valid = Config()
- valid.read_string("""\
- [test]
- test_option: yes
- """)
- invalid = Config()
- invalid.read_string("""\
+ cfg = Config()
+ cfg.read_string("""\
[test]
- test_option: xyz
+ test_option: something
+ [other_section]
+ some_option: something else
""")
- validator.validate(valid)
- self.assertRaises(ValueError, validator.validate, invalid)
+ self.assertRaises(ValueError, validator.validate, cfg)
- def test_regex(self):
+ def test_missing_option(self):
schema = """\
[test]
- test_option: 29*4
+ test_option: something
"""
validator = ConfigValidator(schema)
- valid = Config()
- valid.read_string("""\
- [test]
- test_option: 2999999994
- """)
- invalid = Config()
- invalid.read_string("""\
+ cfg = Config()
+ cfg.read_string("""\
[test]
- test_option: xyz
""")
- validator.validate(valid)
- self.assertRaises(ValueError, validator.validate, invalid)
+ self.assertRaises(ValueError, validator.validate, cfg)
- def test_none(self):
+ def test_additional_option(self):
schema = """\
[test]
- test_option:
+ test_option: something
"""
validator = ConfigValidator(schema)
cfg = Config()
cfg.read_string("""\
[test]
test_option: something
+ other_option: something else
""")
self.assertRaises(ValueError, validator.validate, cfg)
diff --git a/src/mailman_pgp/config/validator.py b/src/mailman_pgp/config/validator.py
index 1010663..51f57d7 100644
--- a/src/mailman_pgp/config/validator.py
+++ b/src/mailman_pgp/config/validator.py
@@ -15,13 +15,9 @@
# You should have received a copy of the GNU General Public License along with
# this program. If not, see <http://www.gnu.org/licenses/>.
-"""Config validation and transforms."""
-import builtins
-import re
+"""Config validation."""
from configparser import ConfigParser
-from mailman.utilities.modules import find_name
-
class ConfigValidator:
"""Validates a ConfigParser object against a schema."""
@@ -36,29 +32,28 @@ class ConfigValidator:
:param cfg:
:type cfg: ConfigParser
"""
+ errors = []
+ additional_sections = set(cfg.sections()).difference(
+ self.schema.sections())
+
+ if len(additional_sections) > 0:
+ errors.append(
+ 'Additional sections: {}'.format(additional_sections))
+
for section in self.schema.sections():
- assert cfg.has_section(section)
+ if not cfg.has_section(section):
+ errors.append('Missing config section: {}'.format(section))
+ continue
for option in self.schema.options(section):
- assert cfg.has_option(section, option)
- self._check_option(cfg.get(section, option),
- self.schema.get(section, option))
-
- def _check_option(self, value, schema):
- call = None
- try:
- call = getattr(builtins, schema)
- except:
- try:
- call = find_name(schema)
- except:
- if len(schema) != 0:
- def call(value):
- match = re.search(schema, value)
- if match is None:
- raise ValueError
- return match
+ if not cfg.has_option(section, option):
+ errors.append(
+ 'Missing config option {} in {}'.format(option,
+ section))
+ additional_options = set(cfg.options(section)).difference(
+ self.schema.options(section))
+ if len(additional_options) > 0:
+ errors.append(
+ 'Additional options: {}'.format(additional_options))
- if call is None:
- raise ValueError
- else:
- return call(value)
+ if len(errors) > 0:
+ raise ValueError(errors)