1 /** 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" 17 #include "chassis.hpp" 18 #include "configuration.hpp" 19 #include "device.hpp" 20 #include "i2c_interface.hpp" 21 #include "id_map.hpp" 22 #include "journal.hpp" 23 #include "mock_journal.hpp" 24 #include "mocked_i2c_interface.hpp" 25 #include "pmbus_read_sensor_action.hpp" 26 #include "presence_detection.hpp" 27 #include "rail.hpp" 28 #include "rule.hpp" 29 #include "system.hpp" 30 #include "test_utils.hpp" 31 32 #include <memory> 33 #include <stdexcept> 34 #include <string> 35 #include <utility> 36 #include <vector> 37 38 #include <gmock/gmock.h> 39 #include <gtest/gtest.h> 40 41 using namespace phosphor::power::regulators; 42 using namespace phosphor::power::regulators::test_utils; 43 44 using ::testing::A; 45 using ::testing::Return; 46 using ::testing::TypedEq; 47 48 TEST(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{}; 61 devices.emplace_back(createDevice("vdd_reg1")); 62 devices.emplace_back(createDevice("vdd_reg2")); 63 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 86 TEST(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 114 TEST(ChassisTests, CloseDevices) 115 { 116 // Test where no devices were specified in constructor 117 { 118 // Create Chassis 119 Chassis chassis{2}; 120 121 // Call closeDevices() 122 journal::clear(); 123 chassis.closeDevices(); 124 EXPECT_EQ(journal::getErrMessages().size(), 0); 125 EXPECT_EQ(journal::getInfoMessages().size(), 0); 126 std::vector<std::string> expectedDebugMessages{ 127 "Closing devices in chassis 2"}; 128 EXPECT_EQ(journal::getDebugMessages(), expectedDebugMessages); 129 } 130 131 // Test where devices were specified in constructor 132 { 133 std::vector<std::unique_ptr<Device>> devices{}; 134 135 // Create Device vdd0_reg 136 { 137 // Create mock I2CInterface: isOpen() and close() should be called 138 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface = 139 std::make_unique<i2c::MockedI2CInterface>(); 140 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true)); 141 EXPECT_CALL(*i2cInterface, close).Times(1); 142 143 // Create Device 144 std::unique_ptr<Device> device = std::make_unique<Device>( 145 "vdd0_reg", true, "/system/chassis/motherboard/vdd0_reg", 146 std::move(i2cInterface)); 147 devices.emplace_back(std::move(device)); 148 } 149 150 // Create Device vdd1_reg 151 { 152 // Create mock I2CInterface: isOpen() and close() should be called 153 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface = 154 std::make_unique<i2c::MockedI2CInterface>(); 155 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true)); 156 EXPECT_CALL(*i2cInterface, close).Times(1); 157 158 // Create Device 159 std::unique_ptr<Device> device = std::make_unique<Device>( 160 "vdd1_reg", true, "/system/chassis/motherboard/vdd1_reg", 161 std::move(i2cInterface)); 162 devices.emplace_back(std::move(device)); 163 } 164 165 // Create Chassis 166 Chassis chassis{1, std::move(devices)}; 167 168 // Call closeDevices() 169 journal::clear(); 170 chassis.closeDevices(); 171 EXPECT_EQ(journal::getErrMessages().size(), 0); 172 EXPECT_EQ(journal::getInfoMessages().size(), 0); 173 std::vector<std::string> expectedDebugMessages{ 174 "Closing devices in chassis 1"}; 175 EXPECT_EQ(journal::getDebugMessages(), expectedDebugMessages); 176 } 177 } 178 179 TEST(ChassisTests, Configure) 180 { 181 // Test where no devices were specified in constructor 182 { 183 // Create Chassis 184 std::unique_ptr<Chassis> chassis = std::make_unique<Chassis>(1); 185 Chassis* chassisPtr = chassis.get(); 186 187 // Create System that contains Chassis 188 std::vector<std::unique_ptr<Rule>> rules{}; 189 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 190 chassisVec.emplace_back(std::move(chassis)); 191 System system{std::move(rules), std::move(chassisVec)}; 192 193 // Call configure() 194 journal::clear(); 195 chassisPtr->configure(system); 196 EXPECT_EQ(journal::getDebugMessages().size(), 0); 197 EXPECT_EQ(journal::getErrMessages().size(), 0); 198 std::vector<std::string> expectedInfoMessages{"Configuring chassis 1"}; 199 EXPECT_EQ(journal::getInfoMessages(), expectedInfoMessages); 200 } 201 202 // Test where devices were specified in constructor 203 { 204 std::vector<std::unique_ptr<Device>> devices{}; 205 206 // Create Device vdd0_reg 207 { 208 // Create Configuration 209 std::vector<std::unique_ptr<Action>> actions{}; 210 std::unique_ptr<Configuration> configuration = 211 std::make_unique<Configuration>(1.3, std::move(actions)); 212 213 // Create Device 214 std::unique_ptr<i2c::I2CInterface> i2cInterface = 215 createI2CInterface(); 216 std::unique_ptr<PresenceDetection> presenceDetection{}; 217 std::unique_ptr<Device> device = std::make_unique<Device>( 218 "vdd0_reg", true, "/system/chassis/motherboard/vdd0_reg", 219 std::move(i2cInterface), std::move(presenceDetection), 220 std::move(configuration)); 221 devices.emplace_back(std::move(device)); 222 } 223 224 // Create Device vdd1_reg 225 { 226 // Create Configuration 227 std::vector<std::unique_ptr<Action>> actions{}; 228 std::unique_ptr<Configuration> configuration = 229 std::make_unique<Configuration>(1.2, std::move(actions)); 230 231 // Create Device 232 std::unique_ptr<i2c::I2CInterface> i2cInterface = 233 createI2CInterface(); 234 std::unique_ptr<PresenceDetection> presenceDetection{}; 235 std::unique_ptr<Device> device = std::make_unique<Device>( 236 "vdd1_reg", true, "/system/chassis/motherboard/vdd1_reg", 237 std::move(i2cInterface), std::move(presenceDetection), 238 std::move(configuration)); 239 devices.emplace_back(std::move(device)); 240 } 241 242 // Create Chassis 243 std::unique_ptr<Chassis> chassis = 244 std::make_unique<Chassis>(2, std::move(devices)); 245 Chassis* chassisPtr = chassis.get(); 246 247 // Create System that contains Chassis 248 std::vector<std::unique_ptr<Rule>> rules{}; 249 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 250 chassisVec.emplace_back(std::move(chassis)); 251 System system{std::move(rules), std::move(chassisVec)}; 252 253 // Call configure() 254 journal::clear(); 255 chassisPtr->configure(system); 256 std::vector<std::string> expectedDebugMessages{ 257 "Configuring vdd0_reg: volts=1.300000", 258 "Configuring vdd1_reg: volts=1.200000"}; 259 EXPECT_EQ(journal::getDebugMessages(), expectedDebugMessages); 260 EXPECT_EQ(journal::getErrMessages().size(), 0); 261 std::vector<std::string> expectedInfoMessages{"Configuring chassis 2"}; 262 EXPECT_EQ(journal::getInfoMessages(), expectedInfoMessages); 263 } 264 } 265 266 TEST(ChassisTests, GetDevices) 267 { 268 // Test where no devices were specified in constructor 269 { 270 Chassis chassis{2}; 271 EXPECT_EQ(chassis.getDevices().size(), 0); 272 } 273 274 // Test where devices were specified in constructor 275 { 276 // Create vector of Device objects 277 std::vector<std::unique_ptr<Device>> devices{}; 278 devices.emplace_back(createDevice("vdd_reg1")); 279 devices.emplace_back(createDevice("vdd_reg2")); 280 281 // Create Chassis 282 Chassis chassis{1, std::move(devices)}; 283 EXPECT_EQ(chassis.getDevices().size(), 2); 284 EXPECT_EQ(chassis.getDevices()[0]->getID(), "vdd_reg1"); 285 EXPECT_EQ(chassis.getDevices()[1]->getID(), "vdd_reg2"); 286 } 287 } 288 289 TEST(ChassisTests, GetNumber) 290 { 291 Chassis chassis{3}; 292 EXPECT_EQ(chassis.getNumber(), 3); 293 } 294 295 TEST(ChassisTests, MonitorSensors) 296 { 297 // Test where no devices were specified in constructor 298 { 299 // Create Chassis 300 std::vector<std::unique_ptr<Device>> devices{}; 301 std::unique_ptr<Chassis> chassis = 302 std::make_unique<Chassis>(1, std::move(devices)); 303 Chassis* chassisPtr = chassis.get(); 304 305 // Create System that contains Chassis 306 std::vector<std::unique_ptr<Rule>> rules{}; 307 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 308 chassisVec.emplace_back(std::move(chassis)); 309 System system{std::move(rules), std::move(chassisVec)}; 310 311 // Call monitorSensors(). Should do nothing. 312 journal::clear(); 313 chassisPtr->monitorSensors(system); 314 EXPECT_EQ(journal::getDebugMessages().size(), 0); 315 EXPECT_EQ(journal::getErrMessages().size(), 0); 316 } 317 318 // Test where devices were specified in constructor 319 { 320 std::vector<std::unique_ptr<Device>> devices{}; 321 322 // Create PMBusReadSensorAction 323 pmbus_utils::SensorValueType type{pmbus_utils::SensorValueType::iout}; 324 uint8_t command = 0x8C; 325 pmbus_utils::SensorDataFormat format{ 326 pmbus_utils::SensorDataFormat::linear_11}; 327 std::optional<int8_t> exponent{}; 328 std::unique_ptr<PMBusReadSensorAction> action = 329 std::make_unique<PMBusReadSensorAction>(type, command, format, 330 exponent); 331 332 // Create mock I2CInterface. A two-byte read should occur. 333 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface = 334 std::make_unique<i2c::MockedI2CInterface>(); 335 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true)); 336 EXPECT_CALL(*i2cInterface, read(TypedEq<uint8_t>(0x8C), A<uint16_t&>())) 337 .Times(1); 338 339 // Create SensorMonitoring 340 std::vector<std::unique_ptr<Action>> actions{}; 341 actions.emplace_back(std::move(action)); 342 std::unique_ptr<SensorMonitoring> sensorMonitoring = 343 std::make_unique<SensorMonitoring>(std::move(actions)); 344 345 // Create Rail 346 std::vector<std::unique_ptr<Rail>> rails{}; 347 std::unique_ptr<Configuration> configuration{}; 348 std::unique_ptr<Rail> rail = std::make_unique<Rail>( 349 "vdd0", std::move(configuration), std::move(sensorMonitoring)); 350 rails.emplace_back(std::move(rail)); 351 352 // Create Device 353 std::unique_ptr<PresenceDetection> presenceDetection{}; 354 std::unique_ptr<Configuration> deviceConfiguration{}; 355 std::unique_ptr<Device> device = std::make_unique<Device>( 356 "reg1", true, "/system/chassis/motherboard/reg1", 357 std::move(i2cInterface), std::move(presenceDetection), 358 std::move(deviceConfiguration), std::move(rails)); 359 360 // Create Chassis 361 devices.emplace_back(std::move(device)); 362 std::unique_ptr<Chassis> chassis = 363 std::make_unique<Chassis>(1, std::move(devices)); 364 Chassis* chassisPtr = chassis.get(); 365 366 // Create System that contains Chassis 367 std::vector<std::unique_ptr<Rule>> rules{}; 368 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 369 chassisVec.emplace_back(std::move(chassis)); 370 System system{std::move(rules), std::move(chassisVec)}; 371 372 // Call monitorSensors() 373 journal::clear(); 374 chassisPtr->monitorSensors(system); 375 EXPECT_EQ(journal::getDebugMessages().size(), 0); 376 EXPECT_EQ(journal::getErrMessages().size(), 0); 377 } 378 } 379