From 4f3bf3d720c737c6eaa6fad4683d7a0f469948b0 Mon Sep 17 00:00:00 2001 From: yan Date: Tue, 7 Apr 2015 14:57:37 -0700 Subject: [PATCH] Add test for recursive file parsing --- letsencrypt/client/plugins/nginx/parser.py | 23 +++- .../client/plugins/nginx/tests/parser_test.py | 123 ++++++++++++++++++ .../tests/testdata/sites-enabled/default | 9 ++ .../tests/testdata/sites-enabled/example.com | 4 + .../client/plugins/nginx/tests/util.py | 10 +- 5 files changed, 161 insertions(+), 8 deletions(-) create mode 100644 letsencrypt/client/plugins/nginx/tests/parser_test.py create mode 100644 letsencrypt/client/plugins/nginx/tests/testdata/sites-enabled/default create mode 100644 letsencrypt/client/plugins/nginx/tests/testdata/sites-enabled/example.com diff --git a/letsencrypt/client/plugins/nginx/parser.py b/letsencrypt/client/plugins/nginx/parser.py index f8a21d72b..6fd6f381d 100644 --- a/letsencrypt/client/plugins/nginx/parser.py +++ b/letsencrypt/client/plugins/nginx/parser.py @@ -37,7 +37,10 @@ class NginxParser(object): .. todo:: Can Nginx 'virtual hosts' be defined somewhere other than in the server context? + :param str filepath: The path to the files to parse, as a glob + """ + filepath = self.abs_path(filepath) trees = self._parse_files(filepath) for tree in trees: for entry in tree: @@ -56,6 +59,20 @@ class NginxParser(object): if self._is_include_directive(server_entry): self._parse_recursively(server_entry[1]) + def abs_path(self, path): + """Converts a relative path to an absolute path relative to the root. + Does nothing for paths that are already absolute. + + :param str path: The path + :returns: The absolute path + :rtype str + + """ + if not os.path.isabs(path): + return os.path.join(self.root, path) + else: + return path + def _is_include_directive(self, entry): """Checks if an nginx parsed entry is an 'include' directive. @@ -339,7 +356,7 @@ class NginxParser(object): return regex def _parse_files(self, filepath): - """Parse file + """Parse files from a glob :param str filepath: Nginx config file path :returns: list of parsed tree structures @@ -356,7 +373,7 @@ class NginxParser(object): self.parsed[f] = parsed trees.append(parsed) except IOError: - logging.warn("Could not parse file: %s" % f) + logging.warn("Could not open file: %s" % f) except pyparsing.ParseException: logging.warn("Could not parse file: %s" % f) return trees @@ -390,7 +407,7 @@ class NginxParser(object): """ root = self._find_config_root() - default = os.path.join(self.root, 'nginx.conf') + default = root temp = os.path.join(self.root, "ports.conf") if os.path.isfile(temp): diff --git a/letsencrypt/client/plugins/nginx/tests/parser_test.py b/letsencrypt/client/plugins/nginx/tests/parser_test.py new file mode 100644 index 000000000..c3c809521 --- /dev/null +++ b/letsencrypt/client/plugins/nginx/tests/parser_test.py @@ -0,0 +1,123 @@ +"""Tests for letsencrypt.client.plugins.nginx.parser.""" +import os +import shutil +import sys +import unittest + +import mock +import zope.component + +from letsencrypt.client import errors +from letsencrypt.client.display import util as display_util + +from letsencrypt.client.plugins.nginx.parser import NginxParser +from letsencrypt.client.plugins.nginx.tests import util + + +class NginxParserTest(util.NginxTest): + """Nginx Parser Test.""" + + def setUp(self): + super(NginxParserTest, self).setUp() + + self.maxDiff = None + zope.component.provideUtility(display_util.FileDisplay(sys.stdout)) + + def tearDown(self): + shutil.rmtree(self.temp_dir) + shutil.rmtree(self.config_dir) + shutil.rmtree(self.work_dir) + + def test_root_normalized(self): + path = os.path.join(self.temp_dir, "debian_nginx_2_4/////" + "two_vhost_80/../../testdata") + parser = NginxParser(path, None) + self.assertEqual(parser.root, self.config_path) + + def test_root_absolute(self): + parser = NginxParser(os.path.relpath(self.config_path), None) + self.assertEqual(parser.root, self.config_path) + + def test_root_no_trailing_slash(self): + parser = NginxParser(self.config_path + os.path.sep, None) + self.assertEqual(parser.root, self.config_path) + + def test_parse(self): + """Test recursive conf file parsing. + + """ + self.parser = NginxParser(self.config_path, self.ssl_options) + self.assertEqual(set(map(self.parser.abs_path, + ['foo.conf', 'nginx.conf', 'server.conf', + 'sites-enabled/default', + 'sites-enabled/example.com'])), + set(self.parser.parsed.keys())) + self.assertEqual([['server_name', 'somename alias another.alias']], + self.parser.parsed[self.parser.abs_path( + 'server.conf')]) + self.assertEqual([[['server'], [['listen', '9000'], + ['server_name', 'example.com']]]], + self.parser.parsed[self.parser.abs_path( + 'sites-enabled/example.com')]) + +# def test_find_dir(self): +# from letsencrypt.client.plugins.nginx.parser import case_i +# test = self.parser.find_dir(case_i("Listen"), "443") +# # This will only look in enabled hosts +# test2 = self.parser.find_dir(case_i("documentroot")) +# self.assertEqual(len(test), 2) +# self.assertEqual(len(test2), 3) +# +# def test_add_dir(self): +# aug_default = "/files" + self.parser.loc["default"] +# self.parser.add_dir(aug_default, "AddDirective", "test") +# +# self.assertTrue( +# self.parser.find_dir("AddDirective", "test", aug_default)) +# +# self.parser.add_dir(aug_default, "AddList", ["1", "2", "3", "4"]) +# matches = self.parser.find_dir("AddList", None, aug_default) +# for i, match in enumerate(matches): +# self.assertEqual(self.parser.aug.get(match), str(i + 1)) +# +# def test_add_dir_to_ifmodssl(self): +# """test add_dir_to_ifmodssl. +# +# Path must be valid before attempting to add to augeas +# +# """ +# from letsencrypt.client.plugins.nginx.parser import get_aug_path +# self.parser.add_dir_to_ifmodssl( +# get_aug_path(self.parser.loc["default"]), +# "FakeDirective", "123") +# +# matches = self.parser.find_dir("FakeDirective", "123") +# +# self.assertEqual(len(matches), 1) +# self.assertTrue("IfModule" in matches[0]) +# +# def test_get_aug_path(self): +# from letsencrypt.client.plugins.nginx.parser import get_aug_path +# self.assertEqual("/files/etc/nginx", get_aug_path("/etc/nginx")) +# +# def test_set_locations(self): +# with mock.patch("letsencrypt.client.plugins.nginx.parser." +# "os.path") as mock_path: +# +# mock_path.isfile.return_value = False +# +# # pylint: disable=protected-access +# self.assertRaises(errors.LetsEncryptConfiguratorError, +# self.parser._set_locations, self.ssl_options) +# +# mock_path.isfile.side_effect = [True, False, False] +# +# # pylint: disable=protected-access +# results = self.parser._set_locations(self.ssl_options) +# +# self.assertEqual(results["default"], results["listen"]) +# self.assertEqual(results["default"], results["name"]) + + +if __name__ == "__main__": + unittest.main() diff --git a/letsencrypt/client/plugins/nginx/tests/testdata/sites-enabled/default b/letsencrypt/client/plugins/nginx/tests/testdata/sites-enabled/default new file mode 100644 index 000000000..29a311cee --- /dev/null +++ b/letsencrypt/client/plugins/nginx/tests/testdata/sites-enabled/default @@ -0,0 +1,9 @@ +server { + listen 1234; + server_name example.org; + + location / { + root html; + index index.html index.htm; + } +} diff --git a/letsencrypt/client/plugins/nginx/tests/testdata/sites-enabled/example.com b/letsencrypt/client/plugins/nginx/tests/testdata/sites-enabled/example.com new file mode 100644 index 000000000..d61f8a698 --- /dev/null +++ b/letsencrypt/client/plugins/nginx/tests/testdata/sites-enabled/example.com @@ -0,0 +1,4 @@ +server { + listen 9000; + server_name example.com; +} diff --git a/letsencrypt/client/plugins/nginx/tests/util.py b/letsencrypt/client/plugins/nginx/tests/util.py index 975360d6c..e8467502e 100644 --- a/letsencrypt/client/plugins/nginx/tests/util.py +++ b/letsencrypt/client/plugins/nginx/tests/util.py @@ -18,12 +18,12 @@ class NginxTest(unittest.TestCase): # pylint: disable=too-few-public-methods super(NginxTest, self).setUp() self.temp_dir, self.config_dir, self.work_dir = dir_setup( - "debian_nginx_2_4/two_vhost_80") + "testdata") self.ssl_options = setup_nginx_ssl_options(self.config_dir) self.config_path = os.path.join( - self.temp_dir, "debian_nginx_2_4/two_vhost_80/nginx2") + self.temp_dir, "testdata") self.rsa256_file = pkg_resources.resource_filename( "letsencrypt.client.tests", "testdata/rsa256_key.pem") @@ -36,14 +36,14 @@ def get_data_filename(filename): "letsencrypt.client.plugins.nginx.tests", "testdata/%s" % filename) -def dir_setup(test_dir="debian_nginx_2_4/two_vhost_80"): +def dir_setup(test_dir="debian_nginx/two_vhost_80"): """Setup the directories necessary for the configurator.""" temp_dir = tempfile.mkdtemp("temp") config_dir = tempfile.mkdtemp("config") work_dir = tempfile.mkdtemp("work") test_configs = pkg_resources.resource_filename( - "letsencrypt.client.plugins.nginx.tests", "testdata/%s" % test_dir) + "letsencrypt.client.plugins.nginx.tests", test_dir) shutil.copytree( test_configs, os.path.join(temp_dir, test_dir), symlinks=True) @@ -54,7 +54,7 @@ def dir_setup(test_dir="debian_nginx_2_4/two_vhost_80"): def setup_nginx_ssl_options(config_dir): """Move the ssl_options into position and return the path.""" option_path = os.path.join(config_dir, "options-ssl.conf") - shutil.copyfile(constants.APACHE_MOD_SSL_CONF, option_path) + shutil.copyfile(constants.NGINX_MOD_SSL_CONF, option_path) return option_path