Merge branch 'master' into log-manual-hooks

This commit is contained in:
Brad Warren 2019-02-21 16:56:31 -08:00 committed by GitHub
commit 94de53cdf6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 98 additions and 34 deletions

View file

@ -16,6 +16,7 @@ Certbot adheres to [Semantic Versioning](https://semver.org/).
command line defaults. command line defaults.
* The running of manual plugin hooks is now always included in Certbot's log * The running of manual plugin hooks is now always included in Certbot's log
output. output.
* Tests execution for certbot, certbot-apache and certbot-nginx packages now relies on pytest.
### Fixed ### Fixed
@ -28,6 +29,7 @@ package with changes other than its version number was:
* acme * acme
* certbot * certbot
* certbot-apache * certbot-apache
* certbot-nginx
More details about these changes can be found on our GitHub repo. More details about these changes can be found on our GitHub repo.

View file

@ -36,6 +36,7 @@ docs_extras = [
'sphinx_rtd_theme', 'sphinx_rtd_theme',
] ]
class PyTest(TestCommand): class PyTest(TestCommand):
user_options = [] user_options = []
@ -50,6 +51,7 @@ class PyTest(TestCommand):
errno = pytest.main(shlex.split(self.pytest_args)) errno = pytest.main(shlex.split(self.pytest_args))
sys.exit(errno) sys.exit(errno)
setup( setup(
name='acme', name='acme',
version=version, version=version,
@ -82,7 +84,7 @@ setup(
'dev': dev_extras, 'dev': dev_extras,
'docs': docs_extras, 'docs': docs_extras,
}, },
tests_require=["pytest"],
test_suite='acme', test_suite='acme',
tests_require=["pytest"],
cmdclass={"test": PyTest}, cmdclass={"test": PyTest},
) )

View file

@ -1,5 +1,7 @@
from setuptools import setup from setuptools import setup
from setuptools import find_packages from setuptools import find_packages
from setuptools.command.test import test as TestCommand
import sys
version = '0.32.0.dev0' version = '0.32.0.dev0'
@ -21,6 +23,22 @@ docs_extras = [
'sphinx_rtd_theme', 'sphinx_rtd_theme',
] ]
class PyTest(TestCommand):
user_options = []
def initialize_options(self):
TestCommand.initialize_options(self)
self.pytest_args = ''
def run_tests(self):
import shlex
# import here, cause outside the eggs aren't loaded
import pytest
errno = pytest.main(shlex.split(self.pytest_args))
sys.exit(errno)
setup( setup(
name='certbot-apache', name='certbot-apache',
version=version, version=version,
@ -64,4 +82,6 @@ setup(
], ],
}, },
test_suite='certbot_apache', test_suite='certbot_apache',
tests_require=["pytest"],
cmdclass={"test": PyTest},
) )

View file

@ -1,5 +1,7 @@
from setuptools import setup from setuptools import setup
from setuptools import find_packages from setuptools import find_packages
from setuptools.command.test import test as TestCommand
import sys
version = '0.32.0.dev0' version = '0.32.0.dev0'
@ -21,6 +23,22 @@ docs_extras = [
'sphinx_rtd_theme', 'sphinx_rtd_theme',
] ]
class PyTest(TestCommand):
user_options = []
def initialize_options(self):
TestCommand.initialize_options(self)
self.pytest_args = ''
def run_tests(self):
import shlex
# import here, cause outside the eggs aren't loaded
import pytest
errno = pytest.main(shlex.split(self.pytest_args))
sys.exit(errno)
setup( setup(
name='certbot-nginx', name='certbot-nginx',
version=version, version=version,
@ -64,4 +82,6 @@ setup(
], ],
}, },
test_suite='certbot_nginx', test_suite='certbot_nginx',
tests_require=["pytest"],
cmdclass={"test": PyTest},
) )

View file

