diff --git a/.coveragerc b/.coveragerc index 087900105..1a87ab2da 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1,3 +1,2 @@ [report] -# show lines missing coverage in output -show_missing = True +omit = */setup.py diff --git a/.travis.yml b/.travis.yml index 48b9b43cb..359801622 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,35 +10,23 @@ before_install: before_script: - 'if [ $TRAVIS_OS_NAME = osx ] ; then ulimit -n 1024 ; fi' -# using separate envs with different TOXENVs creates 4x1 Travis build -# matrix, which allows us to clearly distinguish which component under -# test has failed matrix: include: - python: "2.7" - env: TOXENV=cover + env: TOXENV=cover FYI="this also tests py27" - python: "2.7" env: TOXENV=lint - python: "2.7" - env: TOXENV=py27-oldest BOULDER_INTEGRATION=1 + env: TOXENV=py27-oldest sudo: required - after_failure: - - sudo cat /var/log/mysql/error.log - - ps aux | grep mysql services: docker - python: "2.6" - env: TOXENV=py26 BOULDER_INTEGRATION=1 + env: TOXENV=py26 sudo: required - after_failure: - - sudo cat /var/log/mysql/error.log - - ps aux | grep mysql services: docker - python: "2.7" env: TOXENV=py27_install BOULDER_INTEGRATION=1 sudo: required - after_failure: - - sudo cat /var/log/mysql/error.log - - ps aux | grep mysql services: docker - sudo: required env: TOXENV=apache_compat @@ -79,41 +67,23 @@ matrix: env: TOXENV=apacheconftest sudo: required - python: "3.3" - env: TOXENV=py33 BOULDER_INTEGRATION=1 + env: TOXENV=py33 sudo: required - after_failure: - - sudo cat /var/log/mysql/error.log - - ps aux | grep mysql services: docker - python: "3.4" - env: TOXENV=py34 BOULDER_INTEGRATION=1 + env: TOXENV=py34 sudo: required - after_failure: - - sudo cat /var/log/mysql/error.log - - ps aux | grep mysql services: docker - python: "3.5" - env: TOXENV=py35 BOULDER_INTEGRATION=1 + env: TOXENV=py35 sudo: required - after_failure: - - sudo cat /var/log/mysql/error.log - - ps aux | grep mysql services: docker - python: "3.6" - env: TOXENV=py36 BOULDER_INTEGRATION=1 + env: TOXENV=py36 sudo: required - after_failure: - - sudo cat /var/log/mysql/error.log - - ps aux | grep mysql services: docker - python: "2.7" env: TOXENV=nginxroundtrip - - language: generic - env: TOXENV=py27 - os: osx - - language: generic - env: TOXENV=py36 - os: osx # Only build pushes to the master branch, PRs, and branches beginning with @@ -130,17 +100,6 @@ branches: sudo: false addons: - # Custom /etc/hosts required for simple verification of http-01 - # and tls-sni-01, and for certbot_test_nginx - hosts: - - le.wtf - - le1.wtf - - le2.wtf - - le3.wtf - - nginx.wtf - - boulder - - boulder-mysql - - boulder-rabbitmq apt: sources: - augeas @@ -160,7 +119,7 @@ addons: - libapache2-mod-wsgi - libapache2-mod-macro -install: "travis_retry pip install tox coveralls" +install: "travis_retry $(command -v pip || command -v pip3) install tox coveralls" script: - travis_retry tox - '[ -z "${BOULDER_INTEGRATION+x}" ] || (travis_retry tests/boulder-fetch.sh && tests/tox-boulder-integration.sh)' diff --git a/acme/acme/crypto_util_test.py b/acme/acme/crypto_util_test.py index 4046aa197..da433c5a2 100644 --- a/acme/acme/crypto_util_test.py +++ b/acme/acme/crypto_util_test.py @@ -18,7 +18,6 @@ from acme import test_util class SSLSocketAndProbeSNITest(unittest.TestCase): """Tests for acme.crypto_util.SSLSocket/probe_sni.""" - _multiprocess_can_split_ = True def setUp(self): self.cert = test_util.load_comparable_cert('rsa2048_cert.pem') @@ -69,7 +68,6 @@ class SSLSocketAndProbeSNITest(unittest.TestCase): class PyOpenSSLCertOrReqSANTest(unittest.TestCase): """Test for acme.crypto_util._pyopenssl_cert_or_req_san.""" - _multiprocess_can_split_ = True @classmethod def _call(cls, loader, name): @@ -140,7 +138,6 @@ class PyOpenSSLCertOrReqSANTest(unittest.TestCase): class RandomSnTest(unittest.TestCase): """Test for random certificate serial numbers.""" - _multiprocess_can_split_ = True def setUp(self): self.cert_count = 5 diff --git a/acme/acme/messages_test.py b/acme/acme/messages_test.py index 6692ef905..ad37cd12b 100644 --- a/acme/acme/messages_test.py +++ b/acme/acme/messages_test.py @@ -71,6 +71,12 @@ class ErrorTest(unittest.TestCase): self.assertTrue(is_acme_error(Error.with_code('badCSR'))) self.assertRaises(ValueError, Error.with_code, 'not an ACME error code') + def test_str(self): + self.assertEqual( + str(self.error), + u"{0.typ} :: {0.description} :: {0.detail} :: {0.title}" + .format(self.error)) + class ConstantTest(unittest.TestCase): """Tests for acme.messages._Constant.""" diff --git a/acme/acme/standalone_test.py b/acme/acme/standalone_test.py index 16669680c..48e13d0b6 100644 --- a/acme/acme/standalone_test.py +++ b/acme/acme/standalone_test.py @@ -23,7 +23,6 @@ from acme import test_util class TLSServerTest(unittest.TestCase): """Tests for acme.standalone.TLSServer.""" - _multiprocess_can_split_ = True def test_bind(self): # pylint: disable=no-self-use from acme.standalone import TLSServer @@ -42,7 +41,6 @@ class TLSServerTest(unittest.TestCase): class TLSSNI01ServerTest(unittest.TestCase): """Test for acme.standalone.TLSSNI01Server.""" - _multiprocess_can_split_ = True def setUp(self): self.certs = {b'localhost': ( @@ -70,7 +68,6 @@ class TLSSNI01ServerTest(unittest.TestCase): class HTTP01ServerTest(unittest.TestCase): """Tests for acme.standalone.HTTP01Server.""" - _multiprocess_can_split_ = True def setUp(self): self.account_key = jose.JWK.load( @@ -124,7 +121,6 @@ class HTTP01ServerTest(unittest.TestCase): class BaseDualNetworkedServersTest(unittest.TestCase): """Test for acme.standalone.BaseDualNetworkedServers.""" - _multiprocess_can_split_ = True class SingleProtocolServer(socketserver.TCPServer): """Server that only serves on a single protocol. FreeBSD has this behavior for AF_INET6.""" @@ -174,7 +170,6 @@ class BaseDualNetworkedServersTest(unittest.TestCase): class TLSSNI01DualNetworkedServersTest(unittest.TestCase): """Test for acme.standalone.TLSSNI01DualNetworkedServers.""" - _multiprocess_can_split_ = True def setUp(self): self.certs = {b'localhost': ( @@ -202,7 +197,6 @@ class TLSSNI01DualNetworkedServersTest(unittest.TestCase): class HTTP01DualNetworkedServersTest(unittest.TestCase): """Tests for acme.standalone.HTTP01DualNetworkedServers.""" - _multiprocess_can_split_ = True def setUp(self): self.account_key = jose.JWK.load( @@ -254,7 +248,6 @@ class HTTP01DualNetworkedServersTest(unittest.TestCase): class TestSimpleTLSSNI01Server(unittest.TestCase): """Tests for acme.standalone.simple_tls_sni_01_server.""" - _multiprocess_can_split_ = True def setUp(self): # mirror ../examples/standalone diff --git a/acme/setup.py b/acme/setup.py index c86a72b9d..c28e0c152 100644 --- a/acme/setup.py +++ b/acme/setup.py @@ -31,7 +31,8 @@ if sys.version_info < (2, 7): ]) dev_extras = [ - 'nose', + 'pytest', + 'pytest-xdist', 'tox', ] diff --git a/certbot-apache/certbot_apache/tests/augeas_configurator_test.py b/certbot-apache/certbot_apache/tests/augeas_configurator_test.py index 742afce2d..c121ecdf3 100644 --- a/certbot-apache/certbot_apache/tests/augeas_configurator_test.py +++ b/certbot-apache/certbot_apache/tests/augeas_configurator_test.py @@ -13,7 +13,6 @@ from certbot_apache.tests import util class AugeasConfiguratorTest(util.ApacheTest): """Test for Augeas Configurator base class.""" - _multiprocess_can_split_ = True def setUp(self): # pylint: disable=arguments-differ super(AugeasConfiguratorTest, self).setUp() diff --git a/certbot-apache/certbot_apache/tests/configurator_test.py b/certbot-apache/certbot_apache/tests/configurator_test.py index 7c6b071da..90561d6ad 100644 --- a/certbot-apache/certbot_apache/tests/configurator_test.py +++ b/certbot-apache/certbot_apache/tests/configurator_test.py @@ -30,7 +30,6 @@ from certbot_apache.tests import util class MultipleVhostsTest(util.ApacheTest): """Test two standard well-configured HTTP vhosts.""" - _multiprocess_can_split_ = True def setUp(self): # pylint: disable=arguments-differ super(MultipleVhostsTest, self).setUp() @@ -1369,7 +1368,6 @@ class MultipleVhostsTest(util.ApacheTest): class AugeasVhostsTest(util.ApacheTest): """Test vhosts with illegal names dependent on augeas version.""" # pylint: disable=protected-access - _multiprocess_can_split_ = True def setUp(self): # pylint: disable=arguments-differ td = "debian_apache_2_4/augeas_vhosts" diff --git a/certbot-dns-digitalocean/certbot_dns_digitalocean/dns_digitalocean_test.py b/certbot-dns-digitalocean/certbot_dns_digitalocean/dns_digitalocean_test.py index 11c8c57d5..0fdacf4ad 100644 --- a/certbot-dns-digitalocean/certbot_dns_digitalocean/dns_digitalocean_test.py +++ b/certbot-dns-digitalocean/certbot_dns_digitalocean/dns_digitalocean_test.py @@ -5,7 +5,6 @@ import unittest import digitalocean import mock -import six from certbot import errors from certbot.plugins import dns_test_common @@ -134,8 +133,8 @@ class DigitalOceanClientTest(unittest.TestCase): correct_record_mock.destroy.assert_called() - six.assertCountEqual(self, first_record_mock.destroy.call_args_list, []) - six.assertCountEqual(self, last_record_mock.destroy.call_args_list, []) + self.assertFalse(first_record_mock.destroy.call_args_list) + self.assertFalse(last_record_mock.destroy.call_args_list) def test_del_txt_record_error_finding_domain(self): self.manager.get_all_domains.side_effect = API_ERROR diff --git a/certbot-nginx/certbot_nginx/tests/configurator_test.py b/certbot-nginx/certbot_nginx/tests/configurator_test.py index aa94abecb..996bd238b 100644 --- a/certbot-nginx/certbot_nginx/tests/configurator_test.py +++ b/certbot-nginx/certbot_nginx/tests/configurator_test.py @@ -24,7 +24,6 @@ from certbot_nginx.tests import util class NginxConfiguratorTest(util.NginxTest): """Test a semi complex vhost configuration.""" - _multiprocess_can_split_ = True def setUp(self): super(NginxConfiguratorTest, self).setUp() diff --git a/certbot/cli.py b/certbot/cli.py index 3a12f86c7..622462278 100644 --- a/certbot/cli.py +++ b/certbot/cli.py @@ -828,11 +828,11 @@ class HelpfulArgumentParser(object): return dict([(t, t == chosen_topic) for t in self.help_topics]) def _add_all_groups(helpful): - helpful.add_group("automation", description="Arguments for automating execution & other tweaks") + helpful.add_group("automation", description="Flags for automating execution & other tweaks") helpful.add_group("security", description="Security parameters & server settings") helpful.add_group("testing", description="The following flags are meant for testing and integration purposes only.") - helpful.add_group("paths", description="Arguments changing execution paths & servers") + helpful.add_group("paths", description="Flags for changing execution paths & servers") helpful.add_group("manage", description="Various subcommands and flags are available for managing your certificates:", verbs=["certificates", "delete", "renew", "revoke", "update_symlinks"]) diff --git a/certbot/tests/cli_test.py b/certbot/tests/cli_test.py index ba5e2775f..2fce412e2 100644 --- a/certbot/tests/cli_test.py +++ b/certbot/tests/cli_test.py @@ -26,7 +26,6 @@ PLUGINS = disco.PluginsRegistry.find_all() class TestReadFile(TempDirTestCase): '''Test cli.read_file''' - _multiprocess_can_split_ = True def test_read_file(self): rel_test_path = os.path.relpath(os.path.join(self.tempdir, 'foo')) @@ -46,7 +45,6 @@ class TestReadFile(TempDirTestCase): class ParseTest(unittest.TestCase): # pylint: disable=too-many-public-methods '''Test the cli args entrypoint''' - _multiprocess_can_split_ = True def setUp(self): reload_module(cli) @@ -418,7 +416,6 @@ class ParseTest(unittest.TestCase): # pylint: disable=too-many-public-methods class DefaultTest(unittest.TestCase): """Tests for certbot.cli._Default.""" - _multiprocess_can_split_ = True def setUp(self): # pylint: disable=protected-access @@ -439,7 +436,6 @@ class DefaultTest(unittest.TestCase): class SetByCliTest(unittest.TestCase): """Tests for certbot.set_by_cli and related functions.""" - _multiprocess_can_split_ = True def setUp(self): reload_module(cli) diff --git a/certbot/tests/ocsp_test.py b/certbot/tests/ocsp_test.py index 91dd6f8d6..2d54274f0 100644 --- a/certbot/tests/ocsp_test.py +++ b/certbot/tests/ocsp_test.py @@ -13,7 +13,6 @@ ocsp: Use -help for summary. class OCSPTest(unittest.TestCase): - _multiprocess_can_split_ = True def setUp(self): from certbot import ocsp diff --git a/certbot/tests/storage_test.py b/certbot/tests/storage_test.py index df6391758..6c8f775e2 100644 --- a/certbot/tests/storage_test.py +++ b/certbot/tests/storage_test.py @@ -43,7 +43,6 @@ class BaseRenewableCertTest(test_util.ConfigTestCase): your test. Check :class:`.cli_test.DuplicateCertTest` for an example. """ - _multiprocess_can_split_ = True def setUp(self): from certbot import storage diff --git a/docs/install.rst b/docs/install.rst index 1f6a45e07..a914586ff 100644 --- a/docs/install.rst +++ b/docs/install.rst @@ -156,7 +156,7 @@ If you run Debian Stretch or Debian Sid, you can install certbot packages. sudo apt-get install certbot python-certbot-apache If you don't want to use the Apache plugin, you can omit the -``python-certbot-apache`` package. +``python-certbot-apache`` package. Or you can install ``python-certbot-nginx`` instead. Packages exist for Debian Jessie via backports. First you'll have to follow the instructions at http://backports.debian.org/Instructions/ to enable the Jessie backports diff --git a/letsencrypt-auto-source/Dockerfile.centos6 b/letsencrypt-auto-source/Dockerfile.centos6 index e1280109b..8c1a4b353 100644 --- a/letsencrypt-auto-source/Dockerfile.centos6 +++ b/letsencrypt-auto-source/Dockerfile.centos6 @@ -5,9 +5,13 @@ FROM centos:6 RUN yum install -y epel-release -# Install pip, sudo and nose: +# Install pip and sudo: RUN yum install -y python-pip sudo -RUN pip install nose +# Use pipstrap to update to a stable and tested version of pip +COPY ./pieces/pipstrap.py /opt +RUN /opt/pipstrap.py +# Pin pytest version for increased stability +RUN pip install pytest==3.2.5 # Add an unprivileged user: RUN useradd --create-home --home-dir /home/lea --shell /bin/bash --groups wheel --uid 1000 lea @@ -29,4 +33,4 @@ COPY . /home/lea/certbot/letsencrypt-auto-source USER lea WORKDIR /home/lea -CMD ["nosetests", "-v", "-s", "certbot/letsencrypt-auto-source/tests"] +CMD ["pytest", "-v", "-s", "certbot/letsencrypt-auto-source/tests"] diff --git a/letsencrypt-auto-source/Dockerfile.precise b/letsencrypt-auto-source/Dockerfile.precise index 5ee32c7cc..71d572315 100644 --- a/letsencrypt-auto-source/Dockerfile.precise +++ b/letsencrypt-auto-source/Dockerfile.precise @@ -6,13 +6,16 @@ FROM ubuntu:precise # Add an unprivileged user: RUN useradd --create-home --home-dir /home/lea --shell /bin/bash --groups sudo --uid 1000 lea -# Install pip, sudo, openssl, and nose: +# Install pip, sudo, and openssl: RUN apt-get update && \ apt-get -q -y install python-pip sudo openssl && \ apt-get clean -ENV PIP_INDEX_URL https://pypi.python.org/simple -RUN pip install nose +# Use pipstrap to update to a stable and tested version of pip +COPY ./pieces/pipstrap.py /opt +RUN /opt/pipstrap.py +# Pin pytest version for increased stability +RUN pip install pytest==3.2.5 # Let that user sudo: RUN sed -i.bkp -e \ @@ -30,4 +33,4 @@ COPY . /home/lea/certbot/letsencrypt-auto-source USER lea WORKDIR /home/lea -CMD ["nosetests", "-v", "-s", "certbot/letsencrypt-auto-source/tests"] +CMD ["pytest", "-v", "-s", "certbot/letsencrypt-auto-source/tests"] diff --git a/letsencrypt-auto-source/Dockerfile.trusty b/letsencrypt-auto-source/Dockerfile.trusty index 23e8f26de..e0aacd118 100644 --- a/letsencrypt-auto-source/Dockerfile.trusty +++ b/letsencrypt-auto-source/Dockerfile.trusty @@ -11,11 +11,15 @@ RUN sed -i.bkp -e \ 's/%sudo\s\+ALL=(ALL\(:ALL\)\?)\s\+ALL/%sudo ALL=NOPASSWD:ALL/g' \ /etc/sudoers -# Install pip and nose: +# Install pip: RUN apt-get update && \ apt-get -q -y install python-pip && \ apt-get clean -RUN pip install nose +# Use pipstrap to update to a stable and tested version of pip +COPY ./pieces/pipstrap.py /opt +RUN /opt/pipstrap.py +# Pin pytest version for increased stability +RUN pip install pytest==3.2.5 RUN mkdir -p /home/lea/certbot @@ -29,4 +33,4 @@ COPY . /home/lea/certbot/letsencrypt-auto-source USER lea WORKDIR /home/lea -CMD ["nosetests", "-v", "-s", "certbot/letsencrypt-auto-source/tests"] +CMD ["pytest", "-v", "-s", "certbot/letsencrypt-auto-source/tests"] diff --git a/letsencrypt-auto-source/Dockerfile.wheezy b/letsencrypt-auto-source/Dockerfile.wheezy index acdb791a4..56948d22a 100644 --- a/letsencrypt-auto-source/Dockerfile.wheezy +++ b/letsencrypt-auto-source/Dockerfile.wheezy @@ -6,13 +6,15 @@ FROM debian:wheezy # Add an unprivileged user: RUN useradd --create-home --home-dir /home/lea --shell /bin/bash --groups sudo --uid 1000 lea -# Install pip, sudo, openssl, and nose: +# Install pip, sudo, and openssl: RUN apt-get update && \ apt-get -q -y install python-pip sudo openssl && \ apt-get clean - -ENV PIP_INDEX_URL https://pypi.python.org/simple -RUN pip install nose +# Use pipstrap to update to a stable and tested version of pip +COPY ./pieces/pipstrap.py /opt +RUN /opt/pipstrap.py +# Pin pytest version for increased stability +RUN pip install pytest==3.2.5 # Let that user sudo: RUN sed -i.bkp -e \ @@ -30,4 +32,4 @@ COPY . /home/lea/certbot/letsencrypt-auto-source USER lea WORKDIR /home/lea -CMD ["nosetests", "-v", "-s", "certbot/letsencrypt-auto-source/tests"] +CMD ["pytest", "-v", "-s", "certbot/letsencrypt-auto-source/tests"] diff --git a/letsencrypt-auto-source/tests/auto_test.py b/letsencrypt-auto-source/tests/auto_test.py index 5c63325ee..2fa03105d 100644 --- a/letsencrypt-auto-source/tests/auto_test.py +++ b/letsencrypt-auto-source/tests/auto_test.py @@ -17,10 +17,10 @@ from tempfile import mkdtemp from threading import Thread from unittest import TestCase -from nose.tools import eq_, nottest, ok_ +from pytest import mark -@nottest +@mark.skip def tests_dir(): """Return a path to the "tests" directory.""" return dirname(abspath(__file__)) @@ -279,8 +279,8 @@ class AutoTests(TestCase): # installed, and pip hashes verify: install_le_auto(build_le_auto(version='50.0.0'), le_auto_path) out, err = run_letsencrypt_auto() - ok_(re.match(r'letsencrypt \d+\.\d+\.\d+', - err.strip().splitlines()[-1])) + self.assertTrue(re.match(r'letsencrypt \d+\.\d+\.\d+', + err.strip().splitlines()[-1])) # Make a few assertions to test the validity of the next tests: self.assertTrue('Upgrading certbot-auto ' in out) self.assertTrue('Creating virtual environment...' in out) @@ -327,7 +327,7 @@ class AutoTests(TestCase): try: out, err = run_le_auto(le_auto_path, venv_dir, base_url) except CalledProcessError as exc: - eq_(exc.returncode, 1) + self.assertEqual(exc.returncode, 1) self.assertTrue("Couldn't verify signature of downloaded " "certbot-auto." in exc.output) else: @@ -348,10 +348,11 @@ class AutoTests(TestCase): try: out, err = run_le_auto(le_auto_path, venv_dir, base_url) except CalledProcessError as exc: - eq_(exc.returncode, 1) + self.assertEqual(exc.returncode, 1) self.assertTrue("THESE PACKAGES DO NOT MATCH THE HASHES " "FROM THE REQUIREMENTS FILE" in exc.output) - ok_(not exists(venv_dir), + self.assertFalse( + exists(venv_dir), msg="The virtualenv was left around, even though " "installation didn't succeed. We shouldn't do " "this, as it foils our detection of whether we " diff --git a/setup.cfg b/setup.cfg index 3b4dbaf87..a21bab793 100644 --- a/setup.cfg +++ b/setup.cfg @@ -3,9 +3,3 @@ universal = 1 [easy_install] zip_ok = false - -[nosetests] -nocapture=1 -cover-package=certbot,acme,certbot_apache,certbot_nginx -cover-erase=1 -cover-tests=1 diff --git a/setup.py b/setup.py index 6ffc9a134..ee108c514 100644 --- a/setup.py +++ b/setup.py @@ -67,7 +67,9 @@ dev_extras = [ 'astroid==1.3.5', 'coverage', 'ipdb', - 'nose', + 'pytest', + 'pytest-cov', + 'pytest-xdist', 'pylint==1.4.2', # upstream #248 'tox', 'twine', diff --git a/tests/letstest/scripts/test_sdists.sh b/tests/letstest/scripts/test_sdists.sh index ced21e338..f18a64065 100755 --- a/tests/letstest/scripts/test_sdists.sh +++ b/tests/letstest/scripts/test_sdists.sh @@ -7,13 +7,11 @@ PLUGINS="certbot-apache certbot-nginx" PYTHON=$(command -v python2.7 || command -v python27 || command -v python2 || command -v python) TEMP_DIR=$(mktemp -d) VERSION=$(letsencrypt-auto-source/version.py) +export VENV_ARGS="-p $PYTHON" # setup venv -virtualenv --no-site-packages -p $PYTHON --setuptools venv +tools/_venv_common.sh --requirement letsencrypt-auto-source/pieces/dependency-requirements.txt . ./venv/bin/activate -pip install -U pip -pip install -U setuptools -pip install --requirement letsencrypt-auto-source/pieces/dependency-requirements.txt # build sdists for pkg_dir in acme . $PLUGINS; do diff --git a/tests/letstest/scripts/test_tests.sh b/tests/letstest/scripts/test_tests.sh index 6d67bdf2e..4bed2dd3a 100755 --- a/tests/letstest/scripts/test_tests.sh +++ b/tests/letstest/scripts/test_tests.sh @@ -10,9 +10,9 @@ LE_AUTO_SUDO="" VENV_PATH=$VENV_NAME letsencrypt/certbot-auto --debug --no-boots # change to an empty directory to ensure CWD doesn't affect tests cd $(mktemp -d) -pip install nose +pip install pytest==3.2.5 for module in $MODULES ; do echo testing $module - nosetests -v $module + pytest -v --pyargs $module done diff --git a/tools/_venv_common.sh b/tools/_venv_common.sh index 20ed4c034..0f0ff7e28 100755 --- a/tools/_venv_common.sh +++ b/tools/_venv_common.sh @@ -15,10 +15,10 @@ mv $VENV_NAME "$VENV_NAME.$(date +%s).bak" || true virtualenv --no-site-packages --setuptools $VENV_NAME $VENV_ARGS . ./$VENV_NAME/bin/activate -# Separately install setuptools and pip to make sure following -# invocations use latest -pip install -U pip -pip install -U setuptools +# Use pipstrap to update Python packaging tools to only update to a well tested +# version and to work around https://github.com/pypa/pip/issues/4817 on older +# systems. +python letsencrypt-auto-source/pieces/pipstrap.py ./tools/pip_install.sh "$@" set +x diff --git a/tools/install_and_test.sh b/tools/install_and_test.sh index 0de2ea3f8..0edb41c53 100755 --- a/tools/install_and_test.sh +++ b/tools/install_and_test.sh @@ -16,6 +16,10 @@ for requirement in "$@" ; do pkg=$(echo $requirement | cut -f1 -d\[) # remove any extras such as [dev] if [ $pkg = "." ]; then pkg="certbot" + else + # Work around a bug in pytest/importlib for the deprecated Python 3.3. + # See https://travis-ci.org/certbot/certbot/jobs/308774157#L1333. + pkg=$(echo "$pkg" | tr - _) fi - nosetests -v $pkg --processes=-1 --process-timeout=100 + pytest --numprocesses auto --quiet --pyargs $pkg done diff --git a/tools/pip_constraints.txt b/tools/pip_constraints.txt new file mode 100644 index 000000000..cacec37d6 --- /dev/null +++ b/tools/pip_constraints.txt @@ -0,0 +1,70 @@ +# Specifies Python package versions for packages not specified in +# letsencrypt-auto's requirements file. We should avoid listing packages in +# both places because if both files are used as constraints for the same pip +# invocation, some constraints may be ignored due to pip's lack of dependency +# resolution. +alabaster==0.7.10 +apipkg==1.4 +astroid==1.3.5 +Babel==2.5.1 +backports.shutil-get-terminal-size==1.0.0 +boto3==1.4.7 +botocore==1.7.41 +cloudflare==1.8.1 +coverage==4.4.2 +decorator==4.1.2 +dns-lexicon==2.1.14 +dnspython==1.15.0 +docutils==0.14 +execnet==1.5.0 +future==0.16.0 +futures==3.1.1 +google-api-python-client==1.6.4 +httplib2==0.10.3 +imagesize==0.7.1 +ipdb==0.10.3 +ipython==5.5.0 +ipython-genutils==0.2.0 +Jinja2==2.9.6 +jmespath==0.9.3 +logilab-common==1.4.1 +MarkupSafe==1.0 +oauth2client==4.1.2 +pathlib2==2.3.0 +pexpect==4.2.1 +pickleshare==0.7.4 +pkg-resources==0.0.0 +pkginfo==1.4.1 +pluggy==0.5.2 +prompt-toolkit==1.0.15 +ptyprocess==0.5.2 +py==1.4.34 +pyasn1==0.3.7 +pyasn1-modules==0.1.5 +Pygments==2.2.0 +pylint==1.4.2 +pytest==3.2.5 +pytest-cov==2.5.1 +pytest-forked==0.2 +pytest-xdist==1.20.1 +python-dateutil==2.6.1 +python-digitalocean==1.12 +PyYAML==3.12 +repoze.sphinx.autointerface==0.8 +requests-file==1.4.2 +requests-toolbelt==0.8.0 +rsa==3.4.2 +s3transfer==0.1.11 +scandir==1.6 +simplegeneric==0.8.1 +snowballstemmer==1.2.1 +Sphinx==1.5.6 +sphinx-rtd-theme==0.2.4 +tldextract==2.2.0 +tox==2.9.1 +tqdm==4.19.4 +traitlets==4.3.2 +twine==1.9.1 +uritemplate==3.0.0 +virtualenv==15.1.0 +wcwidth==0.1.7 diff --git a/tools/pip_install.sh b/tools/pip_install.sh index 438e567e4..194501c7d 100755 --- a/tools/pip_install.sh +++ b/tools/pip_install.sh @@ -1,14 +1,15 @@ #!/bin/sh -e -# pip installs packages using Certbot's requirements file as constraints +# pip installs packages using pinned package versions # get the root of the Certbot repo my_path=$("$(dirname $0)/readlink.py" $0) repo_root=$(dirname $(dirname $my_path)) requirements="$repo_root/letsencrypt-auto-source/pieces/dependency-requirements.txt" -constraints=$(mktemp) -trap "rm -f $constraints" EXIT +certbot_auto_constraints=$(mktemp) +trap "rm -f $certbot_auto_constraints" EXIT # extract pinned requirements without hashes -sed -n -e 's/^\([^[:space:]]*==[^[:space:]]*\).*$/\1/p' $requirements > $constraints +sed -n -e 's/^\([^[:space:]]*==[^[:space:]]*\).*$/\1/p' $requirements > $certbot_auto_constraints +dev_constraints="$(dirname $my_path)/pip_constraints.txt" # install the requested packages using the pinned requirements as constraints -pip install --constraint $constraints "$@" +pip install --constraint $certbot_auto_constraints --constraint $dev_constraints "$@" diff --git a/tools/release.sh b/tools/release.sh index 2a8e00aa1..a8de208b5 100755 --- a/tools/release.sh +++ b/tools/release.sh @@ -55,7 +55,7 @@ SUBPKGS="$SUBPKGS_IN_AUTO $SUBPKGS_NOT_IN_AUTO" subpkgs_modules="$(echo $SUBPKGS | sed s/-/_/g)" # certbot_compatibility_test is not packaged because: # - it is not meant to be used by anyone else than Certbot devs -# - it causes problems when running nosetests - the latter tries to +# - it causes problems when running pytest - the latter tries to # run everything that matches test*, while there are no unittests # there @@ -166,10 +166,10 @@ fi mkdir kgs kgs="kgs/$version" pip freeze | tee $kgs -pip install nose +pip install pytest for module in $subpkgs_modules ; do echo testing $module - nosetests $module + pytest --pyargs $module done cd ~- diff --git a/tox.cover.sh b/tox.cover.sh index fc0c9f476..3f0a5f72e 100755 --- a/tox.cover.sh +++ b/tox.cover.sh @@ -16,7 +16,7 @@ fi cover () { if [ "$1" = "certbot" ]; then - min=98 + min=97 elif [ "$1" = "acme" ]; then min=100 elif [ "$1" = "certbot_apache" ]; then @@ -24,23 +24,23 @@ cover () { elif [ "$1" = "certbot_dns_cloudflare" ]; then min=98 elif [ "$1" = "certbot_dns_cloudxns" ]; then - min=99 + min=98 elif [ "$1" = "certbot_dns_digitalocean" ]; then min=98 elif [ "$1" = "certbot_dns_dnsimple" ]; then min=98 elif [ "$1" = "certbot_dns_dnsmadeeasy" ]; then - min=99 + min=98 elif [ "$1" = "certbot_dns_google" ]; then min=99 elif [ "$1" = "certbot_dns_luadns" ]; then min=98 elif [ "$1" = "certbot_dns_nsone" ]; then - min=99 + min=98 elif [ "$1" = "certbot_dns_rfc2136" ]; then min=99 elif [ "$1" = "certbot_dns_route53" ]; then - min=99 + min=91 elif [ "$1" = "certbot_nginx" ]; then min=97 elif [ "$1" = "letshelp_certbot" ]; then @@ -50,17 +50,10 @@ cover () { exit 1 fi - # "-c /dev/null" makes sure setup.cfg is not loaded (multiple - # --with-cover add up, --cover-erase must not be set for coveralls - # to get all the data); --with-cover scopes coverage to only - # specific package, positional argument scopes tests only to - # specific package directory; --cover-tests makes sure every tests - # is run (c.f. #403) - nosetests -c /dev/null --with-cover --cover-tests --cover-package \ - "$1" --cover-min-percentage="$min" "$1" + pytest --cov "$1" --cov-report term-missing \ + --cov-fail-under "$min" --numprocesses auto --pyargs "$1" } -rm -f .coverage # --cover-erase is off, make sure stats are correct for pkg in $pkgs do cover $pkg diff --git a/tox.ini b/tox.ini index dee14b8b3..bb421daa5 100644 --- a/tox.ini +++ b/tox.ini @@ -6,9 +6,6 @@ skipsdist = true envlist = modification,py{26,33,34,35,36},cover,lint -# nosetest -v => more verbose output, allows to detect busy waiting -# loops, especially on Travis - [base] # pip installs the requested packages in editable mode pip_install = {toxinidir}/tools/pip_install_editable.sh @@ -62,6 +59,9 @@ source_paths = commands = {[base]install_and_test} {[base]py26_packages} python tests/lock_test.py +deps = + setuptools==36.8.0 + wheel==0.29.0 [testenv] commands = @@ -71,6 +71,12 @@ setenv = PYTHONPATH = {toxinidir} PYTHONHASHSEED = 0 +[testenv:py33] +commands = + {[testenv]commands} +deps = + wheel==0.29.0 + [testenv:py27-oldest] commands = {[testenv]commands} @@ -96,6 +102,7 @@ deps = pyasn1==0.1.9 pyparsing==1.5.6 pyrfc3339==1.0 + pytest==3.2.5 python-augeas==0.4.1 pytz==2012c requests[security]==2.6.0