diff --git a/letsencrypt-apache/letsencrypt_apache/parser.py b/letsencrypt-apache/letsencrypt_apache/parser.py
index a0bc6fd12..48234bfe5 100644
--- a/letsencrypt-apache/letsencrypt_apache/parser.py
+++ b/letsencrypt-apache/letsencrypt_apache/parser.py
@@ -126,7 +126,7 @@ class ApacheParser(object):
return stdout
- def _filter_args_num(self, matches, args): # pylint: disable=no-self-use
+ def filter_args_num(self, matches, args): # pylint: disable=no-self-use
"""Filter out directives with specific number of arguments.
This function makes the assumption that all related arguments are given
@@ -142,16 +142,16 @@ class ApacheParser(object):
"""
filtered = []
if args == 1:
- for i in range(matches):
+ for i in range(len(matches)):
if matches[i].endswith("/arg"):
filtered.append(matches[i][:-4])
else:
- for i in range(matches):
- if matches[i].endswith("/arg[%d]", args):
+ for i in range(len(matches)):
+ if matches[i].endswith("/arg[%d]" % args):
# Make sure we don't cause an IndexError (end of list)
# Check to make sure arg + 1 doesn't exist
if (i == (len(matches) - 1) or
- not matches[i + 1].endswith("/arg[%d]" % args + 1)):
+ not matches[i + 1].endswith("/arg[%d]" % (args + 1))):
filtered.append(matches[i][:-len("/arg[%d]" % args)])
return filtered
@@ -340,11 +340,16 @@ class ApacheParser(object):
while last_match_idx != -1:
# Check args
end_of_if = match_l.find("/", last_match_idx)
+ # This should be aug.get (vars are not used e.g. parser.aug_get)
expression = self.aug.get(match[:end_of_if] + "/arg")
- expected = not expression.startswith("!")
- if expected != (expression in filter_[1]):
- return False
+ if expression.startswith("!"):
+ # Strip off "!"
+ if expression[1:] in filter_[1]:
+ return False
+ else:
+ if expression not in filter_[1]:
+ return False
last_match_idx = match_l.find(filter_[0], end_of_if)
diff --git a/letsencrypt-apache/letsencrypt_apache/tests/complex_parsing_test.py b/letsencrypt-apache/letsencrypt_apache/tests/complex_parsing_test.py
new file mode 100644
index 000000000..7281061e4
--- /dev/null
+++ b/letsencrypt-apache/letsencrypt_apache/tests/complex_parsing_test.py
@@ -0,0 +1,101 @@
+"""Tests for letsencrypt_apache.parser."""
+import os
+import shutil
+import unittest
+
+from letsencrypt_apache.tests import util
+
+
+class ComplexParserTest(util.ParserTest):
+ """Apache Parser Test."""
+
+ def setUp(self): # pylint: disable=arguments-differ
+ super(ComplexParserTest, self).setUp(
+ "complex_parsing", "complex_parsing")
+
+ self.setup_variables()
+ # This needs to happen after due to setup_variables not being run
+ # until after
+ self.parser._init_modules() # pylint: disable=protected-access
+
+ def tearDown(self):
+ shutil.rmtree(self.temp_dir)
+ shutil.rmtree(self.config_dir)
+ shutil.rmtree(self.work_dir)
+
+ def setup_variables(self):
+ """Set up variables for parser."""
+ self.parser.variables.update(
+ {
+ "COMPLEX": "",
+ "tls_port": "1234",
+ "fnmatch_filename": "test_fnmatch.conf",
+ }
+ )
+
+ def test_filter_args_num(self):
+ matches = self.parser.find_dir("TestArgsDirective")
+
+ self.assertEqual(len(self.parser.filter_args_num(matches, 1)), 3)
+ self.assertEqual(len(self.parser.filter_args_num(matches, 2)), 2)
+ self.assertEqual(len(self.parser.filter_args_num(matches, 3)), 1)
+
+ def test_basic_variable_parsing(self):
+ matches = self.parser.find_dir("TestVariablePort")
+
+ self.assertEqual(len(matches), 1)
+ self.assertEqual(self.parser.get_arg(matches[0]), "1234")
+
+ def test_basic_ifdefine(self):
+ self.assertEqual(len(self.parser.find_dir("VAR_DIRECTIVE")), 2)
+ self.assertEqual(len(self.parser.find_dir("INVALID_VAR_DIRECTIVE")), 0)
+
+ def test_basic_ifmodule(self):
+ self.assertEqual(len(self.parser.find_dir("MOD_DIRECTIVE")), 2)
+ self.assertEqual(
+ len(self.parser.find_dir("INVALID_MOD_DIRECTIVE")), 0)
+
+ def test_nested(self):
+ self.assertEqual(len(self.parser.find_dir("NESTED_DIRECTIVE")), 3)
+ self.assertEqual(
+ len(self.parser.find_dir("INVALID_NESTED_DIRECTIVE")), 0)
+
+
+ def test_load_modules(self):
+ """If only first is found, there is bad variable parsing."""
+ self.assertTrue("status_module" in self.parser.modules)
+ self.assertTrue("mod_status.c" in self.parser.modules)
+
+ # This is in an IfDefine
+ self.assertTrue("ssl_module" in self.parser.modules)
+ self.assertTrue("mod_ssl.c" in self.parser.modules)
+
+ def verify_fnmatch(self, arg, hit=True):
+ """Test if Include was correctly parsed."""
+ from letsencrypt_apache import parser
+ self.parser.add_dir(parser.get_aug_path(self.parser.loc["default"]),
+ "Include", [arg])
+ if hit:
+ self.assertTrue(self.parser.find_dir("FNMATCH_DIRECTIVE"))
+ else:
+ self.assertFalse(self.parser.find_dir("FNMATCH_DIRECTIVE"))
+
+ def test_include(self):
+ self.verify_fnmatch("test_fnmatch.?onf")
+
+ def test_include_complex(self):
+ self.verify_fnmatch("../complex_parsing/[te][te]st_*.?onf")
+
+ def test_include_fullpath(self):
+ self.verify_fnmatch(os.path.join(self.config_path, "test_fnmatch.conf"))
+
+ def test_include_variable(self):
+ self.verify_fnmatch("../complex_parsing/${fnmatch_filename}")
+
+ def test_include_missing(self):
+ # This should miss
+ self.verify_fnmatch("test_*.onf", False)
+
+
+if __name__ == "__main__":
+ unittest.main() # pragma: no cover
diff --git a/letsencrypt-apache/letsencrypt_apache/tests/configurator_test.py b/letsencrypt-apache/letsencrypt_apache/tests/configurator_test.py
index 111e82a2d..e68b21945 100644
--- a/letsencrypt-apache/letsencrypt_apache/tests/configurator_test.py
+++ b/letsencrypt-apache/letsencrypt_apache/tests/configurator_test.py
@@ -22,7 +22,7 @@ from letsencrypt_apache.tests import util
class TwoVhost80Test(util.ApacheTest):
"""Test two standard well-configured HTTP vhosts."""
- def setUp(self):
+ def setUp(self): # pylint: disable=arguments-differ
super(TwoVhost80Test, self).setUp()
self.config = util.get_apache_configurator(
@@ -137,6 +137,18 @@ class TwoVhost80Test(util.ApacheTest):
self.assertEqual(configurator.get_file_path(loc_chain[0]),
self.vh_truth[1].filep)
+ def test_deploy_cert_invalid_vhost(self):
+ self.config.parser.modules.add("ssl_module")
+ mock_find = mock.MagicMock()
+ mock_find.return_value = []
+ self.config.parser.find_dir = mock_find
+
+ # Get the default 443 vhost
+ self.config.assoc["random.demo"] = self.vh_truth[1]
+ self.assertRaises(
+ errors.PluginError, self.config.deploy_cert, "random.demo",
+ "example/cert.pem", "example/key.pem", "example/cert_chain.pem")
+
def test_is_name_vhost(self):
addr = obj.Addr.fromstring("*:80")
self.assertTrue(self.config.is_name_vhost(addr))
@@ -148,6 +160,19 @@ class TwoVhost80Test(util.ApacheTest):
self.assertTrue(self.config.parser.find_dir(
"NameVirtualHost", "*:443"))
+ def test_prepare_server_https(self):
+ self.config.parser.modules.add("ssl_module")
+ mock_find = mock.Mock()
+ mock_add_dir = mock.Mock()
+ mock_find.return_value = []
+
+ # This will test the Add listen
+ self.config.parser.find_dir = mock_find
+ self.config.parser.add_dir_to_ifmodssl = mock_add_dir
+
+ self.config.prepare_server_https("443")
+ self.assertTrue(mock_add_dir.called)
+
def test_make_vhost_ssl(self):
ssl_vhost = self.config.make_vhost_ssl(self.vh_truth[0])
diff --git a/letsencrypt-apache/letsencrypt_apache/tests/dvsni_test.py b/letsencrypt-apache/letsencrypt_apache/tests/dvsni_test.py
index b6f9bc5e0..b0aec4f8a 100644
--- a/letsencrypt-apache/letsencrypt_apache/tests/dvsni_test.py
+++ b/letsencrypt-apache/letsencrypt_apache/tests/dvsni_test.py
@@ -17,7 +17,7 @@ class DvsniPerformTest(util.ApacheTest):
achalls = common_test.DvsniTest.achalls
- def setUp(self):
+ def setUp(self): # pylint: disable=arguments-differ
super(DvsniPerformTest, self).setUp()
config = util.get_apache_configurator(
diff --git a/letsencrypt-apache/letsencrypt_apache/tests/parser_test.py b/letsencrypt-apache/letsencrypt_apache/tests/parser_test.py
index 3a74055ad..49575e977 100644
--- a/letsencrypt-apache/letsencrypt_apache/tests/parser_test.py
+++ b/letsencrypt-apache/letsencrypt_apache/tests/parser_test.py
@@ -1,34 +1,21 @@
"""Tests for letsencrypt_apache.parser."""
import os
import shutil
-import sys
import unittest
import augeas
import mock
-import zope.component
from letsencrypt import errors
-from letsencrypt.display import util as display_util
from letsencrypt_apache.tests import util
-class ApacheParserTest(util.ApacheTest):
+class BasicParserTest(util.ParserTest):
"""Apache Parser Test."""
- def setUp(self):
- super(ApacheParserTest, self).setUp()
-
- zope.component.provideUtility(display_util.FileDisplay(sys.stdout))
-
- from letsencrypt_apache.parser import ApacheParser
- self.aug = augeas.Augeas(
- flags=augeas.Augeas.NONE | augeas.Augeas.NO_MODL_AUTOLOAD)
- with mock.patch("letsencrypt_apache.parser.ApacheParser."
- "update_runtime_variables"):
- self.parser = ApacheParser(
- self.aug, self.config_path, self.ssl_options, "dummy_ctl_path")
+ def setUp(self): # pylint: disable=arguments-differ
+ super(BasicParserTest, self).setUp()
def tearDown(self):
shutil.rmtree(self.temp_dir)
@@ -61,6 +48,10 @@ class ApacheParserTest(util.ApacheTest):
self.assertEqual(len(test), 1)
self.assertEqual(len(test2), 3)
+ def test_filter_args_num(self):
+ # TODO: TEST 2, TEST 1
+ pass
+
def test_add_dir(self):
aug_default = "/files" + self.parser.loc["default"]
self.parser.add_dir(aug_default, "AddDirective", "test")
@@ -115,7 +106,7 @@ class ApacheParserTest(util.ApacheTest):
class ParserInitTest(util.ApacheTest):
- def setUp(self):
+ def setUp(self): # pylint: disable=arguments-differ
super(ParserInitTest, self).setUp()
self.aug = augeas.Augeas(
flags=augeas.Augeas.NONE | augeas.Augeas.NO_MODL_AUTOLOAD)
diff --git a/letsencrypt-apache/letsencrypt_apache/tests/testdata/complex_parsing/apache2.conf b/letsencrypt-apache/letsencrypt_apache/tests/testdata/complex_parsing/apache2.conf
index a1f4e05fc..b7b6a9be2 100644
--- a/letsencrypt-apache/letsencrypt_apache/tests/testdata/complex_parsing/apache2.conf
+++ b/letsencrypt-apache/letsencrypt_apache/tests/testdata/complex_parsing/apache2.conf
@@ -46,8 +46,8 @@ IncludeOptional sites-enabled/*.conf
Define COMPLEX
Define tls_port 1234
-Define example_path1 Documents/root
+Define fnmatch_filename test_fnmatch.conf
-Include test.conf
+Include test_variables.conf
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
diff --git a/letsencrypt-apache/letsencrypt_apache/tests/testdata/complex_parsing/conf-enabled/dummy.conf b/letsencrypt-apache/letsencrypt_apache/tests/testdata/complex_parsing/conf-enabled/dummy.conf
new file mode 100644
index 000000000..1e5307780
--- /dev/null
+++ b/letsencrypt-apache/letsencrypt_apache/tests/testdata/complex_parsing/conf-enabled/dummy.conf
@@ -0,0 +1,9 @@
+# 3 - one arg directives
+# 2 - two arg directives
+# 1 - three arg directives
+TestArgsDirective one_arg
+TestArgsDirective one_arg two_arg
+TestArgsDirective one_arg
+TestArgsDirective one_arg two_arg
+TestArgsDirective one_arg two_arg three_arg
+TestArgsDirective one_arg
diff --git a/letsencrypt-apache/letsencrypt_apache/tests/testdata/complex_parsing/test.conf b/letsencrypt-apache/letsencrypt_apache/tests/testdata/complex_parsing/test.conf
deleted file mode 100644
index f724756d5..000000000
--- a/letsencrypt-apache/letsencrypt_apache/tests/testdata/complex_parsing/test.conf
+++ /dev/null
@@ -1 +0,0 @@
-TESTDIRECTIVE ${tls_port}
diff --git a/letsencrypt-apache/letsencrypt_apache/tests/testdata/complex_parsing/test_fnmatch.conf b/letsencrypt-apache/letsencrypt_apache/tests/testdata/complex_parsing/test_fnmatch.conf
new file mode 100644
index 000000000..4e6b84edf
--- /dev/null
+++ b/letsencrypt-apache/letsencrypt_apache/tests/testdata/complex_parsing/test_fnmatch.conf
@@ -0,0 +1 @@
+FNMATCH_DIRECTIVE Success
diff --git a/letsencrypt-apache/letsencrypt_apache/tests/testdata/complex_parsing/test_variables.conf b/letsencrypt-apache/letsencrypt_apache/tests/testdata/complex_parsing/test_variables.conf
new file mode 100644
index 000000000..a38191837
--- /dev/null
+++ b/letsencrypt-apache/letsencrypt_apache/tests/testdata/complex_parsing/test_variables.conf
@@ -0,0 +1,65 @@
+TestVariablePort ${tls_port}
+
+LoadModule status_module modules/mod_status.so
+
+# Basic IfDefine
+
+ VAR_DIRECTIVE success
+ LoadModule ssl_module modules/mod_ssl.so
+
+
+
+ INVALID_VAR_DIRECTIVE failure
+
+
+
+ INVALID_VAR_DIRECTIVE failure
+
+
+
+ VAR_DIRECTIVE failure
+
+
+
+# Basic IfModule
+
+ MOD_DIRECTIVE Success
+
+
+
+ INVALID_MOD_DIRECTIVE failure
+
+
+
+ INVALID_MOD_DIRECTIVE failure
+
+
+
+ MOD_DIRECTIVE Success
+
+
+# Nested Tests
+
+
+ NESTED_DIRECTIVE success
+
+
+ NESTED_DIRECTIVE success
+
+
+
+ INVALID_NESTED_DIRECTIVE failure
+
+
+
+
+ INVALID_NESTED_DIRECTIVE failure
+
+
+ INVALID_NESTED_DIRECTIVE failure
+
+
+
+ NESTED_DIRECTIVE success
+
+
diff --git a/letsencrypt-apache/letsencrypt_apache/tests/util.py b/letsencrypt-apache/letsencrypt_apache/tests/util.py
index ae2f25b9f..8b54b08a4 100644
--- a/letsencrypt-apache/letsencrypt_apache/tests/util.py
+++ b/letsencrypt-apache/letsencrypt_apache/tests/util.py
@@ -1,9 +1,14 @@
"""Common utilities for letsencrypt_apache."""
import os
import pkg_resources
+import sys
import unittest
+import augeas
import mock
+import zope.component
+
+from letsencrypt.display import util as display_util
from letsencrypt.plugins import common
@@ -14,19 +19,20 @@ from letsencrypt_apache import obj
class ApacheTest(unittest.TestCase): # pylint: disable=too-few-public-methods
- def setUp(self):
+ def setUp(self, test_dir="debian_apache_2_4/two_vhost_80",
+ config_root="debian_apache_2_4/two_vhost_80/apache2"):
+ # pylint: disable=arguments-differ
super(ApacheTest, self).setUp()
self.temp_dir, self.config_dir, self.work_dir = common.dir_setup(
- test_dir="debian_apache_2_4/two_vhost_80",
+ test_dir=test_dir,
pkg="letsencrypt_apache.tests")
self.ssl_options = common.setup_ssl_options(
self.config_dir, constants.MOD_SSL_CONF_SRC,
constants.MOD_SSL_CONF_DEST)
- self.config_path = os.path.join(
- self.temp_dir, "debian_apache_2_4/two_vhost_80/apache2")
+ self.config_path = os.path.join(self.temp_dir, config_root)
self.rsa256_file = pkg_resources.resource_filename(
"letsencrypt.tests", os.path.join("testdata", "rsa256_key.pem"))
@@ -34,6 +40,23 @@ class ApacheTest(unittest.TestCase): # pylint: disable=too-few-public-methods
"letsencrypt.tests", os.path.join("testdata", "rsa256_key.pem"))
+class ParserTest(ApacheTest): # pytlint: disable=too-few-public-methods
+
+ def setUp(self, test_dir="debian_apache_2_4/two_vhost_80",
+ config_root="debian_apache_2_4/two_vhost_80/apache2"):
+ super(ParserTest, self).setUp(test_dir, config_root)
+
+ zope.component.provideUtility(display_util.FileDisplay(sys.stdout))
+
+ from letsencrypt_apache.parser import ApacheParser
+ self.aug = augeas.Augeas(
+ flags=augeas.Augeas.NONE | augeas.Augeas.NO_MODL_AUTOLOAD)
+ with mock.patch("letsencrypt_apache.parser.ApacheParser."
+ "update_runtime_variables"):
+ self.parser = ApacheParser(
+ self.aug, self.config_path, self.ssl_options, "dummy_ctl_path")
+
+
def get_apache_configurator(
config_path, config_dir, work_dir, version=(2, 4, 7), conf=None):
"""Create an Apache Configurator with the specified options.