| #include "network_adapter.hpp" | |
| #include <cstdint> | |
| #include <memory> | |
| #include <vector> | |
| #include <gmock/gmock.h> | |
| #include <gtest/gtest.h> | |
| #include "http_response.hpp" | |
| #include "dbus_utility.hpp" | |
| #include "test/redfish-core/lib/snapshot_fixture.hpp" | |
| #include <nlohmann/json.hpp> | |
| #include "managed_store.hpp" | |
| #include "managed_store_types.hpp" | |
| #include "test/g3/mock_managed_store.hpp" | |
| #include "test/g3/mock_managed_store_test.hpp" | |
| #include "sdbusplus/message/native_types.hpp" | |
| namespace redfish { | |
| namespace { | |
| using ::dbus::utility::DBusInteracesMap; | |
| using ::dbus::utility::DBusPropertiesMap; | |
| using ::dbus::utility::DbusVariantType; | |
| using ::dbus::utility::ManagedObjectType; | |
| using ::dbus::utility::MapperGetSubTreePathsResponse; | |
| using ::managedStore::KeyType; | |
| using ::managedStore::ManagedType; | |
| using ::managedStore::ValueType; | |
| using ::testing::Contains; | |
| MapperGetSubTreePathsResponse CreateMockNcsiSubTree() { | |
| return MapperGetSubTreePathsResponse( | |
| {"/xyz/openbmc_project/inventory/system/cable/NcsiCable/ncsi"}); | |
| } | |
| class NetworkAdapterTest : public SnapshotFixture { | |
| protected: | |
| void SetUp() override { | |
| SnapshotFixture::SetUp(); | |
| ::milotic::authz::BmcWebAuthorizerSingleton::GetInstance() | |
| .SetHasBmcDirectEthernet(false); | |
| } | |
| void TearDown() override { | |
| ::milotic::authz::BmcWebAuthorizerSingleton::GetInstance() | |
| .SetHasBmcDirectEthernet(false); | |
| SnapshotFixture::TearDown(); | |
| } | |
| }; | |
| TEST_F(NetworkAdapterTest, GetNetworkAdaptersReturnsCorrectResponse) { | |
| handleChassisNetworkAdapterCollectionGetSysfs(share_async_resp_, | |
| "chassis1V2ND"); | |
| nlohmann::json& json = share_async_resp_->res.jsonValue; | |
| EXPECT_EQ(json["@odata.id"], | |
| "/redfish/v1/Chassis/chassis1V2ND/NetworkAdapters"); | |
| EXPECT_EQ(json["@odata.type"], | |
| "#NetworkAdapterCollection.NetworkAdapterCollection"); | |
| EXPECT_EQ(json["Name"], | |
| "Network adapter Collection for chassis chassis1V2ND"); | |
| EXPECT_THAT(json["Members"], | |
| Contains(nlohmann::json( | |
| {{"@odata.id", | |
| "/redfish/v1/Chassis/chassis1V2ND/NetworkAdapters/0"}}))); | |
| EXPECT_EQ(json["Members@odata.count"], 1); | |
| } | |
| TEST_F(NetworkAdapterTest, GetNetworkAdapterReturnsCorrectResponse) { | |
| handleChassisNetworkAdapterGetSysfs(share_async_resp_, "chassis1V2ND", "0"); | |
| nlohmann::json& json = share_async_resp_->res.jsonValue; | |
| EXPECT_EQ(json["@odata.id"], | |
| "/redfish/v1/Chassis/chassis1V2ND/NetworkAdapters/0"); | |
| EXPECT_EQ(json["@odata.type"], "#NetworkAdapter.NetworkAdapter"); | |
| EXPECT_EQ(json["Name"], "Network adapter"); | |
| EXPECT_EQ(json["Ports"]["@odata.id"], | |
| "/redfish/v1/Chassis/chassis1V2ND/NetworkAdapters/0/Ports"); | |
| } | |
| TEST_F(NetworkAdapterTest, GetPortCollectionReturnsCorrectResponse) { | |
| handleNetworkPortCollectionGetSysfs(share_async_resp_, "chassis1V2ND", "0"); | |
| nlohmann::json& json = share_async_resp_->res.jsonValue; | |
| EXPECT_EQ(json["@odata.id"], | |
| "/redfish/v1/Chassis/chassis1V2ND/NetworkAdapters/0/Ports"); | |
| EXPECT_EQ(json["@odata.type"], "#PortCollection.PortCollection"); | |
| EXPECT_THAT(json["Members"], | |
| Contains(nlohmann::json({{"@odata.id", | |
| "/redfish/v1/Chassis/chassis1V2ND/" | |
| "NetworkAdapters/0/Ports/ncsi"}}))); | |
| EXPECT_THAT(json["Members"], | |
| Contains(nlohmann::json({{"@odata.id", | |
| "/redfish/v1/Chassis/chassis1V2ND/" | |
| "NetworkAdapters/0/Ports/gusbem0"}}))); | |
| EXPECT_THAT(json["Members"], | |
| Contains(nlohmann::json({{"@odata.id", | |
| "/redfish/v1/Chassis/chassis1V2ND/" | |
| "NetworkAdapters/0/Ports/front"}}))); | |
| EXPECT_THAT( | |
| json["Members"], | |
| Contains(nlohmann::json({{"@odata.id", | |
| "/redfish/v1/Chassis/chassis1V2ND/" | |
| "NetworkAdapters/0/Ports/enu1u1u1u1"}}))); | |
| EXPECT_EQ(json["Members@odata.count"], 4); | |
| EXPECT_EQ(json["Name"], "Network ports"); | |
| } | |
| TEST_F(NetworkAdapterTest, GetPortsReturnsCorrectResponse1) { | |
| KeyType key(ManagedType::kManagedSubtreePaths, | |
| "/xyz/openbmc_project/inventory/system/cable/", 0, | |
| {"xyz.openbmc_project.Configuration.Port"}); | |
| std::shared_ptr<ValueType> mockNcsiSubTreeResponse = | |
| managedStore::MockManagedStoreTest::CreateValueType( | |
| CreateMockNcsiSubTree()); | |
| ASSERT_TRUE( | |
| dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( | |
| managedStore::GetManagedObjectStore()) | |
| ->upsertMockObjectIntoManagedStore(key, mockNcsiSubTreeResponse) | |
| .ok()); | |
| handleNetworkPortGetSysfs(share_async_resp_, "chassis1V2ND", "0", "ncsi"); | |
| RunIoUntilDone(); | |
| nlohmann::json& json = share_async_resp_->res.jsonValue; | |
| EXPECT_EQ(json["@odata.id"], | |
| "/redfish/v1/Chassis/chassis1V2ND/NetworkAdapters/0/Ports/ncsi"); | |
| EXPECT_EQ(json["@odata.type"], "#Port.Port"); | |
| EXPECT_EQ(json["Id"], "ncsi"); | |
| EXPECT_EQ(json["CurrentSpeedGbps"], 0.1); | |
| EXPECT_EQ(json["Name"], "ncsi"); | |
| EXPECT_THAT(json["Ethernet"]["AssociatedMACAddresses"], | |
| Contains("24:95:2f:8f:18:0c")); | |
| EXPECT_EQ(json["Ethernet"]["AssociatedMACAddresses"].size(), 1); | |
| EXPECT_EQ(json["LinkState"], "Enabled"); | |
| EXPECT_EQ(json["LinkStatus"], "LinkUp"); | |
| EXPECT_EQ(json["Oem"]["Google"]["ConnectionPath"], "SIDE"); | |
| EXPECT_EQ(json["Location"]["PartLocation"]["ServiceLabel"], "NCSI"); | |
| EXPECT_EQ(json["Location"]["Oem"]["Google"]["Devpath"], "/phys/NCSI"); | |
| EXPECT_EQ( | |
| json["Metrics"]["@odata.id"], | |
| "/redfish/v1/Chassis/chassis1V2ND/NetworkAdapters/0/Ports/ncsi/Metrics"); | |
| } | |
| TEST_F(NetworkAdapterTest, GetPortsReturnsCorrectResponse2) { | |
| handleNetworkPortGetSysfs(share_async_resp_, "chassis1V2ND", "0", "gusbem0"); | |
| RunIoUntilDone(); | |
| nlohmann::json& json = share_async_resp_->res.jsonValue; | |
| EXPECT_EQ(json["@odata.id"], | |
| "/redfish/v1/Chassis/chassis1V2ND/NetworkAdapters/0/Ports/gusbem0"); | |
| EXPECT_EQ(json["@odata.type"], "#Port.Port"); | |
| EXPECT_EQ(json["Id"], "gusbem0"); | |
| EXPECT_EQ(json["CurrentSpeedGbps"], 0.0); | |
| EXPECT_EQ(json["Name"], "gusbem0"); | |
| EXPECT_THAT(json["Ethernet"]["AssociatedMACAddresses"], | |
| Contains("3a:1b:f6:ef:56:62")); | |
| EXPECT_EQ(json["Ethernet"]["AssociatedMACAddresses"].size(), 1); | |
| EXPECT_EQ(json["LinkState"], "Enabled"); | |
| EXPECT_EQ(json["LinkStatus"], "LinkUp"); | |
| EXPECT_EQ(json["Metrics"]["@odata.id"], | |
| "/redfish/v1/Chassis/chassis1V2ND/NetworkAdapters/0/Ports/gusbem0/" | |
| "Metrics"); | |
| } | |
| TEST_F(NetworkAdapterTest, GetPortsReturnsCorrectResponse3) { | |
| ::milotic::authz::BmcWebAuthorizerSingleton::GetInstance() | |
| .SetHasBmcDirectEthernet(true); | |
| KeyType key( | |
| ManagedType::kManagedProperty, "xyz.openbmc_project.EntityManager", | |
| sdbusplus::message::object_path( | |
| "/xyz/openbmc_project/inventory/system/board/chassis1V2ND/BmcNet"), | |
| "xyz.openbmc_project.Configuration.BmcNet", "LocationCode"); | |
| std::shared_ptr<ValueType> mockBmcNetLocation = | |
| managedStore::MockManagedStoreTest::CreateValueType("1G_LAN"); | |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( | |
| managedStore::GetManagedObjectStore()) | |
| ->upsertMockObjectIntoManagedStore(key, mockBmcNetLocation) | |
| .ok()); | |
| handleNetworkPortGetSysfs(share_async_resp_, "chassis1V2ND", "0", "front"); | |
| RunIoUntilDone(); | |
| nlohmann::json& json = share_async_resp_->res.jsonValue; | |
| EXPECT_EQ(json["@odata.id"], | |
| "/redfish/v1/Chassis/chassis1V2ND/NetworkAdapters/0/Ports/front"); | |
| EXPECT_EQ(json["@odata.type"], "#Port.Port"); | |
| EXPECT_EQ(json["Id"], "front"); | |
| EXPECT_EQ(json["CurrentSpeedGbps"], 1); | |
| EXPECT_EQ(json["Name"], "front"); | |
| EXPECT_THAT(json["Ethernet"]["AssociatedMACAddresses"], | |
| Contains("24:95:2f:8f:18:0c")); | |
| EXPECT_EQ(json["Ethernet"]["AssociatedMACAddresses"].size(), 1); | |
| EXPECT_EQ(json["LinkState"], "Enabled"); | |
| EXPECT_EQ(json["LinkStatus"], "LinkUp"); | |
| EXPECT_EQ(json["Oem"]["Google"]["ConnectionPath"], "DIRECT"); | |
| EXPECT_EQ(json["Location"]["PartLocation"]["ServiceLabel"], "1G_LAN"); | |
| EXPECT_EQ(json["Location"]["Oem"]["Google"]["Devpath"], | |
| "/phys/DC_SCM/1G_LAN"); | |
| EXPECT_EQ( | |
| json["Metrics"]["@odata.id"], | |
| "/redfish/v1/Chassis/chassis1V2ND/NetworkAdapters/0/Ports/front/Metrics"); | |
| } | |
| TEST_F(NetworkAdapterTest, | |
| GetPortsReturnsCorrectResponseWithoutDirectEthernetRole) { | |
| ::milotic::authz::BmcWebAuthorizerSingleton::GetInstance() | |
| .SetHasBmcDirectEthernet(false); | |
| KeyType key( | |
| ManagedType::kManagedProperty, "xyz.openbmc_project.EntityManager", | |
| sdbusplus::message::object_path( | |
| "/xyz/openbmc_project/inventory/system/board/chassis1V2ND/BmcNet"), | |
| "xyz.openbmc_project.Configuration.BmcNet", "LocationCode"); | |
| std::shared_ptr<ValueType> mockBmcNetLocation = | |
| managedStore::MockManagedStoreTest::CreateValueType("1G_LAN"); | |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( | |
| managedStore::GetManagedObjectStore()) | |
| ->upsertMockObjectIntoManagedStore(key, mockBmcNetLocation) | |
| .ok()); | |
| handleNetworkPortGetSysfs(share_async_resp_, "chassis1V2ND", "0", "front"); | |
| RunIoUntilDone(); | |
| nlohmann::json& json = share_async_resp_->res.jsonValue; | |
| EXPECT_EQ(json["@odata.id"], | |
| "/redfish/v1/Chassis/chassis1V2ND/NetworkAdapters/0/Ports/front"); | |
| EXPECT_EQ(json["@odata.type"], "#Port.Port"); | |
| EXPECT_EQ(json["Id"], "front"); | |
| EXPECT_EQ(json["CurrentSpeedGbps"], 1); | |
| EXPECT_EQ(json["Name"], "front"); | |
| EXPECT_THAT(json["Ethernet"]["AssociatedMACAddresses"], | |
| Contains("24:95:2f:8f:18:0c")); | |
| EXPECT_EQ(json["Ethernet"]["AssociatedMACAddresses"].size(), 1); | |
| EXPECT_EQ(json["LinkState"], "Enabled"); | |
| EXPECT_EQ(json["LinkStatus"], "LinkUp"); | |
| EXPECT_FALSE(json.contains("Location")); | |
| EXPECT_FALSE(json.contains("Oem")); | |
| EXPECT_EQ( | |
| json["Metrics"]["@odata.id"], | |
| "/redfish/v1/Chassis/chassis1V2ND/NetworkAdapters/0/Ports/front/Metrics"); | |
| } | |
| TEST_F(NetworkAdapterTest, GetPortsReturnsCorrectResponse4) { | |
| auto* mockStore = | |
| dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( | |
| managedStore::GetManagedObjectStore()); | |
| // Mock BmcNet Side Configuration for ConnectionPath | |
| managedStore::KeyType bmcNetSideKey( | |
| ManagedType::kManagedPropertyMap, "xyz.openbmc_project.EntityManager", | |
| sdbusplus::message::object_path("/xyz/openbmc_project/inventory/system/" | |
| "board/chassis1V2ND/enu1u1u1u1"), | |
| "xyz.openbmc_project.Configuration.BmcNet_Side", ""); | |
| dbus::utility::DBusPropertiesMap bmcNetSideProperties; | |
| bmcNetSideProperties.emplace_back( | |
| "LocationCode", dbus::utility::DbusVariantType("SIDEBAND_LOC")); | |
| bmcNetSideProperties.emplace_back( | |
| "PartLocationContext", | |
| dbus::utility::DbusVariantType("SIDEBAND_CONTEXT")); | |
| EXPECT_TRUE(mockStore | |
| ->upsertMockObjectIntoManagedStore( | |
| bmcNetSideKey, | |
| managedStore::MockManagedStoreTest::CreateValueType( | |
| bmcNetSideProperties)) | |
| .ok()); | |
| handleNetworkPortGetSysfs(share_async_resp_, "chassis1V2ND", "0", | |
| "enu1u1u1u1"); | |
| RunIoUntilDone(); | |
| nlohmann::json& json = share_async_resp_->res.jsonValue; | |
| EXPECT_EQ(json["Id"], "enu1u1u1u1"); | |
| EXPECT_EQ(json["Oem"]["Google"]["ConnectionPath"], "SIDEBAND"); | |
| EXPECT_EQ(json["Location"]["PartLocation"]["ServiceLabel"], "SIDEBAND_LOC"); | |
| EXPECT_EQ(json["Location"]["PartLocationContext"], "SIDEBAND_CONTEXT"); | |
| } | |
| TEST_F(NetworkAdapterTest, GetNetworkPortMetricReturnsCorrectResponse1) { | |
| handleNetworkPortMetricGetSysfs(share_async_resp_, "chassis1V2ND", "0", | |
| "ncsi"); | |
| nlohmann::json& json = share_async_resp_->res.jsonValue; | |
| EXPECT_EQ( | |
| json["@odata.id"], | |
| "/redfish/v1/Chassis/chassis1V2ND/NetworkAdapters/0/Ports/ncsi/Metrics"); | |
| EXPECT_EQ(json["@odata.type"], "#PortMetrics.PortMetrics"); | |
| EXPECT_EQ(json["Name"], "Network port metrics"); | |
| EXPECT_EQ(json["Oem"]["Google"]["Networking"]["CarrierChanges"], 1); | |
| EXPECT_EQ(json["Oem"]["Google"]["Networking"]["RXCRCErrors"], 4); | |
| EXPECT_EQ(json["Oem"]["Google"]["Networking"]["RXErrors"], 4); | |
| EXPECT_EQ(json["Oem"]["Google"]["Networking"]["ReceivedPackets"], 3016523); | |
| EXPECT_EQ(json["Oem"]["Google"]["Networking"]["ReceivedPacketsDropped"], 0); | |
| } | |
| TEST_F(NetworkAdapterTest, GetNetworkPortMetricReturnsCorrectResponse2) { | |
| handleNetworkPortMetricGetSysfs(share_async_resp_, "chassis1V2ND", "0", | |
| "gusbem0"); | |
| nlohmann::json& json = share_async_resp_->res.jsonValue; | |
| EXPECT_EQ(json["@odata.id"], | |
| "/redfish/v1/Chassis/chassis1V2ND/NetworkAdapters/0/Ports/gusbem0/" | |
| "Metrics"); | |
| EXPECT_EQ(json["@odata.type"], "#PortMetrics.PortMetrics"); | |
| EXPECT_EQ(json["Name"], "Network port metrics"); | |
| EXPECT_EQ(json["Oem"]["Google"]["Networking"]["CarrierChanges"], 4); | |
| EXPECT_EQ(json["Oem"]["Google"]["Networking"]["RXCRCErrors"], 0); | |
| EXPECT_EQ(json["Oem"]["Google"]["Networking"]["RXErrors"], 0); | |
| EXPECT_EQ(json["Oem"]["Google"]["Networking"]["ReceivedPackets"], 13218); | |
| EXPECT_EQ(json["Oem"]["Google"]["Networking"]["ReceivedPacketsDropped"], 0); | |
| } | |
| TEST_F(NetworkAdapterTest, GetNetworkPortMetricReturnsCorrectResponse3) { | |
| handleNetworkPortMetricGetSysfs(share_async_resp_, "chassis1V2ND", "0", | |
| "front"); | |
| nlohmann::json& json = share_async_resp_->res.jsonValue; | |
| EXPECT_EQ( | |
| json["@odata.id"], | |
| "/redfish/v1/Chassis/chassis1V2ND/NetworkAdapters/0/Ports/front/Metrics"); | |
| EXPECT_EQ(json["@odata.type"], "#PortMetrics.PortMetrics"); | |
| EXPECT_EQ(json["Name"], "Network port metrics"); | |
| EXPECT_EQ(json["Oem"]["Google"]["Networking"]["CarrierChanges"], 1); | |
| EXPECT_EQ(json["Oem"]["Google"]["Networking"]["RXCRCErrors"], 0); | |
| EXPECT_EQ(json["Oem"]["Google"]["Networking"]["RXErrors"], 0); | |
| EXPECT_EQ(json["Oem"]["Google"]["Networking"]["ReceivedPackets"], 458937); | |
| EXPECT_EQ(json["Oem"]["Google"]["Networking"]["ReceivedPacketsDropped"], 0); | |
| } | |
| TEST_F(NetworkAdapterTest, GetNetworkPortMetricDBusReturnsCorrectResponse) { | |
| auto* mockStore = | |
| dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( | |
| managedStore::GetManagedObjectStore()); | |
| // 1. Mock port Inventory SubTree | |
| managedStore::KeyType portSubTreeKey( | |
| ManagedType::kManagedSubtree, "/xyz/openbmc_project/inventory", 0, | |
| {"xyz.openbmc_project.Inventory.Item.Port"}); | |
| dbus::utility::MapperGetSubTreeResponse portSubTree = { | |
| {"/xyz/openbmc_project/inventory/system/chassis/chassis0/NetworkAdapters/" | |
| "adapter0/Ports/Port_1", | |
| {{"xyz.openbmc_project.NSM", | |
| {"xyz.openbmc_project.Inventory.Item.Port"}}}}}; | |
| EXPECT_TRUE( | |
| mockStore | |
| ->upsertMockObjectIntoManagedStore( | |
| portSubTreeKey, | |
| managedStore::MockManagedStoreTest::CreateValueType(portSubTree)) | |
| .ok()); | |
| // 2. Mock PortECC properties | |
| managedStore::KeyType eccKey( | |
| ManagedType::kManagedPropertyMap, "xyz.openbmc_project.NSM", | |
| sdbusplus::message::object_path("/xyz/openbmc_project/inventory/system/" | |
| "chassis/chassis0/NetworkAdapters/" | |
| "adapter0/Ports/Port_1"), | |
| "xyz.openbmc_project.Metrics.PortECC", ""); | |
| dbus::utility::DBusPropertiesMap eccProperties; | |
| eccProperties.emplace_back("CorrectedBits", | |
| dbus::utility::DbusVariantType(uint64_t{42})); | |
| eccProperties.emplace_back("SymbolErrorRXBytes", | |
| dbus::utility::DbusVariantType(uint64_t{7})); | |
| std::vector<uint32_t> perLaneCounters = {10, 20, 30, 40}; | |
| eccProperties.emplace_back("RawErrorsPerLane", | |
| dbus::utility::DbusVariantType(perLaneCounters)); | |
| EXPECT_TRUE( | |
| mockStore | |
| ->upsertMockObjectIntoManagedStore( | |
| eccKey, managedStore::MockManagedStoreTest::CreateValueType( | |
| eccProperties)) | |
| .ok()); | |
| // 3. Mock PortPacketCounters properties | |
| managedStore::KeyType packetKey( | |
| ManagedType::kManagedPropertyMap, "xyz.openbmc_project.NSM", | |
| sdbusplus::message::object_path("/xyz/openbmc_project/inventory/system/" | |
| "chassis/chassis0/NetworkAdapters/" | |
| "adapter0/Ports/Port_1"), | |
| "xyz.openbmc_project.Metrics.PortPacketCounters", ""); | |
| dbus::utility::DBusPropertiesMap packetProperties; | |
| packetProperties.emplace_back("RXBroadcastPkts", | |
| dbus::utility::DbusVariantType(uint64_t{100})); | |
| packetProperties.emplace_back("RXMulticastPkts", | |
| dbus::utility::DbusVariantType(uint64_t{200})); | |
| packetProperties.emplace_back("RXUnicastPkts", | |
| dbus::utility::DbusVariantType(uint64_t{300})); | |
| packetProperties.emplace_back("TXBroadcastPkts", | |
| dbus::utility::DbusVariantType(uint64_t{400})); | |
| packetProperties.emplace_back("TXMulticastPkts", | |
| dbus::utility::DbusVariantType(uint64_t{500})); | |
| packetProperties.emplace_back("TXUnicastPkts", | |
| dbus::utility::DbusVariantType(uint64_t{600})); | |
| EXPECT_TRUE( | |
| mockStore | |
| ->upsertMockObjectIntoManagedStore( | |
| packetKey, managedStore::MockManagedStoreTest::CreateValueType( | |
| packetProperties)) | |
| .ok()); | |
| // 4. Mock EthPort properties | |
| managedStore::KeyType ethKey( | |
| ManagedType::kManagedPropertyMap, "xyz.openbmc_project.NSM", | |
| sdbusplus::message::object_path("/xyz/openbmc_project/inventory/system/" | |
| "chassis/chassis0/NetworkAdapters/" | |
| "adapter0/Ports/Port_1"), | |
| "xyz.openbmc_project.Metrics.EthPort", ""); | |
| dbus::utility::DBusPropertiesMap ethProperties; | |
| ethProperties.emplace_back("RXFCSErrors", | |
| dbus::utility::DbusVariantType(uint64_t{3})); | |
| ethProperties.emplace_back("RXAlignmentErrors", | |
| dbus::utility::DbusVariantType(uint64_t{1})); | |
| ethProperties.emplace_back("PauseXOFFFramesReceived", | |
| dbus::utility::DbusVariantType(uint64_t{5})); | |
| EXPECT_TRUE( | |
| mockStore | |
| ->upsertMockObjectIntoManagedStore( | |
| ethKey, managedStore::MockManagedStoreTest::CreateValueType( | |
| ethProperties)) | |
| .ok()); | |
| // 5. Mock IBPort properties | |
| managedStore::KeyType ibKey( | |
| ManagedType::kManagedPropertyMap, "xyz.openbmc_project.NSM", | |
| sdbusplus::message::object_path("/xyz/openbmc_project/inventory/system/" | |
| "chassis/chassis0/NetworkAdapters/" | |
| "adapter0/Ports/Port_1"), | |
| "xyz.openbmc_project.Metrics.IBPort", ""); | |
| dbus::utility::DBusPropertiesMap ibProperties; | |
| ibProperties.emplace_back("BitErrorRate", | |
| dbus::utility::DbusVariantType(double{1e-12})); | |
| ibProperties.emplace_back("LinkDownCount", | |
| dbus::utility::DbusVariantType(uint64_t{2})); | |
| EXPECT_TRUE( | |
| mockStore | |
| ->upsertMockObjectIntoManagedStore( | |
| ibKey, | |
| managedStore::MockManagedStoreTest::CreateValueType(ibProperties)) | |
| .ok()); | |
| // 6. Mock PortMetricsOem2 properties | |
| managedStore::KeyType oem2Key( | |
| ManagedType::kManagedPropertyMap, "xyz.openbmc_project.NSM", | |
| sdbusplus::message::object_path("/xyz/openbmc_project/inventory/system/" | |
| "chassis/chassis0/NetworkAdapters/" | |
| "adapter0/Ports/Port_1"), | |
| "xyz.openbmc_project.Metrics.PortMetricsOem2", ""); | |
| dbus::utility::DBusPropertiesMap oem2Properties; | |
| oem2Properties.emplace_back( | |
| "RXBytes", dbus::utility::DbusVariantType(uint64_t{1048576})); | |
| oem2Properties.emplace_back( | |
| "TXBytes", dbus::utility::DbusVariantType(uint64_t{2097152})); | |
| EXPECT_TRUE( | |
| mockStore | |
| ->upsertMockObjectIntoManagedStore( | |
| oem2Key, managedStore::MockManagedStoreTest::CreateValueType( | |
| oem2Properties)) | |
| .ok()); | |
| // 7. Mock PCIeECC properties | |
| managedStore::KeyType pcieKey( | |
| ManagedType::kManagedPropertyMap, "xyz.openbmc_project.NSM", | |
| sdbusplus::message::object_path("/xyz/openbmc_project/inventory/system/" | |
| "chassis/chassis0/NetworkAdapters/" | |
| "adapter0/Ports/Port_1"), | |
| "xyz.openbmc_project.PCIe.PCIeECC", ""); | |
| dbus::utility::DBusPropertiesMap pcieProperties; | |
| pcieProperties.emplace_back("ceCount", | |
| dbus::utility::DbusVariantType(uint64_t{9})); | |
| pcieProperties.emplace_back("ueCount", | |
| dbus::utility::DbusVariantType(uint64_t{0})); | |
| EXPECT_TRUE( | |
| mockStore | |
| ->upsertMockObjectIntoManagedStore( | |
| pcieKey, managedStore::MockManagedStoreTest::CreateValueType( | |
| pcieProperties)) | |
| .ok()); | |
| handleNetworkPortMetricGetDBus(share_async_resp_, "chassis0", "adapter0", | |
| "Port_1"); | |
| RunIoUntilDone(); | |
| nlohmann::json& json = share_async_resp_->res.jsonValue; | |
| EXPECT_EQ( | |
| json["@odata.id"], | |
| "/redfish/v1/Chassis/chassis0/NetworkAdapters/adapter0/Ports/Port_1/" | |
| "Metrics"); | |
| EXPECT_EQ(json["@odata.type"], "#PortMetrics.v1_3_0.PortMetrics"); | |
| EXPECT_EQ(json["Name"], "Port_1 Metrics"); | |
| EXPECT_EQ(json["Id"], "Metrics"); | |
| EXPECT_EQ(json["CorrectableBitErrors"], 42); | |
| EXPECT_EQ(json["SymbolErrors"], 7); | |
| EXPECT_EQ(json["RXBroadcastPackets"], 100); | |
| EXPECT_EQ(json["RXMulticastPackets"], 200); | |
| EXPECT_EQ(json["RXUnicastPackets"], 300); | |
| EXPECT_EQ(json["TXBroadcastPackets"], 400); | |
| EXPECT_EQ(json["TXMulticastPackets"], 500); | |
| EXPECT_EQ(json["TXUnicastPackets"], 600); | |
| EXPECT_EQ(json["RXFCSErrors"], 3); | |
| EXPECT_EQ(json["RXAlignmentErrors"], 1); | |
| EXPECT_EQ(json["RXBytes"], 1048576); | |
| EXPECT_EQ(json["TXBytes"], 2097152); | |
| EXPECT_EQ(json["Oem"]["Google"]["TransceiverTelemetry"]["FECCorrectedCount"], | |
| 42); | |
| EXPECT_EQ( | |
| json["Oem"]["Google"]["TransceiverTelemetry"]["FECUncorrectableCount"], | |
| 7); | |
| EXPECT_EQ(json["Oem"]["Google"]["TransceiverTelemetry"]["PerLaneFECCounters"], | |
| (std::vector<uint64_t>{10, 20, 30, 40})); | |
| EXPECT_DOUBLE_EQ(json["Oem"]["Google"]["TransceiverTelemetry"]["BitErrorRate"] | |
| .get<double>(), | |
| 1e-12); | |
| EXPECT_EQ(json["LinkDownCount"], 2); | |
| EXPECT_EQ(json["Oem"]["Google"]["PCIeErrors"]["ceCount"], 9); | |
| EXPECT_EQ(json["Oem"]["Google"]["PCIeErrors"]["ueCount"], 0); | |
| } | |
| TEST_F(NetworkAdapterTest, GetNetworkPortDBusParallelMergedPldmPriority) { | |
| auto* mockStore = | |
| dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( | |
| managedStore::GetManagedObjectStore()); | |
| ASSERT_NE(mockStore, nullptr); | |
| // 1. Mock Mapper GetSubTree returning both PLDM and NSM endpoints | |
| managedStore::KeyType portSubTreeKey( | |
| ManagedType::kManagedSubtree, "/xyz/openbmc_project/inventory", 0, | |
| {"xyz.openbmc_project.Inventory.Item.Port"}); | |
| dbus::utility::MapperGetSubTreeResponse subtree = { | |
| {"/xyz/openbmc_project/inventory/system/chassis/chassis0/adapter0/Port_1", | |
| {{"xyz.openbmc_project.PLDM", | |
| {"xyz.openbmc_project.Inventory.Item.Port"}}}}, | |
| {"/xyz/openbmc_project/inventory/system/chassis/chassis0/NetworkAdapters/" | |
| "adapter0/Ports/Port_1", | |
| {{"xyz.openbmc_project.NSM", | |
| {"xyz.openbmc_project.Inventory.Item.Port"}}}}}; | |
| EXPECT_TRUE( | |
| mockStore | |
| ->upsertMockObjectIntoManagedStore( | |
| portSubTreeKey, | |
| managedStore::MockManagedStoreTest::CreateValueType(subtree)) | |
| .ok()); | |
| // 2. Mock PLDM port properties (authoritative for link telemetry) | |
| managedStore::KeyType pldmPropKey( | |
| ManagedType::kManagedPropertyMap, "xyz.openbmc_project.PLDM", | |
| sdbusplus::message::object_path( | |
| "/xyz/openbmc_project/inventory/system/chassis/chassis0/adapter0/" | |
| "Port_1"), | |
| "xyz.openbmc_project.Inventory.Item.Port", ""); | |
| dbus::utility::DBusPropertiesMap pldmProps; | |
| pldmProps.emplace_back( | |
| "LinkState", dbus::utility::DbusVariantType(std::string("Enabled"))); | |
| pldmProps.emplace_back("LinkStatus", | |
| dbus::utility::DbusVariantType(std::string("LinkUp"))); | |
| pldmProps.emplace_back("CurrentSpeedGbps", | |
| dbus::utility::DbusVariantType(double{200.0})); | |
| pldmProps.emplace_back("PortNumber", | |
| dbus::utility::DbusVariantType(uint32_t{0})); | |
| EXPECT_TRUE( | |
| mockStore | |
| ->upsertMockObjectIntoManagedStore( | |
| pldmPropKey, | |
| managedStore::MockManagedStoreTest::CreateValueType(pldmProps)) | |
| .ok()); | |
| // 3. Mock NSM port properties (empty/unpopulated link telemetry, valid | |
| // PortNumber) | |
| managedStore::KeyType nsmPropKey( | |
| ManagedType::kManagedPropertyMap, "xyz.openbmc_project.NSM", | |
| sdbusplus::message::object_path("/xyz/openbmc_project/inventory/system/" | |
| "chassis/chassis0/NetworkAdapters/" | |
| "adapter0/Ports/Port_1"), | |
| "xyz.openbmc_project.Inventory.Item.Port", ""); | |
| dbus::utility::DBusPropertiesMap nsmProps; | |
| nsmProps.emplace_back("LinkState", | |
| dbus::utility::DbusVariantType(std::string(""))); | |
| nsmProps.emplace_back("LinkStatus", | |
| dbus::utility::DbusVariantType(std::string(""))); | |
| nsmProps.emplace_back("CurrentSpeedGbps", | |
| dbus::utility::DbusVariantType(double{0.0})); | |
| nsmProps.emplace_back("PortNumber", | |
| dbus::utility::DbusVariantType(uint32_t{1})); | |
| EXPECT_TRUE( | |
| mockStore | |
| ->upsertMockObjectIntoManagedStore( | |
| nsmPropKey, | |
| managedStore::MockManagedStoreTest::CreateValueType(nsmProps)) | |
| .ok()); | |
| // 4. Mock Port LocationCode decorator (from PortLocationCodeMap) | |
| managedStore::KeyType portLocCodeKey( | |
| ManagedType::kManagedProperty, "xyz.openbmc_project.NSM", | |
| sdbusplus::message::object_path("/xyz/openbmc_project/inventory/system/" | |
| "chassis/chassis0/NetworkAdapters/" | |
| "adapter0/Ports/Port_1"), | |
| "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode"); | |
| EXPECT_TRUE( | |
| mockStore | |
| ->upsertMockObjectIntoManagedStore( | |
| portLocCodeKey, | |
| managedStore::MockManagedStoreTest::CreateValueType( | |
| dbus::utility::DbusVariantType(std::string("port0_dev")))) | |
| .ok()); | |
| // 5. Mock chassis paths | |
| managedStore::KeyType chassisPathsKey( | |
| ManagedType::kManagedSubtreePaths, "/xyz/openbmc_project/inventory", 0, | |
| {"xyz.openbmc_project.Inventory.Item.Board", | |
| "xyz.openbmc_project.Inventory.Item.Chassis"}); | |
| std::vector<std::string> chassisPaths = { | |
| "/xyz/openbmc_project/inventory/system/chassis/chassis0"}; | |
| EXPECT_TRUE( | |
| mockStore | |
| ->upsertMockObjectIntoManagedStore( | |
| chassisPathsKey, | |
| managedStore::MockManagedStoreTest::CreateValueType(chassisPaths)) | |
| .ok()); | |
| // 6. Mock chassis object interfaces | |
| managedStore::KeyType chassisObjKey( | |
| ManagedType::kManagedMapperObject, | |
| "/xyz/openbmc_project/inventory/system/chassis/chassis0", | |
| std::vector<std::string>{ | |
| "xyz.openbmc_project.Inventory.Decorator.LocationCode", | |
| "xyz.openbmc_project.Inventory.Decorator.Location"}); | |
| dbus::utility::MapperGetObject chassisObj = { | |
| {"xyz.openbmc_project.NSM", | |
| {"xyz.openbmc_project.Inventory.Decorator.LocationCode", | |
| "xyz.openbmc_project.Inventory.Decorator.Location"}}}; | |
| EXPECT_TRUE( | |
| mockStore | |
| ->upsertMockObjectIntoManagedStore( | |
| chassisObjKey, | |
| managedStore::MockManagedStoreTest::CreateValueType(chassisObj)) | |
| .ok()); | |
| // 7. Mock chassis LocationCode and LocationType | |
| managedStore::KeyType chassisLocCodeKey( | |
| ManagedType::kManagedProperty, "xyz.openbmc_project.NSM", | |
| sdbusplus::message::object_path( | |
| "/xyz/openbmc_project/inventory/system/chassis/chassis0"), | |
| "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode"); | |
| EXPECT_TRUE( | |
| mockStore | |
| ->upsertMockObjectIntoManagedStore( | |
| chassisLocCodeKey, | |
| managedStore::MockManagedStoreTest::CreateValueType( | |
| dbus::utility::DbusVariantType(std::string("chassis0_loc")))) | |
| .ok()); | |
| managedStore::KeyType chassisLocTypeKey( | |
| ManagedType::kManagedProperty, "xyz.openbmc_project.NSM", | |
| sdbusplus::message::object_path( | |
| "/xyz/openbmc_project/inventory/system/chassis/chassis0"), | |
| "xyz.openbmc_project.Inventory.Decorator.Location", "LocationType"); | |
| EXPECT_TRUE(mockStore | |
| ->upsertMockObjectIntoManagedStore( | |
| chassisLocTypeKey, | |
| managedStore::MockManagedStoreTest::CreateValueType( | |
| dbus::utility::DbusVariantType(std::string( | |
| "xyz.openbmc_project.Inventory.Decorator." | |
| "Location.LocationTypes.Embedded")))) | |
| .ok()); | |
| // 8. Mock chassis0 contained_by -> carrier_board | |
| managedStore::KeyType chassisContainedByKey( | |
| ManagedType::kManagedAssociatedSubtree, | |
| "/xyz/openbmc_project/inventory/system/chassis/chassis0/contained_by", | |
| "/xyz/openbmc_project/inventory", 0, | |
| {"xyz.openbmc_project.Inventory.Item.Board", | |
| "xyz.openbmc_project.Inventory.Item.Chassis"}); | |
| dbus::utility::MapperGetSubTreeResponse chassisContainedBy = { | |
| {"/xyz/openbmc_project/inventory/system/board/carrier_board", | |
| {{"xyz.openbmc_project.EntityManager", | |
| {"xyz.openbmc_project.Inventory.Item.Board"}}}}}; | |
| EXPECT_TRUE(mockStore | |
| ->upsertMockObjectIntoManagedStore( | |
| chassisContainedByKey, | |
| managedStore::MockManagedStoreTest::CreateValueType( | |
| chassisContainedBy)) | |
| .ok()); | |
| // 9. Mock carrier_board LocationCode | |
| managedStore::KeyType carrierLocCodeKey( | |
| ManagedType::kManagedProperty, "xyz.openbmc_project.EntityManager", | |
| sdbusplus::message::object_path( | |
| "/xyz/openbmc_project/inventory/system/board/carrier_board"), | |
| "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode"); | |
| EXPECT_TRUE( | |
| mockStore | |
| ->upsertMockObjectIntoManagedStore( | |
| carrierLocCodeKey, | |
| managedStore::MockManagedStoreTest::CreateValueType( | |
| dbus::utility::DbusVariantType(std::string("CARRIER")))) | |
| .ok()); | |
| // 10. Mock carrier_board contained_by -> system_board | |
| managedStore::KeyType carrierContainedByKey( | |
| ManagedType::kManagedAssociatedSubtree, | |
| "/xyz/openbmc_project/inventory/system/board/carrier_board/contained_by", | |
| "/xyz/openbmc_project/inventory", 0, | |
| {"xyz.openbmc_project.Inventory.Item.Board", | |
| "xyz.openbmc_project.Inventory.Item.Chassis"}); | |
| dbus::utility::MapperGetSubTreeResponse carrierContainedBy = { | |
| {"/xyz/openbmc_project/inventory/system/board/system_board", | |
| {{"xyz.openbmc_project.EntityManager", | |
| {"xyz.openbmc_project.Inventory.Item.Board"}}}}}; | |
| EXPECT_TRUE(mockStore | |
| ->upsertMockObjectIntoManagedStore( | |
| carrierContainedByKey, | |
| managedStore::MockManagedStoreTest::CreateValueType( | |
| carrierContainedBy)) | |
| .ok()); | |
| // 11. Mock system_board LocationCode | |
| managedStore::KeyType systemBoardLocCodeKey( | |
| ManagedType::kManagedProperty, "xyz.openbmc_project.EntityManager", | |
| sdbusplus::message::object_path( | |
| "/xyz/openbmc_project/inventory/system/board/system_board"), | |
| "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode"); | |
| EXPECT_TRUE( | |
| mockStore | |
| ->upsertMockObjectIntoManagedStore( | |
| systemBoardLocCodeKey, | |
| managedStore::MockManagedStoreTest::CreateValueType( | |
| dbus::utility::DbusVariantType(std::string("SYSTEM_PLANE")))) | |
| .ok()); | |
| // 12. Mock system_board contained_by -> empty | |
| managedStore::KeyType systemBoardContainedByKey( | |
| ManagedType::kManagedAssociatedSubtree, | |
| "/xyz/openbmc_project/inventory/system/board/system_board/contained_by", | |
| "/xyz/openbmc_project/inventory", 0, | |
| {"xyz.openbmc_project.Inventory.Item.Board", | |
| "xyz.openbmc_project.Inventory.Item.Chassis"}); | |
| dbus::utility::MapperGetSubTreeResponse systemBoardContainedBy = {}; | |
| EXPECT_TRUE(mockStore | |
| ->upsertMockObjectIntoManagedStore( | |
| systemBoardContainedByKey, | |
| managedStore::MockManagedStoreTest::CreateValueType( | |
| systemBoardContainedBy)) | |
| .ok()); | |
| // 13. Mock system_board attached_cables -> empty | |
| managedStore::KeyType attachedCablesKey( | |
| ManagedType::kManagedProperty, "xyz.openbmc_project.ObjectMapper", | |
| sdbusplus::message::object_path( | |
| "/xyz/openbmc_project/inventory/system/board/system_board/" | |
| "attached_cables"), | |
| "xyz.openbmc_project.Association", "endpoints"); | |
| std::vector<std::string> emptyCables; | |
| EXPECT_TRUE(mockStore | |
| ->upsertMockObjectIntoManagedStore( | |
| attachedCablesKey, | |
| managedStore::MockManagedStoreTest::CreateValueType( | |
| dbus::utility::DbusVariantType(emptyCables))) | |
| .ok()); | |
| handleNetworkPortGetDBus(share_async_resp_, "chassis0", "adapter0", "Port_1"); | |
| RunIoUntilDone(); | |
| nlohmann::json& json = share_async_resp_->res.jsonValue; | |
| EXPECT_EQ( | |
| json["@odata.id"], | |
| "/redfish/v1/Chassis/chassis0/NetworkAdapters/adapter0/Ports/Port_1"); | |
| EXPECT_EQ(json["Id"], "Port_1"); | |
| EXPECT_EQ(json["Name"], "Port_1"); | |
| EXPECT_EQ(json["Status"]["State"], "Enabled"); | |
| EXPECT_EQ(json["Status"]["Health"], "OK"); | |
| EXPECT_EQ(json["Location"]["PartLocation"]["ServiceLabel"], "port0_dev"); | |
| EXPECT_EQ(json["Location"]["PartLocation"]["LocationType"], "Embedded"); | |
| EXPECT_EQ(json["Location"]["PartLocationContext"], "SYSTEM_PLANE/CARRIER"); | |
| EXPECT_EQ(json["Location"]["Oem"]["Google"]["Devpath"], | |
| "/phys/SYSTEM_PLANE/CARRIER:device:port0_dev"); | |
| EXPECT_EQ(json["LinkState"], "Enabled"); | |
| EXPECT_EQ(json["LinkStatus"], "LinkUp"); | |
| EXPECT_DOUBLE_EQ(json["CurrentSpeedGbps"].get<double>(), 200.0); | |
| EXPECT_EQ(json["Metrics"]["@odata.id"], | |
| "/redfish/v1/Chassis/chassis0/NetworkAdapters/adapter0/Ports/" | |
| "Port_1/Metrics"); | |
| } | |
| TEST_F(NetworkAdapterTest, GetNetworkPortDBusPldmOnly) { | |
| auto* mockStore = | |
| dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( | |
| managedStore::GetManagedObjectStore()); | |
| ASSERT_NE(mockStore, nullptr); | |
| managedStore::KeyType portSubTreeKey( | |
| ManagedType::kManagedSubtree, "/xyz/openbmc_project/inventory", 0, | |
| {"xyz.openbmc_project.Inventory.Item.Port"}); | |
| dbus::utility::MapperGetSubTreeResponse subtree = { | |
| {"/xyz/openbmc_project/inventory/system/chassis/chassis0/adapter0/Port_1", | |
| {{"xyz.openbmc_project.PLDM", | |
| {"xyz.openbmc_project.Inventory.Item.Port"}}}}}; | |
| EXPECT_TRUE( | |
| mockStore | |
| ->upsertMockObjectIntoManagedStore( | |
| portSubTreeKey, | |
| managedStore::MockManagedStoreTest::CreateValueType(subtree)) | |
| .ok()); | |
| managedStore::KeyType pldmPropKey( | |
| ManagedType::kManagedPropertyMap, "xyz.openbmc_project.PLDM", | |
| sdbusplus::message::object_path( | |
| "/xyz/openbmc_project/inventory/system/chassis/chassis0/adapter0/" | |
| "Port_1"), | |
| "xyz.openbmc_project.Inventory.Item.Port", ""); | |
| dbus::utility::DBusPropertiesMap pldmProps; | |
| pldmProps.emplace_back( | |
| "LinkState", dbus::utility::DbusVariantType(std::string("Enabled"))); | |
| pldmProps.emplace_back("LinkStatus", | |
| dbus::utility::DbusVariantType(std::string("LinkUp"))); | |
| pldmProps.emplace_back("CurrentSpeedGbps", | |
| dbus::utility::DbusVariantType(double{100.0})); | |
| EXPECT_TRUE( | |
| mockStore | |
| ->upsertMockObjectIntoManagedStore( | |
| pldmPropKey, | |
| managedStore::MockManagedStoreTest::CreateValueType(pldmProps)) | |
| .ok()); | |
| handleNetworkPortGetDBus(share_async_resp_, "chassis0", "adapter0", "Port_1"); | |
| RunIoUntilDone(); | |
| nlohmann::json& json = share_async_resp_->res.jsonValue; | |
| EXPECT_EQ(json["Status"]["State"], "Enabled"); | |
| EXPECT_EQ(json["Status"]["Health"], "OK"); | |
| EXPECT_EQ(json["LinkState"], "Enabled"); | |
| EXPECT_EQ(json["LinkStatus"], "LinkUp"); | |
| EXPECT_DOUBLE_EQ(json["CurrentSpeedGbps"].get<double>(), 100.0); | |
| } | |
| TEST_F(NetworkAdapterTest, GetNetworkPortDBusPldmPriorityOverNonEmptyNsm) { | |
| auto* mockStore = | |
| dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( | |
| managedStore::GetManagedObjectStore()); | |
| ASSERT_NE(mockStore, nullptr); | |
| // 1. Mock Mapper GetSubTree returning both PLDM and NSM endpoints | |
| managedStore::KeyType portSubTreeKey( | |
| ManagedType::kManagedSubtree, "/xyz/openbmc_project/inventory", 0, | |
| {"xyz.openbmc_project.Inventory.Item.Port"}); | |
| dbus::utility::MapperGetSubTreeResponse subtree = { | |
| {"/xyz/openbmc_project/inventory/system/chassis/chassis0/adapter0/Port_1", | |
| {{"xyz.openbmc_project.PLDM", | |
| {"xyz.openbmc_project.Inventory.Item.Port"}}}}, | |
| {"/xyz/openbmc_project/inventory/system/chassis/chassis0/NetworkAdapters/" | |
| "adapter0/Ports/Port_1", | |
| {{"xyz.openbmc_project.NSM", | |
| {"xyz.openbmc_project.Inventory.Item.Port"}}}}}; | |
| EXPECT_TRUE( | |
| mockStore | |
| ->upsertMockObjectIntoManagedStore( | |
| portSubTreeKey, | |
| managedStore::MockManagedStoreTest::CreateValueType(subtree)) | |
| .ok()); | |
| // 2. Mock PLDM port properties (authoritative for base link telemetry) | |
| managedStore::KeyType pldmPropKey( | |
| ManagedType::kManagedPropertyMap, "xyz.openbmc_project.PLDM", | |
| sdbusplus::message::object_path( | |
| "/xyz/openbmc_project/inventory/system/chassis/chassis0/adapter0/" | |
| "Port_1"), | |
| "xyz.openbmc_project.Inventory.Item.Port", ""); | |
| dbus::utility::DBusPropertiesMap pldmProps; | |
| pldmProps.emplace_back( | |
| "LinkState", dbus::utility::DbusVariantType(std::string("Enabled"))); | |
| pldmProps.emplace_back("LinkStatus", | |
| dbus::utility::DbusVariantType(std::string("LinkUp"))); | |
| pldmProps.emplace_back("CurrentSpeedGbps", | |
| dbus::utility::DbusVariantType(double{100.0})); | |
| EXPECT_TRUE( | |
| mockStore | |
| ->upsertMockObjectIntoManagedStore( | |
| pldmPropKey, | |
| managedStore::MockManagedStoreTest::CreateValueType(pldmProps)) | |
| .ok()); | |
| // 3. Mock NSM port properties with conflicting non-empty link telemetry | |
| managedStore::KeyType nsmPropKey( | |
| ManagedType::kManagedPropertyMap, "xyz.openbmc_project.NSM", | |
| sdbusplus::message::object_path("/xyz/openbmc_project/inventory/system/" | |
| "chassis/chassis0/NetworkAdapters/" | |
| "adapter0/Ports/Port_1"), | |
| "xyz.openbmc_project.Inventory.Item.Port", ""); | |
| dbus::utility::DBusPropertiesMap nsmProps; | |
| nsmProps.emplace_back( | |
| "LinkState", dbus::utility::DbusVariantType(std::string("Disabled"))); | |
| nsmProps.emplace_back( | |
| "LinkStatus", dbus::utility::DbusVariantType(std::string("LinkDown"))); | |
| nsmProps.emplace_back("CurrentSpeedGbps", | |
| dbus::utility::DbusVariantType(double{400.0})); | |
| EXPECT_TRUE( | |
| mockStore | |
| ->upsertMockObjectIntoManagedStore( | |
| nsmPropKey, | |
| managedStore::MockManagedStoreTest::CreateValueType(nsmProps)) | |
| .ok()); | |
| handleNetworkPortGetDBus(share_async_resp_, "chassis0", "adapter0", "Port_1"); | |
| RunIoUntilDone(); | |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); | |
| nlohmann::json& json = share_async_resp_->res.jsonValue; | |
| EXPECT_EQ(json["Status"]["State"], "Enabled"); | |
| EXPECT_EQ(json["Status"]["Health"], "OK"); | |
| EXPECT_EQ(json["LinkState"], "Enabled"); | |
| EXPECT_EQ(json["LinkStatus"], "LinkUp"); | |
| EXPECT_DOUBLE_EQ(json["CurrentSpeedGbps"].get<double>(), 100.0); | |
| } | |
| TEST_F(NetworkAdapterTest, | |
| GetNetworkPortDBusMissingPropertiesReturnsInternalError) { | |
| auto* mockStore = | |
| dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( | |
| managedStore::GetManagedObjectStore()); | |
| ASSERT_NE(mockStore, nullptr); | |
| managedStore::KeyType portSubTreeKey( | |
| ManagedType::kManagedSubtree, "/xyz/openbmc_project/inventory", 0, | |
| {"xyz.openbmc_project.Inventory.Item.Port"}); | |
| dbus::utility::MapperGetSubTreeResponse subtree = { | |
| {"/xyz/openbmc_project/inventory/system/chassis/chassis0/NetworkAdapters/" | |
| "adapter0/Ports/Port_1", | |
| {{"xyz.openbmc_project.NSM", | |
| {"xyz.openbmc_project.Inventory.Item.Port"}}}}}; | |
| EXPECT_TRUE( | |
| mockStore | |
| ->upsertMockObjectIntoManagedStore( | |
| portSubTreeKey, | |
| managedStore::MockManagedStoreTest::CreateValueType(subtree)) | |
| .ok()); | |
| managedStore::KeyType nsmPropKey( | |
| ManagedType::kManagedPropertyMap, "xyz.openbmc_project.NSM", | |
| sdbusplus::message::object_path("/xyz/openbmc_project/inventory/system/" | |
| "chassis/chassis0/NetworkAdapters/" | |
| "adapter0/Ports/Port_1"), | |
| "xyz.openbmc_project.Inventory.Item.Port", ""); | |
| dbus::utility::DBusPropertiesMap nsmProps; | |
| nsmProps.emplace_back("LinkState", | |
| dbus::utility::DbusVariantType(std::string(""))); | |
| nsmProps.emplace_back("LinkStatus", | |
| dbus::utility::DbusVariantType(std::string(""))); | |
| EXPECT_TRUE( | |
| mockStore | |
| ->upsertMockObjectIntoManagedStore( | |
| nsmPropKey, | |
| managedStore::MockManagedStoreTest::CreateValueType(nsmProps)) | |
| .ok()); | |
| handleNetworkPortGetDBus(share_async_resp_, "chassis0", "adapter0", "Port_1"); | |
| RunIoUntilDone(); | |
| EXPECT_EQ(share_async_resp_->res.result(), | |
| boost::beast::http::status::internal_server_error); | |
| } | |
| TEST_F(NetworkAdapterTest, GetNetworkPortDBusPldmMissingFallsBackToNsm) { | |
| auto* mockStore = | |
| dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( | |
| managedStore::GetManagedObjectStore()); | |
| ASSERT_NE(mockStore, nullptr); | |
| managedStore::KeyType portSubTreeKey( | |
| ManagedType::kManagedSubtree, "/xyz/openbmc_project/inventory", 0, | |
| {"xyz.openbmc_project.Inventory.Item.Port"}); | |
| dbus::utility::MapperGetSubTreeResponse subtree = { | |
| {"/xyz/openbmc_project/inventory/system/chassis/chassis0/adapter0/Port_1", | |
| {{"xyz.openbmc_project.PLDM", | |
| {"xyz.openbmc_project.Inventory.Item.Port"}}}}, | |
| {"/xyz/openbmc_project/inventory/system/chassis/chassis0/NetworkAdapters/" | |
| "adapter0/Ports/Port_1", | |
| {{"xyz.openbmc_project.NSM", | |
| {"xyz.openbmc_project.Inventory.Item.Port"}}}}}; | |
| EXPECT_TRUE( | |
| mockStore | |
| ->upsertMockObjectIntoManagedStore( | |
| portSubTreeKey, | |
| managedStore::MockManagedStoreTest::CreateValueType(subtree)) | |
| .ok()); | |
| // PLDM has empty properties (fails to provide telemetry) | |
| managedStore::KeyType pldmPropKey( | |
| ManagedType::kManagedPropertyMap, "xyz.openbmc_project.PLDM", | |
| sdbusplus::message::object_path( | |
| "/xyz/openbmc_project/inventory/system/chassis/chassis0/adapter0/" | |
| "Port_1"), | |
| "xyz.openbmc_project.Inventory.Item.Port", ""); | |
| dbus::utility::DBusPropertiesMap pldmProps; | |
| pldmProps.emplace_back("LinkState", | |
| dbus::utility::DbusVariantType(std::string(""))); | |
| pldmProps.emplace_back("LinkStatus", | |
| dbus::utility::DbusVariantType(std::string(""))); | |
| pldmProps.emplace_back("CurrentSpeedGbps", | |
| dbus::utility::DbusVariantType(double{0.0})); | |
| EXPECT_TRUE( | |
| mockStore | |
| ->upsertMockObjectIntoManagedStore( | |
| pldmPropKey, | |
| managedStore::MockManagedStoreTest::CreateValueType(pldmProps)) | |
| .ok()); | |
| // NSM has valid properties (provides fallback telemetry) | |
| managedStore::KeyType nsmPropKey( | |
| ManagedType::kManagedPropertyMap, "xyz.openbmc_project.NSM", | |
| sdbusplus::message::object_path("/xyz/openbmc_project/inventory/system/" | |
| "chassis/chassis0/NetworkAdapters/" | |
| "adapter0/Ports/Port_1"), | |
| "xyz.openbmc_project.Inventory.Item.Port", ""); | |
| dbus::utility::DBusPropertiesMap nsmProps; | |
| nsmProps.emplace_back("LinkState", | |
| dbus::utility::DbusVariantType(std::string("Enabled"))); | |
| nsmProps.emplace_back("LinkStatus", | |
| dbus::utility::DbusVariantType(std::string("LinkUp"))); | |
| nsmProps.emplace_back("CurrentSpeedGbps", | |
| dbus::utility::DbusVariantType(double{200.0})); | |
| EXPECT_TRUE( | |
| mockStore | |
| ->upsertMockObjectIntoManagedStore( | |
| nsmPropKey, | |
| managedStore::MockManagedStoreTest::CreateValueType(nsmProps)) | |
| .ok()); | |
| handleNetworkPortGetDBus(share_async_resp_, "chassis0", "adapter0", "Port_1"); | |
| RunIoUntilDone(); | |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); | |
| nlohmann::json& json = share_async_resp_->res.jsonValue; | |
| EXPECT_EQ(json["LinkState"], "Enabled"); | |
| EXPECT_EQ(json["LinkStatus"], "LinkUp"); | |
| EXPECT_DOUBLE_EQ(json["CurrentSpeedGbps"].get<double>(), 200.0); | |
| } | |
| TEST_F(NetworkAdapterTest, GetNetworkPortDBusBothMissingReturnsInternalError) { | |
| auto* mockStore = | |
| dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( | |
| managedStore::GetManagedObjectStore()); | |
| ASSERT_NE(mockStore, nullptr); | |
| managedStore::KeyType portSubTreeKey( | |
| ManagedType::kManagedSubtree, "/xyz/openbmc_project/inventory", 0, | |
| {"xyz.openbmc_project.Inventory.Item.Port"}); | |
| dbus::utility::MapperGetSubTreeResponse subtree = { | |
| {"/xyz/openbmc_project/inventory/system/chassis/chassis0/adapter0/Port_1", | |
| {{"xyz.openbmc_project.PLDM", | |
| {"xyz.openbmc_project.Inventory.Item.Port"}}}}, | |
| {"/xyz/openbmc_project/inventory/system/chassis/chassis0/NetworkAdapters/" | |
| "adapter0/Ports/Port_1", | |
| {{"xyz.openbmc_project.NSM", | |
| {"xyz.openbmc_project.Inventory.Item.Port"}}}}}; | |
| EXPECT_TRUE( | |
| mockStore | |
| ->upsertMockObjectIntoManagedStore( | |
| portSubTreeKey, | |
| managedStore::MockManagedStoreTest::CreateValueType(subtree)) | |
| .ok()); | |
| // Both PLDM and NSM have empty properties | |
| managedStore::KeyType pldmPropKey( | |
| ManagedType::kManagedPropertyMap, "xyz.openbmc_project.PLDM", | |
| sdbusplus::message::object_path( | |
| "/xyz/openbmc_project/inventory/system/chassis/chassis0/adapter0/" | |
| "Port_1"), | |
| "xyz.openbmc_project.Inventory.Item.Port", ""); | |
| dbus::utility::DBusPropertiesMap pldmProps; | |
| pldmProps.emplace_back("LinkState", | |
| dbus::utility::DbusVariantType(std::string(""))); | |
| pldmProps.emplace_back("LinkStatus", | |
| dbus::utility::DbusVariantType(std::string(""))); | |
| pldmProps.emplace_back("CurrentSpeedGbps", | |
| dbus::utility::DbusVariantType(double{0.0})); | |
| EXPECT_TRUE( | |
| mockStore | |
| ->upsertMockObjectIntoManagedStore( | |
| pldmPropKey, | |
| managedStore::MockManagedStoreTest::CreateValueType(pldmProps)) | |
| .ok()); | |
| managedStore::KeyType nsmPropKey( | |
| ManagedType::kManagedPropertyMap, "xyz.openbmc_project.NSM", | |
| sdbusplus::message::object_path("/xyz/openbmc_project/inventory/system/" | |
| "chassis/chassis0/NetworkAdapters/" | |
| "adapter0/Ports/Port_1"), | |
| "xyz.openbmc_project.Inventory.Item.Port", ""); | |
| dbus::utility::DBusPropertiesMap nsmProps; | |
| nsmProps.emplace_back("LinkState", | |
| dbus::utility::DbusVariantType(std::string(""))); | |
| nsmProps.emplace_back("LinkStatus", | |
| dbus::utility::DbusVariantType(std::string(""))); | |
| nsmProps.emplace_back("CurrentSpeedGbps", | |
| dbus::utility::DbusVariantType(double{0.0})); | |
| EXPECT_TRUE( | |
| mockStore | |
| ->upsertMockObjectIntoManagedStore( | |
| nsmPropKey, | |
| managedStore::MockManagedStoreTest::CreateValueType(nsmProps)) | |
| .ok()); | |
| handleNetworkPortGetDBus(share_async_resp_, "chassis0", "adapter0", "Port_1"); | |
| RunIoUntilDone(); | |
| EXPECT_EQ(share_async_resp_->res.result(), | |
| boost::beast::http::status::internal_server_error); | |
| } | |
| TEST_F(NetworkAdapterTest, | |
| NetworkAdapterCollectionDBusDeduplicatesMultipleEndpoints) { | |
| auto* mockStore = | |
| dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( | |
| managedStore::GetManagedObjectStore()); | |
| ASSERT_NE(mockStore, nullptr); | |
| managedStore::KeyType chassisSubTreeKey( | |
| ManagedType::kManagedSubtree, "/xyz/openbmc_project/inventory", 0, | |
| {"xyz.openbmc_project.Inventory.Item.Board", | |
| "xyz.openbmc_project.Inventory.Item.Chassis"}); | |
| dbus::utility::MapperGetSubTreeResponse chassisSubtree = { | |
| {"/xyz/openbmc_project/inventory/system/chassis/chassis0", | |
| {{"xyz.openbmc_project.PLDM", | |
| {"xyz.openbmc_project.Inventory.Item.Board"}}}}}; | |
| EXPECT_TRUE(mockStore | |
| ->upsertMockObjectIntoManagedStore( | |
| chassisSubTreeKey, | |
| managedStore::MockManagedStoreTest::CreateValueType( | |
| chassisSubtree)) | |
| .ok()); | |
| managedStore::KeyType assocKey( | |
| managedStore::ManagedType::kManagedProperty, | |
| "xyz.openbmc_project.ObjectMapper", | |
| sdbusplus::message::object_path("/xyz/openbmc_project/inventory/system/" | |
| "chassis/chassis0/network_adapter"), | |
| "xyz.openbmc_project.Association", "endpoints"); | |
| dbus::utility::MapperEndPoints endpoints = { | |
| "/xyz/openbmc_project/inventory/system/chassis/chassis0/NetworkAdapters/" | |
| "adapter0", | |
| "/xyz/openbmc_project/inventory/system/chassis/chassis0/adapter0"}; | |
| EXPECT_TRUE( | |
| mockStore | |
| ->upsertMockObjectIntoManagedStore( | |
| assocKey, managedStore::MockManagedStoreTest::CreateValueType( | |
| dbus::utility::DbusVariantType(endpoints))) | |
| .ok()); | |
| handleChassisNetworkAdapterCollectionGetDBus(share_async_resp_, "chassis0"); | |
| RunIoUntilDone(); | |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); | |
| nlohmann::json& json = share_async_resp_->res.jsonValue; | |
| EXPECT_EQ(json["@odata.type"], | |
| "#NetworkAdapterCollection.NetworkAdapterCollection"); | |
| EXPECT_EQ(json["Members@odata.count"], 1); | |
| EXPECT_EQ(json["Members"].size(), 1); | |
| EXPECT_EQ(json["Members"][0]["@odata.id"], | |
| "/redfish/v1/Chassis/chassis0/NetworkAdapters/adapter0"); | |
| } | |
| TEST_F(NetworkAdapterTest, | |
| NetworkPortCollectionDBusDeduplicatesMultipleEndpoints) { | |
| auto* mockStore = | |
| dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( | |
| managedStore::GetManagedObjectStore()); | |
| ASSERT_NE(mockStore, nullptr); | |
| managedStore::KeyType adapterSubTreeKey( | |
| ManagedType::kManagedSubtree, "/xyz/openbmc_project/inventory", 0, | |
| {"xyz.openbmc_project.Inventory.Item.NetworkAdapter"}); | |
| dbus::utility::MapperGetSubTreeResponse adapterSubtree = { | |
| {"/xyz/openbmc_project/inventory/system/chassis/chassis0/adapter0", | |
| {{"xyz.openbmc_project.PLDM", | |
| {"xyz.openbmc_project.Inventory.Item.NetworkAdapter"}}}}, | |
| {"/xyz/openbmc_project/inventory/system/chassis/chassis0/NetworkAdapters/" | |
| "adapter0", | |
| {{"xyz.openbmc_project.NSM", | |
| {"xyz.openbmc_project.Inventory.Item.NetworkAdapter"}}}}}; | |
| EXPECT_TRUE(mockStore | |
| ->upsertMockObjectIntoManagedStore( | |
| adapterSubTreeKey, | |
| managedStore::MockManagedStoreTest::CreateValueType( | |
| adapterSubtree)) | |
| .ok()); | |
| managedStore::KeyType pldmAssocKey( | |
| managedStore::ManagedType::kManagedProperty, | |
| "xyz.openbmc_project.ObjectMapper", | |
| sdbusplus::message::object_path( | |
| "/xyz/openbmc_project/inventory/system/chassis/chassis0/adapter0/" | |
| "all_ports"), | |
| "xyz.openbmc_project.Association", "endpoints"); | |
| dbus::utility::MapperEndPoints pldmEndpoints = { | |
| "/xyz/openbmc_project/inventory/system/chassis/chassis0/adapter0/Port_1", | |
| "/xyz/openbmc_project/inventory/system/chassis/chassis0/adapter0/Port_2"}; | |
| EXPECT_TRUE( | |
| mockStore | |
| ->upsertMockObjectIntoManagedStore( | |
| pldmAssocKey, managedStore::MockManagedStoreTest::CreateValueType( | |
| dbus::utility::DbusVariantType(pldmEndpoints))) | |
| .ok()); | |
| managedStore::KeyType nsmAssocKey( | |
| managedStore::ManagedType::kManagedProperty, | |
| "xyz.openbmc_project.ObjectMapper", | |
| sdbusplus::message::object_path("/xyz/openbmc_project/inventory/system/" | |
| "chassis/chassis0/NetworkAdapters/" | |
| "adapter0/all_ports"), | |
| "xyz.openbmc_project.Association", "endpoints"); | |
| dbus::utility::MapperEndPoints nsmEndpoints = { | |
| "/xyz/openbmc_project/inventory/system/chassis/chassis0/NetworkAdapters/" | |
| "adapter0/Ports/Port_1", | |
| "/xyz/openbmc_project/inventory/system/chassis/chassis0/NetworkAdapters/" | |
| "adapter0/Ports/Port_3"}; | |
| EXPECT_TRUE( | |
| mockStore | |
| ->upsertMockObjectIntoManagedStore( | |
| nsmAssocKey, managedStore::MockManagedStoreTest::CreateValueType( | |
| dbus::utility::DbusVariantType(nsmEndpoints))) | |
| .ok()); | |
| handleNetworkPortCollectionGetDBus(share_async_resp_, "chassis0", "adapter0"); | |
| RunIoUntilDone(); | |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); | |
| nlohmann::json& json = share_async_resp_->res.jsonValue; | |
| EXPECT_EQ(json["@odata.type"], "#PortCollection.PortCollection"); | |
| EXPECT_EQ(json["Members@odata.count"], 3); | |
| EXPECT_EQ(json["Members"].size(), 3); | |
| EXPECT_EQ( | |
| json["Members"][0]["@odata.id"], | |
| "/redfish/v1/Chassis/chassis0/NetworkAdapters/adapter0/Ports/Port_1"); | |
| EXPECT_EQ( | |
| json["Members"][1]["@odata.id"], | |
| "/redfish/v1/Chassis/chassis0/NetworkAdapters/adapter0/Ports/Port_2"); | |
| EXPECT_EQ( | |
| json["Members"][2]["@odata.id"], | |
| "/redfish/v1/Chassis/chassis0/NetworkAdapters/adapter0/Ports/Port_3"); | |
| } | |
| TEST(FindPortProviderEndpointsTest, IgnoresEmptyConnectionAndReturnsEndpoints) { | |
| dbus::utility::MapperGetSubTreeResponse subtree = { | |
| {"/xyz/openbmc_project/inventory/system/chassis/chassis0/adapter0/Port_1", | |
| {}}, | |
| {"/xyz/openbmc_project/inventory/system/chassis/chassis0/adapter0/Port_1", | |
| {{"xyz.openbmc_project.PLDM", | |
| {"xyz.openbmc_project.Inventory.Item.Port"}}}}, | |
| {"/xyz/openbmc_project/inventory/system/chassis/chassis0/NetworkAdapters/" | |
| "adapter0/Ports/Port_1", | |
| {{"xyz.openbmc_project.NSM", | |
| {"xyz.openbmc_project.Inventory.Item.Port"}}}}}; | |
| PortProviderEndpoints ep = | |
| findPortProviderEndpoints(subtree, "chassis0", "adapter0", "Port_1"); | |
| EXPECT_EQ( | |
| ep.pldm.first, | |
| "/xyz/openbmc_project/inventory/system/chassis/chassis0/adapter0/Port_1"); | |
| EXPECT_EQ(ep.pldm.second, "xyz.openbmc_project.PLDM"); | |
| EXPECT_EQ( | |
| ep.nsm.first, | |
| "/xyz/openbmc_project/inventory/system/chassis/chassis0/NetworkAdapters/" | |
| "adapter0/Ports/Port_1"); | |
| EXPECT_EQ(ep.nsm.second, "xyz.openbmc_project.NSM"); | |
| } | |
| TEST_F(NetworkAdapterTest, | |
| BuildNetworkPortDBusReturnsNotFoundWhenBothEndpointsEmpty) { | |
| buildNetworkPortDBus(share_async_resp_, "chassis0", "adapter0", "Port_1", | |
| /*pldmEndpoint=*/{"", ""}, /*nsmEndpoint=*/{"", ""}); | |
| EXPECT_EQ(share_async_resp_->res.result(), | |
| boost::beast::http::status::not_found); | |
| } | |
| TEST_F(NetworkAdapterTest, | |
| NetworkPortGetDBusReturnsNotFoundWhenNoMatchingEndpoints) { | |
| auto* mockStore = | |
| dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( | |
| managedStore::GetManagedObjectStore()); | |
| ASSERT_NE(mockStore, nullptr); | |
| managedStore::KeyType portSubTreeKey( | |
| ManagedType::kManagedSubtree, "/xyz/openbmc_project/inventory", 0, | |
| {"xyz.openbmc_project.Inventory.Item.Port"}); | |
| dbus::utility::MapperGetSubTreeResponse subtree = { | |
| {"/xyz/openbmc_project/inventory/system/chassis/chassis0/adapter0/" | |
| "Port_99", | |
| {{"xyz.openbmc_project.PLDM", | |
| {"xyz.openbmc_project.Inventory.Item.Port"}}}}}; | |
| EXPECT_TRUE( | |
| mockStore | |
| ->upsertMockObjectIntoManagedStore( | |
| portSubTreeKey, | |
| managedStore::MockManagedStoreTest::CreateValueType(subtree)) | |
| .ok()); | |
| handleNetworkPortGetDBus(share_async_resp_, "chassis0", "adapter0", "Port_1"); | |
| RunIoUntilDone(); | |
| EXPECT_EQ(share_async_resp_->res.result(), | |
| boost::beast::http::status::not_found); | |
| } | |
| } // namespace | |
| } // namespace redfish |