blob: a402758793e286c7e285c768b4128c317a95c498 [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 {
Lei YUc09155b2019-10-11 17:30:48 +080036 utils::freeUtils();
Lei YU12c9f4c2019-09-11 15:08:15 +080037 }
Lei YUff83c2a2019-09-12 13:55:18 +080038
39 void onUpdateDone()
40 {
41 activation->onUpdateDone();
42 }
43 void onUpdateFailed()
44 {
45 activation->onUpdateFailed();
46 }
47 int getProgress()
48 {
49 return activation->activationProgress->progress();
50 }
Lei YU9edb7332019-09-19 14:46:19 +080051 const auto& getPsuQueue()
52 {
53 return activation->psuQueue;
54 }
Lei YUe8945ea2019-09-29 17:25:31 +080055 std::string getUpdateService(const std::string& psuInventoryPath)
56 {
57 return activation->getUpdateService(psuInventoryPath);
58 }
Lei YU9edb7332019-09-19 14:46:19 +080059
Lei YU12c9f4c2019-09-11 15:08:15 +080060 sdbusplus::SdBusMock sdbusMock;
61 sdbusplus::bus::bus mockedBus = sdbusplus::get_mocked_new(&sdbusMock);
Lei YUff83c2a2019-09-12 13:55:18 +080062 const utils::MockedUtils& mockedUtils;
Lei YU7f2a2152019-09-16 16:50:18 +080063 MockedAssociationInterface mockedAssociationInterface;
Lei YU12c9f4c2019-09-11 15:08:15 +080064 std::unique_ptr<Activation> activation;
65 std::string versionId = "abcdefgh";
Lei YU9edb7332019-09-19 14:46:19 +080066 std::string extVersion = "manufacturer=TestManu,model=TestModel";
Lei YU99301372019-09-29 16:27:12 +080067 std::string filePath = "";
Lei YU7f2a2152019-09-16 16:50:18 +080068 std::string dBusPath = std::string(SOFTWARE_OBJPATH) + "/" + versionId;
Lei YUff83c2a2019-09-12 13:55:18 +080069 Status status = Status::Ready;
Lei YU12c9f4c2019-09-11 15:08:15 +080070 AssociationList associations;
71};
72
73TEST_F(TestActivation, ctordtor)
74{
Lei YU99301372019-09-29 16:27:12 +080075 activation = std::make_unique<Activation>(
76 mockedBus, dBusPath, versionId, extVersion, status, associations,
77 &mockedAssociationInterface, filePath);
Lei YU12c9f4c2019-09-11 15:08:15 +080078}
79
Lei YU58c26e32019-09-27 17:52:06 +080080TEST_F(TestActivation, ctorWithInvalidExtVersion)
81{
82 extVersion = "invalid text";
83 activation = std::make_unique<Activation>(
84 mockedBus, dBusPath, versionId, extVersion, status, associations,
85 &mockedAssociationInterface, filePath);
86}
87
Lei YU12c9f4c2019-09-11 15:08:15 +080088TEST_F(TestActivation, getUpdateService)
89{
90 std::string psuInventoryPath = "/com/example/inventory/powersupply1";
Lei YU12c9f4c2019-09-11 15:08:15 +080091 std::string toCompare = "psu-update@-com-example-inventory-"
92 "powersupply1\\x20-tmp-images-12345678.service";
Lei YUe8945ea2019-09-29 17:25:31 +080093 versionId = "12345678";
94 filePath = "/tmp/images/12345678";
Lei YU12c9f4c2019-09-11 15:08:15 +080095
Lei YUe8945ea2019-09-29 17:25:31 +080096 activation = std::make_unique<Activation>(
97 mockedBus, dBusPath, versionId, extVersion, status, associations,
98 &mockedAssociationInterface, filePath);
99
100 auto service = getUpdateService(psuInventoryPath);
Lei YU12c9f4c2019-09-11 15:08:15 +0800101 EXPECT_EQ(toCompare, service);
102}
Lei YUff83c2a2019-09-12 13:55:18 +0800103
104TEST_F(TestActivation, doUpdateWhenNoPSU)
105{
Lei YU99301372019-09-29 16:27:12 +0800106 activation = std::make_unique<Activation>(
107 mockedBus, dBusPath, versionId, extVersion, status, associations,
108 &mockedAssociationInterface, filePath);
Lei YUff83c2a2019-09-12 13:55:18 +0800109 ON_CALL(mockedUtils, getPSUInventoryPath(_))
110 .WillByDefault(
111 Return(std::vector<std::string>({}))); // No PSU inventory
112 activation->requestedActivation(RequestedStatus::Active);
113
Lei YU7f2a2152019-09-16 16:50:18 +0800114 EXPECT_CALL(mockedAssociationInterface, createActiveAssociation(dBusPath))
115 .Times(0);
116 EXPECT_CALL(mockedAssociationInterface, addFunctionalAssociation(dBusPath))
117 .Times(0);
Lei YUff83c2a2019-09-12 13:55:18 +0800118 EXPECT_EQ(Status::Failed, activation->activation());
119}
120
121TEST_F(TestActivation, doUpdateOnePSUOK)
122{
123 constexpr auto psu0 = "/com/example/inventory/psu0";
Lei YU99301372019-09-29 16:27:12 +0800124 activation = std::make_unique<Activation>(
125 mockedBus, dBusPath, versionId, extVersion, status, associations,
126 &mockedAssociationInterface, filePath);
Lei YUff83c2a2019-09-12 13:55:18 +0800127 ON_CALL(mockedUtils, getPSUInventoryPath(_))
128 .WillByDefault(
129 Return(std::vector<std::string>({psu0}))); // One PSU inventory
130 activation->requestedActivation(RequestedStatus::Active);
131
132 EXPECT_EQ(Status::Activating, activation->activation());
133
Lei YU7f2a2152019-09-16 16:50:18 +0800134 EXPECT_CALL(mockedAssociationInterface, createActiveAssociation(dBusPath))
135 .Times(1);
136 EXPECT_CALL(mockedAssociationInterface, addFunctionalAssociation(dBusPath))
137 .Times(1);
Lei YUff83c2a2019-09-12 13:55:18 +0800138 onUpdateDone();
139 EXPECT_EQ(Status::Active, activation->activation());
140}
141
142TEST_F(TestActivation, doUpdateFourPSUsOK)
143{
144 constexpr auto psu0 = "/com/example/inventory/psu0";
145 constexpr auto psu1 = "/com/example/inventory/psu1";
146 constexpr auto psu2 = "/com/example/inventory/psu2";
147 constexpr auto psu3 = "/com/example/inventory/psu3";
Lei YU99301372019-09-29 16:27:12 +0800148 activation = std::make_unique<Activation>(
149 mockedBus, dBusPath, versionId, extVersion, status, associations,
150 &mockedAssociationInterface, filePath);
Lei YUff83c2a2019-09-12 13:55:18 +0800151 ON_CALL(mockedUtils, getPSUInventoryPath(_))
152 .WillByDefault(Return(
153 std::vector<std::string>({psu0, psu1, psu2, psu3}))); // 4 PSUs
154 activation->requestedActivation(RequestedStatus::Active);
155
156 EXPECT_EQ(Status::Activating, activation->activation());
157 EXPECT_EQ(10, getProgress());
158
159 onUpdateDone();
160 EXPECT_EQ(Status::Activating, activation->activation());
161 EXPECT_EQ(30, getProgress());
162
163 onUpdateDone();
164 EXPECT_EQ(Status::Activating, activation->activation());
165 EXPECT_EQ(50, getProgress());
166
167 onUpdateDone();
168 EXPECT_EQ(Status::Activating, activation->activation());
169 EXPECT_EQ(70, getProgress());
170
Lei YU7f2a2152019-09-16 16:50:18 +0800171 EXPECT_CALL(mockedAssociationInterface, createActiveAssociation(dBusPath))
172 .Times(1);
173 EXPECT_CALL(mockedAssociationInterface, addFunctionalAssociation(dBusPath))
174 .Times(1);
175
Lei YUff83c2a2019-09-12 13:55:18 +0800176 onUpdateDone();
177 EXPECT_EQ(Status::Active, activation->activation());
178}
179
180TEST_F(TestActivation, doUpdateFourPSUsFailonSecond)
181{
182 constexpr auto psu0 = "/com/example/inventory/psu0";
183 constexpr auto psu1 = "/com/example/inventory/psu1";
184 constexpr auto psu2 = "/com/example/inventory/psu2";
185 constexpr auto psu3 = "/com/example/inventory/psu3";
Lei YU99301372019-09-29 16:27:12 +0800186 activation = std::make_unique<Activation>(
187 mockedBus, dBusPath, versionId, extVersion, status, associations,
188 &mockedAssociationInterface, filePath);
Lei YUff83c2a2019-09-12 13:55:18 +0800189 ON_CALL(mockedUtils, getPSUInventoryPath(_))
190 .WillByDefault(Return(
191 std::vector<std::string>({psu0, psu1, psu2, psu3}))); // 4 PSUs
192 activation->requestedActivation(RequestedStatus::Active);
193
194 EXPECT_EQ(Status::Activating, activation->activation());
195 EXPECT_EQ(10, getProgress());
196
197 onUpdateDone();
198 EXPECT_EQ(Status::Activating, activation->activation());
199 EXPECT_EQ(30, getProgress());
200
Lei YU7f2a2152019-09-16 16:50:18 +0800201 EXPECT_CALL(mockedAssociationInterface, createActiveAssociation(dBusPath))
202 .Times(0);
203 EXPECT_CALL(mockedAssociationInterface, addFunctionalAssociation(dBusPath))
204 .Times(0);
Lei YUff83c2a2019-09-12 13:55:18 +0800205 onUpdateFailed();
206 EXPECT_EQ(Status::Failed, activation->activation());
207}
208
209TEST_F(TestActivation, doUpdateOnExceptionFromDbus)
210{
211 constexpr auto psu0 = "/com/example/inventory/psu0";
Lei YU99301372019-09-29 16:27:12 +0800212 activation = std::make_unique<Activation>(
213 mockedBus, dBusPath, versionId, extVersion, status, associations,
214 &mockedAssociationInterface, filePath);
Lei YUff83c2a2019-09-12 13:55:18 +0800215 ON_CALL(mockedUtils, getPSUInventoryPath(_))
216 .WillByDefault(
217 Return(std::vector<std::string>({psu0}))); // One PSU inventory
218 ON_CALL(sdbusMock, sd_bus_call(_, _, _, _, nullptr))
219 .WillByDefault(Return(-1)); // Make sdbus call failure
220 activation->requestedActivation(RequestedStatus::Active);
221
222 EXPECT_EQ(Status::Failed, activation->activation());
223}
Lei YU9edb7332019-09-19 14:46:19 +0800224
225TEST_F(TestActivation, doUpdateOnePSUModelNotCompatible)
226{
227 constexpr auto psu0 = "/com/example/inventory/psu0";
228 extVersion = "manufacturer=TestManu,model=DifferentModel";
Lei YU99301372019-09-29 16:27:12 +0800229 activation = std::make_unique<Activation>(
230 mockedBus, dBusPath, versionId, extVersion, status, associations,
231 &mockedAssociationInterface, filePath);
Lei YU9edb7332019-09-19 14:46:19 +0800232 ON_CALL(mockedUtils, getPSUInventoryPath(_))
233 .WillByDefault(Return(std::vector<std::string>({psu0})));
234 activation->requestedActivation(RequestedStatus::Active);
235
236 EXPECT_EQ(Status::Failed, activation->activation());
237}
238
239TEST_F(TestActivation, doUpdateOnePSUManufactureNotCompatible)
240{
241 constexpr auto psu0 = "/com/example/inventory/psu0";
242 extVersion = "manufacturer=DifferentManu,model=TestModel";
Lei YU99301372019-09-29 16:27:12 +0800243 activation = std::make_unique<Activation>(
244 mockedBus, dBusPath, versionId, extVersion, status, associations,
245 &mockedAssociationInterface, filePath);
Lei YU9edb7332019-09-19 14:46:19 +0800246 ON_CALL(mockedUtils, getPSUInventoryPath(_))
247 .WillByDefault(Return(std::vector<std::string>({psu0})));
248 activation->requestedActivation(RequestedStatus::Active);
249
250 EXPECT_EQ(Status::Failed, activation->activation());
251}
252
253TEST_F(TestActivation, doUpdateOnePSUSelfManufactureIsEmpty)
254{
255 ON_CALL(mockedUtils, getPropertyImpl(_, _, _, _, StrEq(MANUFACTURER)))
256 .WillByDefault(Return(any(PropertyType(std::string("")))));
257 extVersion = "manufacturer=AnyManu,model=TestModel";
258 // Below is the same as doUpdateOnePSUOK case
259 constexpr auto psu0 = "/com/example/inventory/psu0";
Lei YU99301372019-09-29 16:27:12 +0800260 activation = std::make_unique<Activation>(
261 mockedBus, dBusPath, versionId, extVersion, status, associations,
262 &mockedAssociationInterface, filePath);
Lei YU9edb7332019-09-19 14:46:19 +0800263 ON_CALL(mockedUtils, getPSUInventoryPath(_))
264 .WillByDefault(
265 Return(std::vector<std::string>({psu0}))); // One PSU inventory
266 activation->requestedActivation(RequestedStatus::Active);
267
268 EXPECT_EQ(Status::Activating, activation->activation());
269
270 EXPECT_CALL(mockedAssociationInterface, createActiveAssociation(dBusPath))
271 .Times(1);
272 EXPECT_CALL(mockedAssociationInterface, addFunctionalAssociation(dBusPath))
273 .Times(1);
274 onUpdateDone();
275 EXPECT_EQ(Status::Active, activation->activation());
276}
277
278TEST_F(TestActivation, doUpdateFourPSUsSecondPSUNotCompatible)
279{
280 constexpr auto psu0 = "/com/example/inventory/psu0";
281 constexpr auto psu1 = "/com/example/inventory/psu1";
282 constexpr auto psu2 = "/com/example/inventory/psu2";
283 constexpr auto psu3 = "/com/example/inventory/psu3";
284 ON_CALL(mockedUtils, getPropertyImpl(_, _, StrEq(psu1), _, StrEq(MODEL)))
285 .WillByDefault(
286 Return(any(PropertyType(std::string("DifferentModel")))));
Lei YU99301372019-09-29 16:27:12 +0800287 activation = std::make_unique<Activation>(
288 mockedBus, dBusPath, versionId, extVersion, status, associations,
289 &mockedAssociationInterface, filePath);
Lei YU9edb7332019-09-19 14:46:19 +0800290 ON_CALL(mockedUtils, getPSUInventoryPath(_))
291 .WillByDefault(Return(
292 std::vector<std::string>({psu0, psu1, psu2, psu3}))); // 4 PSUs
293 activation->requestedActivation(RequestedStatus::Active);
294
295 const auto& psuQueue = getPsuQueue();
296 EXPECT_EQ(3u, psuQueue.size());
297
298 // Only 3 PSUs shall be updated, and psu1 shall be skipped
299 EXPECT_EQ(Status::Activating, activation->activation());
300 EXPECT_EQ(10, getProgress());
301
302 onUpdateDone();
303 EXPECT_EQ(Status::Activating, activation->activation());
304 EXPECT_EQ(36, getProgress());
305
306 onUpdateDone();
307 EXPECT_EQ(Status::Activating, activation->activation());
308 EXPECT_EQ(62, getProgress());
309
310 EXPECT_CALL(mockedAssociationInterface, createActiveAssociation(dBusPath))
311 .Times(1);
312 EXPECT_CALL(mockedAssociationInterface, addFunctionalAssociation(dBusPath))
313 .Times(1);
314
315 onUpdateDone();
316 EXPECT_EQ(Status::Active, activation->activation());
317}