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_error_logging.hpp" 24 #include "mock_journal.hpp" 25 #include "mock_sensors.hpp" 26 #include "mock_services.hpp" 27 #include "mocked_i2c_interface.hpp" 28 #include "phase_fault_detection.hpp" 29 #include "presence_detection.hpp" 30 #include "rail.hpp" 31 #include "rule.hpp" 32 #include "sensor_monitoring.hpp" 33 #include "sensors.hpp" 34 #include "system.hpp" 35 #include "test_sdbus_error.hpp" 36 #include "test_utils.hpp" 37 38 #include <memory> 39 #include <optional> 40 #include <string> 41 #include <utility> 42 #include <vector> 43 44 #include <gmock/gmock.h> 45 #include <gtest/gtest.h> 46 47 using namespace phosphor::power::regulators; 48 using namespace phosphor::power::regulators::test_utils; 49 50 using ::testing::A; 51 using ::testing::Ref; 52 using ::testing::Return; 53 using ::testing::Throw; 54 using ::testing::TypedEq; 55 56 static const std::string chassisInvPath{ 57 "/xyz/openbmc_project/inventory/system/chassis"}; 58 59 TEST(DeviceTests, Constructor) 60 { 61 // Test where only required parameters are specified 62 { 63 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface(); 64 i2c::I2CInterface* i2cInterfacePtr = i2cInterface.get(); 65 Device device{ 66 "vdd_reg", true, 67 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2", 68 std::move(i2cInterface)}; 69 EXPECT_EQ(device.getID(), "vdd_reg"); 70 EXPECT_EQ(device.isRegulator(), true); 71 EXPECT_EQ( 72 device.getFRU(), 73 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2"); 74 EXPECT_EQ(&(device.getI2CInterface()), i2cInterfacePtr); 75 EXPECT_EQ(device.getPresenceDetection(), nullptr); 76 EXPECT_EQ(device.getConfiguration(), nullptr); 77 EXPECT_EQ(device.getPhaseFaultDetection(), nullptr); 78 EXPECT_EQ(device.getRails().size(), 0); 79 } 80 81 // Test where all parameters are specified 82 { 83 // Create I2CInterface 84 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface(); 85 i2c::I2CInterface* i2cInterfacePtr = i2cInterface.get(); 86 87 // Create PresenceDetection 88 std::vector<std::unique_ptr<Action>> actions{}; 89 actions.push_back(std::make_unique<MockAction>()); 90 std::unique_ptr<PresenceDetection> presenceDetection = 91 std::make_unique<PresenceDetection>(std::move(actions)); 92 93 // Create Configuration 94 std::optional<double> volts{}; 95 actions.clear(); 96 actions.push_back(std::make_unique<MockAction>()); 97 actions.push_back(std::make_unique<MockAction>()); 98 std::unique_ptr<Configuration> configuration = 99 std::make_unique<Configuration>(volts, std::move(actions)); 100 101 // Create PhaseFaultDetection 102 actions.clear(); 103 actions.push_back(std::make_unique<MockAction>()); 104 actions.push_back(std::make_unique<MockAction>()); 105 actions.push_back(std::make_unique<MockAction>()); 106 std::unique_ptr<PhaseFaultDetection> phaseFaultDetection = 107 std::make_unique<PhaseFaultDetection>(std::move(actions)); 108 109 // Create vector of Rail objects 110 std::vector<std::unique_ptr<Rail>> rails{}; 111 rails.push_back(std::make_unique<Rail>("vdd0")); 112 rails.push_back(std::make_unique<Rail>("vdd1")); 113 114 // Create Device 115 Device device{ 116 "vdd_reg", 117 false, 118 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1", 119 std::move(i2cInterface), 120 std::move(presenceDetection), 121 std::move(configuration), 122 std::move(phaseFaultDetection), 123 std::move(rails)}; 124 EXPECT_EQ(device.getID(), "vdd_reg"); 125 EXPECT_EQ(device.isRegulator(), false); 126 EXPECT_EQ( 127 device.getFRU(), 128 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1"); 129 EXPECT_EQ(&(device.getI2CInterface()), i2cInterfacePtr); 130 EXPECT_NE(device.getPresenceDetection(), nullptr); 131 EXPECT_EQ(device.getPresenceDetection()->getActions().size(), 1); 132 EXPECT_NE(device.getConfiguration(), nullptr); 133 EXPECT_EQ(device.getConfiguration()->getVolts().has_value(), false); 134 EXPECT_EQ(device.getConfiguration()->getActions().size(), 2); 135 EXPECT_NE(device.getPhaseFaultDetection(), nullptr); 136 EXPECT_EQ(device.getPhaseFaultDetection()->getActions().size(), 3); 137 EXPECT_EQ(device.getRails().size(), 2); 138 } 139 } 140 141 TEST(DeviceTests, AddToIDMap) 142 { 143 std::unique_ptr<PresenceDetection> presenceDetection{}; 144 std::unique_ptr<Configuration> configuration{}; 145 std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{}; 146 147 // Create vector of Rail objects 148 std::vector<std::unique_ptr<Rail>> rails{}; 149 rails.push_back(std::make_unique<Rail>("vdd0")); 150 rails.push_back(std::make_unique<Rail>("vdd1")); 151 152 // Create Device 153 Device device{ 154 "vdd_reg", 155 false, 156 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2", 157 std::move(createI2CInterface()), 158 std::move(presenceDetection), 159 std::move(configuration), 160 std::move(phaseFaultDetection), 161 std::move(rails)}; 162 163 // Add Device and Rail objects to an IDMap 164 IDMap idMap{}; 165 device.addToIDMap(idMap); 166 167 // Verify Device is in the IDMap 168 EXPECT_NO_THROW(idMap.getDevice("vdd_reg")); 169 EXPECT_THROW(idMap.getDevice("vio_reg"), std::invalid_argument); 170 171 // Verify all Rails are in the IDMap 172 EXPECT_NO_THROW(idMap.getRail("vdd0")); 173 EXPECT_NO_THROW(idMap.getRail("vdd1")); 174 EXPECT_THROW(idMap.getRail("vdd2"), std::invalid_argument); 175 } 176 177 TEST(DeviceTests, ClearCache) 178 { 179 // Test where Device does not contain a PresenceDetection object 180 try 181 { 182 Device device{ 183 "vdd_reg", false, 184 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2", 185 std::move(createI2CInterface())}; 186 device.clearCache(); 187 } 188 catch (...) 189 { 190 ADD_FAILURE() << "Should not have caught exception."; 191 } 192 193 // Test where Device contains a PresenceDetection object 194 { 195 // Create PresenceDetection 196 std::vector<std::unique_ptr<Action>> actions{}; 197 std::unique_ptr<PresenceDetection> presenceDetection = 198 std::make_unique<PresenceDetection>(std::move(actions)); 199 PresenceDetection* presenceDetectionPtr = presenceDetection.get(); 200 201 // Create Device 202 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface(); 203 std::unique_ptr<Device> device = std::make_unique<Device>( 204 "reg1", true, 205 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1", 206 std::move(i2cInterface), std::move(presenceDetection)); 207 Device* devicePtr = device.get(); 208 209 // Create Chassis that contains Device 210 std::vector<std::unique_ptr<Device>> devices{}; 211 devices.emplace_back(std::move(device)); 212 std::unique_ptr<Chassis> chassis = 213 std::make_unique<Chassis>(1, chassisInvPath, std::move(devices)); 214 Chassis* chassisPtr = chassis.get(); 215 216 // Create System that contains Chassis 217 std::vector<std::unique_ptr<Rule>> rules{}; 218 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 219 chassisVec.emplace_back(std::move(chassis)); 220 System system{std::move(rules), std::move(chassisVec)}; 221 222 // Cache presence value in PresenceDetection 223 MockServices services{}; 224 presenceDetectionPtr->execute(services, system, *chassisPtr, 225 *devicePtr); 226 EXPECT_TRUE(presenceDetectionPtr->getCachedPresence().has_value()); 227 228 // Clear cached data in Device 229 devicePtr->clearCache(); 230 231 // Verify presence value no longer cached in PresenceDetection 232 EXPECT_FALSE(presenceDetectionPtr->getCachedPresence().has_value()); 233 } 234 } 235 236 TEST(DeviceTests, ClearErrorHistory) 237 { 238 // Create SensorMonitoring. Will fail with a DBus exception. 239 std::unique_ptr<MockAction> action = std::make_unique<MockAction>(); 240 EXPECT_CALL(*action, execute) 241 .WillRepeatedly(Throw(TestSDBusError{"Unable to set sensor value"})); 242 std::vector<std::unique_ptr<Action>> actions{}; 243 actions.emplace_back(std::move(action)); 244 std::unique_ptr<SensorMonitoring> sensorMonitoring = 245 std::make_unique<SensorMonitoring>(std::move(actions)); 246 247 // Create Rail 248 std::unique_ptr<Configuration> configuration{}; 249 std::unique_ptr<Rail> rail = std::make_unique<Rail>( 250 "vddr1", std::move(configuration), std::move(sensorMonitoring)); 251 252 // Create Device that contains Rail 253 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface = 254 std::make_unique<i2c::MockedI2CInterface>(); 255 std::unique_ptr<PresenceDetection> presenceDetection{}; 256 std::unique_ptr<Configuration> deviceConfiguration{}; 257 std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{}; 258 std::vector<std::unique_ptr<Rail>> rails{}; 259 rails.emplace_back(std::move(rail)); 260 std::unique_ptr<Device> device = std::make_unique<Device>( 261 "reg1", true, 262 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1", 263 std::move(i2cInterface), std::move(presenceDetection), 264 std::move(deviceConfiguration), std::move(phaseFaultDetection), 265 std::move(rails)); 266 Device* devicePtr = device.get(); 267 268 // Create Chassis that contains Device 269 std::vector<std::unique_ptr<Device>> devices{}; 270 devices.emplace_back(std::move(device)); 271 std::unique_ptr<Chassis> chassis = 272 std::make_unique<Chassis>(1, chassisInvPath, std::move(devices)); 273 Chassis* chassisPtr = chassis.get(); 274 275 // Create System that contains Chassis 276 std::vector<std::unique_ptr<Rule>> rules{}; 277 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 278 chassisVec.emplace_back(std::move(chassis)); 279 System system{std::move(rules), std::move(chassisVec)}; 280 281 // Create mock services 282 MockServices services{}; 283 284 // Expect Sensors service to be called 5+5=10 times 285 MockSensors& sensors = services.getMockSensors(); 286 EXPECT_CALL(sensors, startRail).Times(10); 287 EXPECT_CALL(sensors, setValue).Times(0); 288 EXPECT_CALL(sensors, endRail).Times(10); 289 290 // Expect Journal service to be called 3+3=6 times to log error messages 291 MockJournal& journal = services.getMockJournal(); 292 EXPECT_CALL(journal, logError(A<const std::vector<std::string>&>())) 293 .Times(6); 294 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(6); 295 296 // Expect ErrorLogging service to be called 1+1=2 times to log a DBus error 297 MockErrorLogging& errorLogging = services.getMockErrorLogging(); 298 EXPECT_CALL(errorLogging, logDBusError).Times(2); 299 300 // Monitor sensors 5 times. Should fail every time, write to journal 3 301 // times, and log one error. 302 for (int i = 1; i <= 5; ++i) 303 { 304 devicePtr->monitorSensors(services, system, *chassisPtr); 305 } 306 307 // Clear error history 308 devicePtr->clearErrorHistory(); 309 310 // Monitor sensors 5 times again. Should fail every time, write to journal 311 // 3 times, and log one error. 312 for (int i = 1; i <= 5; ++i) 313 { 314 devicePtr->monitorSensors(services, system, *chassisPtr); 315 } 316 } 317 318 TEST(DeviceTests, Close) 319 { 320 // Test where works: I2C interface is not open 321 { 322 // Create mock I2CInterface 323 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface = 324 std::make_unique<i2c::MockedI2CInterface>(); 325 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(false)); 326 EXPECT_CALL(*i2cInterface, close).Times(0); 327 328 // Create mock services. No logError should occur. 329 MockServices services{}; 330 MockJournal& journal = services.getMockJournal(); 331 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0); 332 EXPECT_CALL(journal, logError(A<const std::vector<std::string>&>())) 333 .Times(0); 334 335 // Create Device 336 Device device{ 337 "vdd_reg", true, 338 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2", 339 std::move(i2cInterface)}; 340 341 // Close Device 342 device.close(services); 343 } 344 345 // Test where works: I2C interface is open 346 { 347 // Create mock I2CInterface 348 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface = 349 std::make_unique<i2c::MockedI2CInterface>(); 350 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true)); 351 EXPECT_CALL(*i2cInterface, close).Times(1); 352 353 // Create mock services. No logError should occur. 354 MockServices services{}; 355 MockJournal& journal = services.getMockJournal(); 356 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0); 357 EXPECT_CALL(journal, logError(A<const std::vector<std::string>&>())) 358 .Times(0); 359 360 // Create Device 361 Device device{ 362 "vdd_reg", true, 363 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2", 364 std::move(i2cInterface)}; 365 366 // Close Device 367 device.close(services); 368 } 369 370 // Test where fails: closing I2C interface fails 371 { 372 // Create mock I2CInterface 373 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface = 374 std::make_unique<i2c::MockedI2CInterface>(); 375 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true)); 376 EXPECT_CALL(*i2cInterface, close) 377 .Times(1) 378 .WillOnce(Throw( 379 i2c::I2CException{"Failed to close", "/dev/i2c-1", 0x70})); 380 381 // Create mock services. Expect logError() and logI2CError() to be 382 // called. 383 MockServices services{}; 384 MockErrorLogging& errorLogging = services.getMockErrorLogging(); 385 MockJournal& journal = services.getMockJournal(); 386 std::vector<std::string> expectedErrMessagesException{ 387 "I2CException: Failed to close: bus /dev/i2c-1, addr 0x70"}; 388 EXPECT_CALL(journal, logError("Unable to close device vdd_reg")) 389 .Times(1); 390 EXPECT_CALL(journal, logError(expectedErrMessagesException)).Times(1); 391 EXPECT_CALL(errorLogging, 392 logI2CError(Entry::Level::Notice, Ref(journal), 393 "/dev/i2c-1", 0x70, 0)) 394 .Times(1); 395 396 // Create Device 397 Device device{ 398 "vdd_reg", true, 399 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2", 400 std::move(i2cInterface)}; 401 402 // Close Device 403 device.close(services); 404 } 405 } 406 407 TEST(DeviceTests, Configure) 408 { 409 // Test where device is not present 410 { 411 // Create mock services. No logging should occur. 412 MockServices services{}; 413 MockJournal& journal = services.getMockJournal(); 414 EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0); 415 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0); 416 417 // Create PresenceDetection. Indicates device is not present. 418 std::unique_ptr<MockAction> presAction = std::make_unique<MockAction>(); 419 EXPECT_CALL(*presAction, execute).Times(1).WillOnce(Return(false)); 420 std::vector<std::unique_ptr<Action>> presActions{}; 421 presActions.emplace_back(std::move(presAction)); 422 std::unique_ptr<PresenceDetection> presenceDetection = 423 std::make_unique<PresenceDetection>(std::move(presActions)); 424 425 // Create Configuration. Action inside it should not be executed. 426 std::optional<double> volts{}; 427 std::unique_ptr<MockAction> confAction = std::make_unique<MockAction>(); 428 EXPECT_CALL(*confAction, execute).Times(0); 429 std::vector<std::unique_ptr<Action>> confActions{}; 430 confActions.emplace_back(std::move(confAction)); 431 std::unique_ptr<Configuration> configuration = 432 std::make_unique<Configuration>(volts, std::move(confActions)); 433 434 // Create Device 435 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface(); 436 std::unique_ptr<Device> device = std::make_unique<Device>( 437 "reg1", true, 438 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1", 439 std::move(i2cInterface), std::move(presenceDetection), 440 std::move(configuration)); 441 Device* devicePtr = device.get(); 442 443 // Create Chassis that contains Device 444 std::vector<std::unique_ptr<Device>> devices{}; 445 devices.emplace_back(std::move(device)); 446 std::unique_ptr<Chassis> chassis = 447 std::make_unique<Chassis>(1, chassisInvPath, std::move(devices)); 448 Chassis* chassisPtr = chassis.get(); 449 450 // Create System that contains Chassis 451 std::vector<std::unique_ptr<Rule>> rules{}; 452 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 453 chassisVec.emplace_back(std::move(chassis)); 454 System system{std::move(rules), std::move(chassisVec)}; 455 456 // Call configure(). Should do nothing. 457 devicePtr->configure(services, system, *chassisPtr); 458 } 459 460 // Test where Configuration and Rails were not specified in constructor 461 { 462 // Create mock services. No logging should occur. 463 MockServices services{}; 464 MockJournal& journal = services.getMockJournal(); 465 EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0); 466 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0); 467 468 // Create Device 469 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface(); 470 std::unique_ptr<Device> device = std::make_unique<Device>( 471 "reg1", true, 472 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1", 473 std::move(i2cInterface)); 474 Device* devicePtr = device.get(); 475 476 // Create Chassis that contains Device 477 std::vector<std::unique_ptr<Device>> devices{}; 478 devices.emplace_back(std::move(device)); 479 std::unique_ptr<Chassis> chassis = 480 std::make_unique<Chassis>(1, chassisInvPath, std::move(devices)); 481 Chassis* chassisPtr = chassis.get(); 482 483 // Create System that contains Chassis 484 std::vector<std::unique_ptr<Rule>> rules{}; 485 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 486 chassisVec.emplace_back(std::move(chassis)); 487 System system{std::move(rules), std::move(chassisVec)}; 488 489 // Call configure(). 490 devicePtr->configure(services, system, *chassisPtr); 491 } 492 493 // Test where Configuration and Rails were specified in constructor 494 { 495 std::vector<std::unique_ptr<Rail>> rails{}; 496 497 // Create mock services. Expect logDebug() to be called. 498 // For the Device and both Rails, should execute the Configuration 499 // and log a debug message. 500 MockServices services{}; 501 MockJournal& journal = services.getMockJournal(); 502 EXPECT_CALL(journal, logDebug("Configuring reg1")).Times(1); 503 EXPECT_CALL(journal, logDebug("Configuring vdd0: volts=1.300000")) 504 .Times(1); 505 EXPECT_CALL(journal, logDebug("Configuring vio0: volts=3.200000")) 506 .Times(1); 507 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0); 508 509 // Create Rail vdd0 510 { 511 // Create Configuration for Rail 512 std::optional<double> volts{1.3}; 513 std::unique_ptr<MockAction> action = std::make_unique<MockAction>(); 514 EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true)); 515 std::vector<std::unique_ptr<Action>> actions{}; 516 actions.emplace_back(std::move(action)); 517 std::unique_ptr<Configuration> configuration = 518 std::make_unique<Configuration>(volts, std::move(actions)); 519 520 // Create Rail 521 std::unique_ptr<Rail> rail = 522 std::make_unique<Rail>("vdd0", std::move(configuration)); 523 rails.emplace_back(std::move(rail)); 524 } 525 526 // Create Rail vio0 527 { 528 // Create Configuration for Rail 529 std::optional<double> volts{3.2}; 530 std::unique_ptr<MockAction> action = std::make_unique<MockAction>(); 531 EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true)); 532 std::vector<std::unique_ptr<Action>> actions{}; 533 actions.emplace_back(std::move(action)); 534 std::unique_ptr<Configuration> configuration = 535 std::make_unique<Configuration>(volts, std::move(actions)); 536 537 // Create Rail 538 std::unique_ptr<Rail> rail = 539 std::make_unique<Rail>("vio0", std::move(configuration)); 540 rails.emplace_back(std::move(rail)); 541 } 542 543 // Create Configuration for Device 544 std::optional<double> volts{}; 545 std::unique_ptr<MockAction> action = std::make_unique<MockAction>(); 546 EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true)); 547 std::vector<std::unique_ptr<Action>> actions{}; 548 actions.emplace_back(std::move(action)); 549 std::unique_ptr<Configuration> configuration = 550 std::make_unique<Configuration>(volts, std::move(actions)); 551 552 // Create Device 553 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface(); 554 std::unique_ptr<PresenceDetection> presenceDetection{}; 555 std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{}; 556 std::unique_ptr<Device> device = std::make_unique<Device>( 557 "reg1", true, 558 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1", 559 std::move(i2cInterface), std::move(presenceDetection), 560 std::move(configuration), std::move(phaseFaultDetection), 561 std::move(rails)); 562 Device* devicePtr = device.get(); 563 564 // Create Chassis that contains Device 565 std::vector<std::unique_ptr<Device>> devices{}; 566 devices.emplace_back(std::move(device)); 567 std::unique_ptr<Chassis> chassis = 568 std::make_unique<Chassis>(1, chassisInvPath, std::move(devices)); 569 Chassis* chassisPtr = chassis.get(); 570 571 // Create System that contains Chassis 572 std::vector<std::unique_ptr<Rule>> rules{}; 573 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 574 chassisVec.emplace_back(std::move(chassis)); 575 System system{std::move(rules), std::move(chassisVec)}; 576 577 // Call configure(). 578 devicePtr->configure(services, system, *chassisPtr); 579 } 580 } 581 582 TEST(DeviceTests, GetConfiguration) 583 { 584 // Test where Configuration was not specified in constructor 585 { 586 Device device{ 587 "vdd_reg", true, 588 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2", 589 std::move(createI2CInterface())}; 590 EXPECT_EQ(device.getConfiguration(), nullptr); 591 } 592 593 // Test where Configuration was specified in constructor 594 { 595 std::unique_ptr<PresenceDetection> presenceDetection{}; 596 597 // Create Configuration 598 std::optional<double> volts{3.2}; 599 std::vector<std::unique_ptr<Action>> actions{}; 600 actions.push_back(std::make_unique<MockAction>()); 601 actions.push_back(std::make_unique<MockAction>()); 602 std::unique_ptr<Configuration> configuration = 603 std::make_unique<Configuration>(volts, std::move(actions)); 604 605 // Create Device 606 Device device{ 607 "vdd_reg", 608 true, 609 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2", 610 std::move(createI2CInterface()), 611 std::move(presenceDetection), 612 std::move(configuration)}; 613 EXPECT_NE(device.getConfiguration(), nullptr); 614 EXPECT_EQ(device.getConfiguration()->getVolts().has_value(), true); 615 EXPECT_EQ(device.getConfiguration()->getVolts().value(), 3.2); 616 EXPECT_EQ(device.getConfiguration()->getActions().size(), 2); 617 } 618 } 619 620 TEST(DeviceTests, GetFRU) 621 { 622 Device device{ 623 "vdd_reg", true, 624 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2", 625 std::move(createI2CInterface())}; 626 EXPECT_EQ(device.getFRU(), 627 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2"); 628 } 629 630 TEST(DeviceTests, GetI2CInterface) 631 { 632 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface(); 633 i2c::I2CInterface* i2cInterfacePtr = i2cInterface.get(); 634 Device device{ 635 "vdd_reg", true, 636 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2", 637 std::move(i2cInterface)}; 638 EXPECT_EQ(&(device.getI2CInterface()), i2cInterfacePtr); 639 } 640 641 TEST(DeviceTests, GetID) 642 { 643 Device device{ 644 "vdd_reg", false, 645 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2", 646 std::move(createI2CInterface())}; 647 EXPECT_EQ(device.getID(), "vdd_reg"); 648 } 649 650 TEST(DeviceTests, GetPhaseFaultDetection) 651 { 652 // Test where PhaseFaultDetection was not specified in constructor 653 { 654 Device device{ 655 "vdd_reg", true, 656 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2", 657 std::move(createI2CInterface())}; 658 EXPECT_EQ(device.getPhaseFaultDetection(), nullptr); 659 } 660 661 // Test where PhaseFaultDetection was specified in constructor 662 { 663 // Create PhaseFaultDetection 664 std::vector<std::unique_ptr<Action>> actions{}; 665 actions.push_back(std::make_unique<MockAction>()); 666 std::unique_ptr<PhaseFaultDetection> phaseFaultDetection = 667 std::make_unique<PhaseFaultDetection>(std::move(actions)); 668 669 // Create Device 670 std::unique_ptr<PresenceDetection> presenceDetection{}; 671 std::unique_ptr<Configuration> configuration{}; 672 Device device{ 673 "vdd_reg", 674 false, 675 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2", 676 std::move(createI2CInterface()), 677 std::move(presenceDetection), 678 std::move(configuration), 679 std::move(phaseFaultDetection)}; 680 EXPECT_NE(device.getPhaseFaultDetection(), nullptr); 681 EXPECT_EQ(device.getPhaseFaultDetection()->getActions().size(), 1); 682 } 683 } 684 685 TEST(DeviceTests, GetPresenceDetection) 686 { 687 // Test where PresenceDetection was not specified in constructor 688 { 689 Device device{ 690 "vdd_reg", true, 691 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2", 692 std::move(createI2CInterface())}; 693 EXPECT_EQ(device.getPresenceDetection(), nullptr); 694 } 695 696 // Test where PresenceDetection was specified in constructor 697 { 698 // Create PresenceDetection 699 std::vector<std::unique_ptr<Action>> actions{}; 700 actions.push_back(std::make_unique<MockAction>()); 701 std::unique_ptr<PresenceDetection> presenceDetection = 702 std::make_unique<PresenceDetection>(std::move(actions)); 703 704 // Create Device 705 Device device{ 706 "vdd_reg", false, 707 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2", 708 std::move(createI2CInterface()), std::move(presenceDetection)}; 709 EXPECT_NE(device.getPresenceDetection(), nullptr); 710 EXPECT_EQ(device.getPresenceDetection()->getActions().size(), 1); 711 } 712 } 713 714 TEST(DeviceTests, GetRails) 715 { 716 // Test where no rails were specified in constructor 717 { 718 Device device{ 719 "vdd_reg", true, 720 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2", 721 std::move(createI2CInterface())}; 722 EXPECT_EQ(device.getRails().size(), 0); 723 } 724 725 // Test where rails were specified in constructor 726 { 727 std::unique_ptr<PresenceDetection> presenceDetection{}; 728 std::unique_ptr<Configuration> configuration{}; 729 std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{}; 730 731 // Create vector of Rail objects 732 std::vector<std::unique_ptr<Rail>> rails{}; 733 rails.push_back(std::make_unique<Rail>("vdd0")); 734 rails.push_back(std::make_unique<Rail>("vdd1")); 735 736 // Create Device 737 Device device{ 738 "vdd_reg", 739 false, 740 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2", 741 std::move(createI2CInterface()), 742 std::move(presenceDetection), 743 std::move(configuration), 744 std::move(phaseFaultDetection), 745 std::move(rails)}; 746 EXPECT_EQ(device.getRails().size(), 2); 747 EXPECT_EQ(device.getRails()[0]->getID(), "vdd0"); 748 EXPECT_EQ(device.getRails()[1]->getID(), "vdd1"); 749 } 750 } 751 752 TEST(DeviceTests, IsPresent) 753 { 754 // Test where PresenceDetection not specified in constructor 755 { 756 // Create Device 757 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface(); 758 std::unique_ptr<Device> device = std::make_unique<Device>( 759 "reg1", true, 760 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1", 761 std::move(i2cInterface)); 762 Device* devicePtr = device.get(); 763 764 // Create Chassis that contains Device 765 std::vector<std::unique_ptr<Device>> devices{}; 766 devices.emplace_back(std::move(device)); 767 std::unique_ptr<Chassis> chassis = 768 std::make_unique<Chassis>(1, chassisInvPath, std::move(devices)); 769 Chassis* chassisPtr = chassis.get(); 770 771 // Create System that contains Chassis 772 std::vector<std::unique_ptr<Rule>> rules{}; 773 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 774 chassisVec.emplace_back(std::move(chassis)); 775 System system{std::move(rules), std::move(chassisVec)}; 776 777 // Create MockServices 778 MockServices services{}; 779 780 // Since no PresenceDetection defined, isPresent() should return true 781 EXPECT_TRUE(devicePtr->isPresent(services, system, *chassisPtr)); 782 } 783 784 // Test where PresenceDetection was specified in constructor: Is present 785 { 786 // Create PresenceDetection. Indicates device is present. 787 std::unique_ptr<MockAction> action = std::make_unique<MockAction>(); 788 EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true)); 789 std::vector<std::unique_ptr<Action>> actions{}; 790 actions.emplace_back(std::move(action)); 791 std::unique_ptr<PresenceDetection> presenceDetection = 792 std::make_unique<PresenceDetection>(std::move(actions)); 793 794 // Create Device 795 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface(); 796 std::unique_ptr<Device> device = std::make_unique<Device>( 797 "reg1", true, 798 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1", 799 std::move(i2cInterface), std::move(presenceDetection)); 800 Device* devicePtr = device.get(); 801 802 // Create Chassis that contains Device 803 std::vector<std::unique_ptr<Device>> devices{}; 804 devices.emplace_back(std::move(device)); 805 std::unique_ptr<Chassis> chassis = 806 std::make_unique<Chassis>(1, chassisInvPath, std::move(devices)); 807 Chassis* chassisPtr = chassis.get(); 808 809 // Create System that contains Chassis 810 std::vector<std::unique_ptr<Rule>> rules{}; 811 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 812 chassisVec.emplace_back(std::move(chassis)); 813 System system{std::move(rules), std::move(chassisVec)}; 814 815 // Create MockServices 816 MockServices services{}; 817 818 // PresenceDetection::execute() and isPresent() should return true 819 EXPECT_TRUE(devicePtr->isPresent(services, system, *chassisPtr)); 820 } 821 822 // Test where PresenceDetection was specified in constructor: Is not present 823 { 824 // Create PresenceDetection. Indicates device is not present. 825 std::unique_ptr<MockAction> action = std::make_unique<MockAction>(); 826 EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(false)); 827 std::vector<std::unique_ptr<Action>> actions{}; 828 actions.emplace_back(std::move(action)); 829 std::unique_ptr<PresenceDetection> presenceDetection = 830 std::make_unique<PresenceDetection>(std::move(actions)); 831 832 // Create Device 833 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface(); 834 std::unique_ptr<Device> device = std::make_unique<Device>( 835 "reg1", true, 836 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1", 837 std::move(i2cInterface), std::move(presenceDetection)); 838 Device* devicePtr = device.get(); 839 840 // Create Chassis that contains Device 841 std::vector<std::unique_ptr<Device>> devices{}; 842 devices.emplace_back(std::move(device)); 843 std::unique_ptr<Chassis> chassis = 844 std::make_unique<Chassis>(1, chassisInvPath, std::move(devices)); 845 Chassis* chassisPtr = chassis.get(); 846 847 // Create System that contains Chassis 848 std::vector<std::unique_ptr<Rule>> rules{}; 849 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 850 chassisVec.emplace_back(std::move(chassis)); 851 System system{std::move(rules), std::move(chassisVec)}; 852 853 // Create MockServices 854 MockServices services{}; 855 856 // PresenceDetection::execute() and isPresent() should return false 857 EXPECT_FALSE(devicePtr->isPresent(services, system, *chassisPtr)); 858 } 859 } 860 861 TEST(DeviceTests, IsRegulator) 862 { 863 Device device{ 864 "vdd_reg", false, 865 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2", 866 std::move(createI2CInterface())}; 867 EXPECT_EQ(device.isRegulator(), false); 868 } 869 870 TEST(DeviceTests, MonitorSensors) 871 { 872 // Test where device is not present 873 { 874 // Create mock services. No Sensors methods should be called. 875 MockServices services{}; 876 MockSensors& sensors = services.getMockSensors(); 877 EXPECT_CALL(sensors, startRail).Times(0); 878 EXPECT_CALL(sensors, setValue).Times(0); 879 EXPECT_CALL(sensors, endRail).Times(0); 880 881 // Create SensorMonitoring. Action inside it should not be executed. 882 std::unique_ptr<MockAction> sensAction = std::make_unique<MockAction>(); 883 EXPECT_CALL(*sensAction, execute).Times(0); 884 std::vector<std::unique_ptr<Action>> sensActions{}; 885 sensActions.emplace_back(std::move(sensAction)); 886 std::unique_ptr<SensorMonitoring> sensorMonitoring = 887 std::make_unique<SensorMonitoring>(std::move(sensActions)); 888 889 // Create Rail 890 std::unique_ptr<Configuration> configuration{}; 891 std::unique_ptr<Rail> rail = std::make_unique<Rail>( 892 "vddr1", std::move(configuration), std::move(sensorMonitoring)); 893 894 // Create PresenceDetection. Indicates device is not present. 895 std::unique_ptr<MockAction> presAction = std::make_unique<MockAction>(); 896 EXPECT_CALL(*presAction, execute).Times(1).WillOnce(Return(false)); 897 std::vector<std::unique_ptr<Action>> presActions{}; 898 presActions.emplace_back(std::move(presAction)); 899 std::unique_ptr<PresenceDetection> presenceDetection = 900 std::make_unique<PresenceDetection>(std::move(presActions)); 901 902 // Create Device 903 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface(); 904 std::unique_ptr<Configuration> deviceConfiguration{}; 905 std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{}; 906 std::vector<std::unique_ptr<Rail>> rails{}; 907 rails.emplace_back(std::move(rail)); 908 std::unique_ptr<Device> device = std::make_unique<Device>( 909 "reg1", true, 910 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1", 911 std::move(i2cInterface), std::move(presenceDetection), 912 std::move(deviceConfiguration), std::move(phaseFaultDetection), 913 std::move(rails)); 914 Device* devicePtr = device.get(); 915 916 // Create Chassis that contains Device 917 std::vector<std::unique_ptr<Device>> devices{}; 918 devices.emplace_back(std::move(device)); 919 std::unique_ptr<Chassis> chassis = 920 std::make_unique<Chassis>(1, chassisInvPath, std::move(devices)); 921 Chassis* chassisPtr = chassis.get(); 922 923 // Create System that contains Chassis 924 std::vector<std::unique_ptr<Rule>> rules{}; 925 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 926 chassisVec.emplace_back(std::move(chassis)); 927 System system{std::move(rules), std::move(chassisVec)}; 928 929 // Call monitorSensors(). Should do nothing. 930 devicePtr->monitorSensors(services, system, *chassisPtr); 931 } 932 933 // Test where Rails were not specified in constructor 934 { 935 // Create mock services. No Sensors methods should be called. 936 MockServices services{}; 937 MockSensors& sensors = services.getMockSensors(); 938 EXPECT_CALL(sensors, startRail).Times(0); 939 EXPECT_CALL(sensors, setValue).Times(0); 940 EXPECT_CALL(sensors, endRail).Times(0); 941 942 // Create Device 943 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface(); 944 std::unique_ptr<Device> device = std::make_unique<Device>( 945 "reg1", true, 946 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1", 947 std::move(i2cInterface)); 948 Device* devicePtr = device.get(); 949 950 // Create Chassis that contains Device 951 std::vector<std::unique_ptr<Device>> devices{}; 952 devices.emplace_back(std::move(device)); 953 std::unique_ptr<Chassis> chassis = 954 std::make_unique<Chassis>(1, chassisInvPath, std::move(devices)); 955 Chassis* chassisPtr = chassis.get(); 956 957 // Create System that contains Chassis 958 std::vector<std::unique_ptr<Rule>> rules{}; 959 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 960 chassisVec.emplace_back(std::move(chassis)); 961 System system{std::move(rules), std::move(chassisVec)}; 962 963 // Call monitorSensors(). Should do nothing. 964 devicePtr->monitorSensors(services, system, *chassisPtr); 965 } 966 967 // Test where Rails were specified in constructor 968 { 969 // Create mock services. Set Sensors service expectations. 970 MockServices services{}; 971 MockSensors& sensors = services.getMockSensors(); 972 EXPECT_CALL(sensors, startRail("vdd0", 973 "/xyz/openbmc_project/inventory/system/" 974 "chassis/motherboard/reg1", 975 chassisInvPath)) 976 .Times(1); 977 EXPECT_CALL(sensors, startRail("vio0", 978 "/xyz/openbmc_project/inventory/system/" 979 "chassis/motherboard/reg1", 980 chassisInvPath)) 981 .Times(1); 982 EXPECT_CALL(sensors, setValue).Times(0); 983 EXPECT_CALL(sensors, endRail(false)).Times(2); 984 985 std::vector<std::unique_ptr<Rail>> rails{}; 986 987 // Create Rail vdd0 988 { 989 // Create SensorMonitoring for Rail 990 std::unique_ptr<MockAction> action = std::make_unique<MockAction>(); 991 EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true)); 992 std::vector<std::unique_ptr<Action>> actions{}; 993 actions.emplace_back(std::move(action)); 994 std::unique_ptr<SensorMonitoring> sensorMonitoring = 995 std::make_unique<SensorMonitoring>(std::move(actions)); 996 997 // Create Rail 998 std::unique_ptr<Configuration> configuration{}; 999 std::unique_ptr<Rail> rail = std::make_unique<Rail>( 1000 "vdd0", std::move(configuration), std::move(sensorMonitoring)); 1001 rails.emplace_back(std::move(rail)); 1002 } 1003 1004 // Create Rail vio0 1005 { 1006 // Create SensorMonitoring for Rail 1007 std::unique_ptr<MockAction> action = std::make_unique<MockAction>(); 1008 EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true)); 1009 std::vector<std::unique_ptr<Action>> actions{}; 1010 actions.emplace_back(std::move(action)); 1011 std::unique_ptr<SensorMonitoring> sensorMonitoring = 1012 std::make_unique<SensorMonitoring>(std::move(actions)); 1013 1014 // Create Rail 1015 std::unique_ptr<Configuration> configuration{}; 1016 std::unique_ptr<Rail> rail = std::make_unique<Rail>( 1017 "vio0", std::move(configuration), std::move(sensorMonitoring)); 1018 rails.emplace_back(std::move(rail)); 1019 } 1020 1021 // Create Device that contains Rails 1022 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface(); 1023 std::unique_ptr<PresenceDetection> presenceDetection{}; 1024 std::unique_ptr<Configuration> configuration{}; 1025 std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{}; 1026 std::unique_ptr<Device> device = std::make_unique<Device>( 1027 "reg1", true, 1028 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1", 1029 std::move(i2cInterface), std::move(presenceDetection), 1030 std::move(configuration), std::move(phaseFaultDetection), 1031 std::move(rails)); 1032 Device* devicePtr = device.get(); 1033 1034 // Create Chassis that contains Device 1035 std::vector<std::unique_ptr<Device>> devices{}; 1036 devices.emplace_back(std::move(device)); 1037 std::unique_ptr<Chassis> chassis = 1038 std::make_unique<Chassis>(1, chassisInvPath, std::move(devices)); 1039 Chassis* chassisPtr = chassis.get(); 1040 1041 // Create System that contains Chassis 1042 std::vector<std::unique_ptr<Rule>> rules{}; 1043 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 1044 chassisVec.emplace_back(std::move(chassis)); 1045 System system{std::move(rules), std::move(chassisVec)}; 1046 1047 // Call monitorSensors(). Should monitor sensors in both rails. 1048 devicePtr->monitorSensors(services, system, *chassisPtr); 1049 } 1050 } 1051