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