blob: c231654762a51b2abb80bd2af78259e4f51e7ac8 [file] [log] [blame]
Lei YUf77189f2019-08-07 14:26:30 +08001#include "item_updater.hpp"
2#include "mocked_utils.hpp"
3
4#include <sdbusplus/test/sdbus_mock.hpp>
5
6#include <gmock/gmock.h>
7#include <gtest/gtest.h>
8
9using namespace phosphor::software::updater;
10using ::testing::_;
Lei YU1517f5f2019-10-14 16:44:42 +080011using ::testing::ContainerEq;
Lei YU58c26e32019-09-27 17:52:06 +080012using ::testing::Pointee;
Lei YUf77189f2019-08-07 14:26:30 +080013using ::testing::Return;
14using ::testing::ReturnArg;
15using ::testing::StrEq;
16
Patrick Williamsb5f9b822022-06-16 17:26:17 -050017using std::any;
Lei YUf77189f2019-08-07 14:26:30 +080018
19class TestItemUpdater : public ::testing::Test
20{
21 public:
Lei YUa2c2cd72019-08-09 15:54:10 +080022 using Properties = ItemUpdater::Properties;
23 using PropertyType = utils::UtilsInterface::PropertyType;
24
George Liu66a54ad2024-08-23 13:53:39 +080025 TestItemUpdater(const TestItemUpdater&) = delete;
26 TestItemUpdater& operator=(const TestItemUpdater&) = delete;
27 TestItemUpdater(TestItemUpdater&&) = delete;
28 TestItemUpdater& operator=(TestItemUpdater&&) = delete;
29
Lei YUf77189f2019-08-07 14:26:30 +080030 TestItemUpdater() :
31 mockedUtils(
32 reinterpret_cast<const utils::MockedUtils&>(utils::getUtils()))
33 {
34 ON_CALL(mockedUtils, getVersionId(_)).WillByDefault(ReturnArg<0>());
Lei YUff83c2a2019-09-12 13:55:18 +080035 ON_CALL(mockedUtils, getPropertyImpl(_, _, _, _, StrEq(PRESENT)))
36 .WillByDefault(Return(any(PropertyType(true))));
Lei YUf77189f2019-08-07 14:26:30 +080037 }
38
George Liu047d9942024-08-23 13:44:31 +080039 ~TestItemUpdater() override
Lei YUf77189f2019-08-07 14:26:30 +080040 {
Lei YUc09155b2019-10-11 17:30:48 +080041 utils::freeUtils();
Lei YUf77189f2019-08-07 14:26:30 +080042 }
43
Lei YU1517f5f2019-10-14 16:44:42 +080044 auto& GetActivations()
Lei YUf77189f2019-08-07 14:26:30 +080045 {
46 return itemUpdater->activations;
47 }
48
49 std::string getObjPath(const std::string& versionId)
50 {
51 return std::string(dBusPath) + "/" + versionId;
52 }
53
Lei YUa2c2cd72019-08-09 15:54:10 +080054 void onPsuInventoryChanged(const std::string& psuPath,
55 const Properties& properties)
56 {
57 itemUpdater->onPsuInventoryChanged(psuPath, properties);
58 }
59
Lei YU58c26e32019-09-27 17:52:06 +080060 void scanDirectory(const fs::path& p)
61 {
62 itemUpdater->scanDirectory(p);
63 }
64
Lei YUf77189f2019-08-07 14:26:30 +080065 static constexpr auto dBusPath = SOFTWARE_OBJPATH;
66 sdbusplus::SdBusMock sdbusMock;
Patrick Williams374fae52022-07-22 19:26:55 -050067 sdbusplus::bus_t mockedBus = sdbusplus::get_mocked_new(&sdbusMock);
Lei YUf77189f2019-08-07 14:26:30 +080068 const utils::MockedUtils& mockedUtils;
69 std::unique_ptr<ItemUpdater> itemUpdater;
Lei YU1517f5f2019-10-14 16:44:42 +080070 Properties propAdded{{PRESENT, PropertyType(true)}};
71 Properties propRemoved{{PRESENT, PropertyType(false)}};
72 Properties propModel{{MODEL, PropertyType(std::string("dummyModel"))}};
Lei YUf77189f2019-08-07 14:26:30 +080073};
74
75TEST_F(TestItemUpdater, ctordtor)
76{
Lei YU65207482019-10-11 16:39:36 +080077 EXPECT_CALL(mockedUtils, getLatestVersion(_)).Times(1);
Lei YUf77189f2019-08-07 14:26:30 +080078 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
79}
80
81TEST_F(TestItemUpdater, NotCreateObjectOnNotPresent)
82{
83 constexpr auto psuPath = "/com/example/inventory/psu0";
84 constexpr auto service = "com.example.Software.Psu";
85 constexpr auto version = "version0";
86 std::string objPath = getObjPath(version);
87 EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
88 .WillOnce(Return(std::vector<std::string>({psuPath})));
89 EXPECT_CALL(mockedUtils, getService(_, StrEq(psuPath), _))
90 .WillOnce(Return(service));
Lei YU5f3584d2019-08-27 16:28:53 +080091 EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
92 .WillOnce(Return(std::string(version)));
Lei YUf77189f2019-08-07 14:26:30 +080093 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
94 _, StrEq(PRESENT)))
95 .WillOnce(Return(any(PropertyType(false)))); // not present
Faisal Awada760053d2024-05-16 13:31:32 -050096 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
97 _, StrEq(MODEL)))
98 .WillOnce(Return(any(PropertyType(std::string("")))));
Lei YUf77189f2019-08-07 14:26:30 +080099
100 // The item updater itself
101 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
102 .Times(1);
103
104 // No activation/version objects are created
105 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
106 .Times(0);
107 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
108}
109
110TEST_F(TestItemUpdater, CreateOnePSUOnPresent)
111{
112 constexpr auto psuPath = "/com/example/inventory/psu0";
113 constexpr auto service = "com.example.Software.Psu";
114 constexpr auto version = "version0";
115 std::string objPath = getObjPath(version);
116 EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
117 .WillOnce(Return(std::vector<std::string>({psuPath})));
118 EXPECT_CALL(mockedUtils, getService(_, StrEq(psuPath), _))
119 .WillOnce(Return(service));
Lei YU5f3584d2019-08-27 16:28:53 +0800120 EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
121 .WillOnce(Return(std::string(version)));
Lei YUf77189f2019-08-07 14:26:30 +0800122 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
123 _, StrEq(PRESENT)))
124 .WillOnce(Return(any(PropertyType(true)))); // present
Faisal Awada760053d2024-05-16 13:31:32 -0500125 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
126 _, StrEq(MODEL)))
127 .WillOnce(Return(any(PropertyType(std::string("dummyModel")))));
Lei YUf77189f2019-08-07 14:26:30 +0800128
129 // The item updater itself
130 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
131 .Times(1);
132
133 // activation and version object will be added
134 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
135 .Times(2);
136 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
137}
138
139TEST_F(TestItemUpdater, CreateTwoPSUsWithSameVersion)
140{
141 constexpr auto psu0 = "/com/example/inventory/psu0";
142 constexpr auto psu1 = "/com/example/inventory/psu1";
143 constexpr auto service = "com.example.Software.Psu";
144 auto version0 = std::string("version0");
145 auto version1 = std::string("version0");
146 auto objPath0 = getObjPath(version0);
147 auto objPath1 = getObjPath(version1);
148
149 EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
150 .WillOnce(Return(std::vector<std::string>({psu0, psu1})));
151 EXPECT_CALL(mockedUtils, getService(_, StrEq(psu0), _))
152 .WillOnce(Return(service));
153 EXPECT_CALL(mockedUtils, getService(_, StrEq(psu1), _))
154 .WillOnce(Return(service));
Lei YU5f3584d2019-08-27 16:28:53 +0800155 EXPECT_CALL(mockedUtils, getVersion(StrEq(psu0)))
156 .WillOnce(Return(std::string(version0)));
Lei YUf77189f2019-08-07 14:26:30 +0800157 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
158 StrEq(PRESENT)))
159 .WillOnce(Return(any(PropertyType(true)))); // present
Faisal Awada760053d2024-05-16 13:31:32 -0500160 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
161 StrEq(MODEL)))
162 .WillOnce(Return(any(PropertyType(std::string("dummyModel0")))));
Lei YU5f3584d2019-08-27 16:28:53 +0800163 EXPECT_CALL(mockedUtils, getVersion(StrEq(psu1)))
164 .WillOnce(Return(std::string(version1)));
Lei YUf77189f2019-08-07 14:26:30 +0800165 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
166 StrEq(PRESENT)))
167 .WillOnce(Return(any(PropertyType(true)))); // present
Faisal Awada760053d2024-05-16 13:31:32 -0500168 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
169 StrEq(MODEL)))
170 .WillOnce(Return(any(PropertyType(std::string("dummyModel1")))));
Lei YUf77189f2019-08-07 14:26:30 +0800171
172 // The item updater itself
173 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
174 .Times(1);
175
176 // activation and version object will be added
177 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath0)))
178 .Times(2);
179 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
180
181 // Verify there is only one activation and it has two associations
182 const auto& activations = GetActivations();
183 EXPECT_EQ(1u, activations.size());
184 const auto& activation = activations.find(version0)->second;
185 const auto& assocs = activation->associations();
186 EXPECT_EQ(2u, assocs.size());
187 EXPECT_EQ(psu0, std::get<2>(assocs[0]));
188 EXPECT_EQ(psu1, std::get<2>(assocs[1]));
189}
190
191TEST_F(TestItemUpdater, CreateTwoPSUsWithDifferentVersion)
192{
193 constexpr auto psu0 = "/com/example/inventory/psu0";
194 constexpr auto psu1 = "/com/example/inventory/psu1";
195 constexpr auto service = "com.example.Software.Psu";
196 auto version0 = std::string("version0");
197 auto version1 = std::string("version1");
198 auto objPath0 = getObjPath(version0);
199 auto objPath1 = getObjPath(version1);
200
201 EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
202 .WillOnce(Return(std::vector<std::string>({psu0, psu1})));
203 EXPECT_CALL(mockedUtils, getService(_, StrEq(psu0), _))
204 .WillOnce(Return(service));
205 EXPECT_CALL(mockedUtils, getService(_, StrEq(psu1), _))
206 .WillOnce(Return(service));
Lei YU5f3584d2019-08-27 16:28:53 +0800207 EXPECT_CALL(mockedUtils, getVersion(StrEq(psu0)))
208 .WillOnce(Return(std::string(version0)));
Lei YUf77189f2019-08-07 14:26:30 +0800209 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
210 StrEq(PRESENT)))
211 .WillOnce(Return(any(PropertyType(true)))); // present
Faisal Awada760053d2024-05-16 13:31:32 -0500212 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
213 StrEq(MODEL)))
214 .WillOnce(Return(any(PropertyType(std::string("dummyModel0")))));
Lei YU5f3584d2019-08-27 16:28:53 +0800215 EXPECT_CALL(mockedUtils, getVersion(StrEq(psu1)))
216 .WillOnce(Return(std::string(version1)));
Lei YUf77189f2019-08-07 14:26:30 +0800217 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
218 StrEq(PRESENT)))
219 .WillOnce(Return(any(PropertyType(true)))); // present
Faisal Awada760053d2024-05-16 13:31:32 -0500220 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
221 StrEq(MODEL)))
222 .WillOnce(Return(any(PropertyType(std::string("dummyModel1")))));
Lei YUf77189f2019-08-07 14:26:30 +0800223
224 // The item updater itself
225 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
226 .Times(1);
227
228 // two new activation and version objects will be added
229 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath0)))
230 .Times(2);
231 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath1)))
232 .Times(2);
233 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
234
235 // Verify there are two activations and each with one association
236 const auto& activations = GetActivations();
237 EXPECT_EQ(2u, activations.size());
238 const auto& activation0 = activations.find(version0)->second;
239 const auto& assocs0 = activation0->associations();
240 EXPECT_EQ(1u, assocs0.size());
241 EXPECT_EQ(psu0, std::get<2>(assocs0[0]));
242
243 const auto& activation1 = activations.find(version1)->second;
244 const auto& assocs1 = activation1->associations();
245 EXPECT_EQ(1u, assocs1.size());
246 EXPECT_EQ(psu1, std::get<2>(assocs1[0]));
247}
Lei YUa2c2cd72019-08-09 15:54:10 +0800248
249TEST_F(TestItemUpdater, OnOnePSURemoved)
250{
251 constexpr auto psuPath = "/com/example/inventory/psu0";
252 constexpr auto service = "com.example.Software.Psu";
253 constexpr auto version = "version0";
254 std::string objPath = getObjPath(version);
255 EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
256 .WillOnce(Return(std::vector<std::string>({psuPath})));
257 EXPECT_CALL(mockedUtils, getService(_, StrEq(psuPath), _))
258 .WillOnce(Return(service));
Lei YU5f3584d2019-08-27 16:28:53 +0800259 EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
260 .WillOnce(Return(std::string(version)));
Lei YUa2c2cd72019-08-09 15:54:10 +0800261 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
262 _, StrEq(PRESENT)))
263 .WillOnce(Return(any(PropertyType(true)))); // present
Faisal Awada760053d2024-05-16 13:31:32 -0500264 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
265 _, StrEq(MODEL)))
266 .WillOnce(Return(any(PropertyType(std::string("dummyModel")))));
Lei YUa2c2cd72019-08-09 15:54:10 +0800267
268 // The item updater itself
269 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
270 .Times(1);
271
272 // activation and version object will be added
273 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
274 .Times(2);
275 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
276
277 // the activation and version object will be removed
278 Properties p{{PRESENT, PropertyType(false)}};
279 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(objPath)))
280 .Times(2);
281 onPsuInventoryChanged(psuPath, p);
282
283 // on exit, item updater is removed
284 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(dBusPath)))
285 .Times(1);
286}
287
288TEST_F(TestItemUpdater, OnOnePSUAdded)
289{
290 constexpr auto psuPath = "/com/example/inventory/psu0";
291 constexpr auto service = "com.example.Software.Psu";
292 constexpr auto version = "version0";
293 std::string objPath = getObjPath(version);
294 EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
295 .WillOnce(Return(std::vector<std::string>({psuPath})));
296 EXPECT_CALL(mockedUtils, getService(_, StrEq(psuPath), _))
297 .WillOnce(Return(service));
Lei YU5f3584d2019-08-27 16:28:53 +0800298 EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
299 .WillOnce(Return(std::string(version)));
Lei YUa2c2cd72019-08-09 15:54:10 +0800300 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
301 _, StrEq(PRESENT)))
302 .WillOnce(Return(any(PropertyType(false)))); // not present
Faisal Awada760053d2024-05-16 13:31:32 -0500303 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
304 _, StrEq(MODEL)))
305 .WillOnce(Return(any(PropertyType(std::string("")))));
Lei YUa2c2cd72019-08-09 15:54:10 +0800306
307 // The item updater itself
308 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
309 .Times(1);
310
311 // No activation/version objects are created
312 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
313 .Times(0);
314 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
315
316 // The PSU is present and version is added in a single call
Lei YU1517f5f2019-10-14 16:44:42 +0800317 Properties propAddedAndModel{
318 {PRESENT, PropertyType(true)},
319 {MODEL, PropertyType(std::string("testModel"))}};
Lei YUdcaf8932019-09-09 16:09:35 +0800320 EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
321 .WillOnce(Return(std::string(version)));
Lei YUa2c2cd72019-08-09 15:54:10 +0800322 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
323 .Times(2);
Lei YU1517f5f2019-10-14 16:44:42 +0800324 onPsuInventoryChanged(psuPath, propAddedAndModel);
Lei YUa2c2cd72019-08-09 15:54:10 +0800325}
326
Lei YU1517f5f2019-10-14 16:44:42 +0800327TEST_F(TestItemUpdater, OnOnePSURemovedAndAddedWithLatestVersion)
Lei YUa2c2cd72019-08-09 15:54:10 +0800328{
329 constexpr auto psuPath = "/com/example/inventory/psu0";
330 constexpr auto service = "com.example.Software.Psu";
331 constexpr auto version = "version0";
332 std::string objPath = getObjPath(version);
Lei YU1517f5f2019-10-14 16:44:42 +0800333 ON_CALL(mockedUtils, getPSUInventoryPath(_))
334 .WillByDefault(Return(std::vector<std::string>({psuPath})));
Lei YUa2c2cd72019-08-09 15:54:10 +0800335 EXPECT_CALL(mockedUtils, getService(_, StrEq(psuPath), _))
336 .WillOnce(Return(service));
Lei YU5f3584d2019-08-27 16:28:53 +0800337 EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
338 .WillOnce(Return(std::string(version)));
Lei YUa2c2cd72019-08-09 15:54:10 +0800339 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
340 _, StrEq(PRESENT)))
341 .WillOnce(Return(any(PropertyType(true)))); // present
Faisal Awada760053d2024-05-16 13:31:32 -0500342 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
343 _, StrEq(MODEL)))
344 .WillOnce(Return(any(PropertyType(std::string("dummyModel")))));
Lei YUa2c2cd72019-08-09 15:54:10 +0800345
346 // The item updater itself
347 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
348 .Times(1);
349
350 // activation and version object will be added
351 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
352 .Times(2);
353 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
354
355 // the activation and version object will be removed
Lei YUa2c2cd72019-08-09 15:54:10 +0800356 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(objPath)))
357 .Times(2);
358 onPsuInventoryChanged(psuPath, propRemoved);
359
Lei YUdcaf8932019-09-09 16:09:35 +0800360 EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
361 .WillOnce(Return(std::string(version)));
Lei YUa2c2cd72019-08-09 15:54:10 +0800362 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
363 .Times(2);
Lei YU1517f5f2019-10-14 16:44:42 +0800364
365 // On PSU inserted, it shall check if it's the latest version
366 std::set<std::string> expectedVersions = {version};
367 EXPECT_CALL(mockedUtils, getLatestVersion(ContainerEq(expectedVersions)))
368 .WillOnce(Return(version));
369 EXPECT_CALL(mockedUtils, isAssociated(StrEq(psuPath), _))
370 .WillOnce(Return(true));
371 EXPECT_CALL(sdbusMock, sd_bus_message_new_method_call(_, _, _, _, _,
372 StrEq("StartUnit")))
373 .Times(0);
Lei YUa2c2cd72019-08-09 15:54:10 +0800374 onPsuInventoryChanged(psuPath, propAdded);
Lei YU1517f5f2019-10-14 16:44:42 +0800375 onPsuInventoryChanged(psuPath, propModel);
Lei YUa2c2cd72019-08-09 15:54:10 +0800376
377 // on exit, objects are removed
378 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(objPath)))
379 .Times(2);
380 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(dBusPath)))
381 .Times(1);
382}
383
384TEST_F(TestItemUpdater,
385 TwoPSUsWithSameVersionRemovedAndAddedWithDifferntVersion)
386{
387 constexpr auto psu0 = "/com/example/inventory/psu0";
388 constexpr auto psu1 = "/com/example/inventory/psu1";
389 constexpr auto service = "com.example.Software.Psu";
390 auto version0 = std::string("version0");
391 auto version1 = std::string("version0");
392 auto objPath0 = getObjPath(version0);
393 auto objPath1 = getObjPath(version1);
394
395 EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
396 .WillOnce(Return(std::vector<std::string>({psu0, psu1})));
397 EXPECT_CALL(mockedUtils, getService(_, StrEq(psu0), _))
398 .WillOnce(Return(service));
399 EXPECT_CALL(mockedUtils, getService(_, StrEq(psu1), _))
400 .WillOnce(Return(service));
Lei YU5f3584d2019-08-27 16:28:53 +0800401 EXPECT_CALL(mockedUtils, getVersion(StrEq(psu0)))
402 .WillOnce(Return(std::string(version0)));
Lei YUa2c2cd72019-08-09 15:54:10 +0800403 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
404 StrEq(PRESENT)))
405 .WillOnce(Return(any(PropertyType(true)))); // present
Faisal Awada760053d2024-05-16 13:31:32 -0500406 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
407 StrEq(MODEL)))
408 .WillOnce(Return(any(PropertyType(std::string("dummyModel0")))));
Lei YU5f3584d2019-08-27 16:28:53 +0800409 EXPECT_CALL(mockedUtils, getVersion(StrEq(psu1)))
410 .WillOnce(Return(std::string(version1)));
Lei YUa2c2cd72019-08-09 15:54:10 +0800411 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
412 StrEq(PRESENT)))
413 .WillOnce(Return(any(PropertyType(true)))); // present
Faisal Awada760053d2024-05-16 13:31:32 -0500414 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
415 StrEq(MODEL)))
416 .WillOnce(Return(any(PropertyType(std::string("dummyModel1")))));
Lei YUa2c2cd72019-08-09 15:54:10 +0800417
418 // The item updater itself
419 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
420 .Times(1);
421
422 // activation and version object will be added
423 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath0)))
424 .Times(2);
425 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
426
427 // Verify there is only one activation and it has two associations
428 const auto& activations = GetActivations();
429 EXPECT_EQ(1u, activations.size());
430 const auto& activation = activations.find(version0)->second;
431 auto assocs = activation->associations();
432 EXPECT_EQ(2u, assocs.size());
433 EXPECT_EQ(psu0, std::get<2>(assocs[0]));
434 EXPECT_EQ(psu1, std::get<2>(assocs[1]));
435
436 // PSU0 is removed, only associations shall be updated
Lei YUa2c2cd72019-08-09 15:54:10 +0800437 onPsuInventoryChanged(psu0, propRemoved);
438 assocs = activation->associations();
439 EXPECT_EQ(1u, assocs.size());
440 EXPECT_EQ(psu1, std::get<2>(assocs[0]));
441
442 // PSU1 is removed, the activation and version object shall be removed
443 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(objPath0)))
444 .Times(2);
445 onPsuInventoryChanged(psu1, propRemoved);
446
447 // Add PSU0 and PSU1 back, but PSU1 with a different version
448 version1 = "version1";
449 objPath1 = getObjPath(version1);
Lei YUdcaf8932019-09-09 16:09:35 +0800450 EXPECT_CALL(mockedUtils, getVersion(StrEq(psu0)))
451 .WillOnce(Return(std::string(version0)));
452 EXPECT_CALL(mockedUtils, getVersion(StrEq(psu1)))
453 .WillOnce(Return(std::string(version1)));
Lei YUa2c2cd72019-08-09 15:54:10 +0800454 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath0)))
455 .Times(2);
456 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath1)))
457 .Times(2);
Lei YU1517f5f2019-10-14 16:44:42 +0800458 onPsuInventoryChanged(psu0, propAdded);
459 onPsuInventoryChanged(psu1, propModel);
460 onPsuInventoryChanged(psu1, propAdded);
461 onPsuInventoryChanged(psu0, propModel);
Lei YUa2c2cd72019-08-09 15:54:10 +0800462
463 // on exit, objects are removed
464 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(objPath0)))
465 .Times(2);
466 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(objPath1)))
467 .Times(2);
468 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(dBusPath)))
469 .Times(1);
470}
Lei YU58c26e32019-09-27 17:52:06 +0800471
472TEST_F(TestItemUpdater, scanDirOnNoPSU)
473{
474 constexpr auto psuPath = "/com/example/inventory/psu0";
475 constexpr auto service = "com.example.Software.Psu";
476 constexpr auto version = "version0";
477 std::string objPath = getObjPath(version);
478 EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
479 .WillOnce(Return(std::vector<std::string>({psuPath})));
480 EXPECT_CALL(mockedUtils, getService(_, StrEq(psuPath), _))
481 .WillOnce(Return(service));
482 EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
483 .WillOnce(Return(std::string(version)));
484 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
485 _, StrEq(PRESENT)))
486 .WillOnce(Return(any(PropertyType(false)))); // not present
Faisal Awada760053d2024-05-16 13:31:32 -0500487 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
488 _, StrEq(MODEL)))
489 .WillOnce(Return(any(PropertyType(std::string("")))));
Lei YU58c26e32019-09-27 17:52:06 +0800490
491 // The item updater itself
492 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
493 .Times(1);
494
495 // No activation/version objects are created
496 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
497 .Times(0);
498 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
499
500 // The valid image in test/psu-images-one-valid-one-invalid/model-1/
501 auto objPathValid = getObjPath("psu-test.v0.4");
502 auto objPathInvalid = getObjPath("psu-test.v0.5");
503 // activation and version object will be added on scan dir
504 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPathValid)))
Faisal Awada760053d2024-05-16 13:31:32 -0500505 .Times(0);
Lei YU58c26e32019-09-27 17:52:06 +0800506 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPathInvalid)))
507 .Times(0);
508 scanDirectory("./psu-images-one-valid-one-invalid");
509}
510
511TEST_F(TestItemUpdater, scanDirOnSamePSUVersion)
512{
513 constexpr auto psuPath = "/com/example/inventory/psu0";
514 constexpr auto service = "com.example.Software.Psu";
515 constexpr auto version = "version0";
516 std::string objPath = getObjPath(version);
517 EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
518 .WillOnce(Return(std::vector<std::string>({psuPath})));
519 EXPECT_CALL(mockedUtils, getService(_, StrEq(psuPath), _))
520 .WillOnce(Return(service));
521 EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
522 .WillOnce(Return(std::string(version)));
523 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
524 _, StrEq(PRESENT)))
525 .WillOnce(Return(any(PropertyType(true)))); // present
Faisal Awada760053d2024-05-16 13:31:32 -0500526 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
527 _, StrEq(MODEL)))
528 .WillOnce(Return(any(PropertyType(std::string("dummyModel")))));
Lei YU58c26e32019-09-27 17:52:06 +0800529
530 // The item updater itself
531 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
532 .Times(1);
533
534 // activation and version object will be added
535 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
536 .Times(2);
537 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
538
539 // The valid image in test/psu-images-valid-version0/model-3/ has the same
540 // version as the running PSU, so no objects will be created, but only the
541 // path will be set to the version object
542 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
543 .Times(0);
544 EXPECT_CALL(sdbusMock, sd_bus_emit_properties_changed_strv(
545 _, StrEq(objPath),
546 StrEq("xyz.openbmc_project.Common.FilePath"),
547 Pointee(StrEq("Path"))))
Faisal Awada760053d2024-05-16 13:31:32 -0500548 .Times(0);
Lei YU58c26e32019-09-27 17:52:06 +0800549 scanDirectory("./psu-images-valid-version0");
550}
Lei YUffb36532019-10-15 13:55:24 +0800551
552TEST_F(TestItemUpdater, OnUpdateDoneOnTwoPSUsWithSameVersion)
553{
554 // Simulate there are two PSUs with same version, and updated to a new
555 // version
556 constexpr auto psu0 = "/com/example/inventory/psu0";
557 constexpr auto psu1 = "/com/example/inventory/psu1";
558 constexpr auto service = "com.example.Software.Psu";
559 auto version0 = std::string("version0");
560 auto version1 = std::string("version0");
561 auto objPath0 = getObjPath(version0);
562 auto objPath1 = getObjPath(version1);
563
564 EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
565 .WillOnce(Return(std::vector<std::string>({psu0, psu1})));
566 EXPECT_CALL(mockedUtils, getService(_, StrEq(psu0), _))
567 .WillOnce(Return(service));
568 EXPECT_CALL(mockedUtils, getService(_, StrEq(psu1), _))
569 .WillOnce(Return(service));
570 EXPECT_CALL(mockedUtils, getVersion(StrEq(psu0)))
571 .WillOnce(Return(std::string(version0)));
572 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
573 StrEq(PRESENT)))
574 .WillOnce(Return(any(PropertyType(true)))); // present
Faisal Awada760053d2024-05-16 13:31:32 -0500575 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
576 StrEq(MODEL)))
577 .WillOnce(Return(any(PropertyType(std::string("dummyModel0")))));
Lei YUffb36532019-10-15 13:55:24 +0800578 EXPECT_CALL(mockedUtils, getVersion(StrEq(psu1)))
579 .WillOnce(Return(std::string(version1)));
580 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
581 StrEq(PRESENT)))
582 .WillOnce(Return(any(PropertyType(true)))); // present
Faisal Awada760053d2024-05-16 13:31:32 -0500583 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
584 StrEq(MODEL)))
585 .WillOnce(Return(any(PropertyType(std::string("dummyModel1")))));
Lei YUffb36532019-10-15 13:55:24 +0800586
587 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
588
Lei YU1517f5f2019-10-14 16:44:42 +0800589 std::string newVersionId = "NewVersionId";
590 AssociationList associations;
591 auto dummyActivation = std::make_unique<Activation>(
592 mockedBus, dBusPath, newVersionId, "", Activation::Status::Active,
593 associations, "", itemUpdater.get(), itemUpdater.get());
594
Lei YUffb36532019-10-15 13:55:24 +0800595 // Now there is one activation and it has two associations
596 auto& activations = GetActivations();
Lei YU1517f5f2019-10-14 16:44:42 +0800597 activations.emplace(newVersionId, std::move(dummyActivation));
Lei YUffb36532019-10-15 13:55:24 +0800598 auto& activation = activations.find(version0)->second;
599 auto assocs = activation->associations();
600 EXPECT_EQ(2u, assocs.size());
601 EXPECT_EQ(psu0, std::get<2>(assocs[0]));
602 EXPECT_EQ(psu1, std::get<2>(assocs[1]));
603
604 EXPECT_CALL(mockedUtils, isAssociated(StrEq(psu0), _))
605 .WillOnce(Return(true));
Lei YU1517f5f2019-10-14 16:44:42 +0800606 itemUpdater->onUpdateDone(newVersionId, psu0);
Lei YUffb36532019-10-15 13:55:24 +0800607
Manojkiran Eda33cf9f02024-06-17 14:40:44 +0530608 // Now the activation should have one association
Lei YUffb36532019-10-15 13:55:24 +0800609 assocs = activation->associations();
610 EXPECT_EQ(1u, assocs.size());
611 EXPECT_EQ(psu1, std::get<2>(assocs[0]));
612
613 EXPECT_CALL(mockedUtils, isAssociated(StrEq(psu1), _))
614 .WillOnce(Return(true));
Lei YU1517f5f2019-10-14 16:44:42 +0800615 itemUpdater->onUpdateDone(newVersionId, psu1);
Lei YUffb36532019-10-15 13:55:24 +0800616
Lei YU1517f5f2019-10-14 16:44:42 +0800617 // Now the activation shall be erased and only the dummy one is left
618 EXPECT_EQ(1u, activations.size());
619 EXPECT_NE(activations.find(newVersionId), activations.end());
Lei YUffb36532019-10-15 13:55:24 +0800620}
621
622TEST_F(TestItemUpdater, OnUpdateDoneOnTwoPSUsWithDifferentVersion)
623{
624 // Simulate there are two PSUs with different version, and updated to a new
625 // version
626 constexpr auto psu0 = "/com/example/inventory/psu0";
627 constexpr auto psu1 = "/com/example/inventory/psu1";
628 constexpr auto service = "com.example.Software.Psu";
629 auto version0 = std::string("version0");
630 auto version1 = std::string("version1");
631 auto objPath0 = getObjPath(version0);
632 auto objPath1 = getObjPath(version1);
633
634 EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
635 .WillOnce(Return(std::vector<std::string>({psu0, psu1})));
636 EXPECT_CALL(mockedUtils, getService(_, StrEq(psu0), _))
637 .WillOnce(Return(service));
638 EXPECT_CALL(mockedUtils, getService(_, StrEq(psu1), _))
639 .WillOnce(Return(service));
640 EXPECT_CALL(mockedUtils, getVersion(StrEq(psu0)))
641 .WillOnce(Return(std::string(version0)));
642 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
643 StrEq(PRESENT)))
644 .WillOnce(Return(any(PropertyType(true)))); // present
Faisal Awada760053d2024-05-16 13:31:32 -0500645 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
646 StrEq(MODEL)))
647 .WillOnce(Return(any(PropertyType(std::string("dummyModel0")))));
Lei YUffb36532019-10-15 13:55:24 +0800648 EXPECT_CALL(mockedUtils, getVersion(StrEq(psu1)))
649 .WillOnce(Return(std::string(version1)));
650 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
651 StrEq(PRESENT)))
652 .WillOnce(Return(any(PropertyType(true)))); // present
Faisal Awada760053d2024-05-16 13:31:32 -0500653 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
654 StrEq(MODEL)))
655 .WillOnce(Return(any(PropertyType(std::string("dummyModel1")))));
Lei YUffb36532019-10-15 13:55:24 +0800656
657 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
658
Lei YU1517f5f2019-10-14 16:44:42 +0800659 std::string newVersionId = "NewVersionId";
660 AssociationList associations;
661 auto dummyActivation = std::make_unique<Activation>(
662 mockedBus, dBusPath, newVersionId, "", Activation::Status::Active,
663 associations, "", itemUpdater.get(), itemUpdater.get());
664
665 auto& activations = GetActivations();
666 activations.emplace(newVersionId, std::move(dummyActivation));
Lei YUffb36532019-10-15 13:55:24 +0800667
668 EXPECT_CALL(mockedUtils, isAssociated(StrEq(psu0), _))
669 .WillOnce(Return(true));
Lei YU1517f5f2019-10-14 16:44:42 +0800670
671 // After psu0 is done, two activations should be left
672 itemUpdater->onUpdateDone(newVersionId, psu0);
673 EXPECT_EQ(2u, activations.size());
Lei YUffb36532019-10-15 13:55:24 +0800674 const auto& activation1 = activations.find(version1)->second;
675 const auto& assocs1 = activation1->associations();
676 EXPECT_EQ(1u, assocs1.size());
677 EXPECT_EQ(psu1, std::get<2>(assocs1[0]));
678
679 EXPECT_CALL(mockedUtils, isAssociated(StrEq(psu1), _))
680 .WillOnce(Return(true));
Lei YU1517f5f2019-10-14 16:44:42 +0800681 // After psu1 is done, only the dummy activation should be left
682 itemUpdater->onUpdateDone(newVersionId, psu1);
683 EXPECT_EQ(1u, activations.size());
684 EXPECT_NE(activations.find(newVersionId), activations.end());
685}
686
687TEST_F(TestItemUpdater, OnOnePSURemovedAndAddedWithOldVersion)
688{
689 constexpr auto psuPath = "/com/example/inventory/psu0";
690 constexpr auto service = "com.example.Software.Psu";
691 constexpr auto version = "version0";
692 std::string versionId =
693 version; // In testing versionId is the same as version
694 std::string objPath = getObjPath(version);
695 ON_CALL(mockedUtils, getPSUInventoryPath(_))
696 .WillByDefault(Return(std::vector<std::string>({psuPath})));
Faisal Awada760053d2024-05-16 13:31:32 -0500697 EXPECT_CALL(mockedUtils, getService(_, StrEq(psuPath), _))
698 .WillOnce(Return(service))
699 .WillOnce(Return(service));
Lei YU1517f5f2019-10-14 16:44:42 +0800700 EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
701 .WillOnce(Return(std::string(version)));
702 ON_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath), _,
703 StrEq(PRESENT)))
704 .WillByDefault(Return(any(PropertyType(true)))); // present
Faisal Awada760053d2024-05-16 13:31:32 -0500705 ON_CALL(mockedUtils,
706 getPropertyImpl(_, StrEq(service), StrEq(psuPath), _, StrEq(MODEL)))
707 .WillByDefault(Return(any(PropertyType(std::string("dummyModel")))));
Lei YU1517f5f2019-10-14 16:44:42 +0800708 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
709
710 // Add an association to simulate that it has image in BMC filesystem
711 auto& activation = GetActivations().find(versionId)->second;
712 auto assocs = activation->associations();
713 assocs.emplace_back(ACTIVATION_FWD_ASSOCIATION, ACTIVATION_REV_ASSOCIATION,
714 "SomePath");
715 activation->associations(assocs);
716 activation->path("SomeFilePath");
717
718 onPsuInventoryChanged(psuPath, propRemoved);
719
720 // On PSU inserted, it checks and finds a newer version
721 auto oldVersion = "old-version";
722 EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
723 .WillOnce(Return(std::string(oldVersion)));
724 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
725 _, StrEq(MANUFACTURER)))
726 .WillOnce(
727 Return(any(PropertyType(std::string(""))))); // Checking compatible
728 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
729 _, StrEq(MODEL)))
730 .WillOnce(
731 Return(any(PropertyType(std::string(""))))); // Checking compatible
732 std::set<std::string> expectedVersions = {version, oldVersion};
733 EXPECT_CALL(mockedUtils, getLatestVersion(ContainerEq(expectedVersions)))
734 .WillOnce(Return(version));
735 ON_CALL(mockedUtils, isAssociated(StrEq(psuPath), _))
736 .WillByDefault(Return(false));
737 EXPECT_CALL(sdbusMock, sd_bus_message_new_method_call(_, _, _, _, _,
738 StrEq("StartUnit")))
Lei YU8afeee52019-10-21 15:25:35 +0800739 .Times(3); // There are 3 systemd units are started, enable bmc reboot
740 // guard, start activation, and disable bmc reboot guard
Lei YU1517f5f2019-10-14 16:44:42 +0800741 onPsuInventoryChanged(psuPath, propAdded);
742 onPsuInventoryChanged(psuPath, propModel);
Lei YUffb36532019-10-15 13:55:24 +0800743}