blob: 6a0a08e71dac22db3f9c7ff74e4d7f38a81de19b [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
Lei YUf77189f2019-08-07 14:26:30 +080025 TestItemUpdater() :
26 mockedUtils(
27 reinterpret_cast<const utils::MockedUtils&>(utils::getUtils()))
28 {
29 ON_CALL(mockedUtils, getVersionId(_)).WillByDefault(ReturnArg<0>());
Lei YUff83c2a2019-09-12 13:55:18 +080030 ON_CALL(mockedUtils, getPropertyImpl(_, _, _, _, StrEq(PRESENT)))
31 .WillByDefault(Return(any(PropertyType(true))));
Lei YUf77189f2019-08-07 14:26:30 +080032 }
33
34 ~TestItemUpdater()
35 {
Lei YUc09155b2019-10-11 17:30:48 +080036 utils::freeUtils();
Lei YUf77189f2019-08-07 14:26:30 +080037 }
38
Lei YU1517f5f2019-10-14 16:44:42 +080039 auto& GetActivations()
Lei YUf77189f2019-08-07 14:26:30 +080040 {
41 return itemUpdater->activations;
42 }
43
44 std::string getObjPath(const std::string& versionId)
45 {
46 return std::string(dBusPath) + "/" + versionId;
47 }
48
Lei YUa2c2cd72019-08-09 15:54:10 +080049 void onPsuInventoryChanged(const std::string& psuPath,
50 const Properties& properties)
51 {
52 itemUpdater->onPsuInventoryChanged(psuPath, properties);
53 }
54
Lei YU58c26e32019-09-27 17:52:06 +080055 void scanDirectory(const fs::path& p)
56 {
57 itemUpdater->scanDirectory(p);
58 }
59
Lei YUf77189f2019-08-07 14:26:30 +080060 static constexpr auto dBusPath = SOFTWARE_OBJPATH;
61 sdbusplus::SdBusMock sdbusMock;
Patrick Williams374fae52022-07-22 19:26:55 -050062 sdbusplus::bus_t mockedBus = sdbusplus::get_mocked_new(&sdbusMock);
Lei YUf77189f2019-08-07 14:26:30 +080063 const utils::MockedUtils& mockedUtils;
64 std::unique_ptr<ItemUpdater> itemUpdater;
Lei YU1517f5f2019-10-14 16:44:42 +080065 Properties propAdded{{PRESENT, PropertyType(true)}};
66 Properties propRemoved{{PRESENT, PropertyType(false)}};
67 Properties propModel{{MODEL, PropertyType(std::string("dummyModel"))}};
Lei YUf77189f2019-08-07 14:26:30 +080068};
69
70TEST_F(TestItemUpdater, ctordtor)
71{
Lei YU65207482019-10-11 16:39:36 +080072 EXPECT_CALL(mockedUtils, getLatestVersion(_)).Times(1);
Lei YUf77189f2019-08-07 14:26:30 +080073 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
74}
75
76TEST_F(TestItemUpdater, NotCreateObjectOnNotPresent)
77{
78 constexpr auto psuPath = "/com/example/inventory/psu0";
79 constexpr auto service = "com.example.Software.Psu";
80 constexpr auto version = "version0";
81 std::string objPath = getObjPath(version);
82 EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
83 .WillOnce(Return(std::vector<std::string>({psuPath})));
84 EXPECT_CALL(mockedUtils, getService(_, StrEq(psuPath), _))
85 .WillOnce(Return(service));
Lei YU5f3584d2019-08-27 16:28:53 +080086 EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
87 .WillOnce(Return(std::string(version)));
Lei YUf77189f2019-08-07 14:26:30 +080088 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
89 _, StrEq(PRESENT)))
90 .WillOnce(Return(any(PropertyType(false)))); // not present
Faisal Awada760053d2024-05-16 13:31:32 -050091 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
92 _, StrEq(MODEL)))
93 .WillOnce(Return(any(PropertyType(std::string("")))));
Lei YUf77189f2019-08-07 14:26:30 +080094
95 // The item updater itself
96 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
97 .Times(1);
98
99 // No activation/version objects are created
100 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
101 .Times(0);
102 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
103}
104
105TEST_F(TestItemUpdater, CreateOnePSUOnPresent)
106{
107 constexpr auto psuPath = "/com/example/inventory/psu0";
108 constexpr auto service = "com.example.Software.Psu";
109 constexpr auto version = "version0";
110 std::string objPath = getObjPath(version);
111 EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
112 .WillOnce(Return(std::vector<std::string>({psuPath})));
113 EXPECT_CALL(mockedUtils, getService(_, StrEq(psuPath), _))
114 .WillOnce(Return(service));
Lei YU5f3584d2019-08-27 16:28:53 +0800115 EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
116 .WillOnce(Return(std::string(version)));
Lei YUf77189f2019-08-07 14:26:30 +0800117 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
118 _, StrEq(PRESENT)))
119 .WillOnce(Return(any(PropertyType(true)))); // present
Faisal Awada760053d2024-05-16 13:31:32 -0500120 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
121 _, StrEq(MODEL)))
122 .WillOnce(Return(any(PropertyType(std::string("dummyModel")))));
Lei YUf77189f2019-08-07 14:26:30 +0800123
124 // The item updater itself
125 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
126 .Times(1);
127
128 // activation and version object will be added
129 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
130 .Times(2);
131 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
132}
133
134TEST_F(TestItemUpdater, CreateTwoPSUsWithSameVersion)
135{
136 constexpr auto psu0 = "/com/example/inventory/psu0";
137 constexpr auto psu1 = "/com/example/inventory/psu1";
138 constexpr auto service = "com.example.Software.Psu";
139 auto version0 = std::string("version0");
140 auto version1 = std::string("version0");
141 auto objPath0 = getObjPath(version0);
142 auto objPath1 = getObjPath(version1);
143
144 EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
145 .WillOnce(Return(std::vector<std::string>({psu0, psu1})));
146 EXPECT_CALL(mockedUtils, getService(_, StrEq(psu0), _))
147 .WillOnce(Return(service));
148 EXPECT_CALL(mockedUtils, getService(_, StrEq(psu1), _))
149 .WillOnce(Return(service));
Lei YU5f3584d2019-08-27 16:28:53 +0800150 EXPECT_CALL(mockedUtils, getVersion(StrEq(psu0)))
151 .WillOnce(Return(std::string(version0)));
Lei YUf77189f2019-08-07 14:26:30 +0800152 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
153 StrEq(PRESENT)))
154 .WillOnce(Return(any(PropertyType(true)))); // present
Faisal Awada760053d2024-05-16 13:31:32 -0500155 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
156 StrEq(MODEL)))
157 .WillOnce(Return(any(PropertyType(std::string("dummyModel0")))));
Lei YU5f3584d2019-08-27 16:28:53 +0800158 EXPECT_CALL(mockedUtils, getVersion(StrEq(psu1)))
159 .WillOnce(Return(std::string(version1)));
Lei YUf77189f2019-08-07 14:26:30 +0800160 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
161 StrEq(PRESENT)))
162 .WillOnce(Return(any(PropertyType(true)))); // present
Faisal Awada760053d2024-05-16 13:31:32 -0500163 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
164 StrEq(MODEL)))
165 .WillOnce(Return(any(PropertyType(std::string("dummyModel1")))));
Lei YUf77189f2019-08-07 14:26:30 +0800166
167 // The item updater itself
168 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
169 .Times(1);
170
171 // activation and version object will be added
172 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath0)))
173 .Times(2);
174 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
175
176 // Verify there is only one activation and it has two associations
177 const auto& activations = GetActivations();
178 EXPECT_EQ(1u, activations.size());
179 const auto& activation = activations.find(version0)->second;
180 const auto& assocs = activation->associations();
181 EXPECT_EQ(2u, assocs.size());
182 EXPECT_EQ(psu0, std::get<2>(assocs[0]));
183 EXPECT_EQ(psu1, std::get<2>(assocs[1]));
184}
185
186TEST_F(TestItemUpdater, CreateTwoPSUsWithDifferentVersion)
187{
188 constexpr auto psu0 = "/com/example/inventory/psu0";
189 constexpr auto psu1 = "/com/example/inventory/psu1";
190 constexpr auto service = "com.example.Software.Psu";
191 auto version0 = std::string("version0");
192 auto version1 = std::string("version1");
193 auto objPath0 = getObjPath(version0);
194 auto objPath1 = getObjPath(version1);
195
196 EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
197 .WillOnce(Return(std::vector<std::string>({psu0, psu1})));
198 EXPECT_CALL(mockedUtils, getService(_, StrEq(psu0), _))
199 .WillOnce(Return(service));
200 EXPECT_CALL(mockedUtils, getService(_, StrEq(psu1), _))
201 .WillOnce(Return(service));
Lei YU5f3584d2019-08-27 16:28:53 +0800202 EXPECT_CALL(mockedUtils, getVersion(StrEq(psu0)))
203 .WillOnce(Return(std::string(version0)));
Lei YUf77189f2019-08-07 14:26:30 +0800204 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
205 StrEq(PRESENT)))
206 .WillOnce(Return(any(PropertyType(true)))); // present
Faisal Awada760053d2024-05-16 13:31:32 -0500207 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
208 StrEq(MODEL)))
209 .WillOnce(Return(any(PropertyType(std::string("dummyModel0")))));
Lei YU5f3584d2019-08-27 16:28:53 +0800210 EXPECT_CALL(mockedUtils, getVersion(StrEq(psu1)))
211 .WillOnce(Return(std::string(version1)));
Lei YUf77189f2019-08-07 14:26:30 +0800212 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
213 StrEq(PRESENT)))
214 .WillOnce(Return(any(PropertyType(true)))); // present
Faisal Awada760053d2024-05-16 13:31:32 -0500215 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
216 StrEq(MODEL)))
217 .WillOnce(Return(any(PropertyType(std::string("dummyModel1")))));
Lei YUf77189f2019-08-07 14:26:30 +0800218
219 // The item updater itself
220 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
221 .Times(1);
222
223 // two new activation and version objects will be added
224 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath0)))
225 .Times(2);
226 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath1)))
227 .Times(2);
228 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
229
230 // Verify there are two activations and each with one association
231 const auto& activations = GetActivations();
232 EXPECT_EQ(2u, activations.size());
233 const auto& activation0 = activations.find(version0)->second;
234 const auto& assocs0 = activation0->associations();
235 EXPECT_EQ(1u, assocs0.size());
236 EXPECT_EQ(psu0, std::get<2>(assocs0[0]));
237
238 const auto& activation1 = activations.find(version1)->second;
239 const auto& assocs1 = activation1->associations();
240 EXPECT_EQ(1u, assocs1.size());
241 EXPECT_EQ(psu1, std::get<2>(assocs1[0]));
242}
Lei YUa2c2cd72019-08-09 15:54:10 +0800243
244TEST_F(TestItemUpdater, OnOnePSURemoved)
245{
246 constexpr auto psuPath = "/com/example/inventory/psu0";
247 constexpr auto service = "com.example.Software.Psu";
248 constexpr auto version = "version0";
249 std::string objPath = getObjPath(version);
250 EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
251 .WillOnce(Return(std::vector<std::string>({psuPath})));
252 EXPECT_CALL(mockedUtils, getService(_, StrEq(psuPath), _))
253 .WillOnce(Return(service));
Lei YU5f3584d2019-08-27 16:28:53 +0800254 EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
255 .WillOnce(Return(std::string(version)));
Lei YUa2c2cd72019-08-09 15:54:10 +0800256 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
257 _, StrEq(PRESENT)))
258 .WillOnce(Return(any(PropertyType(true)))); // present
Faisal Awada760053d2024-05-16 13:31:32 -0500259 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
260 _, StrEq(MODEL)))
261 .WillOnce(Return(any(PropertyType(std::string("dummyModel")))));
Lei YUa2c2cd72019-08-09 15:54:10 +0800262
263 // The item updater itself
264 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
265 .Times(1);
266
267 // activation and version object will be added
268 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
269 .Times(2);
270 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
271
272 // the activation and version object will be removed
273 Properties p{{PRESENT, PropertyType(false)}};
274 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(objPath)))
275 .Times(2);
276 onPsuInventoryChanged(psuPath, p);
277
278 // on exit, item updater is removed
279 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(dBusPath)))
280 .Times(1);
281}
282
283TEST_F(TestItemUpdater, OnOnePSUAdded)
284{
285 constexpr auto psuPath = "/com/example/inventory/psu0";
286 constexpr auto service = "com.example.Software.Psu";
287 constexpr auto version = "version0";
288 std::string objPath = getObjPath(version);
289 EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
290 .WillOnce(Return(std::vector<std::string>({psuPath})));
291 EXPECT_CALL(mockedUtils, getService(_, StrEq(psuPath), _))
292 .WillOnce(Return(service));
Lei YU5f3584d2019-08-27 16:28:53 +0800293 EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
294 .WillOnce(Return(std::string(version)));
Lei YUa2c2cd72019-08-09 15:54:10 +0800295 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
296 _, StrEq(PRESENT)))
297 .WillOnce(Return(any(PropertyType(false)))); // not present
Faisal Awada760053d2024-05-16 13:31:32 -0500298 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
299 _, StrEq(MODEL)))
300 .WillOnce(Return(any(PropertyType(std::string("")))));
Lei YUa2c2cd72019-08-09 15:54:10 +0800301
302 // The item updater itself
303 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
304 .Times(1);
305
306 // No activation/version objects are created
307 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
308 .Times(0);
309 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
310
311 // The PSU is present and version is added in a single call
Lei YU1517f5f2019-10-14 16:44:42 +0800312 Properties propAddedAndModel{
313 {PRESENT, PropertyType(true)},
314 {MODEL, PropertyType(std::string("testModel"))}};
Lei YUdcaf8932019-09-09 16:09:35 +0800315 EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
316 .WillOnce(Return(std::string(version)));
Lei YUa2c2cd72019-08-09 15:54:10 +0800317 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
318 .Times(2);
Lei YU1517f5f2019-10-14 16:44:42 +0800319 onPsuInventoryChanged(psuPath, propAddedAndModel);
Lei YUa2c2cd72019-08-09 15:54:10 +0800320}
321
Lei YU1517f5f2019-10-14 16:44:42 +0800322TEST_F(TestItemUpdater, OnOnePSURemovedAndAddedWithLatestVersion)
Lei YUa2c2cd72019-08-09 15:54:10 +0800323{
324 constexpr auto psuPath = "/com/example/inventory/psu0";
325 constexpr auto service = "com.example.Software.Psu";
326 constexpr auto version = "version0";
327 std::string objPath = getObjPath(version);
Lei YU1517f5f2019-10-14 16:44:42 +0800328 ON_CALL(mockedUtils, getPSUInventoryPath(_))
329 .WillByDefault(Return(std::vector<std::string>({psuPath})));
Lei YUa2c2cd72019-08-09 15:54:10 +0800330 EXPECT_CALL(mockedUtils, getService(_, StrEq(psuPath), _))
331 .WillOnce(Return(service));
Lei YU5f3584d2019-08-27 16:28:53 +0800332 EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
333 .WillOnce(Return(std::string(version)));
Lei YUa2c2cd72019-08-09 15:54:10 +0800334 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
335 _, StrEq(PRESENT)))
336 .WillOnce(Return(any(PropertyType(true)))); // present
Faisal Awada760053d2024-05-16 13:31:32 -0500337 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
338 _, StrEq(MODEL)))
339 .WillOnce(Return(any(PropertyType(std::string("dummyModel")))));
Lei YUa2c2cd72019-08-09 15:54:10 +0800340
341 // The item updater itself
342 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
343 .Times(1);
344
345 // activation and version object will be added
346 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
347 .Times(2);
348 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
349
350 // the activation and version object will be removed
Lei YUa2c2cd72019-08-09 15:54:10 +0800351 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(objPath)))
352 .Times(2);
353 onPsuInventoryChanged(psuPath, propRemoved);
354
Lei YUdcaf8932019-09-09 16:09:35 +0800355 EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
356 .WillOnce(Return(std::string(version)));
Lei YUa2c2cd72019-08-09 15:54:10 +0800357 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
358 .Times(2);
Lei YU1517f5f2019-10-14 16:44:42 +0800359
360 // On PSU inserted, it shall check if it's the latest version
361 std::set<std::string> expectedVersions = {version};
362 EXPECT_CALL(mockedUtils, getLatestVersion(ContainerEq(expectedVersions)))
363 .WillOnce(Return(version));
364 EXPECT_CALL(mockedUtils, isAssociated(StrEq(psuPath), _))
365 .WillOnce(Return(true));
366 EXPECT_CALL(sdbusMock, sd_bus_message_new_method_call(_, _, _, _, _,
367 StrEq("StartUnit")))
368 .Times(0);
Lei YUa2c2cd72019-08-09 15:54:10 +0800369 onPsuInventoryChanged(psuPath, propAdded);
Lei YU1517f5f2019-10-14 16:44:42 +0800370 onPsuInventoryChanged(psuPath, propModel);
Lei YUa2c2cd72019-08-09 15:54:10 +0800371
372 // on exit, objects are removed
373 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(objPath)))
374 .Times(2);
375 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(dBusPath)))
376 .Times(1);
377}
378
379TEST_F(TestItemUpdater,
380 TwoPSUsWithSameVersionRemovedAndAddedWithDifferntVersion)
381{
382 constexpr auto psu0 = "/com/example/inventory/psu0";
383 constexpr auto psu1 = "/com/example/inventory/psu1";
384 constexpr auto service = "com.example.Software.Psu";
385 auto version0 = std::string("version0");
386 auto version1 = std::string("version0");
387 auto objPath0 = getObjPath(version0);
388 auto objPath1 = getObjPath(version1);
389
390 EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
391 .WillOnce(Return(std::vector<std::string>({psu0, psu1})));
392 EXPECT_CALL(mockedUtils, getService(_, StrEq(psu0), _))
393 .WillOnce(Return(service));
394 EXPECT_CALL(mockedUtils, getService(_, StrEq(psu1), _))
395 .WillOnce(Return(service));
Lei YU5f3584d2019-08-27 16:28:53 +0800396 EXPECT_CALL(mockedUtils, getVersion(StrEq(psu0)))
397 .WillOnce(Return(std::string(version0)));
Lei YUa2c2cd72019-08-09 15:54:10 +0800398 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
399 StrEq(PRESENT)))
400 .WillOnce(Return(any(PropertyType(true)))); // present
Faisal Awada760053d2024-05-16 13:31:32 -0500401 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
402 StrEq(MODEL)))
403 .WillOnce(Return(any(PropertyType(std::string("dummyModel0")))));
Lei YU5f3584d2019-08-27 16:28:53 +0800404 EXPECT_CALL(mockedUtils, getVersion(StrEq(psu1)))
405 .WillOnce(Return(std::string(version1)));
Lei YUa2c2cd72019-08-09 15:54:10 +0800406 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
407 StrEq(PRESENT)))
408 .WillOnce(Return(any(PropertyType(true)))); // present
Faisal Awada760053d2024-05-16 13:31:32 -0500409 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
410 StrEq(MODEL)))
411 .WillOnce(Return(any(PropertyType(std::string("dummyModel1")))));
Lei YUa2c2cd72019-08-09 15:54:10 +0800412
413 // The item updater itself
414 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
415 .Times(1);
416
417 // activation and version object will be added
418 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath0)))
419 .Times(2);
420 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
421
422 // Verify there is only one activation and it has two associations
423 const auto& activations = GetActivations();
424 EXPECT_EQ(1u, activations.size());
425 const auto& activation = activations.find(version0)->second;
426 auto assocs = activation->associations();
427 EXPECT_EQ(2u, assocs.size());
428 EXPECT_EQ(psu0, std::get<2>(assocs[0]));
429 EXPECT_EQ(psu1, std::get<2>(assocs[1]));
430
431 // PSU0 is removed, only associations shall be updated
Lei YUa2c2cd72019-08-09 15:54:10 +0800432 onPsuInventoryChanged(psu0, propRemoved);
433 assocs = activation->associations();
434 EXPECT_EQ(1u, assocs.size());
435 EXPECT_EQ(psu1, std::get<2>(assocs[0]));
436
437 // PSU1 is removed, the activation and version object shall be removed
438 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(objPath0)))
439 .Times(2);
440 onPsuInventoryChanged(psu1, propRemoved);
441
442 // Add PSU0 and PSU1 back, but PSU1 with a different version
443 version1 = "version1";
444 objPath1 = getObjPath(version1);
Lei YUdcaf8932019-09-09 16:09:35 +0800445 EXPECT_CALL(mockedUtils, getVersion(StrEq(psu0)))
446 .WillOnce(Return(std::string(version0)));
447 EXPECT_CALL(mockedUtils, getVersion(StrEq(psu1)))
448 .WillOnce(Return(std::string(version1)));
Lei YUa2c2cd72019-08-09 15:54:10 +0800449 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath0)))
450 .Times(2);
451 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath1)))
452 .Times(2);
Lei YU1517f5f2019-10-14 16:44:42 +0800453 onPsuInventoryChanged(psu0, propAdded);
454 onPsuInventoryChanged(psu1, propModel);
455 onPsuInventoryChanged(psu1, propAdded);
456 onPsuInventoryChanged(psu0, propModel);
Lei YUa2c2cd72019-08-09 15:54:10 +0800457
458 // on exit, objects are removed
459 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(objPath0)))
460 .Times(2);
461 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(objPath1)))
462 .Times(2);
463 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(dBusPath)))
464 .Times(1);
465}
Lei YU58c26e32019-09-27 17:52:06 +0800466
467TEST_F(TestItemUpdater, scanDirOnNoPSU)
468{
469 constexpr auto psuPath = "/com/example/inventory/psu0";
470 constexpr auto service = "com.example.Software.Psu";
471 constexpr auto version = "version0";
472 std::string objPath = getObjPath(version);
473 EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
474 .WillOnce(Return(std::vector<std::string>({psuPath})));
475 EXPECT_CALL(mockedUtils, getService(_, StrEq(psuPath), _))
476 .WillOnce(Return(service));
477 EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
478 .WillOnce(Return(std::string(version)));
479 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
480 _, StrEq(PRESENT)))
481 .WillOnce(Return(any(PropertyType(false)))); // not present
Faisal Awada760053d2024-05-16 13:31:32 -0500482 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
483 _, StrEq(MODEL)))
484 .WillOnce(Return(any(PropertyType(std::string("")))));
Lei YU58c26e32019-09-27 17:52:06 +0800485
486 // The item updater itself
487 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
488 .Times(1);
489
490 // No activation/version objects are created
491 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
492 .Times(0);
493 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
494
495 // The valid image in test/psu-images-one-valid-one-invalid/model-1/
496 auto objPathValid = getObjPath("psu-test.v0.4");
497 auto objPathInvalid = getObjPath("psu-test.v0.5");
498 // activation and version object will be added on scan dir
499 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPathValid)))
Faisal Awada760053d2024-05-16 13:31:32 -0500500 .Times(0);
Lei YU58c26e32019-09-27 17:52:06 +0800501 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPathInvalid)))
502 .Times(0);
503 scanDirectory("./psu-images-one-valid-one-invalid");
504}
505
506TEST_F(TestItemUpdater, scanDirOnSamePSUVersion)
507{
508 constexpr auto psuPath = "/com/example/inventory/psu0";
509 constexpr auto service = "com.example.Software.Psu";
510 constexpr auto version = "version0";
511 std::string objPath = getObjPath(version);
512 EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
513 .WillOnce(Return(std::vector<std::string>({psuPath})));
514 EXPECT_CALL(mockedUtils, getService(_, StrEq(psuPath), _))
515 .WillOnce(Return(service));
516 EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
517 .WillOnce(Return(std::string(version)));
518 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
519 _, StrEq(PRESENT)))
520 .WillOnce(Return(any(PropertyType(true)))); // present
Faisal Awada760053d2024-05-16 13:31:32 -0500521 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
522 _, StrEq(MODEL)))
523 .WillOnce(Return(any(PropertyType(std::string("dummyModel")))));
Lei YU58c26e32019-09-27 17:52:06 +0800524
525 // The item updater itself
526 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
527 .Times(1);
528
529 // activation and version object will be added
530 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
531 .Times(2);
532 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
533
534 // The valid image in test/psu-images-valid-version0/model-3/ has the same
535 // version as the running PSU, so no objects will be created, but only the
536 // path will be set to the version object
537 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
538 .Times(0);
539 EXPECT_CALL(sdbusMock, sd_bus_emit_properties_changed_strv(
540 _, StrEq(objPath),
541 StrEq("xyz.openbmc_project.Common.FilePath"),
542 Pointee(StrEq("Path"))))
Faisal Awada760053d2024-05-16 13:31:32 -0500543 .Times(0);
Lei YU58c26e32019-09-27 17:52:06 +0800544 scanDirectory("./psu-images-valid-version0");
545}
Lei YUffb36532019-10-15 13:55:24 +0800546
547TEST_F(TestItemUpdater, OnUpdateDoneOnTwoPSUsWithSameVersion)
548{
549 // Simulate there are two PSUs with same version, and updated to a new
550 // version
551 constexpr auto psu0 = "/com/example/inventory/psu0";
552 constexpr auto psu1 = "/com/example/inventory/psu1";
553 constexpr auto service = "com.example.Software.Psu";
554 auto version0 = std::string("version0");
555 auto version1 = std::string("version0");
556 auto objPath0 = getObjPath(version0);
557 auto objPath1 = getObjPath(version1);
558
559 EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
560 .WillOnce(Return(std::vector<std::string>({psu0, psu1})));
561 EXPECT_CALL(mockedUtils, getService(_, StrEq(psu0), _))
562 .WillOnce(Return(service));
563 EXPECT_CALL(mockedUtils, getService(_, StrEq(psu1), _))
564 .WillOnce(Return(service));
565 EXPECT_CALL(mockedUtils, getVersion(StrEq(psu0)))
566 .WillOnce(Return(std::string(version0)));
567 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
568 StrEq(PRESENT)))
569 .WillOnce(Return(any(PropertyType(true)))); // present
Faisal Awada760053d2024-05-16 13:31:32 -0500570 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
571 StrEq(MODEL)))
572 .WillOnce(Return(any(PropertyType(std::string("dummyModel0")))));
Lei YUffb36532019-10-15 13:55:24 +0800573 EXPECT_CALL(mockedUtils, getVersion(StrEq(psu1)))
574 .WillOnce(Return(std::string(version1)));
575 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
576 StrEq(PRESENT)))
577 .WillOnce(Return(any(PropertyType(true)))); // present
Faisal Awada760053d2024-05-16 13:31:32 -0500578 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
579 StrEq(MODEL)))
580 .WillOnce(Return(any(PropertyType(std::string("dummyModel1")))));
Lei YUffb36532019-10-15 13:55:24 +0800581
582 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
583
Lei YU1517f5f2019-10-14 16:44:42 +0800584 std::string newVersionId = "NewVersionId";
585 AssociationList associations;
586 auto dummyActivation = std::make_unique<Activation>(
587 mockedBus, dBusPath, newVersionId, "", Activation::Status::Active,
588 associations, "", itemUpdater.get(), itemUpdater.get());
589
Lei YUffb36532019-10-15 13:55:24 +0800590 // Now there is one activation and it has two associations
591 auto& activations = GetActivations();
Lei YU1517f5f2019-10-14 16:44:42 +0800592 activations.emplace(newVersionId, std::move(dummyActivation));
Lei YUffb36532019-10-15 13:55:24 +0800593 auto& activation = activations.find(version0)->second;
594 auto assocs = activation->associations();
595 EXPECT_EQ(2u, assocs.size());
596 EXPECT_EQ(psu0, std::get<2>(assocs[0]));
597 EXPECT_EQ(psu1, std::get<2>(assocs[1]));
598
599 EXPECT_CALL(mockedUtils, isAssociated(StrEq(psu0), _))
600 .WillOnce(Return(true));
Lei YU1517f5f2019-10-14 16:44:42 +0800601 itemUpdater->onUpdateDone(newVersionId, psu0);
Lei YUffb36532019-10-15 13:55:24 +0800602
Manojkiran Eda33cf9f02024-06-17 14:40:44 +0530603 // Now the activation should have one association
Lei YUffb36532019-10-15 13:55:24 +0800604 assocs = activation->associations();
605 EXPECT_EQ(1u, assocs.size());
606 EXPECT_EQ(psu1, std::get<2>(assocs[0]));
607
608 EXPECT_CALL(mockedUtils, isAssociated(StrEq(psu1), _))
609 .WillOnce(Return(true));
Lei YU1517f5f2019-10-14 16:44:42 +0800610 itemUpdater->onUpdateDone(newVersionId, psu1);
Lei YUffb36532019-10-15 13:55:24 +0800611
Lei YU1517f5f2019-10-14 16:44:42 +0800612 // Now the activation shall be erased and only the dummy one is left
613 EXPECT_EQ(1u, activations.size());
614 EXPECT_NE(activations.find(newVersionId), activations.end());
Lei YUffb36532019-10-15 13:55:24 +0800615}
616
617TEST_F(TestItemUpdater, OnUpdateDoneOnTwoPSUsWithDifferentVersion)
618{
619 // Simulate there are two PSUs with different version, and updated to a new
620 // version
621 constexpr auto psu0 = "/com/example/inventory/psu0";
622 constexpr auto psu1 = "/com/example/inventory/psu1";
623 constexpr auto service = "com.example.Software.Psu";
624 auto version0 = std::string("version0");
625 auto version1 = std::string("version1");
626 auto objPath0 = getObjPath(version0);
627 auto objPath1 = getObjPath(version1);
628
629 EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
630 .WillOnce(Return(std::vector<std::string>({psu0, psu1})));
631 EXPECT_CALL(mockedUtils, getService(_, StrEq(psu0), _))
632 .WillOnce(Return(service));
633 EXPECT_CALL(mockedUtils, getService(_, StrEq(psu1), _))
634 .WillOnce(Return(service));
635 EXPECT_CALL(mockedUtils, getVersion(StrEq(psu0)))
636 .WillOnce(Return(std::string(version0)));
637 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
638 StrEq(PRESENT)))
639 .WillOnce(Return(any(PropertyType(true)))); // present
Faisal Awada760053d2024-05-16 13:31:32 -0500640 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
641 StrEq(MODEL)))
642 .WillOnce(Return(any(PropertyType(std::string("dummyModel0")))));
Lei YUffb36532019-10-15 13:55:24 +0800643 EXPECT_CALL(mockedUtils, getVersion(StrEq(psu1)))
644 .WillOnce(Return(std::string(version1)));
645 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
646 StrEq(PRESENT)))
647 .WillOnce(Return(any(PropertyType(true)))); // present
Faisal Awada760053d2024-05-16 13:31:32 -0500648 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
649 StrEq(MODEL)))
650 .WillOnce(Return(any(PropertyType(std::string("dummyModel1")))));
Lei YUffb36532019-10-15 13:55:24 +0800651
652 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
653
Lei YU1517f5f2019-10-14 16:44:42 +0800654 std::string newVersionId = "NewVersionId";
655 AssociationList associations;
656 auto dummyActivation = std::make_unique<Activation>(
657 mockedBus, dBusPath, newVersionId, "", Activation::Status::Active,
658 associations, "", itemUpdater.get(), itemUpdater.get());
659
660 auto& activations = GetActivations();
661 activations.emplace(newVersionId, std::move(dummyActivation));
Lei YUffb36532019-10-15 13:55:24 +0800662
663 EXPECT_CALL(mockedUtils, isAssociated(StrEq(psu0), _))
664 .WillOnce(Return(true));
Lei YU1517f5f2019-10-14 16:44:42 +0800665
666 // After psu0 is done, two activations should be left
667 itemUpdater->onUpdateDone(newVersionId, psu0);
668 EXPECT_EQ(2u, activations.size());
Lei YUffb36532019-10-15 13:55:24 +0800669 const auto& activation1 = activations.find(version1)->second;
670 const auto& assocs1 = activation1->associations();
671 EXPECT_EQ(1u, assocs1.size());
672 EXPECT_EQ(psu1, std::get<2>(assocs1[0]));
673
674 EXPECT_CALL(mockedUtils, isAssociated(StrEq(psu1), _))
675 .WillOnce(Return(true));
Lei YU1517f5f2019-10-14 16:44:42 +0800676 // After psu1 is done, only the dummy activation should be left
677 itemUpdater->onUpdateDone(newVersionId, psu1);
678 EXPECT_EQ(1u, activations.size());
679 EXPECT_NE(activations.find(newVersionId), activations.end());
680}
681
682TEST_F(TestItemUpdater, OnOnePSURemovedAndAddedWithOldVersion)
683{
684 constexpr auto psuPath = "/com/example/inventory/psu0";
685 constexpr auto service = "com.example.Software.Psu";
686 constexpr auto version = "version0";
687 std::string versionId =
688 version; // In testing versionId is the same as version
689 std::string objPath = getObjPath(version);
690 ON_CALL(mockedUtils, getPSUInventoryPath(_))
691 .WillByDefault(Return(std::vector<std::string>({psuPath})));
Faisal Awada760053d2024-05-16 13:31:32 -0500692 EXPECT_CALL(mockedUtils, getService(_, StrEq(psuPath), _))
693 .WillOnce(Return(service))
694 .WillOnce(Return(service));
Lei YU1517f5f2019-10-14 16:44:42 +0800695 EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
696 .WillOnce(Return(std::string(version)));
697 ON_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath), _,
698 StrEq(PRESENT)))
699 .WillByDefault(Return(any(PropertyType(true)))); // present
Faisal Awada760053d2024-05-16 13:31:32 -0500700 ON_CALL(mockedUtils,
701 getPropertyImpl(_, StrEq(service), StrEq(psuPath), _, StrEq(MODEL)))
702 .WillByDefault(Return(any(PropertyType(std::string("dummyModel")))));
Lei YU1517f5f2019-10-14 16:44:42 +0800703 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
704
705 // Add an association to simulate that it has image in BMC filesystem
706 auto& activation = GetActivations().find(versionId)->second;
707 auto assocs = activation->associations();
708 assocs.emplace_back(ACTIVATION_FWD_ASSOCIATION, ACTIVATION_REV_ASSOCIATION,
709 "SomePath");
710 activation->associations(assocs);
711 activation->path("SomeFilePath");
712
713 onPsuInventoryChanged(psuPath, propRemoved);
714
715 // On PSU inserted, it checks and finds a newer version
716 auto oldVersion = "old-version";
717 EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
718 .WillOnce(Return(std::string(oldVersion)));
719 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
720 _, StrEq(MANUFACTURER)))
721 .WillOnce(
722 Return(any(PropertyType(std::string(""))))); // Checking compatible
723 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
724 _, StrEq(MODEL)))
725 .WillOnce(
726 Return(any(PropertyType(std::string(""))))); // Checking compatible
727 std::set<std::string> expectedVersions = {version, oldVersion};
728 EXPECT_CALL(mockedUtils, getLatestVersion(ContainerEq(expectedVersions)))
729 .WillOnce(Return(version));
730 ON_CALL(mockedUtils, isAssociated(StrEq(psuPath), _))
731 .WillByDefault(Return(false));
732 EXPECT_CALL(sdbusMock, sd_bus_message_new_method_call(_, _, _, _, _,
733 StrEq("StartUnit")))
Lei YU8afeee52019-10-21 15:25:35 +0800734 .Times(3); // There are 3 systemd units are started, enable bmc reboot
735 // guard, start activation, and disable bmc reboot guard
Lei YU1517f5f2019-10-14 16:44:42 +0800736 onPsuInventoryChanged(psuPath, propAdded);
737 onPsuInventoryChanged(psuPath, propModel);
Lei YUffb36532019-10-15 13:55:24 +0800738}