| #include "src/handler.hpp" |
| |
| #include "src/types.hpp" |
| |
| #include <xyz/openbmc_project/Common/error.hpp> |
| |
| #include <span> |
| #include <utility> |
| #include <vector> |
| |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| |
| using ::testing::ElementsAre; |
| |
| class TestHandler : public testing::Test |
| { |
| protected: |
| InterfaceMapType interfaceMap = { |
| { |
| "/test/object_path_0", |
| {{"test_object_connection_0", {"test_interface_0"}}}, |
| }, |
| { |
| "/test/object_path_0/child", |
| {{"test_object_connection_1", {"test_interface_1"}}}, |
| }, |
| { |
| "/test/object_path_0/child/grandchild", |
| {{"test_object_connection_2", {"test_interface_2"}}}, |
| }, |
| { |
| "/test/object_path_0/child/grandchild/dog", |
| {{"test_object_connection_3", {"test_interface_3"}}}, |
| }}; |
| |
| AssociationMaps associationMap = { |
| .ifaces = |
| { |
| { |
| "/test/object_path_0/descendent", |
| { |
| std::shared_ptr<sdbusplus::asio::dbus_interface>(), |
| { |
| "/test/object_path_0/child", |
| "/test/object_path_0/child/grandchild", |
| }, |
| }, |
| }, |
| { |
| "/test/object_path_0/child/descendent", |
| { |
| std::shared_ptr<sdbusplus::asio::dbus_interface>(), |
| { |
| "/test/object_path_0/child/grandchild", |
| }, |
| }, |
| }, |
| }, |
| .owners = {}, |
| .pending = {}, |
| }; |
| }; |
| |
| TEST_F(TestHandler, AddObjectMapResult) |
| { |
| std::vector<InterfaceMapType::value_type> interfaceMaps; |
| addObjectMapResult(interfaceMaps, "test_object_path", |
| std::pair<std::string, InterfaceNames>( |
| "test_object_connection_0", { |
| "test_interface_0", |
| "test_interface_1", |
| })); |
| |
| addObjectMapResult(interfaceMaps, "test_object_path", |
| std::pair<std::string, InterfaceNames>( |
| "test_object_connection_1", { |
| "test_interface_0", |
| "test_interface_1", |
| })); |
| ASSERT_EQ(interfaceMaps.size(), 1); |
| |
| auto entry = std::find_if(interfaceMaps.begin(), interfaceMaps.end(), |
| [](const auto& i) { |
| return "test_object_path" == i.first; |
| }); |
| ASSERT_NE(entry, interfaceMap.end()); |
| for (const auto& [_, interfaces] : entry->second) |
| { |
| ASSERT_THAT(interfaces, |
| ElementsAre("test_interface_0", "test_interface_1")); |
| } |
| |
| // Change the interface, but expect it to be unchanged |
| addObjectMapResult(interfaceMaps, "test_object_path", |
| std::pair<std::string, InterfaceNames>( |
| "test_object_connection_0", {"test_interface_2"})); |
| addObjectMapResult(interfaceMaps, "test_object_path", |
| std::pair<std::string, InterfaceNames>( |
| "test_object_connection_1", {"test_interface_2"})); |
| entry = std::find_if(interfaceMaps.begin(), interfaceMaps.end(), |
| [](const auto& i) { |
| return "test_object_path" == i.first; |
| }); |
| ASSERT_NE(entry, interfaceMaps.end()); |
| for (const auto& [_, interfaces] : entry->second) |
| { |
| ASSERT_THAT(interfaces, |
| ElementsAre("test_interface_0", "test_interface_1")); |
| } |
| } |
| |
| TEST_F(TestHandler, getAncestorsBad) |
| { |
| std::string path = "/test/object_path_0/child/grandchild"; |
| std::vector<std::string> interfaces = {"bad_interface"}; |
| std::vector<InterfaceMapType::value_type> ancestors = |
| getAncestors(interfaceMap, path, interfaces); |
| ASSERT_TRUE(ancestors.empty()); |
| |
| path = "/invalid_path"; |
| EXPECT_THROW( |
| getAncestors(interfaceMap, path, interfaces), |
| sdbusplus::xyz::openbmc_project::Common::Error::ResourceNotFound); |
| } |
| |
| TEST_F(TestHandler, getAncestorsGood) |
| { |
| std::string path = "/test/object_path_0/child/grandchild"; |
| std::vector<std::string> interfaces = {"test_interface_0", |
| "test_interface_1"}; |
| std::vector<InterfaceMapType::value_type> ancestors = |
| getAncestors(interfaceMap, path, interfaces); |
| ASSERT_EQ(ancestors.size(), 2); |
| |
| // Grand Parent |
| EXPECT_EQ(ancestors[0].first, "/test/object_path_0"); |
| ASSERT_EQ(ancestors[0].second.size(), 1); |
| auto grandParent = ancestors[0].second.find("test_object_connection_0"); |
| ASSERT_NE(grandParent, ancestors[0].second.end()); |
| ASSERT_THAT(grandParent->second, ElementsAre("test_interface_0")); |
| |
| // Parent |
| ASSERT_EQ(ancestors[1].first, "/test/object_path_0/child"); |
| ASSERT_EQ(ancestors[1].second.size(), 1); |
| auto parent = ancestors[1].second.find("test_object_connection_1"); |
| ASSERT_NE(parent, ancestors[1].second.end()); |
| ASSERT_THAT(parent->second, ElementsAre("test_interface_1")); |
| } |
| |
| TEST_F(TestHandler, getObjectBad) |
| { |
| std::string path = "/test/object_path_0"; |
| std::vector<std::string> interfaces = {"bad_interface"}; |
| EXPECT_THROW( |
| getObject(interfaceMap, path, interfaces), |
| sdbusplus::xyz::openbmc_project::Common::Error::ResourceNotFound); |
| |
| path = "/invalid_path"; |
| EXPECT_THROW( |
| getObject(interfaceMap, path, interfaces), |
| sdbusplus::xyz::openbmc_project::Common::Error::ResourceNotFound); |
| |
| path = "/"; |
| EXPECT_THROW( |
| getObject(interfaceMap, path, interfaces), |
| sdbusplus::xyz::openbmc_project::Common::Error::ResourceNotFound); |
| } |
| |
| TEST_F(TestHandler, getObjectGood) |
| { |
| std::string path = "/test/object_path_0"; |
| std::vector<std::string> interfaces = {"test_interface_0", |
| "test_interface_1"}; |
| ConnectionNames connection = getObject(interfaceMap, path, interfaces); |
| auto object = connection.find("test_object_connection_0"); |
| ASSERT_NE(object, connection.end()); |
| ASSERT_THAT(object->second, ElementsAre("test_interface_0")); |
| |
| path = "/test/object_path_0/child"; |
| connection = getObject(interfaceMap, path, interfaces); |
| object = connection.find("test_object_connection_1"); |
| ASSERT_NE(object, connection.end()); |
| ASSERT_THAT(object->second, ElementsAre("test_interface_1")); |
| } |
| |
| TEST_F(TestHandler, getSubTreeBad) |
| { |
| std::string path = "/test/object_path_0"; |
| std::vector<std::string> interfaces = {"bad_interface"}; |
| std::vector<InterfaceMapType::value_type> subtree = |
| getSubTree(interfaceMap, path, 0, interfaces); |
| ASSERT_TRUE(subtree.empty()); |
| |
| path = "/invalid_path"; |
| EXPECT_THROW( |
| getSubTree(interfaceMap, path, 0, interfaces), |
| sdbusplus::xyz::openbmc_project::Common::Error::ResourceNotFound); |
| } |
| |
| void verifySubtree(std::span<InterfaceMapType::value_type> subtree) |
| { |
| ASSERT_EQ(subtree.size(), 2); |
| ConnectionNames connection = subtree[0].second; |
| auto object = connection.find("test_object_connection_1"); |
| ASSERT_NE(object, connection.end()); |
| ASSERT_THAT(object->second, ElementsAre("test_interface_1")); |
| |
| connection = subtree[1].second; |
| object = connection.find("test_object_connection_3"); |
| ASSERT_NE(object, connection.end()); |
| ASSERT_THAT(object->second, ElementsAre("test_interface_3")); |
| } |
| |
| TEST_F(TestHandler, getSubTreeGood) |
| { |
| std::string path0 = "/test/object_path_0"; |
| std::string path1 = "/test/object_path_0/child/grandchild"; |
| std::vector<std::string> interfaces = {"test_interface_1", |
| "test_interface_3"}; |
| // Root |
| std::vector<InterfaceMapType::value_type> subtree = |
| getSubTree(interfaceMap, "/", 0, interfaces); |
| verifySubtree(subtree); |
| |
| // Path0 |
| subtree = getSubTree(interfaceMap, path0, 0, interfaces); |
| verifySubtree(subtree); |
| |
| // Path0 with Depth path of 1 |
| subtree = getSubTree(interfaceMap, path0, 1, interfaces); |
| ASSERT_EQ(subtree.size(), 1); |
| ConnectionNames connection = subtree[0].second; |
| auto object = connection.find("test_object_connection_1"); |
| ASSERT_NE(object, connection.end()); |
| ASSERT_THAT(object->second, ElementsAre("test_interface_1")); |
| |
| // Path1 |
| subtree = getSubTree(interfaceMap, path1, 0, interfaces); |
| ASSERT_EQ(subtree.size(), 1); |
| connection = subtree[0].second; |
| object = connection.find("test_object_connection_3"); |
| ASSERT_NE(object, connection.end()); |
| ASSERT_THAT(object->second, ElementsAre("test_interface_3")); |
| } |
| |
| TEST_F(TestHandler, getSubTreePathsBad) |
| { |
| std::string path = "/test/object_path_0"; |
| std::vector<std::string> interfaces = {"bad_interface"}; |
| std::vector<std::string> subtreePath = getSubTreePaths(interfaceMap, path, |
| 0, interfaces); |
| ASSERT_TRUE(subtreePath.empty()); |
| |
| path = "/invalid_path"; |
| EXPECT_THROW( |
| getSubTreePaths(interfaceMap, path, 0, interfaces), |
| sdbusplus::xyz::openbmc_project::Common::Error::ResourceNotFound); |
| } |
| |
| TEST_F(TestHandler, getSubTreePathsGood) |
| { |
| std::string path0 = "/test/object_path_0"; |
| std::string path1 = "/test/object_path_0/child/grandchild"; |
| std::vector<std::string> interfaces = {"test_interface_1", |
| "test_interface_3"}; |
| // Root |
| std::vector<std::string> subtreePath = getSubTreePaths(interfaceMap, "/", 0, |
| interfaces); |
| ASSERT_THAT(subtreePath, |
| ElementsAre("/test/object_path_0/child", |
| "/test/object_path_0/child/grandchild/dog")); |
| |
| // Path0 |
| subtreePath = getSubTreePaths(interfaceMap, path0, 0, interfaces); |
| ASSERT_THAT(subtreePath, |
| ElementsAre("/test/object_path_0/child", |
| "/test/object_path_0/child/grandchild/dog")); |
| |
| // Path0 + Depth path of 1 |
| subtreePath = getSubTreePaths(interfaceMap, path0, 1, interfaces); |
| ASSERT_THAT(subtreePath, ElementsAre("/test/object_path_0/child")); |
| |
| // Path1 |
| subtreePath = getSubTreePaths(interfaceMap, path1, 0, interfaces); |
| ASSERT_THAT(subtreePath, |
| ElementsAre("/test/object_path_0/child/grandchild/dog")); |
| } |
| |
| TEST_F(TestHandler, getAssociatedSubTreeBad) |
| { |
| sdbusplus::message::object_path path("/test/object_path_0"); |
| sdbusplus::message::object_path validAssociatedPath = path / "descendent"; |
| std::vector<std::string> invalidInterfaces = {"test_interface_3"}; |
| std::vector<std::string> validInterfaces = {"test_interface_1", |
| "test_interface_2"}; |
| // Associated path, but invalid interface |
| ASSERT_TRUE(getAssociatedSubTree(interfaceMap, associationMap, |
| validAssociatedPath, path, 0, |
| invalidInterfaces) |
| .empty()); |
| |
| // Valid interface, not associated |
| ASSERT_TRUE(getAssociatedSubTree(interfaceMap, associationMap, path / "dog", |
| path, 0, validInterfaces) |
| .empty()); |
| |
| // Invalid path, with valid association |
| path = sdbusplus::message::object_path("/invalid_path"); |
| EXPECT_THROW( |
| getAssociatedSubTree(interfaceMap, associationMap, validAssociatedPath, |
| path, 0, validInterfaces), |
| sdbusplus::xyz::openbmc_project::Common::Error::ResourceNotFound); |
| } |
| |
| TEST_F(TestHandler, getAssociatedSubTreeGood) |
| { |
| sdbusplus::message::object_path path0("/test/object_path_0"); |
| sdbusplus::message::object_path path1("/test/object_path_0/child"); |
| sdbusplus::message::object_path associatedPath = path0 / "descendent"; |
| std::vector<std::string> interfaces = {"test_interface_1", |
| "test_interface_2", |
| // Not associated to path |
| "test_interface_3"}; |
| |
| // Path0 |
| std::vector<InterfaceMapType::value_type> subtree = getAssociatedSubTree( |
| interfaceMap, associationMap, associatedPath, path0, 0, interfaces); |
| ASSERT_EQ(subtree.size(), 2); |
| ConnectionNames connection = subtree[0].second; |
| auto object = connection.find("test_object_connection_1"); |
| ASSERT_NE(object, connection.end()); |
| ASSERT_THAT(object->second, ElementsAre("test_interface_1")); |
| |
| connection = subtree[1].second; |
| object = connection.find("test_object_connection_2"); |
| ASSERT_NE(object, connection.end()); |
| ASSERT_THAT(object->second, ElementsAre("test_interface_2")); |
| |
| // Path0 with Depth path of 1 |
| subtree = getAssociatedSubTree(interfaceMap, associationMap, associatedPath, |
| path0, 1, interfaces); |
| ASSERT_EQ(subtree.size(), 1); |
| connection = subtree[0].second; |
| object = connection.find("test_object_connection_1"); |
| ASSERT_NE(object, connection.end()); |
| ASSERT_THAT(object->second, ElementsAre("test_interface_1")); |
| |
| // Path1 |
| subtree = getAssociatedSubTree(interfaceMap, associationMap, |
| path1 / "descendent", path1, 0, interfaces); |
| ASSERT_EQ(subtree.size(), 1); |
| connection = subtree[0].second; |
| object = connection.find("test_object_connection_2"); |
| ASSERT_NE(object, connection.end()); |
| ASSERT_THAT(object->second, ElementsAre("test_interface_2")); |
| } |
| |
| TEST_F(TestHandler, getAssociatedSubTreePathsBad) |
| { |
| sdbusplus::message::object_path path("/test/object_path_0"); |
| sdbusplus::message::object_path validAssociatedPath = path / "descendent"; |
| std::vector<std::string> invalidInterfaces = {"test_interface_3"}; |
| std::vector<std::string> validInterfaces = {"test_interface_1", |
| "test_interface_2"}; |
| // Associated path, but invalid interface |
| ASSERT_TRUE(getAssociatedSubTreePaths(interfaceMap, associationMap, |
| validAssociatedPath, path, 0, |
| invalidInterfaces) |
| .empty()); |
| |
| // Valid interface, not associated |
| ASSERT_TRUE(getAssociatedSubTreePaths(interfaceMap, associationMap, |
| path / "dog", path, 0, |
| validInterfaces) |
| .empty()); |
| |
| // Invalid path, with valid association |
| path = sdbusplus::message::object_path("/invalid_path"); |
| EXPECT_THROW( |
| getAssociatedSubTreePaths(interfaceMap, associationMap, |
| validAssociatedPath, path, 0, |
| validInterfaces), |
| sdbusplus::xyz::openbmc_project::Common::Error::ResourceNotFound); |
| } |
| |
| TEST_F(TestHandler, getAssociatedSubTreePathsGood) |
| { |
| sdbusplus::message::object_path path0("/test/object_path_0"); |
| sdbusplus::message::object_path path1("/test/object_path_0/child"); |
| sdbusplus::message::object_path associatedPath = path0 / "descendent"; |
| std::vector<std::string> interfaces = {"test_interface_1", |
| "test_interface_2", |
| // Not associated to path |
| "test_interface_3"}; |
| |
| // Path0 |
| std::vector<std::string> subtreePath = getAssociatedSubTreePaths( |
| interfaceMap, associationMap, associatedPath, path0, 0, interfaces); |
| ASSERT_THAT(subtreePath, |
| ElementsAre("/test/object_path_0/child", |
| "/test/object_path_0/child/grandchild")); |
| |
| // Path0 with Depth path of 1 |
| subtreePath = getAssociatedSubTreePaths( |
| interfaceMap, associationMap, associatedPath, path0, 1, interfaces); |
| ASSERT_THAT(subtreePath, ElementsAre("/test/object_path_0/child")); |
| |
| // Path1 |
| subtreePath = getAssociatedSubTreePaths(interfaceMap, associationMap, |
| path1 / "descendent", path1, 0, |
| interfaces); |
| ASSERT_THAT(subtreePath, |
| ElementsAre("/test/object_path_0/child/grandchild")); |
| } |