@ -41,6 +41,7 @@ class LockFileTest(test_util.TempDirTestCase):
super(LockFileTest, self).setUp() super(LockFileTest, self).setUp()
self.lock_path = os.path.join(self.tempdir, 'test.lock') self.lock_path = os.path.join(self.tempdir, 'test.lock')
@test_util.broken_on_windows
def test_acquire_without_deletion(self): def test_acquire_without_deletion(self):
# acquire the lock in another process but don't delete the file # acquire the lock in another process but don't delete the file
child = multiprocessing.Process(target=self._call, child = multiprocessing.Process(target=self._call,
@ -58,6 +59,7 @@ class LockFileTest(test_util.TempDirTestCase):
self.assertRaises, errors.LockError, self._call, self.lock_path) self.assertRaises, errors.LockError, self._call, self.lock_path)
test_util.lock_and_call(assert_raises, self.lock_path) test_util.lock_and_call(assert_raises, self.lock_path)
@test_util.broken_on_windows
def test_locked_repr(self): def test_locked_repr(self):
lock_file = self._call(self.lock_path) lock_file = self._call(self.lock_path)
locked_repr = repr(lock_file) locked_repr = repr(lock_file)
@ -92,6 +94,7 @@ class LockFileTest(test_util.TempDirTestCase):
self._call(self.lock_path) self._call(self.lock_path)
self.assertFalse(should_delete) self.assertFalse(should_delete)
@test_util.broken_on_windows
def test_removed(self): def test_removed(self):
lock_file = self._call(self.lock_path) lock_file = self._call(self.lock_path)
lock_file.release() lock_file.release()

View file

