1 /** 2 * Copyright © 2024 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 17 #include "mock_pmbus.hpp" 18 #include "mock_services.hpp" 19 #include "pmbus.hpp" 20 #include "pmbus_driver_device.hpp" 21 #include "rail.hpp" 22 #include "services.hpp" 23 #include "temporary_subdirectory.hpp" 24 25 #include <cstdint> 26 #include <exception> 27 #include <filesystem> 28 #include <format> 29 #include <fstream> 30 #include <map> 31 #include <memory> 32 #include <optional> 33 #include <stdexcept> 34 #include <string> 35 #include <utility> 36 #include <vector> 37 38 #include <gmock/gmock.h> 39 #include <gtest/gtest.h> 40 41 using namespace phosphor::power::sequencer; 42 using namespace phosphor::pmbus; 43 using namespace phosphor::power::util; 44 namespace fs = std::filesystem; 45 46 using ::testing::Return; 47 using ::testing::Throw; 48 49 class PMBusDriverDeviceTests : public ::testing::Test 50 { 51 protected: 52 /** 53 * Constructor. 54 * 55 * Creates a temporary directory to use in simulating sysfs files. 56 */ 57 PMBusDriverDeviceTests() : ::testing::Test{} 58 { 59 tempDirPath = tempDir.getPath(); 60 } 61 62 /** 63 * Creates a Rail object that checks for a pgood fault using STATUS_VOUT. 64 * 65 * @param name Unique name for the rail 66 * @param pageNum PMBus PAGE number of the rail 67 * @return Rail object 68 */ 69 std::unique_ptr<Rail> createRail(const std::string& name, uint8_t pageNum) 70 { 71 std::optional<std::string> presence{}; 72 std::optional<uint8_t> page{pageNum}; 73 bool isPowerSupplyRail{false}; 74 bool checkStatusVout{true}; 75 bool compareVoltageToLimit{false}; 76 std::optional<GPIO> gpio{}; 77 return std::make_unique<Rail>(name, presence, page, isPowerSupplyRail, 78 checkStatusVout, compareVoltageToLimit, 79 gpio); 80 } 81 82 /** 83 * Creates a file with the specified contents within the temporary 84 * directory. 85 * 86 * @param name File name 87 * @param contents File contents 88 */ 89 void createFile(const std::string& name, const std::string& contents = "") 90 { 91 fs::path path{tempDirPath / name}; 92 std::ofstream out{path}; 93 out << contents; 94 out.close(); 95 } 96 97 /** 98 * Temporary subdirectory used to create simulated sysfs / hmmon files. 99 */ 100 TemporarySubDirectory tempDir; 101 102 /** 103 * Path to temporary subdirectory. 104 */ 105 fs::path tempDirPath; 106 }; 107 108 TEST_F(PMBusDriverDeviceTests, Constructor) 109 { 110 // Test where works; optional parameters not specified 111 { 112 MockServices services; 113 114 std::string name{"XYZ_PSEQ"}; 115 std::vector<std::unique_ptr<Rail>> rails; 116 rails.emplace_back(createRail("VDD", 5)); 117 rails.emplace_back(createRail("VIO", 7)); 118 uint8_t bus{3}; 119 uint16_t address{0x72}; 120 PMBusDriverDevice device{name, std::move(rails), services, bus, 121 address}; 122 123 EXPECT_EQ(device.getName(), name); 124 EXPECT_EQ(device.getRails().size(), 2); 125 EXPECT_EQ(device.getRails()[0]->getName(), "VDD"); 126 EXPECT_EQ(device.getRails()[1]->getName(), "VIO"); 127 EXPECT_EQ(device.getBus(), bus); 128 EXPECT_EQ(device.getAddress(), address); 129 EXPECT_EQ(device.getDriverName(), ""); 130 EXPECT_EQ(device.getInstance(), 0); 131 EXPECT_NE(&(device.getPMBusInterface()), nullptr); 132 } 133 134 // Test where works; optional parameters specified 135 { 136 MockServices services; 137 138 std::string name{"XYZ_PSEQ"}; 139 std::vector<std::unique_ptr<Rail>> rails; 140 rails.emplace_back(createRail("VDD", 5)); 141 rails.emplace_back(createRail("VIO", 7)); 142 uint8_t bus{3}; 143 uint16_t address{0x72}; 144 std::string driverName{"xyzdev"}; 145 size_t instance{3}; 146 PMBusDriverDevice device{name, std::move(rails), services, bus, 147 address, driverName, instance}; 148 149 EXPECT_EQ(device.getName(), name); 150 EXPECT_EQ(device.getRails().size(), 2); 151 EXPECT_EQ(device.getRails()[0]->getName(), "VDD"); 152 EXPECT_EQ(device.getRails()[1]->getName(), "VIO"); 153 EXPECT_EQ(device.getBus(), bus); 154 EXPECT_EQ(device.getAddress(), address); 155 EXPECT_EQ(device.getDriverName(), driverName); 156 EXPECT_EQ(device.getInstance(), instance); 157 EXPECT_NE(&(device.getPMBusInterface()), nullptr); 158 } 159 } 160 161 TEST_F(PMBusDriverDeviceTests, GetBus) 162 { 163 MockServices services; 164 165 std::string name{"XYZ_PSEQ"}; 166 std::vector<std::unique_ptr<Rail>> rails; 167 uint8_t bus{4}; 168 uint16_t address{0x72}; 169 PMBusDriverDevice device{name, std::move(rails), services, bus, address}; 170 171 EXPECT_EQ(device.getBus(), bus); 172 } 173 174 TEST_F(PMBusDriverDeviceTests, GetAddress) 175 { 176 MockServices services; 177 178 std::string name{"XYZ_PSEQ"}; 179 std::vector<std::unique_ptr<Rail>> rails; 180 uint8_t bus{3}; 181 uint16_t address{0xab}; 182 PMBusDriverDevice device{name, std::move(rails), services, bus, address}; 183 184 EXPECT_EQ(device.getAddress(), address); 185 } 186 187 TEST_F(PMBusDriverDeviceTests, GetDriverName) 188 { 189 MockServices services; 190 191 std::string name{"XYZ_PSEQ"}; 192 std::vector<std::unique_ptr<Rail>> rails; 193 uint8_t bus{3}; 194 uint16_t address{0x72}; 195 std::string driverName{"xyzdev"}; 196 PMBusDriverDevice device{name, std::move(rails), services, 197 bus, address, driverName}; 198 199 EXPECT_EQ(device.getDriverName(), driverName); 200 } 201 202 TEST_F(PMBusDriverDeviceTests, GetInstance) 203 { 204 MockServices services; 205 206 std::string name{"XYZ_PSEQ"}; 207 std::vector<std::unique_ptr<Rail>> rails; 208 uint8_t bus{3}; 209 uint16_t address{0x72}; 210 std::string driverName{"xyzdev"}; 211 size_t instance{3}; 212 PMBusDriverDevice device{name, std::move(rails), services, bus, 213 address, driverName, instance}; 214 215 EXPECT_EQ(device.getInstance(), instance); 216 } 217 218 TEST_F(PMBusDriverDeviceTests, GetPMBusInterface) 219 { 220 MockServices services; 221 222 std::string name{"XYZ_PSEQ"}; 223 std::vector<std::unique_ptr<Rail>> rails; 224 uint8_t bus{3}; 225 uint16_t address{0x72}; 226 PMBusDriverDevice device{name, std::move(rails), services, bus, address}; 227 228 EXPECT_NE(&(device.getPMBusInterface()), nullptr); 229 } 230 231 TEST_F(PMBusDriverDeviceTests, GetGPIOValues) 232 { 233 // Test where works 234 { 235 MockServices services; 236 std::vector<int> gpioValues{1, 1, 1}; 237 EXPECT_CALL(services, getGPIOValues("abc_382%#, zy")) 238 .Times(1) 239 .WillOnce(Return(gpioValues)); 240 241 std::string name{"ABC_382%#, ZY"}; 242 std::vector<std::unique_ptr<Rail>> rails; 243 uint8_t bus{3}; 244 uint16_t address{0x72}; 245 PMBusDriverDevice device{name, std::move(rails), services, bus, 246 address}; 247 248 EXPECT_TRUE(device.getGPIOValues(services) == gpioValues); 249 } 250 251 // Test where fails with exception 252 { 253 MockServices services; 254 EXPECT_CALL(services, getGPIOValues("xyz_pseq")) 255 .Times(1) 256 .WillOnce( 257 Throw(std::runtime_error{"libgpiod: Unable to open chip"})); 258 259 std::string name{"XYZ_PSEQ"}; 260 std::vector<std::unique_ptr<Rail>> rails; 261 uint8_t bus{3}; 262 uint16_t address{0x72}; 263 PMBusDriverDevice device{name, std::move(rails), services, bus, 264 address}; 265 266 try 267 { 268 device.getGPIOValues(services); 269 ADD_FAILURE() << "Should not have reached this line."; 270 } 271 catch (const std::exception& e) 272 { 273 EXPECT_STREQ(e.what(), 274 "Unable to read GPIO values from device XYZ_PSEQ " 275 "using label xyz_pseq: " 276 "libgpiod: Unable to open chip"); 277 } 278 } 279 } 280 281 TEST_F(PMBusDriverDeviceTests, GetStatusWord) 282 { 283 // Test where works 284 { 285 MockServices services; 286 287 std::string name{"xyz_pseq"}; 288 std::vector<std::unique_ptr<Rail>> rails; 289 uint8_t bus{3}; 290 uint16_t address{0x72}; 291 PMBusDriverDevice device{name, std::move(rails), services, bus, 292 address}; 293 294 MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface()); 295 EXPECT_CALL(pmbus, read("status13", Type::Debug, true)) 296 .Times(1) 297 .WillOnce(Return(0x1234)); 298 299 uint8_t page{13}; 300 EXPECT_EQ(device.getStatusWord(page), 0x1234); 301 } 302 303 // Test where fails with exception 304 { 305 MockServices services; 306 307 std::string name{"xyz_pseq"}; 308 std::vector<std::unique_ptr<Rail>> rails; 309 uint8_t bus{3}; 310 uint16_t address{0x72}; 311 PMBusDriverDevice device{name, std::move(rails), services, bus, 312 address}; 313 314 MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface()); 315 EXPECT_CALL(pmbus, read("status0", Type::Debug, true)) 316 .Times(1) 317 .WillOnce(Throw(std::runtime_error{"File does not exist"})); 318 319 try 320 { 321 uint8_t page{0}; 322 device.getStatusWord(page); 323 ADD_FAILURE() << "Should not have reached this line."; 324 } 325 catch (const std::exception& e) 326 { 327 EXPECT_STREQ( 328 e.what(), 329 "Unable to read STATUS_WORD for PAGE 0 of device xyz_pseq: " 330 "File does not exist"); 331 } 332 } 333 } 334 335 TEST_F(PMBusDriverDeviceTests, GetStatusVout) 336 { 337 // Test where works 338 { 339 MockServices services; 340 341 std::string name{"xyz_pseq"}; 342 std::vector<std::unique_ptr<Rail>> rails; 343 uint8_t bus{3}; 344 uint16_t address{0x72}; 345 PMBusDriverDevice device{name, std::move(rails), services, bus, 346 address}; 347 348 MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface()); 349 EXPECT_CALL(pmbus, read("status13_vout", Type::Debug, true)) 350 .Times(1) 351 .WillOnce(Return(0xde)); 352 353 uint8_t page{13}; 354 EXPECT_EQ(device.getStatusVout(page), 0xde); 355 } 356 357 // Test where fails with exception 358 { 359 MockServices services; 360 361 std::string name{"xyz_pseq"}; 362 std::vector<std::unique_ptr<Rail>> rails; 363 uint8_t bus{3}; 364 uint16_t address{0x72}; 365 PMBusDriverDevice device{name, std::move(rails), services, bus, 366 address}; 367 368 MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface()); 369 EXPECT_CALL(pmbus, read("status0_vout", Type::Debug, true)) 370 .Times(1) 371 .WillOnce(Throw(std::runtime_error{"File does not exist"})); 372 373 try 374 { 375 uint8_t page{0}; 376 device.getStatusVout(page); 377 ADD_FAILURE() << "Should not have reached this line."; 378 } 379 catch (const std::exception& e) 380 { 381 EXPECT_STREQ( 382 e.what(), 383 "Unable to read STATUS_VOUT for PAGE 0 of device xyz_pseq: " 384 "File does not exist"); 385 } 386 } 387 } 388 389 TEST_F(PMBusDriverDeviceTests, GetReadVout) 390 { 391 // Test where works 392 { 393 // Create simulated hwmon voltage label file 394 createFile("in13_label"); // PAGE 9 -> file number 13 395 396 MockServices services; 397 398 std::string name{"xyz_pseq"}; 399 std::vector<std::unique_ptr<Rail>> rails; 400 uint8_t bus{3}; 401 uint16_t address{0x72}; 402 PMBusDriverDevice device{name, std::move(rails), services, bus, 403 address}; 404 405 MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface()); 406 EXPECT_CALL(pmbus, getPath(Type::Hwmon)) 407 .Times(1) 408 .WillOnce(Return(tempDirPath)); 409 EXPECT_CALL(pmbus, readString("in13_label", Type::Hwmon)) 410 .Times(1) 411 .WillOnce(Return("vout10")); // PAGE number 9 + 1 412 EXPECT_CALL(pmbus, readString("in13_input", Type::Hwmon)) 413 .Times(1) 414 .WillOnce(Return("851")); 415 416 uint8_t page{9}; 417 EXPECT_EQ(device.getReadVout(page), 0.851); 418 } 419 420 // Test where fails 421 { 422 // Create simulated hwmon voltage label file 423 createFile("in13_label"); // PAGE 8 -> file number 13 424 425 MockServices services; 426 427 std::string name{"xyz_pseq"}; 428 std::vector<std::unique_ptr<Rail>> rails; 429 uint8_t bus{3}; 430 uint16_t address{0x72}; 431 PMBusDriverDevice device{name, std::move(rails), services, bus, 432 address}; 433 434 MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface()); 435 EXPECT_CALL(pmbus, getPath(Type::Hwmon)) 436 .Times(1) 437 .WillOnce(Return(tempDirPath)); 438 EXPECT_CALL(pmbus, readString("in13_label", Type::Hwmon)) 439 .Times(1) 440 .WillOnce(Return("vout9")); // PAGE number 8 + 1 441 442 try 443 { 444 uint8_t page{9}; 445 device.getReadVout(page); 446 ADD_FAILURE() << "Should not have reached this line."; 447 } 448 catch (const std::exception& e) 449 { 450 EXPECT_STREQ( 451 e.what(), 452 "Unable to read READ_VOUT for PAGE 9 of device xyz_pseq: " 453 "Unable to find hwmon file number for PAGE 9 of device xyz_pseq"); 454 } 455 } 456 } 457 458 TEST_F(PMBusDriverDeviceTests, GetVoutUVFaultLimit) 459 { 460 // Test where works 461 { 462 // Create simulated hwmon voltage label file 463 createFile("in1_label"); // PAGE 6 -> file number 1 464 465 MockServices services; 466 467 std::string name{"xyz_pseq"}; 468 std::vector<std::unique_ptr<Rail>> rails; 469 uint8_t bus{3}; 470 uint16_t address{0x72}; 471 PMBusDriverDevice device{name, std::move(rails), services, bus, 472 address}; 473 474 MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface()); 475 EXPECT_CALL(pmbus, getPath(Type::Hwmon)) 476 .Times(1) 477 .WillOnce(Return(tempDirPath)); 478 EXPECT_CALL(pmbus, readString("in1_label", Type::Hwmon)) 479 .Times(1) 480 .WillOnce(Return("vout7")); // PAGE number 6 + 1 481 EXPECT_CALL(pmbus, readString("in1_lcrit", Type::Hwmon)) 482 .Times(1) 483 .WillOnce(Return("1329")); 484 485 uint8_t page{6}; 486 EXPECT_EQ(device.getVoutUVFaultLimit(page), 1.329); 487 } 488 489 // Test where fails 490 { 491 // Create simulated hwmon voltage label file 492 createFile("in1_label"); // PAGE 7 -> file number 1 493 494 MockServices services; 495 496 std::string name{"xyz_pseq"}; 497 std::vector<std::unique_ptr<Rail>> rails; 498 uint8_t bus{3}; 499 uint16_t address{0x72}; 500 PMBusDriverDevice device{name, std::move(rails), services, bus, 501 address}; 502 503 MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface()); 504 EXPECT_CALL(pmbus, getPath(Type::Hwmon)) 505 .Times(1) 506 .WillOnce(Return(tempDirPath)); 507 EXPECT_CALL(pmbus, readString("in1_label", Type::Hwmon)) 508 .Times(1) 509 .WillOnce(Return("vout8")); // PAGE number 7 + 1 510 511 try 512 { 513 uint8_t page{6}; 514 device.getVoutUVFaultLimit(page); 515 ADD_FAILURE() << "Should not have reached this line."; 516 } 517 catch (const std::exception& e) 518 { 519 EXPECT_STREQ( 520 e.what(), 521 "Unable to read VOUT_UV_FAULT_LIMIT for PAGE 6 of device xyz_pseq: " 522 "Unable to find hwmon file number for PAGE 6 of device xyz_pseq"); 523 } 524 } 525 } 526 527 TEST_F(PMBusDriverDeviceTests, GetPageToFileNumberMap) 528 { 529 // Test where works: No voltage label files/mappings found 530 { 531 // Create simulated hwmon files. None are valid voltage label files. 532 createFile("in1_input"); // Not a label file 533 createFile("in9_lcrit"); // Not a label file 534 createFile("in_label"); // Invalid voltage label file name 535 createFile("in9a_label"); // Invalid voltage label file name 536 createFile("fan3_label"); // Not a voltage label file 537 createFile("temp8_label"); // Not a voltage label file 538 539 MockServices services; 540 541 std::string name{"xyz_pseq"}; 542 std::vector<std::unique_ptr<Rail>> rails; 543 uint8_t bus{3}; 544 uint16_t address{0x72}; 545 PMBusDriverDevice device{name, std::move(rails), services, bus, 546 address}; 547 548 MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface()); 549 EXPECT_CALL(pmbus, getPath(Type::Hwmon)) 550 .Times(1) 551 .WillOnce(Return(tempDirPath)); 552 EXPECT_CALL(pmbus, readString).Times(0); 553 554 const std::map<uint8_t, unsigned int>& map = 555 device.getPageToFileNumberMap(); 556 EXPECT_TRUE(map.empty()); 557 } 558 559 // Test where works: Multiple voltage label files/mappings found 560 { 561 // Create simulated hwmon files 562 createFile("in9_label"); // PAGE 3 -> file number 9 563 createFile("in13_label"); // PAGE 7 -> file number 13 564 createFile("in0_label"); // PAGE 12 -> file number 0 565 createFile("in11_label"); // No mapping; invalid contents 566 createFile("in12_label"); // No mapping; invalid contents 567 createFile("in1_input"); // Not a label file 568 createFile("in7_lcrit"); // Not a label file 569 createFile("fan3_label"); // Not a voltage label file 570 createFile("temp8_label"); // Not a voltage label file 571 572 MockServices services; 573 574 std::string name{"xyz_pseq"}; 575 std::vector<std::unique_ptr<Rail>> rails; 576 uint8_t bus{3}; 577 uint16_t address{0x72}; 578 PMBusDriverDevice device{name, std::move(rails), services, bus, 579 address}; 580 581 MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface()); 582 EXPECT_CALL(pmbus, getPath(Type::Hwmon)) 583 .Times(1) 584 .WillOnce(Return(tempDirPath)); 585 EXPECT_CALL(pmbus, readString("in9_label", Type::Hwmon)) 586 .Times(1) 587 .WillOnce(Return("vout4")); // PAGE number 3 + 1 588 EXPECT_CALL(pmbus, readString("in13_label", Type::Hwmon)) 589 .Times(1) 590 .WillOnce(Return("vout8")); // PAGE number 7 + 1 591 EXPECT_CALL(pmbus, readString("in0_label", Type::Hwmon)) 592 .Times(1) 593 .WillOnce(Return("vout13")); // PAGE number 12 + 1 594 EXPECT_CALL(pmbus, readString("in11_label", Type::Hwmon)) 595 .Times(1) 596 .WillOnce(Return("vout")); // Invalid format 597 EXPECT_CALL(pmbus, readString("in12_label", Type::Hwmon)) 598 .Times(1) 599 .WillOnce(Return("vout13a")); // Invalid format 600 601 const std::map<uint8_t, unsigned int>& map = 602 device.getPageToFileNumberMap(); 603 EXPECT_EQ(map.size(), 3); 604 EXPECT_EQ(map.at(uint8_t{3}), 9); 605 EXPECT_EQ(map.at(uint8_t{7}), 13); 606 EXPECT_EQ(map.at(uint8_t{12}), 0); 607 } 608 609 // Test where fails: hwmon directory path is actually a file 610 { 611 // Create file that will be returned as the hwmon directory path 612 createFile("in9_label"); 613 614 MockServices services; 615 616 std::string name{"xyz_pseq"}; 617 std::vector<std::unique_ptr<Rail>> rails; 618 uint8_t bus{3}; 619 uint16_t address{0x72}; 620 PMBusDriverDevice device{name, std::move(rails), services, bus, 621 address}; 622 623 MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface()); 624 EXPECT_CALL(pmbus, getPath(Type::Hwmon)) 625 .Times(1) 626 .WillOnce(Return(tempDirPath / "in9_label")); 627 EXPECT_CALL(pmbus, readString).Times(0); 628 629 const std::map<uint8_t, unsigned int>& map = 630 device.getPageToFileNumberMap(); 631 EXPECT_TRUE(map.empty()); 632 } 633 634 // Test where fails: hwmon directory path does not exist 635 { 636 MockServices services; 637 638 std::string name{"xyz_pseq"}; 639 std::vector<std::unique_ptr<Rail>> rails; 640 uint8_t bus{3}; 641 uint16_t address{0x72}; 642 PMBusDriverDevice device{name, std::move(rails), services, bus, 643 address}; 644 645 MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface()); 646 EXPECT_CALL(pmbus, getPath(Type::Hwmon)) 647 .Times(1) 648 .WillOnce(Return(tempDirPath / "does_not_exist")); 649 EXPECT_CALL(pmbus, readString).Times(0); 650 651 const std::map<uint8_t, unsigned int>& map = 652 device.getPageToFileNumberMap(); 653 EXPECT_TRUE(map.empty()); 654 } 655 656 // Test where fails: hwmon directory path is not readable 657 { 658 // Create simulated hwmon files 659 createFile("in9_label"); 660 createFile("in13_label"); 661 createFile("in0_label"); 662 663 // Change temporary directory to be unreadable 664 fs::permissions(tempDirPath, fs::perms::none); 665 666 MockServices services; 667 668 std::string name{"xyz_pseq"}; 669 std::vector<std::unique_ptr<Rail>> rails; 670 uint8_t bus{3}; 671 uint16_t address{0x72}; 672 PMBusDriverDevice device{name, std::move(rails), services, bus, 673 address}; 674 675 MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface()); 676 EXPECT_CALL(pmbus, getPath(Type::Hwmon)) 677 .Times(1) 678 .WillOnce(Return(tempDirPath)); 679 EXPECT_CALL(pmbus, readString).Times(0); 680 681 try 682 { 683 device.getPageToFileNumberMap(); 684 ADD_FAILURE() << "Should not have reached this line."; 685 } 686 catch (const std::exception& e) 687 { 688 // Error message varies 689 } 690 691 // Change temporary directory to be readable/writable 692 fs::permissions(tempDirPath, fs::perms::owner_all); 693 } 694 } 695 696 TEST_F(PMBusDriverDeviceTests, GetFileNumber) 697 { 698 // Test where works 699 { 700 // Create simulated hwmon voltage label files 701 createFile("in0_label"); // PAGE 6 -> file number 0 702 createFile("in13_label"); // PAGE 9 -> file number 13 703 704 MockServices services; 705 706 std::string name{"xyz_pseq"}; 707 std::vector<std::unique_ptr<Rail>> rails; 708 uint8_t bus{3}; 709 uint16_t address{0x72}; 710 PMBusDriverDevice device{name, std::move(rails), services, bus, 711 address}; 712 713 MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface()); 714 EXPECT_CALL(pmbus, getPath(Type::Hwmon)) 715 .Times(1) 716 .WillOnce(Return(tempDirPath)); 717 EXPECT_CALL(pmbus, readString("in0_label", Type::Hwmon)) 718 .Times(1) 719 .WillOnce(Return("vout7")); // PAGE number 6 + 1 720 EXPECT_CALL(pmbus, readString("in13_label", Type::Hwmon)) 721 .Times(1) 722 .WillOnce(Return("vout10")); // PAGE number 9 + 1 723 724 // Map was empty and needs to be built 725 uint8_t page{6}; 726 EXPECT_EQ(device.getFileNumber(page), 0); 727 728 // Map had already been built 729 page = 9; 730 EXPECT_EQ(device.getFileNumber(page), 13); 731 } 732 733 // Test where fails: No mapping for specified PMBus PAGE 734 { 735 // Create simulated hwmon voltage label files 736 createFile("in0_label"); // PAGE 6 -> file number 0 737 createFile("in13_label"); // PAGE 9 -> file number 13 738 739 MockServices services; 740 741 std::string name{"xyz_pseq"}; 742 std::vector<std::unique_ptr<Rail>> rails; 743 uint8_t bus{3}; 744 uint16_t address{0x72}; 745 PMBusDriverDevice device{name, std::move(rails), services, bus, 746 address}; 747 748 MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface()); 749 EXPECT_CALL(pmbus, getPath(Type::Hwmon)) 750 .Times(1) 751 .WillOnce(Return(tempDirPath)); 752 EXPECT_CALL(pmbus, readString("in0_label", Type::Hwmon)) 753 .Times(1) 754 .WillOnce(Return("vout7")); // PAGE number 6 + 1 755 EXPECT_CALL(pmbus, readString("in13_label", Type::Hwmon)) 756 .Times(1) 757 .WillOnce(Return("vout10")); // PAGE number 9 + 1 758 759 try 760 { 761 uint8_t page{13}; 762 device.getFileNumber(page); 763 ADD_FAILURE() << "Should not have reached this line."; 764 } 765 catch (const std::exception& e) 766 { 767 EXPECT_STREQ( 768 e.what(), 769 "Unable to find hwmon file number for PAGE 13 of device xyz_pseq"); 770 } 771 } 772 } 773 774 TEST_F(PMBusDriverDeviceTests, PrepareForPgoodFaultDetection) 775 { 776 // This is a protected method and cannot be called directly from a gtest. 777 // Call findPgoodFault() which calls prepareForPgoodFaultDetection(). 778 779 // Create simulated hwmon voltage label file 780 createFile("in1_label"); // PAGE 6 -> file number 1 781 782 MockServices services; 783 std::vector<int> gpioValues{1, 1, 1}; 784 EXPECT_CALL(services, getGPIOValues("xyz_pseq")) 785 .Times(1) 786 .WillOnce(Return(gpioValues)); 787 788 std::string name{"xyz_pseq"}; 789 std::vector<std::unique_ptr<Rail>> rails; 790 uint8_t bus{3}; 791 uint16_t address{0x72}; 792 PMBusDriverDevice device{name, std::move(rails), services, bus, address}; 793 794 // Methods that get hwmon file info should be called twice 795 MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface()); 796 EXPECT_CALL(pmbus, getPath(Type::Hwmon)) 797 .Times(2) 798 .WillRepeatedly(Return(tempDirPath)); 799 EXPECT_CALL(pmbus, readString("in1_label", Type::Hwmon)) 800 .Times(2) 801 .WillRepeatedly(Return("vout7")); // PAGE number 6 + 1 802 803 // Map was empty and needs to be built 804 uint8_t page{6}; 805 EXPECT_EQ(device.getFileNumber(page), 1); 806 807 // Call findPgoodFault() which calls prepareForPgoodFaultDetection() which 808 // rebuilds the map. 809 std::string powerSupplyError{}; 810 std::map<std::string, std::string> additionalData{}; 811 std::string error = device.findPgoodFault(services, powerSupplyError, 812 additionalData); 813 EXPECT_TRUE(error.empty()); 814 EXPECT_EQ(additionalData.size(), 0); 815 816 EXPECT_EQ(device.getFileNumber(page), 1); 817 } 818