commit: 4c7ce0e20b36903a4e7acd7aaa6aac8779917fc4 Author: Sam James <sam <AT> gentoo <DOT> org> AuthorDate: Fri Jan 2 01:35:59 2026 +0000 Commit: Zac Medico <zmedico <AT> gentoo <DOT> org> CommitDate: Sun Jan 4 02:21:47 2026 +0000 URL: https://gitweb.gentoo.org/proj/portage.git/commit/?id=4c7ce0e2
tests: add testcase for failed Qt upgrade (XFAIL'd) Dropping dev-python/pyside's dev-qt/qtconnectivity dependency here is enough to fix it. Bug: https://bugs.gentoo.org/968228 Signed-off-by: Sam James <sam <AT> gentoo.org> Signed-off-by: Zac Medico <zmedico <AT> gentoo.org> lib/portage/tests/resolver/meson.build | 1 + lib/portage/tests/resolver/test_missed_update.py | 248 +++++++++++++++++++++++ 2 files changed, 249 insertions(+) diff --git a/lib/portage/tests/resolver/meson.build b/lib/portage/tests/resolver/meson.build index bab474cf0d..7ae73630be 100644 --- a/lib/portage/tests/resolver/meson.build +++ b/lib/portage/tests/resolver/meson.build @@ -85,6 +85,7 @@ py.install_sources( 'test_solve_non_slot_operator_slot_conflicts.py', 'test_targetroot.py', 'test_tar_merge_order.py', + 'test_missed_update.py', 'test_unmerge_order.py', 'test_unnecessary_slot_upgrade.py', 'test_update.py', diff --git a/lib/portage/tests/resolver/test_missed_update.py b/lib/portage/tests/resolver/test_missed_update.py new file mode 100644 index 0000000000..6813a91727 --- /dev/null +++ b/lib/portage/tests/resolver/test_missed_update.py @@ -0,0 +1,248 @@ +# Copyright 2026 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +from portage.tests import TestCase +from portage.tests.resolver.ResolverPlayground import ( + ResolverPlayground, + ResolverPlaygroundTestCase, +) + + +class MissedQtUpdateTestCase(TestCase): + def testMissedQtUpdate(self): + """ + Testcase where Portage was unable to upgrade from + Qt 6.9.3 -> Qt 6.10.1 without an explicit redundant + argument on the command line (bug #968228). + + This was fixed by the "earlier slot operator backtracking" + patch related to bug #964705. + """ + ebuilds = { + "dev-qt/qtbase-6.9.3": { + "EAPI": "8", + "SLOT": "6", + "IUSE": "+nls", + "RDEPEND": """ + !<dev-qt/qtconnectivity-6.9.3:6 + !<dev-qt/qtsvg-6.9.3:6 + !<dev-qt/qttools-6.9.3:6 + """, + "PDEPEND": "nls? ( ~dev-qt/qttranslations-6.9.3:6 )", + }, + "dev-qt/qtbase-6.10.1": { + "EAPI": "8", + "SLOT": "6", + "IUSE": "+nls", + "RDEPEND": """ + !<dev-qt/qtconnectivity-6.10.1:6 + !<dev-qt/qtsvg-6.10.1:6 + !<dev-qt/qttools-6.10.1:6 + """, + "PDEPEND": "nls? ( ~dev-qt/qttranslations-6.10.1:6 )", + }, + "dev-qt/qtconnectivity-6.9.3": { + "EAPI": "8", + "SLOT": "6", + "DEPEND": "~dev-qt/qtbase-6.9.3:6", + }, + "dev-qt/qtconnectivity-6.10.1": { + "EAPI": "8", + "SLOT": "6", + "DEPEND": "~dev-qt/qtbase-6.10.1:6", + }, + "dev-qt/qttranslations-6.9.3": { + "EAPI": "8", + "SLOT": "6", + "DEPEND": "~dev-qt/qtbase-6.9.3:6", + "BDEPEND": "~dev-qt/qttools-6.9.3:6", + }, + "dev-qt/qttranslations-6.10.1": { + "EAPI": "8", + "SLOT": "6", + "DEPEND": "~dev-qt/qtbase-6.10.1:6", + "BDEPEND": "~dev-qt/qttools-6.10.1:6", + }, + "dev-qt/qtsvg-6.9.3": { + "EAPI": "8", + "SLOT": "6", + "DEPEND": "~dev-qt/qtbase-6.9.3:6", + "RDEPEND": """ + ~dev-qt/qtbase-6.9.3:6 + """, + }, + "dev-qt/qtsvg-6.10.1": { + "EAPI": "8", + "SLOT": "6", + "DEPEND": "~dev-qt/qtbase-6.10.1:6", + "RDEPEND": """ + ~dev-qt/qtbase-6.10.1:6 + """, + }, + "dev-qt/qttools-6.9.3": { + "EAPI": "8", + "SLOT": "6", + "DEPEND": "~dev-qt/qtbase-6.9.3:6", + "RDEPEND": "~dev-qt/qtbase-6.9.3:6", + }, + "dev-qt/qttools-6.10.1": { + "EAPI": "8", + "SLOT": "6", + "DEPEND": "~dev-qt/qtbase-6.10.1:6", + "RDEPEND": """ + ~dev-qt/qtbase-6.10.1:6 + """, + }, + "dev-python/pyside-6.9.3": { + "EAPI": "8", + "SLOT": "6/6.9.3", + "DEPEND": """ + =dev-qt/qtbase-6.9.3*:6 + =dev-qt/qttools-6.9.3*:6 + =dev-qt/qtconnectivity-6.9.3*:6 + """, + "RDEPEND": """ + =dev-qt/qtbase-6.9.3*:6 + =dev-qt/qttools-6.9.3*:6 + =dev-qt/qtconnectivity-6.9.3*:6 + """, + }, + "dev-python/pyside-6.10.1": { + "EAPI": "8", + "SLOT": "6/6.10.1", + "DEPEND": """ + =dev-qt/qtbase-6.10.1*:6 + =dev-qt/qtconnectivity-6.10.1*:6 + """, + "RDEPEND": """ + =dev-qt/qtbase-6.10.1*:6 + =dev-qt/qtconnectivity-6.10.1*:6 + """, + }, + "media-gfx/freecad-1.0.1-r2": { + "EAPI": "8", + "SLOT": "6", + "DEPEND": """ + dev-qt/qtbase:6 + dev-qt/qtsvg:6 + dev-python/pyside:6= + """, + "RDEPEND": """ + dev-qt/qtbase:6 + dev-qt/qtsvg:6 + dev-python/pyside:6= + """, + }, + } + installed = { + "dev-qt/qtbase-6.9.3": { + "EAPI": "8", + "SLOT": "6", + "IUSE": "+nls", + "USE": "nls", + "PDEPEND": "nls? ( ~dev-qt/qttranslations-6.9.3:6 )", + }, + "dev-qt/qtconnectivity-6.9.3": { + "EAPI": "8", + "SLOT": "6", + "DEPEND": "~dev-qt/qtbase-6.9.3:6", + }, + "dev-qt/qttranslations-6.9.3": { + "EAPI": "8", + "SLOT": "6", + "DEPEND": "~dev-qt/qtbase-6.9.3:6", + "BDEPEND": "~dev-qt/qttools-6.9.3:6", + }, + "dev-qt/qtsvg-6.9.3": { + "EAPI": "8", + "SLOT": "6", + "DEPEND": "~dev-qt/qtbase-6.9.3:6", + "RDEPEND": "~dev-qt/qtbase-6.9.3:6", + }, + "dev-qt/qttools-6.9.3": { + "EAPI": "8", + "SLOT": "6", + "DEPEND": "~dev-qt/qtbase-6.9.3:6", + "RDEPEND": "~dev-qt/qtbase-6.9.3:6", + }, + "dev-python/pyside-6.9.3": { + "EAPI": "8", + "SLOT": "6/6.9.3", + "DEPEND": """ + =dev-qt/qtbase-6.9.3*:6 + =dev-qt/qtconnectivity-6.9.3*:6 + """, + "RDEPEND": """ + =dev-qt/qtbase-6.9.3*:6 + =dev-qt/qtconnectivity-6.9.3*:6 + """, + }, + "media-gfx/freecad-1.0.1-r2": { + "EAPI": "8", + "SLOT": "6", + "DEPEND": """ + dev-qt/qtbase:6 + dev-qt/qtsvg:6 + dev-python/pyside:6/6.9.3= + """, + "RDEPEND": """ + dev-qt/qtbase:6 + dev-qt/qtsvg:6 + dev-python/pyside:6/6.9.3= + """, + }, + } + + world = ("media-gfx/freecad",) + + test_cases = ( + # The extra pyside atom is sufficient to nudge Portage + # towards a solution but shouldn't be necessary. + # ResolverPlaygroundTestCase( + # ["@world", "=dev-python/pyside-6.10.1"], + # success=True, + # options={"--update": True, "--deep": True}, + # mergelist=[ + # "dev-qt/qtbase-6.10.1", + # "dev-qt/qttools-6.10.1", + # "!<dev-qt/qttools-6.10.1:6", + # "dev-qt/qttranslations-6.10.1", + # "dev-qt/qtconnectivity-6.10.1", + # "!<dev-qt/qtconnectivity-6.10.1:6", + # "dev-qt/qtsvg-6.10.1", + # "!<dev-qt/qtsvg-6.10.1:6", + # "dev-python/pyside-6.10.1", + # "media-gfx/freecad-1.0.1-r2", + # ], + # ), + # It should resolve identically (or at least with a solution) + # without explicit dev-python/pyside, as it's a dependency of + # media-gfx/freecad. + ResolverPlaygroundTestCase( + ["@world"], + success=True, + options={"--update": True, "--deep": True}, + mergelist=[ + "dev-qt/qtbase-6.10.1", + "dev-qt/qttools-6.10.1", + "!<dev-qt/qttools-6.10.1:6", + "dev-qt/qttranslations-6.10.1", + "dev-qt/qtconnectivity-6.10.1", + "!<dev-qt/qtconnectivity-6.10.1:6", + "dev-qt/qtsvg-6.10.1", + "!<dev-qt/qtsvg-6.10.1:6", + "dev-python/pyside-6.10.1", + "media-gfx/freecad-1.0.1-r2", + ], + ), + ) + + playground = ResolverPlayground( + ebuilds=ebuilds, installed=installed, world=world + ) + try: + for test_case in test_cases: + playground.run_TestCase(test_case) + self.assertEqual(test_case.test_success, True, test_case.fail_msg) + finally: + playground.cleanup()
