Enable unit tests of certbot core on Python 3

This commit is contained in:
Yen Chi Hsuan
2016-08-06 21:09:43 +08:00
parent e1d8ba4977
commit fe76d558ed
26 changed files with 142 additions and 99 deletions
+2 -1
View File
@@ -8,6 +8,7 @@ import socket
from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives import serialization
import pyrfc3339 import pyrfc3339
import pytz import pytz
import six
import zope.component import zope.component
from acme import fields as acme_fields from acme import fields as acme_fields
@@ -108,7 +109,7 @@ class AccountMemoryStorage(interfaces.AccountStorage):
self.accounts = initial_accounts if initial_accounts is not None else {} self.accounts = initial_accounts if initial_accounts is not None else {}
def find_all(self): def find_all(self):
return self.accounts.values() return list(six.itervalues(self.accounts))
def save(self, account): def save(self, account):
if account.id in self.accounts: if account.id in self.accounts:
+2 -3
View File
@@ -246,8 +246,7 @@ class Client(object):
domains, domains,
self.config.allow_subset_of_names) self.config.allow_subset_of_names)
auth_domains = set(a.body.identifier.value.encode('ascii') auth_domains = set(a.body.identifier.value for a in authzr)
for a in authzr)
domains = [d for d in domains if d in auth_domains] domains = [d for d in domains if d in auth_domains]
# Create CSR from names # Create CSR from names
@@ -317,7 +316,7 @@ class Client(object):
self.config.strict_permissions) self.config.strict_permissions)
cert_pem = OpenSSL.crypto.dump_certificate( cert_pem = OpenSSL.crypto.dump_certificate(
OpenSSL.crypto.FILETYPE_PEM, certr.body.wrapped) OpenSSL.crypto.FILETYPE_PEM, certr.body.wrapped).decode('ascii')
cert_file, abs_cert_path = _open_pem_file('cert_path', cert_path) cert_file, abs_cert_path = _open_pem_file('cert_path', cert_path)
+16 -9
View File
@@ -10,6 +10,7 @@ import traceback
import OpenSSL import OpenSSL
import pyrfc3339 import pyrfc3339
import six
import zope.component import zope.component
from acme import crypto_util as acme_crypto_util from acme import crypto_util as acme_crypto_util
@@ -115,16 +116,16 @@ def make_csr(key_str, domains, must_staple=False):
# TODO: put SAN if len(domains) > 1 # TODO: put SAN if len(domains) > 1
extensions = [ extensions = [
OpenSSL.crypto.X509Extension( OpenSSL.crypto.X509Extension(
"subjectAltName", b"subjectAltName",
critical=False, critical=False,
value=", ".join("DNS:%s" % d for d in domains) value=", ".join("DNS:%s" % d for d in domains).encode('ascii')
) )
] ]
if must_staple: if must_staple:
extensions.append(OpenSSL.crypto.X509Extension( extensions.append(OpenSSL.crypto.X509Extension(
"1.3.6.1.5.5.7.1.24", b"1.3.6.1.5.5.7.1.24",
critical=False, critical=False,
value="DER:30:03:02:01:05")) value=b"DER:30:03:02:01:05"))
req.add_extensions(extensions) req.add_extensions(extensions)
req.set_version(2) req.set_version(2)
req.set_pubkey(pkey) req.set_pubkey(pkey)
@@ -350,7 +351,7 @@ def dump_pyopenssl_chain(chain, filetype=OpenSSL.crypto.FILETYPE_PEM):
if isinstance(cert, jose.ComparableX509): if isinstance(cert, jose.ComparableX509):
# pylint: disable=protected-access # pylint: disable=protected-access
cert = cert.wrapped cert = cert.wrapped
return OpenSSL.crypto.dump_certificate(filetype, cert) return OpenSSL.crypto.dump_certificate(filetype, cert).decode('ascii')
# assumes that OpenSSL.crypto.dump_certificate includes ending # assumes that OpenSSL.crypto.dump_certificate includes ending
# newline character # newline character
@@ -395,8 +396,14 @@ def _notAfterBefore(cert_path, method):
with open(cert_path) as f: with open(cert_path) as f:
x509 = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, x509 = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,
f.read()) f.read())
# pyopenssl always returns bytes
timestamp = method(x509) timestamp = method(x509)
reformatted_timestamp = [timestamp[0:4], "-", timestamp[4:6], "-", reformatted_timestamp = [timestamp[0:4], b"-", timestamp[4:6], b"-",
timestamp[6:8], "T", timestamp[8:10], ":", timestamp[6:8], b"T", timestamp[8:10], b":",
timestamp[10:12], ":", timestamp[12:]] timestamp[10:12], b":", timestamp[12:]]
return pyrfc3339.parse("".join(reformatted_timestamp)) timestamp_str = b"".join(reformatted_timestamp)
# pyrfc3339 uses "native" strings. That is, bytes on Python 2 and unicode
# on Python 3
if six.PY3:
timestamp_str = timestamp_str.decode('ascii')
return pyrfc3339.parse(timestamp_str)
+6 -1
View File
@@ -180,7 +180,12 @@ def _choose_names_manually():
try: try:
domain_list[i] = util.enforce_domain_sanity(domain) domain_list[i] = util.enforce_domain_sanity(domain)
except errors.ConfigurationError as e: except errors.ConfigurationError as e:
invalid_domains[domain] = e.message try: # Python 2
# pylint: disable=no-member
err_msg = e.message.encode('utf-8')
except AttributeError:
err_msg = str(e)
invalid_domains[domain] = err_msg
if len(invalid_domains): if len(invalid_domains):
retry_message = ( retry_message = (
+5 -4
View File
@@ -4,6 +4,7 @@ import os
import textwrap import textwrap
import dialog import dialog
import six
import zope.interface import zope.interface
from certbot import interfaces from certbot import interfaces
@@ -253,7 +254,7 @@ class FileDisplay(object):
"{line}{frame}{line}{msg}{line}{frame}{line}".format( "{line}{frame}{line}{msg}{line}{frame}{line}".format(
line=os.linesep, frame=side_frame, msg=message)) line=os.linesep, frame=side_frame, msg=message))
if pause: if pause:
raw_input("Press Enter to Continue") six.moves.input("Press Enter to Continue")
def menu(self, message, choices, ok_label="", cancel_label="", def menu(self, message, choices, ok_label="", cancel_label="",
help_label="", **unused_kwargs): help_label="", **unused_kwargs):
@@ -295,7 +296,7 @@ class FileDisplay(object):
:rtype: tuple :rtype: tuple
""" """
ans = raw_input( ans = six.moves.input(
textwrap.fill( textwrap.fill(
"%s (Enter 'c' to cancel): " % message, "%s (Enter 'c' to cancel): " % message,
80, 80,
@@ -330,7 +331,7 @@ class FileDisplay(object):
os.linesep, frame=side_frame, msg=message)) os.linesep, frame=side_frame, msg=message))
while True: while True:
ans = raw_input("{yes}/{no}: ".format( ans = six.moves.input("{yes}/{no}: ".format(
yes=_parens_around_char(yes_label), yes=_parens_around_char(yes_label),
no=_parens_around_char(no_label))) no=_parens_around_char(no_label)))
@@ -468,7 +469,7 @@ class FileDisplay(object):
input_msg = ("Press 1 [enter] to confirm the selection " input_msg = ("Press 1 [enter] to confirm the selection "
"(press 'c' to cancel): ") "(press 'c' to cancel): ")
while selection < 1: while selection < 1:
ans = raw_input(input_msg) ans = six.moves.input(input_msg)
if ans.startswith("c") or ans.startswith("C"): if ans.startswith("c") or ans.startswith("C"):
return CANCEL, -1 return CANCEL, -1
try: try:
+1 -1
View File
@@ -255,4 +255,4 @@ class PluginsRegistry(collections.Mapping):
def __str__(self): def __str__(self):
if not self._plugins: if not self._plugins:
return "No plugins" return "No plugins"
return "\n\n".join(str(p_ep) for p_ep in self._plugins.itervalues()) return "\n\n".join(str(p_ep) for p_ep in six.itervalues(self._plugins))
+2 -1
View File
@@ -3,6 +3,7 @@ import unittest
import mock import mock
import pkg_resources import pkg_resources
import six
import zope.interface import zope.interface
from certbot import errors from certbot import errors
@@ -50,7 +51,7 @@ class PluginEntryPointTest(unittest.TestCase):
EP_SA: "sa", EP_SA: "sa",
} }
for entry_point, name in names.iteritems(): for entry_point, name in six.iteritems(names):
self.assertEqual( self.assertEqual(
name, PluginEntryPoint.entry_point_to_plugin_name(entry_point)) name, PluginEntryPoint.entry_point_to_plugin_name(entry_point))
+1 -1
View File
@@ -51,7 +51,7 @@ class AuthenticatorTest(unittest.TestCase):
@mock.patch("certbot.plugins.manual.zope.component.getUtility") @mock.patch("certbot.plugins.manual.zope.component.getUtility")
@mock.patch("certbot.plugins.manual.sys.stdout") @mock.patch("certbot.plugins.manual.sys.stdout")
@mock.patch("acme.challenges.HTTP01Response.simple_verify") @mock.patch("acme.challenges.HTTP01Response.simple_verify")
@mock.patch("__builtin__.raw_input") @mock.patch("six.moves.input")
def test_perform(self, mock_raw_input, mock_verify, mock_stdout, mock_interaction): def test_perform(self, mock_raw_input, mock_verify, mock_stdout, mock_interaction):
mock_verify.return_value = True mock_verify.return_value = True
mock_interaction().yesno.return_value = True mock_interaction().yesno.return_value = True
+2 -1
View File
@@ -4,6 +4,7 @@ from __future__ import print_function
import os import os
import logging import logging
import six
import zope.component import zope.component
from certbot import errors from certbot import errors
@@ -78,7 +79,7 @@ def pick_plugin(config, default, plugins, question, ifaces):
if len(prepared) > 1: if len(prepared) > 1:
logger.debug("Multiple candidate plugins: %s", prepared) logger.debug("Multiple candidate plugins: %s", prepared)
plugin_ep = choose_plugin(prepared.values(), question) plugin_ep = choose_plugin(list(six.itervalues(prepared)), question)
if plugin_ep is None: if plugin_ep is None:
return None return None
else: else:
+2 -2
View File
@@ -63,7 +63,7 @@ class AlreadyListeningTestNoPsutil(unittest.TestCase):
def test_ports_available(self, mock_getutil): def test_ports_available(self, mock_getutil):
import certbot.plugins.util as plugins_util import certbot.plugins.util as plugins_util
# Ensure we don't get error # Ensure we don't get error
with mock.patch("socket._socketobject.bind"): with mock.patch("socket.socket.bind"):
self.assertFalse(plugins_util.already_listening(80)) self.assertFalse(plugins_util.already_listening(80))
self.assertFalse(plugins_util.already_listening(80, True)) self.assertFalse(plugins_util.already_listening(80, True))
self.assertEqual(mock_getutil.call_count, 0) self.assertEqual(mock_getutil.call_count, 0)
@@ -73,7 +73,7 @@ class AlreadyListeningTestNoPsutil(unittest.TestCase):
sys.modules["psutil"] = None sys.modules["psutil"] = None
import certbot.plugins.util as plugins_util import certbot.plugins.util as plugins_util
import socket import socket
with mock.patch("socket._socketobject.bind", side_effect=socket.error): with mock.patch("socket.socket.bind", side_effect=socket.error):
self.assertTrue(plugins_util.already_listening(80)) self.assertTrue(plugins_util.already_listening(80))
self.assertTrue(plugins_util.already_listening(80, True)) self.assertTrue(plugins_util.already_listening(80, True))
with mock.patch("socket.socket", side_effect=socket.error): with mock.patch("socket.socket", side_effect=socket.error):
+1 -1
View File
@@ -206,7 +206,7 @@ to serve all files under specified web root ({0})."""
old_umask = os.umask(0o022) old_umask = os.umask(0o022)
try: try:
with open(validation_path, "w") as validation_file: with open(validation_path, "wb") as validation_file:
validation_file.write(validation.encode()) validation_file.write(validation.encode())
finally: finally:
os.umask(old_umask) os.umask(old_umask)
+7 -5
View File
@@ -7,7 +7,7 @@ import shutil
import time import time
import traceback import traceback
import six
import zope.component import zope.component
from certbot import constants from certbot import constants
@@ -310,7 +310,9 @@ class Reverter(object):
def _run_undo_commands(self, filepath): # pylint: disable=no-self-use def _run_undo_commands(self, filepath): # pylint: disable=no-self-use
"""Run all commands in a file.""" """Run all commands in a file."""
with open(filepath, 'rb') as csvfile: # NOTE: csv module uses native strings. That is, bytes on Python 2 and
# unicode on Python 3
with open(filepath, 'r') as csvfile:
csvreader = csv.reader(csvfile) csvreader = csv.reader(csvfile)
for command in reversed(list(csvreader)): for command in reversed(list(csvreader)):
try: try:
@@ -408,9 +410,9 @@ class Reverter(object):
command_file = None command_file = None
try: try:
if os.path.isfile(commands_fp): if os.path.isfile(commands_fp):
command_file = open(commands_fp, "ab") command_file = open(commands_fp, "a")
else: else:
command_file = open(commands_fp, "wb") command_file = open(commands_fp, "w")
csvwriter = csv.writer(command_file) csvwriter = csv.writer(command_file)
csvwriter.writerow(command) csvwriter.writerow(command)
@@ -569,7 +571,7 @@ class Reverter(object):
# It is possible save checkpoints faster than 1 per second resulting in # It is possible save checkpoints faster than 1 per second resulting in
# collisions in the naming convention. # collisions in the naming convention.
for _ in xrange(2): for _ in six.moves.range(2):
timestamp = self._checkpoint_timestamp() timestamp = self._checkpoint_timestamp()
final_dir = os.path.join(self.config.backup_dir, timestamp) final_dir = os.path.join(self.config.backup_dir, timestamp)
try: try:
+1 -1
View File
@@ -90,7 +90,7 @@ def write_renewal_config(o_filename, n_filename, target, relevant_data):
# TODO: add human-readable comments explaining other available # TODO: add human-readable comments explaining other available
# parameters # parameters
logger.debug("Writing new config %s.", n_filename) logger.debug("Writing new config %s.", n_filename)
with open(n_filename, "w") as f: with open(n_filename, "wb") as f:
config.write(outfile=f) config.write(outfile=f)
return config return config
+4 -4
View File
@@ -131,8 +131,8 @@ class AccountFileStorageTest(unittest.TestCase):
for file_name in "regr.json", "meta.json", "private_key.json": for file_name in "regr.json", "meta.json", "private_key.json":
self.assertTrue(os.path.exists( self.assertTrue(os.path.exists(
os.path.join(account_path, file_name))) os.path.join(account_path, file_name)))
self.assertEqual("0400", oct(os.stat(os.path.join( self.assertTrue(oct(os.stat(os.path.join(
account_path, "private_key.json"))[stat.ST_MODE] & 0o777)) account_path, "private_key.json"))[stat.ST_MODE] & 0o777) in ("0400", "0o400"))
# restore # restore
self.assertEqual(self.acc, self.storage.load(self.acc.id)) self.assertEqual(self.acc, self.storage.load(self.acc.id))
@@ -179,14 +179,14 @@ class AccountFileStorageTest(unittest.TestCase):
self.storage.save(self.acc) self.storage.save(self.acc)
mock_open = mock.mock_open() mock_open = mock.mock_open()
mock_open.side_effect = IOError mock_open.side_effect = IOError
with mock.patch("__builtin__.open", mock_open): with mock.patch("six.moves.builtins.open", mock_open):
self.assertRaises( self.assertRaises(
errors.AccountStorageError, self.storage.load, self.acc.id) errors.AccountStorageError, self.storage.load, self.acc.id)
def test_save_ioerrors(self): def test_save_ioerrors(self):
mock_open = mock.mock_open() mock_open = mock.mock_open()
mock_open.side_effect = IOError # TODO: [None, None, IOError] mock_open.side_effect = IOError # TODO: [None, None, IOError]
with mock.patch("__builtin__.open", mock_open): with mock.patch("six.moves.builtins.open", mock_open):
self.assertRaises( self.assertRaises(
errors.AccountStorageError, self.storage.save, self.acc) errors.AccountStorageError, self.storage.save, self.acc)
+5 -4
View File
@@ -1,6 +1,7 @@
"""ACME utilities for testing.""" """ACME utilities for testing."""
import datetime import datetime
import itertools
import six
from acme import challenges from acme import challenges
from acme import jose from acme import jose
@@ -13,10 +14,10 @@ KEY = test_util.load_rsa_private_key('rsa512_key.pem')
# Challenges # Challenges
HTTP01 = challenges.HTTP01( HTTP01 = challenges.HTTP01(
token="evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ+PCt92wr+oA") token=b"evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ+PCt92wr+oA")
TLSSNI01 = challenges.TLSSNI01( TLSSNI01 = challenges.TLSSNI01(
token=jose.b64decode(b"evaGxfADs6pSRb2LAv9IZf17Dt3juxGJyPCt92wrDoA")) token=jose.b64decode(b"evaGxfADs6pSRb2LAv9IZf17Dt3juxGJyPCt92wrDoA"))
DNS = challenges.DNS(token="17817c66b60ce2e4012dfad92657527a") DNS = challenges.DNS(token=b"17817c66b60ce2e4012dfad92657527a")
CHALLENGES = [HTTP01, TLSSNI01, DNS] CHALLENGES = [HTTP01, TLSSNI01, DNS]
@@ -62,7 +63,7 @@ def gen_authzr(authz_status, domain, challs, statuses, combos=True):
# pylint: disable=redefined-outer-name # pylint: disable=redefined-outer-name
challbs = tuple( challbs = tuple(
chall_to_challb(chall, status) chall_to_challb(chall, status)
for chall, status in itertools.izip(challs, statuses) for chall, status in six.moves.zip(challs, statuses)
) )
authz_kwargs = { authz_kwargs = {
"identifier": messages.Identifier( "identifier": messages.Identifier(
+9 -8
View File
@@ -4,6 +4,7 @@ import logging
import unittest import unittest
import mock import mock
import six
from acme import challenges from acme import challenges
from acme import client as acme_client from acme import client as acme_client
@@ -93,7 +94,7 @@ class GetAuthorizationsTest(unittest.TestCase):
self.assertEqual(mock_poll.call_count, 1) self.assertEqual(mock_poll.call_count, 1)
chall_update = mock_poll.call_args[0][0] chall_update = mock_poll.call_args[0][0]
self.assertEqual(chall_update.keys(), ["0"]) self.assertEqual(list(six.iterkeys(chall_update)), ["0"])
self.assertEqual(len(chall_update.values()), 1) self.assertEqual(len(chall_update.values()), 1)
self.assertEqual(self.mock_auth.cleanup.call_count, 1) self.assertEqual(self.mock_auth.cleanup.call_count, 1)
@@ -118,7 +119,7 @@ class GetAuthorizationsTest(unittest.TestCase):
self.assertEqual(mock_poll.call_count, 1) self.assertEqual(mock_poll.call_count, 1)
chall_update = mock_poll.call_args[0][0] chall_update = mock_poll.call_args[0][0]
self.assertEqual(chall_update.keys(), ["0"]) self.assertEqual(list(six.iterkeys(chall_update)), ["0"])
self.assertEqual(len(chall_update.values()), 1) self.assertEqual(len(chall_update.values()), 1)
self.assertEqual(self.mock_auth.cleanup.call_count, 1) self.assertEqual(self.mock_auth.cleanup.call_count, 1)
@@ -143,12 +144,12 @@ class GetAuthorizationsTest(unittest.TestCase):
# Check poll call # Check poll call
self.assertEqual(mock_poll.call_count, 1) self.assertEqual(mock_poll.call_count, 1)
chall_update = mock_poll.call_args[0][0] chall_update = mock_poll.call_args[0][0]
self.assertEqual(len(chall_update.keys()), 3) self.assertEqual(len(list(six.iterkeys(chall_update))), 3)
self.assertTrue("0" in chall_update.keys()) self.assertTrue("0" in list(six.iterkeys(chall_update)))
self.assertEqual(len(chall_update["0"]), 1) self.assertEqual(len(chall_update["0"]), 1)
self.assertTrue("1" in chall_update.keys()) self.assertTrue("1" in list(six.iterkeys(chall_update)))
self.assertEqual(len(chall_update["1"]), 1) self.assertEqual(len(chall_update["1"]), 1)
self.assertTrue("2" in chall_update.keys()) self.assertTrue("2" in list(six.iterkeys(chall_update)))
self.assertEqual(len(chall_update["2"]), 1) self.assertEqual(len(chall_update["2"]), 1)
self.assertEqual(self.mock_auth.cleanup.call_count, 1) self.assertEqual(self.mock_auth.cleanup.call_count, 1)
@@ -167,7 +168,7 @@ class GetAuthorizationsTest(unittest.TestCase):
self.assertRaises(errors.AuthorizationError, self.handler.get_authorizations, []) self.assertRaises(errors.AuthorizationError, self.handler.get_authorizations, [])
def _validate_all(self, unused_1, unused_2): def _validate_all(self, unused_1, unused_2):
for dom in self.handler.authzr.keys(): for dom in six.iterkeys(self.handler.authzr):
azr = self.handler.authzr[dom] azr = self.handler.authzr[dom]
self.handler.authzr[dom] = acme_util.gen_authzr( self.handler.authzr[dom] = acme_util.gen_authzr(
messages.STATUS_VALID, messages.STATUS_VALID,
@@ -317,7 +318,7 @@ class GenChallengePathTest(unittest.TestCase):
""" """
def setUp(self): def setUp(self):
logging.disable(logging.fatal) logging.disable(logging.FATAL)
def tearDown(self): def tearDown(self):
logging.disable(logging.NOTSET) logging.disable(logging.NOTSET)
+12 -11
View File
@@ -136,7 +136,8 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods
try: try:
with mock.patch('certbot.main.sys.stderr'): with mock.patch('certbot.main.sys.stderr'):
main.main(self.standard_args + args[:]) # NOTE: parser can alter its args! main.main(self.standard_args + args[:]) # NOTE: parser can alter its args!
except errors.MissingCommandlineFlag as exc: except errors.MissingCommandlineFlag as exc_:
exc = exc_
self.assertTrue(message in str(exc)) self.assertTrue(message in str(exc))
self.assertTrue(exc is not None) self.assertTrue(exc is not None)
@@ -263,7 +264,7 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods
flags = ['--init', '--prepare', '--authenticators', '--installers'] flags = ['--init', '--prepare', '--authenticators', '--installers']
for args in itertools.chain( for args in itertools.chain(
*(itertools.combinations(flags, r) *(itertools.combinations(flags, r)
for r in xrange(len(flags)))): for r in six.moves.range(len(flags)))):
self._call(['plugins'] + list(args)) self._call(['plugins'] + list(args))
@mock.patch('certbot.main.plugins_disco') @mock.patch('certbot.main.plugins_disco')
@@ -332,7 +333,7 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods
self._call(['-a', 'bad_auth', 'certonly']) self._call(['-a', 'bad_auth', 'certonly'])
assert False, "Exception should have been raised" assert False, "Exception should have been raised"
except errors.PluginSelectionError as e: except errors.PluginSelectionError as e:
self.assertTrue('The requested bad_auth plugin does not appear' in e.message) self.assertTrue('The requested bad_auth plugin does not appear' in str(e))
def test_check_config_sanity_domain(self): def test_check_config_sanity_domain(self):
# Punycode # Punycode
@@ -427,9 +428,9 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods
"The following flags didn't conflict with " "The following flags didn't conflict with "
'--server: {0}'.format(', '.join(conflicting_args))) '--server: {0}'.format(', '.join(conflicting_args)))
except errors.Error as error: except errors.Error as error:
self.assertTrue('--server' in error.message) self.assertTrue('--server' in str(error))
for arg in conflicting_args: for arg in conflicting_args:
self.assertTrue(arg in error.message) self.assertTrue(arg in str(error))
def test_must_staple_flag(self): def test_must_staple_flag(self):
parse = self._get_argument_parser() parse = self._get_argument_parser()
@@ -855,10 +856,10 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods
server = 'foo.bar' server = 'foo.bar'
self._call_no_clientmock(['--cert-path', CERT, '--key-path', KEY, self._call_no_clientmock(['--cert-path', CERT, '--key-path', KEY,
'--server', server, 'revoke']) '--server', server, 'revoke'])
with open(KEY) as f: with open(KEY, 'rb') as f:
mock_acme_client.Client.assert_called_once_with( mock_acme_client.Client.assert_called_once_with(
server, key=jose.JWK.load(f.read()), net=mock.ANY) server, key=jose.JWK.load(f.read()), net=mock.ANY)
with open(CERT) as f: with open(CERT, 'rb') as f:
cert = crypto_util.pyopenssl_load_certificate(f.read())[0] cert = crypto_util.pyopenssl_load_certificate(f.read())[0]
mock_revoke = mock_acme_client.Client().revoke mock_revoke = mock_acme_client.Client().revoke
mock_revoke.assert_called_once_with(jose.ComparableX509(cert)) mock_revoke.assert_called_once_with(jose.ComparableX509(cert))
@@ -885,7 +886,7 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods
config.verbose_count = 1 config.verbose_count = 1
main._handle_exception( main._handle_exception(
Exception, exc_value=exception, trace=None, config=None) Exception, exc_value=exception, trace=None, config=None)
mock_open().write.assert_called_once_with(''.join( mock_open().write.assert_any_call(''.join(
traceback.format_exception_only(Exception, exception))) traceback.format_exception_only(Exception, exception)))
error_msg = mock_sys.exit.call_args_list[0][0][0] error_msg = mock_sys.exit.call_args_list[0][0][0]
self.assertTrue('unexpected error' in error_msg) self.assertTrue('unexpected error' in error_msg)
@@ -935,8 +936,8 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods
self.assertRaises( self.assertRaises(
argparse.ArgumentTypeError, cli.read_file, rel_test_path) argparse.ArgumentTypeError, cli.read_file, rel_test_path)
test_contents = 'bar\n' test_contents = b'bar\n'
with open(rel_test_path, 'w') as f: with open(rel_test_path, 'wb') as f:
f.write(test_contents) f.write(test_contents)
path, contents = cli.read_file(rel_test_path) path, contents = cli.read_file(rel_test_path)
@@ -1106,7 +1107,7 @@ class DuplicativeCertsTest(storage_test.BaseRenewableCertTest):
def test_find_duplicative_names(self, unused_makedir): def test_find_duplicative_names(self, unused_makedir):
from certbot.main import _find_duplicative_certs from certbot.main import _find_duplicative_certs
test_cert = test_util.load_vector('cert-san.pem') test_cert = test_util.load_vector('cert-san.pem')
with open(self.test_rc.cert, 'w') as f: with open(self.test_rc.cert, 'wb') as f:
f.write(test_cert) f.write(test_cert)
# No overlap at all # No overlap at all
+2 -2
View File
@@ -232,11 +232,11 @@ class ClientTest(unittest.TestCase):
self.assertEqual(os.path.dirname(fullchain_path), self.assertEqual(os.path.dirname(fullchain_path),
os.path.dirname(candidate_fullchain_path)) os.path.dirname(candidate_fullchain_path))
with open(cert_path, "r") as cert_file: with open(cert_path, "rb") as cert_file:
cert_contents = cert_file.read() cert_contents = cert_file.read()
self.assertEqual(cert_contents, test_util.load_vector(certs[0])) self.assertEqual(cert_contents, test_util.load_vector(certs[0]))
with open(chain_path, "r") as chain_file: with open(chain_path, "rb") as chain_file:
chain_contents = chain_file.read() chain_contents = chain_file.read()
self.assertEqual(chain_contents, test_util.load_vector(certs[1]) + self.assertEqual(chain_contents, test_util.load_vector(certs[1]) +
test_util.load_vector(certs[2])) test_util.load_vector(certs[2]))
+2
View File
@@ -60,6 +60,7 @@ class NamespaceConfigTest(unittest.TestCase):
config_base = "foo" config_base = "foo"
work_base = "bar" work_base = "bar"
logs_base = "baz" logs_base = "baz"
server = "mock.server"
mock_namespace = mock.MagicMock(spec=['config_dir', 'work_dir', mock_namespace = mock.MagicMock(spec=['config_dir', 'work_dir',
'logs_dir', 'http01_port', 'logs_dir', 'http01_port',
@@ -68,6 +69,7 @@ class NamespaceConfigTest(unittest.TestCase):
mock_namespace.config_dir = config_base mock_namespace.config_dir = config_base
mock_namespace.work_dir = work_base mock_namespace.work_dir = work_base
mock_namespace.logs_dir = logs_base mock_namespace.logs_dir = logs_base
mock_namespace.server = server
config = NamespaceConfig(mock_namespace) config = NamespaceConfig(mock_namespace)
self.assertTrue(os.path.isabs(config.config_dir)) self.assertTrue(os.path.isabs(config.config_dir))
+2 -2
View File
@@ -111,7 +111,7 @@ class MakeCSRTest(unittest.TestCase):
# OpenSSL.crypto.X509Extension doesn't give us the extension's raw OID, # OpenSSL.crypto.X509Extension doesn't give us the extension's raw OID,
# and the shortname field is just "UNDEF" # and the shortname field is just "UNDEF"
must_staple_exts = [e for e in csr.get_extensions() must_staple_exts = [e for e in csr.get_extensions()
if e.get_data() == "0\x03\x02\x01\x05"] if e.get_data() == b"0\x03\x02\x01\x05"]
self.assertEqual(len(must_staple_exts), 1, self.assertEqual(len(must_staple_exts), 1,
"Expected exactly one Must Staple extension") "Expected exactly one Must Staple extension")
@@ -341,7 +341,7 @@ class CertLoaderTest(unittest.TestCase):
def test_load_invalid_cert(self): def test_load_invalid_cert(self):
from certbot.crypto_util import pyopenssl_load_certificate from certbot.crypto_util import pyopenssl_load_certificate
bad_cert_data = CERT.replace("BEGIN CERTIFICATE", "ASDFASDFASDF!!!") bad_cert_data = CERT.replace(b"BEGIN CERTIFICATE", b"ASDFASDFASDF!!!")
self.assertRaises( self.assertRaises(
errors.Error, pyopenssl_load_certificate, bad_cert_data) errors.Error, pyopenssl_load_certificate, bad_cert_data)
+12 -12
View File
@@ -151,7 +151,7 @@ class FileOutputDisplayTest(unittest.TestCase):
self.assertTrue("message" in string) self.assertTrue("message" in string)
def test_notification_pause(self): def test_notification_pause(self):
with mock.patch("__builtin__.raw_input", return_value="enter"): with mock.patch("six.moves.input", return_value="enter"):
self.displayer.notification("message") self.displayer.notification("message")
self.assertTrue("message" in self.mock_stdout.write.call_args[0][0]) self.assertTrue("message" in self.mock_stdout.write.call_args[0][0])
@@ -164,31 +164,31 @@ class FileOutputDisplayTest(unittest.TestCase):
self.assertEqual(ret, (display_util.OK, 0)) self.assertEqual(ret, (display_util.OK, 0))
def test_input_cancel(self): def test_input_cancel(self):
with mock.patch("__builtin__.raw_input", return_value="c"): with mock.patch("six.moves.input", return_value="c"):
code, _ = self.displayer.input("message") code, _ = self.displayer.input("message")
self.assertTrue(code, display_util.CANCEL) self.assertTrue(code, display_util.CANCEL)
def test_input_normal(self): def test_input_normal(self):
with mock.patch("__builtin__.raw_input", return_value="domain.com"): with mock.patch("six.moves.input", return_value="domain.com"):
code, input_ = self.displayer.input("message") code, input_ = self.displayer.input("message")
self.assertEqual(code, display_util.OK) self.assertEqual(code, display_util.OK)
self.assertEqual(input_, "domain.com") self.assertEqual(input_, "domain.com")
def test_yesno(self): def test_yesno(self):
with mock.patch("__builtin__.raw_input", return_value="Yes"): with mock.patch("six.moves.input", return_value="Yes"):
self.assertTrue(self.displayer.yesno("message")) self.assertTrue(self.displayer.yesno("message"))
with mock.patch("__builtin__.raw_input", return_value="y"): with mock.patch("six.moves.input", return_value="y"):
self.assertTrue(self.displayer.yesno("message")) self.assertTrue(self.displayer.yesno("message"))
with mock.patch("__builtin__.raw_input", side_effect=["maybe", "y"]): with mock.patch("six.moves.input", side_effect=["maybe", "y"]):
self.assertTrue(self.displayer.yesno("message")) self.assertTrue(self.displayer.yesno("message"))
with mock.patch("__builtin__.raw_input", return_value="No"): with mock.patch("six.moves.input", return_value="No"):
self.assertFalse(self.displayer.yesno("message")) self.assertFalse(self.displayer.yesno("message"))
with mock.patch("__builtin__.raw_input", side_effect=["cancel", "n"]): with mock.patch("six.moves.input", side_effect=["cancel", "n"]):
self.assertFalse(self.displayer.yesno("message")) self.assertFalse(self.displayer.yesno("message"))
with mock.patch("__builtin__.raw_input", return_value="a"): with mock.patch("six.moves.input", return_value="a"):
self.assertTrue(self.displayer.yesno("msg", yes_label="Agree")) self.assertTrue(self.displayer.yesno("msg", yes_label="Agree"))
@mock.patch("certbot.display.util.FileDisplay.input") @mock.patch("certbot.display.util.FileDisplay.input")
@@ -275,11 +275,11 @@ class FileOutputDisplayTest(unittest.TestCase):
def test_get_valid_int_ans_valid(self): def test_get_valid_int_ans_valid(self):
# pylint: disable=protected-access # pylint: disable=protected-access
with mock.patch("__builtin__.raw_input", return_value="1"): with mock.patch("six.moves.input", return_value="1"):
self.assertEqual( self.assertEqual(
self.displayer._get_valid_int_ans(1), (display_util.OK, 1)) self.displayer._get_valid_int_ans(1), (display_util.OK, 1))
ans = "2" ans = "2"
with mock.patch("__builtin__.raw_input", return_value=ans): with mock.patch("six.moves.input", return_value=ans):
self.assertEqual( self.assertEqual(
self.displayer._get_valid_int_ans(3), self.displayer._get_valid_int_ans(3),
(display_util.OK, int(ans))) (display_util.OK, int(ans)))
@@ -292,7 +292,7 @@ class FileOutputDisplayTest(unittest.TestCase):
["c"], ["c"],
] ]
for ans in answers: for ans in answers:
with mock.patch("__builtin__.raw_input", side_effect=ans): with mock.patch("six.moves.input", side_effect=ans):
self.assertEqual( self.assertEqual(
self.displayer._get_valid_int_ans(3), self.displayer._get_valid_int_ans(3),
(display_util.CANCEL, -1)) (display_util.CANCEL, -1))
+2 -2
View File
@@ -1,6 +1,5 @@
"""Test certbot.reverter.""" """Test certbot.reverter."""
import csv import csv
import itertools
import logging import logging
import os import os
import shutil import shutil
@@ -8,6 +7,7 @@ import tempfile
import unittest import unittest
import mock import mock
import six
from certbot import errors from certbot import errors
@@ -153,7 +153,7 @@ class ReverterCheckpointLocalTest(unittest.TestCase):
act_coms = get_undo_commands(self.config.temp_checkpoint_dir) act_coms = get_undo_commands(self.config.temp_checkpoint_dir)
for a_com, com in itertools.izip(act_coms, coms): for a_com, com in six.moves.zip(act_coms, coms):
self.assertEqual(a_com, com) self.assertEqual(a_com, com)
def test_bad_register_undo_command(self): def test_bad_register_undo_command(self):
+15 -14
View File
@@ -9,6 +9,7 @@ import unittest
import configobj import configobj
import mock import mock
import pytz import pytz
import six
import certbot import certbot
from certbot import cli from certbot import cli
@@ -92,8 +93,8 @@ class BaseRenewableCertTest(unittest.TestCase):
os.symlink(os.path.join(os.path.pardir, os.path.pardir, "archive", os.symlink(os.path.join(os.path.pardir, os.path.pardir, "archive",
"example.org", "{0}{1}.pem".format(kind, ver)), "example.org", "{0}{1}.pem".format(kind, ver)),
link) link)
with open(link, "w") as f: with open(link, "wb") as f:
f.write(kind if value is None else value) f.write(kind.encode('ascii') if value is None else value)
def _write_out_ex_kinds(self): def _write_out_ex_kinds(self):
for kind in ALL_FOUR: for kind in ALL_FOUR:
@@ -235,7 +236,7 @@ class RenewableCertTests(BaseRenewableCertTest):
self.assertEqual(self.test_rc.current_version("cert"), None) self.assertEqual(self.test_rc.current_version("cert"), None)
def test_latest_and_next_versions(self): def test_latest_and_next_versions(self):
for ver in xrange(1, 6): for ver in six.moves.range(1, 6):
for kind in ALL_FOUR: for kind in ALL_FOUR:
self._write_out_kind(kind, ver) self._write_out_kind(kind, ver)
self.assertEqual(self.test_rc.latest_common_version(), 5) self.assertEqual(self.test_rc.latest_common_version(), 5)
@@ -258,7 +259,7 @@ class RenewableCertTests(BaseRenewableCertTest):
self.assertEqual(self.test_rc.next_free_version(), 18) self.assertEqual(self.test_rc.next_free_version(), 18)
def test_update_link_to(self): def test_update_link_to(self):
for ver in xrange(1, 6): for ver in six.moves.range(1, 6):
for kind in ALL_FOUR: for kind in ALL_FOUR:
self._write_out_kind(kind, ver) self._write_out_kind(kind, ver)
self.assertEqual(ver, self.test_rc.current_version(kind)) self.assertEqual(ver, self.test_rc.current_version(kind))
@@ -285,12 +286,12 @@ class RenewableCertTests(BaseRenewableCertTest):
os.path.basename(self.test_rc.version("cert", 8))) os.path.basename(self.test_rc.version("cert", 8)))
def test_update_all_links_to_success(self): def test_update_all_links_to_success(self):
for ver in xrange(1, 6): for ver in six.moves.range(1, 6):
for kind in ALL_FOUR: for kind in ALL_FOUR:
self._write_out_kind(kind, ver) self._write_out_kind(kind, ver)
self.assertEqual(ver, self.test_rc.current_version(kind)) self.assertEqual(ver, self.test_rc.current_version(kind))
self.assertEqual(self.test_rc.latest_common_version(), 5) self.assertEqual(self.test_rc.latest_common_version(), 5)
for ver in xrange(1, 6): for ver in six.moves.range(1, 6):
self.test_rc.update_all_links_to(ver) self.test_rc.update_all_links_to(ver)
for kind in ALL_FOUR: for kind in ALL_FOUR:
self.assertEqual(ver, self.test_rc.current_version(kind)) self.assertEqual(ver, self.test_rc.current_version(kind))
@@ -330,11 +331,11 @@ class RenewableCertTests(BaseRenewableCertTest):
self.assertEqual(self.test_rc.current_version(kind), 11) self.assertEqual(self.test_rc.current_version(kind), 11)
def test_has_pending_deployment(self): def test_has_pending_deployment(self):
for ver in xrange(1, 6): for ver in six.moves.range(1, 6):
for kind in ALL_FOUR: for kind in ALL_FOUR:
self._write_out_kind(kind, ver) self._write_out_kind(kind, ver)
self.assertEqual(ver, self.test_rc.current_version(kind)) self.assertEqual(ver, self.test_rc.current_version(kind))
for ver in xrange(1, 6): for ver in six.moves.range(1, 6):
self.test_rc.update_all_links_to(ver) self.test_rc.update_all_links_to(ver)
for kind in ALL_FOUR: for kind in ALL_FOUR:
self.assertEqual(ver, self.test_rc.current_version(kind)) self.assertEqual(ver, self.test_rc.current_version(kind))
@@ -373,10 +374,10 @@ class RenewableCertTests(BaseRenewableCertTest):
self._write_out_ex_kinds() self._write_out_ex_kinds()
self.test_rc.update_all_links_to(12) self.test_rc.update_all_links_to(12)
with open(self.test_rc.cert, "w") as f: with open(self.test_rc.cert, "wb") as f:
f.write(test_cert) f.write(test_cert)
self.test_rc.update_all_links_to(11) self.test_rc.update_all_links_to(11)
with open(self.test_rc.cert, "w") as f: with open(self.test_rc.cert, "wb") as f:
f.write(test_cert) f.write(test_cert)
mock_datetime.timedelta = datetime.timedelta mock_datetime.timedelta = datetime.timedelta
@@ -426,7 +427,7 @@ class RenewableCertTests(BaseRenewableCertTest):
self.assertFalse(self.test_rc.should_autodeploy()) self.assertFalse(self.test_rc.should_autodeploy())
self.test_rc.configuration["autodeploy"] = "1" self.test_rc.configuration["autodeploy"] = "1"
# No pending deployment # No pending deployment
for ver in xrange(1, 6): for ver in six.moves.range(1, 6):
for kind in ALL_FOUR: for kind in ALL_FOUR:
self._write_out_kind(kind, ver) self._write_out_kind(kind, ver)
self.assertFalse(self.test_rc.should_autodeploy()) self.assertFalse(self.test_rc.should_autodeploy())
@@ -461,7 +462,7 @@ class RenewableCertTests(BaseRenewableCertTest):
# (to avoid instantiating parser) # (to avoid instantiating parser)
mock_rv.side_effect = lambda x: x mock_rv.side_effect = lambda x: x
for ver in xrange(1, 6): for ver in six.moves.range(1, 6):
for kind in ALL_FOUR: for kind in ALL_FOUR:
self._write_out_kind(kind, ver) self._write_out_kind(kind, ver)
self.test_rc.update_all_links_to(3) self.test_rc.update_all_links_to(3)
@@ -492,7 +493,7 @@ class RenewableCertTests(BaseRenewableCertTest):
self.test_rc.version("privkey", i)))) self.test_rc.version("privkey", i))))
for kind in ALL_FOUR: for kind in ALL_FOUR:
self.assertEqual(self.test_rc.available_versions(kind), range(1, 9)) self.assertEqual(self.test_rc.available_versions(kind), list(six.moves.range(1, 9)))
self.assertEqual(self.test_rc.current_version(kind), 3) self.assertEqual(self.test_rc.current_version(kind), 3)
# Test updating from latest version rather than old version # Test updating from latest version rather than old version
self.test_rc.update_all_links_to(8) self.test_rc.update_all_links_to(8)
@@ -501,7 +502,7 @@ class RenewableCertTests(BaseRenewableCertTest):
"attempt", self.cli_config)) "attempt", self.cli_config))
for kind in ALL_FOUR: for kind in ALL_FOUR:
self.assertEqual(self.test_rc.available_versions(kind), self.assertEqual(self.test_rc.available_versions(kind),
range(1, 10)) list(six.moves.range(1, 10)))
self.assertEqual(self.test_rc.current_version(kind), 8) self.assertEqual(self.test_rc.current_version(kind), 8)
with open(self.test_rc.version("fullchain", 9)) as f: with open(self.test_rc.version("fullchain", 9)) as f:
self.assertEqual(f.read(), "last" + "attempt") self.assertEqual(f.read(), "last" + "attempt")
+9 -3
View File
@@ -189,6 +189,12 @@ class UniqueFileTest(unittest.TestCase):
self.assertTrue(basename3.endswith("foo.txt")) self.assertTrue(basename3.endswith("foo.txt"))
try:
file_type = file
except NameError:
import io
file_type = io.TextIOWrapper
class UniqueLineageNameTest(unittest.TestCase): class UniqueLineageNameTest(unittest.TestCase):
"""Tests for certbot.util.unique_lineage_name.""" """Tests for certbot.util.unique_lineage_name."""
@@ -204,13 +210,13 @@ class UniqueLineageNameTest(unittest.TestCase):
def test_basic(self): def test_basic(self):
f, path = self._call("wow") f, path = self._call("wow")
self.assertTrue(isinstance(f, file)) self.assertTrue(isinstance(f, file_type))
self.assertEqual(os.path.join(self.root_path, "wow.conf"), path) self.assertEqual(os.path.join(self.root_path, "wow.conf"), path)
def test_multiple(self): def test_multiple(self):
for _ in xrange(10): for _ in six.moves.range(10):
f, name = self._call("wow") f, name = self._call("wow")
self.assertTrue(isinstance(f, file)) self.assertTrue(isinstance(f, file_type))
self.assertTrue(isinstance(name, str)) self.assertTrue(isinstance(name, str))
self.assertTrue("wow-0009.conf" in name) self.assertTrue("wow-0009.conf" in name)
+14 -6
View File
@@ -402,18 +402,27 @@ def enforce_domain_sanity(domain):
:returns: The domain cast to `str`, with ASCII-only contents :returns: The domain cast to `str`, with ASCII-only contents
:rtype: str :rtype: str
""" """
if isinstance(domain, six.text_type):
wildcard_marker = u"*."
punycode_marker = u"xn--"
else:
wildcard_marker = b"*."
punycode_marker = b"xn--"
# Check if there's a wildcard domain # Check if there's a wildcard domain
if domain.startswith("*."): if domain.startswith(wildcard_marker):
raise errors.ConfigurationError( raise errors.ConfigurationError(
"Wildcard domains are not supported: {0}".format(domain)) "Wildcard domains are not supported: {0}".format(domain))
# Punycode # Punycode
if "xn--" in domain: if punycode_marker in domain:
raise errors.ConfigurationError( raise errors.ConfigurationError(
"Punycode domains are not presently supported: {0}".format(domain)) "Punycode domains are not presently supported: {0}".format(domain))
# Unicode # Unicode
try: try:
domain = domain.encode('ascii').lower() if isinstance(domain, six.binary_type):
domain = domain.decode('utf-8')
domain.encode('ascii')
except UnicodeError: except UnicodeError:
error_fmt = (u"Internationalized domain names " error_fmt = (u"Internationalized domain names "
"are not presently supported: {0}") "are not presently supported: {0}")
@@ -422,11 +431,10 @@ def enforce_domain_sanity(domain):
else: else:
raise errors.ConfigurationError(str(error_fmt).format(domain)) raise errors.ConfigurationError(str(error_fmt).format(domain))
if six.PY3: domain = domain.lower()
domain = domain.decode('ascii')
# Remove trailing dot # Remove trailing dot
domain = domain[:-1] if domain.endswith('.') else domain domain = domain[:-1] if domain.endswith(u'.') else domain
# Explain separately that IP addresses aren't allowed (apart from not # Explain separately that IP addresses aren't allowed (apart from not
# being FQDNs) because hope springs eternal concerning this point # being FQDNs) because hope springs eternal concerning this point
+6
View File
@@ -40,16 +40,22 @@ deps =
commands = commands =
pip install -e acme[dns,dev] pip install -e acme[dns,dev]
nosetests -v acme nosetests -v acme
pip install -e .[dev]
nosetests -v certbot
[testenv:py34] [testenv:py34]
commands = commands =
pip install -e acme[dns,dev] pip install -e acme[dns,dev]
nosetests -v acme nosetests -v acme
pip install -e .[dev]
nosetests -v certbot
[testenv:py35] [testenv:py35]
commands = commands =
pip install -e acme[dns,dev] pip install -e acme[dns,dev]
nosetests -v acme nosetests -v acme
pip install -e .[dev]
nosetests -v certbot
[testenv:cover] [testenv:cover]
basepython = python2.7 basepython = python2.7