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_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 "sensors.hpp" 32 #include "system.hpp" 33 #include "test_utils.hpp" 34 35 #include <memory> 36 #include <optional> 37 #include <string> 38 #include <utility> 39 #include <vector> 40 41 #include <gmock/gmock.h> 42 #include <gtest/gtest.h> 43 44 using namespace phosphor::power::regulators; 45 using namespace phosphor::power::regulators::test_utils; 46 47 using ::testing::A; 48 using ::testing::Ref; 49 using ::testing::Return; 50 using ::testing::Throw; 51 using ::testing::TypedEq; 52 53 TEST(DeviceTests, Constructor) 54 { 55 // Test where only required parameters are specified 56 { 57 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface(); 58 i2c::I2CInterface* i2cInterfacePtr = i2cInterface.get(); 59 Device device{ 60 "vdd_reg", true, 61 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2", 62 std::move(i2cInterface)}; 63 EXPECT_EQ(device.getID(), "vdd_reg"); 64 EXPECT_EQ(device.isRegulator(), true); 65 EXPECT_EQ( 66 device.getFRU(), 67 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2"); 68 EXPECT_EQ(&(device.getI2CInterface()), i2cInterfacePtr); 69 EXPECT_EQ(device.getPresenceDetection(), nullptr); 70 EXPECT_EQ(device.getConfiguration(), nullptr); 71 EXPECT_EQ(device.getRails().size(), 0); 72 } 73 74 // Test where all parameters are specified 75 { 76 // Create I2CInterface 77 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface(); 78 i2c::I2CInterface* i2cInterfacePtr = i2cInterface.get(); 79 80 // Create PresenceDetection 81 std::vector<std::unique_ptr<Action>> actions{}; 82 actions.push_back(std::make_unique<MockAction>()); 83 std::unique_ptr<PresenceDetection> presenceDetection = 84 std::make_unique<PresenceDetection>(std::move(actions)); 85 86 // Create Configuration 87 std::optional<double> volts{}; 88 actions.clear(); 89 actions.push_back(std::make_unique<MockAction>()); 90 actions.push_back(std::make_unique<MockAction>()); 91 std::unique_ptr<Configuration> configuration = 92 std::make_unique<Configuration>(volts, std::move(actions)); 93 94 // Create vector of Rail objects 95 std::vector<std::unique_ptr<Rail>> rails{}; 96 rails.push_back(std::make_unique<Rail>("vdd0")); 97 rails.push_back(std::make_unique<Rail>("vdd1")); 98 99 // Create Device 100 Device device{ 101 "vdd_reg", 102 false, 103 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1", 104 std::move(i2cInterface), 105 std::move(presenceDetection), 106 std::move(configuration), 107 std::move(rails)}; 108 EXPECT_EQ(device.getID(), "vdd_reg"); 109 EXPECT_EQ(device.isRegulator(), false); 110 EXPECT_EQ( 111 device.getFRU(), 112 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1"); 113 EXPECT_EQ(&(device.getI2CInterface()), i2cInterfacePtr); 114 EXPECT_NE(device.getPresenceDetection(), nullptr); 115 EXPECT_EQ(device.getPresenceDetection()->getActions().size(), 1); 116 EXPECT_NE(device.getConfiguration(), nullptr); 117 EXPECT_EQ(device.getConfiguration()->getVolts().has_value(), false); 118 EXPECT_EQ(device.getConfiguration()->getActions().size(), 2); 119 EXPECT_EQ(device.getRails().size(), 2); 120 } 121 } 122 123 TEST(DeviceTests, AddToIDMap) 124 { 125 std::unique_ptr<PresenceDetection> presenceDetection{}; 126 std::unique_ptr<Configuration> configuration{}; 127 128 // Create vector of Rail objects 129 std::vector<std::unique_ptr<Rail>> rails{}; 130 rails.push_back(std::make_unique<Rail>("vdd0")); 131 rails.push_back(std::make_unique<Rail>("vdd1")); 132 133 // Create Device 134 Device device{ 135 "vdd_reg", 136 false, 137 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2", 138 std::move(createI2CInterface()), 139 std::move(presenceDetection), 140 std::move(configuration), 141 std::move(rails)}; 142 143 // Add Device and Rail objects to an IDMap 144 IDMap idMap{}; 145 device.addToIDMap(idMap); 146 147 // Verify Device is in the IDMap 148 EXPECT_NO_THROW(idMap.getDevice("vdd_reg")); 149 EXPECT_THROW(idMap.getDevice("vio_reg"), std::invalid_argument); 150 151 // Verify all Rails are in the IDMap 152 EXPECT_NO_THROW(idMap.getRail("vdd0")); 153 EXPECT_NO_THROW(idMap.getRail("vdd1")); 154 EXPECT_THROW(idMap.getRail("vdd2"), std::invalid_argument); 155 } 156 157 TEST(DeviceTests, ClearCache) 158 { 159 // Test where Device does not contain a PresenceDetection object 160 try 161 { 162 Device device{ 163 "vdd_reg", false, 164 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2", 165 std::move(createI2CInterface())}; 166 device.clearCache(); 167 } 168 catch (...) 169 { 170 ADD_FAILURE() << "Should not have caught exception."; 171 } 172 173 // Test where Device contains a PresenceDetection object 174 { 175 // Create PresenceDetection 176 std::vector<std::unique_ptr<Action>> actions{}; 177 std::unique_ptr<PresenceDetection> presenceDetection = 178 std::make_unique<PresenceDetection>(std::move(actions)); 179 PresenceDetection* presenceDetectionPtr = presenceDetection.get(); 180 181 // Create Device 182 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface(); 183 std::unique_ptr<Device> device = std::make_unique<Device>( 184 "reg1", true, 185 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1", 186 std::move(i2cInterface), std::move(presenceDetection)); 187 Device* devicePtr = device.get(); 188 189 // Create Chassis that contains Device 190 std::vector<std::unique_ptr<Device>> devices{}; 191 devices.emplace_back(std::move(device)); 192 std::unique_ptr<Chassis> chassis = 193 std::make_unique<Chassis>(1, std::move(devices)); 194 Chassis* chassisPtr = chassis.get(); 195 196 // Create System that contains Chassis 197 std::vector<std::unique_ptr<Rule>> rules{}; 198 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 199 chassisVec.emplace_back(std::move(chassis)); 200 System system{std::move(rules), std::move(chassisVec)}; 201 202 // Cache presence value in PresenceDetection 203 MockServices services{}; 204 presenceDetectionPtr->execute(services, system, *chassisPtr, 205 *devicePtr); 206 EXPECT_TRUE(presenceDetectionPtr->getCachedPresence().has_value()); 207 208 // Clear cached data in Device 209 devicePtr->clearCache(); 210 211 // Verify presence value no longer cached in PresenceDetection 212 EXPECT_FALSE(presenceDetectionPtr->getCachedPresence().has_value()); 213 } 214 } 215 216 TEST(DeviceTests, Close) 217 { 218 // Test where works: I2C interface is not open 219 { 220 // Create mock I2CInterface 221 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface = 222 std::make_unique<i2c::MockedI2CInterface>(); 223 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(false)); 224 EXPECT_CALL(*i2cInterface, close).Times(0); 225 226 // Create mock services. No logError should occur. 227 MockServices services{}; 228 MockJournal& journal = services.getMockJournal(); 229 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0); 230 EXPECT_CALL(journal, logError(A<const std::vector<std::string>&>())) 231 .Times(0); 232 233 // Create Device 234 Device device{ 235 "vdd_reg", true, 236 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2", 237 std::move(i2cInterface)}; 238 239 // Close Device 240 device.close(services); 241 } 242 243 // Test where works: I2C interface is open 244 { 245 // Create mock I2CInterface 246 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface = 247 std::make_unique<i2c::MockedI2CInterface>(); 248 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true)); 249 EXPECT_CALL(*i2cInterface, close).Times(1); 250 251 // Create mock services. No logError should occur. 252 MockServices services{}; 253 MockJournal& journal = services.getMockJournal(); 254 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0); 255 EXPECT_CALL(journal, logError(A<const std::vector<std::string>&>())) 256 .Times(0); 257 258 // Create Device 259 Device device{ 260 "vdd_reg", true, 261 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2", 262 std::move(i2cInterface)}; 263 264 // Close Device 265 device.close(services); 266 } 267 268 // Test where fails: closing I2C interface fails 269 { 270 // Create mock I2CInterface 271 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface = 272 std::make_unique<i2c::MockedI2CInterface>(); 273 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true)); 274 EXPECT_CALL(*i2cInterface, close) 275 .Times(1) 276 .WillOnce(Throw( 277 i2c::I2CException{"Failed to close", "/dev/i2c-1", 0x70})); 278 279 // Create mock services. Expect logError() and logI2CError() to be 280 // called. 281 MockServices services{}; 282 MockErrorLogging& errorLogging = services.getMockErrorLogging(); 283 MockJournal& journal = services.getMockJournal(); 284 std::vector<std::string> expectedErrMessagesException{ 285 "I2CException: Failed to close: bus /dev/i2c-1, addr 0x70"}; 286 EXPECT_CALL(journal, logError("Unable to close device vdd_reg")) 287 .Times(1); 288 EXPECT_CALL(journal, logError(expectedErrMessagesException)).Times(1); 289 EXPECT_CALL(errorLogging, 290 logI2CError(Entry::Level::Notice, Ref(journal), 291 "/dev/i2c-1", 0x70, 0)) 292 .Times(1); 293 294 // Create Device 295 Device device{ 296 "vdd_reg", true, 297 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2", 298 std::move(i2cInterface)}; 299 300 // Close Device 301 device.close(services); 302 } 303 } 304 305 TEST(DeviceTests, Configure) 306 { 307 // Test where device is not present 308 { 309 // Create mock services. No logging should occur. 310 MockServices services{}; 311 MockJournal& journal = services.getMockJournal(); 312 EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0); 313 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0); 314 315 // Create PresenceDetection. Indicates device is not present. 316 std::unique_ptr<MockAction> presAction = std::make_unique<MockAction>(); 317 EXPECT_CALL(*presAction, execute).Times(1).WillOnce(Return(false)); 318 std::vector<std::unique_ptr<Action>> presActions{}; 319 presActions.emplace_back(std::move(presAction)); 320 std::unique_ptr<PresenceDetection> presenceDetection = 321 std::make_unique<PresenceDetection>(std::move(presActions)); 322 323 // Create Configuration. Action inside it should not be executed. 324 std::optional<double> volts{}; 325 std::unique_ptr<MockAction> confAction = std::make_unique<MockAction>(); 326 EXPECT_CALL(*confAction, execute).Times(0); 327 std::vector<std::unique_ptr<Action>> confActions{}; 328 confActions.emplace_back(std::move(confAction)); 329 std::unique_ptr<Configuration> configuration = 330 std::make_unique<Configuration>(volts, std::move(confActions)); 331 332 // Create Device 333 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface(); 334 std::unique_ptr<Device> device = std::make_unique<Device>( 335 "reg1", true, 336 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1", 337 std::move(i2cInterface), std::move(presenceDetection), 338 std::move(configuration)); 339 Device* devicePtr = device.get(); 340 341 // Create Chassis that contains Device 342 std::vector<std::unique_ptr<Device>> devices{}; 343 devices.emplace_back(std::move(device)); 344 std::unique_ptr<Chassis> chassis = 345 std::make_unique<Chassis>(1, std::move(devices)); 346 Chassis* chassisPtr = chassis.get(); 347 348 // Create System that contains Chassis 349 std::vector<std::unique_ptr<Rule>> rules{}; 350 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 351 chassisVec.emplace_back(std::move(chassis)); 352 System system{std::move(rules), std::move(chassisVec)}; 353 354 // Call configure(). Should do nothing. 355 devicePtr->configure(services, system, *chassisPtr); 356 } 357 358 // Test where Configuration and Rails were not specified in constructor 359 { 360 // Create mock services. No logging should occur. 361 MockServices services{}; 362 MockJournal& journal = services.getMockJournal(); 363 EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0); 364 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0); 365 366 // Create Device 367 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface(); 368 std::unique_ptr<Device> device = std::make_unique<Device>( 369 "reg1", true, 370 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1", 371 std::move(i2cInterface)); 372 Device* devicePtr = device.get(); 373 374 // Create Chassis that contains Device 375 std::vector<std::unique_ptr<Device>> devices{}; 376 devices.emplace_back(std::move(device)); 377 std::unique_ptr<Chassis> chassis = 378 std::make_unique<Chassis>(1, std::move(devices)); 379 Chassis* chassisPtr = chassis.get(); 380 381 // Create System that contains Chassis 382 std::vector<std::unique_ptr<Rule>> rules{}; 383 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 384 chassisVec.emplace_back(std::move(chassis)); 385 System system{std::move(rules), std::move(chassisVec)}; 386 387 // Call configure(). 388 devicePtr->configure(services, system, *chassisPtr); 389 } 390 391 // Test where Configuration and Rails were specified in constructor 392 { 393 std::vector<std::unique_ptr<Rail>> rails{}; 394 395 // Create mock services. Expect logDebug() to be called. 396 // For the Device and both Rails, should execute the Configuration 397 // and log a debug message. 398 MockServices services{}; 399 MockJournal& journal = services.getMockJournal(); 400 EXPECT_CALL(journal, logDebug("Configuring reg1")).Times(1); 401 EXPECT_CALL(journal, logDebug("Configuring vdd0: volts=1.300000")) 402 .Times(1); 403 EXPECT_CALL(journal, logDebug("Configuring vio0: volts=3.200000")) 404 .Times(1); 405 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0); 406 407 // Create Rail vdd0 408 { 409 // Create Configuration for Rail 410 std::optional<double> volts{1.3}; 411 std::unique_ptr<MockAction> action = std::make_unique<MockAction>(); 412 EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true)); 413 std::vector<std::unique_ptr<Action>> actions{}; 414 actions.emplace_back(std::move(action)); 415 std::unique_ptr<Configuration> configuration = 416 std::make_unique<Configuration>(volts, std::move(actions)); 417 418 // Create Rail 419 std::unique_ptr<Rail> rail = 420 std::make_unique<Rail>("vdd0", std::move(configuration)); 421 rails.emplace_back(std::move(rail)); 422 } 423 424 // Create Rail vio0 425 { 426 // Create Configuration for Rail 427 std::optional<double> volts{3.2}; 428 std::unique_ptr<MockAction> action = std::make_unique<MockAction>(); 429 EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true)); 430 std::vector<std::unique_ptr<Action>> actions{}; 431 actions.emplace_back(std::move(action)); 432 std::unique_ptr<Configuration> configuration = 433 std::make_unique<Configuration>(volts, std::move(actions)); 434 435 // Create Rail 436 std::unique_ptr<Rail> rail = 437 std::make_unique<Rail>("vio0", std::move(configuration)); 438 rails.emplace_back(std::move(rail)); 439 } 440 441 // Create Configuration for Device 442 std::optional<double> volts{}; 443 std::unique_ptr<MockAction> action = std::make_unique<MockAction>(); 444 EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true)); 445 std::vector<std::unique_ptr<Action>> actions{}; 446 actions.emplace_back(std::move(action)); 447 std::unique_ptr<Configuration> configuration = 448 std::make_unique<Configuration>(volts, std::move(actions)); 449 450 // Create Device 451 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface(); 452 std::unique_ptr<PresenceDetection> presenceDetection{}; 453 std::unique_ptr<Device> device = std::make_unique<Device>( 454 "reg1", true, 455 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1", 456 std::move(i2cInterface), std::move(presenceDetection), 457 std::move(configuration), std::move(rails)); 458 Device* devicePtr = device.get(); 459 460 // Create Chassis that contains Device 461 std::vector<std::unique_ptr<Device>> devices{}; 462 devices.emplace_back(std::move(device)); 463 std::unique_ptr<Chassis> chassis = 464 std::make_unique<Chassis>(1, std::move(devices)); 465 Chassis* chassisPtr = chassis.get(); 466 467 // Create System that contains Chassis 468 std::vector<std::unique_ptr<Rule>> rules{}; 469 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 470 chassisVec.emplace_back(std::move(chassis)); 471 System system{std::move(rules), std::move(chassisVec)}; 472 473 // Call configure(). 474 devicePtr->configure(services, system, *chassisPtr); 475 } 476 } 477 478 TEST(DeviceTests, GetConfiguration) 479 { 480 // Test where Configuration was not specified in constructor 481 { 482 Device device{ 483 "vdd_reg", true, 484 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2", 485 std::move(createI2CInterface())}; 486 EXPECT_EQ(device.getConfiguration(), nullptr); 487 } 488 489 // Test where Configuration was specified in constructor 490 { 491 std::unique_ptr<PresenceDetection> presenceDetection{}; 492 493 // Create Configuration 494 std::optional<double> volts{3.2}; 495 std::vector<std::unique_ptr<Action>> actions{}; 496 actions.push_back(std::make_unique<MockAction>()); 497 actions.push_back(std::make_unique<MockAction>()); 498 std::unique_ptr<Configuration> configuration = 499 std::make_unique<Configuration>(volts, std::move(actions)); 500 501 // Create Device 502 Device device{ 503 "vdd_reg", 504 true, 505 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2", 506 std::move(createI2CInterface()), 507 std::move(presenceDetection), 508 std::move(configuration)}; 509 EXPECT_NE(device.getConfiguration(), nullptr); 510 EXPECT_EQ(device.getConfiguration()->getVolts().has_value(), true); 511 EXPECT_EQ(device.getConfiguration()->getVolts().value(), 3.2); 512 EXPECT_EQ(device.getConfiguration()->getActions().size(), 2); 513 } 514 } 515 516 TEST(DeviceTests, GetFRU) 517 { 518 Device device{ 519 "vdd_reg", true, 520 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2", 521 std::move(createI2CInterface())}; 522 EXPECT_EQ(device.getFRU(), 523 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2"); 524 } 525 526 TEST(DeviceTests, GetI2CInterface) 527 { 528 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface(); 529 i2c::I2CInterface* i2cInterfacePtr = i2cInterface.get(); 530 Device device{ 531 "vdd_reg", true, 532 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2", 533 std::move(i2cInterface)}; 534 EXPECT_EQ(&(device.getI2CInterface()), i2cInterfacePtr); 535 } 536 537 TEST(DeviceTests, GetID) 538 { 539 Device device{ 540 "vdd_reg", false, 541 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2", 542 std::move(createI2CInterface())}; 543 EXPECT_EQ(device.getID(), "vdd_reg"); 544 } 545 546 TEST(DeviceTests, GetPresenceDetection) 547 { 548 // Test where PresenceDetection was not specified in constructor 549 { 550 Device device{ 551 "vdd_reg", true, 552 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2", 553 std::move(createI2CInterface())}; 554 EXPECT_EQ(device.getPresenceDetection(), nullptr); 555 } 556 557 // Test where PresenceDetection was specified in constructor 558 { 559 // Create PresenceDetection 560 std::vector<std::unique_ptr<Action>> actions{}; 561 actions.push_back(std::make_unique<MockAction>()); 562 std::unique_ptr<PresenceDetection> presenceDetection = 563 std::make_unique<PresenceDetection>(std::move(actions)); 564 565 // Create Device 566 Device device{ 567 "vdd_reg", false, 568 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2", 569 std::move(createI2CInterface()), std::move(presenceDetection)}; 570 EXPECT_NE(device.getPresenceDetection(), nullptr); 571 EXPECT_EQ(device.getPresenceDetection()->getActions().size(), 1); 572 } 573 } 574 575 TEST(DeviceTests, GetRails) 576 { 577 // Test where no rails were specified in constructor 578 { 579 Device device{ 580 "vdd_reg", true, 581 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2", 582 std::move(createI2CInterface())}; 583 EXPECT_EQ(device.getRails().size(), 0); 584 } 585 586 // Test where rails were specified in constructor 587 { 588 std::unique_ptr<PresenceDetection> presenceDetection{}; 589 std::unique_ptr<Configuration> configuration{}; 590 591 // Create vector of Rail objects 592 std::vector<std::unique_ptr<Rail>> rails{}; 593 rails.push_back(std::make_unique<Rail>("vdd0")); 594 rails.push_back(std::make_unique<Rail>("vdd1")); 595 596 // Create Device 597 Device device{ 598 "vdd_reg", 599 false, 600 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2", 601 std::move(createI2CInterface()), 602 std::move(presenceDetection), 603 std::move(configuration), 604 std::move(rails)}; 605 EXPECT_EQ(device.getRails().size(), 2); 606 EXPECT_EQ(device.getRails()[0]->getID(), "vdd0"); 607 EXPECT_EQ(device.getRails()[1]->getID(), "vdd1"); 608 } 609 } 610 611 TEST(DeviceTests, IsPresent) 612 { 613 // Test where PresenceDetection not specified in constructor 614 { 615 // Create Device 616 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface(); 617 std::unique_ptr<Device> device = std::make_unique<Device>( 618 "reg1", true, 619 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1", 620 std::move(i2cInterface)); 621 Device* devicePtr = device.get(); 622 623 // Create Chassis that contains Device 624 std::vector<std::unique_ptr<Device>> devices{}; 625 devices.emplace_back(std::move(device)); 626 std::unique_ptr<Chassis> chassis = 627 std::make_unique<Chassis>(1, std::move(devices)); 628 Chassis* chassisPtr = chassis.get(); 629 630 // Create System that contains Chassis 631 std::vector<std::unique_ptr<Rule>> rules{}; 632 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 633 chassisVec.emplace_back(std::move(chassis)); 634 System system{std::move(rules), std::move(chassisVec)}; 635 636 // Create MockServices 637 MockServices services{}; 638 639 // Since no PresenceDetection defined, isPresent() should return true 640 EXPECT_TRUE(devicePtr->isPresent(services, system, *chassisPtr)); 641 } 642 643 // Test where PresenceDetection was specified in constructor: Is present 644 { 645 // Create PresenceDetection. Indicates device is present. 646 std::unique_ptr<MockAction> action = std::make_unique<MockAction>(); 647 EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true)); 648 std::vector<std::unique_ptr<Action>> actions{}; 649 actions.emplace_back(std::move(action)); 650 std::unique_ptr<PresenceDetection> presenceDetection = 651 std::make_unique<PresenceDetection>(std::move(actions)); 652 653 // Create Device 654 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface(); 655 std::unique_ptr<Device> device = std::make_unique<Device>( 656 "reg1", true, 657 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1", 658 std::move(i2cInterface), std::move(presenceDetection)); 659 Device* devicePtr = device.get(); 660 661 // Create Chassis that contains Device 662 std::vector<std::unique_ptr<Device>> devices{}; 663 devices.emplace_back(std::move(device)); 664 std::unique_ptr<Chassis> chassis = 665 std::make_unique<Chassis>(1, std::move(devices)); 666 Chassis* chassisPtr = chassis.get(); 667 668 // Create System that contains Chassis 669 std::vector<std::unique_ptr<Rule>> rules{}; 670 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 671 chassisVec.emplace_back(std::move(chassis)); 672 System system{std::move(rules), std::move(chassisVec)}; 673 674 // Create MockServices 675 MockServices services{}; 676 677 // PresenceDetection::execute() and isPresent() should return true 678 EXPECT_TRUE(devicePtr->isPresent(services, system, *chassisPtr)); 679 } 680 681 // Test where PresenceDetection was specified in constructor: Is not present 682 { 683 // Create PresenceDetection. Indicates device is not present. 684 std::unique_ptr<MockAction> action = std::make_unique<MockAction>(); 685 EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(false)); 686 std::vector<std::unique_ptr<Action>> actions{}; 687 actions.emplace_back(std::move(action)); 688 std::unique_ptr<PresenceDetection> presenceDetection = 689 std::make_unique<PresenceDetection>(std::move(actions)); 690 691 // Create Device 692 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface(); 693 std::unique_ptr<Device> device = std::make_unique<Device>( 694 "reg1", true, 695 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1", 696 std::move(i2cInterface), std::move(presenceDetection)); 697 Device* devicePtr = device.get(); 698 699 // Create Chassis that contains Device 700 std::vector<std::unique_ptr<Device>> devices{}; 701 devices.emplace_back(std::move(device)); 702 std::unique_ptr<Chassis> chassis = 703 std::make_unique<Chassis>(1, std::move(devices)); 704 Chassis* chassisPtr = chassis.get(); 705 706 // Create System that contains Chassis 707 std::vector<std::unique_ptr<Rule>> rules{}; 708 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 709 chassisVec.emplace_back(std::move(chassis)); 710 System system{std::move(rules), std::move(chassisVec)}; 711 712 // Create MockServices 713 MockServices services{}; 714 715 // PresenceDetection::execute() and isPresent() should return false 716 EXPECT_FALSE(devicePtr->isPresent(services, system, *chassisPtr)); 717 } 718 } 719 720 TEST(DeviceTests, IsRegulator) 721 { 722 Device device{ 723 "vdd_reg", false, 724 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2", 725 std::move(createI2CInterface())}; 726 EXPECT_EQ(device.isRegulator(), false); 727 } 728 729 TEST(DeviceTests, MonitorSensors) 730 { 731 // Test where device is not present 732 // TODO: Add this test when sensoring monitoring is fully implemented 733 734 // Test where Rails were not specified in constructor 735 { 736 // Create mock services. No logging should occur. 737 MockServices services{}; 738 MockJournal& journal = services.getMockJournal(); 739 EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0); 740 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0); 741 742 // Create mock I2CInterface. A two-byte read should NOT occur. 743 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface = 744 std::make_unique<i2c::MockedI2CInterface>(); 745 EXPECT_CALL(*i2cInterface, read(A<uint8_t>(), A<uint16_t&>())).Times(0); 746 747 // Create Device 748 std::unique_ptr<Device> device = std::make_unique<Device>( 749 "reg1", true, 750 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1", 751 std::move(i2cInterface)); 752 Device* devicePtr = device.get(); 753 754 // Create Chassis that contains Device 755 std::vector<std::unique_ptr<Device>> devices{}; 756 devices.emplace_back(std::move(device)); 757 std::unique_ptr<Chassis> chassis = 758 std::make_unique<Chassis>(1, std::move(devices)); 759 Chassis* chassisPtr = chassis.get(); 760 761 // Create System that contains Chassis 762 std::vector<std::unique_ptr<Rule>> rules{}; 763 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 764 chassisVec.emplace_back(std::move(chassis)); 765 System system{std::move(rules), std::move(chassisVec)}; 766 767 // Call monitorSensors(). 768 devicePtr->monitorSensors(services, system, *chassisPtr); 769 } 770 771 // Test where Rails were specified in constructor 772 { 773 // Create mock services. No logging should occur. 774 MockServices services{}; 775 MockJournal& journal = services.getMockJournal(); 776 EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0); 777 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0); 778 779 std::vector<std::unique_ptr<Rail>> rails{}; 780 781 // Create PMBusReadSensorAction 782 SensorType type{SensorType::iout}; 783 uint8_t command = 0x8C; 784 pmbus_utils::SensorDataFormat format{ 785 pmbus_utils::SensorDataFormat::linear_11}; 786 std::optional<int8_t> exponent{}; 787 std::unique_ptr<PMBusReadSensorAction> action = 788 std::make_unique<PMBusReadSensorAction>(type, command, format, 789 exponent); 790 791 // Create mock I2CInterface. A two-byte read should occur. 792 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface = 793 std::make_unique<i2c::MockedI2CInterface>(); 794 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true)); 795 EXPECT_CALL(*i2cInterface, read(TypedEq<uint8_t>(0x8C), A<uint16_t&>())) 796 .Times(1); 797 798 // Create SensorMonitoring 799 std::vector<std::unique_ptr<Action>> actions{}; 800 actions.emplace_back(std::move(action)); 801 std::unique_ptr<SensorMonitoring> sensorMonitoring = 802 std::make_unique<SensorMonitoring>(std::move(actions)); 803 804 // Create Rail 805 std::unique_ptr<Configuration> configuration{}; 806 std::unique_ptr<Rail> rail = std::make_unique<Rail>( 807 "vdd0", std::move(configuration), std::move(sensorMonitoring)); 808 rails.emplace_back(std::move(rail)); 809 810 // Create Device 811 std::unique_ptr<PresenceDetection> presenceDetection{}; 812 std::unique_ptr<Configuration> deviceConfiguration{}; 813 std::unique_ptr<Device> device = std::make_unique<Device>( 814 "reg1", true, 815 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1", 816 std::move(i2cInterface), std::move(presenceDetection), 817 std::move(deviceConfiguration), std::move(rails)); 818 Device* devicePtr = device.get(); 819 820 // Create Chassis that contains Device 821 std::vector<std::unique_ptr<Device>> devices{}; 822 devices.emplace_back(std::move(device)); 823 std::unique_ptr<Chassis> chassis = 824 std::make_unique<Chassis>(1, std::move(devices)); 825 Chassis* chassisPtr = chassis.get(); 826 827 // Create System that contains Chassis 828 std::vector<std::unique_ptr<Rule>> rules{}; 829 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 830 chassisVec.emplace_back(std::move(chassis)); 831 System system{std::move(rules), std::move(chassisVec)}; 832 833 // Call monitorSensors(). 834 devicePtr->monitorSensors(services, system, *chassisPtr); 835 } 836 } 837