diff --git a/Makefile b/Makefile index 5995944e..be299f9f 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ PKGRPMFLAGS=--define "_topdir ${PWD}" --define "_specdir ${PWD}" --define "_sour RPM="noarch/${PKGNAME}-$(VERSION)-$(RELEASE).noarch.rpm" SRPM="${PKGNAME}-$(VERSION)-$(RELEASE).src.rpm" -NOSE=nosetests +PYTEST=pytest all: help @@ -95,10 +95,10 @@ clean: test: - $(NOSE) --exe $(NOSE_OPTS) + $(PYTEST) $(PYTEST_OPTS) test-coverage: - $(NOSE) --exe --with-cov --cov-report html --cov-config tox.ini $(NOSE_OPTS) + $(PYTEST) --cov=pungi --cov-report term --cov-report html --cov-config tox.ini $(PYTEST_OPTS) test-data: ./tests/data/specs/build.sh diff --git a/doc/contributing.rst b/doc/contributing.rst index ca547df0..7844da5e 100644 --- a/doc/contributing.rst +++ b/doc/contributing.rst @@ -42,8 +42,8 @@ These packages will have to installed: For running unit tests, these packages are recommended as well: * python-mock - * python-nose - * python-nose-cov + * python-pytest + * python-pytest-cov * python-unittest2 * rpmdevtools * python-parameterized @@ -61,7 +61,7 @@ packages above as they are used by calling an executable. :: $ for pkg in _deltarpm krbV _selinux deltarpm sqlitecachec _sqlitecache; do ln -vs "$(deactivate && python -c 'import os, '$pkg'; print('$pkg'.__file__)')" "$(virtualenvwrapper_get_site_packages_dir)"; done $ pip install -U pip $ PYCURL_SSL_LIBRARY=nss pip install pycurl --no-binary :all: - $ pip install beanbag jsonschema 'kobo>=0.6.0' lockfile lxml mock nose nose-cov productmd pyopenssl python-multilib requests requests-kerberos setuptools sphinx ordered_set koji PyYAML dogpile.cache parameterized + $ pip install beanbag jsonschema 'kobo>=0.6.0' lockfile lxml mock pytest pytest-cov productmd pyopenssl python-multilib requests requests-kerberos setuptools sphinx ordered_set koji PyYAML dogpile.cache parameterized Now you should be able to run all existing tests. @@ -149,7 +149,7 @@ Testing You must write unit tests for any new code (except for trivial changes). Any code without sufficient test coverage may not be merged. -To run all existing tests, suggested method is to use *nosetests*. With +To run all existing tests, suggested method is to use *pytest*. With additional options, it can generate code coverage. To make sure even tests from executable files are run, don't forget to use the ``--exe`` option. :: diff --git a/pungi.spec b/pungi.spec index 0f58096c..6d8b4b16 100644 --- a/pungi.spec +++ b/pungi.spec @@ -7,7 +7,7 @@ Group: Development/Tools License: GPLv2 URL: https://pagure.io/pungi Source0: https://pagure.io/releases/%{name}/%{name}-%{version}.tar.bz2 -BuildRequires: python-nose, python-mock +BuildRequires: python-pytest, python-mock BuildRequires: python-devel, python-setuptools, python2-productmd BuildRequires: python-lockfile, kobo, kobo-rpmlib, python-kickstart, createrepo_c BuildRequires: python-lxml, libselinux-python, yum-utils, lorax @@ -106,7 +106,7 @@ rm -rf %{buildroot} %{_bindir}/%{name}-wait-for-signed-ostree-handler %check -nosetests --exe +pytest ./tests/data/specs/build.sh cd tests && ./test_compose.sh diff --git a/setup.py b/setup.py index 97c850c0..d678603c 100755 --- a/setup.py +++ b/setup.py @@ -66,5 +66,5 @@ setup( "dogpile.cache", ], extras_require={':python_version=="2.7"': ["enum34", "lockfile"]}, - tests_require=["mock", "nose", "nose-cov"], + tests_require=["mock", "pytest", "pytest-cov"], ) diff --git a/tests/test_checks.py b/tests/test_checks.py index 6dfc3977..788f727a 100644 --- a/tests/test_checks.py +++ b/tests/test_checks.py @@ -96,7 +96,7 @@ class CheckDependenciesTestCase(unittest.TestCase): exists.side_effect = self.dont_find(["/usr/bin/isohybrid"]) result = checks.check(conf) - self.assertRegexpMatches(out.getvalue(), r"^Not checking.*Expect failures.*$") + self.assertRegex(out.getvalue(), r"^Not checking.*Expect failures.*$") self.assertTrue(result) def test_isohybrid_not_needed_in_runroot(self): @@ -215,7 +215,7 @@ class TestSchemaValidator(unittest.TestCase): errors, warnings = checks.validate(config) self.assertEqual(len(errors), 0) self.assertEqual(len(warnings), 1) - self.assertRegexpMatches( + self.assertRegex( warnings[0], r"^WARNING: Config option 'product_name' is deprecated and now an alias to 'release_name'.*", # noqa: E501 ) @@ -268,7 +268,7 @@ class TestSchemaValidator(unittest.TestCase): errors, warnings = checks.validate(config) self.assertEqual(len(errors), 0) self.assertEqual(len(warnings), 1) - self.assertRegexpMatches( + self.assertRegex( warnings[0], r"^WARNING: Config option 'product_name' is deprecated and now an alias to 'release_name'.*", # noqa: E501 ) @@ -295,12 +295,12 @@ class TestSchemaValidator(unittest.TestCase): config = self._load_conf_from_string(string) errors, warnings = checks.validate(config) self.assertEqual(len(errors), 1) - self.assertRegexpMatches( + self.assertRegex( errors[0], r"^ERROR: Config option 'product_name' is an alias of 'release_name', only one can be used.*", # noqa: E501 ) self.assertEqual(len(warnings), 1) - self.assertRegexpMatches( + self.assertRegex( warnings[0], r"^WARNING: Config option 'product_name' is deprecated and now an alias to 'release_name'.*", # noqa: E501 ) @@ -337,11 +337,11 @@ class TestSchemaValidator(unittest.TestCase): errors, warnings = checks.validate(config) self.assertEqual(len(errors), 0) self.assertEqual(len(warnings), 2) - self.assertRegexpMatches( + self.assertRegex( warnings[0], r"^WARNING: Config option '.+' is deprecated and now an alias to '.+'.*", ) - self.assertRegexpMatches( + self.assertRegex( warnings[1], r"^WARNING: Config option '.+' is deprecated and now an alias to '.+'.*", ) @@ -382,11 +382,11 @@ class TestSchemaValidator(unittest.TestCase): errors, warnings = checks.validate(config) self.assertEqual(len(errors), 0) self.assertEqual(len(warnings), 2) - self.assertRegexpMatches( + self.assertRegex( warnings[0], r"^WARNING: Config option 'repo_from' is deprecated, its value will be appended to option 'repo'.*", # noqa: E501 ) - self.assertRegexpMatches( + self.assertRegex( warnings[1], r"^WARNING: Value from config option 'repo_from' is now appended to option 'repo'", # noqa: E501 ) @@ -424,11 +424,11 @@ class TestSchemaValidator(unittest.TestCase): errors, warnings = checks.validate(config) self.assertEqual(len(errors), 0) self.assertEqual(len(warnings), 2) - self.assertRegexpMatches( + self.assertRegex( warnings[0], r"^WARNING: Config option 'repo_from' is deprecated, its value will be appended to option 'repo'.*", # noqa: E501 ) - self.assertRegexpMatches( + self.assertRegex( warnings[1], r"^WARNING: Config option 'repo' is not found, but 'repo_from' is specified,", # noqa: E501 ) @@ -470,19 +470,19 @@ class TestSchemaValidator(unittest.TestCase): errors, warnings = checks.validate(config) self.assertEqual(len(errors), 0) self.assertEqual(len(warnings), 4) - self.assertRegexpMatches( + self.assertRegex( warnings[0], r"^WARNING: Config option 'repo_from' is deprecated, its value will be appended to option 'repo'.*", # noqa: E501 ) - self.assertRegexpMatches( + self.assertRegex( warnings[1], r"^WARNING: Config option 'repo' is not found, but 'repo_from' is specified,", # noqa: E501 ) - self.assertRegexpMatches( + self.assertRegex( warnings[2], r"^WARNING: Config option 'source_repo_from' is deprecated, its value will be appended to option 'repo'", # noqa: E501 ) - self.assertRegexpMatches( + self.assertRegex( warnings[3], r"^WARNING: Value from config option 'source_repo_from' is now appended to option 'repo'.", # noqa: E501 ) @@ -532,11 +532,11 @@ class TestSchemaValidator(unittest.TestCase): errors, warnings = checks.validate(config) self.assertEqual(len(errors), 0) self.assertEqual(len(warnings), 2) - self.assertRegexpMatches( + self.assertRegex( warnings[0], r"^WARNING: Config option 'repo_from' is deprecated, its value will be appended to option 'repo'.*", # noqa: E501 ) - self.assertRegexpMatches( + self.assertRegex( warnings[1], r"^WARNING: Config option 'repo' is not found, but 'repo_from' is specified, value from 'repo_from' is now added as 'repo'.*", # noqa: E501 ) diff --git a/tests/test_compose.py b/tests/test_compose.py index 52d9f922..db8fab6f 100644 --- a/tests/test_compose.py +++ b/tests/test_compose.py @@ -56,6 +56,7 @@ class ComposeTestCase(unittest.TestCase): def test_setup_logger(self, ci): conf = {} logger = logging.getLogger("test_setup_logger") + logger.setLevel(logging.DEBUG) compose = Compose(conf, self.tmp_dir, logger=logger) self.assertEqual(len(logger.handlers), 2) diff --git a/tests/test_createrepophase.py b/tests/test_createrepophase.py index 9f07f48f..c0617e7f 100644 --- a/tests/test_createrepophase.py +++ b/tests/test_createrepophase.py @@ -1341,7 +1341,7 @@ class TestGetProductIds(PungiTestCase): get_productids_from_scm(self.compose) self.assertEqual(get_dir_from_scm.call_args_list, [mock.call(cfg, mock.ANY)]) - self.assertRegexpMatches( + self.assertRegex( str(ctx.exception), r"No product certificate found \(arch: amd64, variant: (Everything|Client)\)", # noqa: E501 ) @@ -1365,6 +1365,4 @@ class TestGetProductIds(PungiTestCase): get_productids_from_scm(self.compose) self.assertEqual(get_dir_from_scm.call_args_list, [mock.call(cfg, mock.ANY)]) - self.assertRegexpMatches( - str(ctx.exception), "Multiple product certificates found.+" - ) + self.assertRegex(str(ctx.exception), "Multiple product certificates found.+") diff --git a/tests/test_extra_files_phase.py b/tests/test_extra_files_phase.py index a05dcc44..21dc3feb 100644 --- a/tests/test_extra_files_phase.py +++ b/tests/test_extra_files_phase.py @@ -244,9 +244,7 @@ class TestCopyFiles(helpers.PungiTestCase): self.compose, [cfg], "x86_64", self.variant, package_sets, self.metadata ) - self.assertRegexpMatches( - str(ctx.exception), r"No.*package.*matching bad-server\*.*" - ) + self.assertRegex(str(ctx.exception), r"No.*package.*matching bad-server\*.*") self.assertEqual(len(get_file_from_scm.call_args_list), 0) self.assertEqual(get_dir_from_scm.call_args_list, []) diff --git a/tests/test_livemediaphase.py b/tests/test_livemediaphase.py index d5e54a49..7a2b878f 100644 --- a/tests/test_livemediaphase.py +++ b/tests/test_livemediaphase.py @@ -363,7 +363,7 @@ class TestLiveMediaPhase(PungiTestCase): phase = LiveMediaPhase(compose) - with self.assertRaisesRegexp( + with self.assertRaisesRegex( RuntimeError, r"no.+Missing.+when building.+Server" ): phase.run() @@ -393,7 +393,7 @@ class TestLiveMediaPhase(PungiTestCase): phase = LiveMediaPhase(compose) - with self.assertRaisesRegexp( + with self.assertRaisesRegex( RuntimeError, r"There is no variant Missing to get repo from." ): phase.run() diff --git a/tests/test_osbs_phase.py b/tests/test_osbs_phase.py index ec17a1ce..059ce828 100644 --- a/tests/test_osbs_phase.py +++ b/tests/test_osbs_phase.py @@ -550,9 +550,7 @@ class OSBSThreadTest(helpers.PungiTestCase): with self.assertRaises(RuntimeError) as ctx: self.t.process((self.compose, self.compose.variants["Server"], cfg), 1) - self.assertRegexpMatches( - str(ctx.exception), r"task 12345 failed: see .+ for details" - ) + self.assertRegex(str(ctx.exception), r"task 12345 failed: see .+ for details") @mock.patch("pungi.phases.osbs.kojiwrapper.KojiWrapper") def test_failing_task_with_failable(self, KojiWrapper): diff --git a/tests/test_pkgset_pkgsets.py b/tests/test_pkgset_pkgsets.py index caf21f62..94fae923 100644 --- a/tests/test_pkgset_pkgsets.py +++ b/tests/test_pkgset_pkgsets.py @@ -301,7 +301,7 @@ class TestKojiPkgset(PkgsetCompareMixin, helpers.PungiTestCase): r"^RPM\(s\) not found for sigs: .+Check log for details.+bash-4\.3\.42-4\.fc24.+bash-debuginfo-4\.3\.42-4\.fc24$", # noqa: E501 re.DOTALL, ) - self.assertRegexpMatches(str(ctx.exception), figure) + self.assertRegex(str(ctx.exception), figure) def test_can_not_find_signed_package_allow_invalid_sigkeys(self): pkgset = pkgsets.KojiPackageSet( @@ -326,7 +326,7 @@ class TestKojiPkgset(PkgsetCompareMixin, helpers.PungiTestCase): r"^RPM\(s\) not found for sigs: .+Check log for details.+bash-4\.3\.42-4\.fc24.+bash-debuginfo-4\.3\.42-4\.fc24$", # noqa: E501 re.DOTALL, ) - self.assertRegexpMatches(str(ctx.exception), figure) + self.assertRegex(str(ctx.exception), figure) def test_can_not_find_any_package(self): pkgset = pkgsets.KojiPackageSet( @@ -341,7 +341,7 @@ class TestKojiPkgset(PkgsetCompareMixin, helpers.PungiTestCase): [mock.call.listTaggedRPMS("f25", event=None, inherit=True, latest=True)], ) - self.assertRegexpMatches( + self.assertRegex( str(ctx.exception), r"^RPM\(s\) not found for sigs: .+Check log for details.+", ) diff --git a/tests/test_unified_isos.py b/tests/test_unified_isos.py index 4952539b..4047e5d5 100755 --- a/tests/test_unified_isos.py +++ b/tests/test_unified_isos.py @@ -4,7 +4,7 @@ import mock import os import shutil import six -from six.moves.configparser import SafeConfigParser +from six.moves.configparser import ConfigParser from tests.helpers import PungiTestCase, FIXTURE_DIR, touch, mk_boom from pungi_utils import unified_isos @@ -24,7 +24,7 @@ class TestUnifiedIsos(PungiTestCase): compose_path = os.path.join(self.topdir, COMPOSE_ID, "compose") isos = unified_isos.UnifiedISO(compose_path) self.assertEqual(isos.compose_path, compose_path) - self.assertRegexpMatches( + self.assertRegex( isos.temp_dir, "^%s/" % os.path.join(self.topdir, COMPOSE_ID, "work") ) @@ -33,7 +33,7 @@ class TestUnifiedIsos(PungiTestCase): self.assertEqual( isos.compose_path, os.path.join(self.topdir, COMPOSE_ID, "compose") ) - self.assertRegexpMatches( + self.assertRegex( isos.temp_dir, "^%s/" % os.path.join(self.topdir, COMPOSE_ID, "work") ) @@ -399,7 +399,7 @@ class TestCreaterepo(PungiTestCase): # treeinfo checksums for arch in self.isos.treeinfo.keys(): - parser = SafeConfigParser() + parser = ConfigParser() parser.optionxform = str parser.read(os.path.join(self.isos.temp_dir, "trees", arch, ".treeinfo")) checksums[arch] = [k for k, v in parser.items("checksums")] @@ -489,7 +489,7 @@ class TestCreaterepo(PungiTestCase): # treeinfo checksums for arch in self.isos.treeinfo.keys(): - parser = SafeConfigParser() + parser = ConfigParser() parser.optionxform = str parser.read(os.path.join(self.isos.temp_dir, "trees", arch, ".treeinfo")) checksums[arch] = [k for k, v in parser.items("checksums")] diff --git a/tox.ini b/tox.ini index 9b007aeb..62e3d148 100644 --- a/tox.ini +++ b/tox.ini @@ -36,15 +36,18 @@ deps = mmdzanata parameterized dict.sorted + urlgrabber mock - nose - nose-cov + unittest2 + pytest + pytest-cov whitelist_externals = sh make coverage commands = sh -c 'find . -name "*.pyc" -exec rm -f \{\} +' + pip install --force-reinstall pytest mock make test-coverage coverage xml @@ -68,12 +71,13 @@ deps = parameterized dict.sorted mock - nose + pytest whitelist_externals = sh make commands = sh -c 'find . -name "__pycache__" -exec rm -rf \{\} +' + pip install --force-reinstall pytest mock make test [flake8] @@ -89,7 +93,5 @@ max-line-length = 88 # E203: whitespace before ':' ignore = E402,H301,H306,E226,W503,E203 -[run] -omit = - tests/* - .tox/* +[pytest] +addopts = --ignore=tests/_composes