1 /** 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 */ 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_action.hpp" 24 #include "mock_journal.hpp" 25 #include "mock_services.hpp" 26 #include "mocked_i2c_interface.hpp" 27 #include "pmbus_read_sensor_action.hpp" 28 #include "presence_detection.hpp" 29 #include "rail.hpp" 30 #include "rule.hpp" 31 #include "system.hpp" 32 #include "test_utils.hpp" 33 34 #include <memory> 35 #include <optional> 36 #include <string> 37 #include <utility> 38 #include <vector> 39 40 #include <gmock/gmock.h> 41 #include <gtest/gtest.h> 42 43 using namespace phosphor::power::regulators; 44 using namespace phosphor::power::regulators::test_utils; 45 46 using ::testing::A; 47 using ::testing::Return; 48 using ::testing::Throw; 49 using ::testing::TypedEq; 50 51 TEST(DeviceTests, Constructor) 52 { 53 // Test where only required parameters are specified 54 { 55 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface(); 56 i2c::I2CInterface* i2cInterfacePtr = i2cInterface.get(); 57 Device device{"vdd_reg", true, "/system/chassis/motherboard/reg2", 58 std::move(i2cInterface)}; 59 EXPECT_EQ(device.getID(), "vdd_reg"); 60 EXPECT_EQ(device.isRegulator(), true); 61 EXPECT_EQ(device.getFRU(), "/system/chassis/motherboard/reg2"); 62 EXPECT_EQ(&(device.getI2CInterface()), i2cInterfacePtr); 63 EXPECT_EQ(device.getPresenceDetection(), nullptr); 64 EXPECT_EQ(device.getConfiguration(), nullptr); 65 EXPECT_EQ(device.getRails().size(), 0); 66 } 67 68 // Test where all parameters are specified 69 { 70 // Create I2CInterface 71 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface(); 72 i2c::I2CInterface* i2cInterfacePtr = i2cInterface.get(); 73 74 // Create PresenceDetection 75 std::vector<std::unique_ptr<Action>> actions{}; 76 actions.push_back(std::make_unique<MockAction>()); 77 std::unique_ptr<PresenceDetection> presenceDetection = 78 std::make_unique<PresenceDetection>(std::move(actions)); 79 80 // Create Configuration 81 std::optional<double> volts{}; 82 actions.clear(); 83 actions.push_back(std::make_unique<MockAction>()); 84 actions.push_back(std::make_unique<MockAction>()); 85 std::unique_ptr<Configuration> configuration = 86 std::make_unique<Configuration>(volts, std::move(actions)); 87 88 // Create vector of Rail objects 89 std::vector<std::unique_ptr<Rail>> rails{}; 90 rails.push_back(std::make_unique<Rail>("vdd0")); 91 rails.push_back(std::make_unique<Rail>("vdd1")); 92 93 // Create Device 94 Device device{"vdd_reg", 95 false, 96 "/system/chassis/motherboard/reg1", 97 std::move(i2cInterface), 98 std::move(presenceDetection), 99 std::move(configuration), 100 std::move(rails)}; 101 EXPECT_EQ(device.getID(), "vdd_reg"); 102 EXPECT_EQ(device.isRegulator(), false); 103 EXPECT_EQ(device.getFRU(), "/system/chassis/motherboard/reg1"); 104 EXPECT_EQ(&(device.getI2CInterface()), i2cInterfacePtr); 105 EXPECT_NE(device.getPresenceDetection(), nullptr); 106 EXPECT_EQ(device.getPresenceDetection()->getActions().size(), 1); 107 EXPECT_NE(device.getConfiguration(), nullptr); 108 EXPECT_EQ(device.getConfiguration()->getVolts().has_value(), false); 109 EXPECT_EQ(device.getConfiguration()->getActions().size(), 2); 110 EXPECT_EQ(device.getRails().size(), 2); 111 } 112 } 113 114 TEST(DeviceTests, AddToIDMap) 115 { 116 std::unique_ptr<PresenceDetection> presenceDetection{}; 117 std::unique_ptr<Configuration> configuration{}; 118 119 // Create vector of Rail objects 120 std::vector<std::unique_ptr<Rail>> rails{}; 121 rails.push_back(std::make_unique<Rail>("vdd0")); 122 rails.push_back(std::make_unique<Rail>("vdd1")); 123 124 // Create Device 125 Device device{"vdd_reg", 126 false, 127 "/system/chassis/motherboard/reg2", 128 std::move(createI2CInterface()), 129 std::move(presenceDetection), 130 std::move(configuration), 131 std::move(rails)}; 132 133 // Add Device and Rail objects to an IDMap 134 IDMap idMap{}; 135 device.addToIDMap(idMap); 136 137 // Verify Device is in the IDMap 138 EXPECT_NO_THROW(idMap.getDevice("vdd_reg")); 139 EXPECT_THROW(idMap.getDevice("vio_reg"), std::invalid_argument); 140 141 // Verify all Rails are in the IDMap 142 EXPECT_NO_THROW(idMap.getRail("vdd0")); 143 EXPECT_NO_THROW(idMap.getRail("vdd1")); 144 EXPECT_THROW(idMap.getRail("vdd2"), std::invalid_argument); 145 } 146 147 TEST(DeviceTests, Close) 148 { 149 // Test where works: I2C interface is not open 150 { 151 // Create mock I2CInterface 152 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface = 153 std::make_unique<i2c::MockedI2CInterface>(); 154 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(false)); 155 EXPECT_CALL(*i2cInterface, close).Times(0); 156 157 // Create Device 158 Device device{"vdd_reg", true, "/system/chassis/motherboard/reg2", 159 std::move(i2cInterface)}; 160 161 // Close Device 162 journal::clear(); 163 device.close(); 164 EXPECT_EQ(journal::getErrMessages().size(), 0); 165 } 166 167 // Test where works: I2C interface is open 168 { 169 // Create mock I2CInterface 170 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface = 171 std::make_unique<i2c::MockedI2CInterface>(); 172 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true)); 173 EXPECT_CALL(*i2cInterface, close).Times(1); 174 175 // Create Device 176 Device device{"vdd_reg", true, "/system/chassis/motherboard/reg2", 177 std::move(i2cInterface)}; 178 179 // Close Device 180 journal::clear(); 181 device.close(); 182 EXPECT_EQ(journal::getErrMessages().size(), 0); 183 } 184 185 // Test where fails: closing I2C interface fails 186 { 187 // Create mock I2CInterface 188 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface = 189 std::make_unique<i2c::MockedI2CInterface>(); 190 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true)); 191 EXPECT_CALL(*i2cInterface, close) 192 .Times(1) 193 .WillOnce(Throw( 194 i2c::I2CException{"Failed to close", "/dev/i2c-1", 0x70})); 195 196 // Create Device 197 Device device{"vdd_reg", true, "/system/chassis/motherboard/reg2", 198 std::move(i2cInterface)}; 199 200 // Close Device 201 journal::clear(); 202 device.close(); 203 std::vector<std::string> expectedErrMessages{ 204 "I2CException: Failed to close: bus /dev/i2c-1, addr 0x70", 205 "Unable to close device vdd_reg"}; 206 EXPECT_EQ(journal::getErrMessages(), expectedErrMessages); 207 } 208 } 209 210 TEST(DeviceTests, Configure) 211 { 212 // Test where Configuration and Rails were not specified in constructor 213 { 214 // Create mock services. No logging should occur. 215 MockServices services{}; 216 MockJournal& journal = services.getMockJournal(); 217 EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0); 218 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0); 219 220 // Create Device 221 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface(); 222 std::unique_ptr<Device> device = std::make_unique<Device>( 223 "reg1", true, "/system/chassis/motherboard/reg1", 224 std::move(i2cInterface)); 225 Device* devicePtr = device.get(); 226 227 // Create Chassis that contains Device 228 std::vector<std::unique_ptr<Device>> devices{}; 229 devices.emplace_back(std::move(device)); 230 std::unique_ptr<Chassis> chassis = 231 std::make_unique<Chassis>(1, std::move(devices)); 232 Chassis* chassisPtr = chassis.get(); 233 234 // Create System that contains Chassis 235 std::vector<std::unique_ptr<Rule>> rules{}; 236 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 237 chassisVec.emplace_back(std::move(chassis)); 238 System system{std::move(rules), std::move(chassisVec)}; 239 240 // Call configure(). 241 devicePtr->configure(services, system, *chassisPtr); 242 } 243 244 // Test where Configuration and Rails were specified in constructor 245 { 246 std::vector<std::unique_ptr<Rail>> rails{}; 247 248 // Create mock services. Expect logDebug() to be called. 249 // For the Device and both Rails, should execute the Configuration 250 // and log a debug message. 251 MockServices services{}; 252 MockJournal& journal = services.getMockJournal(); 253 EXPECT_CALL(journal, logDebug("Configuring reg1")).Times(1); 254 EXPECT_CALL(journal, logDebug("Configuring vdd0: volts=1.300000")) 255 .Times(1); 256 EXPECT_CALL(journal, logDebug("Configuring vio0: volts=3.200000")) 257 .Times(1); 258 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0); 259 260 // Create Rail vdd0 261 { 262 // Create Configuration for Rail 263 std::optional<double> volts{1.3}; 264 std::unique_ptr<MockAction> action = std::make_unique<MockAction>(); 265 EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true)); 266 std::vector<std::unique_ptr<Action>> actions{}; 267 actions.emplace_back(std::move(action)); 268 std::unique_ptr<Configuration> configuration = 269 std::make_unique<Configuration>(volts, std::move(actions)); 270 271 // Create Rail 272 std::unique_ptr<Rail> rail = 273 std::make_unique<Rail>("vdd0", std::move(configuration)); 274 rails.emplace_back(std::move(rail)); 275 } 276 277 // Create Rail vio0 278 { 279 // Create Configuration for Rail 280 std::optional<double> volts{3.2}; 281 std::unique_ptr<MockAction> action = std::make_unique<MockAction>(); 282 EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true)); 283 std::vector<std::unique_ptr<Action>> actions{}; 284 actions.emplace_back(std::move(action)); 285 std::unique_ptr<Configuration> configuration = 286 std::make_unique<Configuration>(volts, std::move(actions)); 287 288 // Create Rail 289 std::unique_ptr<Rail> rail = 290 std::make_unique<Rail>("vio0", std::move(configuration)); 291 rails.emplace_back(std::move(rail)); 292 } 293 294 // Create Configuration for Device 295 std::optional<double> volts{}; 296 std::unique_ptr<MockAction> action = std::make_unique<MockAction>(); 297 EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true)); 298 std::vector<std::unique_ptr<Action>> actions{}; 299 actions.emplace_back(std::move(action)); 300 std::unique_ptr<Configuration> configuration = 301 std::make_unique<Configuration>(volts, std::move(actions)); 302 303 // Create Device 304 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface(); 305 std::unique_ptr<PresenceDetection> presenceDetection{}; 306 std::unique_ptr<Device> device = std::make_unique<Device>( 307 "reg1", true, "/system/chassis/motherboard/reg1", 308 std::move(i2cInterface), std::move(presenceDetection), 309 std::move(configuration), std::move(rails)); 310 Device* devicePtr = device.get(); 311 312 // Create Chassis that contains Device 313 std::vector<std::unique_ptr<Device>> devices{}; 314 devices.emplace_back(std::move(device)); 315 std::unique_ptr<Chassis> chassis = 316 std::make_unique<Chassis>(1, std::move(devices)); 317 Chassis* chassisPtr = chassis.get(); 318 319 // Create System that contains Chassis 320 std::vector<std::unique_ptr<Rule>> rules{}; 321 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 322 chassisVec.emplace_back(std::move(chassis)); 323 System system{std::move(rules), std::move(chassisVec)}; 324 325 // Call configure(). 326 devicePtr->configure(services, system, *chassisPtr); 327 } 328 } 329 330 TEST(DeviceTests, GetConfiguration) 331 { 332 // Test where Configuration was not specified in constructor 333 { 334 Device device{"vdd_reg", true, "/system/chassis/motherboard/reg2", 335 std::move(createI2CInterface())}; 336 EXPECT_EQ(device.getConfiguration(), nullptr); 337 } 338 339 // Test where Configuration was specified in constructor 340 { 341 std::unique_ptr<PresenceDetection> presenceDetection{}; 342 343 // Create Configuration 344 std::optional<double> volts{3.2}; 345 std::vector<std::unique_ptr<Action>> actions{}; 346 actions.push_back(std::make_unique<MockAction>()); 347 actions.push_back(std::make_unique<MockAction>()); 348 std::unique_ptr<Configuration> configuration = 349 std::make_unique<Configuration>(volts, std::move(actions)); 350 351 // Create Device 352 Device device{"vdd_reg", 353 true, 354 "/system/chassis/motherboard/reg2", 355 std::move(createI2CInterface()), 356 std::move(presenceDetection), 357 std::move(configuration)}; 358 EXPECT_NE(device.getConfiguration(), nullptr); 359 EXPECT_EQ(device.getConfiguration()->getVolts().has_value(), true); 360 EXPECT_EQ(device.getConfiguration()->getVolts().value(), 3.2); 361 EXPECT_EQ(device.getConfiguration()->getActions().size(), 2); 362 } 363 } 364 365 TEST(DeviceTests, GetFRU) 366 { 367 Device device{"vdd_reg", true, "/system/chassis/motherboard/reg2", 368 std::move(createI2CInterface())}; 369 EXPECT_EQ(device.getFRU(), "/system/chassis/motherboard/reg2"); 370 } 371 372 TEST(DeviceTests, GetI2CInterface) 373 { 374 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface(); 375 i2c::I2CInterface* i2cInterfacePtr = i2cInterface.get(); 376 Device device{"vdd_reg", true, "/system/chassis/motherboard/reg2", 377 std::move(i2cInterface)}; 378 EXPECT_EQ(&(device.getI2CInterface()), i2cInterfacePtr); 379 } 380 381 TEST(DeviceTests, GetID) 382 { 383 Device device{"vdd_reg", false, "/system/chassis/motherboard/reg2", 384 std::move(createI2CInterface())}; 385 EXPECT_EQ(device.getID(), "vdd_reg"); 386 } 387 388 TEST(DeviceTests, GetPresenceDetection) 389 { 390 // Test where PresenceDetection was not specified in constructor 391 { 392 Device device{"vdd_reg", true, "/system/chassis/motherboard/reg2", 393 std::move(createI2CInterface())}; 394 EXPECT_EQ(device.getPresenceDetection(), nullptr); 395 } 396 397 // Test where PresenceDetection was specified in constructor 398 { 399 // Create PresenceDetection 400 std::vector<std::unique_ptr<Action>> actions{}; 401 actions.push_back(std::make_unique<MockAction>()); 402 std::unique_ptr<PresenceDetection> presenceDetection = 403 std::make_unique<PresenceDetection>(std::move(actions)); 404 405 // Create Device 406 Device device{"vdd_reg", false, "/system/chassis/motherboard/reg2", 407 std::move(createI2CInterface()), 408 std::move(presenceDetection)}; 409 EXPECT_NE(device.getPresenceDetection(), nullptr); 410 EXPECT_EQ(device.getPresenceDetection()->getActions().size(), 1); 411 } 412 } 413 414 TEST(DeviceTests, GetRails) 415 { 416 // Test where no rails were specified in constructor 417 { 418 Device device{"vdd_reg", true, "/system/chassis/motherboard/reg2", 419 std::move(createI2CInterface())}; 420 EXPECT_EQ(device.getRails().size(), 0); 421 } 422 423 // Test where rails were specified in constructor 424 { 425 std::unique_ptr<PresenceDetection> presenceDetection{}; 426 std::unique_ptr<Configuration> configuration{}; 427 428 // Create vector of Rail objects 429 std::vector<std::unique_ptr<Rail>> rails{}; 430 rails.push_back(std::make_unique<Rail>("vdd0")); 431 rails.push_back(std::make_unique<Rail>("vdd1")); 432 433 // Create Device 434 Device device{"vdd_reg", 435 false, 436 "/system/chassis/motherboard/reg2", 437 std::move(createI2CInterface()), 438 std::move(presenceDetection), 439 std::move(configuration), 440 std::move(rails)}; 441 EXPECT_EQ(device.getRails().size(), 2); 442 EXPECT_EQ(device.getRails()[0]->getID(), "vdd0"); 443 EXPECT_EQ(device.getRails()[1]->getID(), "vdd1"); 444 } 445 } 446 447 TEST(DeviceTests, IsRegulator) 448 { 449 Device device{"vdd_reg", false, "/system/chassis/motherboard/reg2", 450 std::move(createI2CInterface())}; 451 EXPECT_EQ(device.isRegulator(), false); 452 } 453 454 TEST(DeviceTests, MonitorSensors) 455 { 456 // Test where Rails were not specified in constructor 457 { 458 // Create mock I2CInterface. A two-byte read should NOT occur. 459 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface = 460 std::make_unique<i2c::MockedI2CInterface>(); 461 EXPECT_CALL(*i2cInterface, read(A<uint8_t>(), A<uint16_t&>())).Times(0); 462 463 // Create Device 464 std::unique_ptr<Device> device = std::make_unique<Device>( 465 "reg1", true, "/system/chassis/motherboard/reg1", 466 std::move(i2cInterface)); 467 Device* devicePtr = device.get(); 468 469 // Create Chassis that contains Device 470 std::vector<std::unique_ptr<Device>> devices{}; 471 devices.emplace_back(std::move(device)); 472 std::unique_ptr<Chassis> chassis = 473 std::make_unique<Chassis>(1, std::move(devices)); 474 Chassis* chassisPtr = chassis.get(); 475 476 // Create System that contains Chassis 477 std::vector<std::unique_ptr<Rule>> rules{}; 478 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 479 chassisVec.emplace_back(std::move(chassis)); 480 System system{std::move(rules), std::move(chassisVec)}; 481 482 // Call monitorSensors(). Should do nothing. 483 journal::clear(); 484 devicePtr->monitorSensors(system, *chassisPtr); 485 EXPECT_EQ(journal::getDebugMessages().size(), 0); 486 EXPECT_EQ(journal::getErrMessages().size(), 0); 487 } 488 489 // Test where Rails were specified in constructor 490 { 491 std::vector<std::unique_ptr<Rail>> rails{}; 492 493 // Create PMBusReadSensorAction 494 pmbus_utils::SensorValueType type{pmbus_utils::SensorValueType::iout}; 495 uint8_t command = 0x8C; 496 pmbus_utils::SensorDataFormat format{ 497 pmbus_utils::SensorDataFormat::linear_11}; 498 std::optional<int8_t> exponent{}; 499 std::unique_ptr<PMBusReadSensorAction> action = 500 std::make_unique<PMBusReadSensorAction>(type, command, format, 501 exponent); 502 503 // Create mock I2CInterface. A two-byte read should occur. 504 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface = 505 std::make_unique<i2c::MockedI2CInterface>(); 506 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true)); 507 EXPECT_CALL(*i2cInterface, read(TypedEq<uint8_t>(0x8C), A<uint16_t&>())) 508 .Times(1); 509 510 // Create SensorMonitoring 511 std::vector<std::unique_ptr<Action>> actions{}; 512 actions.emplace_back(std::move(action)); 513 std::unique_ptr<SensorMonitoring> sensorMonitoring = 514 std::make_unique<SensorMonitoring>(std::move(actions)); 515 516 // Create Rail 517 std::unique_ptr<Configuration> configuration{}; 518 std::unique_ptr<Rail> rail = std::make_unique<Rail>( 519 "vdd0", std::move(configuration), std::move(sensorMonitoring)); 520 rails.emplace_back(std::move(rail)); 521 522 // Create Device 523 std::unique_ptr<PresenceDetection> presenceDetection{}; 524 std::unique_ptr<Configuration> deviceConfiguration{}; 525 std::unique_ptr<Device> device = std::make_unique<Device>( 526 "reg1", true, "/system/chassis/motherboard/reg1", 527 std::move(i2cInterface), std::move(presenceDetection), 528 std::move(deviceConfiguration), std::move(rails)); 529 Device* devicePtr = device.get(); 530 531 // Create Chassis that contains Device 532 std::vector<std::unique_ptr<Device>> devices{}; 533 devices.emplace_back(std::move(device)); 534 std::unique_ptr<Chassis> chassis = 535 std::make_unique<Chassis>(1, std::move(devices)); 536 Chassis* chassisPtr = chassis.get(); 537 538 // Create System that contains Chassis 539 std::vector<std::unique_ptr<Rule>> rules{}; 540 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 541 chassisVec.emplace_back(std::move(chassis)); 542 System system{std::move(rules), std::move(chassisVec)}; 543 544 // Call monitorSensors(). 545 journal::clear(); 546 devicePtr->monitorSensors(system, *chassisPtr); 547 EXPECT_EQ(journal::getDebugMessages().size(), 0); 548 EXPECT_EQ(journal::getErrMessages().size(), 0); 549 } 550 } 551