From e9512e5a46b8743fd35c23dfa9eb374930d058a8 Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Wed, 4 Feb 2015 16:38:13 +0000 Subject: [PATCH] Add tests and docs for IConfig/NamespaceConfig --- letsencrypt/client/configuration.py | 29 ++++++++++++---- letsencrypt/client/constants.py | 8 ++--- letsencrypt/client/interfaces.py | 7 +++- .../client/tests/configuration_test.py | 33 +++++++++++++++++++ 4 files changed, 65 insertions(+), 12 deletions(-) create mode 100644 letsencrypt/client/tests/configuration_test.py diff --git a/letsencrypt/client/configuration.py b/letsencrypt/client/configuration.py index 5b7568c1f..048746b12 100644 --- a/letsencrypt/client/configuration.py +++ b/letsencrypt/client/configuration.py @@ -7,7 +7,24 @@ from letsencrypt.client import interfaces class NamespaceConfig(object): - """Configuration wrapper around `argparse.Namespace`.""" + """Configuration wrapper around :class:`argparse.Namespace`. + + For more documentation, including available attributes, please see + :class:`letsencrypt.client.interfaces.IConfig`. However, note that + the following attributes are dynamically resolved using + :attr:`~letsencrypt.client.interfaces.IConfig.work_dir` and relative + paths defined in :py:mod:`letsencrypt.client.constants`: + + - ``temp_checkpoint_dir`` + - ``in_progress_dir`` + - ``cert_key_backup`` + - ``rev_tokens_dir`` + + :ivar namespace: Namespace typically produced by + :meth:`argparse.ArgumentParser.parse_args`. + :type namespace: :class:`argparse.Namespace` + + """ zope.interface.implements(interfaces.IConfig) def __init__(self, namespace): @@ -19,19 +36,17 @@ class NamespaceConfig(object): @property def temp_checkpoint_dir(self): # pylint: disable=missing-docstring return os.path.join( - self.namespace.work_dir, constants.TEMP_CHECKPOINT_DIR_NAME) + self.namespace.work_dir, constants.TEMP_CHECKPOINT_DIR) @property def in_progress_dir(self): # pylint: disable=missing-docstring - return os.path.join( - self.namespace.work_dir, constants.IN_PROGRESS_DIR_NAME) + return os.path.join(self.namespace.work_dir, constants.IN_PROGRESS_DIR) @property def cert_key_backup(self): # pylint: disable=missing-docstring return os.path.join( - self.namespace.work_dir, constants.CERT_KEY_BACKUP_DIR_NAME) + self.namespace.work_dir, constants.CERT_KEY_BACKUP_DIR) @property def rev_tokens_dir(self): # pylint: disable=missing-docstring - return os.path.join( - self.namespace.work_dir, constants.REV_TOKENS_DIR_NAME) + return os.path.join(self.namespace.work_dir, constants.REV_TOKENS_DIR) diff --git a/letsencrypt/client/constants.py b/letsencrypt/client/constants.py index 3414bce74..e1a8ebaed 100644 --- a/letsencrypt/client/constants.py +++ b/letsencrypt/client/constants.py @@ -49,17 +49,17 @@ DVSNI_DOMAIN_SUFFIX = ".acme.invalid" """Suffix appended to domains in DVSNI validation.""" -TEMP_CHECKPOINT_DIR_NAME = "temp_checkpoint" +TEMP_CHECKPOINT_DIR = "temp_checkpoint" """Temporary checkpoint directory (relative to IConfig.work_dir).""" -IN_PROGRESS_DIR_NAME = "IN_PROGRESS" +IN_PROGRESS_DIR = "IN_PROGRESS" """Directory used before a permanent checkpoint is finalized (relative to IConfig.work_dir).""" -CERT_KEY_BACKUP_DIR_NAME = "keys-certs" +CERT_KEY_BACKUP_DIR = "keys-certs" """Directory where all certificates and keys are stored (relative to IConfig.work_dir. Used for easy revocation.""" -REV_TOKENS_DIR_NAME = "revocation_tokens" +REV_TOKENS_DIR = "revocation_tokens" """Directory where all revocation tokens are saved (relative to IConfig.work_dir).""" diff --git a/letsencrypt/client/interfaces.py b/letsencrypt/client/interfaces.py index 9516ba95d..4f7dcda45 100644 --- a/letsencrypt/client/interfaces.py +++ b/letsencrypt/client/interfaces.py @@ -60,7 +60,12 @@ class IChallenge(zope.interface.Interface): class IConfig(zope.interface.Interface): - """Let's Encrypt user-supplied configuration.""" + """Let's Encrypt user-supplied configuration. + + .. warning:: The values stored in the configuration have not been + filtered, stripped or sanitized in any way! + + """ acme_server = zope.interface.Attribute( "CA hostname (and optionally :port). The server certificate must " diff --git a/letsencrypt/client/tests/configuration_test.py b/letsencrypt/client/tests/configuration_test.py new file mode 100644 index 000000000..8e4a9def1 --- /dev/null +++ b/letsencrypt/client/tests/configuration_test.py @@ -0,0 +1,33 @@ +"""Tests for letsencrypt.client.configuration.""" +import functools +import unittest + +import mock + + +class NamespaceConfigTest(unittest.TestCase): + """Tests for letsencrypt.client.configuration.NamespaceConfig.""" + + def setUp(self): + from letsencrypt.client.configuration import NamespaceConfig + namespace = mock.MagicMock(work_dir='/tmp/foo', foo='bar') + self.config = NamespaceConfig(namespace) + + def test_proxy_getattr(self): + self.assertEqual(self.config.foo, 'bar') + self.assertEqual(self.config.work_dir, '/tmp/foo') + + @mock.patch('letsencrypt.client.configuration.constants') + def test_dynamic_dirs(self, constants): + constants.TEMP_CHECKPOINT_DIR = 't' + constants.IN_PROGRESS_DIR = '../p' + constants.CERT_KEY_BACKUP_DIR = 'c/' + constants.REV_TOKENS_DIR = '/r' + self.assertEqual(self.config.temp_checkpoint_dir, '/tmp/foo/t') + self.assertEqual(self.config.in_progress_dir, '/tmp/foo/../p') + self.assertEqual(self.config.cert_key_backup, '/tmp/foo/c/') + self.assertEqual(self.config.rev_tokens_dir, '/r') + + +if __name__ == '__main__': + unittest.main()