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