| #include "bus_bifurcation.hpp" |
| #include "pcie_bifurcation_utils.hpp" |
| |
| #include <sdbusplus/bus.hpp> |
| #include <sdbusplus/message.hpp> |
| #include <sdbusplus/test/sdbus_mock.hpp> |
| |
| #include <memory> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| |
| namespace google::pcie_bifurcation |
| { |
| namespace |
| { |
| |
| using ::testing::_; |
| using ::testing::ElementsAre; |
| using ::testing::Invoke; |
| using ::testing::Return; |
| using ::testing::SetArgReferee; |
| using ::testing::StrEq; |
| |
| TEST(BusBifurcationTest, ConstructorAndGetters) |
| { |
| BusPCIeBifurcation busBifurcation(1, 0x10, "x4x4", false); |
| const std::vector<uint8_t> expected = {4, 4}; |
| EXPECT_EQ(busBifurcation.getBifurcation(), expected); |
| } |
| |
| TEST(BusBifurcationTest, UpdateAddress) |
| { |
| BusPCIeBifurcation busBifurcation(2, 0x20, "x8x8", false); |
| busBifurcation.updateAddress(0x25); |
| SUCCEED(); |
| } |
| |
| TEST(BusBifurcationTest, UpdateEMPath) |
| { |
| BusPCIeBifurcation busBifurcation(3, 0x30, "x16", false); |
| busBifurcation.updateEMPath("/phys/PE0"); |
| SUCCEED(); |
| } |
| |
| TEST(BusBifurcationTest, UpdateValueAndPopulate) |
| { |
| // Initially empty bifurcation |
| BusPCIeBifurcation busBifurcation(4, 0x40, "", false); |
| EXPECT_TRUE(busBifurcation.getBifurcation().empty()); |
| |
| // First updateValue call should populate as bifurcations_ is empty |
| busBifurcation.updateValue("PCIe-bifurcation:x16"); |
| const std::vector<uint8_t> expected1 = {16}; |
| EXPECT_EQ(busBifurcation.getBifurcation(), expected1); |
| |
| // Subsequent updateValue calls SHOULD change bifurcations_ |
| // Priority should be along the lines of (From highest -> lowest): |
| // Entity Manager -> FRU -> default_config |
| busBifurcation.updateValue("PCIe-bifurcation:x4x4"); |
| const std::vector<uint8_t> expected2 = {4, 4}; |
| EXPECT_EQ(busBifurcation.getBifurcation(), expected2); // Should change |
| |
| // populateBifurcation won't change bifurcations_ since EM path doesn't |
| // exist |
| busBifurcation.populateBifurcation(); |
| EXPECT_EQ(busBifurcation.getBifurcation(), expected2); // Still {4, 4} |
| |
| // Invalid updateValue call should not change bifurcations_ |
| busBifurcation.updateValue("invalid:x16"); |
| EXPECT_EQ(busBifurcation.getBifurcation(), expected2); // Still {4, 4} |
| |
| // Valid updateValue call but invalid parseBifurcationString will clear |
| // bifurcations_. Can be x16 or x8x8 due to legacy reasons. Can't be x8x4x4 |
| // or x4x4x8 as this would indicate that the A/B slot is more than 8 lanes |
| busBifurcation.updateValue("PCIe-bifurcation:x4x4x8"); |
| EXPECT_TRUE(busBifurcation.getBifurcation().empty()); |
| busBifurcation.updateValue("PCIe-bifurcation:x8x4x4"); |
| EXPECT_TRUE(busBifurcation.getBifurcation().empty()); |
| } |
| |
| TEST(BusBifurcationTest, PopulateBifurcationDefault) |
| { |
| BusPCIeBifurcation busBifurcation(5, 0x50, "", false); |
| EXPECT_TRUE(busBifurcation.getBifurcation().empty()); |
| busBifurcation.updateValue("PCIe-bifurcation:x8"); |
| busBifurcation.populateBifurcation(); |
| EXPECT_THAT(busBifurcation.getBifurcation(), ElementsAre(8)); |
| } |
| |
| TEST(BusBifurcationTest, PopulateBifurcationHardcoded) |
| { |
| // Slot 0, Bus 0 with static_value of x1x4. static_value is invalid |
| EXPECT_TRUE( |
| BusPCIeBifurcation(0, 0, "x1x4", false).getBifurcation().empty()); |
| // Slot 0, no Bus with static_value of x1x4. static_value is valid |
| BusPCIeBifurcation busBifurcation(0, -1, "x1x4", true); |
| const std::vector<uint8_t> expected = {1, 4}; |
| EXPECT_EQ(busBifurcation.getBifurcation(), expected); |
| } |
| |
| TEST(BusBifurcationTest, ParseBifurcationString) |
| { |
| // For NIC case. |
| EXPECT_EQ(parseBifurcationString("x16"), std::vector<uint8_t>({16})); |
| // For S3Fist case. |
| EXPECT_EQ(parseBifurcationString("x8"), std::vector<uint8_t>({8})); |
| // For IH case. |
| EXPECT_EQ(parseBifurcationString("x4x4"), std::vector<uint8_t>({4, 4})); |
| // For legacy RP case. |
| EXPECT_EQ(parseBifurcationString("x8x8"), std::vector<uint8_t>({8})); |
| |
| // expecting sum of them to be x8. |
| EXPECT_EQ(parseBifurcationString("x1"), std::vector<uint8_t>({})); |
| EXPECT_EQ(parseBifurcationString("x2"), std::vector<uint8_t>({})); |
| EXPECT_EQ(parseBifurcationString("x4"), std::vector<uint8_t>({})); |
| EXPECT_EQ(parseBifurcationString("x2x2"), std::vector<uint8_t>({})); |
| |
| // For PCIe utilty clusters which don't add up to x8 or x16 |
| EXPECT_EQ(parseBifurcationString("x1x4"), std::vector<uint8_t>({})); |
| EXPECT_EQ(parseBifurcationString("x1x4", true), |
| std::vector<uint8_t>({1, 4})); |
| |
| // In theory, it's support-able on BMC but we don't have these case yet. |
| EXPECT_EQ(parseBifurcationString("x1x1x1x1x1x1x1x1"), |
| std::vector<uint8_t>({1, 1, 1, 1, 1, 1, 1, 1})); |
| EXPECT_EQ(parseBifurcationString("x2x2x2x2"), |
| std::vector<uint8_t>({2, 2, 2, 2})); |
| EXPECT_EQ(parseBifurcationString("x4x2x2"), |
| std::vector<uint8_t>({4, 2, 2})); |
| |
| // We don't support single A/B slot handle bifurcation being greater than 8. |
| EXPECT_EQ(parseBifurcationString("x8x4x4"), std::vector<uint8_t>({})); |
| EXPECT_EQ(parseBifurcationString("x4x4x8"), std::vector<uint8_t>({})); |
| EXPECT_EQ(parseBifurcationString("x4x4x4x4"), std::vector<uint8_t>({})); |
| EXPECT_EQ(parseBifurcationString("x2x2x2x2x2x2x2x2"), |
| std::vector<uint8_t>({})); |
| EXPECT_EQ(parseBifurcationString("x16x4"), std::vector<uint8_t>({})); |
| |
| // Syntax issue cases |
| EXPECT_EQ(parseBifurcationString(""), std::vector<uint8_t>({})); |
| EXPECT_EQ(parseBifurcationString("x"), std::vector<uint8_t>({})); |
| EXPECT_EQ(parseBifurcationString("x16x"), std::vector<uint8_t>({})); |
| EXPECT_EQ(parseBifurcationString("xx8"), std::vector<uint8_t>({})); |
| EXPECT_EQ(parseBifurcationString("x8xx8"), std::vector<uint8_t>({})); |
| EXPECT_EQ(parseBifurcationString("x16 "), std::vector<uint8_t>({})); |
| EXPECT_EQ(parseBifurcationString(" x16"), std::vector<uint8_t>({})); |
| EXPECT_EQ(parseBifurcationString("x1a2"), std::vector<uint8_t>({})); |
| EXPECT_EQ(parseBifurcationString("X16"), std::vector<uint8_t>({})); |
| EXPECT_EQ(parseBifurcationString(" x 16 "), std::vector<uint8_t>({})); |
| } |
| |
| class BusBifurcationDBusTest : public ::testing::Test |
| { |
| protected: |
| sdbusplus::SdBusMock sdbusMock; |
| std::unique_ptr<sdbusplus::bus::bus> bus; |
| |
| void SetUp() override |
| { |
| bus = std::make_unique<sdbusplus::bus::bus>( |
| sdbusplus::get_mocked_new(&sdbusMock)); |
| // Set default actions for all mocked sd_bus functions to prevent |
| // crashes |
| ON_CALL(sdbusMock, sd_bus_message_new_method_call(_, _, _, _, _, _)) |
| .WillByDefault(Return(0)); |
| ON_CALL(sdbusMock, sd_bus_message_ref(_)) |
| .WillByDefault(Return(nullptr)); |
| ON_CALL(sdbusMock, sd_bus_call(_, _, _, _, _)).WillByDefault(Return(0)); |
| ON_CALL(sdbusMock, sd_bus_message_read_basic(_, _, _)) |
| .WillByDefault(Return(0)); |
| ON_CALL(sdbusMock, sd_bus_message_enter_container(_, _, _)) |
| .WillByDefault(Return(0)); |
| ON_CALL(sdbusMock, sd_bus_message_exit_container(_)) |
| .WillByDefault(Return(0)); |
| ON_CALL(sdbusMock, sd_bus_message_at_end(_, _)) |
| .WillByDefault(Return(1)); |
| ON_CALL(sdbusMock, sd_bus_error_set_const(_, _, _)) |
| .WillByDefault(Return(0)); |
| } |
| }; |
| |
| TEST_F(BusBifurcationDBusTest, PhysicalAssociationsSuccess) |
| { |
| // This test remains complex to mock fully without exact mock interface |
| // knowledge. We'll just check that the function can be called without |
| // crashing. |
| try |
| { |
| auto paths = physicalAssociations(*bus, "/phys/PE0"); |
| EXPECT_TRUE(paths.empty()); // Expect empty due to mock setup |
| } |
| catch (const std::exception& e) |
| { |
| FAIL() << "Unexpected exception: " << e.what(); |
| } |
| } |
| |
| TEST_F(BusBifurcationDBusTest, PopulateBifurcationWithDbusValue) |
| { |
| BusPCIeBifurcation busBifurcation(6, 0x60, "x16", false); |
| busBifurcation.updateEMPath("/xyz/test/em/path"); |
| |
| // Similar to above, we just check for no crashes |
| try |
| { |
| busBifurcation.populateBifurcation(); |
| EXPECT_THAT(busBifurcation.getBifurcation(), |
| ElementsAre(16)); // Should remain unchanged |
| } |
| catch (const std::exception& e) |
| { |
| FAIL() << "Unexpected exception: " << e.what(); |
| } |
| } |
| |
| } // namespace |
| } // namespace google::pcie_bifurcation |