blob: 088e3ba8a09855a7550e5270b497de22f19042a9 [file] [log] [blame]
Lei YU12c9f4c2019-09-11 15:08:15 +08001#include "activation.hpp"
Lei YU7f2a2152019-09-16 16:50:18 +08002#include "mocked_association_interface.hpp"
Lei YUff83c2a2019-09-12 13:55:18 +08003#include "mocked_utils.hpp"
Lei YU12c9f4c2019-09-11 15:08:15 +08004
5#include <sdbusplus/test/sdbus_mock.hpp>
6
7#include <gmock/gmock.h>
8#include <gtest/gtest.h>
9
10using namespace phosphor::software::updater;
11
Lei YUff83c2a2019-09-12 13:55:18 +080012using ::testing::_;
13using ::testing::Return;
Lei YU9edb7332019-09-19 14:46:19 +080014using ::testing::StrEq;
15
16using std::experimental::any;
Lei YUff83c2a2019-09-12 13:55:18 +080017
Lei YU12c9f4c2019-09-11 15:08:15 +080018class TestActivation : public ::testing::Test
19{
20 public:
Lei YU9edb7332019-09-19 14:46:19 +080021 using PropertyType = utils::UtilsInterface::PropertyType;
Lei YUff83c2a2019-09-12 13:55:18 +080022 using Status = Activation::Status;
23 using RequestedStatus = Activation::RequestedActivations;
24 TestActivation() :
25 mockedUtils(
26 reinterpret_cast<const utils::MockedUtils&>(utils::getUtils()))
Lei YU12c9f4c2019-09-11 15:08:15 +080027 {
Lei YU9edb7332019-09-19 14:46:19 +080028 // By default make it compatible with the test software
29 ON_CALL(mockedUtils, getPropertyImpl(_, _, _, _, StrEq(MANUFACTURER)))
30 .WillByDefault(Return(any(PropertyType(std::string("TestManu")))));
31 ON_CALL(mockedUtils, getPropertyImpl(_, _, _, _, StrEq(MODEL)))
32 .WillByDefault(Return(any(PropertyType(std::string("TestModel")))));
Lei YU12c9f4c2019-09-11 15:08:15 +080033 }
34 ~TestActivation()
35 {
36 }
Lei YUff83c2a2019-09-12 13:55:18 +080037
38 void onUpdateDone()
39 {
40 activation->onUpdateDone();
41 }
42 void onUpdateFailed()
43 {
44 activation->onUpdateFailed();
45 }
46 int getProgress()
47 {
48 return activation->activationProgress->progress();
49 }
Lei YU9edb7332019-09-19 14:46:19 +080050 const auto& getPsuQueue()
51 {
52 return activation->psuQueue;
53 }
54
Lei YU12c9f4c2019-09-11 15:08:15 +080055 sdbusplus::SdBusMock sdbusMock;
56 sdbusplus::bus::bus mockedBus = sdbusplus::get_mocked_new(&sdbusMock);
Lei YUff83c2a2019-09-12 13:55:18 +080057 const utils::MockedUtils& mockedUtils;
Lei YU7f2a2152019-09-16 16:50:18 +080058 MockedAssociationInterface mockedAssociationInterface;
Lei YU12c9f4c2019-09-11 15:08:15 +080059 std::unique_ptr<Activation> activation;
60 std::string versionId = "abcdefgh";
Lei YU9edb7332019-09-19 14:46:19 +080061 std::string extVersion = "manufacturer=TestManu,model=TestModel";
Lei YU99301372019-09-29 16:27:12 +080062 std::string filePath = "";
Lei YU7f2a2152019-09-16 16:50:18 +080063 std::string dBusPath = std::string(SOFTWARE_OBJPATH) + "/" + versionId;
Lei YUff83c2a2019-09-12 13:55:18 +080064 Status status = Status::Ready;
Lei YU12c9f4c2019-09-11 15:08:15 +080065 AssociationList associations;
66};
67
68TEST_F(TestActivation, ctordtor)
69{
Lei YU99301372019-09-29 16:27:12 +080070 activation = std::make_unique<Activation>(
71 mockedBus, dBusPath, versionId, extVersion, status, associations,
72 &mockedAssociationInterface, filePath);
Lei YU12c9f4c2019-09-11 15:08:15 +080073}
74
75namespace phosphor::software::updater::internal
76{
77extern std::string getUpdateService(const std::string& psuInventoryPath,
78 const std::string& versionId);
79}
80
81TEST_F(TestActivation, getUpdateService)
82{
83 std::string psuInventoryPath = "/com/example/inventory/powersupply1";
84 std::string versionId = "12345678";
85 std::string toCompare = "psu-update@-com-example-inventory-"
86 "powersupply1\\x20-tmp-images-12345678.service";
87
88 auto service = phosphor::software::updater::internal::getUpdateService(
89 psuInventoryPath, versionId);
90 EXPECT_EQ(toCompare, service);
91}
Lei YUff83c2a2019-09-12 13:55:18 +080092
93TEST_F(TestActivation, doUpdateWhenNoPSU)
94{
Lei YU99301372019-09-29 16:27:12 +080095 activation = std::make_unique<Activation>(
96 mockedBus, dBusPath, versionId, extVersion, status, associations,
97 &mockedAssociationInterface, filePath);
Lei YUff83c2a2019-09-12 13:55:18 +080098 ON_CALL(mockedUtils, getPSUInventoryPath(_))
99 .WillByDefault(
100 Return(std::vector<std::string>({}))); // No PSU inventory
101 activation->requestedActivation(RequestedStatus::Active);
102
Lei YU7f2a2152019-09-16 16:50:18 +0800103 EXPECT_CALL(mockedAssociationInterface, createActiveAssociation(dBusPath))
104 .Times(0);
105 EXPECT_CALL(mockedAssociationInterface, addFunctionalAssociation(dBusPath))
106 .Times(0);
Lei YUff83c2a2019-09-12 13:55:18 +0800107 EXPECT_EQ(Status::Failed, activation->activation());
108}
109
110TEST_F(TestActivation, doUpdateOnePSUOK)
111{
112 constexpr auto psu0 = "/com/example/inventory/psu0";
Lei YU99301372019-09-29 16:27:12 +0800113 activation = std::make_unique<Activation>(
114 mockedBus, dBusPath, versionId, extVersion, status, associations,
115 &mockedAssociationInterface, filePath);
Lei YUff83c2a2019-09-12 13:55:18 +0800116 ON_CALL(mockedUtils, getPSUInventoryPath(_))
117 .WillByDefault(
118 Return(std::vector<std::string>({psu0}))); // One PSU inventory
119 activation->requestedActivation(RequestedStatus::Active);
120
121 EXPECT_EQ(Status::Activating, activation->activation());
122
Lei YU7f2a2152019-09-16 16:50:18 +0800123 EXPECT_CALL(mockedAssociationInterface, createActiveAssociation(dBusPath))
124 .Times(1);
125 EXPECT_CALL(mockedAssociationInterface, addFunctionalAssociation(dBusPath))
126 .Times(1);
Lei YUff83c2a2019-09-12 13:55:18 +0800127 onUpdateDone();
128 EXPECT_EQ(Status::Active, activation->activation());
129}
130
131TEST_F(TestActivation, doUpdateFourPSUsOK)
132{
133 constexpr auto psu0 = "/com/example/inventory/psu0";
134 constexpr auto psu1 = "/com/example/inventory/psu1";
135 constexpr auto psu2 = "/com/example/inventory/psu2";
136 constexpr auto psu3 = "/com/example/inventory/psu3";
Lei YU99301372019-09-29 16:27:12 +0800137 activation = std::make_unique<Activation>(
138 mockedBus, dBusPath, versionId, extVersion, status, associations,
139 &mockedAssociationInterface, filePath);
Lei YUff83c2a2019-09-12 13:55:18 +0800140 ON_CALL(mockedUtils, getPSUInventoryPath(_))
141 .WillByDefault(Return(
142 std::vector<std::string>({psu0, psu1, psu2, psu3}))); // 4 PSUs
143 activation->requestedActivation(RequestedStatus::Active);
144
145 EXPECT_EQ(Status::Activating, activation->activation());
146 EXPECT_EQ(10, getProgress());
147
148 onUpdateDone();
149 EXPECT_EQ(Status::Activating, activation->activation());
150 EXPECT_EQ(30, getProgress());
151
152 onUpdateDone();
153 EXPECT_EQ(Status::Activating, activation->activation());
154 EXPECT_EQ(50, getProgress());
155
156 onUpdateDone();
157 EXPECT_EQ(Status::Activating, activation->activation());
158 EXPECT_EQ(70, getProgress());
159
Lei YU7f2a2152019-09-16 16:50:18 +0800160 EXPECT_CALL(mockedAssociationInterface, createActiveAssociation(dBusPath))
161 .Times(1);
162 EXPECT_CALL(mockedAssociationInterface, addFunctionalAssociation(dBusPath))
163 .Times(1);
164
Lei YUff83c2a2019-09-12 13:55:18 +0800165 onUpdateDone();
166 EXPECT_EQ(Status::Active, activation->activation());
167}
168
169TEST_F(TestActivation, doUpdateFourPSUsFailonSecond)
170{
171 constexpr auto psu0 = "/com/example/inventory/psu0";
172 constexpr auto psu1 = "/com/example/inventory/psu1";
173 constexpr auto psu2 = "/com/example/inventory/psu2";
174 constexpr auto psu3 = "/com/example/inventory/psu3";
Lei YU99301372019-09-29 16:27:12 +0800175 activation = std::make_unique<Activation>(
176 mockedBus, dBusPath, versionId, extVersion, status, associations,
177 &mockedAssociationInterface, filePath);
Lei YUff83c2a2019-09-12 13:55:18 +0800178 ON_CALL(mockedUtils, getPSUInventoryPath(_))
179 .WillByDefault(Return(
180 std::vector<std::string>({psu0, psu1, psu2, psu3}))); // 4 PSUs
181 activation->requestedActivation(RequestedStatus::Active);
182
183 EXPECT_EQ(Status::Activating, activation->activation());
184 EXPECT_EQ(10, getProgress());
185
186 onUpdateDone();
187 EXPECT_EQ(Status::Activating, activation->activation());
188 EXPECT_EQ(30, getProgress());
189
Lei YU7f2a2152019-09-16 16:50:18 +0800190 EXPECT_CALL(mockedAssociationInterface, createActiveAssociation(dBusPath))
191 .Times(0);
192 EXPECT_CALL(mockedAssociationInterface, addFunctionalAssociation(dBusPath))
193 .Times(0);
Lei YUff83c2a2019-09-12 13:55:18 +0800194 onUpdateFailed();
195 EXPECT_EQ(Status::Failed, activation->activation());
196}
197
198TEST_F(TestActivation, doUpdateOnExceptionFromDbus)
199{
200 constexpr auto psu0 = "/com/example/inventory/psu0";
Lei YU99301372019-09-29 16:27:12 +0800201 activation = std::make_unique<Activation>(
202 mockedBus, dBusPath, versionId, extVersion, status, associations,
203 &mockedAssociationInterface, filePath);
Lei YUff83c2a2019-09-12 13:55:18 +0800204 ON_CALL(mockedUtils, getPSUInventoryPath(_))
205 .WillByDefault(
206 Return(std::vector<std::string>({psu0}))); // One PSU inventory
207 ON_CALL(sdbusMock, sd_bus_call(_, _, _, _, nullptr))
208 .WillByDefault(Return(-1)); // Make sdbus call failure
209 activation->requestedActivation(RequestedStatus::Active);
210
211 EXPECT_EQ(Status::Failed, activation->activation());
212}
Lei YU9edb7332019-09-19 14:46:19 +0800213
214TEST_F(TestActivation, doUpdateOnePSUModelNotCompatible)
215{
216 constexpr auto psu0 = "/com/example/inventory/psu0";
217 extVersion = "manufacturer=TestManu,model=DifferentModel";
Lei YU99301372019-09-29 16:27:12 +0800218 activation = std::make_unique<Activation>(
219 mockedBus, dBusPath, versionId, extVersion, status, associations,
220 &mockedAssociationInterface, filePath);
Lei YU9edb7332019-09-19 14:46:19 +0800221 ON_CALL(mockedUtils, getPSUInventoryPath(_))
222 .WillByDefault(Return(std::vector<std::string>({psu0})));
223 activation->requestedActivation(RequestedStatus::Active);
224
225 EXPECT_EQ(Status::Failed, activation->activation());
226}
227
228TEST_F(TestActivation, doUpdateOnePSUManufactureNotCompatible)
229{
230 constexpr auto psu0 = "/com/example/inventory/psu0";
231 extVersion = "manufacturer=DifferentManu,model=TestModel";
Lei YU99301372019-09-29 16:27:12 +0800232 activation = std::make_unique<Activation>(
233 mockedBus, dBusPath, versionId, extVersion, status, associations,
234 &mockedAssociationInterface, filePath);
Lei YU9edb7332019-09-19 14:46:19 +0800235 ON_CALL(mockedUtils, getPSUInventoryPath(_))
236 .WillByDefault(Return(std::vector<std::string>({psu0})));
237 activation->requestedActivation(RequestedStatus::Active);
238
239 EXPECT_EQ(Status::Failed, activation->activation());
240}
241
242TEST_F(TestActivation, doUpdateOnePSUSelfManufactureIsEmpty)
243{
244 ON_CALL(mockedUtils, getPropertyImpl(_, _, _, _, StrEq(MANUFACTURER)))
245 .WillByDefault(Return(any(PropertyType(std::string("")))));
246 extVersion = "manufacturer=AnyManu,model=TestModel";
247 // Below is the same as doUpdateOnePSUOK case
248 constexpr auto psu0 = "/com/example/inventory/psu0";
Lei YU99301372019-09-29 16:27:12 +0800249 activation = std::make_unique<Activation>(
250 mockedBus, dBusPath, versionId, extVersion, status, associations,
251 &mockedAssociationInterface, filePath);
Lei YU9edb7332019-09-19 14:46:19 +0800252 ON_CALL(mockedUtils, getPSUInventoryPath(_))
253 .WillByDefault(
254 Return(std::vector<std::string>({psu0}))); // One PSU inventory
255 activation->requestedActivation(RequestedStatus::Active);
256
257 EXPECT_EQ(Status::Activating, activation->activation());
258
259 EXPECT_CALL(mockedAssociationInterface, createActiveAssociation(dBusPath))
260 .Times(1);
261 EXPECT_CALL(mockedAssociationInterface, addFunctionalAssociation(dBusPath))
262 .Times(1);
263 onUpdateDone();
264 EXPECT_EQ(Status::Active, activation->activation());
265}
266
267TEST_F(TestActivation, doUpdateFourPSUsSecondPSUNotCompatible)
268{
269 constexpr auto psu0 = "/com/example/inventory/psu0";
270 constexpr auto psu1 = "/com/example/inventory/psu1";
271 constexpr auto psu2 = "/com/example/inventory/psu2";
272 constexpr auto psu3 = "/com/example/inventory/psu3";
273 ON_CALL(mockedUtils, getPropertyImpl(_, _, StrEq(psu1), _, StrEq(MODEL)))
274 .WillByDefault(
275 Return(any(PropertyType(std::string("DifferentModel")))));
Lei YU99301372019-09-29 16:27:12 +0800276 activation = std::make_unique<Activation>(
277 mockedBus, dBusPath, versionId, extVersion, status, associations,
278 &mockedAssociationInterface, filePath);
Lei YU9edb7332019-09-19 14:46:19 +0800279 ON_CALL(mockedUtils, getPSUInventoryPath(_))
280 .WillByDefault(Return(
281 std::vector<std::string>({psu0, psu1, psu2, psu3}))); // 4 PSUs
282 activation->requestedActivation(RequestedStatus::Active);
283
284 const auto& psuQueue = getPsuQueue();
285 EXPECT_EQ(3u, psuQueue.size());
286
287 // Only 3 PSUs shall be updated, and psu1 shall be skipped
288 EXPECT_EQ(Status::Activating, activation->activation());
289 EXPECT_EQ(10, getProgress());
290
291 onUpdateDone();
292 EXPECT_EQ(Status::Activating, activation->activation());
293 EXPECT_EQ(36, getProgress());
294
295 onUpdateDone();
296 EXPECT_EQ(Status::Activating, activation->activation());
297 EXPECT_EQ(62, getProgress());
298
299 EXPECT_CALL(mockedAssociationInterface, createActiveAssociation(dBusPath))
300 .Times(1);
301 EXPECT_CALL(mockedAssociationInterface, addFunctionalAssociation(dBusPath))
302 .Times(1);
303
304 onUpdateDone();
305 EXPECT_EQ(Status::Active, activation->activation());
306}