Refactored/added tests

This commit is contained in:
James Kasten 2014-12-19 15:49:29 -08:00
parent 083024cb86
commit cc999d3654
14 changed files with 362 additions and 201 deletions

View file

@ -67,7 +67,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
with the configuration
:ivar float version: version of Apache
:ivar list vhosts: All vhosts found in the configuration
(:class:`list` of :class:`letsencrypt.client.apache.obj.VH`)
(:class:`list` of :class:`letsencrypt.client.apache.obj.VirtualHost`)
:ivar dict assoc: Mapping between domains and vhosts
@ -97,7 +97,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
super(ApacheConfigurator, self).__init__(direc)
# See if any temporary changes need to be recovered
# This needs to occur before VH objects are setup...
# This needs to occur before VirtualHost objects are setup...
# because this will change the underlying configuration and potential
# vhosts
self.recovery_routine()
@ -145,7 +145,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
This shouldn't happen within letsencrypt though
:param vhost: ssl vhost to deploy certificate
:type vhost: :class:`letsencrypt.client.apache.obj.VH`
:type vhost: :class:`letsencrypt.client.apache.obj.VirtualHost`
:param str cert: certificate filename
:param str key: private key filename
@ -204,7 +204,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
:param str name: domain name
:returns: ssl vhost associated with name
:rtype: :class:`letsencrypt.client.apache.obj.VH`
:rtype: :class:`letsencrypt.client.apache.obj.VirtualHost`
"""
# Allows for domain names to be associated with a virtual host
@ -242,7 +242,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
:param str domain: domain name to associate
:param vhost: virtual host to associate with domain
:type vhost: :class:`letsencrypt.client.apache.obj.VH`
:type vhost: :class:`letsencrypt.client.apache.obj.VirtualHost`
"""
self.assoc[domain] = vhost
@ -279,7 +279,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
"""Helper function for get_virtual_hosts().
:param host: In progress vhost whose names will be added
:type host: :class:`letsencrypt.client.apache.obj.VH`
:type host: :class:`letsencrypt.client.apache.obj.VirtualHost`
"""
name_match = self.aug.match(("%s//*[self::directive=~regexp('%s')] | "
@ -300,7 +300,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
:param str path: Augeas path to virtual host
:returns: newly created vhost
:rtype: :class:`letsencrypt.client.apache.obj.VH`
:rtype: :class:`letsencrypt.client.apache.obj.VirtualHost`
"""
addrs = set()
@ -315,7 +315,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
filename = get_file_path(path)
is_enabled = self.is_site_enabled(filename)
vhost = obj.VH(filename, path, addrs, is_ssl, is_enabled)
vhost = obj.VirtualHost(filename, path, addrs, is_ssl, is_enabled)
self._add_servernames(vhost)
return vhost
@ -323,7 +323,8 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
def get_virtual_hosts(self):
"""Returns list of virtual hosts found in the Apache configuration.
:returns: List of :class:`letsencrypt.client.apache.obj.VH` objects
:returns: List of
:class:`letsencrypt.client.apache.obj.VirtualHost` objects
found in configuration
:rtype: list
@ -400,8 +401,8 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
def make_server_sni_ready(self, vhost, default_addr="*:443"):
"""Checks to see if the server is ready for SNI challenges.
:param vhost: VHost to check SNI compatibility
:type vhost: :class:`letsencrypt.client.apache.obj.VH`
:param vhost: VirtualHostost to check SNI compatibility
:type vhost: :class:`letsencrypt.client.apache.obj.VirtualHost`
:param str default_addr: TODO - investigate function further
@ -431,10 +432,10 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
New vhost will reside as (nonssl_vhost.path) + CONFIG.LE_VHOST_EXT
:param nonssl_vhost: Valid VH that doesn't have SSLEngine on
:type nonssl_vhost: :class:`letsencrypt.client.apache.obj.VH`
:type nonssl_vhost: :class:`letsencrypt.client.apache.obj.VirtualHost`
:returns: SSL vhost
:rtype: :class:`letsencrypt.client.apache.obj.VH`
:rtype: :class:`letsencrypt.client.apache.obj.VirtualHost`
"""
avail_fp = nonssl_vhost.filep
@ -472,11 +473,11 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
addr_match % (ssl_fp, parser.case_i('VirtualHost')))
for i in range(len(ssl_addr_p)):
ssl_addr_arg = obj.Addr.fromstring(
old_addr = obj.Addr.fromstring(
str(self.aug.get(ssl_addr_p[i])))
ssl_addr_arg.set_port("443")
self.aug.set(ssl_addr_p[i], str(ssl_addr_arg))
ssl_addrs.add(ssl_addr_arg)
ssl_addr = old_addr.get_addr_obj("443")
self.aug.set(ssl_addr_p[i], str(ssl_addr))
ssl_addrs.add(ssl_addr)
# Add directives
vh_p = self.aug.match(("/files%s//* [label()=~regexp('%s')]" %
@ -528,10 +529,10 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
The function then adds the directive
:param ssl_vhost: Destination of traffic, an ssl enabled vhost
:type ssl_vhost: :class:`letsencrypt.client.apache.obj.VH`
:type ssl_vhost: :class:`letsencrypt.client.apache.obj.VirtualHost`
:returns: Success, general_vhost (HTTP vhost)
:rtype: (bool, :class:`letsencrypt.client.apache.obj.VH`)
:rtype: (bool, :class:`letsencrypt.client.apache.obj.VirtualHost`)
"""
# TODO: Enable check to see if it is already there
@ -577,7 +578,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
-1 is also returned in case of no redirection/rewrite directives
:param vhost: vhost to check
:type vhost: :class:`letsencrypt.client.apache.obj.VH`
:type vhost: :class:`letsencrypt.client.apache.obj.VirtualHost`
:returns: Success, code value... see documentation
:rtype: bool, int
@ -608,10 +609,10 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
"""Creates an http_vhost specifically to redirect for the ssl_vhost.
:param ssl_vhost: ssl vhost
:type ssl_vhost: :class:`letsencrypt.client.apache.obj.VH`
:type ssl_vhost: :class:`letsencrypt.client.apache.obj.VirtualHost`
:returns: Success, vhost
:rtype: (bool, :class:`letsencrypt.client.apache.obj.VH`)
:rtype: (bool, :class:`letsencrypt.client.apache.obj.VirtualHost`)
"""
# Consider changing this to a dictionary check
@ -694,7 +695,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
if not conflict: returns space separated list of new host addrs
:param ssl_vhost: SSL Vhost to check for possible port 80 redirection
:type ssl_vhost: :class:`letsencrypt.client.apache.obj.VH`
:type ssl_vhost: :class:`letsencrypt.client.apache.obj.VirtualHost`
:returns: TODO
:rtype: TODO
@ -727,10 +728,10 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
Consider changing this into a dict check
:param ssl_vhost: ssl vhost to check
:type ssl_vhost: :class:`letsencrypt.client.apache.obj.VH`
:type ssl_vhost: :class:`letsencrypt.client.apache.obj.VirtualHost`
:returns: HTTP vhost or None if unsuccessful
:rtype: :class:`letsencrypt.client.apache.obj.VH` or None
:rtype: :class:`letsencrypt.client.apache.obj.VirtualHost` or None
"""
# _default_:443 check
@ -826,7 +827,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
.. todo:: Make sure link is not broken...
:param vhost: vhost to enable
:type vhost: :class:`letsencrypt.client.apache.obj.VH`
:type vhost: :class:`letsencrypt.client.apache.obj.VirtualHost`
:returns: Success
:rtype: bool
@ -1048,11 +1049,11 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
shutil.copyfile(dist_conf, CONFIG.OPTIONS_SSL_CONF)
# TODO: Use ip address of existing vhost instead of relying on FQDN
config_text = "<IfModule mod_ssl.c> \n"
config_text = "<IfModule mod_ssl.c>\n"
for idx, lis in enumerate(ll_addrs):
config_text += self.get_config_text(
list_sni_tuple[idx][2], lis, dvsni_key.file)
config_text += "</IfModule> \n"
config_text += "</IfModule>\n"
self.dvsni_conf_include_check(self.parser.loc["default"])
self.register_file_creation(True, CONFIG.APACHE_CHALLENGE_CONF)

View file

@ -2,10 +2,14 @@
class Addr(object):
"""Represents an Apache VirtualHost address."""
def __init__(self, addr):
""":param tuple addr: tuple of strings (ip, port)"""
self.tup = addr
"""Represents an Apache VirtualHost address.
:param str addr: addr part of vhost address
:param str port: port number or *, or ""
"""
def __init__(self, tup):
self.tup = tup
@classmethod
def fromstring(cls, str_addr):
@ -14,25 +18,18 @@ class Addr(object):
return cls((tup[0], tup[2]))
def __str__(self):
if self.tup[1] != "":
return ':'.join(self.tup)
return str(self.tup[0])
if self.tup[1]:
return "%s:%s" % self.tup
return self.tup[0]
def __eq__(self, other):
if isinstance(other, self.__class__):
return self.tup == other.tup
if type(other) is type(self):
return self.__dict__ == other.__dict__
return False
def __hash__(self):
return hash(self.tup)
def set_port(self, port):
"""Set the port of the address.
:param str port: new port
"""
self.tup = (self.tup[0], port)
def get_addr(self):
"""Return addr part of Addr object."""
return self.tup[0]
@ -47,7 +44,7 @@ class Addr(object):
# pylint: disable=too-few-public-methods
class VH(object):
class VirtualHost(object):
"""Represents an Apache Virtualhost.
:ivar str filep: file path of VH
@ -66,7 +63,7 @@ class VH(object):
self.filep = filep
self.path = path
self.addrs = addrs
self.names = set() if names is None else names
self.names = set() if names is None else set(names)
self.ssl = ssl
self.enabled = enabled
@ -75,12 +72,13 @@ class VH(object):
self.names.add(name)
def __str__(self):
addr_str = ", ".join(str(addr) for addr in self.addrs)
return ("file: %s\n"
"vh_path: %s\n"
"addrs: %s\n"
"names: %s\n"
"ssl: %s\n"
"enabled: %s" % (self.filep, self.path, self.addrs,
"enabled: %s" % (self.filep, self.path, addr_str,
self.names, self.ssl, self.enabled))
def __eq__(self, other):

View file

@ -2,6 +2,8 @@
import os
import re
from letsencrypt.client import errors
class ApacheParser(object):
"""Class handles the fine details of parsing the Apache Configuration."""
@ -311,7 +313,7 @@ class ApacheParser(object):
"""
root = self._find_config_root()
default = self._set_user_config_file()
default = self._set_user_config_file(root)
temp = os.path.join(self.root, "ports.conf")
if os.path.isfile(temp):
@ -335,7 +337,7 @@ class ApacheParser(object):
raise errors.LetsEncryptConfiguratorError(
"Could not find configuration root")
def _set_user_config_file(self, filename=''):
def _set_user_config_file(self, root):
"""Set the appropriate user configuration file
.. todo:: This will have to be updated for other distros versions
@ -344,18 +346,15 @@ class ApacheParser(object):
user config
"""
if filename:
return filename
# Basic check to see if httpd.conf exists and
# in heirarchy via direct include
# httpd.conf was very common as a user file in Apache 2.2
if (os.path.isfile(self.root + 'httpd.conf') and
self.find_dir(
case_i("Include"), case_i("httpd.conf"), root)):
return os.path.join(self.root, 'httpd.conf')
else:
# Basic check to see if httpd.conf exists and
# in heirarchy via direct include
# httpd.conf was very common as a user file in Apache 2.2
if (os.path.isfile(self.root + 'httpd.conf') and
self.find_dir(
case_i("Include"), case_i("httpd.conf"))):
return os.path.join(self.root, 'httpd.conf')
else:
return os.path.join(self.root + 'apache2.conf')
return os.path.join(self.root + 'apache2.conf')
def case_i(string):

View file

@ -29,7 +29,6 @@ class AugeasConfigurator(object):
(used mostly for testing)
"""
super(AugeasConfigurator, self).__init__()
if not direc:
direc = {"backup": CONFIG.BACKUP_DIR,

View file

@ -59,18 +59,13 @@ class Client(object):
self.auth = auth
self.installer = installer
def obtain_certificate(self, privkey, csr,
def obtain_certificate(self, csr,
cert_path=CONFIG.CERT_PATH,
chain_path=CONFIG.CHAIN_PATH):
"""Obtains a certificate from the ACME server.
.. todo:: Check for case when privkey is not authkey and adjust
this function accordingly.
:param privkey: A valid private key that corresponds to the csr
:type privkey: :class:`Key`
:param csr: A valid CSR in der format that corresponds to privkey
:param csr: A valid CSR in DER format for the certificate the client
intends to receive.
:type csr: :class:`CSR`
:param str cert_path: Full desired path to end certificate.
@ -699,8 +694,7 @@ def init_key():
def init_csr(privkey, names):
"""Initialize a CSR with the given private key."""
csr_pem, csr_der = crypto_util.make_csr(
privkey.pem, names)
csr_pem, csr_der = crypto_util.make_csr(privkey.pem, names)
# Save CSR
le_util.make_or_verify_dir(CONFIG.CERT_DIR, 0o755)

View file

@ -81,7 +81,6 @@ def sha256(arg):
# based on M2Crypto unit test written by Toby Allsopp
def make_key(bits=CONFIG.RSA_KEY_SIZE):
"""Returns new RSA key in PEM form with specified bits."""
# Python Crypto module doesn't produce any stdout
key = Crypto.PublicKey.RSA.generate(bits)
# rsa = M2Crypto.RSA.gen_key(bits, 65537)

View file

@ -1,5 +1,4 @@
"""Interfaces."""
import zope.interface

View file

@ -1,22 +1,19 @@
"""Test for letsencrypt.client.apache_configurator."""
import os
import pkg_resources
import re
import shutil
import tempfile
import unittest
import mock
from letsencrypt.client import apache_configurator
from letsencrypt.client import CONFIG
from letsencrypt.client import display
from letsencrypt.client import errors
from letsencrypt.client.apache import configurator
from letsencrypt.client.apache import obj
from letsencrypt.client.apache import parser
UBUNTU_CONFIGS = pkg_resources.resource_filename(
__name__, "testdata/debian_apache_2_4")
from letsencrypt.client.tests import config_util
class TwoVhost80Test(unittest.TestCase):
@ -25,102 +22,31 @@ class TwoVhost80Test(unittest.TestCase):
def setUp(self):
display.set_display(display.NcursesDisplay())
self.temp_dir = os.path.join(
tempfile.mkdtemp("temp"), "debian_apache_2_4")
self.config_dir = tempfile.mkdtemp("config")
self.work_dir = tempfile.mkdtemp("work")
self.temp_dir, self.config_dir, self.work_dir = config_util.dir_setup(
"debian_apache_2_4/two_vhost_80")
shutil.copytree(UBUNTU_CONFIGS, self.temp_dir, symlinks=True)
temp_options = pkg_resources.resource_filename(
"letsencrypt.client", os.path.basename(CONFIG.OPTIONS_SSL_CONF))
shutil.copyfile(
temp_options, os.path.join(self.config_dir, "options-ssl.conf"))
self.ssl_options = config_util.setup_apache_ssl_options(self.config_dir)
# Final slash is currently important
self.config_path = os.path.join(self.temp_dir, "two_vhost_80/apache2/")
self.ssl_options = os.path.join(self.config_dir, "options-ssl.conf")
backups = os.path.join(self.work_dir, "backups")
self.config_path = os.path.join(
self.temp_dir, "debian_apache_2_4/two_vhost_80/apache2/")
with mock.patch("letsencrypt.client.apache_configurator."
"subprocess.Popen") as mock_popen:
# This just states that the ssl module is already loaded
mock_popen().communicate.return_value = ("ssl_module", "")
self.config = apache_configurator.ApacheConfigurator(
self.config_path,
{
"backup": backups,
"temp": os.path.join(self.work_dir, "temp_checkpoint"),
"progress": os.path.join(backups, "IN_PROGRESS"),
"config": self.config_dir,
"work": self.work_dir,
},
self.ssl_options,
(2, 4, 7))
self.config = config_util.get_apache_configurator(
self.config_path, self.config_dir, self.work_dir, self.ssl_options)
prefix = os.path.join(
self.temp_dir, "two_vhost_80/apache2/sites-available")
aug_pre = "/files" + prefix
self.vh_truth = [
obj.VH(
os.path.join(prefix, "encryption-example.conf"),
os.path.join(aug_pre, "encryption-example.conf/VirtualHost"),
set([obj.Addr.fromstring("*:80")]),
False, True, set(["encryption-example.demo"])),
obj.VH(
os.path.join(prefix, "default-ssl.conf"),
os.path.join(aug_pre, "default-ssl.conf/IfModule/VirtualHost"),
set([obj.Addr.fromstring("_default_:443")]), True, False),
obj.VH(
os.path.join(prefix, "000-default.conf"),
os.path.join(aug_pre, "000-default.conf/VirtualHost"),
set([obj.Addr.fromstring("*:80")]), False, True,
set(["ip-172-30-0-17"])),
obj.VH(
os.path.join(prefix, "letsencrypt.conf"),
os.path.join(aug_pre, "letsencrypt.conf/VirtualHost"),
set([obj.Addr.fromstring("*:80")]), False, True,
set(["letsencrypt.demo"])),
]
self.vh_truth = config_util.get_vh_truth(
self.temp_dir, "debian_apache_2_4/two_vhost_80")
def tearDown(self):
shutil.rmtree(self.temp_dir)
shutil.rmtree(self.config_dir)
shutil.rmtree(self.work_dir)
def test_parse_file(self):
"""Test parse_file.
letsencrypt.conf is chosen as the test file as it will not be
included during the normal course of execution.
"""
file_path = os.path.join(
self.config_path, "sites-available", "letsencrypt.conf")
# pylint: disable=protected-access
self.config.parser._parse_file(file_path)
# search for the httpd incl
matches = self.config.aug.match(
"/augeas/load/Httpd/incl [. ='%s']" % file_path)
self.assertTrue(matches)
def test_get_all_names(self):
names = self.config.get_all_names()
self.assertEqual(names, set(
['letsencrypt.demo', 'encryption-example.demo', 'ip-172-30-0-17']))
def test_find_dir(self):
test = self.config.parser.find_dir(
parser.case_i("Listen"), "443")
# This will only look in enabled hosts
test2 = self.config.parser.find_dir(
parser.case_i("documentroot"))
self.assertEqual(len(test), 2)
self.assertEqual(len(test2), 3)
def test_get_virtual_hosts(self):
vhs = self.config.get_virtual_hosts()
self.assertEqual(len(vhs), 4)
@ -140,14 +66,6 @@ class TwoVhost80Test(unittest.TestCase):
self.assertTrue(self.config.is_site_enabled(self.vh_truth[2].filep))
self.assertTrue(self.config.is_site_enabled(self.vh_truth[3].filep))
def test_add_dir(self):
aug_default = "/files" + self.config.parser.loc["default"]
self.config.parser.add_dir(
aug_default, "AddDirective", "test")
self.assertTrue(
self.config.parser.find_dir("AddDirective", "test", aug_default))
def test_deploy_cert(self):
self.config.deploy_cert(
self.vh_truth[1],
@ -165,15 +83,15 @@ class TwoVhost80Test(unittest.TestCase):
# Verify one directive was found in the correct file
self.assertEqual(len(loc_cert), 1)
self.assertEqual(apache_configurator.get_file_path(loc_cert[0]),
self.assertEqual(configurator.get_file_path(loc_cert[0]),
self.vh_truth[1].filep)
self.assertEqual(len(loc_key), 1)
self.assertEqual(apache_configurator.get_file_path(loc_key[0]),
self.assertEqual(configurator.get_file_path(loc_key[0]),
self.vh_truth[1].filep)
self.assertEqual(len(loc_chain), 1)
self.assertEqual(apache_configurator.get_file_path(loc_chain[0]),
self.assertEqual(configurator.get_file_path(loc_chain[0]),
self.vh_truth[1].filep)
def test_is_name_vhost(self):
@ -187,21 +105,6 @@ class TwoVhost80Test(unittest.TestCase):
self.assertTrue(self.config.parser.find_dir(
"NameVirtualHost", re.escape("*:443")))
def test_add_dir_to_ifmodssl(self):
"""test add_dir_to_ifmodssl.
Path must be valid before attempting to add to augeas
"""
self.config.parser.add_dir_to_ifmodssl(
parser.get_aug_path(self.config.parser.loc["default"]),
"FakeDirective", "123")
matches = self.config.parser.find_dir("FakeDirective", "123")
self.assertEqual(len(matches), 1)
self.assertTrue("IfModule" in matches[0])
def test_make_vhost_ssl(self):
ssl_vhost = self.config.make_vhost_ssl(self.vh_truth[0])
@ -212,7 +115,8 @@ class TwoVhost80Test(unittest.TestCase):
self.assertEqual(ssl_vhost.path,
"/files" + ssl_vhost.filep + "/IfModule/VirtualHost")
self.assertEqual(ssl_vhost.addrs, set([obj.Addr.fromstring("*:443")]))
self.assertEqual(len(ssl_vhost.addrs), 1)
self.assertTrue(set([obj.Addr.fromstring("*:443")]) == ssl_vhost.addrs)
self.assertEqual(ssl_vhost.names, set(["encryption-example.demo"]))
self.assertTrue(ssl_vhost.ssl)
self.assertFalse(ssl_vhost.enabled)
@ -229,7 +133,7 @@ class TwoVhost80Test(unittest.TestCase):
self.assertEqual(len(self.config.vhosts), 5)
@mock.patch("letsencrypt.client.apache_configurator."
@mock.patch("letsencrypt.client.apache.configurator."
"subprocess.Popen")
def test_get_version(self, mock_popen):
mock_popen().communicate.return_value = (
@ -254,6 +158,5 @@ class TwoVhost80Test(unittest.TestCase):
self.assertRaises(
errors.LetsEncryptConfiguratorError, self.config.get_version)
if __name__ == '__main__':
unittest.main()

View file

@ -0,0 +1,62 @@
import unittest
from letsencrypt.client.apache import obj
class AddrTest(unittest.TestCase):
"""Test the Addr class."""
def setUp(self):
self.addr1 = obj.Addr.fromstring("192.168.1.1")
self.addr2 = obj.Addr.fromstring("192.168.1.1:*")
self.addr3 = obj.Addr.fromstring("192.168.1.1:80")
def test_fromstring(self):
self.assertEqual(self.addr1.get_addr(), "192.168.1.1")
self.assertEqual(self.addr1.get_port(), "")
self.assertEqual(self.addr2.get_addr(), "192.168.1.1")
self.assertEqual(self.addr2.get_port(), "*")
self.assertEqual(self.addr3.get_addr(), "192.168.1.1")
self.assertEqual(self.addr3.get_port(), "80")
def test_str(self):
self.assertEqual(str(self.addr1), "192.168.1.1")
self.assertEqual(str(self.addr2), "192.168.1.1:*")
self.assertEqual(str(self.addr3), "192.168.1.1:80")
def test_get_addr_obj(self):
self.assertEqual(str(self.addr1.get_addr_obj("443")), "192.168.1.1:443")
self.assertEqual(str(self.addr2.get_addr_obj("")), "192.168.1.1")
self.assertEqual(str(self.addr1.get_addr_obj("*")), "192.168.1.1:*")
def test_eq(self):
self.assertEqual(self.addr1, self.addr2.get_addr_obj(""))
self.assertNotEqual(self.addr1, self.addr2)
# This is specifically designed to hit line 28 but coverage denies me
# the satisfaction :(
self.assertNotEqual(self.addr1, 3333)
def test_set_inclusion(self):
set_a = set([self.addr1, self.addr2])
addr1b = obj.Addr.fromstring("192.168.1.1")
addr2b = obj.Addr.fromstring("192.168.1.1:*")
set_b = set([addr1b, addr2b])
self.assertTrue(addr1b in set_a)
self.assertEqual(set_a, set_b)
class VirtualHostTest(unittest.TestCase):
"""Test the VirtualHost class."""
def setUp(self):
self.vhost1 = obj.VirtualHost(
"filep", "vh_path",
set([obj.Addr.fromstring("localhost")]), False, False)
def test_eq(self):
vhost1b = obj.VirtualHost(
"filep", "vh_path",
set([obj.Addr.fromstring("localhost")]), False, False)
self.assertEqual(vhost1b, self.vhost1)
self.assertEqual(str(vhost1b), str(self.vhost1))
self.assertTrue(vhost1b != 1234)

View file

@ -0,0 +1,114 @@
import os
import shutil
import sys
import unittest
import augeas
import mock
from letsencrypt.client import display
from letsencrypt.client import errors
from letsencrypt.client.apache import parser
from letsencrypt.client.tests import config_util
class BasicParseTests(unittest.TestCase):
def setUp(self):
display.set_display(display.FileDisplay(sys.stdout))
self.temp_dir, self.config_dir, self.work_dir = config_util.dir_setup(
"debian_apache_2_4/two_vhost_80")
self.ssl_options = config_util.setup_apache_ssl_options(self.config_dir)
# Final slash is currently important
self.config_path = os.path.join(
self.temp_dir, "debian_apache_2_4/two_vhost_80/apache2/")
self.parser = parser.ApacheParser(
augeas.Augeas(flags=augeas.Augeas.NONE),
self.config_path, self.ssl_options)
def tearDown(self):
shutil.rmtree(self.temp_dir)
shutil.rmtree(self.config_dir)
shutil.rmtree(self.work_dir)
def test_parse_file(self):
"""Test parse_file.
letsencrypt.conf is chosen as the test file as it will not be
included during the normal course of execution.
"""
file_path = os.path.join(
self.config_path, "sites-available", "letsencrypt.conf")
# pylint: disable=protected-access
self.parser._parse_file(file_path)
# search for the httpd incl
matches = self.parser.aug.match(
"/augeas/load/Httpd/incl [. ='%s']" % file_path)
self.assertTrue(matches)
def test_find_dir(self):
test = self.parser.find_dir(
parser.case_i("Listen"), "443")
# This will only look in enabled hosts
test2 = self.parser.find_dir(
parser.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
"""
self.parser.add_dir_to_ifmodssl(
parser.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):
self.assertEqual(
"/files/etc/apache", parser.get_aug_path("/etc/apache"))
def test_set_locations(self):
with mock.patch("letsencrypt.client.apache.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"])

View file

@ -0,0 +1,94 @@
import os
import pkg_resources
import shutil
import tempfile
import mock
from letsencrypt.client import CONFIG
from letsencrypt.client.apache import configurator
from letsencrypt.client.apache import obj
from letsencrypt.client.apache import parser
def dir_setup(test_dir="debian_apache_2_4/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(
__name__, "testdata/%s" % test_dir)
shutil.copytree(
test_configs, os.path.join(temp_dir, test_dir), symlinks=True)
return temp_dir, config_dir, work_dir
def setup_apache_ssl_options(config_dir):
"""Move the ssl_options into position and return the path."""
option_path = os.path.join(config_dir, "options-ssl.conf")
temp_options = pkg_resources.resource_filename(
"letsencrypt.client", os.path.basename(CONFIG.OPTIONS_SSL_CONF))
shutil.copyfile(
temp_options, option_path)
return option_path
def get_apache_configurator(
config_path, config_dir, work_dir, ssl_options, version=(2, 4, 7)):
"""Create an Apache Configurator with the specified options."""
backups = os.path.join(work_dir, "backups")
with mock.patch("letsencrypt.client.apache.configurator."
"subprocess.Popen") as mock_popen:
# This just states that the ssl module is already loaded
mock_popen().communicate.return_value = ("ssl_module", "")
config = configurator.ApacheConfigurator(
config_path,
{
"backup": backups,
"temp": os.path.join(work_dir, "temp_checkpoint"),
"progress": os.path.join(backups, "IN_PROGRESS"),
"config": config_dir,
"work": work_dir,
},
ssl_options,
version)
return config
def get_vh_truth(temp_dir, config_name):
"""Return the ground truth for the specified directory."""
if config_name == "debian_apache_2_4/two_vhost_80":
prefix = os.path.join(
temp_dir, config_name, "apache2/sites-available")
aug_pre = "/files" + prefix
vh_truth = [
obj.VirtualHost(
os.path.join(prefix, "encryption-example.conf"),
os.path.join(aug_pre, "encryption-example.conf/VirtualHost"),
set([obj.Addr.fromstring("*:80")]),
False, True, set(["encryption-example.demo"])),
obj.VirtualHost(
os.path.join(prefix, "default-ssl.conf"),
os.path.join(aug_pre, "default-ssl.conf/IfModule/VirtualHost"),
set([obj.Addr.fromstring("_default_:443")]), True, False),
obj.VirtualHost(
os.path.join(prefix, "000-default.conf"),
os.path.join(aug_pre, "000-default.conf/VirtualHost"),
set([obj.Addr.fromstring("*:80")]), False, True,
set(["ip-172-30-0-17"])),
obj.VirtualHost(
os.path.join(prefix, "letsencrypt.conf"),
os.path.join(aug_pre, "letsencrypt.conf/VirtualHost"),
set([obj.Addr.fromstring("*:80")]), False, True,
set(["letsencrypt.demo"])),
]
return vh_truth
return None

View file

@ -5,9 +5,6 @@ import logging
import os
import sys
import zope.interface
from letsencrypt.client import apache_configurator
from letsencrypt.client import CONFIG
from letsencrypt.client import client
from letsencrypt.client import display
@ -15,6 +12,8 @@ from letsencrypt.client import interfaces
from letsencrypt.client import errors
from letsencrypt.client import log
from letsencrypt.client.apache import configurator
def main():
"""Command line argument parsing and main script execution."""
@ -82,11 +81,11 @@ def main():
display.set_display(display.FileDisplay(sys.stdout))
if args.rollback > 0:
rollback(apache_configurator.ApacheConfigurator(), args.rollback)
rollback(configurator.ApacheConfigurator(), args.rollback)
sys.exit()
if args.view_checkpoints:
view_checkpoints(apache_configurator.ApacheConfigurator())
view_checkpoints(configurator.ApacheConfigurator())
sys.exit()
server = args.server is None and CONFIG.ACME_SERVER or args.server
@ -122,7 +121,7 @@ def main():
# Validate the key and csr
client.validate_key_csr(privkey, csr, domains)
cert_file, chain_file = acme.obtain_certificate(privkey, csr)
cert_file, chain_file = acme.obtain_certificate(csr)
vhost = acme.deploy_certificate(privkey, cert_file, chain_file)
acme.optimize_config(vhost, args.redirect)
@ -176,20 +175,19 @@ def get_all_names(installer):
# This should be controlled by commandline parameters
def determine_authenticator():
"""Returns a valid authenticator."""
try:
return apache_configurator.ApacheConfigurator()
return configurator.ApacheConfigurator()
except errors.LetsEncryptConfiguratorError:
log.info("Unable to find a way to authenticate.")
logging.info("Unable to find a way to authenticate.")
def determine_installer():
"""Returns a valid installer if one exists."""
try:
return apache_configurator.ApacheConfigurator()
print "shouldn't ha;ppppen!!!!!!!!!!!!!!!!!!!"
return configurator.ApacheConfigurator()
except errors.LetsEncryptConfiguratorError:
log.info("Unable to find a way to install the certificate.")
logging.info("Unable to find a way to install the certificate.")
def read_file(filename):

View file

@ -37,6 +37,7 @@ setup(
'letsencrypt',
'letsencrypt.client',
'letsencrypt.client.apache',
'letsencrypt.client.tests',
'letsencrypt.scripts',
],
install_requires=install_requires,

View file

@ -14,7 +14,7 @@ commands =
[testenv:cover]
commands =
python setup.py dev
python setup.py nosetests --with-coverage --cover-min-percentage=44
python setup.py nosetests --with-coverage --cover-min-percentage=47
[testenv:lint]
commands =