@ -3,13 +3,14 @@
.. warning:: This module is not part of the public API. .. warning:: This module is not part of the public API.
""" """
import logging
import os import os
import pkg_resources import pkg_resources
import shutil import shutil
import stat
import tempfile import tempfile
import unittest import unittest
import sys import sys
import warnings
from multiprocessing import Process, Event from multiprocessing import Process, Event
from cryptography.hazmat.backends import default_backend from cryptography.hazmat.backends import default_backend
@ -329,23 +330,25 @@ class TempDirTestCase(unittest.TestCase):
def tearDown(self): def tearDown(self):
"""Execute after test""" """Execute after test"""
# On Windows we have various files which are not correctly closed at the time of tearDown. # Cleanup opened resources after a test. This is usually done through atexit handlers in
# For know, we log them until a proper file close handling is written. # Certbot, but during tests, atexit will not run registered functions before tearDown is
# Useful for development only, so no warning when we are on a CI process. # called and instead will run them right before the entire test process exits.
def onerror_handler(_, path, excinfo): # It is a problem on Windows, that does not accept to clean resources before closing them.
"""On error handler""" logging.shutdown()
if not os.environ.get('APPVEYOR'): # pragma: no cover # Remove logging handlers that have been closed so they won't be
message = ('Following error occurred when deleting the tempdir {0}' # accidentally used in future tests.
' for path {1} during tearDown process: {2}' logging.getLogger().handlers = []
.format(self.tempdir, path, str(excinfo))) util._release_locks() # pylint: disable=protected-access
warnings.warn(message)
shutil.rmtree(self.tempdir, onerror=onerror_handler) def handle_rw_files(_, path, __):
"""Handle read-only files, that will fail to be removed on Windows."""
os.chmod(path, stat.S_IWRITE)
os.remove(path)
shutil.rmtree(self.tempdir, onerror=handle_rw_files)
class ConfigTestCase(TempDirTestCase): class ConfigTestCase(TempDirTestCase):
"""Test class which sets up a NamespaceConfig object. """Test class which sets up a NamespaceConfig object."""
"""
def setUp(self): def setUp(self):
super(ConfigTestCase, self).setUp() super(ConfigTestCase, self).setUp()
self.config = configuration.NamespaceConfig( self.config = configuration.NamespaceConfig(

View file

@ -193,7 +193,12 @@ class CheckPermissionsTest(test_util.TempDirTestCase):
def test_wrong_mode(self): def test_wrong_mode(self):
os.chmod(self.tempdir, 0o400) os.chmod(self.tempdir, 0o400)
self.assertFalse(self._call(0o600)) try:
self.assertFalse(self._call(0o600))
finally:
# Without proper write permissions, Windows is unable to delete a folder,
# even with admin permissions. Write access must be explicitly set first.
os.chmod(self.tempdir, 0o700)
class UniqueFileTest(test_util.TempDirTestCase): class UniqueFileTest(test_util.TempDirTestCase):
@ -279,20 +284,9 @@ class UniqueLineageNameTest(test_util.TempDirTestCase):
for f, _ in items: for f, _ in items:
f.close() f.close()
@mock.patch("certbot.util.os.fdopen") def test_failure(self):
def test_failure(self, mock_fdopen): with mock.patch("certbot.util.os.open", side_effect=OSError(errno.EIO)):
err = OSError("whoops") self.assertRaises(OSError, self._call, "wow")
err.errno = errno.EIO
mock_fdopen.side_effect = err
self.assertRaises(OSError, self._call, "wow")
@mock.patch("certbot.util.os.fdopen")
def test_subsequent_failure(self, mock_fdopen):
self._call("wow")
err = OSError("whoops")
err.errno = errno.EIO
mock_fdopen.side_effect = err
self.assertRaises(OSError, self._call, "wow")
class SafelyRemoveTest(test_util.TempDirTestCase): class SafelyRemoveTest(test_util.TempDirTestCase):

View file

@ -142,6 +142,7 @@ def _release_locks():
except: # pylint: disable=bare-except except: # pylint: disable=bare-except
msg = 'Exception occurred releasing lock: {0!r}'.format(dir_lock) msg = 'Exception occurred releasing lock: {0!r}'.format(dir_lock)
logger.debug(msg, exc_info=True) logger.debug(msg, exc_info=True)
_LOCKS.clear()
def set_up_core_dir(directory, mode, uid, strict): def set_up_core_dir(directory, mode, uid, strict):
@ -225,9 +226,8 @@ def safe_open(path, mode="w", chmod=None, buffering=None):
fdopen_args = () # type: Union[Tuple[()], Tuple[int]] fdopen_args = () # type: Union[Tuple[()], Tuple[int]]
if buffering is not None: if buffering is not None:
fdopen_args = (buffering,) fdopen_args = (buffering,)
return os.fdopen( fd = os.open(path, os.O_CREAT | os.O_EXCL | os.O_RDWR, *open_args)
os.open(path, os.O_CREAT | os.O_EXCL | os.O_RDWR, *open_args), return os.fdopen(fd, mode, *fdopen_args)
mode, *fdopen_args)
def _unique_file(path, filename_pat, count, chmod, mode): def _unique_file(path, filename_pat, count, chmod, mode):

View file

@ -1,8 +1,10 @@
import codecs import codecs
import os import os
import re import re
import sys
from setuptools import find_packages, setup from setuptools import find_packages, setup
from setuptools.command.test import test as TestCommand
# Workaround for http://bugs.python.org/issue8876, see # Workaround for http://bugs.python.org/issue8876, see
# http://bugs.python.org/issue8876#msg208792 # http://bugs.python.org/issue8876#msg208792
@ -77,6 +79,22 @@ docs_extras = [
'sphinx_rtd_theme', 'sphinx_rtd_theme',
] ]
class PyTest(TestCommand):
user_options = []
def initialize_options(self):
TestCommand.initialize_options(self)
self.pytest_args = ''
def run_tests(self):
import shlex
# import here, cause outside the eggs aren't loaded
import pytest
errno = pytest.main(shlex.split(self.pytest_args))
sys.exit(errno)
setup( setup(
name='certbot', name='certbot',
version=version, version=version,
@ -123,6 +141,8 @@ setup(
# to test all packages run "python setup.py test -s # to test all packages run "python setup.py test -s
# {acme,certbot_apache,certbot_nginx}" # {acme,certbot_apache,certbot_nginx}"
test_suite='certbot', test_suite='certbot',
tests_require=["pytest"],
cmdclass={"test": PyTest},
entry_points={ entry_points={
'console_scripts': [ 'console_scripts': [