Use pytest instead of nosetests

Nose has been in maintenance mode for the past several years
and pytest is a good replacement.

Other changes:
- Replace deprecated assertRegexpMatches with assertRegex
- Replace deprecated assertRaisesRegexp with assertRaisesRegex
- Replace deprecated SafeConfigParser with ConfigParser
- Force reinstall pytest and mock in tox virtualenv. This is because
  the globally installed packages may not work as expected(occured in
  jenkins job).

JIRA: RHELCMP-1619
Signed-off-by: Haibo Lin <hlin@redhat.com>
This commit is contained in:
Haibo Lin 2020-07-28 09:23:53 +08:00
parent 495a4c48b2
commit 3c72755814
13 changed files with 51 additions and 54 deletions

View File

@ -9,7 +9,7 @@ PKGRPMFLAGS=--define "_topdir ${PWD}" --define "_specdir ${PWD}" --define "_sour
RPM="noarch/${PKGNAME}-$(VERSION)-$(RELEASE).noarch.rpm" RPM="noarch/${PKGNAME}-$(VERSION)-$(RELEASE).noarch.rpm"
SRPM="${PKGNAME}-$(VERSION)-$(RELEASE).src.rpm" SRPM="${PKGNAME}-$(VERSION)-$(RELEASE).src.rpm"
NOSE=nosetests PYTEST=pytest
all: help all: help
@ -95,10 +95,10 @@ clean:
test: test:
$(NOSE) --exe $(NOSE_OPTS) $(PYTEST) $(PYTEST_OPTS)
test-coverage: 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: test-data:
./tests/data/specs/build.sh ./tests/data/specs/build.sh

View File

@ -42,8 +42,8 @@ These packages will have to installed:
For running unit tests, these packages are recommended as well: For running unit tests, these packages are recommended as well:
* python-mock * python-mock
* python-nose * python-pytest
* python-nose-cov * python-pytest-cov
* python-unittest2 * python-unittest2
* rpmdevtools * rpmdevtools
* python-parameterized * 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 $ 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 $ pip install -U pip
$ PYCURL_SSL_LIBRARY=nss pip install pycurl --no-binary :all: $ 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. 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 You must write unit tests for any new code (except for trivial changes). Any
code without sufficient test coverage may not be merged. 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 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. :: executable files are run, don't forget to use the ``--exe`` option. ::

View File

@ -7,7 +7,7 @@ Group: Development/Tools
License: GPLv2 License: GPLv2
URL: https://pagure.io/pungi URL: https://pagure.io/pungi
Source0: https://pagure.io/releases/%{name}/%{name}-%{version}.tar.bz2 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-devel, python-setuptools, python2-productmd
BuildRequires: python-lockfile, kobo, kobo-rpmlib, python-kickstart, createrepo_c BuildRequires: python-lockfile, kobo, kobo-rpmlib, python-kickstart, createrepo_c
BuildRequires: python-lxml, libselinux-python, yum-utils, lorax BuildRequires: python-lxml, libselinux-python, yum-utils, lorax
@ -106,7 +106,7 @@ rm -rf %{buildroot}
%{_bindir}/%{name}-wait-for-signed-ostree-handler %{_bindir}/%{name}-wait-for-signed-ostree-handler
%check %check
nosetests --exe pytest
./tests/data/specs/build.sh ./tests/data/specs/build.sh
cd tests && ./test_compose.sh cd tests && ./test_compose.sh

View File

@ -66,5 +66,5 @@ setup(
"dogpile.cache", "dogpile.cache",
], ],
extras_require={':python_version=="2.7"': ["enum34", "lockfile"]}, extras_require={':python_version=="2.7"': ["enum34", "lockfile"]},
tests_require=["mock", "nose", "nose-cov"], tests_require=["mock", "pytest", "pytest-cov"],
) )

View File

