blob: 0865be77d940a4952b610ef77ca0e92c1b046f3c [file] [log] [blame]
Shawn McCarneyd3a8aab2020-03-10 10:30:02 -05001/**
2 * Copyright © 2020 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#include "action.hpp"
Shawn McCarney39765002020-04-09 18:03:26 -050017#include "chassis.hpp"
Shawn McCarneyd3a8aab2020-03-10 10:30:02 -050018#include "configuration.hpp"
Shawn McCarney39765002020-04-09 18:03:26 -050019#include "device.hpp"
20#include "i2c_interface.hpp"
21#include "i2c_write_byte_action.hpp"
22#include "journal.hpp"
Shawn McCarneyd3a8aab2020-03-10 10:30:02 -050023#include "mock_action.hpp"
Shawn McCarney39765002020-04-09 18:03:26 -050024#include "mock_journal.hpp"
25#include "mocked_i2c_interface.hpp"
26#include "pmbus_utils.hpp"
27#include "pmbus_write_vout_command_action.hpp"
28#include "rail.hpp"
29#include "system.hpp"
Shawn McCarneyd3a8aab2020-03-10 10:30:02 -050030
31#include <memory>
32#include <optional>
33#include <utility>
34#include <vector>
35
Shawn McCarney39765002020-04-09 18:03:26 -050036#include <gmock/gmock.h>
Shawn McCarneyd3a8aab2020-03-10 10:30:02 -050037#include <gtest/gtest.h>
38
39using namespace phosphor::power::regulators;
Shawn McCarney39765002020-04-09 18:03:26 -050040using namespace phosphor::power::regulators::pmbus_utils;
41
42using ::testing::Return;
43using ::testing::Throw;
44using ::testing::TypedEq;
Shawn McCarneyd3a8aab2020-03-10 10:30:02 -050045
46TEST(ConfigurationTests, Constructor)
47{
48 // Test where volts value specified
49 {
50 std::optional<double> volts{1.3};
51
52 std::vector<std::unique_ptr<Action>> actions{};
53 actions.push_back(std::make_unique<MockAction>());
54 actions.push_back(std::make_unique<MockAction>());
55
56 Configuration configuration(volts, std::move(actions));
57 EXPECT_EQ(configuration.getVolts().has_value(), true);
58 EXPECT_EQ(configuration.getVolts().value(), 1.3);
59 EXPECT_EQ(configuration.getActions().size(), 2);
60 }
61
62 // Test where volts value not specified
63 {
64 std::optional<double> volts{};
65
66 std::vector<std::unique_ptr<Action>> actions{};
67 actions.push_back(std::make_unique<MockAction>());
68
69 Configuration configuration(volts, std::move(actions));
70 EXPECT_EQ(configuration.getVolts().has_value(), false);
71 EXPECT_EQ(configuration.getActions().size(), 1);
72 }
73}
74
Shawn McCarney39765002020-04-09 18:03:26 -050075// Test for execute(System&, Chassis&, Device&)
76TEST(ConfigurationTests, ExecuteForDevice)
Shawn McCarneyd3a8aab2020-03-10 10:30:02 -050077{
Shawn McCarney39765002020-04-09 18:03:26 -050078 // Test where works: Volts value not specified
79 {
80 // Create I2CWriteByteAction with register 0x7C and value 0x0A
81 std::unique_ptr<I2CWriteByteAction> action =
82 std::make_unique<I2CWriteByteAction>(0x7C, 0x0A);
83
84 // Create mock I2CInterface. Expect action to write 0x0A to 0x7C.
85 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
86 std::make_unique<i2c::MockedI2CInterface>();
87 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
88 EXPECT_CALL(*i2cInterface,
89 write(TypedEq<uint8_t>(0x7C), TypedEq<uint8_t>(0x0A)))
90 .Times(1);
91
92 // Create Configuration with no volts value specified
93 std::optional<double> volts{};
94 std::vector<std::unique_ptr<Action>> actions{};
95 actions.emplace_back(std::move(action));
96 std::unique_ptr<Configuration> configuration =
97 std::make_unique<Configuration>(volts, std::move(actions));
98 Configuration* configurationPtr = configuration.get();
99
100 // Create Device that contains Configuration
101 std::unique_ptr<PresenceDetection> presenceDetection{};
102 std::unique_ptr<Device> device = std::make_unique<Device>(
103 "vdd_reg", true, "/system/chassis/motherboard/reg2",
104 std::move(i2cInterface), std::move(presenceDetection),
105 std::move(configuration));
106 Device* devicePtr = device.get();
107
108 // Create Chassis that contains Device
109 std::vector<std::unique_ptr<Device>> devices{};
110 devices.emplace_back(std::move(device));
111 std::unique_ptr<Chassis> chassis =
112 std::make_unique<Chassis>(1, std::move(devices));
113 Chassis* chassisPtr = chassis.get();
114
115 // Create System that contains Chassis
116 std::vector<std::unique_ptr<Rule>> rules{};
117 std::vector<std::unique_ptr<Chassis>> chassisVec{};
118 chassisVec.emplace_back(std::move(chassis));
119 System system{std::move(rules), std::move(chassisVec)};
120
121 // Execute Configuration
122 journal::clear();
123 configurationPtr->execute(system, *chassisPtr, *devicePtr);
124 std::vector<std::string> expectedDebugMessages{"Configuring vdd_reg"};
125 EXPECT_EQ(journal::getDebugMessages(), expectedDebugMessages);
126 EXPECT_EQ(journal::getErrMessages().size(), 0);
127 }
128
129 // Test where works: Volts value specified
130 {
131 // Create PMBusWriteVoutCommandAction. Do not specify a volts value
132 // because it will get a value of 1.3V from the
133 // ActionEnvironment/Configuration. Specify a -8 exponent.
134 // Linear format volts value = (1.3 / 2^(-8)) = 332.8 = 333 = 0x014D.
135 std::optional<double> volts{};
136 std::unique_ptr<PMBusWriteVoutCommandAction> action =
137 std::make_unique<PMBusWriteVoutCommandAction>(
138 volts, pmbus_utils::VoutDataFormat::linear, -8, false);
139
140 // Create mock I2CInterface. Expect action to write 0x014D to
141 // VOUT_COMMAND (command/register 0x21).
142 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
143 std::make_unique<i2c::MockedI2CInterface>();
144 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
145 EXPECT_CALL(*i2cInterface,
146 write(TypedEq<uint8_t>(0x21), TypedEq<uint16_t>(0x014D)))
147 .Times(1);
148
149 // Create Configuration with volts value 1.3V
150 std::vector<std::unique_ptr<Action>> actions{};
151 actions.emplace_back(std::move(action));
152 std::unique_ptr<Configuration> configuration =
153 std::make_unique<Configuration>(1.3, std::move(actions));
154 Configuration* configurationPtr = configuration.get();
155
156 // Create Device that contains Configuration
157 std::unique_ptr<PresenceDetection> presenceDetection{};
158 std::unique_ptr<Device> device = std::make_unique<Device>(
159 "vdd_reg", true, "/system/chassis/motherboard/reg2",
160 std::move(i2cInterface), std::move(presenceDetection),
161 std::move(configuration));
162 Device* devicePtr = device.get();
163
164 // Create Chassis that contains Device
165 std::vector<std::unique_ptr<Device>> devices{};
166 devices.emplace_back(std::move(device));
167 std::unique_ptr<Chassis> chassis =
168 std::make_unique<Chassis>(1, std::move(devices));
169 Chassis* chassisPtr = chassis.get();
170
171 // Create System that contains Chassis
172 std::vector<std::unique_ptr<Rule>> rules{};
173 std::vector<std::unique_ptr<Chassis>> chassisVec{};
174 chassisVec.emplace_back(std::move(chassis));
175 System system{std::move(rules), std::move(chassisVec)};
176
177 // Execute Configuration
178 journal::clear();
179 configurationPtr->execute(system, *chassisPtr, *devicePtr);
180 std::vector<std::string> expectedDebugMessages{
181 "Configuring vdd_reg: volts=1.300000"};
182 EXPECT_EQ(journal::getDebugMessages(), expectedDebugMessages);
183 EXPECT_EQ(journal::getErrMessages().size(), 0);
184 }
185
186 // Test where fails
187 {
188 // Create I2CWriteByteAction with register 0x7C and value 0x0A
189 std::unique_ptr<I2CWriteByteAction> action =
190 std::make_unique<I2CWriteByteAction>(0x7C, 0x0A);
191
192 // Create mock I2CInterface. write() throws an I2CException.
193 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
194 std::make_unique<i2c::MockedI2CInterface>();
195 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
196 EXPECT_CALL(*i2cInterface,
197 write(TypedEq<uint8_t>(0x7C), TypedEq<uint8_t>(0x0A)))
198 .Times(1)
199 .WillOnce(Throw(
200 i2c::I2CException{"Failed to write byte", "/dev/i2c-1", 0x70}));
201
202 // Create Configuration with no volts value specified
203 std::optional<double> volts{};
204 std::vector<std::unique_ptr<Action>> actions{};
205 actions.emplace_back(std::move(action));
206 std::unique_ptr<Configuration> configuration =
207 std::make_unique<Configuration>(volts, std::move(actions));
208 Configuration* configurationPtr = configuration.get();
209
210 // Create Device that contains Configuration
211 std::unique_ptr<PresenceDetection> presenceDetection{};
212 std::unique_ptr<Device> device = std::make_unique<Device>(
213 "vdd_reg", true, "/system/chassis/motherboard/reg2",
214 std::move(i2cInterface), std::move(presenceDetection),
215 std::move(configuration));
216 Device* devicePtr = device.get();
217
218 // Create Chassis that contains Device
219 std::vector<std::unique_ptr<Device>> devices{};
220 devices.emplace_back(std::move(device));
221 std::unique_ptr<Chassis> chassis =
222 std::make_unique<Chassis>(1, std::move(devices));
223 Chassis* chassisPtr = chassis.get();
224
225 // Create System that contains Chassis
226 std::vector<std::unique_ptr<Rule>> rules{};
227 std::vector<std::unique_ptr<Chassis>> chassisVec{};
228 chassisVec.emplace_back(std::move(chassis));
229 System system{std::move(rules), std::move(chassisVec)};
230
231 // Execute Configuration
232 journal::clear();
233 configurationPtr->execute(system, *chassisPtr, *devicePtr);
234 std::vector<std::string> expectedDebugMessages{"Configuring vdd_reg"};
235 EXPECT_EQ(journal::getDebugMessages(), expectedDebugMessages);
236 std::vector<std::string> expectedErrMessages{
237 "I2CException: Failed to write byte: bus /dev/i2c-1, addr 0x70",
238 "ActionError: i2c_write_byte: { register: 0x7C, value: 0xA, mask: "
239 "0xFF }",
240 "Unable to configure vdd_reg"};
241 EXPECT_EQ(journal::getErrMessages(), expectedErrMessages);
242 }
243}
244
245// Test for execute(System&, Chassis&, Device&, Rail&)
246TEST(ConfigurationTests, ExecuteForRail)
247{
248 // Test where works: Volts value not specified
249 {
250 // Create I2CWriteByteAction with register 0x7C and value 0x0A
251 std::unique_ptr<I2CWriteByteAction> action =
252 std::make_unique<I2CWriteByteAction>(0x7C, 0x0A);
253
254 // Create mock I2CInterface. Expect action to write 0x0A to 0x7C.
255 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
256 std::make_unique<i2c::MockedI2CInterface>();
257 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
258 EXPECT_CALL(*i2cInterface,
259 write(TypedEq<uint8_t>(0x7C), TypedEq<uint8_t>(0x0A)))
260 .Times(1);
261
262 // Create Configuration with no volts value specified
263 std::optional<double> volts{};
264 std::vector<std::unique_ptr<Action>> actions{};
265 actions.emplace_back(std::move(action));
266 std::unique_ptr<Configuration> configuration =
267 std::make_unique<Configuration>(volts, std::move(actions));
268 Configuration* configurationPtr = configuration.get();
269
270 // Create Rail that contains Configuration
271 std::unique_ptr<Rail> rail =
272 std::make_unique<Rail>("vio2", std::move(configuration));
273 Rail* railPtr = rail.get();
274
275 // Create Device that contains Rail
276 std::unique_ptr<PresenceDetection> presenceDetection{};
277 std::unique_ptr<Configuration> deviceConfiguration{};
278 std::vector<std::unique_ptr<Rail>> rails{};
279 rails.emplace_back(std::move(rail));
280 std::unique_ptr<Device> device = std::make_unique<Device>(
281 "reg1", true, "/system/chassis/motherboard/reg1",
282 std::move(i2cInterface), std::move(presenceDetection),
283 std::move(deviceConfiguration), std::move(rails));
284 Device* devicePtr = device.get();
285
286 // Create Chassis that contains Device
287 std::vector<std::unique_ptr<Device>> devices{};
288 devices.emplace_back(std::move(device));
289 std::unique_ptr<Chassis> chassis =
290 std::make_unique<Chassis>(1, std::move(devices));
291 Chassis* chassisPtr = chassis.get();
292
293 // Create System that contains Chassis
294 std::vector<std::unique_ptr<Rule>> rules{};
295 std::vector<std::unique_ptr<Chassis>> chassisVec{};
296 chassisVec.emplace_back(std::move(chassis));
297 System system{std::move(rules), std::move(chassisVec)};
298
299 // Execute Configuration
300 journal::clear();
301 configurationPtr->execute(system, *chassisPtr, *devicePtr, *railPtr);
302 std::vector<std::string> expectedDebugMessages{"Configuring vio2"};
303 EXPECT_EQ(journal::getDebugMessages(), expectedDebugMessages);
304 EXPECT_EQ(journal::getErrMessages().size(), 0);
305 }
306
307 // Test where works: Volts value specified
308 {
309 // Create PMBusWriteVoutCommandAction. Do not specify a volts value
310 // because it will get a value of 1.3V from the
311 // ActionEnvironment/Configuration. Specify a -8 exponent.
312 // Linear format volts value = (1.3 / 2^(-8)) = 332.8 = 333 = 0x014D.
313 std::optional<double> volts{};
314 std::unique_ptr<PMBusWriteVoutCommandAction> action =
315 std::make_unique<PMBusWriteVoutCommandAction>(
316 volts, pmbus_utils::VoutDataFormat::linear, -8, false);
317
318 // Create mock I2CInterface. Expect action to write 0x014D to
319 // VOUT_COMMAND (command/register 0x21).
320 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
321 std::make_unique<i2c::MockedI2CInterface>();
322 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
323 EXPECT_CALL(*i2cInterface,
324 write(TypedEq<uint8_t>(0x21), TypedEq<uint16_t>(0x014D)))
325 .Times(1);
326
327 // Create Configuration with volts value 1.3V
328 std::vector<std::unique_ptr<Action>> actions{};
329 actions.emplace_back(std::move(action));
330 std::unique_ptr<Configuration> configuration =
331 std::make_unique<Configuration>(1.3, std::move(actions));
332 Configuration* configurationPtr = configuration.get();
333
334 // Create Rail that contains Configuration
335 std::unique_ptr<Rail> rail =
336 std::make_unique<Rail>("vio2", std::move(configuration));
337 Rail* railPtr = rail.get();
338
339 // Create Device that contains Rail
340 std::unique_ptr<PresenceDetection> presenceDetection{};
341 std::unique_ptr<Configuration> deviceConfiguration{};
342 std::vector<std::unique_ptr<Rail>> rails{};
343 rails.emplace_back(std::move(rail));
344 std::unique_ptr<Device> device = std::make_unique<Device>(
345 "reg1", true, "/system/chassis/motherboard/reg1",
346 std::move(i2cInterface), std::move(presenceDetection),
347 std::move(deviceConfiguration), std::move(rails));
348 Device* devicePtr = device.get();
349
350 // Create Chassis that contains Device
351 std::vector<std::unique_ptr<Device>> devices{};
352 devices.emplace_back(std::move(device));
353 std::unique_ptr<Chassis> chassis =
354 std::make_unique<Chassis>(1, std::move(devices));
355 Chassis* chassisPtr = chassis.get();
356
357 // Create System that contains Chassis
358 std::vector<std::unique_ptr<Rule>> rules{};
359 std::vector<std::unique_ptr<Chassis>> chassisVec{};
360 chassisVec.emplace_back(std::move(chassis));
361 System system{std::move(rules), std::move(chassisVec)};
362
363 // Execute Configuration
364 journal::clear();
365 configurationPtr->execute(system, *chassisPtr, *devicePtr, *railPtr);
366 std::vector<std::string> expectedDebugMessages{
367 "Configuring vio2: volts=1.300000"};
368 EXPECT_EQ(journal::getDebugMessages(), expectedDebugMessages);
369 EXPECT_EQ(journal::getErrMessages().size(), 0);
370 }
371
372 // Test where fails
373 {
374 // Create I2CWriteByteAction with register 0x7C and value 0x0A
375 std::unique_ptr<I2CWriteByteAction> action =
376 std::make_unique<I2CWriteByteAction>(0x7C, 0x0A);
377
378 // Create mock I2CInterface. write() throws an I2CException.
379 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
380 std::make_unique<i2c::MockedI2CInterface>();
381 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
382 EXPECT_CALL(*i2cInterface,
383 write(TypedEq<uint8_t>(0x7C), TypedEq<uint8_t>(0x0A)))
384 .Times(1)
385 .WillOnce(Throw(
386 i2c::I2CException{"Failed to write byte", "/dev/i2c-1", 0x70}));
387
388 // Create Configuration with no volts value specified
389 std::optional<double> volts{};
390 std::vector<std::unique_ptr<Action>> actions{};
391 actions.emplace_back(std::move(action));
392 std::unique_ptr<Configuration> configuration =
393 std::make_unique<Configuration>(volts, std::move(actions));
394 Configuration* configurationPtr = configuration.get();
395
396 // Create Rail that contains Configuration
397 std::unique_ptr<Rail> rail =
398 std::make_unique<Rail>("vio2", std::move(configuration));
399 Rail* railPtr = rail.get();
400
401 // Create Device that contains Rail
402 std::unique_ptr<PresenceDetection> presenceDetection{};
403 std::unique_ptr<Configuration> deviceConfiguration{};
404 std::vector<std::unique_ptr<Rail>> rails{};
405 rails.emplace_back(std::move(rail));
406 std::unique_ptr<Device> device = std::make_unique<Device>(
407 "reg1", true, "/system/chassis/motherboard/reg1",
408 std::move(i2cInterface), std::move(presenceDetection),
409 std::move(deviceConfiguration), std::move(rails));
410 Device* devicePtr = device.get();
411
412 // Create Chassis that contains Device
413 std::vector<std::unique_ptr<Device>> devices{};
414 devices.emplace_back(std::move(device));
415 std::unique_ptr<Chassis> chassis =
416 std::make_unique<Chassis>(1, std::move(devices));
417 Chassis* chassisPtr = chassis.get();
418
419 // Create System that contains Chassis
420 std::vector<std::unique_ptr<Rule>> rules{};
421 std::vector<std::unique_ptr<Chassis>> chassisVec{};
422 chassisVec.emplace_back(std::move(chassis));
423 System system{std::move(rules), std::move(chassisVec)};
424
425 // Execute Configuration
426 journal::clear();
427 configurationPtr->execute(system, *chassisPtr, *devicePtr, *railPtr);
428 std::vector<std::string> expectedDebugMessages{"Configuring vio2"};
429 EXPECT_EQ(journal::getDebugMessages(), expectedDebugMessages);
430 std::vector<std::string> expectedErrMessages{
431 "I2CException: Failed to write byte: bus /dev/i2c-1, addr 0x70",
432 "ActionError: i2c_write_byte: { register: 0x7C, value: 0xA, mask: "
433 "0xFF }",
434 "Unable to configure vio2"};
435 EXPECT_EQ(journal::getErrMessages(), expectedErrMessages);
436 }
Shawn McCarneyd3a8aab2020-03-10 10:30:02 -0500437}
438
439TEST(ConfigurationTests, GetActions)
440{
441 std::optional<double> volts{1.3};
442
443 std::vector<std::unique_ptr<Action>> actions{};
444
445 MockAction* action1 = new MockAction{};
446 actions.push_back(std::unique_ptr<MockAction>{action1});
447
448 MockAction* action2 = new MockAction{};
449 actions.push_back(std::unique_ptr<MockAction>{action2});
450
451 Configuration configuration(volts, std::move(actions));
452 EXPECT_EQ(configuration.getActions().size(), 2);
453 EXPECT_EQ(configuration.getActions()[0].get(), action1);
454 EXPECT_EQ(configuration.getActions()[1].get(), action2);
455}
456
457TEST(ConfigurationTests, GetVolts)
458{
459 // Test where volts value specified
460 {
461 std::optional<double> volts{3.2};
462
463 std::vector<std::unique_ptr<Action>> actions{};
464 actions.push_back(std::make_unique<MockAction>());
465
466 Configuration configuration(volts, std::move(actions));
467 EXPECT_EQ(configuration.getVolts().has_value(), true);
468 EXPECT_EQ(configuration.getVolts().value(), 3.2);
469 }
470
471 // Test where volts value not specified
472 {
473 std::optional<double> volts{};
474
475 std::vector<std::unique_ptr<Action>> actions{};
476 actions.push_back(std::make_unique<MockAction>());
477
478 Configuration configuration(volts, std::move(actions));
479 EXPECT_EQ(configuration.getVolts().has_value(), false);
480 }
481}