blob: 2fe1c863810ae9684195b5a947b84538eaf0ef07 [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
91
92 // The item updater itself
93 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
94 .Times(1);
95
96 // No activation/version objects are created
97 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
98 .Times(0);
99 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
100}
101
102TEST_F(TestItemUpdater, CreateOnePSUOnPresent)
103{
104 constexpr auto psuPath = "/com/example/inventory/psu0";
105 constexpr auto service = "com.example.Software.Psu";
106 constexpr auto version = "version0";
107 std::string objPath = getObjPath(version);
108 EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
109 .WillOnce(Return(std::vector<std::string>({psuPath})));
110 EXPECT_CALL(mockedUtils, getService(_, StrEq(psuPath), _))
111 .WillOnce(Return(service));
Lei YU5f3584d2019-08-27 16:28:53 +0800112 EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
113 .WillOnce(Return(std::string(version)));
Lei YUf77189f2019-08-07 14:26:30 +0800114 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
115 _, StrEq(PRESENT)))
116 .WillOnce(Return(any(PropertyType(true)))); // present
117
118 // The item updater itself
119 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
120 .Times(1);
121
122 // activation and version object will be added
123 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
124 .Times(2);
125 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
126}
127
128TEST_F(TestItemUpdater, CreateTwoPSUsWithSameVersion)
129{
130 constexpr auto psu0 = "/com/example/inventory/psu0";
131 constexpr auto psu1 = "/com/example/inventory/psu1";
132 constexpr auto service = "com.example.Software.Psu";
133 auto version0 = std::string("version0");
134 auto version1 = std::string("version0");
135 auto objPath0 = getObjPath(version0);
136 auto objPath1 = getObjPath(version1);
137
138 EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
139 .WillOnce(Return(std::vector<std::string>({psu0, psu1})));
140 EXPECT_CALL(mockedUtils, getService(_, StrEq(psu0), _))
141 .WillOnce(Return(service));
142 EXPECT_CALL(mockedUtils, getService(_, StrEq(psu1), _))
143 .WillOnce(Return(service));
Lei YU5f3584d2019-08-27 16:28:53 +0800144 EXPECT_CALL(mockedUtils, getVersion(StrEq(psu0)))
145 .WillOnce(Return(std::string(version0)));
Lei YUf77189f2019-08-07 14:26:30 +0800146 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
147 StrEq(PRESENT)))
148 .WillOnce(Return(any(PropertyType(true)))); // present
Lei YU5f3584d2019-08-27 16:28:53 +0800149 EXPECT_CALL(mockedUtils, getVersion(StrEq(psu1)))
150 .WillOnce(Return(std::string(version1)));
Lei YUf77189f2019-08-07 14:26:30 +0800151 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
152 StrEq(PRESENT)))
153 .WillOnce(Return(any(PropertyType(true)))); // present
154
155 // The item updater itself
156 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
157 .Times(1);
158
159 // activation and version object will be added
160 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath0)))
161 .Times(2);
162 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
163
164 // Verify there is only one activation and it has two associations
165 const auto& activations = GetActivations();
166 EXPECT_EQ(1u, activations.size());
167 const auto& activation = activations.find(version0)->second;
168 const auto& assocs = activation->associations();
169 EXPECT_EQ(2u, assocs.size());
170 EXPECT_EQ(psu0, std::get<2>(assocs[0]));
171 EXPECT_EQ(psu1, std::get<2>(assocs[1]));
172}
173
174TEST_F(TestItemUpdater, CreateTwoPSUsWithDifferentVersion)
175{
176 constexpr auto psu0 = "/com/example/inventory/psu0";
177 constexpr auto psu1 = "/com/example/inventory/psu1";
178 constexpr auto service = "com.example.Software.Psu";
179 auto version0 = std::string("version0");
180 auto version1 = std::string("version1");
181 auto objPath0 = getObjPath(version0);
182 auto objPath1 = getObjPath(version1);
183
184 EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
185 .WillOnce(Return(std::vector<std::string>({psu0, psu1})));
186 EXPECT_CALL(mockedUtils, getService(_, StrEq(psu0), _))
187 .WillOnce(Return(service));
188 EXPECT_CALL(mockedUtils, getService(_, StrEq(psu1), _))
189 .WillOnce(Return(service));
Lei YU5f3584d2019-08-27 16:28:53 +0800190 EXPECT_CALL(mockedUtils, getVersion(StrEq(psu0)))
191 .WillOnce(Return(std::string(version0)));
Lei YUf77189f2019-08-07 14:26:30 +0800192 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
193 StrEq(PRESENT)))
194 .WillOnce(Return(any(PropertyType(true)))); // present
Lei YU5f3584d2019-08-27 16:28:53 +0800195 EXPECT_CALL(mockedUtils, getVersion(StrEq(psu1)))
196 .WillOnce(Return(std::string(version1)));
Lei YUf77189f2019-08-07 14:26:30 +0800197 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
198 StrEq(PRESENT)))
199 .WillOnce(Return(any(PropertyType(true)))); // present
200
201 // The item updater itself
202 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
203 .Times(1);
204
205 // two new activation and version objects will be added
206 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath0)))
207 .Times(2);
208 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath1)))
209 .Times(2);
210 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
211
212 // Verify there are two activations and each with one association
213 const auto& activations = GetActivations();
214 EXPECT_EQ(2u, activations.size());
215 const auto& activation0 = activations.find(version0)->second;
216 const auto& assocs0 = activation0->associations();
217 EXPECT_EQ(1u, assocs0.size());
218 EXPECT_EQ(psu0, std::get<2>(assocs0[0]));
219
220 const auto& activation1 = activations.find(version1)->second;
221 const auto& assocs1 = activation1->associations();
222 EXPECT_EQ(1u, assocs1.size());
223 EXPECT_EQ(psu1, std::get<2>(assocs1[0]));
224}
Lei YUa2c2cd72019-08-09 15:54:10 +0800225
226TEST_F(TestItemUpdater, OnOnePSURemoved)
227{
228 constexpr auto psuPath = "/com/example/inventory/psu0";
229 constexpr auto service = "com.example.Software.Psu";
230 constexpr auto version = "version0";
231 std::string objPath = getObjPath(version);
232 EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
233 .WillOnce(Return(std::vector<std::string>({psuPath})));
234 EXPECT_CALL(mockedUtils, getService(_, StrEq(psuPath), _))
235 .WillOnce(Return(service));
Lei YU5f3584d2019-08-27 16:28:53 +0800236 EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
237 .WillOnce(Return(std::string(version)));
Lei YUa2c2cd72019-08-09 15:54:10 +0800238 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
239 _, StrEq(PRESENT)))
240 .WillOnce(Return(any(PropertyType(true)))); // present
241
242 // The item updater itself
243 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
244 .Times(1);
245
246 // activation and version object will be added
247 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
248 .Times(2);
249 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
250
251 // the activation and version object will be removed
252 Properties p{{PRESENT, PropertyType(false)}};
253 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(objPath)))
254 .Times(2);
255 onPsuInventoryChanged(psuPath, p);
256
257 // on exit, item updater is removed
258 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(dBusPath)))
259 .Times(1);
260}
261
262TEST_F(TestItemUpdater, OnOnePSUAdded)
263{
264 constexpr auto psuPath = "/com/example/inventory/psu0";
265 constexpr auto service = "com.example.Software.Psu";
266 constexpr auto version = "version0";
267 std::string objPath = getObjPath(version);
268 EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
269 .WillOnce(Return(std::vector<std::string>({psuPath})));
270 EXPECT_CALL(mockedUtils, getService(_, StrEq(psuPath), _))
271 .WillOnce(Return(service));
Lei YU5f3584d2019-08-27 16:28:53 +0800272 EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
273 .WillOnce(Return(std::string(version)));
Lei YUa2c2cd72019-08-09 15:54:10 +0800274 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
275 _, StrEq(PRESENT)))
276 .WillOnce(Return(any(PropertyType(false)))); // not present
277
278 // The item updater itself
279 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
280 .Times(1);
281
282 // No activation/version objects are created
283 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
284 .Times(0);
285 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
286
287 // The PSU is present and version is added in a single call
Lei YU1517f5f2019-10-14 16:44:42 +0800288 Properties propAddedAndModel{
289 {PRESENT, PropertyType(true)},
290 {MODEL, PropertyType(std::string("testModel"))}};
Lei YUdcaf8932019-09-09 16:09:35 +0800291 EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
292 .WillOnce(Return(std::string(version)));
Lei YUa2c2cd72019-08-09 15:54:10 +0800293 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
294 .Times(2);
Lei YU1517f5f2019-10-14 16:44:42 +0800295 onPsuInventoryChanged(psuPath, propAddedAndModel);
Lei YUa2c2cd72019-08-09 15:54:10 +0800296}
297
Lei YU1517f5f2019-10-14 16:44:42 +0800298TEST_F(TestItemUpdater, OnOnePSURemovedAndAddedWithLatestVersion)
Lei YUa2c2cd72019-08-09 15:54:10 +0800299{
300 constexpr auto psuPath = "/com/example/inventory/psu0";
301 constexpr auto service = "com.example.Software.Psu";
302 constexpr auto version = "version0";
303 std::string objPath = getObjPath(version);
Lei YU1517f5f2019-10-14 16:44:42 +0800304 ON_CALL(mockedUtils, getPSUInventoryPath(_))
305 .WillByDefault(Return(std::vector<std::string>({psuPath})));
Lei YUa2c2cd72019-08-09 15:54:10 +0800306 EXPECT_CALL(mockedUtils, getService(_, StrEq(psuPath), _))
307 .WillOnce(Return(service));
Lei YU5f3584d2019-08-27 16:28:53 +0800308 EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
309 .WillOnce(Return(std::string(version)));
Lei YUa2c2cd72019-08-09 15:54:10 +0800310 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
311 _, StrEq(PRESENT)))
312 .WillOnce(Return(any(PropertyType(true)))); // present
313
314 // The item updater itself
315 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
316 .Times(1);
317
318 // activation and version object will be added
319 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
320 .Times(2);
321 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
322
323 // the activation and version object will be removed
Lei YUa2c2cd72019-08-09 15:54:10 +0800324 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(objPath)))
325 .Times(2);
326 onPsuInventoryChanged(psuPath, propRemoved);
327
Lei YUdcaf8932019-09-09 16:09:35 +0800328 EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
329 .WillOnce(Return(std::string(version)));
Lei YUa2c2cd72019-08-09 15:54:10 +0800330 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
331 .Times(2);
Lei YU1517f5f2019-10-14 16:44:42 +0800332
333 // On PSU inserted, it shall check if it's the latest version
334 std::set<std::string> expectedVersions = {version};
335 EXPECT_CALL(mockedUtils, getLatestVersion(ContainerEq(expectedVersions)))
336 .WillOnce(Return(version));
337 EXPECT_CALL(mockedUtils, isAssociated(StrEq(psuPath), _))
338 .WillOnce(Return(true));
339 EXPECT_CALL(sdbusMock, sd_bus_message_new_method_call(_, _, _, _, _,
340 StrEq("StartUnit")))
341 .Times(0);
Lei YUa2c2cd72019-08-09 15:54:10 +0800342 onPsuInventoryChanged(psuPath, propAdded);
Lei YU1517f5f2019-10-14 16:44:42 +0800343 onPsuInventoryChanged(psuPath, propModel);
Lei YUa2c2cd72019-08-09 15:54:10 +0800344
345 // on exit, objects are removed
346 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(objPath)))
347 .Times(2);
348 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(dBusPath)))
349 .Times(1);
350}
351
352TEST_F(TestItemUpdater,
353 TwoPSUsWithSameVersionRemovedAndAddedWithDifferntVersion)
354{
355 constexpr auto psu0 = "/com/example/inventory/psu0";
356 constexpr auto psu1 = "/com/example/inventory/psu1";
357 constexpr auto service = "com.example.Software.Psu";
358 auto version0 = std::string("version0");
359 auto version1 = std::string("version0");
360 auto objPath0 = getObjPath(version0);
361 auto objPath1 = getObjPath(version1);
362
363 EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
364 .WillOnce(Return(std::vector<std::string>({psu0, psu1})));
365 EXPECT_CALL(mockedUtils, getService(_, StrEq(psu0), _))
366 .WillOnce(Return(service));
367 EXPECT_CALL(mockedUtils, getService(_, StrEq(psu1), _))
368 .WillOnce(Return(service));
Lei YU5f3584d2019-08-27 16:28:53 +0800369 EXPECT_CALL(mockedUtils, getVersion(StrEq(psu0)))
370 .WillOnce(Return(std::string(version0)));
Lei YUa2c2cd72019-08-09 15:54:10 +0800371 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
372 StrEq(PRESENT)))
373 .WillOnce(Return(any(PropertyType(true)))); // present
Lei YU5f3584d2019-08-27 16:28:53 +0800374 EXPECT_CALL(mockedUtils, getVersion(StrEq(psu1)))
375 .WillOnce(Return(std::string(version1)));
Lei YUa2c2cd72019-08-09 15:54:10 +0800376 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
377 StrEq(PRESENT)))
378 .WillOnce(Return(any(PropertyType(true)))); // present
379
380 // The item updater itself
381 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
382 .Times(1);
383
384 // activation and version object will be added
385 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath0)))
386 .Times(2);
387 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
388
389 // Verify there is only one activation and it has two associations
390 const auto& activations = GetActivations();
391 EXPECT_EQ(1u, activations.size());
392 const auto& activation = activations.find(version0)->second;
393 auto assocs = activation->associations();
394 EXPECT_EQ(2u, assocs.size());
395 EXPECT_EQ(psu0, std::get<2>(assocs[0]));
396 EXPECT_EQ(psu1, std::get<2>(assocs[1]));
397
398 // PSU0 is removed, only associations shall be updated
Lei YUa2c2cd72019-08-09 15:54:10 +0800399 onPsuInventoryChanged(psu0, propRemoved);
400 assocs = activation->associations();
401 EXPECT_EQ(1u, assocs.size());
402 EXPECT_EQ(psu1, std::get<2>(assocs[0]));
403
404 // PSU1 is removed, the activation and version object shall be removed
405 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(objPath0)))
406 .Times(2);
407 onPsuInventoryChanged(psu1, propRemoved);
408
409 // Add PSU0 and PSU1 back, but PSU1 with a different version
410 version1 = "version1";
411 objPath1 = getObjPath(version1);
Lei YUdcaf8932019-09-09 16:09:35 +0800412 EXPECT_CALL(mockedUtils, getVersion(StrEq(psu0)))
413 .WillOnce(Return(std::string(version0)));
414 EXPECT_CALL(mockedUtils, getVersion(StrEq(psu1)))
415 .WillOnce(Return(std::string(version1)));
Lei YUa2c2cd72019-08-09 15:54:10 +0800416 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath0)))
417 .Times(2);
418 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath1)))
419 .Times(2);
Lei YU1517f5f2019-10-14 16:44:42 +0800420 onPsuInventoryChanged(psu0, propAdded);
421 onPsuInventoryChanged(psu1, propModel);
422 onPsuInventoryChanged(psu1, propAdded);
423 onPsuInventoryChanged(psu0, propModel);
Lei YUa2c2cd72019-08-09 15:54:10 +0800424
425 // on exit, objects are removed
426 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(objPath0)))
427 .Times(2);
428 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(objPath1)))
429 .Times(2);
430 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(dBusPath)))
431 .Times(1);
432}
Lei YU58c26e32019-09-27 17:52:06 +0800433
434TEST_F(TestItemUpdater, scanDirOnNoPSU)
435{
436 constexpr auto psuPath = "/com/example/inventory/psu0";
437 constexpr auto service = "com.example.Software.Psu";
438 constexpr auto version = "version0";
439 std::string objPath = getObjPath(version);
440 EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
441 .WillOnce(Return(std::vector<std::string>({psuPath})));
442 EXPECT_CALL(mockedUtils, getService(_, StrEq(psuPath), _))
443 .WillOnce(Return(service));
444 EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
445 .WillOnce(Return(std::string(version)));
446 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
447 _, StrEq(PRESENT)))
448 .WillOnce(Return(any(PropertyType(false)))); // not present
449
450 // The item updater itself
451 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
452 .Times(1);
453
454 // No activation/version objects are created
455 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
456 .Times(0);
457 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
458
459 // The valid image in test/psu-images-one-valid-one-invalid/model-1/
460 auto objPathValid = getObjPath("psu-test.v0.4");
461 auto objPathInvalid = getObjPath("psu-test.v0.5");
462 // activation and version object will be added on scan dir
463 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPathValid)))
464 .Times(2);
465 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPathInvalid)))
466 .Times(0);
467 scanDirectory("./psu-images-one-valid-one-invalid");
468}
469
470TEST_F(TestItemUpdater, scanDirOnSamePSUVersion)
471{
472 constexpr auto psuPath = "/com/example/inventory/psu0";
473 constexpr auto service = "com.example.Software.Psu";
474 constexpr auto version = "version0";
475 std::string objPath = getObjPath(version);
476 EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
477 .WillOnce(Return(std::vector<std::string>({psuPath})));
478 EXPECT_CALL(mockedUtils, getService(_, StrEq(psuPath), _))
479 .WillOnce(Return(service));
480 EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
481 .WillOnce(Return(std::string(version)));
482 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
483 _, StrEq(PRESENT)))
484 .WillOnce(Return(any(PropertyType(true)))); // present
485
486 // The item updater itself
487 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
488 .Times(1);
489
490 // activation and version object will be added
491 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
492 .Times(2);
493 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
494
495 // The valid image in test/psu-images-valid-version0/model-3/ has the same
496 // version as the running PSU, so no objects will be created, but only the
497 // path will be set to the version object
498 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
499 .Times(0);
500 EXPECT_CALL(sdbusMock, sd_bus_emit_properties_changed_strv(
501 _, StrEq(objPath),
502 StrEq("xyz.openbmc_project.Common.FilePath"),
503 Pointee(StrEq("Path"))))
504 .Times(1);
505 scanDirectory("./psu-images-valid-version0");
506}
Lei YUffb36532019-10-15 13:55:24 +0800507
508TEST_F(TestItemUpdater, OnUpdateDoneOnTwoPSUsWithSameVersion)
509{
510 // Simulate there are two PSUs with same version, and updated to a new
511 // version
512 constexpr auto psu0 = "/com/example/inventory/psu0";
513 constexpr auto psu1 = "/com/example/inventory/psu1";
514 constexpr auto service = "com.example.Software.Psu";
515 auto version0 = std::string("version0");
516 auto version1 = std::string("version0");
517 auto objPath0 = getObjPath(version0);
518 auto objPath1 = getObjPath(version1);
519
520 EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
521 .WillOnce(Return(std::vector<std::string>({psu0, psu1})));
522 EXPECT_CALL(mockedUtils, getService(_, StrEq(psu0), _))
523 .WillOnce(Return(service));
524 EXPECT_CALL(mockedUtils, getService(_, StrEq(psu1), _))
525 .WillOnce(Return(service));
526 EXPECT_CALL(mockedUtils, getVersion(StrEq(psu0)))
527 .WillOnce(Return(std::string(version0)));
528 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
529 StrEq(PRESENT)))
530 .WillOnce(Return(any(PropertyType(true)))); // present
531 EXPECT_CALL(mockedUtils, getVersion(StrEq(psu1)))
532 .WillOnce(Return(std::string(version1)));
533 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
534 StrEq(PRESENT)))
535 .WillOnce(Return(any(PropertyType(true)))); // present
536
537 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
538
Lei YU1517f5f2019-10-14 16:44:42 +0800539 std::string newVersionId = "NewVersionId";
540 AssociationList associations;
541 auto dummyActivation = std::make_unique<Activation>(
542 mockedBus, dBusPath, newVersionId, "", Activation::Status::Active,
543 associations, "", itemUpdater.get(), itemUpdater.get());
544
Lei YUffb36532019-10-15 13:55:24 +0800545 // Now there is one activation and it has two associations
546 auto& activations = GetActivations();
Lei YU1517f5f2019-10-14 16:44:42 +0800547 activations.emplace(newVersionId, std::move(dummyActivation));
Lei YUffb36532019-10-15 13:55:24 +0800548 auto& activation = activations.find(version0)->second;
549 auto assocs = activation->associations();
550 EXPECT_EQ(2u, assocs.size());
551 EXPECT_EQ(psu0, std::get<2>(assocs[0]));
552 EXPECT_EQ(psu1, std::get<2>(assocs[1]));
553
554 EXPECT_CALL(mockedUtils, isAssociated(StrEq(psu0), _))
555 .WillOnce(Return(true));
Lei YU1517f5f2019-10-14 16:44:42 +0800556 itemUpdater->onUpdateDone(newVersionId, psu0);
Lei YUffb36532019-10-15 13:55:24 +0800557
558 // Now the activation should have one assoiation
559 assocs = activation->associations();
560 EXPECT_EQ(1u, assocs.size());
561 EXPECT_EQ(psu1, std::get<2>(assocs[0]));
562
563 EXPECT_CALL(mockedUtils, isAssociated(StrEq(psu1), _))
564 .WillOnce(Return(true));
Lei YU1517f5f2019-10-14 16:44:42 +0800565 itemUpdater->onUpdateDone(newVersionId, psu1);
Lei YUffb36532019-10-15 13:55:24 +0800566
Lei YU1517f5f2019-10-14 16:44:42 +0800567 // Now the activation shall be erased and only the dummy one is left
568 EXPECT_EQ(1u, activations.size());
569 EXPECT_NE(activations.find(newVersionId), activations.end());
Lei YUffb36532019-10-15 13:55:24 +0800570}
571
572TEST_F(TestItemUpdater, OnUpdateDoneOnTwoPSUsWithDifferentVersion)
573{
574 // Simulate there are two PSUs with different version, and updated to a new
575 // version
576 constexpr auto psu0 = "/com/example/inventory/psu0";
577 constexpr auto psu1 = "/com/example/inventory/psu1";
578 constexpr auto service = "com.example.Software.Psu";
579 auto version0 = std::string("version0");
580 auto version1 = std::string("version1");
581 auto objPath0 = getObjPath(version0);
582 auto objPath1 = getObjPath(version1);
583
584 EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
585 .WillOnce(Return(std::vector<std::string>({psu0, psu1})));
586 EXPECT_CALL(mockedUtils, getService(_, StrEq(psu0), _))
587 .WillOnce(Return(service));
588 EXPECT_CALL(mockedUtils, getService(_, StrEq(psu1), _))
589 .WillOnce(Return(service));
590 EXPECT_CALL(mockedUtils, getVersion(StrEq(psu0)))
591 .WillOnce(Return(std::string(version0)));
592 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
593 StrEq(PRESENT)))
594 .WillOnce(Return(any(PropertyType(true)))); // present
595 EXPECT_CALL(mockedUtils, getVersion(StrEq(psu1)))
596 .WillOnce(Return(std::string(version1)));
597 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
598 StrEq(PRESENT)))
599 .WillOnce(Return(any(PropertyType(true)))); // present
600
601 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
602
Lei YU1517f5f2019-10-14 16:44:42 +0800603 std::string newVersionId = "NewVersionId";
604 AssociationList associations;
605 auto dummyActivation = std::make_unique<Activation>(
606 mockedBus, dBusPath, newVersionId, "", Activation::Status::Active,
607 associations, "", itemUpdater.get(), itemUpdater.get());
608
609 auto& activations = GetActivations();
610 activations.emplace(newVersionId, std::move(dummyActivation));
Lei YUffb36532019-10-15 13:55:24 +0800611
612 EXPECT_CALL(mockedUtils, isAssociated(StrEq(psu0), _))
613 .WillOnce(Return(true));
Lei YU1517f5f2019-10-14 16:44:42 +0800614
615 // After psu0 is done, two activations should be left
616 itemUpdater->onUpdateDone(newVersionId, psu0);
617 EXPECT_EQ(2u, activations.size());
Lei YUffb36532019-10-15 13:55:24 +0800618 const auto& activation1 = activations.find(version1)->second;
619 const auto& assocs1 = activation1->associations();
620 EXPECT_EQ(1u, assocs1.size());
621 EXPECT_EQ(psu1, std::get<2>(assocs1[0]));
622
623 EXPECT_CALL(mockedUtils, isAssociated(StrEq(psu1), _))
624 .WillOnce(Return(true));
Lei YU1517f5f2019-10-14 16:44:42 +0800625 // After psu1 is done, only the dummy activation should be left
626 itemUpdater->onUpdateDone(newVersionId, psu1);
627 EXPECT_EQ(1u, activations.size());
628 EXPECT_NE(activations.find(newVersionId), activations.end());
629}
630
631TEST_F(TestItemUpdater, OnOnePSURemovedAndAddedWithOldVersion)
632{
633 constexpr auto psuPath = "/com/example/inventory/psu0";
634 constexpr auto service = "com.example.Software.Psu";
635 constexpr auto version = "version0";
636 std::string versionId =
637 version; // In testing versionId is the same as version
638 std::string objPath = getObjPath(version);
639 ON_CALL(mockedUtils, getPSUInventoryPath(_))
640 .WillByDefault(Return(std::vector<std::string>({psuPath})));
641 ON_CALL(mockedUtils, getService(_, StrEq(psuPath), _))
642 .WillByDefault(Return(service));
643 EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
644 .WillOnce(Return(std::string(version)));
645 ON_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath), _,
646 StrEq(PRESENT)))
647 .WillByDefault(Return(any(PropertyType(true)))); // present
648
649 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
650
651 // Add an association to simulate that it has image in BMC filesystem
652 auto& activation = GetActivations().find(versionId)->second;
653 auto assocs = activation->associations();
654 assocs.emplace_back(ACTIVATION_FWD_ASSOCIATION, ACTIVATION_REV_ASSOCIATION,
655 "SomePath");
656 activation->associations(assocs);
657 activation->path("SomeFilePath");
658
659 onPsuInventoryChanged(psuPath, propRemoved);
660
661 // On PSU inserted, it checks and finds a newer version
662 auto oldVersion = "old-version";
663 EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
664 .WillOnce(Return(std::string(oldVersion)));
665 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
666 _, StrEq(MANUFACTURER)))
667 .WillOnce(
668 Return(any(PropertyType(std::string(""))))); // Checking compatible
669 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
670 _, StrEq(MODEL)))
671 .WillOnce(
672 Return(any(PropertyType(std::string(""))))); // Checking compatible
673 std::set<std::string> expectedVersions = {version, oldVersion};
674 EXPECT_CALL(mockedUtils, getLatestVersion(ContainerEq(expectedVersions)))
675 .WillOnce(Return(version));
676 ON_CALL(mockedUtils, isAssociated(StrEq(psuPath), _))
677 .WillByDefault(Return(false));
678 EXPECT_CALL(sdbusMock, sd_bus_message_new_method_call(_, _, _, _, _,
679 StrEq("StartUnit")))
Lei YU8afeee52019-10-21 15:25:35 +0800680 .Times(3); // There are 3 systemd units are started, enable bmc reboot
681 // guard, start activation, and disable bmc reboot guard
Lei YU1517f5f2019-10-14 16:44:42 +0800682 onPsuInventoryChanged(psuPath, propAdded);
683 onPsuInventoryChanged(psuPath, propModel);
Lei YUffb36532019-10-15 13:55:24 +0800684}