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