blob: 601bf3feff9c0bc724d50132a8dae8ceaad5de58 [file] [log] [blame]
Shawn McCarney8a3afd72020-03-12 14:28:44 -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 */
Shawn McCarney525e20c2020-04-14 11:05:39 -050016#include "action.hpp"
Shawn McCarney8a3afd72020-03-12 14:28:44 -050017#include "chassis.hpp"
Shawn McCarney525e20c2020-04-14 11:05:39 -050018#include "configuration.hpp"
Shawn McCarney8a3afd72020-03-12 14:28:44 -050019#include "device.hpp"
20#include "i2c_interface.hpp"
Shawn McCarneydb0b8332020-04-06 14:13:04 -050021#include "id_map.hpp"
Shawn McCarney525e20c2020-04-14 11:05:39 -050022#include "mock_journal.hpp"
Bob King23243f82020-07-29 10:38:57 +080023#include "mock_services.hpp"
Shawn McCarney050531f2020-06-02 14:17:12 -050024#include "mocked_i2c_interface.hpp"
Bob Kinga2c81a62020-07-08 13:31:16 +080025#include "pmbus_read_sensor_action.hpp"
Shawn McCarney525e20c2020-04-14 11:05:39 -050026#include "presence_detection.hpp"
27#include "rail.hpp"
28#include "rule.hpp"
29#include "system.hpp"
Shawn McCarney8a3afd72020-03-12 14:28:44 -050030#include "test_utils.hpp"
31
32#include <memory>
33#include <stdexcept>
Shawn McCarney525e20c2020-04-14 11:05:39 -050034#include <string>
Shawn McCarney8a3afd72020-03-12 14:28:44 -050035#include <utility>
36#include <vector>
37
Bob Kinga2c81a62020-07-08 13:31:16 +080038#include <gmock/gmock.h>
Shawn McCarney8a3afd72020-03-12 14:28:44 -050039#include <gtest/gtest.h>
40
41using namespace phosphor::power::regulators;
42using namespace phosphor::power::regulators::test_utils;
43
Bob Kinga2c81a62020-07-08 13:31:16 +080044using ::testing::A;
Shawn McCarney050531f2020-06-02 14:17:12 -050045using ::testing::Return;
Bob Kinga2c81a62020-07-08 13:31:16 +080046using ::testing::TypedEq;
Shawn McCarney050531f2020-06-02 14:17:12 -050047
Shawn McCarney8a3afd72020-03-12 14:28:44 -050048TEST(ChassisTests, Constructor)
49{
50 // Test where works: Only required parameters are specified
51 {
52 Chassis chassis{2};
53 EXPECT_EQ(chassis.getNumber(), 2);
54 EXPECT_EQ(chassis.getDevices().size(), 0);
55 }
56
57 // Test where works: All parameters are specified
58 {
59 // Create vector of Device objects
60 std::vector<std::unique_ptr<Device>> devices{};
Shawn McCarneydb0b8332020-04-06 14:13:04 -050061 devices.emplace_back(createDevice("vdd_reg1"));
62 devices.emplace_back(createDevice("vdd_reg2"));
Shawn McCarney8a3afd72020-03-12 14:28:44 -050063
64 // Create Chassis
65 Chassis chassis{1, std::move(devices)};
66 EXPECT_EQ(chassis.getNumber(), 1);
67 EXPECT_EQ(chassis.getDevices().size(), 2);
68 }
69
70 // Test where fails: Invalid chassis number < 1
71 try
72 {
73 Chassis chassis{0};
74 ADD_FAILURE() << "Should not have reached this line.";
75 }
76 catch (const std::invalid_argument& e)
77 {
78 EXPECT_STREQ(e.what(), "Invalid chassis number: 0");
79 }
80 catch (...)
81 {
82 ADD_FAILURE() << "Should not have caught exception.";
83 }
84}
85
Shawn McCarneydb0b8332020-04-06 14:13:04 -050086TEST(ChassisTests, AddToIDMap)
87{
88 // Create vector of Device objects
89 std::vector<std::unique_ptr<Device>> devices{};
90 devices.emplace_back(createDevice("reg1", {"rail1"}));
91 devices.emplace_back(createDevice("reg2", {"rail2a", "rail2b"}));
92 devices.emplace_back(createDevice("reg3"));
93
94 // Create Chassis
95 Chassis chassis{1, std::move(devices)};
96
97 // Add Device and Rail objects within the Chassis to an IDMap
98 IDMap idMap{};
99 chassis.addToIDMap(idMap);
100
101 // Verify all Devices are in the IDMap
102 EXPECT_NO_THROW(idMap.getDevice("reg1"));
103 EXPECT_NO_THROW(idMap.getDevice("reg2"));
104 EXPECT_NO_THROW(idMap.getDevice("reg3"));
105 EXPECT_THROW(idMap.getDevice("reg4"), std::invalid_argument);
106
107 // Verify all Rails are in the IDMap
108 EXPECT_NO_THROW(idMap.getRail("rail1"));
109 EXPECT_NO_THROW(idMap.getRail("rail2a"));
110 EXPECT_NO_THROW(idMap.getRail("rail2b"));
111 EXPECT_THROW(idMap.getRail("rail3"), std::invalid_argument);
112}
113
Shawn McCarney9bd94d32021-01-25 19:40:42 -0600114TEST(ChassisTests, ClearCache)
115{
116 // Create PresenceDetection
117 std::vector<std::unique_ptr<Action>> actions{};
118 std::unique_ptr<PresenceDetection> presenceDetection =
119 std::make_unique<PresenceDetection>(std::move(actions));
120 PresenceDetection* presenceDetectionPtr = presenceDetection.get();
121
122 // Create Device that contains PresenceDetection
123 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
124 std::unique_ptr<Device> device = std::make_unique<Device>(
125 "reg1", true,
126 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
127 std::move(i2cInterface), std::move(presenceDetection));
128 Device* devicePtr = device.get();
129
130 // Create Chassis that contains Device
131 std::vector<std::unique_ptr<Device>> devices{};
132 devices.emplace_back(std::move(device));
133 std::unique_ptr<Chassis> chassis =
134 std::make_unique<Chassis>(1, std::move(devices));
135 Chassis* chassisPtr = chassis.get();
136
137 // Create System that contains Chassis
138 std::vector<std::unique_ptr<Rule>> rules{};
139 std::vector<std::unique_ptr<Chassis>> chassisVec{};
140 chassisVec.emplace_back(std::move(chassis));
141 System system{std::move(rules), std::move(chassisVec)};
142
143 // Cache presence value in PresenceDetection
144 MockServices services{};
145 presenceDetectionPtr->execute(services, system, *chassisPtr, *devicePtr);
146 EXPECT_TRUE(presenceDetectionPtr->getCachedPresence().has_value());
147
148 // Clear cached data in Chassis
149 chassisPtr->clearCache();
150
151 // Verify presence value no longer cached in PresenceDetection
152 EXPECT_FALSE(presenceDetectionPtr->getCachedPresence().has_value());
153}
154
Shawn McCarney050531f2020-06-02 14:17:12 -0500155TEST(ChassisTests, CloseDevices)
156{
157 // Test where no devices were specified in constructor
158 {
Bob Kingd692d6d2020-09-14 13:42:57 +0800159 // Create mock services. Expect logDebug() to be called.
160 MockServices services{};
161 MockJournal& journal = services.getMockJournal();
162 EXPECT_CALL(journal, logDebug("Closing devices in chassis 2")).Times(1);
163
Shawn McCarney050531f2020-06-02 14:17:12 -0500164 // Create Chassis
165 Chassis chassis{2};
166
167 // Call closeDevices()
Bob Kingd692d6d2020-09-14 13:42:57 +0800168 chassis.closeDevices(services);
Shawn McCarney050531f2020-06-02 14:17:12 -0500169 }
170
171 // Test where devices were specified in constructor
172 {
173 std::vector<std::unique_ptr<Device>> devices{};
174
Bob Kingd692d6d2020-09-14 13:42:57 +0800175 // Create mock services. Expect logDebug() to be called.
176 MockServices services{};
177 MockJournal& journal = services.getMockJournal();
178 EXPECT_CALL(journal, logDebug("Closing devices in chassis 1")).Times(1);
179
Shawn McCarney050531f2020-06-02 14:17:12 -0500180 // Create Device vdd0_reg
181 {
182 // Create mock I2CInterface: isOpen() and close() should be called
183 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
184 std::make_unique<i2c::MockedI2CInterface>();
185 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
186 EXPECT_CALL(*i2cInterface, close).Times(1);
187
188 // Create Device
Bob Kinga76898f2020-10-13 15:08:33 +0800189 std::unique_ptr<Device> device =
190 std::make_unique<Device>("vdd0_reg", true,
191 "/xyz/openbmc_project/inventory/"
192 "system/chassis/motherboard/vdd0_reg",
193 std::move(i2cInterface));
Shawn McCarney050531f2020-06-02 14:17:12 -0500194 devices.emplace_back(std::move(device));
195 }
196
197 // Create Device vdd1_reg
198 {
199 // Create mock I2CInterface: isOpen() and close() should be called
200 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
201 std::make_unique<i2c::MockedI2CInterface>();
202 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
203 EXPECT_CALL(*i2cInterface, close).Times(1);
204
205 // Create Device
Bob Kinga76898f2020-10-13 15:08:33 +0800206 std::unique_ptr<Device> device =
207 std::make_unique<Device>("vdd1_reg", true,
208 "/xyz/openbmc_project/inventory/"
209 "system/chassis/motherboard/vdd1_reg",
210 std::move(i2cInterface));
Shawn McCarney050531f2020-06-02 14:17:12 -0500211 devices.emplace_back(std::move(device));
212 }
213
214 // Create Chassis
215 Chassis chassis{1, std::move(devices)};
216
217 // Call closeDevices()
Bob Kingd692d6d2020-09-14 13:42:57 +0800218 chassis.closeDevices(services);
Shawn McCarney050531f2020-06-02 14:17:12 -0500219 }
220}
221
Shawn McCarney525e20c2020-04-14 11:05:39 -0500222TEST(ChassisTests, Configure)
223{
224 // Test where no devices were specified in constructor
225 {
Bob King5cfe5102020-07-30 16:26:18 +0800226 // Create mock services. Expect logInfo() to be called.
Bob King23243f82020-07-29 10:38:57 +0800227 MockServices services{};
Bob King5cfe5102020-07-30 16:26:18 +0800228 MockJournal& journal = services.getMockJournal();
229 EXPECT_CALL(journal, logInfo("Configuring chassis 1")).Times(1);
230 EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0);
231 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
Bob King23243f82020-07-29 10:38:57 +0800232
Shawn McCarney525e20c2020-04-14 11:05:39 -0500233 // Create Chassis
234 std::unique_ptr<Chassis> chassis = std::make_unique<Chassis>(1);
235 Chassis* chassisPtr = chassis.get();
236
237 // Create System that contains Chassis
238 std::vector<std::unique_ptr<Rule>> rules{};
239 std::vector<std::unique_ptr<Chassis>> chassisVec{};
240 chassisVec.emplace_back(std::move(chassis));
241 System system{std::move(rules), std::move(chassisVec)};
242
243 // Call configure()
Bob King23243f82020-07-29 10:38:57 +0800244 chassisPtr->configure(services, system);
Shawn McCarney525e20c2020-04-14 11:05:39 -0500245 }
246
247 // Test where devices were specified in constructor
248 {
249 std::vector<std::unique_ptr<Device>> devices{};
250
Bob King5cfe5102020-07-30 16:26:18 +0800251 // Create mock services. Expect logInfo() and logDebug() to be called.
252 MockServices services{};
253 MockJournal& journal = services.getMockJournal();
254 EXPECT_CALL(journal, logInfo("Configuring chassis 2")).Times(1);
255 EXPECT_CALL(journal, logDebug("Configuring vdd0_reg: volts=1.300000"))
256 .Times(1);
257 EXPECT_CALL(journal, logDebug("Configuring vdd1_reg: volts=1.200000"))
258 .Times(1);
259 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
260
Shawn McCarney525e20c2020-04-14 11:05:39 -0500261 // Create Device vdd0_reg
262 {
263 // Create Configuration
264 std::vector<std::unique_ptr<Action>> actions{};
265 std::unique_ptr<Configuration> configuration =
266 std::make_unique<Configuration>(1.3, std::move(actions));
267
268 // Create Device
269 std::unique_ptr<i2c::I2CInterface> i2cInterface =
270 createI2CInterface();
271 std::unique_ptr<PresenceDetection> presenceDetection{};
272 std::unique_ptr<Device> device = std::make_unique<Device>(
Bob Kinga76898f2020-10-13 15:08:33 +0800273 "vdd0_reg", true,
274 "/xyz/openbmc_project/inventory/system/chassis/motherboard/"
275 "vdd0_reg",
Shawn McCarney525e20c2020-04-14 11:05:39 -0500276 std::move(i2cInterface), std::move(presenceDetection),
277 std::move(configuration));
278 devices.emplace_back(std::move(device));
279 }
280
281 // Create Device vdd1_reg
282 {
283 // Create Configuration
284 std::vector<std::unique_ptr<Action>> actions{};
285 std::unique_ptr<Configuration> configuration =
286 std::make_unique<Configuration>(1.2, std::move(actions));
287
288 // Create Device
289 std::unique_ptr<i2c::I2CInterface> i2cInterface =
290 createI2CInterface();
291 std::unique_ptr<PresenceDetection> presenceDetection{};
292 std::unique_ptr<Device> device = std::make_unique<Device>(
Bob Kinga76898f2020-10-13 15:08:33 +0800293 "vdd1_reg", true,
294 "/xyz/openbmc_project/inventory/system/chassis/motherboard/"
295 "vdd1_reg",
Shawn McCarney525e20c2020-04-14 11:05:39 -0500296 std::move(i2cInterface), std::move(presenceDetection),
297 std::move(configuration));
298 devices.emplace_back(std::move(device));
299 }
300
301 // Create Chassis
302 std::unique_ptr<Chassis> chassis =
303 std::make_unique<Chassis>(2, std::move(devices));
304 Chassis* chassisPtr = chassis.get();
305
306 // Create System that contains Chassis
307 std::vector<std::unique_ptr<Rule>> rules{};
308 std::vector<std::unique_ptr<Chassis>> chassisVec{};
309 chassisVec.emplace_back(std::move(chassis));
310 System system{std::move(rules), std::move(chassisVec)};
311
312 // Call configure()
Bob King23243f82020-07-29 10:38:57 +0800313 chassisPtr->configure(services, system);
Shawn McCarney525e20c2020-04-14 11:05:39 -0500314 }
315}
316
Shawn McCarney8a3afd72020-03-12 14:28:44 -0500317TEST(ChassisTests, GetDevices)
318{
319 // Test where no devices were specified in constructor
320 {
321 Chassis chassis{2};
322 EXPECT_EQ(chassis.getDevices().size(), 0);
323 }
324
325 // Test where devices were specified in constructor
326 {
327 // Create vector of Device objects
328 std::vector<std::unique_ptr<Device>> devices{};
Shawn McCarneydb0b8332020-04-06 14:13:04 -0500329 devices.emplace_back(createDevice("vdd_reg1"));
330 devices.emplace_back(createDevice("vdd_reg2"));
Shawn McCarney8a3afd72020-03-12 14:28:44 -0500331
332 // Create Chassis
333 Chassis chassis{1, std::move(devices)};
334 EXPECT_EQ(chassis.getDevices().size(), 2);
335 EXPECT_EQ(chassis.getDevices()[0]->getID(), "vdd_reg1");
336 EXPECT_EQ(chassis.getDevices()[1]->getID(), "vdd_reg2");
337 }
338}
339
340TEST(ChassisTests, GetNumber)
341{
342 Chassis chassis{3};
343 EXPECT_EQ(chassis.getNumber(), 3);
344}
Bob Kinga2c81a62020-07-08 13:31:16 +0800345
346TEST(ChassisTests, MonitorSensors)
347{
348 // Test where no devices were specified in constructor
349 {
Bob King8a552922020-08-05 17:02:31 +0800350 // Create mock services. No logging should occur.
351 MockServices services{};
352 MockJournal& journal = services.getMockJournal();
353 EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0);
354 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
355
Bob Kinga2c81a62020-07-08 13:31:16 +0800356 // Create Chassis
357 std::vector<std::unique_ptr<Device>> devices{};
358 std::unique_ptr<Chassis> chassis =
359 std::make_unique<Chassis>(1, std::move(devices));
360 Chassis* chassisPtr = chassis.get();
361
362 // Create System that contains Chassis
363 std::vector<std::unique_ptr<Rule>> rules{};
364 std::vector<std::unique_ptr<Chassis>> chassisVec{};
365 chassisVec.emplace_back(std::move(chassis));
366 System system{std::move(rules), std::move(chassisVec)};
367
368 // Call monitorSensors(). Should do nothing.
Bob King8a552922020-08-05 17:02:31 +0800369 chassisPtr->monitorSensors(services, system);
Bob Kinga2c81a62020-07-08 13:31:16 +0800370 }
371
372 // Test where devices were specified in constructor
373 {
Bob King8a552922020-08-05 17:02:31 +0800374 // Create mock services. No logging should occur.
375 MockServices services{};
376 MockJournal& journal = services.getMockJournal();
377 EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0);
378 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
379
Bob Kinga2c81a62020-07-08 13:31:16 +0800380 std::vector<std::unique_ptr<Device>> devices{};
381
382 // Create PMBusReadSensorAction
383 pmbus_utils::SensorValueType type{pmbus_utils::SensorValueType::iout};
384 uint8_t command = 0x8C;
385 pmbus_utils::SensorDataFormat format{
386 pmbus_utils::SensorDataFormat::linear_11};
387 std::optional<int8_t> exponent{};
388 std::unique_ptr<PMBusReadSensorAction> action =
389 std::make_unique<PMBusReadSensorAction>(type, command, format,
390 exponent);
391
392 // Create mock I2CInterface. A two-byte read should occur.
393 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
394 std::make_unique<i2c::MockedI2CInterface>();
395 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
396 EXPECT_CALL(*i2cInterface, read(TypedEq<uint8_t>(0x8C), A<uint16_t&>()))
397 .Times(1);
398
399 // Create SensorMonitoring
400 std::vector<std::unique_ptr<Action>> actions{};
401 actions.emplace_back(std::move(action));
402 std::unique_ptr<SensorMonitoring> sensorMonitoring =
403 std::make_unique<SensorMonitoring>(std::move(actions));
404
405 // Create Rail
406 std::vector<std::unique_ptr<Rail>> rails{};
407 std::unique_ptr<Configuration> configuration{};
408 std::unique_ptr<Rail> rail = std::make_unique<Rail>(
409 "vdd0", std::move(configuration), std::move(sensorMonitoring));
410 rails.emplace_back(std::move(rail));
411
412 // Create Device
413 std::unique_ptr<PresenceDetection> presenceDetection{};
414 std::unique_ptr<Configuration> deviceConfiguration{};
415 std::unique_ptr<Device> device = std::make_unique<Device>(
Bob Kinga76898f2020-10-13 15:08:33 +0800416 "reg1", true,
417 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
Bob Kinga2c81a62020-07-08 13:31:16 +0800418 std::move(i2cInterface), std::move(presenceDetection),
419 std::move(deviceConfiguration), std::move(rails));
420
421 // Create Chassis
422 devices.emplace_back(std::move(device));
423 std::unique_ptr<Chassis> chassis =
424 std::make_unique<Chassis>(1, std::move(devices));
425 Chassis* chassisPtr = chassis.get();
426
427 // Create System that contains Chassis
428 std::vector<std::unique_ptr<Rule>> rules{};
429 std::vector<std::unique_ptr<Chassis>> chassisVec{};
430 chassisVec.emplace_back(std::move(chassis));
431 System system{std::move(rules), std::move(chassisVec)};
432
433 // Call monitorSensors()
Bob King8a552922020-08-05 17:02:31 +0800434 chassisPtr->monitorSensors(services, system);
Bob Kinga2c81a62020-07-08 13:31:16 +0800435 }
436}