blob: b020c28f968d27085faa68a57f9e0082b9b8dcde [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::_;
11using ::testing::Return;
12using ::testing::ReturnArg;
13using ::testing::StrEq;
14
15using std::experimental::any;
Lei YUf77189f2019-08-07 14:26:30 +080016
17class TestItemUpdater : public ::testing::Test
18{
19 public:
Lei YUa2c2cd72019-08-09 15:54:10 +080020 using Properties = ItemUpdater::Properties;
21 using PropertyType = utils::UtilsInterface::PropertyType;
22
Lei YUf77189f2019-08-07 14:26:30 +080023 TestItemUpdater() :
24 mockedUtils(
25 reinterpret_cast<const utils::MockedUtils&>(utils::getUtils()))
26 {
27 ON_CALL(mockedUtils, getVersionId(_)).WillByDefault(ReturnArg<0>());
Lei YUff83c2a2019-09-12 13:55:18 +080028 ON_CALL(mockedUtils, getPropertyImpl(_, _, _, _, StrEq(PRESENT)))
29 .WillByDefault(Return(any(PropertyType(true))));
Lei YUf77189f2019-08-07 14:26:30 +080030 }
31
32 ~TestItemUpdater()
33 {
34 }
35
36 const auto& GetActivations()
37 {
38 return itemUpdater->activations;
39 }
40
41 std::string getObjPath(const std::string& versionId)
42 {
43 return std::string(dBusPath) + "/" + versionId;
44 }
45
Lei YUa2c2cd72019-08-09 15:54:10 +080046 void onPsuInventoryChanged(const std::string& psuPath,
47 const Properties& properties)
48 {
49 itemUpdater->onPsuInventoryChanged(psuPath, properties);
50 }
51
Lei YUf77189f2019-08-07 14:26:30 +080052 static constexpr auto dBusPath = SOFTWARE_OBJPATH;
53 sdbusplus::SdBusMock sdbusMock;
54 sdbusplus::bus::bus mockedBus = sdbusplus::get_mocked_new(&sdbusMock);
55 const utils::MockedUtils& mockedUtils;
56 std::unique_ptr<ItemUpdater> itemUpdater;
57};
58
59TEST_F(TestItemUpdater, ctordtor)
60{
61 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
62}
63
64TEST_F(TestItemUpdater, NotCreateObjectOnNotPresent)
65{
66 constexpr auto psuPath = "/com/example/inventory/psu0";
67 constexpr auto service = "com.example.Software.Psu";
68 constexpr auto version = "version0";
69 std::string objPath = getObjPath(version);
70 EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
71 .WillOnce(Return(std::vector<std::string>({psuPath})));
72 EXPECT_CALL(mockedUtils, getService(_, StrEq(psuPath), _))
73 .WillOnce(Return(service));
Lei YU5f3584d2019-08-27 16:28:53 +080074 EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
75 .WillOnce(Return(std::string(version)));
Lei YUf77189f2019-08-07 14:26:30 +080076 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
77 _, StrEq(PRESENT)))
78 .WillOnce(Return(any(PropertyType(false)))); // not present
79
80 // The item updater itself
81 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
82 .Times(1);
83
84 // No activation/version objects are created
85 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
86 .Times(0);
87 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
88}
89
90TEST_F(TestItemUpdater, CreateOnePSUOnPresent)
91{
92 constexpr auto psuPath = "/com/example/inventory/psu0";
93 constexpr auto service = "com.example.Software.Psu";
94 constexpr auto version = "version0";
95 std::string objPath = getObjPath(version);
96 EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
97 .WillOnce(Return(std::vector<std::string>({psuPath})));
98 EXPECT_CALL(mockedUtils, getService(_, StrEq(psuPath), _))
99 .WillOnce(Return(service));
Lei YU5f3584d2019-08-27 16:28:53 +0800100 EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
101 .WillOnce(Return(std::string(version)));
Lei YUf77189f2019-08-07 14:26:30 +0800102 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
103 _, StrEq(PRESENT)))
104 .WillOnce(Return(any(PropertyType(true)))); // present
105
106 // The item updater itself
107 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
108 .Times(1);
109
110 // activation and version object will be added
111 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
112 .Times(2);
113 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
114}
115
116TEST_F(TestItemUpdater, CreateTwoPSUsWithSameVersion)
117{
118 constexpr auto psu0 = "/com/example/inventory/psu0";
119 constexpr auto psu1 = "/com/example/inventory/psu1";
120 constexpr auto service = "com.example.Software.Psu";
121 auto version0 = std::string("version0");
122 auto version1 = std::string("version0");
123 auto objPath0 = getObjPath(version0);
124 auto objPath1 = getObjPath(version1);
125
126 EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
127 .WillOnce(Return(std::vector<std::string>({psu0, psu1})));
128 EXPECT_CALL(mockedUtils, getService(_, StrEq(psu0), _))
129 .WillOnce(Return(service));
130 EXPECT_CALL(mockedUtils, getService(_, StrEq(psu1), _))
131 .WillOnce(Return(service));
Lei YU5f3584d2019-08-27 16:28:53 +0800132 EXPECT_CALL(mockedUtils, getVersion(StrEq(psu0)))
133 .WillOnce(Return(std::string(version0)));
Lei YUf77189f2019-08-07 14:26:30 +0800134 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
135 StrEq(PRESENT)))
136 .WillOnce(Return(any(PropertyType(true)))); // present
Lei YU5f3584d2019-08-27 16:28:53 +0800137 EXPECT_CALL(mockedUtils, getVersion(StrEq(psu1)))
138 .WillOnce(Return(std::string(version1)));
Lei YUf77189f2019-08-07 14:26:30 +0800139 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
140 StrEq(PRESENT)))
141 .WillOnce(Return(any(PropertyType(true)))); // present
142
143 // The item updater itself
144 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
145 .Times(1);
146
147 // activation and version object will be added
148 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath0)))
149 .Times(2);
150 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
151
152 // Verify there is only one activation and it has two associations
153 const auto& activations = GetActivations();
154 EXPECT_EQ(1u, activations.size());
155 const auto& activation = activations.find(version0)->second;
156 const auto& assocs = activation->associations();
157 EXPECT_EQ(2u, assocs.size());
158 EXPECT_EQ(psu0, std::get<2>(assocs[0]));
159 EXPECT_EQ(psu1, std::get<2>(assocs[1]));
160}
161
162TEST_F(TestItemUpdater, CreateTwoPSUsWithDifferentVersion)
163{
164 constexpr auto psu0 = "/com/example/inventory/psu0";
165 constexpr auto psu1 = "/com/example/inventory/psu1";
166 constexpr auto service = "com.example.Software.Psu";
167 auto version0 = std::string("version0");
168 auto version1 = std::string("version1");
169 auto objPath0 = getObjPath(version0);
170 auto objPath1 = getObjPath(version1);
171
172 EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
173 .WillOnce(Return(std::vector<std::string>({psu0, psu1})));
174 EXPECT_CALL(mockedUtils, getService(_, StrEq(psu0), _))
175 .WillOnce(Return(service));
176 EXPECT_CALL(mockedUtils, getService(_, StrEq(psu1), _))
177 .WillOnce(Return(service));
Lei YU5f3584d2019-08-27 16:28:53 +0800178 EXPECT_CALL(mockedUtils, getVersion(StrEq(psu0)))
179 .WillOnce(Return(std::string(version0)));
Lei YUf77189f2019-08-07 14:26:30 +0800180 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
181 StrEq(PRESENT)))
182 .WillOnce(Return(any(PropertyType(true)))); // present
Lei YU5f3584d2019-08-27 16:28:53 +0800183 EXPECT_CALL(mockedUtils, getVersion(StrEq(psu1)))
184 .WillOnce(Return(std::string(version1)));
Lei YUf77189f2019-08-07 14:26:30 +0800185 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
186 StrEq(PRESENT)))
187 .WillOnce(Return(any(PropertyType(true)))); // present
188
189 // The item updater itself
190 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
191 .Times(1);
192
193 // two new activation and version objects will be added
194 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath0)))
195 .Times(2);
196 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath1)))
197 .Times(2);
198 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
199
200 // Verify there are two activations and each with one association
201 const auto& activations = GetActivations();
202 EXPECT_EQ(2u, activations.size());
203 const auto& activation0 = activations.find(version0)->second;
204 const auto& assocs0 = activation0->associations();
205 EXPECT_EQ(1u, assocs0.size());
206 EXPECT_EQ(psu0, std::get<2>(assocs0[0]));
207
208 const auto& activation1 = activations.find(version1)->second;
209 const auto& assocs1 = activation1->associations();
210 EXPECT_EQ(1u, assocs1.size());
211 EXPECT_EQ(psu1, std::get<2>(assocs1[0]));
212}
Lei YUa2c2cd72019-08-09 15:54:10 +0800213
214TEST_F(TestItemUpdater, OnOnePSURemoved)
215{
216 constexpr auto psuPath = "/com/example/inventory/psu0";
217 constexpr auto service = "com.example.Software.Psu";
218 constexpr auto version = "version0";
219 std::string objPath = getObjPath(version);
220 EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
221 .WillOnce(Return(std::vector<std::string>({psuPath})));
222 EXPECT_CALL(mockedUtils, getService(_, StrEq(psuPath), _))
223 .WillOnce(Return(service));
Lei YU5f3584d2019-08-27 16:28:53 +0800224 EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
225 .WillOnce(Return(std::string(version)));
Lei YUa2c2cd72019-08-09 15:54:10 +0800226 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
227 _, StrEq(PRESENT)))
228 .WillOnce(Return(any(PropertyType(true)))); // present
229
230 // The item updater itself
231 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
232 .Times(1);
233
234 // activation and version object will be added
235 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
236 .Times(2);
237 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
238
239 // the activation and version object will be removed
240 Properties p{{PRESENT, PropertyType(false)}};
241 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(objPath)))
242 .Times(2);
243 onPsuInventoryChanged(psuPath, p);
244
245 // on exit, item updater is removed
246 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(dBusPath)))
247 .Times(1);
248}
249
250TEST_F(TestItemUpdater, OnOnePSUAdded)
251{
252 constexpr auto psuPath = "/com/example/inventory/psu0";
253 constexpr auto service = "com.example.Software.Psu";
254 constexpr auto version = "version0";
255 std::string objPath = getObjPath(version);
256 EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
257 .WillOnce(Return(std::vector<std::string>({psuPath})));
258 EXPECT_CALL(mockedUtils, getService(_, StrEq(psuPath), _))
259 .WillOnce(Return(service));
Lei YU5f3584d2019-08-27 16:28:53 +0800260 EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
261 .WillOnce(Return(std::string(version)));
Lei YUa2c2cd72019-08-09 15:54:10 +0800262 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
263 _, StrEq(PRESENT)))
264 .WillOnce(Return(any(PropertyType(false)))); // not present
265
266 // The item updater itself
267 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
268 .Times(1);
269
270 // No activation/version objects are created
271 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
272 .Times(0);
273 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
274
275 // The PSU is present and version is added in a single call
Lei YUdcaf8932019-09-09 16:09:35 +0800276 Properties propAdded{{PRESENT, PropertyType(true)}};
277 EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
278 .WillOnce(Return(std::string(version)));
Lei YUa2c2cd72019-08-09 15:54:10 +0800279 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
280 .Times(2);
281 onPsuInventoryChanged(psuPath, propAdded);
282}
283
284TEST_F(TestItemUpdater, OnOnePSURemovedAndAdded)
285{
286 constexpr auto psuPath = "/com/example/inventory/psu0";
287 constexpr auto service = "com.example.Software.Psu";
288 constexpr auto version = "version0";
289 std::string objPath = getObjPath(version);
290 EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
291 .WillOnce(Return(std::vector<std::string>({psuPath})));
292 EXPECT_CALL(mockedUtils, getService(_, StrEq(psuPath), _))
293 .WillOnce(Return(service));
Lei YU5f3584d2019-08-27 16:28:53 +0800294 EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
295 .WillOnce(Return(std::string(version)));
Lei YUa2c2cd72019-08-09 15:54:10 +0800296 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
297 _, StrEq(PRESENT)))
298 .WillOnce(Return(any(PropertyType(true)))); // present
299
300 // The item updater itself
301 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
302 .Times(1);
303
304 // activation and version object will be added
305 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
306 .Times(2);
307 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
308
309 // the activation and version object will be removed
310 Properties propRemoved{{PRESENT, PropertyType(false)}};
311 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(objPath)))
312 .Times(2);
313 onPsuInventoryChanged(psuPath, propRemoved);
314
315 Properties propAdded{{PRESENT, PropertyType(true)}};
Lei YUdcaf8932019-09-09 16:09:35 +0800316 EXPECT_CALL(mockedUtils, getVersion(StrEq(psuPath)))
317 .WillOnce(Return(std::string(version)));
Lei YUa2c2cd72019-08-09 15:54:10 +0800318 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
319 .Times(2);
320 onPsuInventoryChanged(psuPath, propAdded);
Lei YUa2c2cd72019-08-09 15:54:10 +0800321
322 // on exit, objects are removed
323 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(objPath)))
324 .Times(2);
325 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(dBusPath)))
326 .Times(1);
327}
328
329TEST_F(TestItemUpdater,
330 TwoPSUsWithSameVersionRemovedAndAddedWithDifferntVersion)
331{
332 constexpr auto psu0 = "/com/example/inventory/psu0";
333 constexpr auto psu1 = "/com/example/inventory/psu1";
334 constexpr auto service = "com.example.Software.Psu";
335 auto version0 = std::string("version0");
336 auto version1 = std::string("version0");
337 auto objPath0 = getObjPath(version0);
338 auto objPath1 = getObjPath(version1);
339
340 EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
341 .WillOnce(Return(std::vector<std::string>({psu0, psu1})));
342 EXPECT_CALL(mockedUtils, getService(_, StrEq(psu0), _))
343 .WillOnce(Return(service));
344 EXPECT_CALL(mockedUtils, getService(_, StrEq(psu1), _))
345 .WillOnce(Return(service));
Lei YU5f3584d2019-08-27 16:28:53 +0800346 EXPECT_CALL(mockedUtils, getVersion(StrEq(psu0)))
347 .WillOnce(Return(std::string(version0)));
Lei YUa2c2cd72019-08-09 15:54:10 +0800348 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
349 StrEq(PRESENT)))
350 .WillOnce(Return(any(PropertyType(true)))); // present
Lei YU5f3584d2019-08-27 16:28:53 +0800351 EXPECT_CALL(mockedUtils, getVersion(StrEq(psu1)))
352 .WillOnce(Return(std::string(version1)));
Lei YUa2c2cd72019-08-09 15:54:10 +0800353 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
354 StrEq(PRESENT)))
355 .WillOnce(Return(any(PropertyType(true)))); // present
356
357 // The item updater itself
358 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
359 .Times(1);
360
361 // activation and version object will be added
362 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath0)))
363 .Times(2);
364 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
365
366 // Verify there is only one activation and it has two associations
367 const auto& activations = GetActivations();
368 EXPECT_EQ(1u, activations.size());
369 const auto& activation = activations.find(version0)->second;
370 auto assocs = activation->associations();
371 EXPECT_EQ(2u, assocs.size());
372 EXPECT_EQ(psu0, std::get<2>(assocs[0]));
373 EXPECT_EQ(psu1, std::get<2>(assocs[1]));
374
375 // PSU0 is removed, only associations shall be updated
376 Properties propRemoved{{PRESENT, PropertyType(false)}};
377 onPsuInventoryChanged(psu0, propRemoved);
378 assocs = activation->associations();
379 EXPECT_EQ(1u, assocs.size());
380 EXPECT_EQ(psu1, std::get<2>(assocs[0]));
381
382 // PSU1 is removed, the activation and version object shall be removed
383 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(objPath0)))
384 .Times(2);
385 onPsuInventoryChanged(psu1, propRemoved);
386
387 // Add PSU0 and PSU1 back, but PSU1 with a different version
388 version1 = "version1";
389 objPath1 = getObjPath(version1);
Lei YUdcaf8932019-09-09 16:09:35 +0800390 Properties propAdded0{{PRESENT, PropertyType(true)}};
391 Properties propAdded1{{PRESENT, PropertyType(true)}};
392 EXPECT_CALL(mockedUtils, getVersion(StrEq(psu0)))
393 .WillOnce(Return(std::string(version0)));
394 EXPECT_CALL(mockedUtils, getVersion(StrEq(psu1)))
395 .WillOnce(Return(std::string(version1)));
Lei YUa2c2cd72019-08-09 15:54:10 +0800396 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath0)))
397 .Times(2);
398 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath1)))
399 .Times(2);
400 onPsuInventoryChanged(psu0, propAdded0);
401 onPsuInventoryChanged(psu1, propAdded1);
402
403 // on exit, objects are removed
404 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(objPath0)))
405 .Times(2);
406 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(objPath1)))
407 .Times(2);
408 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(dBusPath)))
409 .Times(1);
410}