From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from lists.gentoo.org (pigeon.gentoo.org [208.92.234.80]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by finch.gentoo.org (Postfix) with ESMTPS id 4CBF1158004 for ; Wed, 3 Jan 2024 19:59:58 +0000 (UTC) Received: from pigeon.gentoo.org (localhost [127.0.0.1]) by pigeon.gentoo.org (Postfix) with SMTP id 4A1622BC017; Wed, 3 Jan 2024 19:59:57 +0000 (UTC) Received: from smtp.gentoo.org (woodpecker.gentoo.org [140.211.166.183]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by pigeon.gentoo.org (Postfix) with ESMTPS id 2827D2BC017 for ; Wed, 3 Jan 2024 19:59:57 +0000 (UTC) Received: from oystercatcher.gentoo.org (oystercatcher.gentoo.org [148.251.78.52]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by smtp.gentoo.org (Postfix) with ESMTPS id 3649934069F for ; Wed, 3 Jan 2024 19:59:56 +0000 (UTC) Received: from localhost.localdomain (localhost [IPv6:::1]) by oystercatcher.gentoo.org (Postfix) with ESMTP id C92611339 for ; Wed, 3 Jan 2024 19:59:54 +0000 (UTC) From: "Sam James" To: gentoo-commits@lists.gentoo.org Content-Transfer-Encoding: 8bit Content-type: text/plain; charset=UTF-8 Reply-To: gentoo-dev@lists.gentoo.org, "Sam James" Message-ID: <1704311991.14ec6c259ca5bd7439ede37216bbb0d160e909e9.sam@gentoo> Subject: [gentoo-commits] proj/portage:master commit in: lib/portage/tests/emerge/ X-VCS-Repository: proj/portage X-VCS-Files: lib/portage/tests/emerge/meson.build lib/portage/tests/emerge/test_binpkg_fetch.py X-VCS-Directories: lib/portage/tests/emerge/ X-VCS-Committer: sam X-VCS-Committer-Name: Sam James X-VCS-Revision: 14ec6c259ca5bd7439ede37216bbb0d160e909e9 X-VCS-Branch: master Date: Wed, 3 Jan 2024 19:59:54 +0000 (UTC) Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-Id: Gentoo Linux mail X-BeenThere: gentoo-commits@lists.gentoo.org X-Auto-Response-Suppress: DR, RN, NRN, OOF, AutoReply X-Archives-Salt: 3f1280fd-ff7c-4954-a22c-b7691ef97e15 X-Archives-Hash: 5df313d10d82691a5a715d28aa29ed50 commit: 14ec6c259ca5bd7439ede37216bbb0d160e909e9 Author: Sam James gentoo org> AuthorDate: Wed Jan 3 04:22:24 2024 +0000 Commit: Sam James gentoo org> CommitDate: Wed Jan 3 19:59:51 2024 +0000 URL: https://gitweb.gentoo.org/proj/portage.git/commit/?id=14ec6c25 tests: add getbinpkg file:// sync testcase for BUILD_ID We do a bit of a strange dance here where we: 1) create a binpkg; 2) shift the PKGDIR so that it becomes a "remote" one for use with file:///; 3) try to merge the binpkg but defer checking the exit status; 4) check if the downloaded filename was unnecessarily incremented (-2). if it is, fail. 5) check the deferred exit status from 3) so that we fail if the merge failed for another reason (e.g. failed injection). Bug: https://bugs.gentoo.org/921208 Signed-off-by: Sam James gentoo.org> lib/portage/tests/emerge/meson.build | 1 + lib/portage/tests/emerge/test_binpkg_fetch.py | 226 ++++++++++++++++++++++++++ 2 files changed, 227 insertions(+) diff --git a/lib/portage/tests/emerge/meson.build b/lib/portage/tests/emerge/meson.build index 0d34cbecf7..0e0a419740 100644 --- a/lib/portage/tests/emerge/meson.build +++ b/lib/portage/tests/emerge/meson.build @@ -1,6 +1,7 @@ py.install_sources( [ 'test_actions.py', + 'test_binpkg_fetch.py', 'test_config_protect.py', 'test_emerge_blocker_file_collision.py', 'test_emerge_slot_abi.py', diff --git a/lib/portage/tests/emerge/test_binpkg_fetch.py b/lib/portage/tests/emerge/test_binpkg_fetch.py new file mode 100644 index 0000000000..731711bad8 --- /dev/null +++ b/lib/portage/tests/emerge/test_binpkg_fetch.py @@ -0,0 +1,226 @@ +# Copyright 2024 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +import shutil +import subprocess +import sys +import tempfile + +import portage +from portage import _unicode_decode, os +from portage.const import ( + PORTAGE_PYM_PATH, + USER_CONFIG_PATH, +) +from portage.process import find_binary +from portage.tests import TestCase +from portage.tests.resolver.ResolverPlayground import ResolverPlayground +from portage.util import ensure_dirs + + +class BinpkgFetchtestCase(TestCase): + def testLocalFilePkgSyncUpdate(self): + """ + Check handling of local file:// sync-uri and unnecessary BUILD_ID + increments (bug #921208). + """ + debug = False + + ebuilds = { + "dev-libs/A-1::local": { + "EAPI": "7", + "SLOT": "0", + }, + } + + playground = ResolverPlayground(ebuilds=ebuilds, debug=debug) + settings = playground.settings + eprefix = settings["EPREFIX"] + eroot = settings["EROOT"] + trees = playground.trees + bindb = trees[eroot]["bintree"].dbapi + var_cache_edb = os.path.join(eprefix, "var", "cache", "edb") + user_config_dir = os.path.join(eprefix, USER_CONFIG_PATH) + + portage_python = portage._python_interpreter + emerge_cmd = ( + portage_python, + "-b", + "-Wd", + os.path.join(str(self.bindir), "emerge"), + ) + + tmppkgdir = tempfile.TemporaryDirectory() + tmppkgdir_suffix = os.path.join(tmppkgdir.name, "binpkg") + + test_commands = ( + # Create a trivial binpkg first. + emerge_cmd + + ( + "--oneshot", + "--verbose", + "--buildpkg", + "dev-libs/A", + ), + # Copy to a new PKGDIR which we'll use as PORTAGE_BINHOST then delete the old PKGDIR. + ( + ( + lambda: shutil.copytree(bindb.bintree.pkgdir, tmppkgdir_suffix) + or True, + ) + ), + ( + ( + lambda: os.unlink( + os.path.join( + bindb.bintree.pkgdir, "dev-libs", "A", "A-1-1.gpkg.tar" + ) + ) + or True, + ) + ), + ) + test_commands_nonfatal = ( + # This should succeed if we've correctly saved it as A-1-1.gpkg.tar, not + # A-1-2.gpkg.tar, and then also try to unpack the right filename, but + # we defer checking the exit code to get a better error if the binpkg + # was downloaded with the wrong filename. + emerge_cmd + + ( + "--oneshot", + "--verbose", + "--getbinpkgonly", + "dev-libs/A", + ), + ) + test_commands_final = ( + # Check whether the downloaded binpkg in PKGDIR has the correct + # filename (-1) or an unnecessarily-incremented one (-2). + ( + lambda: os.path.exists( + os.path.join( + bindb.bintree.pkgdir, "dev-libs", "A", "A-1-1.gpkg.tar" + ) + ), + ), + ) + + fake_bin = os.path.join(eprefix, "bin") + portage_tmpdir = os.path.join(eprefix, "var", "tmp", "portage") + + path = settings.get("PATH") + if path is not None and not path.strip(): + path = None + if path is None: + path = "" + else: + path = ":" + path + path = fake_bin + path + + pythonpath = os.environ.get("PYTHONPATH") + if pythonpath is not None and not pythonpath.strip(): + pythonpath = None + if pythonpath is not None and pythonpath.split(":")[0] == PORTAGE_PYM_PATH: + pass + else: + if pythonpath is None: + pythonpath = "" + else: + pythonpath = ":" + pythonpath + pythonpath = PORTAGE_PYM_PATH + pythonpath + + env = { + "PORTAGE_OVERRIDE_EPREFIX": eprefix, + "PATH": path, + "PORTAGE_PYTHON": portage_python, + "PORTAGE_REPOSITORIES": settings.repositories.config_string(), + "PYTHONDONTWRITEBYTECODE": os.environ.get("PYTHONDONTWRITEBYTECODE", ""), + "PYTHONPATH": pythonpath, + "PORTAGE_INST_GID": str(os.getgid()), + "PORTAGE_INST_UID": str(os.getuid()), + "FEATURES": "-pkgdir-index-trusted", + } + + dirs = [ + playground.distdir, + fake_bin, + portage_tmpdir, + user_config_dir, + var_cache_edb, + ] + + true_symlinks = ["chown", "chgrp"] + + needed_binaries = { + "true": (find_binary("true"), True), + } + + def run_commands(test_commands, require_success=True): + all_successful = True + + for i, args in enumerate(test_commands): + if hasattr(args[0], "__call__"): + if require_success: + self.assertTrue(args[0](), f"callable at index {i} failed") + continue + + if isinstance(args[0], dict): + local_env = env.copy() + local_env.update(args[0]) + args = args[1:] + else: + local_env = env + + local_env["PORTAGE_BINHOST"] = f"file:///{tmppkgdir_suffix}" + proc = subprocess.Popen(args, env=local_env, stdout=stdout) + + if debug: + proc.wait() + else: + output = proc.stdout.readlines() + proc.wait() + proc.stdout.close() + if proc.returncode != os.EX_OK: + for line in output: + sys.stderr.write(_unicode_decode(line)) + + if all_successful and proc.returncode != os.EX_OK: + all_successful = False + + if require_success: + self.assertEqual( + os.EX_OK, proc.returncode, f"emerge failed with args {args}" + ) + + return all_successful + + try: + for d in dirs: + ensure_dirs(d) + for x in true_symlinks: + os.symlink(needed_binaries["true"][0], os.path.join(fake_bin, x)) + + with open(os.path.join(var_cache_edb, "counter"), "wb") as f: + f.write(b"100") + + if debug: + # The subprocess inherits both stdout and stderr, for + # debugging purposes. + stdout = None + else: + # The subprocess inherits stderr so that any warnings + # triggered by python -Wd will be visible. + stdout = subprocess.PIPE + + run_commands(test_commands) + deferred_success = run_commands(test_commands_nonfatal, False) + run_commands(test_commands_final) + + # Check the return value of test_commands_nonfatal later on so + # we can get a better error message from test_commands_final + # if possible. + self.assertTrue(deferred_success, f"{test_commands_nonfatal} failed") + finally: + playground.debug = False + playground.cleanup() + tmppkgdir.cleanup()