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;
1258c26e3fSLei YU using ::testing::Pointee;
13f77189f7SLei YU using ::testing::Return;
14f77189f7SLei YU using ::testing::ReturnArg;
15f77189f7SLei YU using ::testing::StrEq;
16f77189f7SLei YU 
17b5f9b829SPatrick Williams using std::any;
18f77189f7SLei YU 
19f77189f7SLei YU class TestItemUpdater : public ::testing::Test
20f77189f7SLei YU {
21f77189f7SLei YU   public:
22a2c2cd72SLei YU     using Properties = ItemUpdater::Properties;
23a2c2cd72SLei YU     using PropertyType = utils::UtilsInterface::PropertyType;
24a2c2cd72SLei YU 
TestItemUpdater()25f77189f7SLei YU     TestItemUpdater() :
26f77189f7SLei YU         mockedUtils(
27f77189f7SLei YU             reinterpret_cast<const utils::MockedUtils&>(utils::getUtils()))
28f77189f7SLei YU     {
29f77189f7SLei YU         ON_CALL(mockedUtils, getVersionId(_)).WillByDefault(ReturnArg<0>());
30ff83c2a0SLei YU         ON_CALL(mockedUtils, getPropertyImpl(_, _, _, _, StrEq(PRESENT)))
31ff83c2a0SLei YU             .WillByDefault(Return(any(PropertyType(true))));
32f77189f7SLei YU     }
33f77189f7SLei YU 
~TestItemUpdater()34f77189f7SLei YU     ~TestItemUpdater()
35f77189f7SLei YU     {
36c09155bbSLei YU         utils::freeUtils();
37f77189f7SLei YU     }
38f77189f7SLei YU 
GetActivations()391517f5f6SLei YU     auto& GetActivations()
40f77189f7SLei YU     {
41f77189f7SLei YU         return itemUpdater->activations;
42f77189f7SLei YU     }
43f77189f7SLei YU 
getObjPath(const std::string & versionId)44f77189f7SLei YU     std::string getObjPath(const std::string& versionId)
45f77189f7SLei YU     {
46f77189f7SLei YU         return std::string(dBusPath) + "/" + versionId;
47f77189f7SLei YU     }
48f77189f7SLei YU 
onPsuInventoryChanged(const std::string & psuPath,const Properties & properties)49a2c2cd72SLei YU     void onPsuInventoryChanged(const std::string& psuPath,
50a2c2cd72SLei YU                                const Properties& properties)
51a2c2cd72SLei YU     {
52a2c2cd72SLei YU         itemUpdater->onPsuInventoryChanged(psuPath, properties);
53a2c2cd72SLei YU     }
54a2c2cd72SLei YU 
scanDirectory(const fs::path & p)5558c26e3fSLei YU     void scanDirectory(const fs::path& p)
5658c26e3fSLei YU     {
5758c26e3fSLei YU         itemUpdater->scanDirectory(p);
5858c26e3fSLei YU     }
5958c26e3fSLei YU 
60f77189f7SLei YU     static constexpr auto dBusPath = SOFTWARE_OBJPATH;
61f77189f7SLei YU     sdbusplus::SdBusMock sdbusMock;
62374fae56SPatrick Williams     sdbusplus::bus_t mockedBus = sdbusplus::get_mocked_new(&sdbusMock);
63f77189f7SLei YU     const utils::MockedUtils& mockedUtils;
64f77189f7SLei YU     std::unique_ptr<ItemUpdater> itemUpdater;
651517f5f6SLei YU     Properties propAdded{{PRESENT, PropertyType(true)}};
661517f5f6SLei YU     Properties propRemoved{{PRESENT, PropertyType(false)}};
671517f5f6SLei YU     Properties propModel{{MODEL, PropertyType(std::string("dummyModel"))}};
68f77189f7SLei YU };
69f77189f7SLei YU 
TEST_F(TestItemUpdater,ctordtor)70f77189f7SLei YU TEST_F(TestItemUpdater, ctordtor)
71f77189f7SLei YU {
726520748dSLei YU     EXPECT_CALL(mockedUtils, getLatestVersion(_)).Times(1);
73f77189f7SLei YU     itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
74f77189f7SLei YU }
75f77189f7SLei YU 
TEST_F(TestItemUpdater,NotCreateObjectOnNotPresent)76f77189f7SLei YU TEST_F(TestItemUpdater, NotCreateObjectOnNotPresent)
77f77189f7SLei YU {
78f77189f7SLei YU     constexpr auto psuPath = "/com/example/inventory/psu0";
79f77189f7SLei YU     constexpr auto service = "com.example.Software.Psu";
80f77189f7SLei YU     constexpr auto version = "version0";
81f77189f7SLei YU     std::string objPath = getObjPath(version);
82f77189f7SLei YU     EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
83f77189f7SLei YU         .WillOnce(Return(std::vector<std::string>({psuPath})));
84f77189f7SLei YU     EXPECT_CALL(mockedUtils, getService(_, StrEq(psuPath), _))
85f77189f7SLei YU         .WillOnce(Return(service));
865f3584d4SLei YU     EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
875f3584d4SLei YU         .WillOnce(Return(std::string(version)));
88f77189f7SLei YU     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
89f77189f7SLei YU                                              _, StrEq(PRESENT)))
90f77189f7SLei YU         .WillOnce(Return(any(PropertyType(false)))); // not present
91*760053d8SFaisal Awada     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
92*760053d8SFaisal Awada                                              _, StrEq(MODEL)))
93*760053d8SFaisal Awada         .WillOnce(Return(any(PropertyType(std::string("")))));
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);
111f77189f7SLei YU     EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
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
120*760053d8SFaisal Awada     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
121*760053d8SFaisal Awada                                              _, StrEq(MODEL)))
122*760053d8SFaisal Awada         .WillOnce(Return(any(PropertyType(std::string("dummyModel")))));
123f77189f7SLei YU 
124f77189f7SLei YU     // The item updater itself
125f77189f7SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
126f77189f7SLei YU         .Times(1);
127f77189f7SLei YU 
128f77189f7SLei YU     // activation and version object will be added
129f77189f7SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
130f77189f7SLei YU         .Times(2);
131f77189f7SLei YU     itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
132f77189f7SLei YU }
133f77189f7SLei YU 
TEST_F(TestItemUpdater,CreateTwoPSUsWithSameVersion)134f77189f7SLei YU TEST_F(TestItemUpdater, CreateTwoPSUsWithSameVersion)
135f77189f7SLei YU {
136f77189f7SLei YU     constexpr auto psu0 = "/com/example/inventory/psu0";
137f77189f7SLei YU     constexpr auto psu1 = "/com/example/inventory/psu1";
138f77189f7SLei YU     constexpr auto service = "com.example.Software.Psu";
139f77189f7SLei YU     auto version0 = std::string("version0");
140f77189f7SLei YU     auto version1 = std::string("version0");
141f77189f7SLei YU     auto objPath0 = getObjPath(version0);
142f77189f7SLei YU     auto objPath1 = getObjPath(version1);
143f77189f7SLei YU 
144f77189f7SLei YU     EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
145f77189f7SLei YU         .WillOnce(Return(std::vector<std::string>({psu0, psu1})));
146f77189f7SLei YU     EXPECT_CALL(mockedUtils, getService(_, StrEq(psu0), _))
147f77189f7SLei YU         .WillOnce(Return(service));
148f77189f7SLei YU     EXPECT_CALL(mockedUtils, getService(_, StrEq(psu1), _))
149f77189f7SLei YU         .WillOnce(Return(service));
1505f3584d4SLei YU     EXPECT_CALL(mockedUtils, getVersion(StrEq(psu0)))
1515f3584d4SLei YU         .WillOnce(Return(std::string(version0)));
152f77189f7SLei YU     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
153f77189f7SLei YU                                              StrEq(PRESENT)))
154f77189f7SLei YU         .WillOnce(Return(any(PropertyType(true)))); // present
155*760053d8SFaisal Awada     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
156*760053d8SFaisal Awada                                              StrEq(MODEL)))
157*760053d8SFaisal Awada         .WillOnce(Return(any(PropertyType(std::string("dummyModel0")))));
1585f3584d4SLei YU     EXPECT_CALL(mockedUtils, getVersion(StrEq(psu1)))
1595f3584d4SLei YU         .WillOnce(Return(std::string(version1)));
160f77189f7SLei YU     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
161f77189f7SLei YU                                              StrEq(PRESENT)))
162f77189f7SLei YU         .WillOnce(Return(any(PropertyType(true)))); // present
163*760053d8SFaisal Awada     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
164*760053d8SFaisal Awada                                              StrEq(MODEL)))
165*760053d8SFaisal Awada         .WillOnce(Return(any(PropertyType(std::string("dummyModel1")))));
166f77189f7SLei YU 
167f77189f7SLei YU     // The item updater itself
168f77189f7SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
169f77189f7SLei YU         .Times(1);
170f77189f7SLei YU 
171f77189f7SLei YU     // activation and version object will be added
172f77189f7SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath0)))
173f77189f7SLei YU         .Times(2);
174f77189f7SLei YU     itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
175f77189f7SLei YU 
176f77189f7SLei YU     // Verify there is only one activation and it has two associations
177f77189f7SLei YU     const auto& activations = GetActivations();
178f77189f7SLei YU     EXPECT_EQ(1u, activations.size());
179f77189f7SLei YU     const auto& activation = activations.find(version0)->second;
180f77189f7SLei YU     const auto& assocs = activation->associations();
181f77189f7SLei YU     EXPECT_EQ(2u, assocs.size());
182f77189f7SLei YU     EXPECT_EQ(psu0, std::get<2>(assocs[0]));
183f77189f7SLei YU     EXPECT_EQ(psu1, std::get<2>(assocs[1]));
184f77189f7SLei YU }
185f77189f7SLei YU 
TEST_F(TestItemUpdater,CreateTwoPSUsWithDifferentVersion)186f77189f7SLei YU TEST_F(TestItemUpdater, CreateTwoPSUsWithDifferentVersion)
187f77189f7SLei YU {
188f77189f7SLei YU     constexpr auto psu0 = "/com/example/inventory/psu0";
189f77189f7SLei YU     constexpr auto psu1 = "/com/example/inventory/psu1";
190f77189f7SLei YU     constexpr auto service = "com.example.Software.Psu";
191f77189f7SLei YU     auto version0 = std::string("version0");
192f77189f7SLei YU     auto version1 = std::string("version1");
193f77189f7SLei YU     auto objPath0 = getObjPath(version0);
194f77189f7SLei YU     auto objPath1 = getObjPath(version1);
195f77189f7SLei YU 
196f77189f7SLei YU     EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
197f77189f7SLei YU         .WillOnce(Return(std::vector<std::string>({psu0, psu1})));
198f77189f7SLei YU     EXPECT_CALL(mockedUtils, getService(_, StrEq(psu0), _))
199f77189f7SLei YU         .WillOnce(Return(service));
200f77189f7SLei YU     EXPECT_CALL(mockedUtils, getService(_, StrEq(psu1), _))
201f77189f7SLei YU         .WillOnce(Return(service));
2025f3584d4SLei YU     EXPECT_CALL(mockedUtils, getVersion(StrEq(psu0)))
2035f3584d4SLei YU         .WillOnce(Return(std::string(version0)));
204f77189f7SLei YU     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
205f77189f7SLei YU                                              StrEq(PRESENT)))
206f77189f7SLei YU         .WillOnce(Return(any(PropertyType(true)))); // present
207*760053d8SFaisal Awada     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
208*760053d8SFaisal Awada                                              StrEq(MODEL)))
209*760053d8SFaisal Awada         .WillOnce(Return(any(PropertyType(std::string("dummyModel0")))));
2105f3584d4SLei YU     EXPECT_CALL(mockedUtils, getVersion(StrEq(psu1)))
2115f3584d4SLei YU         .WillOnce(Return(std::string(version1)));
212f77189f7SLei YU     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
213f77189f7SLei YU                                              StrEq(PRESENT)))
214f77189f7SLei YU         .WillOnce(Return(any(PropertyType(true)))); // present
215*760053d8SFaisal Awada     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
216*760053d8SFaisal Awada                                              StrEq(MODEL)))
217*760053d8SFaisal Awada         .WillOnce(Return(any(PropertyType(std::string("dummyModel1")))));
218f77189f7SLei YU 
219f77189f7SLei YU     // The item updater itself
220f77189f7SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
221f77189f7SLei YU         .Times(1);
222f77189f7SLei YU 
223f77189f7SLei YU     // two new activation and version objects will be added
224f77189f7SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath0)))
225f77189f7SLei YU         .Times(2);
226f77189f7SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath1)))
227f77189f7SLei YU         .Times(2);
228f77189f7SLei YU     itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
229f77189f7SLei YU 
230f77189f7SLei YU     // Verify there are two activations and each with one association
231f77189f7SLei YU     const auto& activations = GetActivations();
232f77189f7SLei YU     EXPECT_EQ(2u, activations.size());
233f77189f7SLei YU     const auto& activation0 = activations.find(version0)->second;
234f77189f7SLei YU     const auto& assocs0 = activation0->associations();
235f77189f7SLei YU     EXPECT_EQ(1u, assocs0.size());
236f77189f7SLei YU     EXPECT_EQ(psu0, std::get<2>(assocs0[0]));
237f77189f7SLei YU 
238f77189f7SLei YU     const auto& activation1 = activations.find(version1)->second;
239f77189f7SLei YU     const auto& assocs1 = activation1->associations();
240f77189f7SLei YU     EXPECT_EQ(1u, assocs1.size());
241f77189f7SLei YU     EXPECT_EQ(psu1, std::get<2>(assocs1[0]));
242f77189f7SLei YU }
243a2c2cd72SLei YU 
TEST_F(TestItemUpdater,OnOnePSURemoved)244a2c2cd72SLei YU TEST_F(TestItemUpdater, OnOnePSURemoved)
245a2c2cd72SLei YU {
246a2c2cd72SLei YU     constexpr auto psuPath = "/com/example/inventory/psu0";
247a2c2cd72SLei YU     constexpr auto service = "com.example.Software.Psu";
248a2c2cd72SLei YU     constexpr auto version = "version0";
249a2c2cd72SLei YU     std::string objPath = getObjPath(version);
250a2c2cd72SLei YU     EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
251a2c2cd72SLei YU         .WillOnce(Return(std::vector<std::string>({psuPath})));
252a2c2cd72SLei YU     EXPECT_CALL(mockedUtils, getService(_, StrEq(psuPath), _))
253a2c2cd72SLei YU         .WillOnce(Return(service));
2545f3584d4SLei YU     EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
2555f3584d4SLei YU         .WillOnce(Return(std::string(version)));
256a2c2cd72SLei YU     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
257a2c2cd72SLei YU                                              _, StrEq(PRESENT)))
258a2c2cd72SLei YU         .WillOnce(Return(any(PropertyType(true)))); // present
259*760053d8SFaisal Awada     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
260*760053d8SFaisal Awada                                              _, StrEq(MODEL)))
261*760053d8SFaisal Awada         .WillOnce(Return(any(PropertyType(std::string("dummyModel")))));
262a2c2cd72SLei YU 
263a2c2cd72SLei YU     // The item updater itself
264a2c2cd72SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
265a2c2cd72SLei YU         .Times(1);
266a2c2cd72SLei YU 
267a2c2cd72SLei YU     // activation and version object will be added
268a2c2cd72SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
269a2c2cd72SLei YU         .Times(2);
270a2c2cd72SLei YU     itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
271a2c2cd72SLei YU 
272a2c2cd72SLei YU     // the activation and version object will be removed
273a2c2cd72SLei YU     Properties p{{PRESENT, PropertyType(false)}};
274a2c2cd72SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(objPath)))
275a2c2cd72SLei YU         .Times(2);
276a2c2cd72SLei YU     onPsuInventoryChanged(psuPath, p);
277a2c2cd72SLei YU 
278a2c2cd72SLei YU     // on exit, item updater is removed
279a2c2cd72SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(dBusPath)))
280a2c2cd72SLei YU         .Times(1);
281a2c2cd72SLei YU }
282a2c2cd72SLei YU 
TEST_F(TestItemUpdater,OnOnePSUAdded)283a2c2cd72SLei YU TEST_F(TestItemUpdater, OnOnePSUAdded)
284a2c2cd72SLei YU {
285a2c2cd72SLei YU     constexpr auto psuPath = "/com/example/inventory/psu0";
286a2c2cd72SLei YU     constexpr auto service = "com.example.Software.Psu";
287a2c2cd72SLei YU     constexpr auto version = "version0";
288a2c2cd72SLei YU     std::string objPath = getObjPath(version);
289a2c2cd72SLei YU     EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
290a2c2cd72SLei YU         .WillOnce(Return(std::vector<std::string>({psuPath})));
291a2c2cd72SLei YU     EXPECT_CALL(mockedUtils, getService(_, StrEq(psuPath), _))
292a2c2cd72SLei YU         .WillOnce(Return(service));
2935f3584d4SLei YU     EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
2945f3584d4SLei YU         .WillOnce(Return(std::string(version)));
295a2c2cd72SLei YU     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
296a2c2cd72SLei YU                                              _, StrEq(PRESENT)))
297a2c2cd72SLei YU         .WillOnce(Return(any(PropertyType(false)))); // not present
298*760053d8SFaisal Awada     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
299*760053d8SFaisal Awada                                              _, StrEq(MODEL)))
300*760053d8SFaisal Awada         .WillOnce(Return(any(PropertyType(std::string("")))));
301a2c2cd72SLei YU 
302a2c2cd72SLei YU     // The item updater itself
303a2c2cd72SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
304a2c2cd72SLei YU         .Times(1);
305a2c2cd72SLei YU 
306a2c2cd72SLei YU     // No activation/version objects are created
307a2c2cd72SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
308a2c2cd72SLei YU         .Times(0);
309a2c2cd72SLei YU     itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
310a2c2cd72SLei YU 
311a2c2cd72SLei YU     // The PSU is present and version is added in a single call
3121517f5f6SLei YU     Properties propAddedAndModel{
3131517f5f6SLei YU         {PRESENT, PropertyType(true)},
3141517f5f6SLei YU         {MODEL, PropertyType(std::string("testModel"))}};
315dcaf8934SLei YU     EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
316dcaf8934SLei YU         .WillOnce(Return(std::string(version)));
317a2c2cd72SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
318a2c2cd72SLei YU         .Times(2);
3191517f5f6SLei YU     onPsuInventoryChanged(psuPath, propAddedAndModel);
320a2c2cd72SLei YU }
321a2c2cd72SLei YU 
TEST_F(TestItemUpdater,OnOnePSURemovedAndAddedWithLatestVersion)3221517f5f6SLei YU TEST_F(TestItemUpdater, OnOnePSURemovedAndAddedWithLatestVersion)
323a2c2cd72SLei YU {
324a2c2cd72SLei YU     constexpr auto psuPath = "/com/example/inventory/psu0";
325a2c2cd72SLei YU     constexpr auto service = "com.example.Software.Psu";
326a2c2cd72SLei YU     constexpr auto version = "version0";
327a2c2cd72SLei YU     std::string objPath = getObjPath(version);
3281517f5f6SLei YU     ON_CALL(mockedUtils, getPSUInventoryPath(_))
3291517f5f6SLei YU         .WillByDefault(Return(std::vector<std::string>({psuPath})));
330a2c2cd72SLei YU     EXPECT_CALL(mockedUtils, getService(_, StrEq(psuPath), _))
331a2c2cd72SLei YU         .WillOnce(Return(service));
3325f3584d4SLei YU     EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
3335f3584d4SLei YU         .WillOnce(Return(std::string(version)));
334a2c2cd72SLei YU     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
335a2c2cd72SLei YU                                              _, StrEq(PRESENT)))
336a2c2cd72SLei YU         .WillOnce(Return(any(PropertyType(true)))); // present
337*760053d8SFaisal Awada     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
338*760053d8SFaisal Awada                                              _, StrEq(MODEL)))
339*760053d8SFaisal Awada         .WillOnce(Return(any(PropertyType(std::string("dummyModel")))));
340a2c2cd72SLei YU 
341a2c2cd72SLei YU     // The item updater itself
342a2c2cd72SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
343a2c2cd72SLei YU         .Times(1);
344a2c2cd72SLei YU 
345a2c2cd72SLei YU     // activation and version object will be added
346a2c2cd72SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
347a2c2cd72SLei YU         .Times(2);
348a2c2cd72SLei YU     itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
349a2c2cd72SLei YU 
350a2c2cd72SLei YU     // the activation and version object will be removed
351a2c2cd72SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(objPath)))
352a2c2cd72SLei YU         .Times(2);
353a2c2cd72SLei YU     onPsuInventoryChanged(psuPath, propRemoved);
354a2c2cd72SLei YU 
355dcaf8934SLei YU     EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
356dcaf8934SLei YU         .WillOnce(Return(std::string(version)));
357a2c2cd72SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
358a2c2cd72SLei YU         .Times(2);
3591517f5f6SLei YU 
3601517f5f6SLei YU     // On PSU inserted, it shall check if it's the latest version
3611517f5f6SLei YU     std::set<std::string> expectedVersions = {version};
3621517f5f6SLei YU     EXPECT_CALL(mockedUtils, getLatestVersion(ContainerEq(expectedVersions)))
3631517f5f6SLei YU         .WillOnce(Return(version));
3641517f5f6SLei YU     EXPECT_CALL(mockedUtils, isAssociated(StrEq(psuPath), _))
3651517f5f6SLei YU         .WillOnce(Return(true));
3661517f5f6SLei YU     EXPECT_CALL(sdbusMock, sd_bus_message_new_method_call(_, _, _, _, _,
3671517f5f6SLei YU                                                           StrEq("StartUnit")))
3681517f5f6SLei YU         .Times(0);
369a2c2cd72SLei YU     onPsuInventoryChanged(psuPath, propAdded);
3701517f5f6SLei YU     onPsuInventoryChanged(psuPath, propModel);
371a2c2cd72SLei YU 
372a2c2cd72SLei YU     // on exit, objects are removed
373a2c2cd72SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(objPath)))
374a2c2cd72SLei YU         .Times(2);
375a2c2cd72SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(dBusPath)))
376a2c2cd72SLei YU         .Times(1);
377a2c2cd72SLei YU }
378a2c2cd72SLei YU 
TEST_F(TestItemUpdater,TwoPSUsWithSameVersionRemovedAndAddedWithDifferntVersion)379a2c2cd72SLei YU TEST_F(TestItemUpdater,
380a2c2cd72SLei YU        TwoPSUsWithSameVersionRemovedAndAddedWithDifferntVersion)
381a2c2cd72SLei YU {
382a2c2cd72SLei YU     constexpr auto psu0 = "/com/example/inventory/psu0";
383a2c2cd72SLei YU     constexpr auto psu1 = "/com/example/inventory/psu1";
384a2c2cd72SLei YU     constexpr auto service = "com.example.Software.Psu";
385a2c2cd72SLei YU     auto version0 = std::string("version0");
386a2c2cd72SLei YU     auto version1 = std::string("version0");
387a2c2cd72SLei YU     auto objPath0 = getObjPath(version0);
388a2c2cd72SLei YU     auto objPath1 = getObjPath(version1);
389a2c2cd72SLei YU 
390a2c2cd72SLei YU     EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
391a2c2cd72SLei YU         .WillOnce(Return(std::vector<std::string>({psu0, psu1})));
392a2c2cd72SLei YU     EXPECT_CALL(mockedUtils, getService(_, StrEq(psu0), _))
393a2c2cd72SLei YU         .WillOnce(Return(service));
394a2c2cd72SLei YU     EXPECT_CALL(mockedUtils, getService(_, StrEq(psu1), _))
395a2c2cd72SLei YU         .WillOnce(Return(service));
3965f3584d4SLei YU     EXPECT_CALL(mockedUtils, getVersion(StrEq(psu0)))
3975f3584d4SLei YU         .WillOnce(Return(std::string(version0)));
398a2c2cd72SLei YU     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
399a2c2cd72SLei YU                                              StrEq(PRESENT)))
400a2c2cd72SLei YU         .WillOnce(Return(any(PropertyType(true)))); // present
401*760053d8SFaisal Awada     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
402*760053d8SFaisal Awada                                              StrEq(MODEL)))
403*760053d8SFaisal Awada         .WillOnce(Return(any(PropertyType(std::string("dummyModel0")))));
4045f3584d4SLei YU     EXPECT_CALL(mockedUtils, getVersion(StrEq(psu1)))
4055f3584d4SLei YU         .WillOnce(Return(std::string(version1)));
406a2c2cd72SLei YU     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
407a2c2cd72SLei YU                                              StrEq(PRESENT)))
408a2c2cd72SLei YU         .WillOnce(Return(any(PropertyType(true)))); // present
409*760053d8SFaisal Awada     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
410*760053d8SFaisal Awada                                              StrEq(MODEL)))
411*760053d8SFaisal Awada         .WillOnce(Return(any(PropertyType(std::string("dummyModel1")))));
412a2c2cd72SLei YU 
413a2c2cd72SLei YU     // The item updater itself
414a2c2cd72SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
415a2c2cd72SLei YU         .Times(1);
416a2c2cd72SLei YU 
417a2c2cd72SLei YU     // activation and version object will be added
418a2c2cd72SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath0)))
419a2c2cd72SLei YU         .Times(2);
420a2c2cd72SLei YU     itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
421a2c2cd72SLei YU 
422a2c2cd72SLei YU     // Verify there is only one activation and it has two associations
423a2c2cd72SLei YU     const auto& activations = GetActivations();
424a2c2cd72SLei YU     EXPECT_EQ(1u, activations.size());
425a2c2cd72SLei YU     const auto& activation = activations.find(version0)->second;
426a2c2cd72SLei YU     auto assocs = activation->associations();
427a2c2cd72SLei YU     EXPECT_EQ(2u, assocs.size());
428a2c2cd72SLei YU     EXPECT_EQ(psu0, std::get<2>(assocs[0]));
429a2c2cd72SLei YU     EXPECT_EQ(psu1, std::get<2>(assocs[1]));
430a2c2cd72SLei YU 
431a2c2cd72SLei YU     // PSU0 is removed, only associations shall be updated
432a2c2cd72SLei YU     onPsuInventoryChanged(psu0, propRemoved);
433a2c2cd72SLei YU     assocs = activation->associations();
434a2c2cd72SLei YU     EXPECT_EQ(1u, assocs.size());
435a2c2cd72SLei YU     EXPECT_EQ(psu1, std::get<2>(assocs[0]));
436a2c2cd72SLei YU 
437a2c2cd72SLei YU     // PSU1 is removed, the activation and version object shall be removed
438a2c2cd72SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(objPath0)))
439a2c2cd72SLei YU         .Times(2);
440a2c2cd72SLei YU     onPsuInventoryChanged(psu1, propRemoved);
441a2c2cd72SLei YU 
442a2c2cd72SLei YU     // Add PSU0 and PSU1 back, but PSU1 with a different version
443a2c2cd72SLei YU     version1 = "version1";
444a2c2cd72SLei YU     objPath1 = getObjPath(version1);
445dcaf8934SLei YU     EXPECT_CALL(mockedUtils, getVersion(StrEq(psu0)))
446dcaf8934SLei YU         .WillOnce(Return(std::string(version0)));
447dcaf8934SLei YU     EXPECT_CALL(mockedUtils, getVersion(StrEq(psu1)))
448dcaf8934SLei YU         .WillOnce(Return(std::string(version1)));
449a2c2cd72SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath0)))
450a2c2cd72SLei YU         .Times(2);
451a2c2cd72SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath1)))
452a2c2cd72SLei YU         .Times(2);
4531517f5f6SLei YU     onPsuInventoryChanged(psu0, propAdded);
4541517f5f6SLei YU     onPsuInventoryChanged(psu1, propModel);
4551517f5f6SLei YU     onPsuInventoryChanged(psu1, propAdded);
4561517f5f6SLei YU     onPsuInventoryChanged(psu0, propModel);
457a2c2cd72SLei YU 
458a2c2cd72SLei YU     // on exit, objects are removed
459a2c2cd72SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(objPath0)))
460a2c2cd72SLei YU         .Times(2);
461a2c2cd72SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(objPath1)))
462a2c2cd72SLei YU         .Times(2);
463a2c2cd72SLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(dBusPath)))
464a2c2cd72SLei YU         .Times(1);
465a2c2cd72SLei YU }
46658c26e3fSLei YU 
TEST_F(TestItemUpdater,scanDirOnNoPSU)46758c26e3fSLei YU TEST_F(TestItemUpdater, scanDirOnNoPSU)
46858c26e3fSLei YU {
46958c26e3fSLei YU     constexpr auto psuPath = "/com/example/inventory/psu0";
47058c26e3fSLei YU     constexpr auto service = "com.example.Software.Psu";
47158c26e3fSLei YU     constexpr auto version = "version0";
47258c26e3fSLei YU     std::string objPath = getObjPath(version);
47358c26e3fSLei YU     EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
47458c26e3fSLei YU         .WillOnce(Return(std::vector<std::string>({psuPath})));
47558c26e3fSLei YU     EXPECT_CALL(mockedUtils, getService(_, StrEq(psuPath), _))
47658c26e3fSLei YU         .WillOnce(Return(service));
47758c26e3fSLei YU     EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
47858c26e3fSLei YU         .WillOnce(Return(std::string(version)));
47958c26e3fSLei YU     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
48058c26e3fSLei YU                                              _, StrEq(PRESENT)))
48158c26e3fSLei YU         .WillOnce(Return(any(PropertyType(false)))); // not present
482*760053d8SFaisal Awada     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
483*760053d8SFaisal Awada                                              _, StrEq(MODEL)))
484*760053d8SFaisal Awada         .WillOnce(Return(any(PropertyType(std::string("")))));
48558c26e3fSLei YU 
48658c26e3fSLei YU     // The item updater itself
48758c26e3fSLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
48858c26e3fSLei YU         .Times(1);
48958c26e3fSLei YU 
49058c26e3fSLei YU     // No activation/version objects are created
49158c26e3fSLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
49258c26e3fSLei YU         .Times(0);
49358c26e3fSLei YU     itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
49458c26e3fSLei YU 
49558c26e3fSLei YU     // The valid image in test/psu-images-one-valid-one-invalid/model-1/
49658c26e3fSLei YU     auto objPathValid = getObjPath("psu-test.v0.4");
49758c26e3fSLei YU     auto objPathInvalid = getObjPath("psu-test.v0.5");
49858c26e3fSLei YU     // activation and version object will be added on scan dir
49958c26e3fSLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPathValid)))
500*760053d8SFaisal Awada         .Times(0);
50158c26e3fSLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPathInvalid)))
50258c26e3fSLei YU         .Times(0);
50358c26e3fSLei YU     scanDirectory("./psu-images-one-valid-one-invalid");
50458c26e3fSLei YU }
50558c26e3fSLei YU 
TEST_F(TestItemUpdater,scanDirOnSamePSUVersion)50658c26e3fSLei YU TEST_F(TestItemUpdater, scanDirOnSamePSUVersion)
50758c26e3fSLei YU {
50858c26e3fSLei YU     constexpr auto psuPath = "/com/example/inventory/psu0";
50958c26e3fSLei YU     constexpr auto service = "com.example.Software.Psu";
51058c26e3fSLei YU     constexpr auto version = "version0";
51158c26e3fSLei YU     std::string objPath = getObjPath(version);
51258c26e3fSLei YU     EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
51358c26e3fSLei YU         .WillOnce(Return(std::vector<std::string>({psuPath})));
51458c26e3fSLei YU     EXPECT_CALL(mockedUtils, getService(_, StrEq(psuPath), _))
51558c26e3fSLei YU         .WillOnce(Return(service));
51658c26e3fSLei YU     EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
51758c26e3fSLei YU         .WillOnce(Return(std::string(version)));
51858c26e3fSLei YU     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
51958c26e3fSLei YU                                              _, StrEq(PRESENT)))
52058c26e3fSLei YU         .WillOnce(Return(any(PropertyType(true)))); // present
521*760053d8SFaisal Awada     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
522*760053d8SFaisal Awada                                              _, StrEq(MODEL)))
523*760053d8SFaisal Awada         .WillOnce(Return(any(PropertyType(std::string("dummyModel")))));
52458c26e3fSLei YU 
52558c26e3fSLei YU     // The item updater itself
52658c26e3fSLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
52758c26e3fSLei YU         .Times(1);
52858c26e3fSLei YU 
52958c26e3fSLei YU     // activation and version object will be added
53058c26e3fSLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
53158c26e3fSLei YU         .Times(2);
53258c26e3fSLei YU     itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
53358c26e3fSLei YU 
53458c26e3fSLei YU     // The valid image in test/psu-images-valid-version0/model-3/ has the same
53558c26e3fSLei YU     // version as the running PSU, so no objects will be created, but only the
53658c26e3fSLei YU     // path will be set to the version object
53758c26e3fSLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
53858c26e3fSLei YU         .Times(0);
53958c26e3fSLei YU     EXPECT_CALL(sdbusMock, sd_bus_emit_properties_changed_strv(
54058c26e3fSLei YU                                _, StrEq(objPath),
54158c26e3fSLei YU                                StrEq("xyz.openbmc_project.Common.FilePath"),
54258c26e3fSLei YU                                Pointee(StrEq("Path"))))
543*760053d8SFaisal Awada         .Times(0);
54458c26e3fSLei YU     scanDirectory("./psu-images-valid-version0");
54558c26e3fSLei YU }
546ffb36539SLei YU 
TEST_F(TestItemUpdater,OnUpdateDoneOnTwoPSUsWithSameVersion)547ffb36539SLei YU TEST_F(TestItemUpdater, OnUpdateDoneOnTwoPSUsWithSameVersion)
548ffb36539SLei YU {
549ffb36539SLei YU     // Simulate there are two PSUs with same version, and updated to a new
550ffb36539SLei YU     // version
551ffb36539SLei YU     constexpr auto psu0 = "/com/example/inventory/psu0";
552ffb36539SLei YU     constexpr auto psu1 = "/com/example/inventory/psu1";
553ffb36539SLei YU     constexpr auto service = "com.example.Software.Psu";
554ffb36539SLei YU     auto version0 = std::string("version0");
555ffb36539SLei YU     auto version1 = std::string("version0");
556ffb36539SLei YU     auto objPath0 = getObjPath(version0);
557ffb36539SLei YU     auto objPath1 = getObjPath(version1);
558ffb36539SLei YU 
559ffb36539SLei YU     EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
560ffb36539SLei YU         .WillOnce(Return(std::vector<std::string>({psu0, psu1})));
561ffb36539SLei YU     EXPECT_CALL(mockedUtils, getService(_, StrEq(psu0), _))
562ffb36539SLei YU         .WillOnce(Return(service));
563ffb36539SLei YU     EXPECT_CALL(mockedUtils, getService(_, StrEq(psu1), _))
564ffb36539SLei YU         .WillOnce(Return(service));
565ffb36539SLei YU     EXPECT_CALL(mockedUtils, getVersion(StrEq(psu0)))
566ffb36539SLei YU         .WillOnce(Return(std::string(version0)));
567ffb36539SLei YU     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
568ffb36539SLei YU                                              StrEq(PRESENT)))
569ffb36539SLei YU         .WillOnce(Return(any(PropertyType(true)))); // present
570*760053d8SFaisal Awada     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
571*760053d8SFaisal Awada                                              StrEq(MODEL)))
572*760053d8SFaisal Awada         .WillOnce(Return(any(PropertyType(std::string("dummyModel0")))));
573ffb36539SLei YU     EXPECT_CALL(mockedUtils, getVersion(StrEq(psu1)))
574ffb36539SLei YU         .WillOnce(Return(std::string(version1)));
575ffb36539SLei YU     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
576ffb36539SLei YU                                              StrEq(PRESENT)))
577ffb36539SLei YU         .WillOnce(Return(any(PropertyType(true)))); // present
578*760053d8SFaisal Awada     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
579*760053d8SFaisal Awada                                              StrEq(MODEL)))
580*760053d8SFaisal Awada         .WillOnce(Return(any(PropertyType(std::string("dummyModel1")))));
581ffb36539SLei YU 
582ffb36539SLei YU     itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
583ffb36539SLei YU 
5841517f5f6SLei YU     std::string newVersionId = "NewVersionId";
5851517f5f6SLei YU     AssociationList associations;
5861517f5f6SLei YU     auto dummyActivation = std::make_unique<Activation>(
5871517f5f6SLei YU         mockedBus, dBusPath, newVersionId, "", Activation::Status::Active,
5881517f5f6SLei YU         associations, "", itemUpdater.get(), itemUpdater.get());
5891517f5f6SLei YU 
590ffb36539SLei YU     // Now there is one activation and it has two associations
591ffb36539SLei YU     auto& activations = GetActivations();
5921517f5f6SLei YU     activations.emplace(newVersionId, std::move(dummyActivation));
593ffb36539SLei YU     auto& activation = activations.find(version0)->second;
594ffb36539SLei YU     auto assocs = activation->associations();
595ffb36539SLei YU     EXPECT_EQ(2u, assocs.size());
596ffb36539SLei YU     EXPECT_EQ(psu0, std::get<2>(assocs[0]));
597ffb36539SLei YU     EXPECT_EQ(psu1, std::get<2>(assocs[1]));
598ffb36539SLei YU 
599ffb36539SLei YU     EXPECT_CALL(mockedUtils, isAssociated(StrEq(psu0), _))
600ffb36539SLei YU         .WillOnce(Return(true));
6011517f5f6SLei YU     itemUpdater->onUpdateDone(newVersionId, psu0);
602ffb36539SLei YU 
60333cf9f08SManojkiran Eda     // Now the activation should have one association
604ffb36539SLei YU     assocs = activation->associations();
605ffb36539SLei YU     EXPECT_EQ(1u, assocs.size());
606ffb36539SLei YU     EXPECT_EQ(psu1, std::get<2>(assocs[0]));
607ffb36539SLei YU 
608ffb36539SLei YU     EXPECT_CALL(mockedUtils, isAssociated(StrEq(psu1), _))
609ffb36539SLei YU         .WillOnce(Return(true));
6101517f5f6SLei YU     itemUpdater->onUpdateDone(newVersionId, psu1);
611ffb36539SLei YU 
6121517f5f6SLei YU     // Now the activation shall be erased and only the dummy one is left
6131517f5f6SLei YU     EXPECT_EQ(1u, activations.size());
6141517f5f6SLei YU     EXPECT_NE(activations.find(newVersionId), activations.end());
615ffb36539SLei YU }
616ffb36539SLei YU 
TEST_F(TestItemUpdater,OnUpdateDoneOnTwoPSUsWithDifferentVersion)617ffb36539SLei YU TEST_F(TestItemUpdater, OnUpdateDoneOnTwoPSUsWithDifferentVersion)
618ffb36539SLei YU {
619ffb36539SLei YU     // Simulate there are two PSUs with different version, and updated to a new
620ffb36539SLei YU     // version
621ffb36539SLei YU     constexpr auto psu0 = "/com/example/inventory/psu0";
622ffb36539SLei YU     constexpr auto psu1 = "/com/example/inventory/psu1";
623ffb36539SLei YU     constexpr auto service = "com.example.Software.Psu";
624ffb36539SLei YU     auto version0 = std::string("version0");
625ffb36539SLei YU     auto version1 = std::string("version1");
626ffb36539SLei YU     auto objPath0 = getObjPath(version0);
627ffb36539SLei YU     auto objPath1 = getObjPath(version1);
628ffb36539SLei YU 
629ffb36539SLei YU     EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
630ffb36539SLei YU         .WillOnce(Return(std::vector<std::string>({psu0, psu1})));
631ffb36539SLei YU     EXPECT_CALL(mockedUtils, getService(_, StrEq(psu0), _))
632ffb36539SLei YU         .WillOnce(Return(service));
633ffb36539SLei YU     EXPECT_CALL(mockedUtils, getService(_, StrEq(psu1), _))
634ffb36539SLei YU         .WillOnce(Return(service));
635ffb36539SLei YU     EXPECT_CALL(mockedUtils, getVersion(StrEq(psu0)))
636ffb36539SLei YU         .WillOnce(Return(std::string(version0)));
637ffb36539SLei YU     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
638ffb36539SLei YU                                              StrEq(PRESENT)))
639ffb36539SLei YU         .WillOnce(Return(any(PropertyType(true)))); // present
640*760053d8SFaisal Awada     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
641*760053d8SFaisal Awada                                              StrEq(MODEL)))
642*760053d8SFaisal Awada         .WillOnce(Return(any(PropertyType(std::string("dummyModel0")))));
643ffb36539SLei YU     EXPECT_CALL(mockedUtils, getVersion(StrEq(psu1)))
644ffb36539SLei YU         .WillOnce(Return(std::string(version1)));
645ffb36539SLei YU     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
646ffb36539SLei YU                                              StrEq(PRESENT)))
647ffb36539SLei YU         .WillOnce(Return(any(PropertyType(true)))); // present
648*760053d8SFaisal Awada     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
649*760053d8SFaisal Awada                                              StrEq(MODEL)))
650*760053d8SFaisal Awada         .WillOnce(Return(any(PropertyType(std::string("dummyModel1")))));
651ffb36539SLei YU 
652ffb36539SLei YU     itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
653ffb36539SLei YU 
6541517f5f6SLei YU     std::string newVersionId = "NewVersionId";
6551517f5f6SLei YU     AssociationList associations;
6561517f5f6SLei YU     auto dummyActivation = std::make_unique<Activation>(
6571517f5f6SLei YU         mockedBus, dBusPath, newVersionId, "", Activation::Status::Active,
6581517f5f6SLei YU         associations, "", itemUpdater.get(), itemUpdater.get());
6591517f5f6SLei YU 
6601517f5f6SLei YU     auto& activations = GetActivations();
6611517f5f6SLei YU     activations.emplace(newVersionId, std::move(dummyActivation));
662ffb36539SLei YU 
663ffb36539SLei YU     EXPECT_CALL(mockedUtils, isAssociated(StrEq(psu0), _))
664ffb36539SLei YU         .WillOnce(Return(true));
6651517f5f6SLei YU 
6661517f5f6SLei YU     // After psu0 is done, two activations should be left
6671517f5f6SLei YU     itemUpdater->onUpdateDone(newVersionId, psu0);
6681517f5f6SLei YU     EXPECT_EQ(2u, activations.size());
669ffb36539SLei YU     const auto& activation1 = activations.find(version1)->second;
670ffb36539SLei YU     const auto& assocs1 = activation1->associations();
671ffb36539SLei YU     EXPECT_EQ(1u, assocs1.size());
672ffb36539SLei YU     EXPECT_EQ(psu1, std::get<2>(assocs1[0]));
673ffb36539SLei YU 
674ffb36539SLei YU     EXPECT_CALL(mockedUtils, isAssociated(StrEq(psu1), _))
675ffb36539SLei YU         .WillOnce(Return(true));
6761517f5f6SLei YU     // After psu1 is done, only the dummy activation should be left
6771517f5f6SLei YU     itemUpdater->onUpdateDone(newVersionId, psu1);
6781517f5f6SLei YU     EXPECT_EQ(1u, activations.size());
6791517f5f6SLei YU     EXPECT_NE(activations.find(newVersionId), activations.end());
6801517f5f6SLei YU }
6811517f5f6SLei YU 
TEST_F(TestItemUpdater,OnOnePSURemovedAndAddedWithOldVersion)6821517f5f6SLei YU TEST_F(TestItemUpdater, OnOnePSURemovedAndAddedWithOldVersion)
6831517f5f6SLei YU {
6841517f5f6SLei YU     constexpr auto psuPath = "/com/example/inventory/psu0";
6851517f5f6SLei YU     constexpr auto service = "com.example.Software.Psu";
6861517f5f6SLei YU     constexpr auto version = "version0";
6871517f5f6SLei YU     std::string versionId =
6881517f5f6SLei YU         version; // In testing versionId is the same as version
6891517f5f6SLei YU     std::string objPath = getObjPath(version);
6901517f5f6SLei YU     ON_CALL(mockedUtils, getPSUInventoryPath(_))
6911517f5f6SLei YU         .WillByDefault(Return(std::vector<std::string>({psuPath})));
692*760053d8SFaisal Awada     EXPECT_CALL(mockedUtils, getService(_, StrEq(psuPath), _))
693*760053d8SFaisal Awada         .WillOnce(Return(service))
694*760053d8SFaisal Awada         .WillOnce(Return(service));
6951517f5f6SLei YU     EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
6961517f5f6SLei YU         .WillOnce(Return(std::string(version)));
6971517f5f6SLei YU     ON_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath), _,
6981517f5f6SLei YU                                          StrEq(PRESENT)))
6991517f5f6SLei YU         .WillByDefault(Return(any(PropertyType(true)))); // present
700*760053d8SFaisal Awada     ON_CALL(mockedUtils,
701*760053d8SFaisal Awada             getPropertyImpl(_, StrEq(service), StrEq(psuPath), _, StrEq(MODEL)))
702*760053d8SFaisal Awada         .WillByDefault(Return(any(PropertyType(std::string("dummyModel")))));
7031517f5f6SLei YU     itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
7041517f5f6SLei YU 
7051517f5f6SLei YU     // Add an association to simulate that it has image in BMC filesystem
7061517f5f6SLei YU     auto& activation = GetActivations().find(versionId)->second;
7071517f5f6SLei YU     auto assocs = activation->associations();
7081517f5f6SLei YU     assocs.emplace_back(ACTIVATION_FWD_ASSOCIATION, ACTIVATION_REV_ASSOCIATION,
7091517f5f6SLei YU                         "SomePath");
7101517f5f6SLei YU     activation->associations(assocs);
7111517f5f6SLei YU     activation->path("SomeFilePath");
7121517f5f6SLei YU 
7131517f5f6SLei YU     onPsuInventoryChanged(psuPath, propRemoved);
7141517f5f6SLei YU 
7151517f5f6SLei YU     // On PSU inserted, it checks and finds a newer version
7161517f5f6SLei YU     auto oldVersion = "old-version";
7171517f5f6SLei YU     EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
7181517f5f6SLei YU         .WillOnce(Return(std::string(oldVersion)));
7191517f5f6SLei YU     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
7201517f5f6SLei YU                                              _, StrEq(MANUFACTURER)))
7211517f5f6SLei YU         .WillOnce(
7221517f5f6SLei YU             Return(any(PropertyType(std::string(""))))); // Checking compatible
7231517f5f6SLei YU     EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
7241517f5f6SLei YU                                              _, StrEq(MODEL)))
7251517f5f6SLei YU         .WillOnce(
7261517f5f6SLei YU             Return(any(PropertyType(std::string(""))))); // Checking compatible
7271517f5f6SLei YU     std::set<std::string> expectedVersions = {version, oldVersion};
7281517f5f6SLei YU     EXPECT_CALL(mockedUtils, getLatestVersion(ContainerEq(expectedVersions)))
7291517f5f6SLei YU         .WillOnce(Return(version));
7301517f5f6SLei YU     ON_CALL(mockedUtils, isAssociated(StrEq(psuPath), _))
7311517f5f6SLei YU         .WillByDefault(Return(false));
7321517f5f6SLei YU     EXPECT_CALL(sdbusMock, sd_bus_message_new_method_call(_, _, _, _, _,
7331517f5f6SLei YU                                                           StrEq("StartUnit")))
7348afeee56SLei YU         .Times(3); // There are 3 systemd units are started, enable bmc reboot
7358afeee56SLei YU                    // guard, start activation, and disable bmc reboot guard
7361517f5f6SLei YU     onPsuInventoryChanged(psuPath, propAdded);
7371517f5f6SLei YU     onPsuInventoryChanged(psuPath, propModel);
738ffb36539SLei YU }
739