blob: 92f7916b24ae98eb7daf28f7c261b1993901328d [file] [log] [blame]
/**
* Copyright © 2024 IBM Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "mock_pmbus.hpp"
#include "mock_services.hpp"
#include "pmbus.hpp"
#include "pmbus_driver_device.hpp"
#include "rail.hpp"
#include "services.hpp"
#include <errno.h>
#include <stdlib.h> // for mkdtemp()
#include <cstdint>
#include <exception>
#include <filesystem>
#include <format>
#include <fstream>
#include <map>
#include <memory>
#include <optional>
#include <stdexcept>
#include <string>
#include <utility>
#include <vector>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
using namespace phosphor::power::sequencer;
using namespace phosphor::pmbus;
using ::testing::Return;
using ::testing::Throw;
class PMBusDriverDeviceTests : public ::testing::Test
{
protected:
/**
* Constructor.
*
* Creates a temporary directory to use in simulating sysfs files.
*/
PMBusDriverDeviceTests() : ::testing::Test{}
{
char pathTemplate[] = "/tmp/pmbus_driver_device_testsXXXXXX";
char* retVal = mkdtemp(pathTemplate);
if (retVal == nullptr)
{
throw std::runtime_error{std::format(
"Unable to create temporary directory: errno={}", errno)};
}
tempDir = fs::path{pathTemplate};
}
/**
* Destructor.
*
* Deletes the temporary directory created in the constructor.
*/
virtual ~PMBusDriverDeviceTests()
{
try
{
if (!tempDir.empty() && fs::exists(tempDir))
{
fs::remove_all(tempDir);
}
}
catch (...)
{
// Destructors must not throw exceptions
}
}
/**
* Creates a Rail object that checks for a pgood fault using STATUS_VOUT.
*
* @param name Unique name for the rail
* @param pageNum PMBus PAGE number of the rail
* @return Rail object
*/
std::unique_ptr<Rail> createRail(const std::string& name, uint8_t pageNum)
{
std::optional<std::string> presence{};
std::optional<uint8_t> page{pageNum};
bool isPowerSupplyRail{false};
bool checkStatusVout{true};
bool compareVoltageToLimit{false};
std::optional<GPIO> gpio{};
return std::make_unique<Rail>(name, presence, page, isPowerSupplyRail,
checkStatusVout, compareVoltageToLimit,
gpio);
}
/**
* Creates a file with the specified contents within the temporary
* directory.
*
* @param name File name
* @param contents File contents
*/
void createFile(const std::string& name, const std::string& contents = "")
{
fs::path path{tempDir / name};
std::ofstream out{path};
out << contents;
out.close();
}
/**
* Temporary directory that is used to create simulated sysfs / hmmon files.
*/
fs::path tempDir{};
};
TEST_F(PMBusDriverDeviceTests, Constructor)
{
// Test where works; optional parameters not specified
{
MockServices services;
std::string name{"XYZ_PSEQ"};
std::vector<std::unique_ptr<Rail>> rails;
rails.emplace_back(createRail("VDD", 5));
rails.emplace_back(createRail("VIO", 7));
uint8_t bus{3};
uint16_t address{0x72};
PMBusDriverDevice device{name, std::move(rails), services, bus,
address};
EXPECT_EQ(device.getName(), name);
EXPECT_EQ(device.getRails().size(), 2);
EXPECT_EQ(device.getRails()[0]->getName(), "VDD");
EXPECT_EQ(device.getRails()[1]->getName(), "VIO");
EXPECT_EQ(device.getBus(), bus);
EXPECT_EQ(device.getAddress(), address);
EXPECT_EQ(device.getDriverName(), "");
EXPECT_EQ(device.getInstance(), 0);
EXPECT_NE(&(device.getPMBusInterface()), nullptr);
}
// Test where works; optional parameters specified
{
MockServices services;
std::string name{"XYZ_PSEQ"};
std::vector<std::unique_ptr<Rail>> rails;
rails.emplace_back(createRail("VDD", 5));
rails.emplace_back(createRail("VIO", 7));
uint8_t bus{3};
uint16_t address{0x72};
std::string driverName{"xyzdev"};
size_t instance{3};
PMBusDriverDevice device{name, std::move(rails), services, bus,
address, driverName, instance};
EXPECT_EQ(device.getName(), name);
EXPECT_EQ(device.getRails().size(), 2);
EXPECT_EQ(device.getRails()[0]->getName(), "VDD");
EXPECT_EQ(device.getRails()[1]->getName(), "VIO");
EXPECT_EQ(device.getBus(), bus);
EXPECT_EQ(device.getAddress(), address);
EXPECT_EQ(device.getDriverName(), driverName);
EXPECT_EQ(device.getInstance(), instance);
EXPECT_NE(&(device.getPMBusInterface()), nullptr);
}
}
TEST_F(PMBusDriverDeviceTests, GetBus)
{
MockServices services;
std::string name{"XYZ_PSEQ"};
std::vector<std::unique_ptr<Rail>> rails;
uint8_t bus{4};
uint16_t address{0x72};
PMBusDriverDevice device{name, std::move(rails), services, bus, address};
EXPECT_EQ(device.getBus(), bus);
}
TEST_F(PMBusDriverDeviceTests, GetAddress)
{
MockServices services;
std::string name{"XYZ_PSEQ"};
std::vector<std::unique_ptr<Rail>> rails;
uint8_t bus{3};
uint16_t address{0xab};
PMBusDriverDevice device{name, std::move(rails), services, bus, address};
EXPECT_EQ(device.getAddress(), address);
}
TEST_F(PMBusDriverDeviceTests, GetDriverName)
{
MockServices services;
std::string name{"XYZ_PSEQ"};
std::vector<std::unique_ptr<Rail>> rails;
uint8_t bus{3};
uint16_t address{0x72};
std::string driverName{"xyzdev"};
PMBusDriverDevice device{name, std::move(rails), services,
bus, address, driverName};
EXPECT_EQ(device.getDriverName(), driverName);
}
TEST_F(PMBusDriverDeviceTests, GetInstance)
{
MockServices services;
std::string name{"XYZ_PSEQ"};
std::vector<std::unique_ptr<Rail>> rails;
uint8_t bus{3};
uint16_t address{0x72};
std::string driverName{"xyzdev"};
size_t instance{3};
PMBusDriverDevice device{name, std::move(rails), services, bus,
address, driverName, instance};
EXPECT_EQ(device.getInstance(), instance);
}
TEST_F(PMBusDriverDeviceTests, GetPMBusInterface)
{
MockServices services;
std::string name{"XYZ_PSEQ"};
std::vector<std::unique_ptr<Rail>> rails;
uint8_t bus{3};
uint16_t address{0x72};
PMBusDriverDevice device{name, std::move(rails), services, bus, address};
EXPECT_NE(&(device.getPMBusInterface()), nullptr);
}
TEST_F(PMBusDriverDeviceTests, GetGPIOValues)
{
// Test where works
{
MockServices services;
std::vector<int> gpioValues{1, 1, 1};
EXPECT_CALL(services, getGPIOValues("abc_382%#, zy"))
.Times(1)
.WillOnce(Return(gpioValues));
std::string name{"ABC_382%#, ZY"};
std::vector<std::unique_ptr<Rail>> rails;
uint8_t bus{3};
uint16_t address{0x72};
PMBusDriverDevice device{name, std::move(rails), services, bus,
address};
EXPECT_TRUE(device.getGPIOValues(services) == gpioValues);
}
// Test where fails with exception
{
MockServices services;
EXPECT_CALL(services, getGPIOValues("xyz_pseq"))
.Times(1)
.WillOnce(
Throw(std::runtime_error{"libgpiod: Unable to open chip"}));
std::string name{"XYZ_PSEQ"};
std::vector<std::unique_ptr<Rail>> rails;
uint8_t bus{3};
uint16_t address{0x72};
PMBusDriverDevice device{name, std::move(rails), services, bus,
address};
try
{
device.getGPIOValues(services);
ADD_FAILURE() << "Should not have reached this line.";
}
catch (const std::exception& e)
{
EXPECT_STREQ(e.what(),
"Unable to read GPIO values from device XYZ_PSEQ "
"using label xyz_pseq: "
"libgpiod: Unable to open chip");
}
}
}
TEST_F(PMBusDriverDeviceTests, GetStatusWord)
{
// Test where works
{
MockServices services;
std::string name{"xyz_pseq"};
std::vector<std::unique_ptr<Rail>> rails;
uint8_t bus{3};
uint16_t address{0x72};
PMBusDriverDevice device{name, std::move(rails), services, bus,
address};
MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface());
EXPECT_CALL(pmbus, read("status13", Type::Debug, true))
.Times(1)
.WillOnce(Return(0x1234));
uint8_t page{13};
EXPECT_EQ(device.getStatusWord(page), 0x1234);
}
// Test where fails with exception
{
MockServices services;
std::string name{"xyz_pseq"};
std::vector<std::unique_ptr<Rail>> rails;
uint8_t bus{3};
uint16_t address{0x72};
PMBusDriverDevice device{name, std::move(rails), services, bus,
address};
MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface());
EXPECT_CALL(pmbus, read("status0", Type::Debug, true))
.Times(1)
.WillOnce(Throw(std::runtime_error{"File does not exist"}));
try
{
uint8_t page{0};
device.getStatusWord(page);
ADD_FAILURE() << "Should not have reached this line.";
}
catch (const std::exception& e)
{
EXPECT_STREQ(
e.what(),
"Unable to read STATUS_WORD for PAGE 0 of device xyz_pseq: "
"File does not exist");
}
}
}
TEST_F(PMBusDriverDeviceTests, GetStatusVout)
{
// Test where works
{
MockServices services;
std::string name{"xyz_pseq"};
std::vector<std::unique_ptr<Rail>> rails;
uint8_t bus{3};
uint16_t address{0x72};
PMBusDriverDevice device{name, std::move(rails), services, bus,
address};
MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface());
EXPECT_CALL(pmbus, read("status13_vout", Type::Debug, true))
.Times(1)
.WillOnce(Return(0xde));
uint8_t page{13};
EXPECT_EQ(device.getStatusVout(page), 0xde);
}
// Test where fails with exception
{
MockServices services;
std::string name{"xyz_pseq"};
std::vector<std::unique_ptr<Rail>> rails;
uint8_t bus{3};
uint16_t address{0x72};
PMBusDriverDevice device{name, std::move(rails), services, bus,
address};
MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface());
EXPECT_CALL(pmbus, read("status0_vout", Type::Debug, true))
.Times(1)
.WillOnce(Throw(std::runtime_error{"File does not exist"}));
try
{
uint8_t page{0};
device.getStatusVout(page);
ADD_FAILURE() << "Should not have reached this line.";
}
catch (const std::exception& e)
{
EXPECT_STREQ(
e.what(),
"Unable to read STATUS_VOUT for PAGE 0 of device xyz_pseq: "
"File does not exist");
}
}
}
TEST_F(PMBusDriverDeviceTests, GetReadVout)
{
// Test where works
{
// Create simulated hwmon voltage label file
createFile("in13_label"); // PAGE 9 -> file number 13
MockServices services;
std::string name{"xyz_pseq"};
std::vector<std::unique_ptr<Rail>> rails;
uint8_t bus{3};
uint16_t address{0x72};
PMBusDriverDevice device{name, std::move(rails), services, bus,
address};
MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface());
EXPECT_CALL(pmbus, getPath(Type::Hwmon))
.Times(1)
.WillOnce(Return(tempDir));
EXPECT_CALL(pmbus, readString("in13_label", Type::Hwmon))
.Times(1)
.WillOnce(Return("vout10")); // PAGE number 9 + 1
EXPECT_CALL(pmbus, readString("in13_input", Type::Hwmon))
.Times(1)
.WillOnce(Return("851"));
uint8_t page{9};
EXPECT_EQ(device.getReadVout(page), 0.851);
}
// Test where fails
{
// Create simulated hwmon voltage label file
createFile("in13_label"); // PAGE 8 -> file number 13
MockServices services;
std::string name{"xyz_pseq"};
std::vector<std::unique_ptr<Rail>> rails;
uint8_t bus{3};
uint16_t address{0x72};
PMBusDriverDevice device{name, std::move(rails), services, bus,
address};
MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface());
EXPECT_CALL(pmbus, getPath(Type::Hwmon))
.Times(1)
.WillOnce(Return(tempDir));
EXPECT_CALL(pmbus, readString("in13_label", Type::Hwmon))
.Times(1)
.WillOnce(Return("vout9")); // PAGE number 8 + 1
try
{
uint8_t page{9};
device.getReadVout(page);
ADD_FAILURE() << "Should not have reached this line.";
}
catch (const std::exception& e)
{
EXPECT_STREQ(
e.what(),
"Unable to read READ_VOUT for PAGE 9 of device xyz_pseq: "
"Unable to find hwmon file number for PAGE 9 of device xyz_pseq");
}
}
}
TEST_F(PMBusDriverDeviceTests, GetVoutUVFaultLimit)
{
// Test where works
{
// Create simulated hwmon voltage label file
createFile("in1_label"); // PAGE 6 -> file number 1
MockServices services;
std::string name{"xyz_pseq"};
std::vector<std::unique_ptr<Rail>> rails;
uint8_t bus{3};
uint16_t address{0x72};
PMBusDriverDevice device{name, std::move(rails), services, bus,
address};
MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface());
EXPECT_CALL(pmbus, getPath(Type::Hwmon))
.Times(1)
.WillOnce(Return(tempDir));
EXPECT_CALL(pmbus, readString("in1_label", Type::Hwmon))
.Times(1)
.WillOnce(Return("vout7")); // PAGE number 6 + 1
EXPECT_CALL(pmbus, readString("in1_lcrit", Type::Hwmon))
.Times(1)
.WillOnce(Return("1329"));
uint8_t page{6};
EXPECT_EQ(device.getVoutUVFaultLimit(page), 1.329);
}
// Test where fails
{
// Create simulated hwmon voltage label file
createFile("in1_label"); // PAGE 7 -> file number 1
MockServices services;
std::string name{"xyz_pseq"};
std::vector<std::unique_ptr<Rail>> rails;
uint8_t bus{3};
uint16_t address{0x72};
PMBusDriverDevice device{name, std::move(rails), services, bus,
address};
MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface());
EXPECT_CALL(pmbus, getPath(Type::Hwmon))
.Times(1)
.WillOnce(Return(tempDir));
EXPECT_CALL(pmbus, readString("in1_label", Type::Hwmon))
.Times(1)
.WillOnce(Return("vout8")); // PAGE number 7 + 1
try
{
uint8_t page{6};
device.getVoutUVFaultLimit(page);
ADD_FAILURE() << "Should not have reached this line.";
}
catch (const std::exception& e)
{
EXPECT_STREQ(
e.what(),
"Unable to read VOUT_UV_FAULT_LIMIT for PAGE 6 of device xyz_pseq: "
"Unable to find hwmon file number for PAGE 6 of device xyz_pseq");
}
}
}
TEST_F(PMBusDriverDeviceTests, GetPageToFileNumberMap)
{
// Test where works: No voltage label files/mappings found
{
// Create simulated hwmon files. None are valid voltage label files.
createFile("in1_input"); // Not a label file
createFile("in9_lcrit"); // Not a label file
createFile("in_label"); // Invalid voltage label file name
createFile("in9a_label"); // Invalid voltage label file name
createFile("fan3_label"); // Not a voltage label file
createFile("temp8_label"); // Not a voltage label file
MockServices services;
std::string name{"xyz_pseq"};
std::vector<std::unique_ptr<Rail>> rails;
uint8_t bus{3};
uint16_t address{0x72};
PMBusDriverDevice device{name, std::move(rails), services, bus,
address};
MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface());
EXPECT_CALL(pmbus, getPath(Type::Hwmon))
.Times(1)
.WillOnce(Return(tempDir));
EXPECT_CALL(pmbus, readString).Times(0);
const std::map<uint8_t, unsigned int>& map =
device.getPageToFileNumberMap();
EXPECT_TRUE(map.empty());
}
// Test where works: Multiple voltage label files/mappings found
{
// Create simulated hwmon files
createFile("in9_label"); // PAGE 3 -> file number 9
createFile("in13_label"); // PAGE 7 -> file number 13
createFile("in0_label"); // PAGE 12 -> file number 0
createFile("in11_label"); // No mapping; invalid contents
createFile("in12_label"); // No mapping; invalid contents
createFile("in1_input"); // Not a label file
createFile("in7_lcrit"); // Not a label file
createFile("fan3_label"); // Not a voltage label file
createFile("temp8_label"); // Not a voltage label file
MockServices services;
std::string name{"xyz_pseq"};
std::vector<std::unique_ptr<Rail>> rails;
uint8_t bus{3};
uint16_t address{0x72};
PMBusDriverDevice device{name, std::move(rails), services, bus,
address};
MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface());
EXPECT_CALL(pmbus, getPath(Type::Hwmon))
.Times(1)
.WillOnce(Return(tempDir));
EXPECT_CALL(pmbus, readString("in9_label", Type::Hwmon))
.Times(1)
.WillOnce(Return("vout4")); // PAGE number 3 + 1
EXPECT_CALL(pmbus, readString("in13_label", Type::Hwmon))
.Times(1)
.WillOnce(Return("vout8")); // PAGE number 7 + 1
EXPECT_CALL(pmbus, readString("in0_label", Type::Hwmon))
.Times(1)
.WillOnce(Return("vout13")); // PAGE number 12 + 1
EXPECT_CALL(pmbus, readString("in11_label", Type::Hwmon))
.Times(1)
.WillOnce(Return("vout")); // Invalid format
EXPECT_CALL(pmbus, readString("in12_label", Type::Hwmon))
.Times(1)
.WillOnce(Return("vout13a")); // Invalid format
const std::map<uint8_t, unsigned int>& map =
device.getPageToFileNumberMap();
EXPECT_EQ(map.size(), 3);
EXPECT_EQ(map.at(uint8_t{3}), 9);
EXPECT_EQ(map.at(uint8_t{7}), 13);
EXPECT_EQ(map.at(uint8_t{12}), 0);
}
// Test where fails: hwmon directory path is actually a file
{
// Create file that will be returned as the hwmon directory path
createFile("in9_label");
MockServices services;
std::string name{"xyz_pseq"};
std::vector<std::unique_ptr<Rail>> rails;
uint8_t bus{3};
uint16_t address{0x72};
PMBusDriverDevice device{name, std::move(rails), services, bus,
address};
MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface());
EXPECT_CALL(pmbus, getPath(Type::Hwmon))
.Times(1)
.WillOnce(Return(tempDir / "in9_label"));
EXPECT_CALL(pmbus, readString).Times(0);
const std::map<uint8_t, unsigned int>& map =
device.getPageToFileNumberMap();
EXPECT_TRUE(map.empty());
}
// Test where fails: hwmon directory path does not exist
{
MockServices services;
std::string name{"xyz_pseq"};
std::vector<std::unique_ptr<Rail>> rails;
uint8_t bus{3};
uint16_t address{0x72};
PMBusDriverDevice device{name, std::move(rails), services, bus,
address};
MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface());
EXPECT_CALL(pmbus, getPath(Type::Hwmon))
.Times(1)
.WillOnce(Return(tempDir / "does_not_exist"));
EXPECT_CALL(pmbus, readString).Times(0);
const std::map<uint8_t, unsigned int>& map =
device.getPageToFileNumberMap();
EXPECT_TRUE(map.empty());
}
// Test where fails: hwmon directory path is not readable
{
// Create simulated hwmon files
createFile("in9_label");
createFile("in13_label");
createFile("in0_label");
// Change temporary directory to be unreadable
fs::permissions(tempDir, fs::perms::none);
MockServices services;
std::string name{"xyz_pseq"};
std::vector<std::unique_ptr<Rail>> rails;
uint8_t bus{3};
uint16_t address{0x72};
PMBusDriverDevice device{name, std::move(rails), services, bus,
address};
MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface());
EXPECT_CALL(pmbus, getPath(Type::Hwmon))
.Times(1)
.WillOnce(Return(tempDir));
EXPECT_CALL(pmbus, readString).Times(0);
try
{
device.getPageToFileNumberMap();
ADD_FAILURE() << "Should not have reached this line.";
}
catch (const std::exception& e)
{
// Error message varies
}
// Change temporary directory to be readable/writable
fs::permissions(tempDir, fs::perms::owner_all);
}
}
TEST_F(PMBusDriverDeviceTests, GetFileNumber)
{
// Test where works
{
// Create simulated hwmon voltage label files
createFile("in0_label"); // PAGE 6 -> file number 0
createFile("in13_label"); // PAGE 9 -> file number 13
MockServices services;
std::string name{"xyz_pseq"};
std::vector<std::unique_ptr<Rail>> rails;
uint8_t bus{3};
uint16_t address{0x72};
PMBusDriverDevice device{name, std::move(rails), services, bus,
address};
MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface());
EXPECT_CALL(pmbus, getPath(Type::Hwmon))
.Times(1)
.WillOnce(Return(tempDir));
EXPECT_CALL(pmbus, readString("in0_label", Type::Hwmon))
.Times(1)
.WillOnce(Return("vout7")); // PAGE number 6 + 1
EXPECT_CALL(pmbus, readString("in13_label", Type::Hwmon))
.Times(1)
.WillOnce(Return("vout10")); // PAGE number 9 + 1
// Map was empty and needs to be built
uint8_t page{6};
EXPECT_EQ(device.getFileNumber(page), 0);
// Map had already been built
page = 9;
EXPECT_EQ(device.getFileNumber(page), 13);
}
// Test where fails: No mapping for specified PMBus PAGE
{
// Create simulated hwmon voltage label files
createFile("in0_label"); // PAGE 6 -> file number 0
createFile("in13_label"); // PAGE 9 -> file number 13
MockServices services;
std::string name{"xyz_pseq"};
std::vector<std::unique_ptr<Rail>> rails;
uint8_t bus{3};
uint16_t address{0x72};
PMBusDriverDevice device{name, std::move(rails), services, bus,
address};
MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface());
EXPECT_CALL(pmbus, getPath(Type::Hwmon))
.Times(1)
.WillOnce(Return(tempDir));
EXPECT_CALL(pmbus, readString("in0_label", Type::Hwmon))
.Times(1)
.WillOnce(Return("vout7")); // PAGE number 6 + 1
EXPECT_CALL(pmbus, readString("in13_label", Type::Hwmon))
.Times(1)
.WillOnce(Return("vout10")); // PAGE number 9 + 1
try
{
uint8_t page{13};
device.getFileNumber(page);
ADD_FAILURE() << "Should not have reached this line.";
}
catch (const std::exception& e)
{
EXPECT_STREQ(
e.what(),
"Unable to find hwmon file number for PAGE 13 of device xyz_pseq");
}
}
}
TEST_F(PMBusDriverDeviceTests, PrepareForPgoodFaultDetection)
{
// This is a protected method and cannot be called directly from a gtest.
// Call findPgoodFault() which calls prepareForPgoodFaultDetection().
// Create simulated hwmon voltage label file
createFile("in1_label"); // PAGE 6 -> file number 1
MockServices services;
std::vector<int> gpioValues{1, 1, 1};
EXPECT_CALL(services, getGPIOValues("xyz_pseq"))
.Times(1)
.WillOnce(Return(gpioValues));
std::string name{"xyz_pseq"};
std::vector<std::unique_ptr<Rail>> rails;
uint8_t bus{3};
uint16_t address{0x72};
PMBusDriverDevice device{name, std::move(rails), services, bus, address};
// Methods that get hwmon file info should be called twice
MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface());
EXPECT_CALL(pmbus, getPath(Type::Hwmon))
.Times(2)
.WillRepeatedly(Return(tempDir));
EXPECT_CALL(pmbus, readString("in1_label", Type::Hwmon))
.Times(2)
.WillRepeatedly(Return("vout7")); // PAGE number 6 + 1
// Map was empty and needs to be built
uint8_t page{6};
EXPECT_EQ(device.getFileNumber(page), 1);
// Call findPgoodFault() which calls prepareForPgoodFaultDetection() which
// rebuilds the map.
std::string powerSupplyError{};
std::map<std::string, std::string> additionalData{};
std::string error = device.findPgoodFault(services, powerSupplyError,
additionalData);
EXPECT_TRUE(error.empty());
EXPECT_EQ(additionalData.size(), 0);
EXPECT_EQ(device.getFileNumber(page), 1);
}