diff --git a/data/tests/hawkey/@System.repo b/data/tests/hawkey/@System.repo index 04e257ce37..381de75feb 100644 --- a/data/tests/hawkey/@System.repo +++ b/data/tests/hawkey/@System.repo @@ -23,3 +23,4 @@ =Req: /usr/bin/away =Pkg: tour 4 0 noarch =Prv: /usr/bin/away +=Pkg: bloop 1.0 1 noarch diff --git a/data/tests/hawkey/updates.repo b/data/tests/hawkey/updates.repo index a7e9198e6a..8e0a06620f 100644 --- a/data/tests/hawkey/updates.repo +++ b/data/tests/hawkey/updates.repo @@ -28,3 +28,9 @@ =Prv: dodo-dep =Pkg: dodo-dep-b 1.0 1 noarch =Prv: dodo-dep +=Pkg: bloop 1.0 1 noarch +=Pkg: bloop-ext 1.0 1 noarch +=Req: bloop = 1.0-1 +=Pkg: bloop 2.0 1 noarch +=Pkg: bloop-ext 2.0 1 noarch +=Req: bloop = 2.0-1 diff --git a/libdnf/goal/Goal.cpp b/libdnf/goal/Goal.cpp index c819dcebae..62679cce7a 100644 --- a/libdnf/goal/Goal.cpp +++ b/libdnf/goal/Goal.cpp @@ -758,6 +758,12 @@ Goal::install(DnfPackage *new_pkg, bool optional) packageToJob(new_pkg, &pImpl->staging, solverActions); } +void +Goal::lock(DnfPackage *pkg) +{ + queue_push2(&pImpl->staging, SOLVER_SOLVABLE|SOLVER_LOCK, dnf_package_get_id(pkg)); +} + void Goal::favor(DnfPackage *pkg) { diff --git a/libdnf/goal/Goal.hpp b/libdnf/goal/Goal.hpp index e3e651cf22..71265edbbd 100644 --- a/libdnf/goal/Goal.hpp +++ b/libdnf/goal/Goal.hpp @@ -74,6 +74,7 @@ struct Goal { */ void erase(HySelector sltr, int flags); void install(DnfPackage *new_pkg, bool optional); + void lock(DnfPackage *new_pkg); void favor(DnfPackage *new_pkg); void disfavor(DnfPackage *new_pkg); diff --git a/libdnf/hy-goal.cpp b/libdnf/hy-goal.cpp index a53982e3e4..8dc60437b2 100644 --- a/libdnf/hy-goal.cpp +++ b/libdnf/hy-goal.cpp @@ -170,6 +170,13 @@ hy_goal_install_optional(HyGoal goal, DnfPackage *new_pkg) return 0; } +int +hy_goal_lock(HyGoal goal, DnfPackage *pkg, GError **error) +{ + goal->lock(pkg); + return 0; +} + int hy_goal_favor(HyGoal goal, DnfPackage *pkg) { diff --git a/libdnf/hy-goal.h b/libdnf/hy-goal.h index cb906d0d92..94ec5e6260 100644 --- a/libdnf/hy-goal.h +++ b/libdnf/hy-goal.h @@ -117,6 +117,16 @@ int hy_goal_install(HyGoal goal, DnfPackage *new_pkg); */ int hy_goal_install_optional(HyGoal goal, DnfPackage *new_pkg); +/** +* @brief Lock package state. If installed, remains installed. If uninstalled, +* remains uninstalled. Returns 0 on success. +* +* @param goal HyGoal +* @param pkg Package to lock +* @return int +*/ +int hy_goal_lock(HyGoal goal, DnfPackage *pkg, GError **error); + /** * @brief Favor package when considering alternatives. Return value is always 0. * diff --git a/python/hawkey/tests/tests/test_query.py b/python/hawkey/tests/tests/test_query.py index 40fd1e97f0..925584c409 100644 --- a/python/hawkey/tests/tests/test_query.py +++ b/python/hawkey/tests/tests/test_query.py @@ -212,13 +212,13 @@ def test_disabled_repo(self): def test_multiple_flags(self): q = hawkey.Query(self.sack).filter(name__glob__not=["p*", "j*"]) self.assertItemsEqual(list(map(lambda p: p.name, q.run())), - ["baby", "dog", "flying", "fool", "gun", "tour"]) + ["baby", "bloop", "dog", "flying", "fool", "gun", "tour"]) def test_apply(self): q = hawkey.Query(self.sack).filter(name__glob__not="p*").apply() res = q.filter(name__glob__not="j*").run() self.assertItemsEqual(list(map(lambda p: p.name, res)), - ["baby", "dog", "flying", "fool", "gun", "tour"]) + ["baby", "bloop", "dog", "flying", "fool", "gun", "tour"]) def test_provides_glob_should_work(self): q1 = hawkey.Query(self.sack).filter(provides__glob="penny*") @@ -298,7 +298,7 @@ def test_downgradable(self): def test_rco_glob(self): q1 = hawkey.Query(self.sack).filter(requires__glob="*") - self.assertLength(q1, 10) + self.assertLength(q1, 12) q2 = hawkey.Query(self.sack).filter(requires="*") self.assertLength(q2, 0) q3 = hawkey.Query(self.sack).filter(conflicts__glob="cu*") @@ -326,9 +326,9 @@ def setUp(self): def test_upgradable(self): query = hawkey.Query(self.sack).filter(upgradable=True) self.assertEqual({str(pkg) for pkg in query}, - {"dog-1-1.x86_64", "flying-2-9.noarch", - "fool-1-3.noarch", "pilchard-1.2.3-1.i686", - "pilchard-1.2.3-1.x86_64"}) + {"bloop-1.0-1.noarch", "dog-1-1.x86_64", + "flying-2-9.noarch", "fool-1-3.noarch", + "pilchard-1.2.3-1.i686", "pilchard-1.2.3-1.x86_64"}) def test_updates_noarch(self): q = hawkey.Query(self.sack) diff --git a/tests/hawkey/README b/tests/hawkey/README index 46db6472ed..63ef3b4437 100644 --- a/tests/hawkey/README +++ b/tests/hawkey/README @@ -65,6 +65,10 @@ pigs, tour dodo, dodo-dep-a, dodo-dep-b * testing favor/disfavor +bloop, bloop-ext +* bloop-1.0 installed, bloop-ext-1.0 and *-2.0 in updates +* for testing package locking + === repos/yum === To test loading of yum repos we need an actual yum repo. It currently consists diff --git a/tests/hawkey/test_goal.cpp b/tests/hawkey/test_goal.cpp index c88901a92b..cca1277521 100644 --- a/tests/hawkey/test_goal.cpp +++ b/tests/hawkey/test_goal.cpp @@ -478,11 +478,11 @@ START_TEST(test_goal_upgrade_all) if (implicitobsoleteusescolors) { // Fedora, Mageia assert_list_names<&dnf_package_get_name>( - true, plist, "dog", "flying", "fool", "pilchard", "pilchard", NULL); + true, plist, "bloop", "dog", "flying", "fool", "pilchard", "pilchard", NULL); } else { // openSUSE assert_list_names<&dnf_package_get_name>( - true, plist, "dog", "flying", "fool", NULL); + true, plist, "bloop", "dog", "flying", "fool", NULL); } // see all obsoletes of fool: @@ -789,6 +789,92 @@ START_TEST(test_goal_disfavor) } END_TEST +START_TEST(test_goal_lock) +{ + DnfSack *sack = test_globals.sack; + HyGoal goal = hy_goal_create(sack); + + // check that installing "bloop-ext" without locking the base works fine + // (and auto-updates the base) + g_auto(HySubject) subject = hy_subject_create("bloop-ext"); + g_auto(HySelector) selector = hy_subject_get_best_selector(subject, sack, NULL, FALSE, "updates"); + fail_if(!hy_goal_install_selector(goal, selector, NULL)); + fail_if(hy_goal_run_flags(goal, DNF_NONE)); + + assert_iueo(goal, 1, 1, 0, 0); + + GPtrArray *plist = hy_goal_list_installs(goal, NULL); + const char *nvra = dnf_package_get_nevra( + static_cast(g_ptr_array_index(plist, 0))); + ck_assert_str_eq(nvra, "bloop-ext-2.0-1.noarch"); + g_ptr_array_unref(plist); + + plist = hy_goal_list_upgrades(goal, NULL); + nvra = dnf_package_get_nevra( + static_cast(g_ptr_array_index(plist, 0))); + ck_assert_str_eq(nvra, "bloop-2.0-1.noarch"); + g_ptr_array_unref(plist); + + hy_goal_free(goal); + + // now redo the same test, but lock the base pkg + goal = hy_goal_create(sack); + + g_autoptr(DnfPackage) base_pkg = by_name_repo(sack, "bloop", HY_SYSTEM_REPO_NAME); + fail_if(base_pkg == NULL); + fail_if(hy_goal_lock(goal, base_pkg, NULL)); + + fail_if(!hy_goal_install_selector(goal, selector, NULL)); + fail_if(hy_goal_run_flags(goal, DNF_NONE)); + + assert_iueo(goal, 1, 0, 0, 0); + + plist = hy_goal_list_installs(goal, NULL); + nvra = dnf_package_get_nevra( + static_cast(g_ptr_array_index(plist, 0))); + ck_assert_str_eq(nvra, "bloop-ext-1.0-1.noarch"); + g_ptr_array_unref(plist); + + hy_goal_free(goal); + + // now purposely exclude the compatible version and check that we get a + // sensical error + goal = hy_goal_create(sack); + fail_if(hy_goal_lock(goal, base_pkg, NULL)); + + HyQuery q = hy_query_create(sack); + hy_query_filter(q, HY_PKG_NEVRA, HY_EQ, "bloop-ext-1.0-1.noarch"); + hy_query_filter(q, HY_PKG_REPONAME, HY_EQ, "updates"); + g_autoptr(DnfPackageSet) pset = hy_query_run_set(q); + dnf_sack_add_excludes(sack, pset); + hy_query_free(q); + + fail_if(!hy_goal_install_selector(goal, selector, NULL)); + // notice the ! here; we expect failure + fail_if(!hy_goal_run_flags(goal, DNF_NONE)); + + g_autoptr(GError) error = NULL; + fail_unless(hy_goal_list_installs(goal, &error) == NULL); + fail_unless(error->code == DNF_ERROR_NO_SOLUTION); + fail_unless(hy_goal_count_problems(goal) > 0); + + auto problems = goal->describeProblemRules(0, true); + const char *expected[] = { + "package bloop-ext-2.0-1.noarch requires bloop = 2.0-1, but none of the providers can be installed", + "cannot install both bloop-2.0-1.noarch and bloop-1.0-1.noarch", + "conflicting requests", + "package bloop-ext-1.0-1.noarch is filtered out by exclude filtering" + }; + ck_assert_int_eq(problems.size(), 4); + ck_assert_str_eq(problems[0].c_str(), expected[0]); + ck_assert_str_eq(problems[1].c_str(), expected[1]); + ck_assert_str_eq(problems[2].c_str(), expected[2]); + ck_assert_str_eq(problems[3].c_str(), expected[3]); + + hy_goal_free(goal); +} +END_TEST + START_TEST(test_goal_installonly) { const char *installonly[] = {"fool", NULL}; @@ -829,10 +915,10 @@ START_TEST(test_goal_installonly_upgrade_all) int implicitobsoleteusescolors = pool_get_flag(pool, POOL_FLAG_IMPLICITOBSOLETEUSESCOLORS); if (implicitobsoleteusescolors) { // Fedora, Mageia - assert_iueo(goal, 1, 4, 1, 0); + assert_iueo(goal, 1, 5, 1, 0); } else { // openSUSE - assert_iueo(goal, 1, 2, 1, 0); + assert_iueo(goal, 1, 3, 1, 0); } hy_goal_free(goal); @@ -853,7 +939,7 @@ START_TEST(test_goal_upgrade_all_excludes) HyGoal goal = hy_goal_create(sack); hy_goal_upgrade_all(goal); hy_goal_run_flags(goal, DNF_NONE); - fail_unless(size_and_free(hy_goal_list_upgrades(goal, NULL)) == 3); + fail_unless(size_and_free(hy_goal_list_upgrades(goal, NULL)) == 4); hy_goal_free(goal); } END_TEST @@ -869,10 +955,10 @@ START_TEST(test_goal_upgrade_disabled_repo) int implicitobsoleteusescolors = pool_get_flag(pool, POOL_FLAG_IMPLICITOBSOLETEUSESCOLORS); if (implicitobsoleteusescolors) { // Fedora, Mageia - fail_unless(size_and_free(hy_goal_list_upgrades(goal, NULL)) == 5); + fail_unless(size_and_free(hy_goal_list_upgrades(goal, NULL)) == 6); } else { // openSUSE - fail_unless(size_and_free(hy_goal_list_upgrades(goal, NULL)) == 3); + fail_unless(size_and_free(hy_goal_list_upgrades(goal, NULL)) == 4); } hy_goal_free(goal); @@ -973,13 +1059,13 @@ START_TEST(test_goal_distupgrade_all_keep_arch) // gun pkg is not upgraded to latest version of different arch if (implicitobsoleteusescolors) { // Fedora, Mageia - assert_iueo(goal, 0, 5, 0, 1); - assert_list_names<&dnf_package_get_nevra>(true, plist, "dog-1-2.x86_64", "fool-1-5.noarch", + assert_iueo(goal, 0, 6, 0, 1); + assert_list_names<&dnf_package_get_nevra>(true, plist, "bloop-2.0-1.noarch", "dog-1-2.x86_64", "fool-1-5.noarch", "flying-3.1-0.x86_64", "pilchard-1.2.4-1.x86_64", "pilchard-1.2.4-1.i686", NULL); } else { // openSUSE - assert_iueo(goal, 0, 4, 0, 1); - assert_list_names<&dnf_package_get_nevra>(true, plist, "dog-1-2.x86_64", "fool-1-5.noarch", + assert_iueo(goal, 0, 5, 0, 1); + assert_list_names<&dnf_package_get_nevra>(true, plist, "bloop-2.0-1.noarch", "dog-1-2.x86_64", "fool-1-5.noarch", "flying-3.1-0.x86_64", "pilchard-1.2.4-2.x86_64", NULL); } g_ptr_array_unref(plist); @@ -1076,6 +1162,7 @@ START_TEST(test_goal_unneeded) HyGoal goal = hy_goal_create(sack); userinstalled(sack, goal, "baby"); + userinstalled(sack, goal, "bloop"); userinstalled(sack, goal, "dog"); userinstalled(sack, goal, "fool"); userinstalled(sack, goal, "gun"); @@ -1331,6 +1418,7 @@ goal_suite(void) tcase_add_test(tc, test_goal_forcebest); tcase_add_test(tc, test_goal_favor); tcase_add_test(tc, test_goal_disfavor); + tcase_add_test(tc, test_goal_lock); suite_add_tcase(s, tc); tc = tcase_create("ModifiesSackState"); diff --git a/tests/hawkey/test_query.cpp b/tests/hawkey/test_query.cpp index 12c7733c88..aac8c1d389 100644 --- a/tests/hawkey/test_query.cpp +++ b/tests/hawkey/test_query.cpp @@ -484,7 +484,7 @@ START_TEST(test_upgrades) HyQuery q = hy_query_create(test_globals.sack); hy_query_filter_upgrades(q, 1); - fail_unless(query_count_results(q) == TEST_EXPECT_UPDATES_NSOLVABLES - 5); + fail_unless(query_count_results(q) == TEST_EXPECT_UPDATES_NSOLVABLES - 8); hy_query_free(q); } END_TEST @@ -493,7 +493,7 @@ START_TEST(test_upgradable) { HyQuery q = hy_query_create(test_globals.sack); hy_query_filter_upgradable(q, 1); - ck_assert_int_eq(query_count_results(q), 5); + ck_assert_int_eq(query_count_results(q), 6); hy_query_free(q); } END_TEST @@ -893,7 +893,7 @@ START_TEST(test_query_multiple_flags) hy_query_filter(q, HY_PKG_NAME, HY_NOT | HY_GLOB, "p*"); plist = hy_query_run(q); - ck_assert_int_eq(plist->len, 8); + ck_assert_int_eq(plist->len, 9); g_ptr_array_unref(plist); hy_query_free(q); } @@ -920,7 +920,7 @@ START_TEST(test_query_apply) ck_assert_int_eq(_q.getApplied(), 0); plist = hy_query_run(q); - ck_assert_int_eq(plist->len, 6); + ck_assert_int_eq(plist->len, 7); g_ptr_array_unref(plist); hy_query_free(q); } diff --git a/tests/hawkey/testshared.h b/tests/hawkey/testshared.h index 2da9b56056..bf0dda7522 100644 --- a/tests/hawkey/testshared.h +++ b/tests/hawkey/testshared.h @@ -31,10 +31,10 @@ #define YUM_DIR_SUFFIX "yum/repodata/" #define YUM_REPO_NAME "nevermac" #define TEST_FIXED_ARCH "x86_64" -#define TEST_EXPECT_SYSTEM_PKGS 13 +#define TEST_EXPECT_SYSTEM_PKGS 14 #define TEST_EXPECT_SYSTEM_NSOLVABLES TEST_EXPECT_SYSTEM_PKGS #define TEST_EXPECT_MAIN_NSOLVABLES 14 -#define TEST_EXPECT_UPDATES_NSOLVABLES 13 +#define TEST_EXPECT_UPDATES_NSOLVABLES 17 #define TEST_EXPECT_YUM_NSOLVABLES 2 #ifdef __cplusplus