171d7fe43SShawn McCarney /**
271d7fe43SShawn McCarney * Copyright © 2024 IBM Corporation
371d7fe43SShawn McCarney *
471d7fe43SShawn McCarney * Licensed under the Apache License, Version 2.0 (the "License");
571d7fe43SShawn McCarney * you may not use this file except in compliance with the License.
671d7fe43SShawn McCarney * You may obtain a copy of the License at
771d7fe43SShawn McCarney *
871d7fe43SShawn McCarney * http://www.apache.org/licenses/LICENSE-2.0
971d7fe43SShawn McCarney *
1071d7fe43SShawn McCarney * Unless required by applicable law or agreed to in writing, software
1171d7fe43SShawn McCarney * distributed under the License is distributed on an "AS IS" BASIS,
1271d7fe43SShawn McCarney * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1371d7fe43SShawn McCarney * See the License for the specific language governing permissions and
1471d7fe43SShawn McCarney * limitations under the License.
1571d7fe43SShawn McCarney */
1671d7fe43SShawn McCarney
1771d7fe43SShawn McCarney #include "mock_pmbus.hpp"
1871d7fe43SShawn McCarney #include "mock_services.hpp"
1971d7fe43SShawn McCarney #include "pmbus.hpp"
2071d7fe43SShawn McCarney #include "rail.hpp"
2171d7fe43SShawn McCarney #include "services.hpp"
2271d7fe43SShawn McCarney #include "ucd90x_device.hpp"
2371d7fe43SShawn McCarney
2471d7fe43SShawn McCarney #include <cstdint>
2571d7fe43SShawn McCarney #include <exception>
2671d7fe43SShawn McCarney #include <map>
2771d7fe43SShawn McCarney #include <memory>
2871d7fe43SShawn McCarney #include <optional>
2971d7fe43SShawn McCarney #include <string>
3071d7fe43SShawn McCarney #include <utility>
3171d7fe43SShawn McCarney #include <vector>
3271d7fe43SShawn McCarney
3371d7fe43SShawn McCarney #include <gmock/gmock.h>
3471d7fe43SShawn McCarney #include <gtest/gtest.h>
3571d7fe43SShawn McCarney
3671d7fe43SShawn McCarney using namespace phosphor::power::sequencer;
3771d7fe43SShawn McCarney using namespace phosphor::pmbus;
3871d7fe43SShawn McCarney
3971d7fe43SShawn McCarney using ::testing::Return;
4071d7fe43SShawn McCarney using ::testing::Throw;
4171d7fe43SShawn McCarney
4271d7fe43SShawn McCarney /**
4371d7fe43SShawn McCarney * Creates a Rail object that checks for a pgood fault using a GPIO.
4471d7fe43SShawn McCarney *
4571d7fe43SShawn McCarney * @param name Unique name for the rail
4671d7fe43SShawn McCarney * @param gpio GPIO line to read to determine the pgood status of the rail
4771d7fe43SShawn McCarney * @return Rail object
4871d7fe43SShawn McCarney */
createRail(const std::string & name,unsigned int gpioLine)49fec38334SShawn McCarney static std::unique_ptr<Rail> createRail(const std::string& name,
50fec38334SShawn McCarney unsigned int gpioLine)
5171d7fe43SShawn McCarney {
5271d7fe43SShawn McCarney std::optional<std::string> presence{};
5371d7fe43SShawn McCarney std::optional<uint8_t> page{};
5471d7fe43SShawn McCarney bool isPowerSupplyRail{false};
5571d7fe43SShawn McCarney bool checkStatusVout{false};
5671d7fe43SShawn McCarney bool compareVoltageToLimit{false};
5771d7fe43SShawn McCarney bool activeLow{false};
5871d7fe43SShawn McCarney std::optional<GPIO> gpio{GPIO{gpioLine, activeLow}};
5971d7fe43SShawn McCarney return std::make_unique<Rail>(name, presence, page, isPowerSupplyRail,
6071d7fe43SShawn McCarney checkStatusVout, compareVoltageToLimit, gpio);
6171d7fe43SShawn McCarney }
6271d7fe43SShawn McCarney
TEST(UCD90xDeviceTests,Constructor)6371d7fe43SShawn McCarney TEST(UCD90xDeviceTests, Constructor)
6471d7fe43SShawn McCarney {
6571d7fe43SShawn McCarney MockServices services;
6671d7fe43SShawn McCarney
6771d7fe43SShawn McCarney std::string name{"ucd90320"};
6871d7fe43SShawn McCarney std::vector<std::unique_ptr<Rail>> rails;
6971d7fe43SShawn McCarney rails.emplace_back(createRail("VDD", 5));
7071d7fe43SShawn McCarney rails.emplace_back(createRail("VIO", 7));
7171d7fe43SShawn McCarney uint8_t bus{3};
7271d7fe43SShawn McCarney uint16_t address{0x72};
7371d7fe43SShawn McCarney UCD90xDevice device{name, std::move(rails), services, bus, address};
7471d7fe43SShawn McCarney
7571d7fe43SShawn McCarney EXPECT_EQ(device.getName(), name);
7671d7fe43SShawn McCarney EXPECT_EQ(device.getRails().size(), 2);
7771d7fe43SShawn McCarney EXPECT_EQ(device.getRails()[0]->getName(), "VDD");
7871d7fe43SShawn McCarney EXPECT_EQ(device.getRails()[1]->getName(), "VIO");
7971d7fe43SShawn McCarney EXPECT_EQ(device.getBus(), bus);
8071d7fe43SShawn McCarney EXPECT_EQ(device.getAddress(), address);
8171d7fe43SShawn McCarney EXPECT_EQ(device.getDriverName(), "ucd9000");
8271d7fe43SShawn McCarney EXPECT_EQ(device.getInstance(), 0);
8371d7fe43SShawn McCarney EXPECT_NE(&(device.getPMBusInterface()), nullptr);
8471d7fe43SShawn McCarney }
8571d7fe43SShawn McCarney
TEST(UCD90xDeviceTests,GetMfrStatus)8671d7fe43SShawn McCarney TEST(UCD90xDeviceTests, GetMfrStatus)
8771d7fe43SShawn McCarney {
8871d7fe43SShawn McCarney // Test where works
8971d7fe43SShawn McCarney {
9071d7fe43SShawn McCarney MockServices services;
9171d7fe43SShawn McCarney
9271d7fe43SShawn McCarney std::string name{"ucd90320"};
9371d7fe43SShawn McCarney std::vector<std::unique_ptr<Rail>> rails;
9471d7fe43SShawn McCarney uint8_t bus{3};
9571d7fe43SShawn McCarney uint16_t address{0x72};
9671d7fe43SShawn McCarney UCD90xDevice device{name, std::move(rails), services, bus, address};
9771d7fe43SShawn McCarney
9871d7fe43SShawn McCarney MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface());
9971d7fe43SShawn McCarney uint64_t mfrStatus{0x123456789abcull};
10071d7fe43SShawn McCarney EXPECT_CALL(pmbus, read("mfr_status", Type::HwmonDeviceDebug, true))
10171d7fe43SShawn McCarney .Times(1)
10271d7fe43SShawn McCarney .WillOnce(Return(mfrStatus));
10371d7fe43SShawn McCarney
10471d7fe43SShawn McCarney EXPECT_EQ(device.getMfrStatus(), mfrStatus);
10571d7fe43SShawn McCarney }
10671d7fe43SShawn McCarney
10771d7fe43SShawn McCarney // Test where fails with exception
10871d7fe43SShawn McCarney {
10971d7fe43SShawn McCarney MockServices services;
11071d7fe43SShawn McCarney
11171d7fe43SShawn McCarney std::string name{"ucd90320"};
11271d7fe43SShawn McCarney std::vector<std::unique_ptr<Rail>> rails;
11371d7fe43SShawn McCarney uint8_t bus{3};
11471d7fe43SShawn McCarney uint16_t address{0x72};
11571d7fe43SShawn McCarney UCD90xDevice device{name, std::move(rails), services, bus, address};
11671d7fe43SShawn McCarney
11771d7fe43SShawn McCarney MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface());
11871d7fe43SShawn McCarney EXPECT_CALL(pmbus, read("mfr_status", Type::HwmonDeviceDebug, true))
11971d7fe43SShawn McCarney .Times(1)
12071d7fe43SShawn McCarney .WillOnce(Throw(std::runtime_error{"File does not exist"}));
12171d7fe43SShawn McCarney
12271d7fe43SShawn McCarney try
12371d7fe43SShawn McCarney {
12471d7fe43SShawn McCarney device.getMfrStatus();
12571d7fe43SShawn McCarney ADD_FAILURE() << "Should not have reached this line.";
12671d7fe43SShawn McCarney }
12771d7fe43SShawn McCarney catch (const std::exception& e)
12871d7fe43SShawn McCarney {
12971d7fe43SShawn McCarney EXPECT_STREQ(e.what(),
13071d7fe43SShawn McCarney "Unable to read MFR_STATUS for device ucd90320: "
13171d7fe43SShawn McCarney "File does not exist");
13271d7fe43SShawn McCarney }
13371d7fe43SShawn McCarney }
13471d7fe43SShawn McCarney }
13571d7fe43SShawn McCarney
TEST(UCD90xDeviceTests,StorePgoodFaultDebugData)13671d7fe43SShawn McCarney TEST(UCD90xDeviceTests, StorePgoodFaultDebugData)
13771d7fe43SShawn McCarney {
13871d7fe43SShawn McCarney // This is a protected method and cannot be called directly from a gtest.
13971d7fe43SShawn McCarney // Call findPgoodFault() which calls storePgoodFaultDebugData().
14071d7fe43SShawn McCarney
14171d7fe43SShawn McCarney // Test where works
14271d7fe43SShawn McCarney {
14371d7fe43SShawn McCarney MockServices services;
14471d7fe43SShawn McCarney std::vector<int> gpioValues{1, 1, 0};
14571d7fe43SShawn McCarney EXPECT_CALL(services, getGPIOValues("ucd90320"))
14671d7fe43SShawn McCarney .Times(1)
14771d7fe43SShawn McCarney .WillOnce(Return(gpioValues));
14871d7fe43SShawn McCarney EXPECT_CALL(services,
14971d7fe43SShawn McCarney logInfoMsg("Device ucd90320 GPIO values: [1, 1, 0]"))
15071d7fe43SShawn McCarney .Times(1);
15171d7fe43SShawn McCarney EXPECT_CALL(services,
15271d7fe43SShawn McCarney logInfoMsg("Device ucd90320 MFR_STATUS: 0x123456789abc"))
15371d7fe43SShawn McCarney .Times(1);
15471d7fe43SShawn McCarney EXPECT_CALL(
15571d7fe43SShawn McCarney services,
15671d7fe43SShawn McCarney logErrorMsg(
15771d7fe43SShawn McCarney "Pgood fault found in rail monitored by device ucd90320"))
15871d7fe43SShawn McCarney .Times(1);
15971d7fe43SShawn McCarney EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail VDD"))
16071d7fe43SShawn McCarney .Times(1);
16171d7fe43SShawn McCarney EXPECT_CALL(
16271d7fe43SShawn McCarney services,
16371d7fe43SShawn McCarney logErrorMsg(
16471d7fe43SShawn McCarney "Rail VDD pgood GPIO line offset 2 has inactive value 0"))
16571d7fe43SShawn McCarney .Times(1);
16671d7fe43SShawn McCarney
16771d7fe43SShawn McCarney std::string name{"ucd90320"};
16871d7fe43SShawn McCarney std::vector<std::unique_ptr<Rail>> rails;
16971d7fe43SShawn McCarney rails.emplace_back(createRail("VDD", 2));
17071d7fe43SShawn McCarney uint8_t bus{3};
17171d7fe43SShawn McCarney uint16_t address{0x72};
17271d7fe43SShawn McCarney UCD90xDevice device{name, std::move(rails), services, bus, address};
17371d7fe43SShawn McCarney
17471d7fe43SShawn McCarney MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface());
17571d7fe43SShawn McCarney EXPECT_CALL(pmbus, getPath(Type::Hwmon))
17671d7fe43SShawn McCarney .Times(1)
17771d7fe43SShawn McCarney .WillOnce(Return("/tmp"));
17871d7fe43SShawn McCarney EXPECT_CALL(pmbus, read("mfr_status", Type::HwmonDeviceDebug, true))
17971d7fe43SShawn McCarney .Times(1)
18071d7fe43SShawn McCarney .WillOnce(Return(0x123456789abcull));
18171d7fe43SShawn McCarney
18271d7fe43SShawn McCarney // Call findPgoodFault() which calls storePgoodFaultDebugData()
18371d7fe43SShawn McCarney std::string powerSupplyError{};
18471d7fe43SShawn McCarney std::map<std::string, std::string> additionalData{};
185*f5402197SPatrick Williams std::string error =
186*f5402197SPatrick Williams device.findPgoodFault(services, powerSupplyError, additionalData);
18771d7fe43SShawn McCarney EXPECT_EQ(error,
18871d7fe43SShawn McCarney "xyz.openbmc_project.Power.Error.PowerSequencerVoltageFault");
18971d7fe43SShawn McCarney EXPECT_EQ(additionalData.size(), 6);
19071d7fe43SShawn McCarney EXPECT_EQ(additionalData["MFR_STATUS"], "0x123456789abc");
19171d7fe43SShawn McCarney EXPECT_EQ(additionalData["DEVICE_NAME"], "ucd90320");
19271d7fe43SShawn McCarney EXPECT_EQ(additionalData["GPIO_VALUES"], "[1, 1, 0]");
19371d7fe43SShawn McCarney EXPECT_EQ(additionalData["RAIL_NAME"], "VDD");
19471d7fe43SShawn McCarney EXPECT_EQ(additionalData["GPIO_LINE"], "2");
19571d7fe43SShawn McCarney EXPECT_EQ(additionalData["GPIO_VALUE"], "0");
19671d7fe43SShawn McCarney }
19771d7fe43SShawn McCarney
19871d7fe43SShawn McCarney // Test where exception thrown trying to get MFR_STATUS
19971d7fe43SShawn McCarney {
20071d7fe43SShawn McCarney MockServices services;
20171d7fe43SShawn McCarney std::vector<int> gpioValues{1, 1, 0};
20271d7fe43SShawn McCarney EXPECT_CALL(services, getGPIOValues("ucd90320"))
20371d7fe43SShawn McCarney .Times(1)
20471d7fe43SShawn McCarney .WillOnce(Return(gpioValues));
20571d7fe43SShawn McCarney EXPECT_CALL(services,
20671d7fe43SShawn McCarney logInfoMsg("Device ucd90320 GPIO values: [1, 1, 0]"))
20771d7fe43SShawn McCarney .Times(1);
20871d7fe43SShawn McCarney EXPECT_CALL(
20971d7fe43SShawn McCarney services,
21071d7fe43SShawn McCarney logErrorMsg(
21171d7fe43SShawn McCarney "Pgood fault found in rail monitored by device ucd90320"))
21271d7fe43SShawn McCarney .Times(1);
21371d7fe43SShawn McCarney EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail VDD"))
21471d7fe43SShawn McCarney .Times(1);
21571d7fe43SShawn McCarney EXPECT_CALL(
21671d7fe43SShawn McCarney services,
21771d7fe43SShawn McCarney logErrorMsg(
21871d7fe43SShawn McCarney "Rail VDD pgood GPIO line offset 2 has inactive value 0"))
21971d7fe43SShawn McCarney .Times(1);
22071d7fe43SShawn McCarney
22171d7fe43SShawn McCarney std::string name{"ucd90320"};
22271d7fe43SShawn McCarney std::vector<std::unique_ptr<Rail>> rails;
22371d7fe43SShawn McCarney rails.emplace_back(createRail("VDD", 2));
22471d7fe43SShawn McCarney uint8_t bus{3};
22571d7fe43SShawn McCarney uint16_t address{0x72};
22671d7fe43SShawn McCarney UCD90xDevice device{name, std::move(rails), services, bus, address};
22771d7fe43SShawn McCarney
22871d7fe43SShawn McCarney MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface());
22971d7fe43SShawn McCarney EXPECT_CALL(pmbus, getPath(Type::Hwmon))
23071d7fe43SShawn McCarney .Times(1)
23171d7fe43SShawn McCarney .WillOnce(Return("/tmp"));
23271d7fe43SShawn McCarney EXPECT_CALL(pmbus, read("mfr_status", Type::HwmonDeviceDebug, true))
23371d7fe43SShawn McCarney .Times(1)
23471d7fe43SShawn McCarney .WillOnce(Throw(std::runtime_error{"File does not exist"}));
23571d7fe43SShawn McCarney
23671d7fe43SShawn McCarney // Call findPgoodFault() which calls storePgoodFaultDebugData()
23771d7fe43SShawn McCarney std::string powerSupplyError{};
23871d7fe43SShawn McCarney std::map<std::string, std::string> additionalData{};
239*f5402197SPatrick Williams std::string error =
240*f5402197SPatrick Williams device.findPgoodFault(services, powerSupplyError, additionalData);
24171d7fe43SShawn McCarney EXPECT_EQ(error,
24271d7fe43SShawn McCarney "xyz.openbmc_project.Power.Error.PowerSequencerVoltageFault");
24371d7fe43SShawn McCarney EXPECT_EQ(additionalData.size(), 5);
24471d7fe43SShawn McCarney EXPECT_EQ(additionalData["DEVICE_NAME"], "ucd90320");
24571d7fe43SShawn McCarney EXPECT_EQ(additionalData["GPIO_VALUES"], "[1, 1, 0]");
24671d7fe43SShawn McCarney EXPECT_EQ(additionalData["RAIL_NAME"], "VDD");
24771d7fe43SShawn McCarney EXPECT_EQ(additionalData["GPIO_LINE"], "2");
24871d7fe43SShawn McCarney EXPECT_EQ(additionalData["GPIO_VALUE"], "0");
24971d7fe43SShawn McCarney }
25071d7fe43SShawn McCarney }
251