blob: d9bc8d3b32344e90e4fab9b3f585cb5610fb9807 [file] [log] [blame]
Shawn McCarneya2461b32019-10-24 18:53:01 -05001/**
2 * Copyright © 2019 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 */
Shawn McCarney0b1a0e72020-03-11 18:01:44 -050016#include "action.hpp"
Shawn McCarneyeb7bec42020-04-14 09:38:15 -050017#include "chassis.hpp"
Shawn McCarney0b1a0e72020-03-11 18:01:44 -050018#include "configuration.hpp"
Shawn McCarneya2461b32019-10-24 18:53:01 -050019#include "device.hpp"
Shawn McCarneyafb7fc32019-12-11 19:42:03 -060020#include "i2c_interface.hpp"
Shawn McCarneydb0b8332020-04-06 14:13:04 -050021#include "id_map.hpp"
Shawn McCarneyeb7bec42020-04-14 09:38:15 -050022#include "journal.hpp"
Shawn McCarney0b1a0e72020-03-11 18:01:44 -050023#include "mock_action.hpp"
Shawn McCarneyeb7bec42020-04-14 09:38:15 -050024#include "mock_journal.hpp"
Shawn McCarneyb4d18a42020-06-02 10:27:05 -050025#include "mocked_i2c_interface.hpp"
Shawn McCarney0b1a0e72020-03-11 18:01:44 -050026#include "presence_detection.hpp"
27#include "rail.hpp"
Shawn McCarneyeb7bec42020-04-14 09:38:15 -050028#include "rule.hpp"
Shawn McCarneyeb7bec42020-04-14 09:38:15 -050029#include "system.hpp"
Shawn McCarney8a3afd72020-03-12 14:28:44 -050030#include "test_utils.hpp"
Shawn McCarneyafb7fc32019-12-11 19:42:03 -060031
32#include <memory>
Shawn McCarney0b1a0e72020-03-11 18:01:44 -050033#include <optional>
Shawn McCarney525e20c2020-04-14 11:05:39 -050034#include <string>
Shawn McCarneyafb7fc32019-12-11 19:42:03 -060035#include <utility>
Shawn McCarney0b1a0e72020-03-11 18:01:44 -050036#include <vector>
Shawn McCarneya2461b32019-10-24 18:53:01 -050037
Shawn McCarneyeb7bec42020-04-14 09:38:15 -050038#include <gmock/gmock.h>
Shawn McCarneya2461b32019-10-24 18:53:01 -050039#include <gtest/gtest.h>
40
41using namespace phosphor::power::regulators;
Shawn McCarney8a3afd72020-03-12 14:28:44 -050042using namespace phosphor::power::regulators::test_utils;
Shawn McCarneyafb7fc32019-12-11 19:42:03 -060043
Shawn McCarneyeb7bec42020-04-14 09:38:15 -050044using ::testing::Return;
Shawn McCarneyb4d18a42020-06-02 10:27:05 -050045using ::testing::Throw;
Shawn McCarneyeb7bec42020-04-14 09:38:15 -050046
Shawn McCarneya2461b32019-10-24 18:53:01 -050047TEST(DeviceTests, Constructor)
48{
Shawn McCarney0b1a0e72020-03-11 18:01:44 -050049 // Test where only required parameters are specified
50 {
51 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
52 i2c::I2CInterface* i2cInterfacePtr = i2cInterface.get();
53 Device device{"vdd_reg", true, "/system/chassis/motherboard/reg2",
54 std::move(i2cInterface)};
55 EXPECT_EQ(device.getID(), "vdd_reg");
56 EXPECT_EQ(device.isRegulator(), true);
57 EXPECT_EQ(device.getFRU(), "/system/chassis/motherboard/reg2");
58 EXPECT_EQ(&(device.getI2CInterface()), i2cInterfacePtr);
59 EXPECT_EQ(device.getPresenceDetection(), nullptr);
60 EXPECT_EQ(device.getConfiguration(), nullptr);
61 EXPECT_EQ(device.getRails().size(), 0);
62 }
63
64 // Test where all parameters are specified
65 {
66 // Create I2CInterface
67 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
68 i2c::I2CInterface* i2cInterfacePtr = i2cInterface.get();
69
70 // Create PresenceDetection
71 std::vector<std::unique_ptr<Action>> actions{};
72 actions.push_back(std::make_unique<MockAction>());
73 std::unique_ptr<PresenceDetection> presenceDetection =
74 std::make_unique<PresenceDetection>(std::move(actions));
75
76 // Create Configuration
77 std::optional<double> volts{};
78 actions.clear();
79 actions.push_back(std::make_unique<MockAction>());
80 actions.push_back(std::make_unique<MockAction>());
81 std::unique_ptr<Configuration> configuration =
82 std::make_unique<Configuration>(volts, std::move(actions));
83
84 // Create vector of Rail objects
85 std::vector<std::unique_ptr<Rail>> rails{};
86 rails.push_back(std::make_unique<Rail>("vdd0"));
87 rails.push_back(std::make_unique<Rail>("vdd1"));
88
89 // Create Device
90 Device device{"vdd_reg",
91 false,
92 "/system/chassis/motherboard/reg1",
93 std::move(i2cInterface),
94 std::move(presenceDetection),
95 std::move(configuration),
96 std::move(rails)};
97 EXPECT_EQ(device.getID(), "vdd_reg");
98 EXPECT_EQ(device.isRegulator(), false);
99 EXPECT_EQ(device.getFRU(), "/system/chassis/motherboard/reg1");
100 EXPECT_EQ(&(device.getI2CInterface()), i2cInterfacePtr);
101 EXPECT_NE(device.getPresenceDetection(), nullptr);
102 EXPECT_EQ(device.getPresenceDetection()->getActions().size(), 1);
103 EXPECT_NE(device.getConfiguration(), nullptr);
104 EXPECT_EQ(device.getConfiguration()->getVolts().has_value(), false);
105 EXPECT_EQ(device.getConfiguration()->getActions().size(), 2);
106 EXPECT_EQ(device.getRails().size(), 2);
107 }
Shawn McCarneya2461b32019-10-24 18:53:01 -0500108}
109
Shawn McCarneydb0b8332020-04-06 14:13:04 -0500110TEST(DeviceTests, AddToIDMap)
111{
112 std::unique_ptr<PresenceDetection> presenceDetection{};
113 std::unique_ptr<Configuration> configuration{};
114
115 // Create vector of Rail objects
116 std::vector<std::unique_ptr<Rail>> rails{};
117 rails.push_back(std::make_unique<Rail>("vdd0"));
118 rails.push_back(std::make_unique<Rail>("vdd1"));
119
120 // Create Device
121 Device device{"vdd_reg",
122 false,
123 "/system/chassis/motherboard/reg2",
124 std::move(createI2CInterface()),
125 std::move(presenceDetection),
126 std::move(configuration),
127 std::move(rails)};
128
129 // Add Device and Rail objects to an IDMap
130 IDMap idMap{};
131 device.addToIDMap(idMap);
132
133 // Verify Device is in the IDMap
134 EXPECT_NO_THROW(idMap.getDevice("vdd_reg"));
135 EXPECT_THROW(idMap.getDevice("vio_reg"), std::invalid_argument);
136
137 // Verify all Rails are in the IDMap
138 EXPECT_NO_THROW(idMap.getRail("vdd0"));
139 EXPECT_NO_THROW(idMap.getRail("vdd1"));
140 EXPECT_THROW(idMap.getRail("vdd2"), std::invalid_argument);
141}
142
Shawn McCarneyb4d18a42020-06-02 10:27:05 -0500143TEST(DeviceTests, Close)
144{
145 // Test where works: I2C interface is not open
146 {
147 // Create mock I2CInterface
148 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
149 std::make_unique<i2c::MockedI2CInterface>();
150 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(false));
151 EXPECT_CALL(*i2cInterface, close).Times(0);
152
153 // Create Device
154 Device device{"vdd_reg", true, "/system/chassis/motherboard/reg2",
155 std::move(i2cInterface)};
156
157 // Close Device
158 journal::clear();
159 device.close();
160 EXPECT_EQ(journal::getErrMessages().size(), 0);
161 }
162
163 // Test where works: I2C interface is open
164 {
165 // Create mock I2CInterface
166 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
167 std::make_unique<i2c::MockedI2CInterface>();
168 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
169 EXPECT_CALL(*i2cInterface, close).Times(1);
170
171 // Create Device
172 Device device{"vdd_reg", true, "/system/chassis/motherboard/reg2",
173 std::move(i2cInterface)};
174
175 // Close Device
176 journal::clear();
177 device.close();
178 EXPECT_EQ(journal::getErrMessages().size(), 0);
179 }
180
181 // Test where fails: closing I2C interface fails
182 {
183 // Create mock I2CInterface
184 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
185 std::make_unique<i2c::MockedI2CInterface>();
186 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
187 EXPECT_CALL(*i2cInterface, close)
188 .Times(1)
189 .WillOnce(Throw(
190 i2c::I2CException{"Failed to close", "/dev/i2c-1", 0x70}));
191
192 // Create Device
193 Device device{"vdd_reg", true, "/system/chassis/motherboard/reg2",
194 std::move(i2cInterface)};
195
196 // Close Device
197 journal::clear();
198 device.close();
199 std::vector<std::string> expectedErrMessages{
200 "I2CException: Failed to close: bus /dev/i2c-1, addr 0x70",
201 "Unable to close device vdd_reg"};
202 EXPECT_EQ(journal::getErrMessages(), expectedErrMessages);
203 }
204}
205
Shawn McCarneyeb7bec42020-04-14 09:38:15 -0500206TEST(DeviceTests, Configure)
207{
208 // Test where Configuration and Rails were not specified in constructor
209 {
210 // Create Device
211 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
212 std::unique_ptr<Device> device = std::make_unique<Device>(
213 "reg1", true, "/system/chassis/motherboard/reg1",
214 std::move(i2cInterface));
215 Device* devicePtr = device.get();
216
217 // Create Chassis that contains Device
218 std::vector<std::unique_ptr<Device>> devices{};
219 devices.emplace_back(std::move(device));
220 std::unique_ptr<Chassis> chassis =
221 std::make_unique<Chassis>(1, std::move(devices));
222 Chassis* chassisPtr = chassis.get();
223
224 // Create System that contains Chassis
225 std::vector<std::unique_ptr<Rule>> rules{};
226 std::vector<std::unique_ptr<Chassis>> chassisVec{};
227 chassisVec.emplace_back(std::move(chassis));
228 System system{std::move(rules), std::move(chassisVec)};
229
230 // Call configure(). Should do nothing.
231 journal::clear();
232 devicePtr->configure(system, *chassisPtr);
233 EXPECT_EQ(journal::getDebugMessages().size(), 0);
234 EXPECT_EQ(journal::getErrMessages().size(), 0);
235 }
236
237 // Test where Configuration and Rails were specified in constructor
238 {
239 std::vector<std::unique_ptr<Rail>> rails{};
240
241 // Create Rail vdd0
242 {
243 // Create Configuration for Rail
244 std::optional<double> volts{1.3};
245 std::unique_ptr<MockAction> action = std::make_unique<MockAction>();
246 EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true));
247 std::vector<std::unique_ptr<Action>> actions{};
248 actions.emplace_back(std::move(action));
249 std::unique_ptr<Configuration> configuration =
250 std::make_unique<Configuration>(volts, std::move(actions));
251
252 // Create Rail
253 std::unique_ptr<Rail> rail =
254 std::make_unique<Rail>("vdd0", std::move(configuration));
255 rails.emplace_back(std::move(rail));
256 }
257
258 // Create Rail vio0
259 {
260 // Create Configuration for Rail
261 std::optional<double> volts{3.2};
262 std::unique_ptr<MockAction> action = std::make_unique<MockAction>();
263 EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true));
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
269 // Create Rail
270 std::unique_ptr<Rail> rail =
271 std::make_unique<Rail>("vio0", std::move(configuration));
272 rails.emplace_back(std::move(rail));
273 }
274
275 // Create Configuration for Device
276 std::optional<double> volts{};
277 std::unique_ptr<MockAction> action = std::make_unique<MockAction>();
278 EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true));
279 std::vector<std::unique_ptr<Action>> actions{};
280 actions.emplace_back(std::move(action));
281 std::unique_ptr<Configuration> configuration =
282 std::make_unique<Configuration>(volts, std::move(actions));
283
284 // Create Device
285 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
286 std::unique_ptr<PresenceDetection> presenceDetection{};
287 std::unique_ptr<Device> device = std::make_unique<Device>(
288 "reg1", true, "/system/chassis/motherboard/reg1",
289 std::move(i2cInterface), std::move(presenceDetection),
290 std::move(configuration), std::move(rails));
291 Device* devicePtr = device.get();
292
293 // Create Chassis that contains Device
294 std::vector<std::unique_ptr<Device>> devices{};
295 devices.emplace_back(std::move(device));
296 std::unique_ptr<Chassis> chassis =
297 std::make_unique<Chassis>(1, std::move(devices));
298 Chassis* chassisPtr = chassis.get();
299
300 // Create System that contains Chassis
301 std::vector<std::unique_ptr<Rule>> rules{};
302 std::vector<std::unique_ptr<Chassis>> chassisVec{};
303 chassisVec.emplace_back(std::move(chassis));
304 System system{std::move(rules), std::move(chassisVec)};
305
306 // Call configure(). For the Device and both Rails, should execute the
307 // Configuration and log a debug message.
308 journal::clear();
309 devicePtr->configure(system, *chassisPtr);
310 std::vector<std::string> expectedDebugMessages{
Shawn McCarney525e20c2020-04-14 11:05:39 -0500311 "Configuring reg1", "Configuring vdd0: volts=1.300000",
312 "Configuring vio0: volts=3.200000"};
Shawn McCarneyeb7bec42020-04-14 09:38:15 -0500313 EXPECT_EQ(journal::getDebugMessages(), expectedDebugMessages);
314 EXPECT_EQ(journal::getErrMessages().size(), 0);
315 }
316}
317
Shawn McCarney0b1a0e72020-03-11 18:01:44 -0500318TEST(DeviceTests, GetConfiguration)
Shawn McCarneya2461b32019-10-24 18:53:01 -0500319{
Shawn McCarney0b1a0e72020-03-11 18:01:44 -0500320 // Test where Configuration was not specified in constructor
321 {
322 Device device{"vdd_reg", true, "/system/chassis/motherboard/reg2",
323 std::move(createI2CInterface())};
324 EXPECT_EQ(device.getConfiguration(), nullptr);
325 }
Shawn McCarneyafb7fc32019-12-11 19:42:03 -0600326
Shawn McCarney0b1a0e72020-03-11 18:01:44 -0500327 // Test where Configuration was specified in constructor
328 {
329 std::unique_ptr<PresenceDetection> presenceDetection{};
330
331 // Create Configuration
332 std::optional<double> volts{3.2};
333 std::vector<std::unique_ptr<Action>> actions{};
334 actions.push_back(std::make_unique<MockAction>());
335 actions.push_back(std::make_unique<MockAction>());
336 std::unique_ptr<Configuration> configuration =
337 std::make_unique<Configuration>(volts, std::move(actions));
338
339 // Create Device
340 Device device{"vdd_reg",
341 true,
342 "/system/chassis/motherboard/reg2",
343 std::move(createI2CInterface()),
344 std::move(presenceDetection),
345 std::move(configuration)};
346 EXPECT_NE(device.getConfiguration(), nullptr);
347 EXPECT_EQ(device.getConfiguration()->getVolts().has_value(), true);
348 EXPECT_EQ(device.getConfiguration()->getVolts().value(), 3.2);
349 EXPECT_EQ(device.getConfiguration()->getActions().size(), 2);
350 }
Shawn McCarneyafb7fc32019-12-11 19:42:03 -0600351}
352
353TEST(DeviceTests, GetFRU)
354{
355 Device device{"vdd_reg", true, "/system/chassis/motherboard/reg2",
356 std::move(createI2CInterface())};
357 EXPECT_EQ(device.getFRU(), "/system/chassis/motherboard/reg2");
358}
359
360TEST(DeviceTests, GetI2CInterface)
361{
362 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
363 i2c::I2CInterface* i2cInterfacePtr = i2cInterface.get();
364 Device device{"vdd_reg", true, "/system/chassis/motherboard/reg2",
365 std::move(i2cInterface)};
366 EXPECT_EQ(&(device.getI2CInterface()), i2cInterfacePtr);
Shawn McCarneya2461b32019-10-24 18:53:01 -0500367}
Shawn McCarney0b1a0e72020-03-11 18:01:44 -0500368
369TEST(DeviceTests, GetID)
370{
371 Device device{"vdd_reg", false, "/system/chassis/motherboard/reg2",
372 std::move(createI2CInterface())};
373 EXPECT_EQ(device.getID(), "vdd_reg");
374}
375
376TEST(DeviceTests, GetPresenceDetection)
377{
378 // Test where PresenceDetection was not specified in constructor
379 {
380 Device device{"vdd_reg", true, "/system/chassis/motherboard/reg2",
381 std::move(createI2CInterface())};
382 EXPECT_EQ(device.getPresenceDetection(), nullptr);
383 }
384
385 // Test where PresenceDetection was specified in constructor
386 {
387 // Create PresenceDetection
388 std::vector<std::unique_ptr<Action>> actions{};
389 actions.push_back(std::make_unique<MockAction>());
390 std::unique_ptr<PresenceDetection> presenceDetection =
391 std::make_unique<PresenceDetection>(std::move(actions));
392
393 // Create Device
394 Device device{"vdd_reg", false, "/system/chassis/motherboard/reg2",
395 std::move(createI2CInterface()),
396 std::move(presenceDetection)};
397 EXPECT_NE(device.getPresenceDetection(), nullptr);
398 EXPECT_EQ(device.getPresenceDetection()->getActions().size(), 1);
399 }
400}
401
402TEST(DeviceTests, GetRails)
403{
404 // Test where no rails were specified in constructor
405 {
406 Device device{"vdd_reg", true, "/system/chassis/motherboard/reg2",
407 std::move(createI2CInterface())};
408 EXPECT_EQ(device.getRails().size(), 0);
409 }
410
411 // Test where rails were specified in constructor
412 {
413 std::unique_ptr<PresenceDetection> presenceDetection{};
414 std::unique_ptr<Configuration> configuration{};
415
416 // Create vector of Rail objects
417 std::vector<std::unique_ptr<Rail>> rails{};
418 rails.push_back(std::make_unique<Rail>("vdd0"));
419 rails.push_back(std::make_unique<Rail>("vdd1"));
420
421 // Create Device
422 Device device{"vdd_reg",
423 false,
424 "/system/chassis/motherboard/reg2",
425 std::move(createI2CInterface()),
426 std::move(presenceDetection),
427 std::move(configuration),
428 std::move(rails)};
429 EXPECT_EQ(device.getRails().size(), 2);
430 EXPECT_EQ(device.getRails()[0]->getID(), "vdd0");
431 EXPECT_EQ(device.getRails()[1]->getID(), "vdd1");
432 }
433}
434
435TEST(DeviceTests, IsRegulator)
436{
437 Device device{"vdd_reg", false, "/system/chassis/motherboard/reg2",
438 std::move(createI2CInterface())};
439 EXPECT_EQ(device.isRegulator(), false);
440}