diff options
author | James Le Cuirot <chewi@gentoo.org> | 2023-07-21 21:36:31 +0100 |
---|---|---|
committer | Sam James <sam@gentoo.org> | 2023-08-02 07:31:20 +0100 |
commit | f3b90592994c418286b10d883b4aee9a104f5e75 (patch) | |
tree | 773d70d2932a1db333e8dbc32b592deca23c1dc0 | |
parent | Patch Meson in GitHub CI to fix pypy-3.9 detection (diff) | |
download | portage-f3b90592.tar.gz portage-f3b90592.tar.bz2 portage-f3b90592.zip |
Drop custom test runner bits in favour of pytest
Signed-off-by: James Le Cuirot <chewi@gentoo.org>
Signed-off-by: Sam James <sam@gentoo.org>
34 files changed, 49 insertions, 617 deletions
diff --git a/.builds/lint.yml b/.builds/lint.yml index 847552aac..e7aad2114 100644 --- a/.builds/lint.yml +++ b/.builds/lint.yml @@ -25,7 +25,7 @@ tasks: - black: | source .venv/bin/activate cd portage - STRAGGLERS="$(find bin runtests -type f -not -name '*.py' -not -name '*.sh' | \ + STRAGGLERS="$(find bin -type f -not -name '*.py' -not -name '*.sh' | \ xargs grep -l '#!/usr/bin/env python' | \ tr '\n' ' ')" time black --check --diff --color . $STRAGGLERS diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index f2af40957..69b9578d4 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -11,7 +11,7 @@ jobs: id: stragglers run: | echo "::set-output name=missed::$( - find bin runtests -type f -not -name '*.py' -not -name '*.sh' | \ + find bin -type f -not -name '*.py' -not -name '*.sh' | \ xargs grep -l '#!/usr/bin/env python' | tr $'\n' ' ')" - uses: psf/black@stable with: diff --git a/DEVELOPING b/DEVELOPING index a49afff83..8302f9aa1 100644 --- a/DEVELOPING +++ b/DEVELOPING @@ -223,7 +223,7 @@ and commit. - meson setup -Dmodules-only=true build - meson test -C build --verbose Use meson setup's --native-file to override the Python version. See - PYTHON_SUPPORTED_VERSIONS in runtests. + Python versions listed in tox.ini. 4. Version bump the ebuild locally (don't push) and verify it can re-install itself: emerge --oneshot sys-apps/portage diff --git a/TEST-NOTES b/TEST-NOTES index 8be5f9cf3..8a1b981bb 100644 --- a/TEST-NOTES +++ b/TEST-NOTES @@ -42,4 +42,4 @@ functionality. You should raise portage.tests.SkipException in that case. emerge ------ -The emerge namespace currently has 0 tests (and no runner) +The emerge namespace currently has 0 tests diff --git a/lib/portage/tests/__init__.py b/lib/portage/tests/__init__.py index d8e0cc78f..ef5985298 100644 --- a/lib/portage/tests/__init__.py +++ b/lib/portage/tests/__init__.py @@ -1,5 +1,5 @@ # tests/__init__.py -- Portage Unit Test functionality -# Copyright 2006-2021 Gentoo Authors +# Copyright 2006-2023 Gentoo Authors # Distributed under the terms of the GNU General Public License v2 import argparse @@ -64,175 +64,6 @@ def cnf_sbindir(): return os.path.join(portage.const.EPREFIX or "/", "usr", "sbin") -def main(): - suite = unittest.TestSuite() - basedir = Path(__file__).resolve().parent - - argv0 = Path(sys.argv[0]) - - usage = f"usage: {argv0.name} [options] [tests to run]" - parser = argparse.ArgumentParser(usage=usage) - parser.add_argument( - "-l", "--list", help="list all tests", action="store_true", dest="list_tests" - ) - parser.add_argument("tests", nargs="*", type=Path) - options = parser.parse_args(args=sys.argv) - - if ( - no_color(os.environ) - or os.environ.get("TERM") == "dumb" - or not sys.stdout.isatty() - ): - portage.output.nocolor() - - if options.list_tests: - testdir = argv0.parent - for mydir in getTestDirs(basedir): - testsubdir = mydir.name - for name in getTestNames(mydir): - print(f"{testdir}/{testsubdir}/{name}.py") - return os.EX_OK - - if len(options.tests) > 1: - suite.addTests(getTestFromCommandLine(options.tests[1:], basedir)) - else: - for mydir in getTestDirs(basedir): - suite.addTests(getTests(mydir, basedir)) - - result = TextTestRunner(verbosity=2).run(suite) - if not result.wasSuccessful(): - return 1 - return os.EX_OK - - -def my_import(name): - mod = __import__(name) - components = name.split(".") - for comp in components[1:]: - mod = getattr(mod, comp) - return mod - - -def getTestFromCommandLine(args, base_path): - result = [] - for arg in args: - realpath = arg.resolve() - path = realpath.parent - f = realpath.relative_to(path) - - if not f.name.startswith("test") or not f.suffix == ".py": - raise Exception(f"Invalid argument: '{arg}'") - - mymodule = f.stem - result.extend(getTestsFromFiles(path, base_path, [mymodule])) - return result - - -def getTestDirs(base_path): - TEST_FILE = "__test__.py" - testDirs = [] - - # the os.walk help mentions relative paths as being quirky - # I was tired of adding dirs to the list, so now we add __test__.py - # to each dir we want tested. - for testFile in base_path.rglob(TEST_FILE): - testDirs.append(testFile.parent) - - testDirs.sort() - return testDirs - - -def getTestNames(path): - files = path.glob("*") - files = [f.stem for f in files if f.name.startswith("test") and f.suffix == ".py"] - files.sort() - return files - - -def getTestsFromFiles(path, base_path, files): - parent_path = path.relative_to(base_path) - parent_module = ".".join(("portage", "tests") + parent_path.parts) - result = [] - for mymodule in files: - # Make the trailing / a . for module importing - modname = ".".join((parent_module, mymodule)) - mod = my_import(modname) - result.append(unittest.TestLoader().loadTestsFromModule(mod)) - return result - - -def getTests(path, base_path): - """ - - path is the path to a given subdir ( 'portage/' for example) - This does a simple filter on files in that dir to give us modules - to import - - """ - return getTestsFromFiles(path, base_path, getTestNames(path)) - - -class TextTestResult(_TextTestResult): - """ - We need a subclass of unittest.runner.TextTestResult to handle tests with TODO - - This just adds an addTodo method that can be used to add tests - that are marked TODO; these can be displayed later - by the test runner. - """ - - def __init__(self, stream, descriptions, verbosity): - super().__init__(stream, descriptions, verbosity) - self.todoed = [] - self.portage_skipped = [] - - def addSuccess(self, test): - super(_TextTestResult, self).addSuccess(test) - if self.showAll: - self.stream.writeln(colorize("GOOD", "ok")) - elif self.dots: - self.stream.write(colorize("GOOD", ".")) - self.stream.flush() - - def addError(self, test, err): - super(_TextTestResult, self).addError(test, err) - if self.showAll: - self.stream.writeln(colorize("BAD", "ERROR")) - elif self.dots: - self.stream.write(colorize("HILITE", "E")) - self.stream.flush() - - def addFailure(self, test, err): - super(_TextTestResult, self).addFailure(test, err) - if self.showAll: - self.stream.writeln(colorize("BAD", "FAIL")) - elif self.dots: - self.stream.write(colorize("BAD", "F")) - self.stream.flush() - - def addTodo(self, test, info): - self.todoed.append((test, info)) - if self.showAll: - self.stream.writeln(colorize("BRACKET", "TODO")) - elif self.dots: - self.stream.write(colorize("BRACKET", ".")) - - def addPortageSkip(self, test, info): - self.portage_skipped.append((test, info)) - if self.showAll: - self.stream.writeln(colorize("WARN", "SKIP")) - elif self.dots: - self.stream.write(colorize("WARN", ".")) - - def printErrors(self): - if self.dots or self.showAll: - self.stream.writeln() - self.printErrorList("ERROR", self.errors) - self.printErrorList("FAIL", self.failures) - self.printErrorList("TODO", self.todoed) - self.printErrorList("SKIP", self.portage_skipped) - - class TestCase(unittest.TestCase): """ We need a way to mark a unit test as "ok to fail" @@ -243,69 +74,11 @@ class TestCase(unittest.TestCase): def __init__(self, *pargs, **kwargs): unittest.TestCase.__init__(self, *pargs, **kwargs) - self.todo = False - self.portage_skip = None self.cnf_path = cnf_path self.cnf_etc_path = cnf_etc_path self.bindir = cnf_bindir self.sbindir = cnf_sbindir - def defaultTestResult(self): - return TextTestResult() - - def run(self, result=None): - if result is None: - result = self.defaultTestResult() - result.startTest(self) - testMethod = getattr(self, self._testMethodName) - try: - ok = False - try: - try: - self.setUp() - except KeyboardInterrupt: - raise - except unittest.SkipTest: - raise - except Exception: - result.addError(self, sys.exc_info()) - return - - testMethod() - ok = True - except unittest.SkipTest as e: - result.addPortageSkip(self, f"{testMethod}: SKIP: {str(e)}") - except self.failureException: - if self.portage_skip is not None: - if self.portage_skip is True: - result.addPortageSkip(self, f"{testMethod}: SKIP") - else: - result.addPortageSkip( - self, f"{testMethod}: SKIP: {self.portage_skip}" - ) - elif self.todo: - result.addTodo(self, f"{testMethod}: TODO") - else: - result.addFailure(self, sys.exc_info()) - except (KeyboardInterrupt, SystemExit): - raise - except: - result.addError(self, sys.exc_info()) - - try: - self.tearDown() - except SystemExit: - raise - except KeyboardInterrupt: - raise - except: - result.addError(self, sys.exc_info()) - ok = False - if ok: - result.addSuccess(self) - finally: - result.stopTest(self) - def assertRaisesMsg(self, msg, excClass, callableObj, *args, **kwargs): """Fail unless an exception of class excClass is thrown by callableObj when invoked with arguments args and keyword @@ -332,46 +105,6 @@ class TestCase(unittest.TestCase): raise self.failureException(f"path exists when it should not: {path}") -class TextTestRunner(unittest.TextTestRunner): - """ - We subclass unittest.TextTestRunner to output SKIP for tests that fail but are skippable - """ - - def _makeResult(self): - return TextTestResult(self.stream, self.descriptions, self.verbosity) - - def run(self, test): - """ - Run the given test case or test suite. - """ - result = self._makeResult() - startTime = time.time() - test(result) - stopTime = time.time() - timeTaken = stopTime - startTime - result.printErrors() - self.stream.writeln(result.separator2) - run = result.testsRun - self.stream.writeln( - "Ran %d test%s in %.3fs" % (run, run != 1 and "s" or "", timeTaken) - ) - self.stream.writeln() - if not result.wasSuccessful(): - self.stream.write(colorize("BAD", "FAILED") + " (") - failed = len(result.failures) - errored = len(result.errors) - if failed: - self.stream.write("failures=%d" % failed) - if errored: - if failed: - self.stream.write(", ") - self.stream.write("errors=%d" % errored) - self.stream.writeln(")") - else: - self.stream.writeln(colorize("GOOD", "OK")) - return result - - test_cps = ["sys-apps/portage", "virtual/portage"] test_versions = ["1.0", "1.0-r1", "2.3_p4", "1.0_alpha57"] test_slots = [None, "1", "gentoo-sources-2.6.17", "spankywashere"] diff --git a/lib/portage/tests/conftest.py b/lib/portage/tests/conftest.py index 88fc72b15..76bdaa381 100644 --- a/lib/portage/tests/conftest.py +++ b/lib/portage/tests/conftest.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# runTests.py -- Portage Unit Test Functionality # Copyright 2006-2023 Gentoo Authors # Distributed under the terms of the GNU General Public License v2 @@ -64,22 +63,24 @@ def prepare_environment(): path.insert(0, PORTAGE_BIN_PATH) os.environ["PATH"] = ":".join(path) - # Copy GPG test keys to temporary directory - gpg_path = tempfile.mkdtemp(prefix="gpg_") + try: + # Copy GPG test keys to temporary directory + gpg_path = tempfile.mkdtemp(prefix="gpg_") - shutil.copytree( - os.path.join(os.path.dirname(os.path.realpath(__file__)), ".gnupg"), - gpg_path, - dirs_exist_ok=True, - ) + shutil.copytree( + os.path.join(os.path.dirname(os.path.realpath(__file__)), ".gnupg"), + gpg_path, + dirs_exist_ok=True, + ) - os.chmod(gpg_path, 0o700) - os.environ["PORTAGE_GNUPGHOME"] = gpg_path + os.chmod(gpg_path, 0o700) + os.environ["PORTAGE_GNUPGHOME"] = gpg_path - yield + yield - global_event_loop().close() - shutil.rmtree(gpg_path, ignore_errors=True) + finally: + global_event_loop().close() + shutil.rmtree(gpg_path, ignore_errors=True) # if __name__ == "__main__": diff --git a/lib/portage/tests/dep/meson.build b/lib/portage/tests/dep/meson.build index f96018917..848f5aade 100644 --- a/lib/portage/tests/dep/meson.build +++ b/lib/portage/tests/dep/meson.build @@ -1,10 +1,10 @@ py.install_sources( [ - 'testAtom.py', - 'testCheckRequiredUse.py', - 'testExtendedAtomDict.py', - 'testExtractAffectingUSE.py', - 'testStandalone.py', + 'test_atom.py', + 'test_check_required_use.py', + 'test_extended_atom_dict.py', + 'test_extract_affecting_use.py', + 'test_standalone.py', 'test_best_match_to_list.py', 'test_dep_getcpv.py', 'test_dep_getrepo.py', diff --git a/lib/portage/tests/dep/testAtom.py b/lib/portage/tests/dep/test_atom.py index b7d8bee8b..b7d8bee8b 100644 --- a/lib/portage/tests/dep/testAtom.py +++ b/lib/portage/tests/dep/test_atom.py diff --git a/lib/portage/tests/dep/testCheckRequiredUse.py b/lib/portage/tests/dep/test_check_required_use.py index cbb1a608a..cbb1a608a 100644 --- a/lib/portage/tests/dep/testCheckRequiredUse.py +++ b/lib/portage/tests/dep/test_check_required_use.py diff --git a/lib/portage/tests/dep/testExtendedAtomDict.py b/lib/portage/tests/dep/test_extended_atom_dict.py index 7c177b927..7c177b927 100644 --- a/lib/portage/tests/dep/testExtendedAtomDict.py +++ b/lib/portage/tests/dep/test_extended_atom_dict.py diff --git a/lib/portage/tests/dep/testExtractAffectingUSE.py b/lib/portage/tests/dep/test_extract_affecting_use.py index 8c93ad973..8c93ad973 100644 --- a/lib/portage/tests/dep/testExtractAffectingUSE.py +++ b/lib/portage/tests/dep/test_extract_affecting_use.py diff --git a/lib/portage/tests/dep/testStandalone.py b/lib/portage/tests/dep/test_standalone.py index 3b6cb12d7..3b6cb12d7 100644 --- a/lib/portage/tests/dep/testStandalone.py +++ b/lib/portage/tests/dep/test_standalone.py diff --git a/lib/portage/tests/glsa/test_security_set.py b/lib/portage/tests/glsa/test_security_set.py index 867a7cd4f..a0ba1e5b4 100644 --- a/lib/portage/tests/glsa/test_security_set.py +++ b/lib/portage/tests/glsa/test_security_set.py @@ -1,4 +1,4 @@ -# Copyright 2013-2022 Gentoo Authors +# Copyright 2013-2023 Gentoo Authors # Distributed under the terms of the GNU General Public License v2 @@ -64,7 +64,7 @@ class SecuritySetTestCase(TestCase): __import__("xml.etree.ElementTree") __import__("xml.parsers.expat").parsers.expat.ExpatError except (AttributeError, ImportError): - return "python is missing xml support" + self.skipTest("python is missing xml support") def write_glsa_test_case(self, glsa_dir, glsa): with open( @@ -75,11 +75,7 @@ class SecuritySetTestCase(TestCase): f.write(self.glsa_template % glsa) def testSecuritySet(self): - skip_reason = self._must_skip() - if skip_reason: - self.portage_skip = skip_reason - self.assertFalse(True, skip_reason) - return + self._must_skip() ebuilds = { "cat/A-vulnerable-2.2": {"KEYWORDS": "x86"}, @@ -159,11 +155,7 @@ class SecuritySetTestCase(TestCase): # testing the format parsing with a bit more flexibility (no # need to keep inventing packages). - skip_reason = self._must_skip() - if skip_reason: - self.portage_skip = skip_reason - self.assertFalse(True, skip_reason) - return + self._must_skip() ebuilds = { "cat/A-vulnerable-2.2": {"KEYWORDS": "x86"}, diff --git a/lib/portage/tests/meson.build b/lib/portage/tests/meson.build index 86e8e71ce..e8f204b51 100644 --- a/lib/portage/tests/meson.build +++ b/lib/portage/tests/meson.build @@ -1,7 +1,6 @@ py.install_sources( [ 'conftest.py', - 'runTests.py', '__init__.py', ], subdir : 'portage/tests', diff --git a/lib/portage/tests/process/test_poll.py b/lib/portage/tests/process/test_poll.py index 371dd1906..65a9ca1bf 100644 --- a/lib/portage/tests/process/test_poll.py +++ b/lib/portage/tests/process/test_poll.py @@ -121,4 +121,3 @@ class PipeReaderArrayTestCase(PipeReaderTestCase): super().__init__(*args, **kwargs) # https://bugs.python.org/issue5380 # https://bugs.pypy.org/issue956 - self.todo = True diff --git a/lib/portage/tests/process/test_unshare_net.py b/lib/portage/tests/process/test_unshare_net.py index e17357f4d..dabf15585 100644 --- a/lib/portage/tests/process/test_unshare_net.py +++ b/lib/portage/tests/process/test_unshare_net.py @@ -33,19 +33,6 @@ class UnshareNetTestCase(TestCase): ) @pytest.mark.skipif(platform.system() != "Linux", reason="not Linux") def testUnshareNet(self): - AM_I_UNDER_PYTEST = "PYTEST_CURRENT_TEST" in os.environ - if not AM_I_UNDER_PYTEST: - if platform.system() != "Linux": - self.skipTest("not Linux") - if portage.process.find_binary("ping") is None: - self.skipTest("ping not found") - - errno_value = portage.process._unshare_validate(CLONE_NEWNET) - if errno_value != 0: - self.skipTest( - f"Unable to unshare: {errno.errorcode.get(errno_value, '?')}" - ) - env = os.environ.copy() env["IPV6"] = "1" if portage.process._has_ipv6() else "" self.assertEqual( diff --git a/lib/portage/tests/resolver/test_autounmask_multilib_use.py b/lib/portage/tests/resolver/test_autounmask_multilib_use.py index 3abbebbd5..2d3da85c5 100644 --- a/lib/portage/tests/resolver/test_autounmask_multilib_use.py +++ b/lib/portage/tests/resolver/test_autounmask_multilib_use.py @@ -13,8 +13,6 @@ from portage.tests.resolver.ResolverPlayground import ( class AutounmaskMultilibUseTestCase(TestCase): @pytest.mark.xfail() def testAutounmaskMultilibUse(self): - self.todo = True - ebuilds = { "x11-proto/xextproto-7.2.1-r1": { "EAPI": "5", diff --git a/lib/portage/tests/resolver/test_autounmask_use_slot_conflict.py b/lib/portage/tests/resolver/test_autounmask_use_slot_conflict.py index 2db1396bc..a0b8c4ae7 100644 --- a/lib/portage/tests/resolver/test_autounmask_use_slot_conflict.py +++ b/lib/portage/tests/resolver/test_autounmask_use_slot_conflict.py @@ -13,8 +13,6 @@ from portage.tests.resolver.ResolverPlayground import ( class AutounmaskUseSlotConflictTestCase(TestCase): @pytest.mark.xfail() def testAutounmaskUseSlotConflict(self): - self.todo = True - ebuilds = { "sci-libs/K-1": {"IUSE": "+foo", "EAPI": 1}, "sci-libs/L-1": {"DEPEND": "sci-libs/K[-foo]", "EAPI": 2}, diff --git a/lib/portage/tests/resolver/test_or_choices.py b/lib/portage/tests/resolver/test_or_choices.py index 33707c71a..4258a1ab5 100644 --- a/lib/portage/tests/resolver/test_or_choices.py +++ b/lib/portage/tests/resolver/test_or_choices.py @@ -649,8 +649,6 @@ class OrChoicesLibpostprocTestCase(TestCase): # compatible with any available media-video/ffmpeg slot. In order to # solve this test case, some fancy backtracking (like for bug 382421) # will be required. - self.todo = True - ebuilds = { "media-video/ffmpeg-0.10": {"EAPI": "5", "SLOT": "0.10"}, "media-video/ffmpeg-1.2.2": {"EAPI": "5", "SLOT": "0"}, diff --git a/lib/portage/tests/runTests.py b/lib/portage/tests/runTests.py deleted file mode 100644 index 36ea3a791..000000000 --- a/lib/portage/tests/runTests.py +++ /dev/null @@ -1,79 +0,0 @@ -#!/usr/bin/env python -# runTests.py -- Portage Unit Test Functionality -# Copyright 2006-2022 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -import grp -import os -import os.path as osp -import pwd -import signal -import tempfile -import shutil -import sys - - -def debug_signal(signum, frame): - import pdb - - pdb.set_trace() - - -signal.signal(signal.SIGUSR1, debug_signal) - -# Pretend that the current user's uid/gid are the 'portage' uid/gid, -# so things go smoothly regardless of the current user and global -# user/group configuration. -os.environ["PORTAGE_USERNAME"] = pwd.getpwuid(os.getuid()).pw_name -os.environ["PORTAGE_GRPNAME"] = grp.getgrgid(os.getgid()).gr_name - -# Insert our parent dir so we can do shiny import "tests" -# This line courtesy of Marienz and Pkgcore ;) -sys.path.insert(0, osp.dirname(osp.dirname(osp.dirname(osp.realpath(__file__))))) - -import portage - -portage._internal_caller = True - -# Ensure that we don't instantiate portage.settings, so that tests should -# work the same regardless of global configuration file state/existence. -portage._disable_legacy_globals() - -if portage.util.no_color(os.environ): - portage.output.nocolor() - -import portage.tests as tests -from portage.util._eventloop.global_event_loop import global_event_loop -from portage.const import PORTAGE_BIN_PATH - -path = os.environ.get("PATH", "").split(":") -path = [x for x in path if x] - -insert_bin_path = True -try: - insert_bin_path = not path or not os.path.samefile(path[0], PORTAGE_BIN_PATH) -except OSError: - pass - -if insert_bin_path: - path.insert(0, PORTAGE_BIN_PATH) - os.environ["PATH"] = ":".join(path) - -# Copy GPG test keys to temporary directory -gpg_path = tempfile.mkdtemp(prefix="gpg_") - -shutil.copytree( - os.path.join(os.path.dirname(os.path.realpath(__file__)), ".gnupg"), - gpg_path, - dirs_exist_ok=True, -) - -os.chmod(gpg_path, 0o700) -os.environ["PORTAGE_GNUPGHOME"] = gpg_path - -if __name__ == "__main__": - try: - sys.exit(tests.main()) - finally: - global_event_loop().close() - shutil.rmtree(gpg_path, ignore_errors=True) diff --git a/lib/portage/tests/sets/base/meson.build b/lib/portage/tests/sets/base/meson.build index ba15a8213..6c59b11ee 100644 --- a/lib/portage/tests/sets/base/meson.build +++ b/lib/portage/tests/sets/base/meson.build @@ -1,7 +1,7 @@ py.install_sources( [ - 'testInternalPackageSet.py', - 'testVariableSet.py', + 'test_internal_package_set.py', + 'test_variable_set.py', '__init__.py', '__test__.py', ], diff --git a/lib/portage/tests/sets/base/testInternalPackageSet.py b/lib/portage/tests/sets/base/test_internal_package_set.py index 77934cab2..77934cab2 100644 --- a/lib/portage/tests/sets/base/testInternalPackageSet.py +++ b/lib/portage/tests/sets/base/test_internal_package_set.py diff --git a/lib/portage/tests/sets/base/testVariableSet.py b/lib/portage/tests/sets/base/test_variable_set.py index 506104667..506104667 100644 --- a/lib/portage/tests/sets/base/testVariableSet.py +++ b/lib/portage/tests/sets/base/test_variable_set.py diff --git a/lib/portage/tests/sets/files/meson.build b/lib/portage/tests/sets/files/meson.build index 0ac7449db..d4550f4ee 100644 --- a/lib/portage/tests/sets/files/meson.build +++ b/lib/portage/tests/sets/files/meson.build @@ -1,7 +1,7 @@ py.install_sources( [ - 'testConfigFileSet.py', - 'testStaticFileSet.py', + 'test_config_file_set.py', + 'test_static_file_set.py', '__init__.py', '__test__.py', ], diff --git a/lib/portage/tests/sets/files/testConfigFileSet.py b/lib/portage/tests/sets/files/test_config_file_set.py index 81419df4a..81419df4a 100644 --- a/lib/portage/tests/sets/files/testConfigFileSet.py +++ b/lib/portage/tests/sets/files/test_config_file_set.py diff --git a/lib/portage/tests/sets/files/testStaticFileSet.py b/lib/portage/tests/sets/files/test_static_file_set.py index a4e6c29c2..a4e6c29c2 100644 --- a/lib/portage/tests/sets/files/testStaticFileSet.py +++ b/lib/portage/tests/sets/files/test_static_file_set.py diff --git a/lib/portage/tests/sets/shell/meson.build b/lib/portage/tests/sets/shell/meson.build index 6044f3ebe..55a41a6e0 100644 --- a/lib/portage/tests/sets/shell/meson.build +++ b/lib/portage/tests/sets/shell/meson.build @@ -1,6 +1,6 @@ py.install_sources( [ - 'testShell.py', + 'test_shell.py', '__init__.py', '__test__.py', ], diff --git a/lib/portage/tests/sets/shell/testShell.py b/lib/portage/tests/sets/shell/test_shell.py index f30b72a8b..f30b72a8b 100644 --- a/lib/portage/tests/sets/shell/testShell.py +++ b/lib/portage/tests/sets/shell/test_shell.py diff --git a/lib/portage/tests/sync/test_sync_local.py b/lib/portage/tests/sync/test_sync_local.py index c400c9bba..a8a71cd4b 100644 --- a/lib/portage/tests/sync/test_sync_local.py +++ b/lib/portage/tests/sync/test_sync_local.py @@ -1,4 +1,4 @@ -# Copyright 2014-2021 Gentoo Authors +# Copyright 2014-2023 Gentoo Authors # Distributed under the terms of the GNU General Public License v2 import datetime @@ -23,18 +23,13 @@ class SyncLocalTestCase(TestCase): def _must_skip(self): if find_binary("rsync") is None: - return "rsync: command not found" + self.skipTest("rsync: command not found") if find_binary("git") is None: - return "git: command not found" + self.skipTest("git: command not found") def testSyncLocal(self): debug = False - - skip_reason = self._must_skip() - if skip_reason: - self.portage_skip = skip_reason - self.assertFalse(True, skip_reason) - return + self._must_skip() repos_conf = textwrap.dedent( """ diff --git a/lib/portage/tests/util/file_copy/test_copyfile.py b/lib/portage/tests/util/file_copy/test_copyfile.py index 22c3982f0..e91a47bed 100644 --- a/lib/portage/tests/util/file_copy/test_copyfile.py +++ b/lib/portage/tests/util/file_copy/test_copyfile.py @@ -56,15 +56,8 @@ class CopyFileSparseTestCase(TestCase): self.assertEqual(perform_md5(src_path), perform_md5(dest_path)) # This last part of the test is expected to fail when sparse - # copy is not implemented, so set the todo flag in order - # to tolerate failures. Or mark it xfail: - - AM_I_UNDER_PYTEST = "PYTEST_CURRENT_TEST" in os.environ - - if AM_I_UNDER_PYTEST: - pytest.xfail(reason="sparse copy is not implemented") - else: - self.todo = True + # copy is not implemented, so mark it xfail: + pytest.xfail(reason="sparse copy is not implemented") # If sparse blocks were preserved, then both files should # consume the same number of blocks. diff --git a/lib/portage/tests/util/futures/test_iter_completed.py b/lib/portage/tests/util/futures/test_iter_completed.py index 8955546ee..bda900505 100644 --- a/lib/portage/tests/util/futures/test_iter_completed.py +++ b/lib/portage/tests/util/futures/test_iter_completed.py @@ -1,7 +1,10 @@ -# Copyright 2018 Gentoo Foundation +# Copyright 2023 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 import time + +import pytest + from portage.tests import TestCase from portage.util._async.ForkProcess import ForkProcess from portage.util._eventloop.global_event_loop import global_event_loop @@ -28,11 +31,10 @@ class SleepProcess(ForkProcess): class IterCompletedTestCase(TestCase): + # Mark this as todo, since we don't want to fail if heavy system load causes + # the tasks to finish in an unexpected order. + @pytest.mark.xfail(strict=False) def testIterCompleted(self): - # Mark this as todo, since we don't want to fail if heavy system - # load causes the tasks to finish in an unexpected order. - self.todo = True - loop = global_event_loop() tasks = [ SleepProcess(seconds=0.200), diff --git a/meson.build b/meson.build index db812eeaf..3d2a053b5 100644 --- a/meson.build +++ b/meson.build @@ -95,9 +95,9 @@ if get_option('native-extensions') endif test( - 'python', + 'pytest', py, - args : ['-bWd', meson.current_source_dir() / 'lib' / 'portage' / 'tests' / 'runTests.py'], + args : ['-m', 'pytest', '--rootdir', meson.current_source_dir(), meson.current_source_dir()], timeout : 0 ) diff --git a/runtests b/runtests deleted file mode 100755 index 1701190b4..000000000 --- a/runtests +++ /dev/null @@ -1,184 +0,0 @@ -#!/usr/bin/env python -# Copyright 2010-2023 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 -# -# Note: We don't want to import portage modules directly because we do things -# like run the testsuite through multiple versions of python. - -"""Helper script to run portage unittests against different python versions. - -Note: Any additional arguments will be passed down directly to the underlying -unittest runner. This lets you select specific tests to execute. -""" - -import argparse -import os -import shutil -import subprocess -import sys -import tempfile - - -# These are the versions we fully support and require to pass tests. -PYTHON_SUPPORTED_VERSIONS = ["3.9", "3.10", "3.11"] -# The rest are just "nice to have". -PYTHON_NICE_VERSIONS = ["pypy3", "3.12"] - -EPREFIX = os.environ.get("PORTAGE_OVERRIDE_EPREFIX", "/") - - -class Colors: - """Simple object holding color constants.""" - - _COLORS_YES = ("y", "yes", "true") - _COLORS_NO = ("n", "no", "false") - - WARN = GOOD = BAD = NORMAL = "" - - def __init__(self, colorize=None): - if colorize is None: - nocolors = os.environ.get("NOCOLOR", "false") - # Ugh, look away, for here we invert the world! - if nocolors in self._COLORS_YES: - colorize = False - elif nocolors in self._COLORS_NO: - colorize = True - else: - raise ValueError(f"$NOCOLORS is invalid: {nocolors}") - else: - if colorize in self._COLORS_YES: - colorize = True - elif colorize in self._COLORS_NO: - colorize = False - else: - raise ValueError(f"--colors is invalid: {colorize}") - - if colorize: - self.WARN = "\033[1;33m" - self.GOOD = "\033[1;32m" - self.BAD = "\033[1;31m" - self.NORMAL = "\033[0m" - - -def get_python_executable(ver): - """Find the right python executable for |ver|""" - if ver in ("pypy", "pypy3"): - prog = ver - else: - prog = "python" + ver - return os.path.join(EPREFIX, "usr", "bin", prog) - - -def get_parser(): - """Return a argument parser for this module""" - epilog = """Examples: -List all the available unittests. -$ %(prog)s --list - -Run against specific versions of python. -$ %(prog)s --python-versions '2.7 3.3' - -Run just one unittest. -$ %(prog)s lib/portage/tests/xpak/test_decodeint.py -""" - parser = argparse.ArgumentParser( - description=__doc__, - formatter_class=argparse.RawDescriptionHelpFormatter, - epilog=epilog, - ) - parser.add_argument( - "--keep-temp", - default=False, - action="store_true", - help="Do not delete the temporary directory when exiting", - ) - parser.add_argument( - "--color", - type=str, - default=None, - help="Whether to use colorized output (default is auto)", - ) - parser.add_argument( - "--python-versions", - action="append", - help="Versions of python to test (default is test available)", - ) - return parser - - -def main(argv): - parser = get_parser() - opts, args = parser.parse_known_args(argv) - colors = Colors(colorize=opts.color) - - # Figure out all the versions we want to test. - if opts.python_versions is None: - ignore_missing = True - pyversions = PYTHON_SUPPORTED_VERSIONS + PYTHON_NICE_VERSIONS - else: - ignore_missing = False - pyversions = [] - for ver in opts.python_versions: - if ver == "supported": - pyversions.extend(PYTHON_SUPPORTED_VERSIONS) - else: - pyversions.extend(ver.split()) - - tempdir = None - try: - # Set up a single tempdir for all the tests to use. - # This way we know the tests won't leak things on us. - tempdir = tempfile.mkdtemp(prefix="portage.runtests.") - os.environ["TMPDIR"] = tempdir - - # Actually test those versions now. - statuses = [] - for ver in pyversions: - prog = get_python_executable(ver) - cmd = [prog, "-b", "-Wd", "lib/portage/tests/runTests.py"] + args - if os.access(prog, os.X_OK): - print(f"{colors.GOOD}Testing with Python {ver}...{colors.NORMAL}") - statuses.append((ver, subprocess.call(cmd))) - elif not ignore_missing: - print( - f"{colors.BAD}Could not find requested Python {ver}{colors.NORMAL}" - ) - statuses.append((ver, 1)) - else: - print(f"{colors.WARN}Skip Python {ver}...{colors.NORMAL}") - print() - finally: - if tempdir is not None: - if opts.keep_temp: - print(f"Temporary directory left behind:\n{tempdir}") - else: - # Nuke our tempdir and anything that might be under it. - shutil.rmtree(tempdir, True) - - # Then summarize it all. - print("\nSummary:\n") - width = 10 - header = "| %-*s | %s" % (width, "Version", "Status") - print(f"{header}\n|{'-' * (len(header) - 1)}") - exit_status = 0 - for ver, status in statuses: - exit_status += status - if status: - color = colors.BAD - msg = "FAIL" - else: - color = colors.GOOD - msg = "PASS" - print( - "| %s%-*s%s | %s%s%s" - % (color, width, ver, colors.NORMAL, color, msg, colors.NORMAL) - ) - exit(exit_status) - - -if __name__ == "__main__": - try: - main(sys.argv[1:]) - except KeyboardInterrupt: - print("interrupted ...", file=sys.stderr) - exit(1) @@ -28,4 +28,4 @@ allowlist_externals = ./run-pylint commands = pylint: ./run-pylint - test: python -bWd lib/portage/tests/runTests.py + test: pytest |