|
|
9fc8e2 |
From a96d701f7f55ff475e11ac9cda63b81c31c54e7a Mon Sep 17 00:00:00 2001
|
|
|
9fc8e2 |
From: Daniel Mach <dmach@redhat.com>
|
|
|
9fc8e2 |
Date: Wed, 6 May 2020 08:34:46 +0200
|
|
|
9fc8e2 |
Subject: [PATCH] history: Fix dnf history rollback when a package was removed
|
|
|
9fc8e2 |
(RhBug:1683134)
|
|
|
9fc8e2 |
|
|
|
9fc8e2 |
---
|
|
|
9fc8e2 |
libdnf/transaction/MergedTransaction.cpp | 25 +++-
|
|
|
9fc8e2 |
.../transaction/MergedTransactionTest.cpp | 120 ++++++++++++++++--
|
|
|
9fc8e2 |
.../transaction/MergedTransactionTest.hpp | 6 +-
|
|
|
9fc8e2 |
3 files changed, 137 insertions(+), 14 deletions(-)
|
|
|
9fc8e2 |
|
|
|
9fc8e2 |
diff --git a/libdnf/transaction/MergedTransaction.cpp b/libdnf/transaction/MergedTransaction.cpp
|
|
|
9fc8e2 |
index a7c06ffa9..a8d878cb5 100644
|
|
|
9fc8e2 |
--- a/libdnf/transaction/MergedTransaction.cpp
|
|
|
9fc8e2 |
+++ b/libdnf/transaction/MergedTransaction.cpp
|
|
|
9fc8e2 |
@@ -19,6 +19,7 @@
|
|
|
9fc8e2 |
*/
|
|
|
9fc8e2 |
|
|
|
9fc8e2 |
#include "MergedTransaction.hpp"
|
|
|
9fc8e2 |
+#include <algorithm>
|
|
|
9fc8e2 |
#include <vector>
|
|
|
9fc8e2 |
|
|
|
9fc8e2 |
namespace libdnf {
|
|
|
9fc8e2 |
@@ -171,6 +172,21 @@ MergedTransaction::getConsoleOutput()
|
|
|
9fc8e2 |
return output;
|
|
|
9fc8e2 |
}
|
|
|
9fc8e2 |
|
|
|
9fc8e2 |
+
|
|
|
9fc8e2 |
+static bool transaction_item_sort_function(const std::shared_ptr<TransactionItemBase> lhs, const std::shared_ptr<TransactionItemBase> rhs) {
|
|
|
9fc8e2 |
+ if (lhs->isForwardAction() && rhs->isForwardAction()) {
|
|
|
9fc8e2 |
+ return false;
|
|
|
9fc8e2 |
+ }
|
|
|
9fc8e2 |
+ if (lhs->isBackwardAction() && rhs->isBackwardAction()) {
|
|
|
9fc8e2 |
+ return false;
|
|
|
9fc8e2 |
+ }
|
|
|
9fc8e2 |
+ if (lhs->isBackwardAction()) {
|
|
|
9fc8e2 |
+ return true;
|
|
|
9fc8e2 |
+ }
|
|
|
9fc8e2 |
+ return false;
|
|
|
9fc8e2 |
+}
|
|
|
9fc8e2 |
+
|
|
|
9fc8e2 |
+
|
|
|
9fc8e2 |
/**
|
|
|
9fc8e2 |
* Get list of transaction items involved in the merged transaction
|
|
|
9fc8e2 |
* Actions are merged using following rules:
|
|
|
9fc8e2 |
@@ -203,6 +219,9 @@ MergedTransaction::getItems()
|
|
|
9fc8e2 |
// iterate over transaction
|
|
|
9fc8e2 |
for (auto t : transactions) {
|
|
|
9fc8e2 |
auto transItems = t->getItems();
|
|
|
9fc8e2 |
+ // sort transaction items by their action type - forward/backward
|
|
|
9fc8e2 |
+ // this fixes behavior of the merging algorithm in several edge cases
|
|
|
9fc8e2 |
+ std::sort(transItems.begin(), transItems.end(), transaction_item_sort_function);
|
|
|
9fc8e2 |
// iterate over transaction items
|
|
|
9fc8e2 |
for (auto transItem : transItems) {
|
|
|
9fc8e2 |
// get item and its type
|
|
|
9fc8e2 |
@@ -383,10 +402,6 @@ MergedTransaction::mergeItem(ItemPairMap &itemPairMap, TransactionItemBasePtr mT
|
|
|
9fc8e2 |
auto firstState = previousItemPair.first->getAction();
|
|
|
9fc8e2 |
auto newState = mTransItem->getAction();
|
|
|
9fc8e2 |
|
|
|
9fc8e2 |
- if (firstState == TransactionItemAction::INSTALL && mTransItem->isBackwardAction()) {
|
|
|
9fc8e2 |
- return;
|
|
|
9fc8e2 |
- }
|
|
|
9fc8e2 |
-
|
|
|
9fc8e2 |
switch (firstState) {
|
|
|
9fc8e2 |
case TransactionItemAction::REMOVE:
|
|
|
9fc8e2 |
case TransactionItemAction::OBSOLETED:
|
|
|
9fc8e2 |
@@ -399,6 +414,8 @@ MergedTransaction::mergeItem(ItemPairMap &itemPairMap, TransactionItemBasePtr mT
|
|
|
9fc8e2 |
// Install -> Remove = (nothing)
|
|
|
9fc8e2 |
itemPairMap.erase(name);
|
|
|
9fc8e2 |
break;
|
|
|
9fc8e2 |
+ } else if (mTransItem->isBackwardAction()) {
|
|
|
9fc8e2 |
+ break;
|
|
|
9fc8e2 |
}
|
|
|
9fc8e2 |
// altered -> transfer install to the altered package
|
|
|
9fc8e2 |
mTransItem->setAction(TransactionItemAction::INSTALL);
|
|
|
9fc8e2 |
diff --git a/tests/libdnf/transaction/MergedTransactionTest.cpp b/tests/libdnf/transaction/MergedTransactionTest.cpp
|
|
|
9fc8e2 |
index 90ad182cf..52507700b 100644
|
|
|
9fc8e2 |
--- a/tests/libdnf/transaction/MergedTransactionTest.cpp
|
|
|
9fc8e2 |
+++ b/tests/libdnf/transaction/MergedTransactionTest.cpp
|
|
|
9fc8e2 |
@@ -700,7 +700,7 @@ MergedTransactionTest::test_downgrade()
|
|
|
9fc8e2 |
}
|
|
|
9fc8e2 |
|
|
|
9fc8e2 |
void
|
|
|
9fc8e2 |
-MergedTransactionTest::test_install_downgrade()
|
|
|
9fc8e2 |
+MergedTransactionTest::test_install_downgrade_upgrade_remove()
|
|
|
9fc8e2 |
{
|
|
|
9fc8e2 |
auto trans1 = std::make_shared< libdnf::swdb_private::Transaction >(conn);
|
|
|
9fc8e2 |
trans1->addItem(
|
|
|
9fc8e2 |
@@ -724,19 +724,123 @@ MergedTransactionTest::test_install_downgrade()
|
|
|
9fc8e2 |
TransactionItemReason::USER
|
|
|
9fc8e2 |
);
|
|
|
9fc8e2 |
|
|
|
9fc8e2 |
+ auto trans3 = std::make_shared< libdnf::swdb_private::Transaction >(conn);
|
|
|
9fc8e2 |
+ trans3->addItem(
|
|
|
9fc8e2 |
+ nevraToRPMItem(conn, "tour-0:4.6-1.noarch"),
|
|
|
9fc8e2 |
+ "repo2",
|
|
|
9fc8e2 |
+ TransactionItemAction::UPGRADED,
|
|
|
9fc8e2 |
+ TransactionItemReason::USER
|
|
|
9fc8e2 |
+ );
|
|
|
9fc8e2 |
+ trans3->addItem(
|
|
|
9fc8e2 |
+ nevraToRPMItem(conn, "tour-0:4.8-1.noarch"),
|
|
|
9fc8e2 |
+ "repo1",
|
|
|
9fc8e2 |
+ TransactionItemAction::UPGRADE,
|
|
|
9fc8e2 |
+ TransactionItemReason::USER
|
|
|
9fc8e2 |
+ );
|
|
|
9fc8e2 |
+
|
|
|
9fc8e2 |
+ auto trans4 = std::make_shared< libdnf::swdb_private::Transaction >(conn);
|
|
|
9fc8e2 |
+ trans4->addItem(
|
|
|
9fc8e2 |
+ nevraToRPMItem(conn, "tour-0:4.8-1.noarch"),
|
|
|
9fc8e2 |
+ "repo1",
|
|
|
9fc8e2 |
+ TransactionItemAction::REMOVE,
|
|
|
9fc8e2 |
+ TransactionItemReason::USER
|
|
|
9fc8e2 |
+ );
|
|
|
9fc8e2 |
+
|
|
|
9fc8e2 |
MergedTransaction merged(trans1);
|
|
|
9fc8e2 |
+
|
|
|
9fc8e2 |
+ // test merging trans1, trans2
|
|
|
9fc8e2 |
merged.merge(trans2);
|
|
|
9fc8e2 |
+ auto items2 = merged.getItems();
|
|
|
9fc8e2 |
+ CPPUNIT_ASSERT_EQUAL(1, (int)items2.size());
|
|
|
9fc8e2 |
+ auto item2 = items2.at(0);
|
|
|
9fc8e2 |
+ CPPUNIT_ASSERT_EQUAL(std::string("tour-4.6-1.noarch"), item2->getItem()->toStr());
|
|
|
9fc8e2 |
+ CPPUNIT_ASSERT_EQUAL(std::string("repo2"), item2->getRepoid());
|
|
|
9fc8e2 |
+ CPPUNIT_ASSERT_EQUAL(TransactionItemAction::INSTALL, item2->getAction());
|
|
|
9fc8e2 |
+ CPPUNIT_ASSERT_EQUAL(TransactionItemReason::USER, item2->getReason());
|
|
|
9fc8e2 |
|
|
|
9fc8e2 |
- auto items = merged.getItems();
|
|
|
9fc8e2 |
- CPPUNIT_ASSERT_EQUAL(1, (int)items.size());
|
|
|
9fc8e2 |
+ // test merging trans1, trans2, trans3
|
|
|
9fc8e2 |
+ merged.merge(trans3);
|
|
|
9fc8e2 |
+ auto items3 = merged.getItems();
|
|
|
9fc8e2 |
+ CPPUNIT_ASSERT_EQUAL(1, (int)items3.size());
|
|
|
9fc8e2 |
+ auto item3 = items3.at(0);
|
|
|
9fc8e2 |
+ CPPUNIT_ASSERT_EQUAL(std::string("tour-4.8-1.noarch"), item3->getItem()->toStr());
|
|
|
9fc8e2 |
+ CPPUNIT_ASSERT_EQUAL(std::string("repo1"), item3->getRepoid());
|
|
|
9fc8e2 |
+ CPPUNIT_ASSERT_EQUAL(TransactionItemAction::INSTALL, item3->getAction());
|
|
|
9fc8e2 |
+ CPPUNIT_ASSERT_EQUAL(TransactionItemReason::USER, item3->getReason());
|
|
|
9fc8e2 |
|
|
|
9fc8e2 |
- auto item = items.at(0);
|
|
|
9fc8e2 |
- CPPUNIT_ASSERT_EQUAL(std::string("tour-4.6-1.noarch"), item->getItem()->toStr());
|
|
|
9fc8e2 |
- CPPUNIT_ASSERT_EQUAL(std::string("repo2"), item->getRepoid());
|
|
|
9fc8e2 |
- CPPUNIT_ASSERT_EQUAL(TransactionItemAction::INSTALL, item->getAction());
|
|
|
9fc8e2 |
- CPPUNIT_ASSERT_EQUAL(TransactionItemReason::USER, item->getReason());
|
|
|
9fc8e2 |
+ // test merging trans1, trans2, trans3, trans4
|
|
|
9fc8e2 |
+ merged.merge(trans4);
|
|
|
9fc8e2 |
+ auto items4 = merged.getItems();
|
|
|
9fc8e2 |
+ CPPUNIT_ASSERT_EQUAL(0, (int)items4.size());
|
|
|
9fc8e2 |
+ // trans4 removes the package, empty output is expected
|
|
|
9fc8e2 |
}
|
|
|
9fc8e2 |
|
|
|
9fc8e2 |
+
|
|
|
9fc8e2 |
+void
|
|
|
9fc8e2 |
+MergedTransactionTest::test_downgrade_upgrade_remove()
|
|
|
9fc8e2 |
+{
|
|
|
9fc8e2 |
+ auto trans1 = std::make_shared< libdnf::swdb_private::Transaction >(conn);
|
|
|
9fc8e2 |
+ trans1->addItem(
|
|
|
9fc8e2 |
+ nevraToRPMItem(conn, "tour-0:4.6-1.noarch"),
|
|
|
9fc8e2 |
+ "repo2",
|
|
|
9fc8e2 |
+ TransactionItemAction::DOWNGRADE,
|
|
|
9fc8e2 |
+ TransactionItemReason::USER
|
|
|
9fc8e2 |
+ );
|
|
|
9fc8e2 |
+ trans1->addItem(
|
|
|
9fc8e2 |
+ nevraToRPMItem(conn, "tour-0:4.8-1.noarch"),
|
|
|
9fc8e2 |
+ "repo1",
|
|
|
9fc8e2 |
+ TransactionItemAction::DOWNGRADED,
|
|
|
9fc8e2 |
+ TransactionItemReason::USER
|
|
|
9fc8e2 |
+ );
|
|
|
9fc8e2 |
+
|
|
|
9fc8e2 |
+ // items are in reversed order than in test_install_downgrade_upgrade_remove()
|
|
|
9fc8e2 |
+ // fixing this required ordering transaction items by forward/backward action
|
|
|
9fc8e2 |
+ auto trans2 = std::make_shared< libdnf::swdb_private::Transaction >(conn);
|
|
|
9fc8e2 |
+ trans2->addItem(
|
|
|
9fc8e2 |
+ nevraToRPMItem(conn, "tour-0:4.8-1.noarch"),
|
|
|
9fc8e2 |
+ "repo1",
|
|
|
9fc8e2 |
+ TransactionItemAction::UPGRADE,
|
|
|
9fc8e2 |
+ TransactionItemReason::USER
|
|
|
9fc8e2 |
+ );
|
|
|
9fc8e2 |
+ trans2->addItem(
|
|
|
9fc8e2 |
+ nevraToRPMItem(conn, "tour-0:4.6-1.noarch"),
|
|
|
9fc8e2 |
+ "repo2",
|
|
|
9fc8e2 |
+ TransactionItemAction::UPGRADED,
|
|
|
9fc8e2 |
+ TransactionItemReason::USER
|
|
|
9fc8e2 |
+ );
|
|
|
9fc8e2 |
+
|
|
|
9fc8e2 |
+ auto trans3 = std::make_shared< libdnf::swdb_private::Transaction >(conn);
|
|
|
9fc8e2 |
+ trans3->addItem(
|
|
|
9fc8e2 |
+ nevraToRPMItem(conn, "tour-0:4.8-1.noarch"),
|
|
|
9fc8e2 |
+ "repo1",
|
|
|
9fc8e2 |
+ TransactionItemAction::REMOVE,
|
|
|
9fc8e2 |
+ TransactionItemReason::USER
|
|
|
9fc8e2 |
+ );
|
|
|
9fc8e2 |
+
|
|
|
9fc8e2 |
+ MergedTransaction merged(trans1);
|
|
|
9fc8e2 |
+
|
|
|
9fc8e2 |
+ // test merging trans1, trans2
|
|
|
9fc8e2 |
+ merged.merge(trans2);
|
|
|
9fc8e2 |
+ auto items2 = merged.getItems();
|
|
|
9fc8e2 |
+ CPPUNIT_ASSERT_EQUAL(1, (int)items2.size());
|
|
|
9fc8e2 |
+ auto item2 = items2.at(0);
|
|
|
9fc8e2 |
+ CPPUNIT_ASSERT_EQUAL(std::string("tour-4.8-1.noarch"), item2->getItem()->toStr());
|
|
|
9fc8e2 |
+ CPPUNIT_ASSERT_EQUAL(std::string("repo1"), item2->getRepoid());
|
|
|
9fc8e2 |
+ CPPUNIT_ASSERT_EQUAL(TransactionItemAction::REINSTALL, item2->getAction());
|
|
|
9fc8e2 |
+ CPPUNIT_ASSERT_EQUAL(TransactionItemReason::USER, item2->getReason());
|
|
|
9fc8e2 |
+
|
|
|
9fc8e2 |
+ // test merging trans1, trans2, trans3
|
|
|
9fc8e2 |
+ merged.merge(trans3);
|
|
|
9fc8e2 |
+ auto items3 = merged.getItems();
|
|
|
9fc8e2 |
+ CPPUNIT_ASSERT_EQUAL(1, (int)items3.size());
|
|
|
9fc8e2 |
+ auto item3 = items3.at(0);
|
|
|
9fc8e2 |
+ CPPUNIT_ASSERT_EQUAL(std::string("tour-4.8-1.noarch"), item3->getItem()->toStr());
|
|
|
9fc8e2 |
+ CPPUNIT_ASSERT_EQUAL(std::string("repo1"), item3->getRepoid());
|
|
|
9fc8e2 |
+ CPPUNIT_ASSERT_EQUAL(TransactionItemAction::REMOVE, item3->getAction());
|
|
|
9fc8e2 |
+ CPPUNIT_ASSERT_EQUAL(TransactionItemReason::USER, item3->getReason());
|
|
|
9fc8e2 |
+}
|
|
|
9fc8e2 |
+
|
|
|
9fc8e2 |
+
|
|
|
9fc8e2 |
void
|
|
|
9fc8e2 |
MergedTransactionTest::test_multilib_identity()
|
|
|
9fc8e2 |
{
|
|
|
9fc8e2 |
diff --git a/tests/libdnf/transaction/MergedTransactionTest.hpp b/tests/libdnf/transaction/MergedTransactionTest.hpp
|
|
|
9fc8e2 |
index 9f1ed660a..77585e865 100644
|
|
|
9fc8e2 |
--- a/tests/libdnf/transaction/MergedTransactionTest.hpp
|
|
|
9fc8e2 |
+++ b/tests/libdnf/transaction/MergedTransactionTest.hpp
|
|
|
9fc8e2 |
@@ -26,7 +26,8 @@ class MergedTransactionTest : public CppUnit::TestCase {
|
|
|
9fc8e2 |
CPPUNIT_TEST(test_add_obsoleted_obsoleted);
|
|
|
9fc8e2 |
|
|
|
9fc8e2 |
CPPUNIT_TEST(test_downgrade);
|
|
|
9fc8e2 |
- CPPUNIT_TEST(test_install_downgrade);
|
|
|
9fc8e2 |
+ CPPUNIT_TEST(test_install_downgrade_upgrade_remove);
|
|
|
9fc8e2 |
+ CPPUNIT_TEST(test_downgrade_upgrade_remove);
|
|
|
9fc8e2 |
|
|
|
9fc8e2 |
CPPUNIT_TEST(test_multilib_identity);
|
|
|
9fc8e2 |
|
|
|
9fc8e2 |
@@ -56,7 +57,8 @@ class MergedTransactionTest : public CppUnit::TestCase {
|
|
|
9fc8e2 |
// END: tests ported from DNF unit tests
|
|
|
9fc8e2 |
|
|
|
9fc8e2 |
void test_downgrade();
|
|
|
9fc8e2 |
- void test_install_downgrade();
|
|
|
9fc8e2 |
+ void test_install_downgrade_upgrade_remove();
|
|
|
9fc8e2 |
+ void test_downgrade_upgrade_remove();
|
|
|
9fc8e2 |
|
|
|
9fc8e2 |
void test_multilib_identity();
|
|
|
9fc8e2 |
private:
|