mirror of
https://github.com/tahoe-lafs/tahoe-lafs.git
synced 2025-01-11 07:23:04 +00:00
Add everything and nothing config validation helpers
This commit is contained in:
parent
aedac9d570
commit
34714d5f6b
@ -14,6 +14,17 @@ if PY2:
|
||||
from builtins import filter, map, zip, ascii, chr, hex, input, next, oct, open, pow, round, super, bytes, list, object, range, str, max, min # noqa: F401
|
||||
|
||||
import os.path
|
||||
from configparser import (
|
||||
ConfigParser,
|
||||
)
|
||||
|
||||
from hypothesis import (
|
||||
given,
|
||||
)
|
||||
from hypothesis.strategies import (
|
||||
dictionaries,
|
||||
text,
|
||||
)
|
||||
|
||||
from twisted.python.filepath import (
|
||||
FilePath,
|
||||
@ -23,6 +34,51 @@ from twisted.trial import unittest
|
||||
from allmydata.util import configutil
|
||||
|
||||
|
||||
def arbitrary_config_dicts(
|
||||
min_sections=0,
|
||||
max_sections=3,
|
||||
max_items_per_section=3,
|
||||
max_item_length=8,
|
||||
max_value_length=8,
|
||||
):
|
||||
"""
|
||||
Build ``dict[str, dict[str, str]]`` instances populated with arbitrary
|
||||
configurations.
|
||||
"""
|
||||
return dictionaries(
|
||||
text(),
|
||||
dictionaries(
|
||||
text(max_size=max_item_length),
|
||||
text(max_size=max_value_length),
|
||||
max_size=max_items_per_section,
|
||||
),
|
||||
min_size=min_sections,
|
||||
max_size=max_sections,
|
||||
)
|
||||
|
||||
|
||||
def to_configparser(dictconfig):
|
||||
"""
|
||||
Take a ``dict[str, dict[str, str]]`` and turn it into the corresponding
|
||||
populated ``ConfigParser`` instance.
|
||||
"""
|
||||
cp = ConfigParser()
|
||||
for section, items in dictconfig.items():
|
||||
cp.add_section(section)
|
||||
for k, v in items.items():
|
||||
cp.set(
|
||||
section,
|
||||
k,
|
||||
# ConfigParser has a feature that everyone knows and loves
|
||||
# where it will use %-style interpolation to substitute
|
||||
# values from one part of the config into another part of
|
||||
# the config. Escape all our `%`s to avoid hitting this
|
||||
# and complicating things.
|
||||
v.replace("%", "%%"),
|
||||
)
|
||||
return cp
|
||||
|
||||
|
||||
class ConfigUtilTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
super(ConfigUtilTests, self).setUp()
|
||||
@ -166,3 +222,48 @@ enabled = false
|
||||
config = configutil.get_config(fname)
|
||||
self.assertEqual(config.get("node", "a"), "foo")
|
||||
self.assertEqual(config.get("node", "b"), "bar")
|
||||
|
||||
@given(arbitrary_config_dicts())
|
||||
def test_everything_valid(self, cfgdict):
|
||||
"""
|
||||
``validate_config`` returns ``None`` when the validator is
|
||||
``ValidConfiguration.everything()``.
|
||||
"""
|
||||
cfg = to_configparser(cfgdict)
|
||||
self.assertIs(
|
||||
configutil.validate_config(
|
||||
"<test_everything_valid>",
|
||||
cfg,
|
||||
configutil.ValidConfiguration.everything(),
|
||||
),
|
||||
None,
|
||||
)
|
||||
|
||||
@given(arbitrary_config_dicts(min_sections=1))
|
||||
def test_nothing_valid(self, cfgdict):
|
||||
"""
|
||||
``validate_config`` raises ``UnknownConfigError`` when the validator is
|
||||
``ValidConfiguration.nothing()`` for all non-empty configurations.
|
||||
"""
|
||||
cfg = to_configparser(cfgdict)
|
||||
with self.assertRaises(configutil.UnknownConfigError):
|
||||
configutil.validate_config(
|
||||
"<test_everything_valid>",
|
||||
cfg,
|
||||
configutil.ValidConfiguration.nothing(),
|
||||
)
|
||||
|
||||
def test_nothing_empty_valid(self):
|
||||
"""
|
||||
``validate_config`` returns ``None`` when the validator is
|
||||
``ValidConfiguration.nothing()`` if the configuration is empty.
|
||||
"""
|
||||
cfg = ConfigParser()
|
||||
self.assertIs(
|
||||
configutil.validate_config(
|
||||
"<test_everything_valid>",
|
||||
cfg,
|
||||
configutil.ValidConfiguration.nothing(),
|
||||
),
|
||||
None,
|
||||
)
|
||||
|
@ -115,10 +115,34 @@ class ValidConfiguration(object):
|
||||
an item name as bytes and returns True if that section, item pair is
|
||||
valid, False otherwise.
|
||||
"""
|
||||
_static_valid_sections = attr.ib()
|
||||
_static_valid_sections = attr.ib(
|
||||
validator=attr.validators.instance_of(dict)
|
||||
)
|
||||
_is_valid_section = attr.ib(default=lambda section_name: False)
|
||||
_is_valid_item = attr.ib(default=lambda section_name, item_name: False)
|
||||
|
||||
@classmethod
|
||||
def everything(cls):
|
||||
"""
|
||||
Create a validator which considers everything valid.
|
||||
"""
|
||||
return cls(
|
||||
{},
|
||||
lambda section_name: True,
|
||||
lambda section_name, item_name: True,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def nothing(cls):
|
||||
"""
|
||||
Create a validator which considers nothing valid.
|
||||
"""
|
||||
return cls(
|
||||
{},
|
||||
lambda section_name: False,
|
||||
lambda section_name, item_name: False,
|
||||
)
|
||||
|
||||
def is_valid_section(self, section_name):
|
||||
"""
|
||||
:return: True if the given section name is valid, False otherwise.
|
||||
|
Loading…
Reference in New Issue
Block a user