blob: b3628037eefcc2cb496c38bcd297db0a091e725b [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));
72 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
73 _, StrEq(VERSION)))
74 .WillOnce(Return(any(PropertyType(std::string(version)))));
75 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
76 _, StrEq(PRESENT)))
77 .WillOnce(Return(any(PropertyType(false)))); // not present
78
79 // The item updater itself
80 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
81 .Times(1);
82
83 // No activation/version objects are created
84 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
85 .Times(0);
86 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
87}
88
89TEST_F(TestItemUpdater, CreateOnePSUOnPresent)
90{
91 constexpr auto psuPath = "/com/example/inventory/psu0";
92 constexpr auto service = "com.example.Software.Psu";
93 constexpr auto version = "version0";
94 std::string objPath = getObjPath(version);
95 EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
96 .WillOnce(Return(std::vector<std::string>({psuPath})));
97 EXPECT_CALL(mockedUtils, getService(_, StrEq(psuPath), _))
98 .WillOnce(Return(service));
99 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
100 _, StrEq(VERSION)))
101 .WillOnce(Return(any(PropertyType(std::string(version)))));
102 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));
132 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
133 StrEq(VERSION)))
134 .WillOnce(Return(any(PropertyType(version0))));
135 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
136 StrEq(PRESENT)))
137 .WillOnce(Return(any(PropertyType(true)))); // present
138 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
139 StrEq(VERSION)))
140 .WillOnce(Return(any(PropertyType(version1))));
141 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
142 StrEq(PRESENT)))
143 .WillOnce(Return(any(PropertyType(true)))); // present
144
145 // The item updater itself
146 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
147 .Times(1);
148
149 // activation and version object will be added
150 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath0)))
151 .Times(2);
152 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
153
154 // Verify there is only one activation and it has two associations
155 const auto& activations = GetActivations();
156 EXPECT_EQ(1u, activations.size());
157 const auto& activation = activations.find(version0)->second;
158 const auto& assocs = activation->associations();
159 EXPECT_EQ(2u, assocs.size());
160 EXPECT_EQ(psu0, std::get<2>(assocs[0]));
161 EXPECT_EQ(psu1, std::get<2>(assocs[1]));
162}
163
164TEST_F(TestItemUpdater, CreateTwoPSUsWithDifferentVersion)
165{
166 constexpr auto psu0 = "/com/example/inventory/psu0";
167 constexpr auto psu1 = "/com/example/inventory/psu1";
168 constexpr auto service = "com.example.Software.Psu";
169 auto version0 = std::string("version0");
170 auto version1 = std::string("version1");
171 auto objPath0 = getObjPath(version0);
172 auto objPath1 = getObjPath(version1);
173
174 EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
175 .WillOnce(Return(std::vector<std::string>({psu0, psu1})));
176 EXPECT_CALL(mockedUtils, getService(_, StrEq(psu0), _))
177 .WillOnce(Return(service));
178 EXPECT_CALL(mockedUtils, getService(_, StrEq(psu1), _))
179 .WillOnce(Return(service));
180 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
181 StrEq(VERSION)))
182 .WillOnce(Return(any(PropertyType(version0))));
183 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
184 StrEq(PRESENT)))
185 .WillOnce(Return(any(PropertyType(true)))); // present
186 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
187 StrEq(VERSION)))
188 .WillOnce(Return(any(PropertyType(version1))));
189 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
190 StrEq(PRESENT)))
191 .WillOnce(Return(any(PropertyType(true)))); // present
192
193 // The item updater itself
194 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
195 .Times(1);
196
197 // two new activation and version objects will be added
198 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath0)))
199 .Times(2);
200 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath1)))
201 .Times(2);
202 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
203
204 // Verify there are two activations and each with one association
205 const auto& activations = GetActivations();
206 EXPECT_EQ(2u, activations.size());
207 const auto& activation0 = activations.find(version0)->second;
208 const auto& assocs0 = activation0->associations();
209 EXPECT_EQ(1u, assocs0.size());
210 EXPECT_EQ(psu0, std::get<2>(assocs0[0]));
211
212 const auto& activation1 = activations.find(version1)->second;
213 const auto& assocs1 = activation1->associations();
214 EXPECT_EQ(1u, assocs1.size());
215 EXPECT_EQ(psu1, std::get<2>(assocs1[0]));
216}
Lei YUa2c2cd72019-08-09 15:54:10 +0800217
218TEST_F(TestItemUpdater, OnOnePSURemoved)
219{
220 constexpr auto psuPath = "/com/example/inventory/psu0";
221 constexpr auto service = "com.example.Software.Psu";
222 constexpr auto version = "version0";
223 std::string objPath = getObjPath(version);
224 EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
225 .WillOnce(Return(std::vector<std::string>({psuPath})));
226 EXPECT_CALL(mockedUtils, getService(_, StrEq(psuPath), _))
227 .WillOnce(Return(service));
228 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
229 _, StrEq(VERSION)))
230 .WillOnce(Return(any(PropertyType(std::string(version)))));
231 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
232 _, StrEq(PRESENT)))
233 .WillOnce(Return(any(PropertyType(true)))); // present
234
235 // The item updater itself
236 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
237 .Times(1);
238
239 // activation and version object will be added
240 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
241 .Times(2);
242 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
243
244 // the activation and version object will be removed
245 Properties p{{PRESENT, PropertyType(false)}};
246 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(objPath)))
247 .Times(2);
248 onPsuInventoryChanged(psuPath, p);
249
250 // on exit, item updater is removed
251 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(dBusPath)))
252 .Times(1);
253}
254
255TEST_F(TestItemUpdater, OnOnePSUAdded)
256{
257 constexpr auto psuPath = "/com/example/inventory/psu0";
258 constexpr auto service = "com.example.Software.Psu";
259 constexpr auto version = "version0";
260 std::string objPath = getObjPath(version);
261 EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
262 .WillOnce(Return(std::vector<std::string>({psuPath})));
263 EXPECT_CALL(mockedUtils, getService(_, StrEq(psuPath), _))
264 .WillOnce(Return(service));
265 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
266 _, StrEq(VERSION)))
267 .WillOnce(Return(any(PropertyType(std::string(version)))));
268 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
269 _, StrEq(PRESENT)))
270 .WillOnce(Return(any(PropertyType(false)))); // not present
271
272 // The item updater itself
273 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
274 .Times(1);
275
276 // No activation/version objects are created
277 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
278 .Times(0);
279 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
280
281 // The PSU is present and version is added in a single call
282 Properties propAdded{{PRESENT, PropertyType(true)},
283 {VERSION, PropertyType(std::string(version))}};
284 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
285 .Times(2);
286 onPsuInventoryChanged(psuPath, propAdded);
287}
288
289TEST_F(TestItemUpdater, OnOnePSURemovedAndAdded)
290{
291 constexpr auto psuPath = "/com/example/inventory/psu0";
292 constexpr auto service = "com.example.Software.Psu";
293 constexpr auto version = "version0";
294 std::string objPath = getObjPath(version);
295 EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
296 .WillOnce(Return(std::vector<std::string>({psuPath})));
297 EXPECT_CALL(mockedUtils, getService(_, StrEq(psuPath), _))
298 .WillOnce(Return(service));
299 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
300 _, StrEq(VERSION)))
301 .WillOnce(Return(any(PropertyType(std::string(version)))));
302 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psuPath),
303 _, StrEq(PRESENT)))
304 .WillOnce(Return(any(PropertyType(true)))); // present
305
306 // The item updater itself
307 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
308 .Times(1);
309
310 // activation and version object will be added
311 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
312 .Times(2);
313 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
314
315 // the activation and version object will be removed
316 Properties propRemoved{{PRESENT, PropertyType(false)}};
317 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(objPath)))
318 .Times(2);
319 onPsuInventoryChanged(psuPath, propRemoved);
320
321 Properties propAdded{{PRESENT, PropertyType(true)}};
322 Properties propVersion{{VERSION, PropertyType(std::string(version))}};
323 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
324 .Times(2);
325 onPsuInventoryChanged(psuPath, propAdded);
326 onPsuInventoryChanged(psuPath, propVersion);
327
328 // on exit, objects are removed
329 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(objPath)))
330 .Times(2);
331 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(dBusPath)))
332 .Times(1);
333}
334
335TEST_F(TestItemUpdater,
336 TwoPSUsWithSameVersionRemovedAndAddedWithDifferntVersion)
337{
338 constexpr auto psu0 = "/com/example/inventory/psu0";
339 constexpr auto psu1 = "/com/example/inventory/psu1";
340 constexpr auto service = "com.example.Software.Psu";
341 auto version0 = std::string("version0");
342 auto version1 = std::string("version0");
343 auto objPath0 = getObjPath(version0);
344 auto objPath1 = getObjPath(version1);
345
346 EXPECT_CALL(mockedUtils, getPSUInventoryPath(_))
347 .WillOnce(Return(std::vector<std::string>({psu0, psu1})));
348 EXPECT_CALL(mockedUtils, getService(_, StrEq(psu0), _))
349 .WillOnce(Return(service));
350 EXPECT_CALL(mockedUtils, getService(_, StrEq(psu1), _))
351 .WillOnce(Return(service));
352 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
353 StrEq(VERSION)))
354 .WillOnce(Return(any(PropertyType(version0))));
355 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu0), _,
356 StrEq(PRESENT)))
357 .WillOnce(Return(any(PropertyType(true)))); // present
358 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
359 StrEq(VERSION)))
360 .WillOnce(Return(any(PropertyType(version1))));
361 EXPECT_CALL(mockedUtils, getPropertyImpl(_, StrEq(service), StrEq(psu1), _,
362 StrEq(PRESENT)))
363 .WillOnce(Return(any(PropertyType(true)))); // present
364
365 // The item updater itself
366 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(dBusPath)))
367 .Times(1);
368
369 // activation and version object will be added
370 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath0)))
371 .Times(2);
372 itemUpdater = std::make_unique<ItemUpdater>(mockedBus, dBusPath);
373
374 // Verify there is only one activation and it has two associations
375 const auto& activations = GetActivations();
376 EXPECT_EQ(1u, activations.size());
377 const auto& activation = activations.find(version0)->second;
378 auto assocs = activation->associations();
379 EXPECT_EQ(2u, assocs.size());
380 EXPECT_EQ(psu0, std::get<2>(assocs[0]));
381 EXPECT_EQ(psu1, std::get<2>(assocs[1]));
382
383 // PSU0 is removed, only associations shall be updated
384 Properties propRemoved{{PRESENT, PropertyType(false)}};
385 onPsuInventoryChanged(psu0, propRemoved);
386 assocs = activation->associations();
387 EXPECT_EQ(1u, assocs.size());
388 EXPECT_EQ(psu1, std::get<2>(assocs[0]));
389
390 // PSU1 is removed, the activation and version object shall be removed
391 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(objPath0)))
392 .Times(2);
393 onPsuInventoryChanged(psu1, propRemoved);
394
395 // Add PSU0 and PSU1 back, but PSU1 with a different version
396 version1 = "version1";
397 objPath1 = getObjPath(version1);
398 Properties propAdded0{{PRESENT, PropertyType(true)},
399 {VERSION, PropertyType(std::string(version0))}};
400 Properties propAdded1{{PRESENT, PropertyType(true)},
401 {VERSION, PropertyType(std::string(version1))}};
402 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath0)))
403 .Times(2);
404 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath1)))
405 .Times(2);
406 onPsuInventoryChanged(psu0, propAdded0);
407 onPsuInventoryChanged(psu1, propAdded1);
408
409 // on exit, objects are removed
410 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(objPath0)))
411 .Times(2);
412 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(objPath1)))
413 .Times(2);
414 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(_, StrEq(dBusPath)))
415 .Times(1);
416}