xref: /openbmc/phosphor-psu-code-mgmt/test/test_item_updater.cpp (revision b8590f56389a9dfd1af6ae4f722cc2fed46de918)
1f77189f7SLei YU #include "item_updater.hpp"
2f77189f7SLei YU #include "mocked_utils.hpp"
3f77189f7SLei YU 
4f77189f7SLei YU #include <sdbusplus/test/sdbus_mock.hpp>
5f77189f7SLei YU 
6f77189f7SLei YU #include <gmock/gmock.h>
7f77189f7SLei YU #include <gtest/gtest.h>
8f77189f7SLei YU 
9f77189f7SLei YU using namespace phosphor::software::updater;
10f77189f7SLei YU using ::testing::_;
111517f5f6SLei YU using ::testing::ContainerEq;
12*b8590f56SShawn McCarney using ::testing::NiceMock;
1358c26e3fSLei YU using ::testing::Pointee;
14f77189f7SLei YU using ::testing::Return;
15f77189f7SLei YU using ::testing::ReturnArg;
16f77189f7SLei YU using ::testing::StrEq;
17f77189f7SLei YU 
18b5f9b829SPatrick Williams using std::any;
19f77189f7SLei YU 
20f77189f7SLei YU class TestItemUpdater : public ::testing::Test
21f77189f7SLei YU {
22f77189f7SLei YU   public:
23a2c2cd72SLei YU     using Properties = ItemUpdater::Properties;
24a2c2cd72SLei YU     using PropertyType = utils::UtilsInterface::PropertyType;
25a2c2cd72SLei YU 
2666a54ad4SGeorge Liu     TestItemUpdater(const TestItemUpdater&) = delete;
2766a54ad4SGeorge Liu     TestItemUpdater& operator=(const TestItemUpdater&) = delete;
2866a54ad4SGeorge Liu     TestItemUpdater(TestItemUpdater&&) = delete;
2966a54ad4SGeorge Liu     TestItemUpdater& operator=(TestItemUpdater&&) = delete;
3066a54ad4SGeorge Liu 
TestItemUpdater()31f77189f7SLei YU     TestItemUpdater() :
32f77189f7SLei YU         mockedUtils(
33f77189f7SLei YU             reinterpret_cast<const utils::MockedUtils&>(utils::getUtils()))
34f77189f7SLei YU     {
35f77189f7SLei YU         ON_CALL(mockedUtils, getVersionId(_)).WillByDefault(ReturnArg<0>());
36ff83c2a0SLei YU         ON_CALL(mockedUtils, getPropertyImpl(_, _, _, _, StrEq(PRESENT)))
37ff83c2a0SLei YU             .WillByDefault(Return(any(PropertyType(true))));
38f77189f7SLei YU     }
39f77189f7SLei YU 
~TestItemUpdater()40047d9944SGeorge Liu     ~TestItemUpdater() override
41f77189f7SLei YU     {
42c09155bbSLei YU         utils::freeUtils();
43f77189f7SLei YU     }
44f77189f7SLei YU 
GetActivations() const4571ae535cSGeorge Liu     auto& GetActivations() const
46f77189f7SLei YU     {
47f77189f7SLei YU         return itemUpdater->activations;
48f77189f7SLei YU     }
49f77189f7SLei YU 
getObjPath(const std::string & versionId)5080c2daaeSGeorge Liu     static std::string getObjPath(const std::string& versionId)
51f77189f7SLei YU     {
52f77189f7SLei YU         return std::string(dBusPath) + "/" + versionId;
53f77189f7SLei YU     }
54f77189f7SLei YU 
onPsuInventoryChanged(const std::string & psuPath,const Properties & properties) const55a2c2cd72SLei YU     void onPsuInventoryChanged(const std::string& psuPath,
5671ae535cSGeorge Liu                                const Properties& properties) const
57a2c2cd72SLei YU     {
58a2c2cd72SLei YU         itemUpdater->onPsuInventoryChanged(psuPath, properties);
59a2c2cd72SLei YU     }
60a2c2cd72SLei YU 
scanDirectory(const fs::path & p) const6171ae535cSGeorge Liu     void scanDirectory(const fs::path& p) const
6258c26e3fSLei YU     {
6358c26e3fSLei YU         itemUpdater->scanDirectory(p);
6458c26e3fSLei YU     }
6558c26e3fSLei YU 
66f77189f7SLei YU     static constexpr auto dBusPath = SOFTWARE_OBJPATH;
67*b8590f56SShawn McCarney     NiceMock<sdbusplus::SdBusMock> sdbusMock;
68374fae56SPatrick Williams     sdbusplus::bus_t mockedBus = sdbusplus::get_mocked_new(&sdbusMock);
69f77189f7SLei YU     const utils::MockedUtils& mockedUtils;
70f77189f7SLei YU     std::unique_ptr<ItemUpdater> itemUpdater;
711517f5f6SLei YU     Properties propAdded{{PRESENT, PropertyType(true)}};
721517f5f6SLei YU     Properties propRemoved{{PRESENT, PropertyType(false)}};
73f77189f7SLei YU };
74f77189f7SLei YU 
TEST_F(TestItemUpdater,ctordtor)75f77189f7SLei YU TEST_F(TestItemUpdater, ctordtor)
76f77189f7SLei YU {
776520748dSLei YU     EXPECT_CALL(mockedUtils, getLatestVersion(_)).Times(1);
78f77189f7SLei YU     itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
79f77189f7SLei YU }
80f77189f7SLei YU 
TEST_F(TestItemUpdater,NotCreateObjectOnNotPresent)81f77189f7SLei YU TEST_F(TestItemUpdater, NotCreateObjectOnNotPresent)
82f77189f7SLei YU {
83f77189f7SLei YU     constexpr auto psuPath = "/com/example/inventory/psu0";
84f77189f7SLei YU     constexpr auto service = "com.example.Software.Psu";
85f77189f7SLei YU     constexpr auto version = "version0";
86f77189f7SLei YU     std::string objPath = getObjPath(version);
87d57bd2f2SShawn McCarney     EXPECT_CALL(mockedUtils, getPSUInventoryPaths(_))
88f77189f7SLei YU         .WillOnce(Return(std::vector<std::string>({psuPath})));
89f77189f7SLei YU     EXPECT_CALL(mockedUtils, getService(_, StrEq(psuPath), _))
90f77189f7SLei YU         .WillOnce(Return(service));
91f77189f7SLei YU     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
92f77189f7SLei YU                                              _, StrEq(PRESENT)))
93f77189f7SLei YU         .WillOnce(Return(any(PropertyType(false)))); // not present
94f77189f7SLei YU 
95f77189f7SLei YU     // The item updater itself
96f77189f7SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
97f77189f7SLei YU         .Times(1);
98f77189f7SLei YU 
99f77189f7SLei YU     // No activation/version objects are created
100f77189f7SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
101f77189f7SLei YU         .Times(0);
102f77189f7SLei YU     itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
103f77189f7SLei YU }
104f77189f7SLei YU 
TEST_F(TestItemUpdater,CreateOnePSUOnPresent)105f77189f7SLei YU TEST_F(TestItemUpdater, CreateOnePSUOnPresent)
106f77189f7SLei YU {
107f77189f7SLei YU     constexpr auto psuPath = "/com/example/inventory/psu0";
108f77189f7SLei YU     constexpr auto service = "com.example.Software.Psu";
109f77189f7SLei YU     constexpr auto version = "version0";
110f77189f7SLei YU     std::string objPath = getObjPath(version);
111d57bd2f2SShawn McCarney     EXPECT_CALL(mockedUtils, getPSUInventoryPaths(_))
112f77189f7SLei YU         .WillOnce(Return(std::vector<std::string>({psuPath})));
113f77189f7SLei YU     EXPECT_CALL(mockedUtils, getService(_, StrEq(psuPath), _))
114f77189f7SLei YU         .WillOnce(Return(service));
1155f3584d4SLei YU     EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
1165f3584d4SLei YU         .WillOnce(Return(std::string(version)));
117f77189f7SLei YU     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
118f77189f7SLei YU                                              _, StrEq(PRESENT)))
119f77189f7SLei YU         .WillOnce(Return(any(PropertyType(true)))); // present
120783406e6SShawn McCarney     EXPECT_CALL(mockedUtils, getModel(StrEq(psuPath)))
121783406e6SShawn McCarney         .WillOnce(Return(std::string("dummyModel")));
122f77189f7SLei YU 
123f77189f7SLei YU     // The item updater itself
124f77189f7SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
125f77189f7SLei YU         .Times(1);
126f77189f7SLei YU 
127f77189f7SLei YU     // activation and version object will be added
128f77189f7SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
129f77189f7SLei YU         .Times(2);
130f77189f7SLei YU     itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
131f77189f7SLei YU }
132f77189f7SLei YU 
TEST_F(TestItemUpdater,CreateTwoPSUsWithSameVersion)133f77189f7SLei YU TEST_F(TestItemUpdater, CreateTwoPSUsWithSameVersion)
134f77189f7SLei YU {
135f77189f7SLei YU     constexpr auto psu0 = "/com/example/inventory/psu0";
136f77189f7SLei YU     constexpr auto psu1 = "/com/example/inventory/psu1";
137f77189f7SLei YU     constexpr auto service = "com.example.Software.Psu";
138f77189f7SLei YU     auto version0 = std::string("version0");
139f77189f7SLei YU     auto version1 = std::string("version0");
140f77189f7SLei YU     auto objPath0 = getObjPath(version0);
141f77189f7SLei YU     auto objPath1 = getObjPath(version1);
142f77189f7SLei YU 
143d57bd2f2SShawn McCarney     EXPECT_CALL(mockedUtils, getPSUInventoryPaths(_))
144f77189f7SLei YU         .WillOnce(Return(std::vector<std::string>({psu0, psu1})));
145f77189f7SLei YU     EXPECT_CALL(mockedUtils, getService(_, StrEq(psu0), _))
146f77189f7SLei YU         .WillOnce(Return(service));
147f77189f7SLei YU     EXPECT_CALL(mockedUtils, getService(_, StrEq(psu1), _))
148f77189f7SLei YU         .WillOnce(Return(service));
1495f3584d4SLei YU     EXPECT_CALL(mockedUtils, getVersion(StrEq(psu0)))
1505f3584d4SLei YU         .WillOnce(Return(std::string(version0)));
151f77189f7SLei YU     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
152f77189f7SLei YU                                              StrEq(PRESENT)))
153f77189f7SLei YU         .WillOnce(Return(any(PropertyType(true)))); // present
154783406e6SShawn McCarney     EXPECT_CALL(mockedUtils, getModel(StrEq(psu0)))
155783406e6SShawn McCarney         .WillOnce(Return(std::string("dummyModel0")));
1565f3584d4SLei YU     EXPECT_CALL(mockedUtils, getVersion(StrEq(psu1)))
1575f3584d4SLei YU         .WillOnce(Return(std::string(version1)));
158f77189f7SLei YU     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
159f77189f7SLei YU                                              StrEq(PRESENT)))
160f77189f7SLei YU         .WillOnce(Return(any(PropertyType(true)))); // present
161783406e6SShawn McCarney     EXPECT_CALL(mockedUtils, getModel(StrEq(psu1)))
162783406e6SShawn McCarney         .WillOnce(Return(std::string("dummyModel1")));
163f77189f7SLei YU 
164f77189f7SLei YU     // The item updater itself
165f77189f7SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
166f77189f7SLei YU         .Times(1);
167f77189f7SLei YU 
168f77189f7SLei YU     // activation and version object will be added
169f77189f7SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath0)))
170f77189f7SLei YU         .Times(2);
171f77189f7SLei YU     itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
172f77189f7SLei YU 
173f77189f7SLei YU     // Verify there is only one activation and it has two associations
174f77189f7SLei YU     const auto& activations = GetActivations();
17522c2fbd8SGeorge Liu     EXPECT_EQ(1U, activations.size());
176f77189f7SLei YU     const auto& activation = activations.find(version0)->second;
177f77189f7SLei YU     const auto& assocs = activation->associations();
17822c2fbd8SGeorge Liu     EXPECT_EQ(2U, assocs.size());
179f77189f7SLei YU     EXPECT_EQ(psu0, std::get<2>(assocs[0]));
180f77189f7SLei YU     EXPECT_EQ(psu1, std::get<2>(assocs[1]));
181f77189f7SLei YU }
182f77189f7SLei YU 
TEST_F(TestItemUpdater,CreateTwoPSUsWithDifferentVersion)183f77189f7SLei YU TEST_F(TestItemUpdater, CreateTwoPSUsWithDifferentVersion)
184f77189f7SLei YU {
185f77189f7SLei YU     constexpr auto psu0 = "/com/example/inventory/psu0";
186f77189f7SLei YU     constexpr auto psu1 = "/com/example/inventory/psu1";
187f77189f7SLei YU     constexpr auto service = "com.example.Software.Psu";
188f77189f7SLei YU     auto version0 = std::string("version0");
189f77189f7SLei YU     auto version1 = std::string("version1");
190f77189f7SLei YU     auto objPath0 = getObjPath(version0);
191f77189f7SLei YU     auto objPath1 = getObjPath(version1);
192f77189f7SLei YU 
193d57bd2f2SShawn McCarney     EXPECT_CALL(mockedUtils, getPSUInventoryPaths(_))
194f77189f7SLei YU         .WillOnce(Return(std::vector<std::string>({psu0, psu1})));
195f77189f7SLei YU     EXPECT_CALL(mockedUtils, getService(_, StrEq(psu0), _))
196f77189f7SLei YU         .WillOnce(Return(service));
197f77189f7SLei YU     EXPECT_CALL(mockedUtils, getService(_, StrEq(psu1), _))
198f77189f7SLei YU         .WillOnce(Return(service));
1995f3584d4SLei YU     EXPECT_CALL(mockedUtils, getVersion(StrEq(psu0)))
2005f3584d4SLei YU         .WillOnce(Return(std::string(version0)));
201f77189f7SLei YU     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
202f77189f7SLei YU                                              StrEq(PRESENT)))
203f77189f7SLei YU         .WillOnce(Return(any(PropertyType(true)))); // present
204783406e6SShawn McCarney     EXPECT_CALL(mockedUtils, getModel(StrEq(psu0)))
205783406e6SShawn McCarney         .WillOnce(Return(std::string("dummyModel0")));
2065f3584d4SLei YU     EXPECT_CALL(mockedUtils, getVersion(StrEq(psu1)))
2075f3584d4SLei YU         .WillOnce(Return(std::string(version1)));
208f77189f7SLei YU     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
209f77189f7SLei YU                                              StrEq(PRESENT)))
210f77189f7SLei YU         .WillOnce(Return(any(PropertyType(true)))); // present
211783406e6SShawn McCarney     EXPECT_CALL(mockedUtils, getModel(StrEq(psu1)))
212783406e6SShawn McCarney         .WillOnce(Return(std::string("dummyModel1")));
213f77189f7SLei YU 
214f77189f7SLei YU     // The item updater itself
215f77189f7SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
216f77189f7SLei YU         .Times(1);
217f77189f7SLei YU 
218f77189f7SLei YU     // two new activation and version objects will be added
219f77189f7SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath0)))
220f77189f7SLei YU         .Times(2);
221f77189f7SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath1)))
222f77189f7SLei YU         .Times(2);
223f77189f7SLei YU     itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
224f77189f7SLei YU 
225f77189f7SLei YU     // Verify there are two activations and each with one association
226f77189f7SLei YU     const auto& activations = GetActivations();
22722c2fbd8SGeorge Liu     EXPECT_EQ(2U, activations.size());
228f77189f7SLei YU     const auto& activation0 = activations.find(version0)->second;
229f77189f7SLei YU     const auto& assocs0 = activation0->associations();
23022c2fbd8SGeorge Liu     EXPECT_EQ(1U, assocs0.size());
231f77189f7SLei YU     EXPECT_EQ(psu0, std::get<2>(assocs0[0]));
232f77189f7SLei YU 
233f77189f7SLei YU     const auto& activation1 = activations.find(version1)->second;
234f77189f7SLei YU     const auto& assocs1 = activation1->associations();
23522c2fbd8SGeorge Liu     EXPECT_EQ(1U, assocs1.size());
236f77189f7SLei YU     EXPECT_EQ(psu1, std::get<2>(assocs1[0]));
237f77189f7SLei YU }
238a2c2cd72SLei YU 
TEST_F(TestItemUpdater,OnOnePSURemoved)239a2c2cd72SLei YU TEST_F(TestItemUpdater, OnOnePSURemoved)
240a2c2cd72SLei YU {
241a2c2cd72SLei YU     constexpr auto psuPath = "/com/example/inventory/psu0";
242a2c2cd72SLei YU     constexpr auto service = "com.example.Software.Psu";
243a2c2cd72SLei YU     constexpr auto version = "version0";
244a2c2cd72SLei YU     std::string objPath = getObjPath(version);
245d57bd2f2SShawn McCarney     EXPECT_CALL(mockedUtils, getPSUInventoryPaths(_))
246a2c2cd72SLei YU         .WillOnce(Return(std::vector<std::string>({psuPath})));
247a2c2cd72SLei YU     EXPECT_CALL(mockedUtils, getService(_, StrEq(psuPath), _))
248a2c2cd72SLei YU         .WillOnce(Return(service));
2495f3584d4SLei YU     EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
2505f3584d4SLei YU         .WillOnce(Return(std::string(version)));
251a2c2cd72SLei YU     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
252a2c2cd72SLei YU                                              _, StrEq(PRESENT)))
253a2c2cd72SLei YU         .WillOnce(Return(any(PropertyType(true)))); // present
254783406e6SShawn McCarney     EXPECT_CALL(mockedUtils, getModel(StrEq(psuPath)))
255783406e6SShawn McCarney         .WillOnce(Return(std::string("dummyModel")));
256a2c2cd72SLei YU 
257a2c2cd72SLei YU     // The item updater itself
258a2c2cd72SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
259a2c2cd72SLei YU         .Times(1);
260a2c2cd72SLei YU 
261a2c2cd72SLei YU     // activation and version object will be added
262a2c2cd72SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
263a2c2cd72SLei YU         .Times(2);
264a2c2cd72SLei YU     itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
265a2c2cd72SLei YU 
266a2c2cd72SLei YU     // the activation and version object will be removed
267a2c2cd72SLei YU     Properties p{{PRESENT, PropertyType(false)}};
268a2c2cd72SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(objPath)))
269a2c2cd72SLei YU         .Times(2);
270a2c2cd72SLei YU     onPsuInventoryChanged(psuPath, p);
271a2c2cd72SLei YU 
272a2c2cd72SLei YU     // on exit, item updater is removed
273a2c2cd72SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(dBusPath)))
274a2c2cd72SLei YU         .Times(1);
275a2c2cd72SLei YU }
276a2c2cd72SLei YU 
TEST_F(TestItemUpdater,OnOnePSUAdded)277a2c2cd72SLei YU TEST_F(TestItemUpdater, OnOnePSUAdded)
278a2c2cd72SLei YU {
279a2c2cd72SLei YU     constexpr auto psuPath = "/com/example/inventory/psu0";
280a2c2cd72SLei YU     constexpr auto service = "com.example.Software.Psu";
281a2c2cd72SLei YU     constexpr auto version = "version0";
282a2c2cd72SLei YU     std::string objPath = getObjPath(version);
283d57bd2f2SShawn McCarney     EXPECT_CALL(mockedUtils, getPSUInventoryPaths(_))
284a2c2cd72SLei YU         .WillOnce(Return(std::vector<std::string>({psuPath})));
285a2c2cd72SLei YU     EXPECT_CALL(mockedUtils, getService(_, StrEq(psuPath), _))
286a2c2cd72SLei YU         .WillOnce(Return(service));
287a2c2cd72SLei YU     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
288a2c2cd72SLei YU                                              _, StrEq(PRESENT)))
289a2c2cd72SLei YU         .WillOnce(Return(any(PropertyType(false)))); // not present
290a2c2cd72SLei YU 
291a2c2cd72SLei YU     // The item updater itself
292a2c2cd72SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
293a2c2cd72SLei YU         .Times(1);
294a2c2cd72SLei YU 
295a2c2cd72SLei YU     // No activation/version objects are created
296a2c2cd72SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
297a2c2cd72SLei YU         .Times(0);
298a2c2cd72SLei YU     itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
299a2c2cd72SLei YU 
300a2c2cd72SLei YU     // The PSU is present and version is added in a single call
301783406e6SShawn McCarney     Properties propAdded{{PRESENT, PropertyType(true)}};
302dcaf8934SLei YU     EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
303dcaf8934SLei YU         .WillOnce(Return(std::string(version)));
304783406e6SShawn McCarney     EXPECT_CALL(mockedUtils, getModel(StrEq(psuPath)))
305783406e6SShawn McCarney         .WillOnce(Return(std::string("testModel")));
306a2c2cd72SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
307a2c2cd72SLei YU         .Times(2);
308783406e6SShawn McCarney     onPsuInventoryChanged(psuPath, propAdded);
309a2c2cd72SLei YU }
310a2c2cd72SLei YU 
TEST_F(TestItemUpdater,OnOnePSURemovedAndAddedWithLatestVersion)3111517f5f6SLei YU TEST_F(TestItemUpdater, OnOnePSURemovedAndAddedWithLatestVersion)
312a2c2cd72SLei YU {
313a2c2cd72SLei YU     constexpr auto psuPath = "/com/example/inventory/psu0";
314a2c2cd72SLei YU     constexpr auto service = "com.example.Software.Psu";
315a2c2cd72SLei YU     constexpr auto version = "version0";
316a2c2cd72SLei YU     std::string objPath = getObjPath(version);
317d57bd2f2SShawn McCarney     ON_CALL(mockedUtils, getPSUInventoryPaths(_))
3181517f5f6SLei YU         .WillByDefault(Return(std::vector<std::string>({psuPath})));
319a2c2cd72SLei YU     EXPECT_CALL(mockedUtils, getService(_, StrEq(psuPath), _))
320a2c2cd72SLei YU         .WillOnce(Return(service));
3215f3584d4SLei YU     EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
3225f3584d4SLei YU         .WillOnce(Return(std::string(version)));
323a2c2cd72SLei YU     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
324a2c2cd72SLei YU                                              _, StrEq(PRESENT)))
325a2c2cd72SLei YU         .WillOnce(Return(any(PropertyType(true)))); // present
326783406e6SShawn McCarney     EXPECT_CALL(mockedUtils, getModel(StrEq(psuPath)))
327783406e6SShawn McCarney         .WillOnce(Return(std::string("dummyModel")));
328a2c2cd72SLei YU 
329a2c2cd72SLei YU     // The item updater itself
330a2c2cd72SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
331a2c2cd72SLei YU         .Times(1);
332a2c2cd72SLei YU 
333a2c2cd72SLei YU     // activation and version object will be added
334a2c2cd72SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
335a2c2cd72SLei YU         .Times(2);
336a2c2cd72SLei YU     itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
337a2c2cd72SLei YU 
338a2c2cd72SLei YU     // the activation and version object will be removed
339a2c2cd72SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(objPath)))
340a2c2cd72SLei YU         .Times(2);
341a2c2cd72SLei YU     onPsuInventoryChanged(psuPath, propRemoved);
342a2c2cd72SLei YU 
343dcaf8934SLei YU     EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
344dcaf8934SLei YU         .WillOnce(Return(std::string(version)));
345783406e6SShawn McCarney     EXPECT_CALL(mockedUtils, getModel(StrEq(psuPath)))
346783406e6SShawn McCarney         .WillOnce(Return(std::string("dummyModel")));
347a2c2cd72SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
348a2c2cd72SLei YU         .Times(2);
3491517f5f6SLei YU 
3501517f5f6SLei YU     // On PSU inserted, it shall check if it's the latest version
3511517f5f6SLei YU     std::set<std::string> expectedVersions = {version};
3521517f5f6SLei YU     EXPECT_CALL(mockedUtils, getLatestVersion(ContainerEq(expectedVersions)))
3531517f5f6SLei YU         .WillOnce(Return(version));
3541517f5f6SLei YU     EXPECT_CALL(mockedUtils, isAssociated(StrEq(psuPath), _))
3551517f5f6SLei YU         .WillOnce(Return(true));
3561517f5f6SLei YU     EXPECT_CALL(sdbusMock, sd_bus_message_new_method_call(_, _, _, _, _,
3571517f5f6SLei YU                                                           StrEq("StartUnit")))
3581517f5f6SLei YU         .Times(0);
359a2c2cd72SLei YU     onPsuInventoryChanged(psuPath, propAdded);
360a2c2cd72SLei YU 
361a2c2cd72SLei YU     // on exit, objects are removed
362a2c2cd72SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(objPath)))
363a2c2cd72SLei YU         .Times(2);
364a2c2cd72SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(dBusPath)))
365a2c2cd72SLei YU         .Times(1);
366a2c2cd72SLei YU }
367a2c2cd72SLei YU 
TEST_F(TestItemUpdater,TwoPSUsWithSameVersionRemovedAndAddedWithDifferntVersion)368a2c2cd72SLei YU TEST_F(TestItemUpdater,
369a2c2cd72SLei YU        TwoPSUsWithSameVersionRemovedAndAddedWithDifferntVersion)
370a2c2cd72SLei YU {
371a2c2cd72SLei YU     constexpr auto psu0 = "/com/example/inventory/psu0";
372a2c2cd72SLei YU     constexpr auto psu1 = "/com/example/inventory/psu1";
373a2c2cd72SLei YU     constexpr auto service = "com.example.Software.Psu";
374a2c2cd72SLei YU     auto version0 = std::string("version0");
375a2c2cd72SLei YU     auto version1 = std::string("version0");
376a2c2cd72SLei YU     auto objPath0 = getObjPath(version0);
377a2c2cd72SLei YU     auto objPath1 = getObjPath(version1);
378a2c2cd72SLei YU 
379d57bd2f2SShawn McCarney     EXPECT_CALL(mockedUtils, getPSUInventoryPaths(_))
380a2c2cd72SLei YU         .WillOnce(Return(std::vector<std::string>({psu0, psu1})));
381a2c2cd72SLei YU     EXPECT_CALL(mockedUtils, getService(_, StrEq(psu0), _))
382a2c2cd72SLei YU         .WillOnce(Return(service));
383a2c2cd72SLei YU     EXPECT_CALL(mockedUtils, getService(_, StrEq(psu1), _))
384a2c2cd72SLei YU         .WillOnce(Return(service));
3855f3584d4SLei YU     EXPECT_CALL(mockedUtils, getVersion(StrEq(psu0)))
3865f3584d4SLei YU         .WillOnce(Return(std::string(version0)));
387a2c2cd72SLei YU     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
388a2c2cd72SLei YU                                              StrEq(PRESENT)))
389a2c2cd72SLei YU         .WillOnce(Return(any(PropertyType(true)))); // present
390783406e6SShawn McCarney     EXPECT_CALL(mockedUtils, getModel(StrEq(psu0)))
391783406e6SShawn McCarney         .WillOnce(Return(std::string("dummyModel0")));
3925f3584d4SLei YU     EXPECT_CALL(mockedUtils, getVersion(StrEq(psu1)))
3935f3584d4SLei YU         .WillOnce(Return(std::string(version1)));
394a2c2cd72SLei YU     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
395a2c2cd72SLei YU                                              StrEq(PRESENT)))
396a2c2cd72SLei YU         .WillOnce(Return(any(PropertyType(true)))); // present
397783406e6SShawn McCarney     EXPECT_CALL(mockedUtils, getModel(StrEq(psu1)))
398783406e6SShawn McCarney         .WillOnce(Return(std::string("dummyModel1")));
399a2c2cd72SLei YU 
400a2c2cd72SLei YU     // The item updater itself
401a2c2cd72SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
402a2c2cd72SLei YU         .Times(1);
403a2c2cd72SLei YU 
404a2c2cd72SLei YU     // activation and version object will be added
405a2c2cd72SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath0)))
406a2c2cd72SLei YU         .Times(2);
407a2c2cd72SLei YU     itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
408a2c2cd72SLei YU 
409a2c2cd72SLei YU     // Verify there is only one activation and it has two associations
410a2c2cd72SLei YU     const auto& activations = GetActivations();
41122c2fbd8SGeorge Liu     EXPECT_EQ(1U, activations.size());
412a2c2cd72SLei YU     const auto& activation = activations.find(version0)->second;
413a2c2cd72SLei YU     auto assocs = activation->associations();
41422c2fbd8SGeorge Liu     EXPECT_EQ(2U, assocs.size());
415a2c2cd72SLei YU     EXPECT_EQ(psu0, std::get<2>(assocs[0]));
416a2c2cd72SLei YU     EXPECT_EQ(psu1, std::get<2>(assocs[1]));
417a2c2cd72SLei YU 
418a2c2cd72SLei YU     // PSU0 is removed, only associations shall be updated
419a2c2cd72SLei YU     onPsuInventoryChanged(psu0, propRemoved);
420a2c2cd72SLei YU     assocs = activation->associations();
42122c2fbd8SGeorge Liu     EXPECT_EQ(1U, assocs.size());
422a2c2cd72SLei YU     EXPECT_EQ(psu1, std::get<2>(assocs[0]));
423a2c2cd72SLei YU 
424a2c2cd72SLei YU     // PSU1 is removed, the activation and version object shall be removed
425a2c2cd72SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(objPath0)))
426a2c2cd72SLei YU         .Times(2);
427a2c2cd72SLei YU     onPsuInventoryChanged(psu1, propRemoved);
428a2c2cd72SLei YU 
429a2c2cd72SLei YU     // Add PSU0 and PSU1 back, but PSU1 with a different version
430a2c2cd72SLei YU     version1 = "version1";
431a2c2cd72SLei YU     objPath1 = getObjPath(version1);
432dcaf8934SLei YU     EXPECT_CALL(mockedUtils, getVersion(StrEq(psu0)))
433dcaf8934SLei YU         .WillOnce(Return(std::string(version0)));
434783406e6SShawn McCarney     EXPECT_CALL(mockedUtils, getModel(StrEq(psu0)))
435783406e6SShawn McCarney         .WillOnce(Return(std::string("dummyModel0")));
436dcaf8934SLei YU     EXPECT_CALL(mockedUtils, getVersion(StrEq(psu1)))
437dcaf8934SLei YU         .WillOnce(Return(std::string(version1)));
438783406e6SShawn McCarney     EXPECT_CALL(mockedUtils, getModel(StrEq(psu1)))
439783406e6SShawn McCarney         .WillOnce(Return(std::string("dummyModel1")));
440a2c2cd72SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath0)))
441a2c2cd72SLei YU         .Times(2);
442a2c2cd72SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath1)))
443a2c2cd72SLei YU         .Times(2);
4441517f5f6SLei YU     onPsuInventoryChanged(psu0, propAdded);
4451517f5f6SLei YU     onPsuInventoryChanged(psu1, propAdded);
446a2c2cd72SLei YU 
447a2c2cd72SLei YU     // on exit, objects are removed
448a2c2cd72SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(objPath0)))
449a2c2cd72SLei YU         .Times(2);
450a2c2cd72SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(objPath1)))
451a2c2cd72SLei YU         .Times(2);
452a2c2cd72SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(dBusPath)))
453a2c2cd72SLei YU         .Times(1);
454a2c2cd72SLei YU }
45558c26e3fSLei YU 
TEST_F(TestItemUpdater,scanDirOnNoPSU)45658c26e3fSLei YU TEST_F(TestItemUpdater, scanDirOnNoPSU)
45758c26e3fSLei YU {
45858c26e3fSLei YU     constexpr auto psuPath = "/com/example/inventory/psu0";
45958c26e3fSLei YU     constexpr auto service = "com.example.Software.Psu";
46058c26e3fSLei YU     constexpr auto version = "version0";
46158c26e3fSLei YU     std::string objPath = getObjPath(version);
462d57bd2f2SShawn McCarney     EXPECT_CALL(mockedUtils, getPSUInventoryPaths(_))
46358c26e3fSLei YU         .WillOnce(Return(std::vector<std::string>({psuPath})));
46458c26e3fSLei YU     EXPECT_CALL(mockedUtils, getService(_, StrEq(psuPath), _))
46558c26e3fSLei YU         .WillOnce(Return(service));
46658c26e3fSLei YU     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
46758c26e3fSLei YU                                              _, StrEq(PRESENT)))
46858c26e3fSLei YU         .WillOnce(Return(any(PropertyType(false)))); // not present
46958c26e3fSLei YU 
47058c26e3fSLei YU     // The item updater itself
47158c26e3fSLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
47258c26e3fSLei YU         .Times(1);
47358c26e3fSLei YU 
47458c26e3fSLei YU     // No activation/version objects are created
47558c26e3fSLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
47658c26e3fSLei YU         .Times(0);
47758c26e3fSLei YU     itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
47858c26e3fSLei YU 
47958c26e3fSLei YU     // The valid image in test/psu-images-one-valid-one-invalid/model-1/
48058c26e3fSLei YU     auto objPathValid = getObjPath("psu-test.v0.4");
48158c26e3fSLei YU     auto objPathInvalid = getObjPath("psu-test.v0.5");
482487e2e19SShawn McCarney     // No activation or version objects will be added on scan dir
48358c26e3fSLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPathValid)))
484760053d8SFaisal Awada         .Times(0);
48558c26e3fSLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPathInvalid)))
48658c26e3fSLei YU         .Times(0);
48758c26e3fSLei YU     scanDirectory("./psu-images-one-valid-one-invalid");
48858c26e3fSLei YU }
48958c26e3fSLei YU 
TEST_F(TestItemUpdater,scanDirOnSamePSUVersion)49058c26e3fSLei YU TEST_F(TestItemUpdater, scanDirOnSamePSUVersion)
49158c26e3fSLei YU {
49258c26e3fSLei YU     constexpr auto psuPath = "/com/example/inventory/psu0";
49358c26e3fSLei YU     constexpr auto service = "com.example.Software.Psu";
49458c26e3fSLei YU     constexpr auto version = "version0";
49558c26e3fSLei YU     std::string objPath = getObjPath(version);
496d57bd2f2SShawn McCarney     EXPECT_CALL(mockedUtils, getPSUInventoryPaths(_))
49758c26e3fSLei YU         .WillOnce(Return(std::vector<std::string>({psuPath})));
49858c26e3fSLei YU     EXPECT_CALL(mockedUtils, getService(_, StrEq(psuPath), _))
49958c26e3fSLei YU         .WillOnce(Return(service));
50058c26e3fSLei YU     EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
50158c26e3fSLei YU         .WillOnce(Return(std::string(version)));
50258c26e3fSLei YU     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
50358c26e3fSLei YU                                              _, StrEq(PRESENT)))
50458c26e3fSLei YU         .WillOnce(Return(any(PropertyType(true)))); // present
505783406e6SShawn McCarney     EXPECT_CALL(mockedUtils, getModel(StrEq(psuPath)))
506487e2e19SShawn McCarney         .WillOnce(Return(std::string("model-3")));
50758c26e3fSLei YU 
50858c26e3fSLei YU     // The item updater itself
50958c26e3fSLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
51058c26e3fSLei YU         .Times(1);
51158c26e3fSLei YU 
51258c26e3fSLei YU     // activation and version object will be added
51358c26e3fSLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
51458c26e3fSLei YU         .Times(2);
51558c26e3fSLei YU     itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
51658c26e3fSLei YU 
51758c26e3fSLei YU     // The valid image in test/psu-images-valid-version0/model-3/ has the same
51817c2c94eSShawn McCarney     // version as the running PSU, so no objects will be created. However, the
51917c2c94eSShawn McCarney     // Path and ExtendedVersion properties will be set on the Activation object.
52058c26e3fSLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
52158c26e3fSLei YU         .Times(0);
52258c26e3fSLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_properties_changed_strv(
52358c26e3fSLei YU                                _, StrEq(objPath),
52458c26e3fSLei YU                                StrEq("xyz.openbmc_project.Common.FilePath"),
52558c26e3fSLei YU                                Pointee(StrEq("Path"))))
526487e2e19SShawn McCarney         .Times(1);
52717c2c94eSShawn McCarney     EXPECT_CALL(sdbusMock,
52817c2c94eSShawn McCarney                 sd_bus_emit_properties_changed_strv(
52917c2c94eSShawn McCarney                     _, StrEq(objPath),
53017c2c94eSShawn McCarney                     StrEq("xyz.openbmc_project.Software.ExtendedVersion"),
53117c2c94eSShawn McCarney                     Pointee(StrEq("ExtendedVersion"))))
53217c2c94eSShawn McCarney         .Times(1);
53358c26e3fSLei YU     scanDirectory("./psu-images-valid-version0");
53458c26e3fSLei YU }
535ffb36539SLei YU 
TEST_F(TestItemUpdater,OnUpdateDoneOnTwoPSUsWithSameVersion)536ffb36539SLei YU TEST_F(TestItemUpdater, OnUpdateDoneOnTwoPSUsWithSameVersion)
537ffb36539SLei YU {
538ffb36539SLei YU     // Simulate there are two PSUs with same version, and updated to a new
539ffb36539SLei YU     // version
540ffb36539SLei YU     constexpr auto psu0 = "/com/example/inventory/psu0";
541ffb36539SLei YU     constexpr auto psu1 = "/com/example/inventory/psu1";
542ffb36539SLei YU     constexpr auto service = "com.example.Software.Psu";
543ffb36539SLei YU     auto version0 = std::string("version0");
544ffb36539SLei YU     auto version1 = std::string("version0");
545ffb36539SLei YU     auto objPath0 = getObjPath(version0);
546ffb36539SLei YU     auto objPath1 = getObjPath(version1);
547ffb36539SLei YU 
548d57bd2f2SShawn McCarney     EXPECT_CALL(mockedUtils, getPSUInventoryPaths(_))
549ffb36539SLei YU         .WillOnce(Return(std::vector<std::string>({psu0, psu1})));
550ffb36539SLei YU     EXPECT_CALL(mockedUtils, getService(_, StrEq(psu0), _))
551ffb36539SLei YU         .WillOnce(Return(service));
552ffb36539SLei YU     EXPECT_CALL(mockedUtils, getService(_, StrEq(psu1), _))
553ffb36539SLei YU         .WillOnce(Return(service));
554ffb36539SLei YU     EXPECT_CALL(mockedUtils, getVersion(StrEq(psu0)))
555ffb36539SLei YU         .WillOnce(Return(std::string(version0)));
556ffb36539SLei YU     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
557ffb36539SLei YU                                              StrEq(PRESENT)))
558ffb36539SLei YU         .WillOnce(Return(any(PropertyType(true)))); // present
559783406e6SShawn McCarney     EXPECT_CALL(mockedUtils, getModel(StrEq(psu0)))
560783406e6SShawn McCarney         .WillOnce(Return(std::string("dummyModel0")));
561ffb36539SLei YU     EXPECT_CALL(mockedUtils, getVersion(StrEq(psu1)))
562ffb36539SLei YU         .WillOnce(Return(std::string(version1)));
563ffb36539SLei YU     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
564ffb36539SLei YU                                              StrEq(PRESENT)))
565ffb36539SLei YU         .WillOnce(Return(any(PropertyType(true)))); // present
566783406e6SShawn McCarney     EXPECT_CALL(mockedUtils, getModel(StrEq(psu1)))
567783406e6SShawn McCarney         .WillOnce(Return(std::string("dummyModel1")));
568ffb36539SLei YU 
569ffb36539SLei YU     itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
570ffb36539SLei YU 
5711517f5f6SLei YU     std::string newVersionId = "NewVersionId";
5721517f5f6SLei YU     AssociationList associations;
5731517f5f6SLei YU     auto dummyActivation = std::make_unique<Activation>(
5741517f5f6SLei YU         mockedBus, dBusPath, newVersionId, "", Activation::Status::Active,
5751517f5f6SLei YU         associations, "", itemUpdater.get(), itemUpdater.get());
5761517f5f6SLei YU 
577ffb36539SLei YU     // Now there is one activation and it has two associations
578ffb36539SLei YU     auto& activations = GetActivations();
5791517f5f6SLei YU     activations.emplace(newVersionId, std::move(dummyActivation));
580ffb36539SLei YU     auto& activation = activations.find(version0)->second;
581ffb36539SLei YU     auto assocs = activation->associations();
58222c2fbd8SGeorge Liu     EXPECT_EQ(2U, assocs.size());
583ffb36539SLei YU     EXPECT_EQ(psu0, std::get<2>(assocs[0]));
584ffb36539SLei YU     EXPECT_EQ(psu1, std::get<2>(assocs[1]));
585ffb36539SLei YU 
586ffb36539SLei YU     EXPECT_CALL(mockedUtils, isAssociated(StrEq(psu0), _))
587ffb36539SLei YU         .WillOnce(Return(true));
5881517f5f6SLei YU     itemUpdater->onUpdateDone(newVersionId, psu0);
589ffb36539SLei YU 
59033cf9f08SManojkiran Eda     // Now the activation should have one association
591ffb36539SLei YU     assocs = activation->associations();
59222c2fbd8SGeorge Liu     EXPECT_EQ(1U, assocs.size());
593ffb36539SLei YU     EXPECT_EQ(psu1, std::get<2>(assocs[0]));
594ffb36539SLei YU 
595ffb36539SLei YU     EXPECT_CALL(mockedUtils, isAssociated(StrEq(psu1), _))
596ffb36539SLei YU         .WillOnce(Return(true));
5971517f5f6SLei YU     itemUpdater->onUpdateDone(newVersionId, psu1);
598ffb36539SLei YU 
5991517f5f6SLei YU     // Now the activation shall be erased and only the dummy one is left
60022c2fbd8SGeorge Liu     EXPECT_EQ(1U, activations.size());
6011517f5f6SLei YU     EXPECT_NE(activations.find(newVersionId), activations.end());
602ffb36539SLei YU }
603ffb36539SLei YU 
TEST_F(TestItemUpdater,OnUpdateDoneOnTwoPSUsWithDifferentVersion)604ffb36539SLei YU TEST_F(TestItemUpdater, OnUpdateDoneOnTwoPSUsWithDifferentVersion)
605ffb36539SLei YU {
606ffb36539SLei YU     // Simulate there are two PSUs with different version, and updated to a new
607ffb36539SLei YU     // version
608ffb36539SLei YU     constexpr auto psu0 = "/com/example/inventory/psu0";
609ffb36539SLei YU     constexpr auto psu1 = "/com/example/inventory/psu1";
610ffb36539SLei YU     constexpr auto service = "com.example.Software.Psu";
611ffb36539SLei YU     auto version0 = std::string("version0");
612ffb36539SLei YU     auto version1 = std::string("version1");
613ffb36539SLei YU     auto objPath0 = getObjPath(version0);
614ffb36539SLei YU     auto objPath1 = getObjPath(version1);
615ffb36539SLei YU 
616d57bd2f2SShawn McCarney     EXPECT_CALL(mockedUtils, getPSUInventoryPaths(_))
617ffb36539SLei YU         .WillOnce(Return(std::vector<std::string>({psu0, psu1})));
618ffb36539SLei YU     EXPECT_CALL(mockedUtils, getService(_, StrEq(psu0), _))
619ffb36539SLei YU         .WillOnce(Return(service));
620ffb36539SLei YU     EXPECT_CALL(mockedUtils, getService(_, StrEq(psu1), _))
621ffb36539SLei YU         .WillOnce(Return(service));
622ffb36539SLei YU     EXPECT_CALL(mockedUtils, getVersion(StrEq(psu0)))
623ffb36539SLei YU         .WillOnce(Return(std::string(version0)));
624ffb36539SLei YU     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
625ffb36539SLei YU                                              StrEq(PRESENT)))
626ffb36539SLei YU         .WillOnce(Return(any(PropertyType(true)))); // present
627783406e6SShawn McCarney     EXPECT_CALL(mockedUtils, getModel(StrEq(psu0)))
628783406e6SShawn McCarney         .WillOnce(Return(std::string("dummyModel0")));
629ffb36539SLei YU     EXPECT_CALL(mockedUtils, getVersion(StrEq(psu1)))
630ffb36539SLei YU         .WillOnce(Return(std::string(version1)));
631ffb36539SLei YU     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
632ffb36539SLei YU                                              StrEq(PRESENT)))
633ffb36539SLei YU         .WillOnce(Return(any(PropertyType(true)))); // present
634783406e6SShawn McCarney     EXPECT_CALL(mockedUtils, getModel(StrEq(psu1)))
635783406e6SShawn McCarney         .WillOnce(Return(std::string("dummyModel1")));
636ffb36539SLei YU 
637ffb36539SLei YU     itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
638ffb36539SLei YU 
6391517f5f6SLei YU     std::string newVersionId = "NewVersionId";
6401517f5f6SLei YU     AssociationList associations;
6411517f5f6SLei YU     auto dummyActivation = std::make_unique<Activation>(
6421517f5f6SLei YU         mockedBus, dBusPath, newVersionId, "", Activation::Status::Active,
6431517f5f6SLei YU         associations, "", itemUpdater.get(), itemUpdater.get());
6441517f5f6SLei YU 
6451517f5f6SLei YU     auto& activations = GetActivations();
6461517f5f6SLei YU     activations.emplace(newVersionId, std::move(dummyActivation));
647ffb36539SLei YU 
648ffb36539SLei YU     EXPECT_CALL(mockedUtils, isAssociated(StrEq(psu0), _))
649ffb36539SLei YU         .WillOnce(Return(true));
6501517f5f6SLei YU 
6511517f5f6SLei YU     // After psu0 is done, two activations should be left
6521517f5f6SLei YU     itemUpdater->onUpdateDone(newVersionId, psu0);
65322c2fbd8SGeorge Liu     EXPECT_EQ(2U, activations.size());
654ffb36539SLei YU     const auto& activation1 = activations.find(version1)->second;
655ffb36539SLei YU     const auto& assocs1 = activation1->associations();
65622c2fbd8SGeorge Liu     EXPECT_EQ(1U, assocs1.size());
657ffb36539SLei YU     EXPECT_EQ(psu1, std::get<2>(assocs1[0]));
658ffb36539SLei YU 
659ffb36539SLei YU     EXPECT_CALL(mockedUtils, isAssociated(StrEq(psu1), _))
660ffb36539SLei YU         .WillOnce(Return(true));
6611517f5f6SLei YU     // After psu1 is done, only the dummy activation should be left
6621517f5f6SLei YU     itemUpdater->onUpdateDone(newVersionId, psu1);
66322c2fbd8SGeorge Liu     EXPECT_EQ(1U, activations.size());
6641517f5f6SLei YU     EXPECT_NE(activations.find(newVersionId), activations.end());
6651517f5f6SLei YU }
6661517f5f6SLei YU 
TEST_F(TestItemUpdater,OnOnePSURemovedAndAddedWithOldVersion)6671517f5f6SLei YU TEST_F(TestItemUpdater, OnOnePSURemovedAndAddedWithOldVersion)
6681517f5f6SLei YU {
6691517f5f6SLei YU     constexpr auto psuPath = "/com/example/inventory/psu0";
6701517f5f6SLei YU     constexpr auto service = "com.example.Software.Psu";
6711517f5f6SLei YU     constexpr auto version = "version0";
6721517f5f6SLei YU     std::string versionId =
6731517f5f6SLei YU         version; // In testing versionId is the same as version
6741517f5f6SLei YU     std::string objPath = getObjPath(version);
675d57bd2f2SShawn McCarney     ON_CALL(mockedUtils, getPSUInventoryPaths(_))
6761517f5f6SLei YU         .WillByDefault(Return(std::vector<std::string>({psuPath})));
677760053d8SFaisal Awada     EXPECT_CALL(mockedUtils, getService(_, StrEq(psuPath), _))
678760053d8SFaisal Awada         .WillOnce(Return(service));
6791517f5f6SLei YU     EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
6801517f5f6SLei YU         .WillOnce(Return(std::string(version)));
68146ea388cSShawn McCarney     EXPECT_CALL(mockedUtils,
68246ea388cSShawn McCarney                 getPropertyImpl(_, StrEq(service), StrEq(psuPath), _,
6831517f5f6SLei YU                                 StrEq(PRESENT)))
68446ea388cSShawn McCarney         .WillOnce(Return(any(PropertyType(true)))); // present
685783406e6SShawn McCarney     EXPECT_CALL(mockedUtils, getModel(StrEq(psuPath)))
686783406e6SShawn McCarney         .WillOnce(Return(std::string("dummyModel")));
687783406e6SShawn McCarney 
6881517f5f6SLei YU     itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
6891517f5f6SLei YU 
6901517f5f6SLei YU     // Add an association to simulate that it has image in BMC filesystem
6911517f5f6SLei YU     auto& activation = GetActivations().find(versionId)->second;
6921517f5f6SLei YU     auto assocs = activation->associations();
6931517f5f6SLei YU     assocs.emplace_back(ACTIVATION_FWD_ASSOCIATION, ACTIVATION_REV_ASSOCIATION,
6941517f5f6SLei YU                         "SomePath");
6951517f5f6SLei YU     activation->associations(assocs);
6961517f5f6SLei YU     activation->path("SomeFilePath");
6971517f5f6SLei YU 
6981517f5f6SLei YU     onPsuInventoryChanged(psuPath, propRemoved);
6991517f5f6SLei YU 
7001517f5f6SLei YU     // On PSU inserted, it checks and finds a newer version
7011517f5f6SLei YU     auto oldVersion = "old-version";
70246ea388cSShawn McCarney     EXPECT_CALL(mockedUtils, getService(_, StrEq(psuPath), _))
70346ea388cSShawn McCarney         .WillOnce(Return(service))
70446ea388cSShawn McCarney         .WillOnce(Return(service));
70546ea388cSShawn McCarney     EXPECT_CALL(mockedUtils,
70646ea388cSShawn McCarney                 getPropertyImpl(_, StrEq(service), StrEq(psuPath), _,
70746ea388cSShawn McCarney                                 StrEq(PRESENT)))
70846ea388cSShawn McCarney         .WillOnce(Return(any(PropertyType(true)))); // present
7091517f5f6SLei YU     EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
7101517f5f6SLei YU         .WillOnce(Return(std::string(oldVersion)));
7111517f5f6SLei YU     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
7121517f5f6SLei YU                                              _, StrEq(MANUFACTURER)))
7131517f5f6SLei YU         .WillOnce(
7141517f5f6SLei YU             Return(any(PropertyType(std::string(""))))); // Checking compatible
715783406e6SShawn McCarney     EXPECT_CALL(mockedUtils, getModel(StrEq(psuPath)))
716783406e6SShawn McCarney         .WillOnce(Return(std::string("")))
717783406e6SShawn McCarney         .WillOnce(Return(std::string("")));
7181517f5f6SLei YU     std::set<std::string> expectedVersions = {version, oldVersion};
7191517f5f6SLei YU     EXPECT_CALL(mockedUtils, getLatestVersion(ContainerEq(expectedVersions)))
7201517f5f6SLei YU         .WillOnce(Return(version));
7211517f5f6SLei YU     ON_CALL(mockedUtils, isAssociated(StrEq(psuPath), _))
7221517f5f6SLei YU         .WillByDefault(Return(false));
7231517f5f6SLei YU     EXPECT_CALL(sdbusMock, sd_bus_message_new_method_call(_, _, _, _, _,
7241517f5f6SLei YU                                                           StrEq("StartUnit")))
7258afeee56SLei YU         .Times(3); // There are 3 systemd units are started, enable bmc reboot
7268afeee56SLei YU                    // guard, start activation, and disable bmc reboot guard
7271517f5f6SLei YU     onPsuInventoryChanged(psuPath, propAdded);
728ffb36539SLei YU }
729