Break out post codes
Similar to other patches, break out the post codes log services into
their own file. log_services.hpp is far too large.
Change-Id: I3cb644d52a9d3b5f9a15a2f90c1b69c87491e5c8
Signed-off-by: Ed Tanous <etanous@nvidia.com>
diff --git a/meson.build b/meson.build
index 4984d1a..f50212c 100644
--- a/meson.build
+++ b/meson.build
@@ -445,12 +445,13 @@
'test/redfish-core/include/utils/time_utils_test.cpp',
'test/redfish-core/lib/chassis_test.cpp',
'test/redfish-core/lib/log_services_dump_test.cpp',
- 'test/redfish-core/lib/log_services_test.cpp',
'test/redfish-core/lib/manager_diagnostic_data_test.cpp',
+ 'test/redfish-core/lib/manager_logservices_journal_test.cpp',
'test/redfish-core/lib/metadata_test.cpp',
'test/redfish-core/lib/power_subsystem_test.cpp',
'test/redfish-core/lib/service_root_test.cpp',
'test/redfish-core/lib/system_test.cpp',
+ 'test/redfish-core/lib/systems_logservices_postcode.cpp',
'test/redfish-core/lib/thermal_subsystem_test.cpp',
'test/redfish-core/lib/update_service_test.cpp',
)
diff --git a/redfish-core/lib/log_services.hpp b/redfish-core/lib/log_services.hpp
index 1fb88ea..46ceae1 100644
--- a/redfish-core/lib/log_services.hpp
+++ b/redfish-core/lib/log_services.hpp
@@ -3468,607 +3468,4 @@
});
}
-/****************************************************
- * Redfish PostCode interfaces
- * using DBUS interface: getPostCodesTS
- ******************************************************/
-inline void requestRoutesPostCodesLogService(App& app)
-{
- BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/")
- .privileges(redfish::privileges::getLogService)
- .methods(
- boost::beast::http::verb::
- get)([&app](const crow::Request& req,
- const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
- const std::string& systemName) {
- if (!redfish::setUpRedfishRoute(app, req, asyncResp))
- {
- return;
- }
- if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
- {
- // Option currently returns no systems. TBD
- messages::resourceNotFound(asyncResp->res, "ComputerSystem",
- systemName);
- return;
- }
- if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
- {
- messages::resourceNotFound(asyncResp->res, "ComputerSystem",
- systemName);
- return;
- }
- asyncResp->res.jsonValue["@odata.id"] =
- std::format("/redfish/v1/Systems/{}/LogServices/PostCodes",
- BMCWEB_REDFISH_SYSTEM_URI_NAME);
- asyncResp->res.jsonValue["@odata.type"] =
- "#LogService.v1_2_0.LogService";
- asyncResp->res.jsonValue["Name"] = "POST Code Log Service";
- asyncResp->res.jsonValue["Description"] = "POST Code Log Service";
- asyncResp->res.jsonValue["Id"] = "PostCodes";
- asyncResp->res.jsonValue["OverWritePolicy"] =
- log_service::OverWritePolicy::WrapsWhenFull;
- asyncResp->res.jsonValue["Entries"]["@odata.id"] = std::format(
- "/redfish/v1/Systems/{}/LogServices/PostCodes/Entries",
- BMCWEB_REDFISH_SYSTEM_URI_NAME);
-
- std::pair<std::string, std::string> redfishDateTimeOffset =
- redfish::time_utils::getDateTimeOffsetNow();
- asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
- asyncResp->res.jsonValue["DateTimeLocalOffset"] =
- redfishDateTimeOffset.second;
-
- asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]
- ["target"] = std::format(
- "/redfish/v1/Systems/{}/LogServices/PostCodes/Actions/LogService.ClearLog",
- BMCWEB_REDFISH_SYSTEM_URI_NAME);
- });
-}
-
-inline void requestRoutesPostCodesClear(App& app)
-{
- BMCWEB_ROUTE(
- app,
- "/redfish/v1/Systems/<str>/LogServices/PostCodes/Actions/LogService.ClearLog/")
- // The following privilege is incorrect; It should be ConfigureManager
- //.privileges(redfish::privileges::postLogService)
- .privileges({{"ConfigureComponents"}})
- .methods(boost::beast::http::verb::post)(
- [&app](const crow::Request& req,
- const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
- const std::string& systemName) {
- if (!redfish::setUpRedfishRoute(app, req, asyncResp))
- {
- return;
- }
- if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
- {
- // Option currently returns no systems. TBD
- messages::resourceNotFound(asyncResp->res, "ComputerSystem",
- systemName);
- return;
- }
- if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
- {
- messages::resourceNotFound(asyncResp->res, "ComputerSystem",
- systemName);
- return;
- }
- BMCWEB_LOG_DEBUG("Do delete all postcodes entries.");
-
- // Make call to post-code service to request clear all
- crow::connections::systemBus->async_method_call(
- [asyncResp](const boost::system::error_code& ec) {
- if (ec)
- {
- // TODO Handle for specific error code
- BMCWEB_LOG_ERROR(
- "doClearPostCodes resp_handler got error {}",
- ec);
- asyncResp->res.result(boost::beast::http::status::
- internal_server_error);
- messages::internalError(asyncResp->res);
- return;
- }
- messages::success(asyncResp->res);
- },
- "xyz.openbmc_project.State.Boot.PostCode0",
- "/xyz/openbmc_project/State/Boot/PostCode0",
- "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll");
- });
-}
-
-/**
- * @brief Parse post code ID and get the current value and index value
- * eg: postCodeID=B1-2, currentValue=1, index=2
- *
- * @param[in] postCodeID Post Code ID
- * @param[out] currentValue Current value
- * @param[out] index Index value
- *
- * @return bool true if the parsing is successful, false the parsing fails
- */
-inline bool parsePostCode(std::string_view postCodeID, uint64_t& currentValue,
- uint16_t& index)
-{
- std::vector<std::string> split;
- bmcweb::split(split, postCodeID, '-');
- if (split.size() != 2)
- {
- return false;
- }
- std::string_view postCodeNumber = split[0];
- if (postCodeNumber.size() < 2)
- {
- return false;
- }
- if (postCodeNumber[0] != 'B')
- {
- return false;
- }
- postCodeNumber.remove_prefix(1);
- auto [ptrIndex, ecIndex] =
- std::from_chars(postCodeNumber.begin(), postCodeNumber.end(), index);
- if (ptrIndex != postCodeNumber.end() || ecIndex != std::errc())
- {
- return false;
- }
-
- std::string_view postCodeIndex = split[1];
-
- auto [ptrValue, ecValue] = std::from_chars(
- postCodeIndex.begin(), postCodeIndex.end(), currentValue);
-
- return ptrValue == postCodeIndex.end() && ecValue == std::errc();
-}
-
-static bool fillPostCodeEntry(
- const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
- const boost::container::flat_map<
- uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& postcode,
- const uint16_t bootIndex, const uint64_t codeIndex = 0,
- const uint64_t skip = 0, const uint64_t top = 0)
-{
- // Get the Message from the MessageRegistry
- const registries::Message* message =
- registries::getMessage("OpenBMC.0.2.BIOSPOSTCode");
- if (message == nullptr)
- {
- BMCWEB_LOG_ERROR("Couldn't find known message?");
- return false;
- }
- uint64_t currentCodeIndex = 0;
- uint64_t firstCodeTimeUs = 0;
- for (const std::pair<uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
- code : postcode)
- {
- currentCodeIndex++;
- std::string postcodeEntryID =
- "B" + std::to_string(bootIndex) + "-" +
- std::to_string(currentCodeIndex); // 1 based index in EntryID string
-
- uint64_t usecSinceEpoch = code.first;
- uint64_t usTimeOffset = 0;
-
- if (1 == currentCodeIndex)
- { // already incremented
- firstCodeTimeUs = code.first;
- }
- else
- {
- usTimeOffset = code.first - firstCodeTimeUs;
- }
-
- // skip if no specific codeIndex is specified and currentCodeIndex does
- // not fall between top and skip
- if ((codeIndex == 0) &&
- (currentCodeIndex <= skip || currentCodeIndex > top))
- {
- continue;
- }
-
- // skip if a specific codeIndex is specified and does not match the
- // currentIndex
- if ((codeIndex > 0) && (currentCodeIndex != codeIndex))
- {
- // This is done for simplicity. 1st entry is needed to calculate
- // time offset. To improve efficiency, one can get to the entry
- // directly (possibly with flatmap's nth method)
- continue;
- }
-
- // currentCodeIndex is within top and skip or equal to specified code
- // index
-
- // Get the Created time from the timestamp
- std::string entryTimeStr;
- entryTimeStr = redfish::time_utils::getDateTimeUintUs(usecSinceEpoch);
-
- // assemble messageArgs: BootIndex, TimeOffset(100us), PostCode(hex)
- std::ostringstream hexCode;
- hexCode << "0x" << std::setfill('0') << std::setw(2) << std::hex
- << std::get<0>(code.second);
- std::ostringstream timeOffsetStr;
- // Set Fixed -Point Notation
- timeOffsetStr << std::fixed;
- // Set precision to 4 digits
- timeOffsetStr << std::setprecision(4);
- // Add double to stream
- timeOffsetStr << static_cast<double>(usTimeOffset) / 1000 / 1000;
-
- std::string bootIndexStr = std::to_string(bootIndex);
- std::string timeOffsetString = timeOffsetStr.str();
- std::string hexCodeStr = hexCode.str();
-
- std::array<std::string_view, 3> messageArgs = {
- bootIndexStr, timeOffsetString, hexCodeStr};
-
- std::string msg =
- redfish::registries::fillMessageArgs(messageArgs, message->message);
- if (msg.empty())
- {
- messages::internalError(asyncResp->res);
- return false;
- }
-
- // Get Severity template from message registry
- std::string severity;
- if (message != nullptr)
- {
- severity = message->messageSeverity;
- }
-
- // Format entry
- nlohmann::json::object_t bmcLogEntry;
- bmcLogEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
- bmcLogEntry["@odata.id"] = boost::urls::format(
- "/redfish/v1/Systems/{}/LogServices/PostCodes/Entries/{}",
- BMCWEB_REDFISH_SYSTEM_URI_NAME, postcodeEntryID);
- bmcLogEntry["Name"] = "POST Code Log Entry";
- bmcLogEntry["Id"] = postcodeEntryID;
- bmcLogEntry["Message"] = std::move(msg);
- bmcLogEntry["MessageId"] = "OpenBMC.0.2.BIOSPOSTCode";
- bmcLogEntry["MessageArgs"] = messageArgs;
- bmcLogEntry["EntryType"] = "Event";
- bmcLogEntry["Severity"] = std::move(severity);
- bmcLogEntry["Created"] = entryTimeStr;
- if (!std::get<std::vector<uint8_t>>(code.second).empty())
- {
- bmcLogEntry["AdditionalDataURI"] =
- std::format(
- "/redfish/v1/Systems/{}/LogServices/PostCodes/Entries/",
- BMCWEB_REDFISH_SYSTEM_URI_NAME) +
- postcodeEntryID + "/attachment";
- }
-
- // codeIndex is only specified when querying single entry, return only
- // that entry in this case
- if (codeIndex != 0)
- {
- asyncResp->res.jsonValue.update(bmcLogEntry);
- return true;
- }
-
- nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
- logEntryArray.emplace_back(std::move(bmcLogEntry));
- }
-
- // Return value is always false when querying multiple entries
- return false;
-}
-
-static void
- getPostCodeForEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
- const std::string& entryId)
-{
- uint16_t bootIndex = 0;
- uint64_t codeIndex = 0;
- if (!parsePostCode(entryId, codeIndex, bootIndex))
- {
- // Requested ID was not found
- messages::resourceNotFound(asyncResp->res, "LogEntry", entryId);
- return;
- }
-
- if (bootIndex == 0 || codeIndex == 0)
- {
- // 0 is an invalid index
- messages::resourceNotFound(asyncResp->res, "LogEntry", entryId);
- return;
- }
-
- crow::connections::systemBus->async_method_call(
- [asyncResp, entryId, bootIndex,
- codeIndex](const boost::system::error_code& ec,
- const boost::container::flat_map<
- uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
- postcode) {
- if (ec)
- {
- BMCWEB_LOG_DEBUG("DBUS POST CODE PostCode response error");
- messages::internalError(asyncResp->res);
- return;
- }
-
- if (postcode.empty())
- {
- messages::resourceNotFound(asyncResp->res, "LogEntry", entryId);
- return;
- }
-
- if (!fillPostCodeEntry(asyncResp, postcode, bootIndex, codeIndex))
- {
- messages::resourceNotFound(asyncResp->res, "LogEntry", entryId);
- return;
- }
- },
- "xyz.openbmc_project.State.Boot.PostCode0",
- "/xyz/openbmc_project/State/Boot/PostCode0",
- "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
- bootIndex);
-}
-
-static void
- getPostCodeForBoot(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
- const uint16_t bootIndex, const uint16_t bootCount,
- const uint64_t entryCount, size_t skip, size_t top)
-{
- crow::connections::systemBus->async_method_call(
- [asyncResp, bootIndex, bootCount, entryCount, skip,
- top](const boost::system::error_code& ec,
- const boost::container::flat_map<
- uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
- postcode) {
- if (ec)
- {
- BMCWEB_LOG_DEBUG("DBUS POST CODE PostCode response error");
- messages::internalError(asyncResp->res);
- return;
- }
-
- uint64_t endCount = entryCount;
- if (!postcode.empty())
- {
- endCount = entryCount + postcode.size();
- if (skip < endCount && (top + skip) > entryCount)
- {
- uint64_t thisBootSkip =
- std::max(static_cast<uint64_t>(skip), entryCount) -
- entryCount;
- uint64_t thisBootTop =
- std::min(static_cast<uint64_t>(top + skip), endCount) -
- entryCount;
-
- fillPostCodeEntry(asyncResp, postcode, bootIndex, 0,
- thisBootSkip, thisBootTop);
- }
- asyncResp->res.jsonValue["Members@odata.count"] = endCount;
- }
-
- // continue to previous bootIndex
- if (bootIndex < bootCount)
- {
- getPostCodeForBoot(asyncResp,
- static_cast<uint16_t>(bootIndex + 1),
- bootCount, endCount, skip, top);
- }
- else if (skip + top < endCount)
- {
- asyncResp->res.jsonValue["Members@odata.nextLink"] =
- std::format(
- "/redfish/v1/Systems/{}/LogServices/PostCodes/Entries?$skip=",
- BMCWEB_REDFISH_SYSTEM_URI_NAME) +
- std::to_string(skip + top);
- }
- },
- "xyz.openbmc_project.State.Boot.PostCode0",
- "/xyz/openbmc_project/State/Boot/PostCode0",
- "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
- bootIndex);
-}
-
-static void
- getCurrentBootNumber(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
- size_t skip, size_t top)
-{
- uint64_t entryCount = 0;
- sdbusplus::asio::getProperty<uint16_t>(
- *crow::connections::systemBus,
- "xyz.openbmc_project.State.Boot.PostCode0",
- "/xyz/openbmc_project/State/Boot/PostCode0",
- "xyz.openbmc_project.State.Boot.PostCode", "CurrentBootCycleCount",
- [asyncResp, entryCount, skip,
- top](const boost::system::error_code& ec, const uint16_t bootCount) {
- if (ec)
- {
- BMCWEB_LOG_DEBUG("DBUS response error {}", ec);
- messages::internalError(asyncResp->res);
- return;
- }
- getPostCodeForBoot(asyncResp, 1, bootCount, entryCount, skip, top);
- });
-}
-
-inline void requestRoutesPostCodesEntryCollection(App& app)
-{
- BMCWEB_ROUTE(app,
- "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/")
- .privileges(redfish::privileges::getLogEntryCollection)
- .methods(boost::beast::http::verb::get)(
- [&app](const crow::Request& req,
- const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
- const std::string& systemName) {
- query_param::QueryCapabilities capabilities = {
- .canDelegateTop = true,
- .canDelegateSkip = true,
- };
- query_param::Query delegatedQuery;
- if (!redfish::setUpRedfishRouteWithDelegation(
- app, req, asyncResp, delegatedQuery, capabilities))
- {
- return;
- }
- if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
- {
- // Option currently returns no systems. TBD
- messages::resourceNotFound(asyncResp->res, "ComputerSystem",
- systemName);
- return;
- }
-
- if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
- {
- messages::resourceNotFound(asyncResp->res, "ComputerSystem",
- systemName);
- return;
- }
- asyncResp->res.jsonValue["@odata.type"] =
- "#LogEntryCollection.LogEntryCollection";
- asyncResp->res.jsonValue["@odata.id"] = std::format(
- "/redfish/v1/Systems/{}/LogServices/PostCodes/Entries",
- BMCWEB_REDFISH_SYSTEM_URI_NAME);
- asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries";
- asyncResp->res.jsonValue["Description"] =
- "Collection of POST Code Log Entries";
- asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
- asyncResp->res.jsonValue["Members@odata.count"] = 0;
- size_t skip = delegatedQuery.skip.value_or(0);
- size_t top =
- delegatedQuery.top.value_or(query_param::Query::maxTop);
- getCurrentBootNumber(asyncResp, skip, top);
- });
-}
-
-inline void requestRoutesPostCodesEntryAdditionalData(App& app)
-{
- BMCWEB_ROUTE(
- app,
- "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/attachment/")
- .privileges(redfish::privileges::getLogEntry)
- .methods(
- boost::beast::http::verb::
- get)([&app](const crow::Request& req,
- const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
- const std::string& systemName,
- const std::string& postCodeID) {
- if (!redfish::setUpRedfishRoute(app, req, asyncResp))
- {
- return;
- }
- if (!http_helpers::isContentTypeAllowed(
- req.getHeaderValue("Accept"),
- http_helpers::ContentType::OctetStream, true))
- {
- asyncResp->res.result(boost::beast::http::status::bad_request);
- return;
- }
- if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
- {
- // Option currently returns no systems. TBD
- messages::resourceNotFound(asyncResp->res, "ComputerSystem",
- systemName);
- return;
- }
- if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
- {
- messages::resourceNotFound(asyncResp->res, "ComputerSystem",
- systemName);
- return;
- }
-
- uint64_t currentValue = 0;
- uint16_t index = 0;
- if (!parsePostCode(postCodeID, currentValue, index))
- {
- messages::resourceNotFound(asyncResp->res, "LogEntry",
- postCodeID);
- return;
- }
-
- crow::connections::systemBus->async_method_call(
- [asyncResp, postCodeID, currentValue](
- const boost::system::error_code& ec,
- const std::vector<std::tuple<
- uint64_t, std::vector<uint8_t>>>& postcodes) {
- if (ec.value() == EBADR)
- {
- messages::resourceNotFound(asyncResp->res, "LogEntry",
- postCodeID);
- return;
- }
- if (ec)
- {
- BMCWEB_LOG_DEBUG("DBUS response error {}", ec);
- messages::internalError(asyncResp->res);
- return;
- }
-
- size_t value = static_cast<size_t>(currentValue) - 1;
- if (value == std::string::npos ||
- postcodes.size() < currentValue)
- {
- BMCWEB_LOG_WARNING("Wrong currentValue value");
- messages::resourceNotFound(asyncResp->res, "LogEntry",
- postCodeID);
- return;
- }
-
- const auto& [tID, c] = postcodes[value];
- if (c.empty())
- {
- BMCWEB_LOG_WARNING("No found post code data");
- messages::resourceNotFound(asyncResp->res, "LogEntry",
- postCodeID);
- return;
- }
- // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
- const char* d = reinterpret_cast<const char*>(c.data());
- std::string_view strData(d, c.size());
-
- asyncResp->res.addHeader(
- boost::beast::http::field::content_type,
- "application/octet-stream");
- asyncResp->res.addHeader(
- boost::beast::http::field::content_transfer_encoding,
- "Base64");
- asyncResp->res.write(crow::utility::base64encode(strData));
- },
- "xyz.openbmc_project.State.Boot.PostCode0",
- "/xyz/openbmc_project/State/Boot/PostCode0",
- "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodes",
- index);
- });
-}
-
-inline void requestRoutesPostCodesEntry(App& app)
-{
- BMCWEB_ROUTE(
- app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/")
- .privileges(redfish::privileges::getLogEntry)
- .methods(boost::beast::http::verb::get)(
- [&app](const crow::Request& req,
- const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
- const std::string& systemName, const std::string& targetID) {
- if (!redfish::setUpRedfishRoute(app, req, asyncResp))
- {
- return;
- }
- if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
- {
- // Option currently returns no systems. TBD
- messages::resourceNotFound(asyncResp->res, "ComputerSystem",
- systemName);
- return;
- }
- if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
- {
- messages::resourceNotFound(asyncResp->res, "ComputerSystem",
- systemName);
- return;
- }
-
- getPostCodeForEntry(asyncResp, targetID);
- });
-}
-
} // namespace redfish
diff --git a/redfish-core/lib/systems_logservices_postcodes.hpp b/redfish-core/lib/systems_logservices_postcodes.hpp
new file mode 100644
index 0000000..7c592ad
--- /dev/null
+++ b/redfish-core/lib/systems_logservices_postcodes.hpp
@@ -0,0 +1,629 @@
+#pragma once
+
+#include "app.hpp"
+#include "generated/enums/log_service.hpp"
+#include "query.hpp"
+#include "registries/openbmc_message_registry.hpp"
+#include "registries/privilege_registry.hpp"
+#include "utils/time_utils.hpp"
+
+#include <cstdint>
+#include <memory>
+#include <string_view>
+#include <utility>
+#include <vector>
+
+namespace redfish
+{
+/****************************************************
+ * Redfish PostCode interfaces
+ * using DBUS interface: getPostCodesTS
+ ******************************************************/
+inline void requestRoutesPostCodesLogService(App& app)
+{
+ BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/")
+ .privileges(redfish::privileges::getLogService)
+ .methods(
+ boost::beast::http::verb::
+ get)([&app](const crow::Request& req,
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const std::string& systemName) {
+ if (!redfish::setUpRedfishRoute(app, req, asyncResp))
+ {
+ return;
+ }
+ if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
+ {
+ // Option currently returns no systems. TBD
+ messages::resourceNotFound(asyncResp->res, "ComputerSystem",
+ systemName);
+ return;
+ }
+ if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
+ {
+ messages::resourceNotFound(asyncResp->res, "ComputerSystem",
+ systemName);
+ return;
+ }
+ asyncResp->res.jsonValue["@odata.id"] =
+ std::format("/redfish/v1/Systems/{}/LogServices/PostCodes",
+ BMCWEB_REDFISH_SYSTEM_URI_NAME);
+ asyncResp->res.jsonValue["@odata.type"] =
+ "#LogService.v1_2_0.LogService";
+ asyncResp->res.jsonValue["Name"] = "POST Code Log Service";
+ asyncResp->res.jsonValue["Description"] = "POST Code Log Service";
+ asyncResp->res.jsonValue["Id"] = "PostCodes";
+ asyncResp->res.jsonValue["OverWritePolicy"] =
+ log_service::OverWritePolicy::WrapsWhenFull;
+ asyncResp->res.jsonValue["Entries"]["@odata.id"] = std::format(
+ "/redfish/v1/Systems/{}/LogServices/PostCodes/Entries",
+ BMCWEB_REDFISH_SYSTEM_URI_NAME);
+
+ std::pair<std::string, std::string> redfishDateTimeOffset =
+ redfish::time_utils::getDateTimeOffsetNow();
+ asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
+ asyncResp->res.jsonValue["DateTimeLocalOffset"] =
+ redfishDateTimeOffset.second;
+
+ asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]
+ ["target"] = std::format(
+ "/redfish/v1/Systems/{}/LogServices/PostCodes/Actions/LogService.ClearLog",
+ BMCWEB_REDFISH_SYSTEM_URI_NAME);
+ });
+}
+
+inline void requestRoutesPostCodesClear(App& app)
+{
+ BMCWEB_ROUTE(
+ app,
+ "/redfish/v1/Systems/<str>/LogServices/PostCodes/Actions/LogService.ClearLog/")
+ // The following privilege is incorrect; It should be ConfigureManager
+ //.privileges(redfish::privileges::postLogService)
+ .privileges({{"ConfigureComponents"}})
+ .methods(boost::beast::http::verb::post)(
+ [&app](const crow::Request& req,
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const std::string& systemName) {
+ if (!redfish::setUpRedfishRoute(app, req, asyncResp))
+ {
+ return;
+ }
+ if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
+ {
+ // Option currently returns no systems. TBD
+ messages::resourceNotFound(asyncResp->res, "ComputerSystem",
+ systemName);
+ return;
+ }
+ if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
+ {
+ messages::resourceNotFound(asyncResp->res, "ComputerSystem",
+ systemName);
+ return;
+ }
+ BMCWEB_LOG_DEBUG("Do delete all postcodes entries.");
+
+ // Make call to post-code service to request clear all
+ crow::connections::systemBus->async_method_call(
+ [asyncResp](const boost::system::error_code& ec) {
+ if (ec)
+ {
+ // TODO Handle for specific error code
+ BMCWEB_LOG_ERROR(
+ "doClearPostCodes resp_handler got error {}",
+ ec);
+ asyncResp->res.result(boost::beast::http::status::
+ internal_server_error);
+ messages::internalError(asyncResp->res);
+ return;
+ }
+ messages::success(asyncResp->res);
+ },
+ "xyz.openbmc_project.State.Boot.PostCode0",
+ "/xyz/openbmc_project/State/Boot/PostCode0",
+ "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll");
+ });
+}
+
+/**
+ * @brief Parse post code ID and get the current value and index value
+ * eg: postCodeID=B1-2, currentValue=1, index=2
+ *
+ * @param[in] postCodeID Post Code ID
+ * @param[out] currentValue Current value
+ * @param[out] index Index value
+ *
+ * @return bool true if the parsing is successful, false the parsing fails
+ */
+inline bool parsePostCode(std::string_view postCodeID, uint64_t& currentValue,
+ uint16_t& index)
+{
+ std::vector<std::string> split;
+ bmcweb::split(split, postCodeID, '-');
+ if (split.size() != 2)
+ {
+ return false;
+ }
+ std::string_view postCodeNumber = split[0];
+ if (postCodeNumber.size() < 2)
+ {
+ return false;
+ }
+ if (postCodeNumber[0] != 'B')
+ {
+ return false;
+ }
+ postCodeNumber.remove_prefix(1);
+ auto [ptrIndex, ecIndex] =
+ std::from_chars(postCodeNumber.begin(), postCodeNumber.end(), index);
+ if (ptrIndex != postCodeNumber.end() || ecIndex != std::errc())
+ {
+ return false;
+ }
+
+ std::string_view postCodeIndex = split[1];
+
+ auto [ptrValue, ecValue] = std::from_chars(
+ postCodeIndex.begin(), postCodeIndex.end(), currentValue);
+
+ return ptrValue == postCodeIndex.end() && ecValue == std::errc();
+}
+
+static bool fillPostCodeEntry(
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const boost::container::flat_map<
+ uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& postcode,
+ const uint16_t bootIndex, const uint64_t codeIndex = 0,
+ const uint64_t skip = 0, const uint64_t top = 0)
+{
+ // Get the Message from the MessageRegistry
+ const registries::Message* message =
+ registries::getMessage("OpenBMC.0.2.BIOSPOSTCode");
+ if (message == nullptr)
+ {
+ BMCWEB_LOG_ERROR("Couldn't find known message?");
+ return false;
+ }
+ uint64_t currentCodeIndex = 0;
+ uint64_t firstCodeTimeUs = 0;
+ for (const std::pair<uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
+ code : postcode)
+ {
+ currentCodeIndex++;
+ std::string postcodeEntryID =
+ "B" + std::to_string(bootIndex) + "-" +
+ std::to_string(currentCodeIndex); // 1 based index in EntryID string
+
+ uint64_t usecSinceEpoch = code.first;
+ uint64_t usTimeOffset = 0;
+
+ if (1 == currentCodeIndex)
+ { // already incremented
+ firstCodeTimeUs = code.first;
+ }
+ else
+ {
+ usTimeOffset = code.first - firstCodeTimeUs;
+ }
+
+ // skip if no specific codeIndex is specified and currentCodeIndex does
+ // not fall between top and skip
+ if ((codeIndex == 0) &&
+ (currentCodeIndex <= skip || currentCodeIndex > top))
+ {
+ continue;
+ }
+
+ // skip if a specific codeIndex is specified and does not match the
+ // currentIndex
+ if ((codeIndex > 0) && (currentCodeIndex != codeIndex))
+ {
+ // This is done for simplicity. 1st entry is needed to calculate
+ // time offset. To improve efficiency, one can get to the entry
+ // directly (possibly with flatmap's nth method)
+ continue;
+ }
+
+ // currentCodeIndex is within top and skip or equal to specified code
+ // index
+
+ // Get the Created time from the timestamp
+ std::string entryTimeStr;
+ entryTimeStr = redfish::time_utils::getDateTimeUintUs(usecSinceEpoch);
+
+ // assemble messageArgs: BootIndex, TimeOffset(100us), PostCode(hex)
+ std::ostringstream hexCode;
+ hexCode << "0x" << std::setfill('0') << std::setw(2) << std::hex
+ << std::get<0>(code.second);
+ std::ostringstream timeOffsetStr;
+ // Set Fixed -Point Notation
+ timeOffsetStr << std::fixed;
+ // Set precision to 4 digits
+ timeOffsetStr << std::setprecision(4);
+ // Add double to stream
+ timeOffsetStr << static_cast<double>(usTimeOffset) / 1000 / 1000;
+
+ std::string bootIndexStr = std::to_string(bootIndex);
+ std::string timeOffsetString = timeOffsetStr.str();
+ std::string hexCodeStr = hexCode.str();
+
+ std::array<std::string_view, 3> messageArgs = {
+ bootIndexStr, timeOffsetString, hexCodeStr};
+
+ std::string msg =
+ redfish::registries::fillMessageArgs(messageArgs, message->message);
+ if (msg.empty())
+ {
+ messages::internalError(asyncResp->res);
+ return false;
+ }
+
+ // Get Severity template from message registry
+ std::string severity;
+ if (message != nullptr)
+ {
+ severity = message->messageSeverity;
+ }
+
+ // Format entry
+ nlohmann::json::object_t bmcLogEntry;
+ bmcLogEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
+ bmcLogEntry["@odata.id"] = boost::urls::format(
+ "/redfish/v1/Systems/{}/LogServices/PostCodes/Entries/{}",
+ BMCWEB_REDFISH_SYSTEM_URI_NAME, postcodeEntryID);
+ bmcLogEntry["Name"] = "POST Code Log Entry";
+ bmcLogEntry["Id"] = postcodeEntryID;
+ bmcLogEntry["Message"] = std::move(msg);
+ bmcLogEntry["MessageId"] = "OpenBMC.0.2.BIOSPOSTCode";
+ bmcLogEntry["MessageArgs"] = messageArgs;
+ bmcLogEntry["EntryType"] = "Event";
+ bmcLogEntry["Severity"] = std::move(severity);
+ bmcLogEntry["Created"] = entryTimeStr;
+ if (!std::get<std::vector<uint8_t>>(code.second).empty())
+ {
+ bmcLogEntry["AdditionalDataURI"] =
+ std::format(
+ "/redfish/v1/Systems/{}/LogServices/PostCodes/Entries/",
+ BMCWEB_REDFISH_SYSTEM_URI_NAME) +
+ postcodeEntryID + "/attachment";
+ }
+
+ // codeIndex is only specified when querying single entry, return only
+ // that entry in this case
+ if (codeIndex != 0)
+ {
+ asyncResp->res.jsonValue.update(bmcLogEntry);
+ return true;
+ }
+
+ nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
+ logEntryArray.emplace_back(std::move(bmcLogEntry));
+ }
+
+ // Return value is always false when querying multiple entries
+ return false;
+}
+
+static void
+ getPostCodeForEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const std::string& entryId)
+{
+ uint16_t bootIndex = 0;
+ uint64_t codeIndex = 0;
+ if (!parsePostCode(entryId, codeIndex, bootIndex))
+ {
+ // Requested ID was not found
+ messages::resourceNotFound(asyncResp->res, "LogEntry", entryId);
+ return;
+ }
+
+ if (bootIndex == 0 || codeIndex == 0)
+ {
+ // 0 is an invalid index
+ messages::resourceNotFound(asyncResp->res, "LogEntry", entryId);
+ return;
+ }
+
+ crow::connections::systemBus->async_method_call(
+ [asyncResp, entryId, bootIndex,
+ codeIndex](const boost::system::error_code& ec,
+ const boost::container::flat_map<
+ uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
+ postcode) {
+ if (ec)
+ {
+ BMCWEB_LOG_DEBUG("DBUS POST CODE PostCode response error");
+ messages::internalError(asyncResp->res);
+ return;
+ }
+
+ if (postcode.empty())
+ {
+ messages::resourceNotFound(asyncResp->res, "LogEntry", entryId);
+ return;
+ }
+
+ if (!fillPostCodeEntry(asyncResp, postcode, bootIndex, codeIndex))
+ {
+ messages::resourceNotFound(asyncResp->res, "LogEntry", entryId);
+ return;
+ }
+ },
+ "xyz.openbmc_project.State.Boot.PostCode0",
+ "/xyz/openbmc_project/State/Boot/PostCode0",
+ "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
+ bootIndex);
+}
+
+static void
+ getPostCodeForBoot(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const uint16_t bootIndex, const uint16_t bootCount,
+ const uint64_t entryCount, size_t skip, size_t top)
+{
+ crow::connections::systemBus->async_method_call(
+ [asyncResp, bootIndex, bootCount, entryCount, skip,
+ top](const boost::system::error_code& ec,
+ const boost::container::flat_map<
+ uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
+ postcode) {
+ if (ec)
+ {
+ BMCWEB_LOG_DEBUG("DBUS POST CODE PostCode response error");
+ messages::internalError(asyncResp->res);
+ return;
+ }
+
+ uint64_t endCount = entryCount;
+ if (!postcode.empty())
+ {
+ endCount = entryCount + postcode.size();
+ if (skip < endCount && (top + skip) > entryCount)
+ {
+ uint64_t thisBootSkip =
+ std::max(static_cast<uint64_t>(skip), entryCount) -
+ entryCount;
+ uint64_t thisBootTop =
+ std::min(static_cast<uint64_t>(top + skip), endCount) -
+ entryCount;
+
+ fillPostCodeEntry(asyncResp, postcode, bootIndex, 0,
+ thisBootSkip, thisBootTop);
+ }
+ asyncResp->res.jsonValue["Members@odata.count"] = endCount;
+ }
+
+ // continue to previous bootIndex
+ if (bootIndex < bootCount)
+ {
+ getPostCodeForBoot(asyncResp,
+ static_cast<uint16_t>(bootIndex + 1),
+ bootCount, endCount, skip, top);
+ }
+ else if (skip + top < endCount)
+ {
+ asyncResp->res.jsonValue["Members@odata.nextLink"] =
+ std::format(
+ "/redfish/v1/Systems/{}/LogServices/PostCodes/Entries?$skip=",
+ BMCWEB_REDFISH_SYSTEM_URI_NAME) +
+ std::to_string(skip + top);
+ }
+ },
+ "xyz.openbmc_project.State.Boot.PostCode0",
+ "/xyz/openbmc_project/State/Boot/PostCode0",
+ "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
+ bootIndex);
+}
+
+static void
+ getCurrentBootNumber(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ size_t skip, size_t top)
+{
+ uint64_t entryCount = 0;
+ sdbusplus::asio::getProperty<uint16_t>(
+ *crow::connections::systemBus,
+ "xyz.openbmc_project.State.Boot.PostCode0",
+ "/xyz/openbmc_project/State/Boot/PostCode0",
+ "xyz.openbmc_project.State.Boot.PostCode", "CurrentBootCycleCount",
+ [asyncResp, entryCount, skip,
+ top](const boost::system::error_code& ec, const uint16_t bootCount) {
+ if (ec)
+ {
+ BMCWEB_LOG_DEBUG("DBUS response error {}", ec);
+ messages::internalError(asyncResp->res);
+ return;
+ }
+ getPostCodeForBoot(asyncResp, 1, bootCount, entryCount, skip, top);
+ });
+}
+
+inline void requestRoutesPostCodesEntryCollection(App& app)
+{
+ BMCWEB_ROUTE(app,
+ "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/")
+ .privileges(redfish::privileges::getLogEntryCollection)
+ .methods(boost::beast::http::verb::get)(
+ [&app](const crow::Request& req,
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const std::string& systemName) {
+ query_param::QueryCapabilities capabilities = {
+ .canDelegateTop = true,
+ .canDelegateSkip = true,
+ };
+ query_param::Query delegatedQuery;
+ if (!redfish::setUpRedfishRouteWithDelegation(
+ app, req, asyncResp, delegatedQuery, capabilities))
+ {
+ return;
+ }
+ if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
+ {
+ // Option currently returns no systems. TBD
+ messages::resourceNotFound(asyncResp->res, "ComputerSystem",
+ systemName);
+ return;
+ }
+
+ if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
+ {
+ messages::resourceNotFound(asyncResp->res, "ComputerSystem",
+ systemName);
+ return;
+ }
+ asyncResp->res.jsonValue["@odata.type"] =
+ "#LogEntryCollection.LogEntryCollection";
+ asyncResp->res.jsonValue["@odata.id"] = std::format(
+ "/redfish/v1/Systems/{}/LogServices/PostCodes/Entries",
+ BMCWEB_REDFISH_SYSTEM_URI_NAME);
+ asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries";
+ asyncResp->res.jsonValue["Description"] =
+ "Collection of POST Code Log Entries";
+ asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
+ asyncResp->res.jsonValue["Members@odata.count"] = 0;
+ size_t skip = delegatedQuery.skip.value_or(0);
+ size_t top =
+ delegatedQuery.top.value_or(query_param::Query::maxTop);
+ getCurrentBootNumber(asyncResp, skip, top);
+ });
+}
+
+inline void requestRoutesPostCodesEntryAdditionalData(App& app)
+{
+ BMCWEB_ROUTE(
+ app,
+ "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/attachment/")
+ .privileges(redfish::privileges::getLogEntry)
+ .methods(
+ boost::beast::http::verb::
+ get)([&app](const crow::Request& req,
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const std::string& systemName,
+ const std::string& postCodeID) {
+ if (!redfish::setUpRedfishRoute(app, req, asyncResp))
+ {
+ return;
+ }
+ if (!http_helpers::isContentTypeAllowed(
+ req.getHeaderValue("Accept"),
+ http_helpers::ContentType::OctetStream, true))
+ {
+ asyncResp->res.result(boost::beast::http::status::bad_request);
+ return;
+ }
+ if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
+ {
+ // Option currently returns no systems. TBD
+ messages::resourceNotFound(asyncResp->res, "ComputerSystem",
+ systemName);
+ return;
+ }
+ if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
+ {
+ messages::resourceNotFound(asyncResp->res, "ComputerSystem",
+ systemName);
+ return;
+ }
+
+ uint64_t currentValue = 0;
+ uint16_t index = 0;
+ if (!parsePostCode(postCodeID, currentValue, index))
+ {
+ messages::resourceNotFound(asyncResp->res, "LogEntry",
+ postCodeID);
+ return;
+ }
+
+ crow::connections::systemBus->async_method_call(
+ [asyncResp, postCodeID, currentValue](
+ const boost::system::error_code& ec,
+ const std::vector<std::tuple<
+ uint64_t, std::vector<uint8_t>>>& postcodes) {
+ if (ec.value() == EBADR)
+ {
+ messages::resourceNotFound(asyncResp->res, "LogEntry",
+ postCodeID);
+ return;
+ }
+ if (ec)
+ {
+ BMCWEB_LOG_DEBUG("DBUS response error {}", ec);
+ messages::internalError(asyncResp->res);
+ return;
+ }
+
+ size_t value = static_cast<size_t>(currentValue) - 1;
+ if (value == std::string::npos ||
+ postcodes.size() < currentValue)
+ {
+ BMCWEB_LOG_WARNING("Wrong currentValue value");
+ messages::resourceNotFound(asyncResp->res, "LogEntry",
+ postCodeID);
+ return;
+ }
+
+ const auto& [tID, c] = postcodes[value];
+ if (c.empty())
+ {
+ BMCWEB_LOG_WARNING("No found post code data");
+ messages::resourceNotFound(asyncResp->res, "LogEntry",
+ postCodeID);
+ return;
+ }
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ const char* d = reinterpret_cast<const char*>(c.data());
+ std::string_view strData(d, c.size());
+
+ asyncResp->res.addHeader(
+ boost::beast::http::field::content_type,
+ "application/octet-stream");
+ asyncResp->res.addHeader(
+ boost::beast::http::field::content_transfer_encoding,
+ "Base64");
+ asyncResp->res.write(crow::utility::base64encode(strData));
+ },
+ "xyz.openbmc_project.State.Boot.PostCode0",
+ "/xyz/openbmc_project/State/Boot/PostCode0",
+ "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodes",
+ index);
+ });
+}
+
+inline void requestRoutesPostCodesEntry(App& app)
+{
+ BMCWEB_ROUTE(
+ app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/")
+ .privileges(redfish::privileges::getLogEntry)
+ .methods(boost::beast::http::verb::get)(
+ [&app](const crow::Request& req,
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const std::string& systemName, const std::string& targetID) {
+ if (!redfish::setUpRedfishRoute(app, req, asyncResp))
+ {
+ return;
+ }
+ if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
+ {
+ // Option currently returns no systems. TBD
+ messages::resourceNotFound(asyncResp->res, "ComputerSystem",
+ systemName);
+ return;
+ }
+ if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
+ {
+ messages::resourceNotFound(asyncResp->res, "ComputerSystem",
+ systemName);
+ return;
+ }
+
+ getPostCodeForEntry(asyncResp, targetID);
+ });
+}
+
+inline void requestRoutesSystemsLogServicesPostCode(App& app)
+{
+ requestRoutesPostCodesClear(app);
+ requestRoutesPostCodesEntry(app);
+ requestRoutesPostCodesEntryAdditionalData(app);
+ requestRoutesPostCodesEntryCollection(app);
+ requestRoutesPostCodesLogService(app);
+}
+} // namespace redfish
diff --git a/redfish-core/src/redfish.cpp b/redfish-core/src/redfish.cpp
index e81691f..95f50ca 100644
--- a/redfish-core/src/redfish.cpp
+++ b/redfish-core/src/redfish.cpp
@@ -39,6 +39,7 @@
#include "service_root.hpp"
#include "storage.hpp"
#include "systems.hpp"
+#include "systems_logservices_postcodes.hpp"
#include "task.hpp"
#include "telemetry_service.hpp"
#include "thermal.hpp"
@@ -108,12 +109,8 @@
requestRoutesSystemLogServiceCollection(app);
requestRoutesEventLogService(app);
- requestRoutesPostCodesEntryAdditionalData(app);
- requestRoutesPostCodesLogService(app);
- requestRoutesPostCodesClear(app);
- requestRoutesPostCodesEntry(app);
- requestRoutesPostCodesEntryCollection(app);
+ requestRoutesSystemsLogServicesPostCode(app);
if constexpr (BMCWEB_REDFISH_DUMP_LOG)
{
diff --git a/test/redfish-core/lib/log_services_test.cpp b/test/redfish-core/lib/manager_logservices_journal_test.cpp
similarity index 67%
rename from test/redfish-core/lib/log_services_test.cpp
rename to test/redfish-core/lib/manager_logservices_journal_test.cpp
index e413d0e..86c201c 100644
--- a/test/redfish-core/lib/log_services_test.cpp
+++ b/test/redfish-core/lib/manager_logservices_journal_test.cpp
@@ -1,5 +1,4 @@
#include "async_resp.hpp"
-#include "log_services.hpp"
#include "manager_logservices_journal.hpp"
#include <systemd/sd-id128.h>
@@ -68,34 +67,5 @@
EXPECT_EQ(indexOut, 1);
}
-TEST(LogServicesPostCodeParse, PostCodeParse)
-{
- uint64_t currentValue = 0;
- uint16_t index = 0;
- EXPECT_TRUE(parsePostCode("B1-2", currentValue, index));
- EXPECT_EQ(currentValue, 2);
- EXPECT_EQ(index, 1);
- EXPECT_TRUE(parsePostCode("B200-300", currentValue, index));
- EXPECT_EQ(currentValue, 300);
- EXPECT_EQ(index, 200);
-
- EXPECT_FALSE(parsePostCode("", currentValue, index));
- EXPECT_FALSE(parsePostCode("B", currentValue, index));
- EXPECT_FALSE(parsePostCode("B1", currentValue, index));
- EXPECT_FALSE(parsePostCode("B1-", currentValue, index));
- EXPECT_FALSE(parsePostCode("B1A-2", currentValue, index));
- EXPECT_FALSE(parsePostCode("B1A-2", currentValue, index));
- EXPECT_FALSE(parsePostCode("B1A-2z", currentValue, index));
- // Uint16_t max + 1
- EXPECT_FALSE(parsePostCode("B65536-1", currentValue, index));
-
- // Uint64_t max + 1
- EXPECT_FALSE(parsePostCode("B1-18446744073709551616", currentValue, index));
-
- // Negative numbers
- EXPECT_FALSE(parsePostCode("B-1-2", currentValue, index));
- EXPECT_FALSE(parsePostCode("B-1--2", currentValue, index));
-}
-
} // namespace
} // namespace redfish
diff --git a/test/redfish-core/lib/systems_logservices_postcode.cpp b/test/redfish-core/lib/systems_logservices_postcode.cpp
new file mode 100644
index 0000000..aa98cb1
--- /dev/null
+++ b/test/redfish-core/lib/systems_logservices_postcode.cpp
@@ -0,0 +1,43 @@
+
+#include "systems_logservices_postcodes.hpp"
+
+#include <cstdint>
+
+#include <gtest/gtest.h>
+
+namespace redfish
+{
+namespace
+{
+
+TEST(LogServicesPostCodeParse, PostCodeParse)
+{
+ uint64_t currentValue = 0;
+ uint16_t index = 0;
+ EXPECT_TRUE(parsePostCode("B1-2", currentValue, index));
+ EXPECT_EQ(currentValue, 2);
+ EXPECT_EQ(index, 1);
+ EXPECT_TRUE(parsePostCode("B200-300", currentValue, index));
+ EXPECT_EQ(currentValue, 300);
+ EXPECT_EQ(index, 200);
+
+ EXPECT_FALSE(parsePostCode("", currentValue, index));
+ EXPECT_FALSE(parsePostCode("B", currentValue, index));
+ EXPECT_FALSE(parsePostCode("B1", currentValue, index));
+ EXPECT_FALSE(parsePostCode("B1-", currentValue, index));
+ EXPECT_FALSE(parsePostCode("B1A-2", currentValue, index));
+ EXPECT_FALSE(parsePostCode("B1A-2", currentValue, index));
+ EXPECT_FALSE(parsePostCode("B1A-2z", currentValue, index));
+ // Uint16_t max + 1
+ EXPECT_FALSE(parsePostCode("B65536-1", currentValue, index));
+
+ // Uint64_t max + 1
+ EXPECT_FALSE(parsePostCode("B1-18446744073709551616", currentValue, index));
+
+ // Negative numbers
+ EXPECT_FALSE(parsePostCode("B-1-2", currentValue, index));
+ EXPECT_FALSE(parsePostCode("B-1--2", currentValue, index));
+}
+
+} // namespace
+} // namespace redfish