@ -96,7 +96,7 @@ class CheckDependenciesTestCase(unittest.TestCase):
exists.side_effect = self.dont_find(["/usr/bin/isohybrid"]) exists.side_effect = self.dont_find(["/usr/bin/isohybrid"])
result = checks.check(conf) 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) self.assertTrue(result)
def test_isohybrid_not_needed_in_runroot(self): def test_isohybrid_not_needed_in_runroot(self):
@ -215,7 +215,7 @@ class TestSchemaValidator(unittest.TestCase):
errors, warnings = checks.validate(config) errors, warnings = checks.validate(config)
self.assertEqual(len(errors), 0) self.assertEqual(len(errors), 0)
self.assertEqual(len(warnings), 1) self.assertEqual(len(warnings), 1)
self.assertRegexpMatches( self.assertRegex(
warnings[0], warnings[0],
r"^WARNING: Config option 'product_name' is deprecated and now an alias to 'release_name'.*", # noqa: E501 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) errors, warnings = checks.validate(config)
self.assertEqual(len(errors), 0) self.assertEqual(len(errors), 0)
self.assertEqual(len(warnings), 1) self.assertEqual(len(warnings), 1)
self.assertRegexpMatches( self.assertRegex(
warnings[0], warnings[0],
r"^WARNING: Config option 'product_name' is deprecated and now an alias to 'release_name'.*", # noqa: E501 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) config = self._load_conf_from_string(string)
errors, warnings = checks.validate(config) errors, warnings = checks.validate(config)
self.assertEqual(len(errors), 1) self.assertEqual(len(errors), 1)
self.assertRegexpMatches( self.assertRegex(
errors[0], errors[0],
r"^ERROR: Config option 'product_name' is an alias of 'release_name', only one can be used.*", # noqa: E501 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.assertEqual(len(warnings), 1)
self.assertRegexpMatches( self.assertRegex(
warnings[0], warnings[0],
r"^WARNING: Config option 'product_name' is deprecated and now an alias to 'release_name'.*", # noqa: E501 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) errors, warnings = checks.validate(config)
self.assertEqual(len(errors), 0) self.assertEqual(len(errors), 0)
self.assertEqual(len(warnings), 2) self.assertEqual(len(warnings), 2)
self.assertRegexpMatches( self.assertRegex(
warnings[0], warnings[0],
r"^WARNING: Config option '.+' is deprecated and now an alias to '.+'.*", r"^WARNING: Config option '.+' is deprecated and now an alias to '.+'.*",
) )
self.assertRegexpMatches( self.assertRegex(
warnings[1], warnings[1],
r"^WARNING: Config option '.+' is deprecated and now an alias to '.+'.*", r"^WARNING: Config option '.+' is deprecated and now an alias to '.+'.*",
) )
@ -382,11 +382,11 @@ class TestSchemaValidator(unittest.TestCase):
errors, warnings = checks.validate(config) errors, warnings = checks.validate(config)
self.assertEqual(len(errors), 0) self.assertEqual(len(errors), 0)
self.assertEqual(len(warnings), 2) self.assertEqual(len(warnings), 2)
self.assertRegexpMatches( self.assertRegex(
warnings[0], warnings[0],
r"^WARNING: Config option 'repo_from' is deprecated, its value will be appended to option 'repo'.*", # noqa: E501 r"^WARNING: Config option 'repo_from' is deprecated, its value will be appended to option 'repo'.*", # noqa: E501
) )
self.assertRegexpMatches( self.assertRegex(
warnings[1], warnings[1],
r"^WARNING: Value from config option 'repo_from' is now appended to option 'repo'", # noqa: E501 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) errors, warnings = checks.validate(config)
self.assertEqual(len(errors), 0) self.assertEqual(len(errors), 0)
self.assertEqual(len(warnings), 2) self.assertEqual(len(warnings), 2)
self.assertRegexpMatches( self.assertRegex(
warnings[0], warnings[0],
r"^WARNING: Config option 'repo_from' is deprecated, its value will be appended to option 'repo'.*", # noqa: E501 r"^WARNING: Config option 'repo_from' is deprecated, its value will be appended to option 'repo'.*", # noqa: E501
) )
self.assertRegexpMatches( self.assertRegex(
warnings[1], warnings[1],
r"^WARNING: Config option 'repo' is not found, but 'repo_from' is specified,", # noqa: E501 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) errors, warnings = checks.validate(config)
self.assertEqual(len(errors), 0) self.assertEqual(len(errors), 0)
self.assertEqual(len(warnings), 4) self.assertEqual(len(warnings), 4)
self.assertRegexpMatches( self.assertRegex(
warnings[0], warnings[0],
r"^WARNING: Config option 'repo_from' is deprecated, its value will be appended to option 'repo'.*", # noqa: E501 r"^WARNING: Config option 'repo_from' is deprecated, its value will be appended to option 'repo'.*", # noqa: E501
) )
self.assertRegexpMatches( self.assertRegex(
warnings[1], warnings[1],
r"^WARNING: Config option 'repo' is not found, but 'repo_from' is specified,", # noqa: E501 r"^WARNING: Config option 'repo' is not found, but 'repo_from' is specified,", # noqa: E501
) )
self.assertRegexpMatches( self.assertRegex(
warnings[2], warnings[2],
r"^WARNING: Config option 'source_repo_from' is deprecated, its value will be appended to option 'repo'", # noqa: E501 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], warnings[3],
r"^WARNING: Value from config option 'source_repo_from' is now appended to option 'repo'.", # noqa: E501 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) errors, warnings = checks.validate(config)
self.assertEqual(len(errors), 0) self.assertEqual(len(errors), 0)
self.assertEqual(len(warnings), 2) self.assertEqual(len(warnings), 2)
self.assertRegexpMatches( self.assertRegex(
warnings[0], warnings[0],
r"^WARNING: Config option 'repo_from' is deprecated, its value will be appended to option 'repo'.*", # noqa: E501 r"^WARNING: Config option 'repo_from' is deprecated, its value will be appended to option 'repo'.*", # noqa: E501
) )
self.assertRegexpMatches( self.assertRegex(
warnings[1], 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 r"^WARNING: Config option 'repo' is not found, but 'repo_from' is specified, value from 'repo_from' is now added as 'repo'.*", # noqa: E501
) )

View File

@ -56,6 +56,7 @@ class ComposeTestCase(unittest.TestCase):
def test_setup_logger(self, ci): def test_setup_logger(self, ci):
conf = {} conf = {}
logger = logging.getLogger("test_setup_logger") logger = logging.getLogger("test_setup_logger")
logger.setLevel(logging.DEBUG)
compose = Compose(conf, self.tmp_dir, logger=logger) compose = Compose(conf, self.tmp_dir, logger=logger)
self.assertEqual(len(logger.handlers), 2) self.assertEqual(len(logger.handlers), 2)

View File

@ -1341,7 +1341,7 @@ class TestGetProductIds(PungiTestCase):
get_productids_from_scm(self.compose) get_productids_from_scm(self.compose)
self.assertEqual(get_dir_from_scm.call_args_list, [mock.call(cfg, mock.ANY)]) self.assertEqual(get_dir_from_scm.call_args_list, [mock.call(cfg, mock.ANY)])
self.assertRegexpMatches( self.assertRegex(
str(ctx.exception), str(ctx.exception),
r"No product certificate found \(arch: amd64, variant: (Everything|Client)\)", # noqa: E501 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) get_productids_from_scm(self.compose)
self.assertEqual(get_dir_from_scm.call_args_list, [mock.call(cfg, mock.ANY)]) self.assertEqual(get_dir_from_scm.call_args_list, [mock.call(cfg, mock.ANY)])
self.assertRegexpMatches( self.assertRegex(str(ctx.exception), "Multiple product certificates found.+")
str(ctx.exception), "Multiple product certificates found.+"
)

View File

@ -244,9 +244,7 @@ class TestCopyFiles(helpers.PungiTestCase):
self.compose, [cfg], "x86_64", self.variant, package_sets, self.metadata self.compose, [cfg], "x86_64", self.variant, package_sets, self.metadata
) )
self.assertRegexpMatches( self.assertRegex(str(ctx.exception), r"No.*package.*matching bad-server\*.*")
str(ctx.exception), r"No.*package.*matching bad-server\*.*"
)
self.assertEqual(len(get_file_from_scm.call_args_list), 0) self.assertEqual(len(get_file_from_scm.call_args_list), 0)
self.assertEqual(get_dir_from_scm.call_args_list, []) self.assertEqual(get_dir_from_scm.call_args_list, [])

View File

@ -363,7 +363,7 @@ class TestLiveMediaPhase(PungiTestCase):
phase = LiveMediaPhase(compose) phase = LiveMediaPhase(compose)
with self.assertRaisesRegexp( with self.assertRaisesRegex(
RuntimeError, r"no.+Missing.+when building.+Server" RuntimeError, r"no.+Missing.+when building.+Server"
): ):
phase.run() phase.run()
@ -393,7 +393,7 @@ class TestLiveMediaPhase(PungiTestCase):
phase = LiveMediaPhase(compose) phase = LiveMediaPhase(compose)
with self.assertRaisesRegexp( with self.assertRaisesRegex(
RuntimeError, r"There is no variant Missing to get repo from." RuntimeError, r"There is no variant Missing to get repo from."
): ):
phase.run() phase.run()

View File

@ -550,9 +550,7 @@ class OSBSThreadTest(helpers.PungiTestCase):
with self.assertRaises(RuntimeError) as ctx: with self.assertRaises(RuntimeError) as ctx:
self.t.process((self.compose, self.compose.variants["Server"], cfg), 1) self.t.process((self.compose, self.compose.variants["Server"], cfg), 1)
self.assertRegexpMatches( self.assertRegex(str(ctx.exception), r"task 12345 failed: see .+ for details")
str(ctx.exception), r"task 12345 failed: see .+ for details"
)
@mock.patch("pungi.phases.osbs.kojiwrapper.KojiWrapper") @mock.patch("pungi.phases.osbs.kojiwrapper.KojiWrapper")
def test_failing_task_with_failable(self, KojiWrapper): def test_failing_task_with_failable(self, KojiWrapper):

View File

@ -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 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, 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): def test_can_not_find_signed_package_allow_invalid_sigkeys(self):
pkgset = pkgsets.KojiPackageSet( 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 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, re.DOTALL,
) )
self.assertRegexpMatches(str(ctx.exception), figure) self.assertRegex(str(ctx.exception), figure)
def test_can_not_find_any_package(self): def test_can_not_find_any_package(self):
pkgset = pkgsets.KojiPackageSet( pkgset = pkgsets.KojiPackageSet(
@ -341,7 +341,7 @@ class TestKojiPkgset(PkgsetCompareMixin, helpers.PungiTestCase):
[mock.call.listTaggedRPMS("f25", event=None, inherit=True, latest=True)], [mock.call.listTaggedRPMS("f25", event=None, inherit=True, latest=True)],
) )
self.assertRegexpMatches( self.assertRegex(
str(ctx.exception), str(ctx.exception),
r"^RPM\(s\) not found for sigs: .+Check log for details.+", r"^RPM\(s\) not found for sigs: .+Check log for details.+",
) )

View File

@ -4,7 +4,7 @@ import mock
import os import os
import shutil import shutil
import six 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 tests.helpers import PungiTestCase, FIXTURE_DIR, touch, mk_boom
from pungi_utils import unified_isos from pungi_utils import unified_isos
@ -24,7 +24,7 @@ class TestUnifiedIsos(PungiTestCase):
compose_path = os.path.join(self.topdir, COMPOSE_ID, "compose") compose_path = os.path.join(self.topdir, COMPOSE_ID, "compose")
isos = unified_isos.UnifiedISO(compose_path) isos = unified_isos.UnifiedISO(compose_path)
self.assertEqual(isos.compose_path, 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") isos.temp_dir, "^%s/" % os.path.join(self.topdir, COMPOSE_ID, "work")
) )
@ -33,7 +33,7 @@ class TestUnifiedIsos(PungiTestCase):
self.assertEqual( self.assertEqual(
isos.compose_path, os.path.join(self.topdir, COMPOSE_ID, "compose") 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") isos.temp_dir, "^%s/" % os.path.join(self.topdir, COMPOSE_ID, "work")
) )
@ -399,7 +399,7 @@ class TestCreaterepo(PungiTestCase):
# treeinfo checksums # treeinfo checksums
for arch in self.isos.treeinfo.keys(): for arch in self.isos.treeinfo.keys():
parser = SafeConfigParser() parser = ConfigParser()
parser.optionxform = str parser.optionxform = str
parser.read(os.path.join(self.isos.temp_dir, "trees", arch, ".treeinfo")) parser.read(os.path.join(self.isos.temp_dir, "trees", arch, ".treeinfo"))
checksums[arch] = [k for k, v in parser.items("checksums")] checksums[arch] = [k for k, v in parser.items("checksums")]
@ -489,7 +489,7 @@ class TestCreaterepo(PungiTestCase):
# treeinfo checksums # treeinfo checksums
for arch in self.isos.treeinfo.keys(): for arch in self.isos.treeinfo.keys():
parser = SafeConfigParser() parser = ConfigParser()
parser.optionxform = str parser.optionxform = str
parser.read(os.path.join(self.isos.temp_dir, "trees", arch, ".treeinfo")) parser.read(os.path.join(self.isos.temp_dir, "trees", arch, ".treeinfo"))
checksums[arch] = [k for k, v in parser.items("checksums")] checksums[arch] = [k for k, v in parser.items("checksums")]

16
tox.ini
View File

@ -36,15 +36,18 @@ deps =
mmdzanata mmdzanata
parameterized parameterized
dict.sorted dict.sorted
urlgrabber
mock mock
nose unittest2
nose-cov pytest
pytest-cov
whitelist_externals = whitelist_externals =
sh sh
make make
coverage coverage
commands = commands =
sh -c 'find . -name "*.pyc" -exec rm -f \{\} +' sh -c 'find . -name "*.pyc" -exec rm -f \{\} +'
pip install --force-reinstall pytest mock
make test-coverage make test-coverage
coverage xml coverage xml
@ -68,12 +71,13 @@ deps =
parameterized parameterized
dict.sorted dict.sorted
mock mock
nose pytest
whitelist_externals = whitelist_externals =
sh sh
make make
commands = commands =
sh -c 'find . -name "__pycache__" -exec rm -rf \{\} +' sh -c 'find . -name "__pycache__" -exec rm -rf \{\} +'
pip install --force-reinstall pytest mock
make test make test
[flake8] [flake8]
@ -89,7 +93,5 @@ max-line-length = 88
# E203: whitespace before ':' # E203: whitespace before ':'
ignore = E402,H301,H306,E226,W503,E203 ignore = E402,H301,H306,E226,W503,E203
[run] [pytest]
omit = addopts = --ignore=tests/_composes
tests/*
.tox/*