Activation: remove old objects after update done
The update on PSUs is one-by-one, after each PSU is updated, notify
ItemUpdater by onUpdateDone() so that the old object for the PSU is
removed.
Tested: With dummy PSU image and update service, verify the old
objects are removed on Witherspoon.
Change-Id: I212b8cba9570ad96083d362bf57691fdabb4e42f
diff --git a/test/mocked_activation_listener.hpp b/test/mocked_activation_listener.hpp
new file mode 100644
index 0000000..cbef46d
--- /dev/null
+++ b/test/mocked_activation_listener.hpp
@@ -0,0 +1,14 @@
+#pragma once
+
+#include "activation_listener.hpp"
+
+#include <gmock/gmock.h>
+
+class MockedActivationListener : public ActivationListener
+{
+ public:
+ virtual ~MockedActivationListener() = default;
+
+ MOCK_METHOD2(onUpdateDone, void(const std::string& versionId,
+ const std::string& psuInventoryPath));
+};
diff --git a/test/test_activation.cpp b/test/test_activation.cpp
index 97efe79..a7ce542 100644
--- a/test/test_activation.cpp
+++ b/test/test_activation.cpp
@@ -1,4 +1,5 @@
#include "activation.hpp"
+#include "mocked_activation_listener.hpp"
#include "mocked_association_interface.hpp"
#include "mocked_utils.hpp"
@@ -62,6 +63,7 @@
sdbusplus::bus::bus mockedBus = sdbusplus::get_mocked_new(&sdbusMock);
const utils::MockedUtils& mockedUtils;
MockedAssociationInterface mockedAssociationInterface;
+ MockedActivationListener mockedActivationListener;
std::unique_ptr<Activation> activation;
std::string versionId = "abcdefgh";
std::string extVersion = "manufacturer=TestManu,model=TestModel";
@@ -75,7 +77,7 @@
{
activation = std::make_unique<Activation>(
mockedBus, dBusPath, versionId, extVersion, status, associations,
- &mockedAssociationInterface, filePath);
+ filePath, &mockedAssociationInterface, &mockedActivationListener);
}
TEST_F(TestActivation, ctorWithInvalidExtVersion)
@@ -83,7 +85,7 @@
extVersion = "invalid text";
activation = std::make_unique<Activation>(
mockedBus, dBusPath, versionId, extVersion, status, associations,
- &mockedAssociationInterface, filePath);
+ filePath, &mockedAssociationInterface, &mockedActivationListener);
}
TEST_F(TestActivation, getUpdateService)
@@ -96,7 +98,7 @@
activation = std::make_unique<Activation>(
mockedBus, dBusPath, versionId, extVersion, status, associations,
- &mockedAssociationInterface, filePath);
+ filePath, &mockedAssociationInterface, &mockedActivationListener);
auto service = getUpdateService(psuInventoryPath);
EXPECT_EQ(toCompare, service);
@@ -106,7 +108,7 @@
{
activation = std::make_unique<Activation>(
mockedBus, dBusPath, versionId, extVersion, status, associations,
- &mockedAssociationInterface, filePath);
+ filePath, &mockedAssociationInterface, &mockedActivationListener);
ON_CALL(mockedUtils, getPSUInventoryPath(_))
.WillByDefault(
Return(std::vector<std::string>({}))); // No PSU inventory
@@ -116,6 +118,7 @@
.Times(0);
EXPECT_CALL(mockedAssociationInterface, addFunctionalAssociation(dBusPath))
.Times(0);
+ EXPECT_CALL(mockedActivationListener, onUpdateDone(_, _)).Times(0);
EXPECT_EQ(Status::Failed, activation->activation());
}
@@ -124,7 +127,7 @@
constexpr auto psu0 = "/com/example/inventory/psu0";
activation = std::make_unique<Activation>(
mockedBus, dBusPath, versionId, extVersion, status, associations,
- &mockedAssociationInterface, filePath);
+ filePath, &mockedAssociationInterface, &mockedActivationListener);
ON_CALL(mockedUtils, getPSUInventoryPath(_))
.WillByDefault(
Return(std::vector<std::string>({psu0}))); // One PSU inventory
@@ -136,6 +139,9 @@
.Times(1);
EXPECT_CALL(mockedAssociationInterface, addFunctionalAssociation(dBusPath))
.Times(1);
+ EXPECT_CALL(mockedActivationListener,
+ onUpdateDone(StrEq(versionId), StrEq(psu0)))
+ .Times(1);
onUpdateDone();
EXPECT_EQ(Status::Active, activation->activation());
}
@@ -148,7 +154,7 @@
constexpr auto psu3 = "/com/example/inventory/psu3";
activation = std::make_unique<Activation>(
mockedBus, dBusPath, versionId, extVersion, status, associations,
- &mockedAssociationInterface, filePath);
+ filePath, &mockedAssociationInterface, &mockedActivationListener);
ON_CALL(mockedUtils, getPSUInventoryPath(_))
.WillByDefault(Return(
std::vector<std::string>({psu0, psu1, psu2, psu3}))); // 4 PSUs
@@ -157,14 +163,23 @@
EXPECT_EQ(Status::Activating, activation->activation());
EXPECT_EQ(10, getProgress());
+ EXPECT_CALL(mockedActivationListener,
+ onUpdateDone(StrEq(versionId), StrEq(psu0)))
+ .Times(1);
onUpdateDone();
EXPECT_EQ(Status::Activating, activation->activation());
EXPECT_EQ(30, getProgress());
+ EXPECT_CALL(mockedActivationListener,
+ onUpdateDone(StrEq(versionId), StrEq(psu1)))
+ .Times(1);
onUpdateDone();
EXPECT_EQ(Status::Activating, activation->activation());
EXPECT_EQ(50, getProgress());
+ EXPECT_CALL(mockedActivationListener,
+ onUpdateDone(StrEq(versionId), StrEq(psu2)))
+ .Times(1);
onUpdateDone();
EXPECT_EQ(Status::Activating, activation->activation());
EXPECT_EQ(70, getProgress());
@@ -174,6 +189,9 @@
EXPECT_CALL(mockedAssociationInterface, addFunctionalAssociation(dBusPath))
.Times(1);
+ EXPECT_CALL(mockedActivationListener,
+ onUpdateDone(StrEq(versionId), StrEq(psu3)))
+ .Times(1);
onUpdateDone();
EXPECT_EQ(Status::Active, activation->activation());
}
@@ -186,7 +204,7 @@
constexpr auto psu3 = "/com/example/inventory/psu3";
activation = std::make_unique<Activation>(
mockedBus, dBusPath, versionId, extVersion, status, associations,
- &mockedAssociationInterface, filePath);
+ filePath, &mockedAssociationInterface, &mockedActivationListener);
ON_CALL(mockedUtils, getPSUInventoryPath(_))
.WillByDefault(Return(
std::vector<std::string>({psu0, psu1, psu2, psu3}))); // 4 PSUs
@@ -195,6 +213,9 @@
EXPECT_EQ(Status::Activating, activation->activation());
EXPECT_EQ(10, getProgress());
+ EXPECT_CALL(mockedActivationListener,
+ onUpdateDone(StrEq(versionId), StrEq(psu0)))
+ .Times(1);
onUpdateDone();
EXPECT_EQ(Status::Activating, activation->activation());
EXPECT_EQ(30, getProgress());
@@ -203,6 +224,7 @@
.Times(0);
EXPECT_CALL(mockedAssociationInterface, addFunctionalAssociation(dBusPath))
.Times(0);
+ EXPECT_CALL(mockedActivationListener, onUpdateDone(_, _)).Times(0);
onUpdateFailed();
EXPECT_EQ(Status::Failed, activation->activation());
}
@@ -212,7 +234,7 @@
constexpr auto psu0 = "/com/example/inventory/psu0";
activation = std::make_unique<Activation>(
mockedBus, dBusPath, versionId, extVersion, status, associations,
- &mockedAssociationInterface, filePath);
+ filePath, &mockedAssociationInterface, &mockedActivationListener);
ON_CALL(mockedUtils, getPSUInventoryPath(_))
.WillByDefault(
Return(std::vector<std::string>({psu0}))); // One PSU inventory
@@ -229,7 +251,7 @@
extVersion = "manufacturer=TestManu,model=DifferentModel";
activation = std::make_unique<Activation>(
mockedBus, dBusPath, versionId, extVersion, status, associations,
- &mockedAssociationInterface, filePath);
+ filePath, &mockedAssociationInterface, &mockedActivationListener);
ON_CALL(mockedUtils, getPSUInventoryPath(_))
.WillByDefault(Return(std::vector<std::string>({psu0})));
activation->requestedActivation(RequestedStatus::Active);
@@ -243,7 +265,7 @@
extVersion = "manufacturer=DifferentManu,model=TestModel";
activation = std::make_unique<Activation>(
mockedBus, dBusPath, versionId, extVersion, status, associations,
- &mockedAssociationInterface, filePath);
+ filePath, &mockedAssociationInterface, &mockedActivationListener);
ON_CALL(mockedUtils, getPSUInventoryPath(_))
.WillByDefault(Return(std::vector<std::string>({psu0})));
activation->requestedActivation(RequestedStatus::Active);
@@ -260,7 +282,7 @@
constexpr auto psu0 = "/com/example/inventory/psu0";
activation = std::make_unique<Activation>(
mockedBus, dBusPath, versionId, extVersion, status, associations,
- &mockedAssociationInterface, filePath);
+ filePath, &mockedAssociationInterface, &mockedActivationListener);
ON_CALL(mockedUtils, getPSUInventoryPath(_))
.WillByDefault(
Return(std::vector<std::string>({psu0}))); // One PSU inventory
@@ -287,7 +309,7 @@
Return(any(PropertyType(std::string("DifferentModel")))));
activation = std::make_unique<Activation>(
mockedBus, dBusPath, versionId, extVersion, status, associations,
- &mockedAssociationInterface, filePath);
+ filePath, &mockedAssociationInterface, &mockedActivationListener);
ON_CALL(mockedUtils, getPSUInventoryPath(_))
.WillByDefault(Return(
std::vector<std::string>({psu0, psu1, psu2, psu3}))); // 4 PSUs
@@ -325,7 +347,7 @@
constexpr auto psu0 = "/com/example/inventory/psu0";
activation = std::make_unique<Activation>(
mockedBus, dBusPath, versionId, extVersion, status, associations,
- &mockedAssociationInterface, filePath);
+ filePath, &mockedAssociationInterface, &mockedActivationListener);
ON_CALL(mockedUtils, getPSUInventoryPath(_))
.WillByDefault(
@@ -348,7 +370,7 @@
constexpr auto psu0 = "/com/example/inventory/psu0";
activation = std::make_unique<Activation>(
mockedBus, dBusPath, versionId, extVersion, status, associations,
- &mockedAssociationInterface, filePath);
+ filePath, &mockedAssociationInterface, &mockedActivationListener);
ON_CALL(mockedUtils, getPSUInventoryPath(_))
.WillByDefault(
@@ -369,7 +391,7 @@
status = Status::Active; // Typically, a running PSU software is associated
activation = std::make_unique<Activation>(
mockedBus, dBusPath, versionId, extVersion, status, associations,
- &mockedAssociationInterface, filePath);
+ filePath, &mockedAssociationInterface, &mockedActivationListener);
ON_CALL(mockedUtils, getPSUInventoryPath(_))
.WillByDefault(
diff --git a/test/test_item_updater.cpp b/test/test_item_updater.cpp
index b4ecafc..cbea53c 100644
--- a/test/test_item_updater.cpp
+++ b/test/test_item_updater.cpp
@@ -490,3 +490,111 @@
.Times(1);
scanDirectory("./psu-images-valid-version0");
}
+
+TEST_F(TestItemUpdater, OnUpdateDoneOnTwoPSUsWithSameVersion)
+{
+ // Simulate there are two PSUs with same version, and updated to a new
+ // version
+ constexpr auto psu0 = "/com/example/inventory/psu0";
+ constexpr auto psu1 = "/com/example/inventory/psu1";
+ constexpr auto service = "com.example.Software.Psu";
+ auto version0 = std::string("version0");
+ auto version1 = std::string("version0");
+ auto objPath0 = getObjPath(version0);
+ auto objPath1 = getObjPath(version1);
+
+ EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
+ .WillOnce(Return(std::vector<std::string>({psu0, psu1})));
+ EXPECT_CALL(mockedUtils, getService(_, StrEq(psu0), _))
+ .WillOnce(Return(service));
+ EXPECT_CALL(mockedUtils, getService(_, StrEq(psu1), _))
+ .WillOnce(Return(service));
+ EXPECT_CALL(mockedUtils, getVersion(StrEq(psu0)))
+ .WillOnce(Return(std::string(version0)));
+ EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
+ StrEq(PRESENT)))
+ .WillOnce(Return(any(PropertyType(true)))); // present
+ EXPECT_CALL(mockedUtils, getVersion(StrEq(psu1)))
+ .WillOnce(Return(std::string(version1)));
+ EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
+ StrEq(PRESENT)))
+ .WillOnce(Return(any(PropertyType(true)))); // present
+
+ itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
+
+ // Now there is one activation and it has two associations
+ auto& activations = GetActivations();
+ auto& activation = activations.find(version0)->second;
+ auto assocs = activation->associations();
+ EXPECT_EQ(2u, assocs.size());
+ EXPECT_EQ(psu0, std::get<2>(assocs[0]));
+ EXPECT_EQ(psu1, std::get<2>(assocs[1]));
+
+ EXPECT_CALL(mockedUtils, isAssociated(StrEq(psu0), _))
+ .WillOnce(Return(true));
+ itemUpdater->onUpdateDone("A new version", psu0);
+
+ // Now the activation should have one assoiation
+ assocs = activation->associations();
+ EXPECT_EQ(1u, assocs.size());
+ EXPECT_EQ(psu1, std::get<2>(assocs[0]));
+
+ EXPECT_CALL(mockedUtils, isAssociated(StrEq(psu1), _))
+ .WillOnce(Return(true));
+ itemUpdater->onUpdateDone("A new version", psu1);
+
+ // Now the activation shall be erased
+ EXPECT_EQ(0u, activations.size());
+}
+
+TEST_F(TestItemUpdater, OnUpdateDoneOnTwoPSUsWithDifferentVersion)
+{
+ // Simulate there are two PSUs with different version, and updated to a new
+ // version
+ constexpr auto psu0 = "/com/example/inventory/psu0";
+ constexpr auto psu1 = "/com/example/inventory/psu1";
+ constexpr auto service = "com.example.Software.Psu";
+ auto version0 = std::string("version0");
+ auto version1 = std::string("version1");
+ auto objPath0 = getObjPath(version0);
+ auto objPath1 = getObjPath(version1);
+
+ EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
+ .WillOnce(Return(std::vector<std::string>({psu0, psu1})));
+ EXPECT_CALL(mockedUtils, getService(_, StrEq(psu0), _))
+ .WillOnce(Return(service));
+ EXPECT_CALL(mockedUtils, getService(_, StrEq(psu1), _))
+ .WillOnce(Return(service));
+ EXPECT_CALL(mockedUtils, getVersion(StrEq(psu0)))
+ .WillOnce(Return(std::string(version0)));
+ EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
+ StrEq(PRESENT)))
+ .WillOnce(Return(any(PropertyType(true)))); // present
+ EXPECT_CALL(mockedUtils, getVersion(StrEq(psu1)))
+ .WillOnce(Return(std::string(version1)));
+ EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
+ StrEq(PRESENT)))
+ .WillOnce(Return(any(PropertyType(true)))); // present
+
+ itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
+
+ // There are two activations and each with one association
+ const auto& activations = GetActivations();
+ EXPECT_EQ(2u, activations.size());
+
+ EXPECT_CALL(mockedUtils, isAssociated(StrEq(psu0), _))
+ .WillOnce(Return(true));
+ // After psu0 is done, only one activation should be left
+ itemUpdater->onUpdateDone("A new version", psu0);
+ EXPECT_EQ(1u, activations.size());
+ const auto& activation1 = activations.find(version1)->second;
+ const auto& assocs1 = activation1->associations();
+ EXPECT_EQ(1u, assocs1.size());
+ EXPECT_EQ(psu1, std::get<2>(assocs1[0]));
+
+ EXPECT_CALL(mockedUtils, isAssociated(StrEq(psu1), _))
+ .WillOnce(Return(true));
+ // After psu1 is done, no activation should be left
+ itemUpdater->onUpdateDone("A new version", psu1);
+ EXPECT_EQ(0u, activations.size());
+}