Test: Add unit test for PSU plug out and in
Split the function into two, one for handling the sdbus::message, the
other for handling the changed properties, so that it's easier to write
unit test cases.
Added the test cases:
* On a system with a PSU present, remove the PSU;
* On a system without PSU, plug the PSU in;
* On a system with a PSU, remove the PSU and add it back, while the
propertiesChanged callback is invoked with both Present and Version
properties.
* On a system with two PSUs with same version, remove them one-by-one,
and add back one-by-one, while PSU1 has a different version.
Tested: Verify ItemUpdater correctly handles the above cases:
* Remove the activation and version object if PSU is removed;
* Create activation and version object if PSU is added;
* When there are two PSUs with same version, removing one only
update the associations, removing the other shall result in
the objects to be removed;
Adding one back will create the objects, and adding the other
one with different version will create new objects.
Signed-off-by: Lei YU <mine260309@gmail.com>
Change-Id: I14c7ae9f03ec91bb1c85bb5a18d69f20dc1efd53
diff --git a/test/test_item_updater.cpp b/test/test_item_updater.cpp
index 2b9af43..b362803 100644
--- a/test/test_item_updater.cpp
+++ b/test/test_item_updater.cpp
@@ -13,11 +13,13 @@
using ::testing::StrEq;
using std::experimental::any;
-using PropertyType = utils::UtilsInterface::PropertyType;
class TestItemUpdater : public ::testing::Test
{
public:
+ using Properties = ItemUpdater::Properties;
+ using PropertyType = utils::UtilsInterface::PropertyType;
+
TestItemUpdater() :
mockedUtils(
reinterpret_cast<const utils::MockedUtils&>(utils::getUtils()))
@@ -39,6 +41,12 @@
return std::string(dBusPath) + "/" + versionId;
}
+ void onPsuInventoryChanged(const std::string& psuPath,
+ const Properties& properties)
+ {
+ itemUpdater->onPsuInventoryChanged(psuPath, properties);
+ }
+
static constexpr auto dBusPath = SOFTWARE_OBJPATH;
sdbusplus::SdBusMock sdbusMock;
sdbusplus::bus::bus mockedBus = sdbusplus::get_mocked_new(&sdbusMock);
@@ -206,3 +214,203 @@
EXPECT_EQ(1u, assocs1.size());
EXPECT_EQ(psu1, std::get<2>(assocs1[0]));
}
+
+TEST_F(TestItemUpdater, OnOnePSURemoved)
+{
+ constexpr auto psuPath = "/com/example/inventory/psu0";
+ constexpr auto service = "com.example.Software.Psu";
+ constexpr auto version = "version0";
+ std::string objPath = getObjPath(version);
+ EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
+ .WillOnce(Return(std::vector<std::string>({psuPath})));
+ EXPECT_CALL(mockedUtils, getService(_, StrEq(psuPath), _))
+ .WillOnce(Return(service));
+ EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
+ _, StrEq(VERSION)))
+ .WillOnce(Return(any(PropertyType(std::string(version)))));
+ EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
+ _, StrEq(PRESENT)))
+ .WillOnce(Return(any(PropertyType(true)))); // present
+
+ // The item updater itself
+ EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
+ .Times(1);
+
+ // activation and version object will be added
+ EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
+ .Times(2);
+ itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
+
+ // the activation and version object will be removed
+ Properties p{{PRESENT, PropertyType(false)}};
+ EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(objPath)))
+ .Times(2);
+ onPsuInventoryChanged(psuPath, p);
+
+ // on exit, item updater is removed
+ EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(dBusPath)))
+ .Times(1);
+}
+
+TEST_F(TestItemUpdater, OnOnePSUAdded)
+{
+ constexpr auto psuPath = "/com/example/inventory/psu0";
+ constexpr auto service = "com.example.Software.Psu";
+ constexpr auto version = "version0";
+ std::string objPath = getObjPath(version);
+ EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
+ .WillOnce(Return(std::vector<std::string>({psuPath})));
+ EXPECT_CALL(mockedUtils, getService(_, StrEq(psuPath), _))
+ .WillOnce(Return(service));
+ EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
+ _, StrEq(VERSION)))
+ .WillOnce(Return(any(PropertyType(std::string(version)))));
+ EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
+ _, StrEq(PRESENT)))
+ .WillOnce(Return(any(PropertyType(false)))); // not present
+
+ // The item updater itself
+ EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
+ .Times(1);
+
+ // No activation/version objects are created
+ EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
+ .Times(0);
+ itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
+
+ // The PSU is present and version is added in a single call
+ Properties propAdded{{PRESENT, PropertyType(true)},
+ {VERSION, PropertyType(std::string(version))}};
+ EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
+ .Times(2);
+ onPsuInventoryChanged(psuPath, propAdded);
+}
+
+TEST_F(TestItemUpdater, OnOnePSURemovedAndAdded)
+{
+ constexpr auto psuPath = "/com/example/inventory/psu0";
+ constexpr auto service = "com.example.Software.Psu";
+ constexpr auto version = "version0";
+ std::string objPath = getObjPath(version);
+ EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
+ .WillOnce(Return(std::vector<std::string>({psuPath})));
+ EXPECT_CALL(mockedUtils, getService(_, StrEq(psuPath), _))
+ .WillOnce(Return(service));
+ EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
+ _, StrEq(VERSION)))
+ .WillOnce(Return(any(PropertyType(std::string(version)))));
+ EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
+ _, StrEq(PRESENT)))
+ .WillOnce(Return(any(PropertyType(true)))); // present
+
+ // The item updater itself
+ EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
+ .Times(1);
+
+ // activation and version object will be added
+ EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
+ .Times(2);
+ itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
+
+ // the activation and version object will be removed
+ Properties propRemoved{{PRESENT, PropertyType(false)}};
+ EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(objPath)))
+ .Times(2);
+ onPsuInventoryChanged(psuPath, propRemoved);
+
+ Properties propAdded{{PRESENT, PropertyType(true)}};
+ Properties propVersion{{VERSION, PropertyType(std::string(version))}};
+ EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
+ .Times(2);
+ onPsuInventoryChanged(psuPath, propAdded);
+ onPsuInventoryChanged(psuPath, propVersion);
+
+ // on exit, objects are removed
+ EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(objPath)))
+ .Times(2);
+ EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(dBusPath)))
+ .Times(1);
+}
+
+TEST_F(TestItemUpdater,
+ TwoPSUsWithSameVersionRemovedAndAddedWithDifferntVersion)
+{
+ 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, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
+ StrEq(VERSION)))
+ .WillOnce(Return(any(PropertyType(version0))));
+ EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
+ StrEq(PRESENT)))
+ .WillOnce(Return(any(PropertyType(true)))); // present
+ EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
+ StrEq(VERSION)))
+ .WillOnce(Return(any(PropertyType(version1))));
+ EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
+ StrEq(PRESENT)))
+ .WillOnce(Return(any(PropertyType(true)))); // present
+
+ // The item updater itself
+ EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
+ .Times(1);
+
+ // activation and version object will be added
+ EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath0)))
+ .Times(2);
+ itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
+
+ // Verify there is only one activation and it has two associations
+ const auto& activations = GetActivations();
+ EXPECT_EQ(1u, activations.size());
+ const 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]));
+
+ // PSU0 is removed, only associations shall be updated
+ Properties propRemoved{{PRESENT, PropertyType(false)}};
+ onPsuInventoryChanged(psu0, propRemoved);
+ assocs = activation->associations();
+ EXPECT_EQ(1u, assocs.size());
+ EXPECT_EQ(psu1, std::get<2>(assocs[0]));
+
+ // PSU1 is removed, the activation and version object shall be removed
+ EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(objPath0)))
+ .Times(2);
+ onPsuInventoryChanged(psu1, propRemoved);
+
+ // Add PSU0 and PSU1 back, but PSU1 with a different version
+ version1 = "version1";
+ objPath1 = getObjPath(version1);
+ Properties propAdded0{{PRESENT, PropertyType(true)},
+ {VERSION, PropertyType(std::string(version0))}};
+ Properties propAdded1{{PRESENT, PropertyType(true)},
+ {VERSION, PropertyType(std::string(version1))}};
+ EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath0)))
+ .Times(2);
+ EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath1)))
+ .Times(2);
+ onPsuInventoryChanged(psu0, propAdded0);
+ onPsuInventoryChanged(psu1, propAdded1);
+
+ // on exit, objects are removed
+ EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(objPath0)))
+ .Times(2);
+ EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(objPath1)))
+ .Times(2);
+ EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(dBusPath)))
+ .Times(1);
+}