diff options
author | Carson Labrado <clabrado@google.com> | 2023-01-03 20:30:47 +0300 |
---|---|---|
committer | Ed Tanous <ed@tanous.net> | 2023-04-07 01:16:56 +0300 |
commit | 8fd333d664f87c73757e0c5e58c611dc0c3e76d7 (patch) | |
tree | 0babf511e86ce1980f42a8dab157f92ad5939a17 | |
parent | e628df8658c57f6943b6d3612e1077618e5a168a (diff) | |
download | bmcweb-8fd333d664f87c73757e0c5e58c611dc0c3e76d7.tar.xz |
Aggregation: Check for subordinate collection
Adds a search function which is able to determine if a passed URI is a
top level collection, is uptree from a top level collection, or both.
The type being searched for depends on a second argument passed to the
function.
Each of these searches are used to add links to top level collections
which are only supported by a satellite BMC. They all use similar steps
so rolling them into a single function cuts down on redundant code.
Adds test cases to verify the implementation is correct.
Tested:
New test cases pass
Signed-off-by: Carson Labrado <clabrado@google.com>
Change-Id: I72ae7442d5f314656b57a73aee544bca516fa7c2
-rw-r--r-- | redfish-core/include/redfish_aggregator.hpp | 105 | ||||
-rw-r--r-- | test/redfish-core/include/redfish_aggregator_test.cpp | 129 |
2 files changed, 234 insertions, 0 deletions
diff --git a/redfish-core/include/redfish_aggregator.hpp b/redfish-core/include/redfish_aggregator.hpp index c640586c10..245c698233 100644 --- a/redfish-core/include/redfish_aggregator.hpp +++ b/redfish-core/include/redfish_aggregator.hpp @@ -21,6 +21,14 @@ enum class Result NoLocalHandle }; +enum class SearchType +{ + Collection, + CollOrCon, + ContainsSubordinate, + Resource +}; + // clang-format off // These are all of the properties as of version 2022.2 of the Redfish Resource // and Schema Guide whose Type is "string (URI)" and the name does not end in a @@ -43,6 +51,103 @@ constexpr std::array nonUriProperties{ }; // clang-format on +// Search the top collection array to determine if the passed URI is of a +// desired type +inline bool searchCollectionsArray(std::string_view uri, + const SearchType searchType) +{ + constexpr std::string_view serviceRootUri = "/redfish/v1"; + + // The passed URI must begin with "/redfish/v1", but we have to strip it + // from the URI since topCollections does not include it in its URIs + if (!uri.starts_with(serviceRootUri)) + { + return false; + } + + // Catch empty final segments such as "/redfish/v1/Chassis//" + if (uri.ends_with("//")) + { + return false; + } + + std::size_t parseCount = uri.size() - serviceRootUri.size(); + // Don't include the trailing "/" if it exists such as in "/redfish/v1/" + if (uri.ends_with("/")) + { + parseCount--; + } + + boost::urls::result<boost::urls::url_view> parsedUrl = + boost::urls::parse_relative_ref( + uri.substr(serviceRootUri.size(), parseCount)); + if (!parsedUrl) + { + BMCWEB_LOG_ERROR << "Failed to get target URI from " + << uri.substr(serviceRootUri.size()); + return false; + } + + if (!parsedUrl->segments().is_absolute() && !parsedUrl->segments().empty()) + { + return false; + } + + // If no segments() then the passed URI was either "/redfish/v1" or + // "/redfish/v1/". + if (parsedUrl->segments().empty()) + { + return (searchType == SearchType::ContainsSubordinate) || + (searchType == SearchType::CollOrCon); + } + + const auto* it = std::lower_bound( + topCollections.begin(), topCollections.end(), parsedUrl->buffer()); + if (it == topCollections.end()) + { + // parsedUrl is alphabetically after the last entry in the array so it + // can't be a top collection or up tree from a top collection + return false; + } + + boost::urls::url collectionUrl(*it); + boost::urls::segments_view collectionSegments = collectionUrl.segments(); + boost::urls::segments_view::iterator itCollection = + collectionSegments.begin(); + const boost::urls::segments_view::const_iterator endCollection = + collectionSegments.end(); + + // Each segment in the passed URI should match the found collection + for (const auto& segment : parsedUrl->segments()) + { + if (itCollection == endCollection) + { + // Leftover segments means the target is for an aggregation + // supported resource + return searchType == SearchType::Resource; + } + + if (segment != (*itCollection)) + { + return false; + } + itCollection++; + } + + // No remaining segments means the passed URI was a top level collection + if (searchType == SearchType::Collection) + { + return itCollection == endCollection; + } + if (searchType == SearchType::ContainsSubordinate) + { + return itCollection != endCollection; + } + + // Return this check instead of "true" in case other SearchTypes get added + return searchType == SearchType::CollOrCon; +} + // Determines if the passed property contains a URI. Those property names // either end with a case-insensitive version of "uri" or are specifically // defined in the above array. diff --git a/test/redfish-core/include/redfish_aggregator_test.cpp b/test/redfish-core/include/redfish_aggregator_test.cpp index 2fdd784d3b..da3209ab9b 100644 --- a/test/redfish-core/include/redfish_aggregator_test.cpp +++ b/test/redfish-core/include/redfish_aggregator_test.cpp @@ -518,5 +518,134 @@ TEST(processResponse, DifferentContentType) assertProcessResponseContentType(";charset=utf-8"); } +bool containsSubordinateCollection(const std::string_view uri) +{ + return searchCollectionsArray(uri, SearchType::ContainsSubordinate); +} + +bool containsCollection(const std::string_view uri) +{ + return searchCollectionsArray(uri, SearchType::Collection); +} + +bool isCollOrCon(const std::string_view uri) +{ + return searchCollectionsArray(uri, SearchType::CollOrCon); +} + +TEST(searchCollectionsArray, containsSubordinateValidURIs) +{ + EXPECT_TRUE(containsSubordinateCollection("/redfish/v1")); + EXPECT_TRUE(containsSubordinateCollection("/redfish/v1/")); + EXPECT_TRUE( + containsSubordinateCollection("/redfish/v1/AggregationService")); + EXPECT_TRUE( + containsSubordinateCollection("/redfish/v1/CompositionService/")); + EXPECT_TRUE(containsSubordinateCollection("/redfish/v1/JobService")); + EXPECT_TRUE(containsSubordinateCollection("/redfish/v1/JobService/Log")); + EXPECT_TRUE(containsSubordinateCollection("/redfish/v1/KeyService")); + EXPECT_TRUE(containsSubordinateCollection("/redfish/v1/LicenseService/")); + EXPECT_TRUE(containsSubordinateCollection("/redfish/v1/PowerEquipment")); + EXPECT_TRUE(containsSubordinateCollection("/redfish/v1/TaskService")); + EXPECT_TRUE(containsSubordinateCollection("/redfish/v1/TelemetryService")); + EXPECT_TRUE(containsSubordinateCollection( + "/redfish/v1/TelemetryService/LogService/")); + EXPECT_TRUE(containsSubordinateCollection("/redfish/v1/UpdateService")); +} + +TEST(searchCollectionsArray, containsSubordinateInvalidURIs) +{ + EXPECT_FALSE(containsSubordinateCollection("")); + EXPECT_FALSE(containsSubordinateCollection("http://")); + EXPECT_FALSE(containsSubordinateCollection("/redfish")); + EXPECT_FALSE(containsSubordinateCollection("/redfish/")); + EXPECT_FALSE(containsSubordinateCollection("/redfish//")); + EXPECT_FALSE(containsSubordinateCollection("/redfish/v1//")); + EXPECT_FALSE(containsSubordinateCollection("/redfish/v11")); + EXPECT_FALSE(containsSubordinateCollection("/redfish/v11/")); + EXPECT_FALSE(containsSubordinateCollection("www.test.com/redfish/v1")); + EXPECT_FALSE(containsSubordinateCollection("/fail")); + EXPECT_FALSE(containsSubordinateCollection( + "/redfish/v1/AggregationService/Aggregates")); + EXPECT_FALSE(containsSubordinateCollection( + "/redfish/v1/AggregationService/AggregationSources/")); + EXPECT_FALSE(containsSubordinateCollection("/redfish/v1/Cables/")); + EXPECT_FALSE( + containsSubordinateCollection("/redfish/v1/Chassis/chassisId")); + EXPECT_FALSE(containsSubordinateCollection("/redfish/v1/Fake")); + EXPECT_FALSE( + containsSubordinateCollection("/redfish/v1/TelemetryService//")); + EXPECT_FALSE(containsSubordinateCollection( + "/redfish/v1/TelemetryService/LogService/Entries")); + EXPECT_FALSE(containsSubordinateCollection( + "/redfish/v1/UpdateService/SoftwareInventory/")); + EXPECT_FALSE(containsSubordinateCollection( + "/redfish/v1/UpdateService/SoftwareInventory/Te")); + EXPECT_FALSE(containsSubordinateCollection( + "/redfish/v1/UpdateService/SoftwareInventory2")); +} + +TEST(searchCollectionsArray, collectionURIs) +{ + EXPECT_TRUE(containsCollection("/redfish/v1/Chassis")); + EXPECT_TRUE(containsCollection("/redfish/v1/Chassis/")); + EXPECT_TRUE(containsCollection("/redfish/v1/Managers")); + EXPECT_TRUE(containsCollection("/redfish/v1/Systems")); + EXPECT_TRUE( + containsCollection("/redfish/v1/TelemetryService/LogService/Entries")); + EXPECT_TRUE( + containsCollection("/redfish/v1/TelemetryService/LogService/Entries/")); + EXPECT_TRUE( + containsCollection("/redfish/v1/UpdateService/FirmwareInventory")); + EXPECT_TRUE( + containsCollection("/redfish/v1/UpdateService/FirmwareInventory/")); + + EXPECT_FALSE(containsCollection("http://")); + EXPECT_FALSE(containsCollection("/redfish/v11/Chassis")); + EXPECT_FALSE(containsCollection("/redfish/v11/Chassis/")); + EXPECT_FALSE(containsCollection("/redfish/v1")); + EXPECT_FALSE(containsCollection("/redfish/v1/")); + EXPECT_FALSE(containsCollection("/redfish/v1//")); + EXPECT_FALSE(containsCollection("/redfish/v1/Chassis//")); + EXPECT_FALSE(containsCollection("/redfish/v1/Chassis/Test")); + EXPECT_FALSE(containsCollection("/redfish/v1/TelemetryService")); + EXPECT_FALSE(containsCollection("/redfish/v1/TelemetryService/")); + EXPECT_FALSE(containsCollection("/redfish/v1/UpdateService")); + EXPECT_FALSE( + containsCollection("/redfish/v1/UpdateService/FirmwareInventory/Test")); + EXPECT_FALSE( + containsCollection("/redfish/v1/UpdateService/FirmwareInventory/Tes/")); + EXPECT_FALSE( + containsCollection("/redfish/v1/UpdateService/SoftwareInventory/Te")); + EXPECT_FALSE( + containsCollection("/redfish/v1/UpdateService/SoftwareInventory2")); + EXPECT_FALSE(containsCollection("/redfish/v11")); + EXPECT_FALSE(containsCollection("/redfish/v11/")); +} + +TEST(searchCollectionsArray, collectionOrContainsURIs) +{ + // Resources that are a top level collection or are uptree of one + EXPECT_TRUE(isCollOrCon("/redfish/v1/")); + EXPECT_TRUE(isCollOrCon("/redfish/v1/AggregationService")); + EXPECT_TRUE(isCollOrCon("/redfish/v1/CompositionService/")); + EXPECT_TRUE(isCollOrCon("/redfish/v1/Chassis")); + EXPECT_TRUE(isCollOrCon("/redfish/v1/Cables/")); + EXPECT_TRUE(isCollOrCon("/redfish/v1/Fabrics")); + EXPECT_TRUE(isCollOrCon("/redfish/v1/Managers")); + EXPECT_TRUE(isCollOrCon("/redfish/v1/UpdateService/FirmwareInventory")); + EXPECT_TRUE(isCollOrCon("/redfish/v1/UpdateService/FirmwareInventory/")); + + EXPECT_FALSE(isCollOrCon("http://")); + EXPECT_FALSE(isCollOrCon("/redfish/v11")); + EXPECT_FALSE(isCollOrCon("/redfish/v11/")); + EXPECT_FALSE(isCollOrCon("/redfish/v1/Chassis/Test")); + EXPECT_FALSE(isCollOrCon("/redfish/v1/Managers/Test/")); + EXPECT_FALSE(isCollOrCon("/redfish/v1/TaskService/Tasks/0")); + EXPECT_FALSE(isCollOrCon("/redfish/v1/UpdateService/FirmwareInventory/Te")); + EXPECT_FALSE(isCollOrCon("/redfish/v1/UpdateService/SoftwareInventory/Te")); + EXPECT_FALSE(isCollOrCon("/redfish/v1/UpdateService/SoftwareInventory2")); +} + } // namespace } // namespace redfish |