summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatt Spinler <spinler@us.ibm.com>2019-09-19 15:33:52 -0500
committerMatt Spinler <spinler@us.ibm.com>2019-10-09 13:11:51 +0000
commit367144cfa0eb857f4cb9ba786f43933469e19e34 (patch)
tree8291c90a44b4ec2b321c3ca2c6e5ed13e21307f9
parent835a86938f3cf59fbdcd25835b48e6cdb1e6552b (diff)
downloadphosphor-logging-367144cfa0eb857f4cb9ba786f43933469e19e34.tar.gz
phosphor-logging-367144cfa0eb857f4cb9ba786f43933469e19e34.zip
PEL: Find an entry in the message registry JSON
The message registry is a JSON file that holds data required to create a PEL out of an OpenBMC event log. It includes fields like 'subsystem', 'event type', 'action flags', 'SRC reason code', etc. Many fields in the message registry are optional, and a very minimal entry make look like: { "Name": "xyz.openbmc_project.Power.Error.Fault", "Subsystem": "power_supply", "ActionFlags": ["service_action", "report"], "SRC": { "ReasonCode": "0x2030" } } This commit adds support to look up a message registry entry based on an OpenBMC event log's 'Message' property (i.e. xyz.openbmc_project.Power.Error.Fault) and then fill in a structure with the fields found. Future commits will fill in the SRC related fields, as well as actually create the PEL. The message registry file can be found on the BMC at: /usr/share/phosphor-logging/pels/message_registry.json. For testing, users can put their own message_registry.json in /etc/phosphor-logging, and that will take precedence. Signed-off-by: Matt Spinler <spinler@us.ibm.com> Change-Id: Ie4195ed7e58ab6a231271f6b295e63b1d0a4cd78
-rw-r--r--configure.ac7
-rw-r--r--extensions/openpower-pels/manager.cpp1
-rw-r--r--extensions/openpower-pels/manager.hpp18
-rw-r--r--extensions/openpower-pels/openpower-pels.mk1
-rw-r--r--extensions/openpower-pels/paths.cpp6
-rw-r--r--extensions/openpower-pels/paths.hpp4
-rw-r--r--extensions/openpower-pels/registry.cpp195
-rw-r--r--extensions/openpower-pels/registry.hpp179
-rw-r--r--test/openpower-pels/Makefile.include13
-rw-r--r--test/openpower-pels/paths.cpp13
-rw-r--r--test/openpower-pels/pel_manager_test.cpp3
-rw-r--r--test/openpower-pels/pel_utils.cpp1
-rw-r--r--test/openpower-pels/pel_utils.hpp3
-rw-r--r--test/openpower-pels/registry_test.cpp166
14 files changed, 602 insertions, 8 deletions
diff --git a/configure.ac b/configure.ac
index ead0a07..e5f2d81 100644
--- a/configure.ac
+++ b/configure.ac
@@ -159,6 +159,13 @@ AC_DEFINE_UNQUOTED([EXTENSION_PERSIST_DIR], ["$EXTENSION_PERSIST_DIR"], \
AM_CONDITIONAL([ENABLE_PEL_EXTENSION], [test "x$enable_openpower_pel_extension" == "xyes"])
+AS_IF([test "x$enable_openpower_pel_extension" == "xyes"],
+ [AC_CHECK_HEADER(
+ nlohmann/json.hpp,
+ [],
+ [AC_MSG_ERROR([Could not find nlohmann/json.hpp])]])
+)
+
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_FILES([Makefile test/Makefile phosphor-rsyslog-config/Makefile])
AC_CONFIG_FILES([phosphor-logging.pc])
diff --git a/extensions/openpower-pels/manager.cpp b/extensions/openpower-pels/manager.cpp
index ef071bd..fd3670c 100644
--- a/extensions/openpower-pels/manager.cpp
+++ b/extensions/openpower-pels/manager.cpp
@@ -110,6 +110,7 @@ void Manager::createPEL(const std::string& message, uint32_t obmcLogID,
const std::vector<std::string>& additionalData,
const std::vector<std::string>& associations)
{
+ // TODO: look up the error in _registry and create a PEL
}
} // namespace pels
diff --git a/extensions/openpower-pels/manager.hpp b/extensions/openpower-pels/manager.hpp
index 49ac8bf..5f092f4 100644
--- a/extensions/openpower-pels/manager.hpp
+++ b/extensions/openpower-pels/manager.hpp
@@ -3,6 +3,7 @@
#include "data_interface.hpp"
#include "log_manager.hpp"
#include "paths.hpp"
+#include "registry.hpp"
#include "repository.hpp"
namespace openpower
@@ -10,8 +11,6 @@ namespace openpower
namespace pels
{
-using namespace phosphor::logging;
-
/**
* @brief PEL manager object
*/
@@ -33,7 +32,9 @@ class Manager
explicit Manager(phosphor::logging::internal::Manager& logManager,
std::unique_ptr<DataInterfaceBase>&& dataIface) :
_logManager(logManager),
- _repo(getPELRepoPath()), _dataIface(std::move(dataIface))
+ _repo(getPELRepoPath()),
+ _registry(getMessageRegistryPath() / message::registryFileName),
+ _dataIface(std::move(dataIface))
{
}
@@ -50,7 +51,7 @@ class Manager
* @param[in] associations - the Associations property
*/
void create(const std::string& message, uint32_t obmcLogID,
- uint64_t timestamp, Entry::Level severity,
+ uint64_t timestamp, phosphor::logging::Entry::Level severity,
const std::vector<std::string>& additionalData,
const std::vector<std::string>& associations);
@@ -93,14 +94,14 @@ class Manager
* @param[in] associations - The associations property
*/
void createPEL(const std::string& message, uint32_t obmcLogID,
- uint64_t timestamp, Entry::Level severity,
+ uint64_t timestamp, phosphor::logging::Entry::Level severity,
const std::vector<std::string>& additionalData,
const std::vector<std::string>& associations);
/**
* @brief Reference to phosphor-logging's Manager class
*/
- internal::Manager& _logManager;
+ phosphor::logging::internal::Manager& _logManager;
/**
* @brief The PEL repository object
@@ -108,6 +109,11 @@ class Manager
Repository _repo;
/**
+ * @brief The PEL message registry object
+ */
+ message::Registry _registry;
+
+ /**
* @brief The API the PEL sections use to gather data
*/
std::unique_ptr<DataInterfaceBase> _dataIface;
diff --git a/extensions/openpower-pels/openpower-pels.mk b/extensions/openpower-pels/openpower-pels.mk
index 14e1966..aa69a2e 100644
--- a/extensions/openpower-pels/openpower-pels.mk
+++ b/extensions/openpower-pels/openpower-pels.mk
@@ -10,5 +10,6 @@ phosphor_log_manager_SOURCES += \
extensions/openpower-pels/pel.cpp \
extensions/openpower-pels/pel_values.cpp \
extensions/openpower-pels/private_header.cpp \
+ extensions/openpower-pels/registry.cpp \
extensions/openpower-pels/repository.cpp \
extensions/openpower-pels/user_header.cpp
diff --git a/extensions/openpower-pels/paths.cpp b/extensions/openpower-pels/paths.cpp
index 27e7373..b8ccfe8 100644
--- a/extensions/openpower-pels/paths.cpp
+++ b/extensions/openpower-pels/paths.cpp
@@ -25,6 +25,10 @@ fs::path getPELRepoPath()
return repoPath;
}
-} // namespace pels
+fs::path getMessageRegistryPath()
+{
+ return std::filesystem::path{"/usr/share/phosphor-logging/pels"};
+}
+} // namespace pels
} // namespace openpower
diff --git a/extensions/openpower-pels/paths.hpp b/extensions/openpower-pels/paths.hpp
index 64566d2..91d8c5f 100644
--- a/extensions/openpower-pels/paths.hpp
+++ b/extensions/openpower-pels/paths.hpp
@@ -16,5 +16,9 @@ std::filesystem::path getPELIDFile();
*/
std::filesystem::path getPELRepoPath();
+/**
+ * @brief Returns the path to the message registry JSON file
+ */
+std::filesystem::path getMessageRegistryPath();
} // namespace pels
} // namespace openpower
diff --git a/extensions/openpower-pels/registry.cpp b/extensions/openpower-pels/registry.cpp
new file mode 100644
index 0000000..42ced0c
--- /dev/null
+++ b/extensions/openpower-pels/registry.cpp
@@ -0,0 +1,195 @@
+#include "registry.hpp"
+
+#include "pel_types.hpp"
+#include "pel_values.hpp"
+
+#include <fstream>
+#include <phosphor-logging/log.hpp>
+
+namespace openpower
+{
+namespace pels
+{
+namespace message
+{
+
+namespace pv = pel_values;
+namespace fs = std::filesystem;
+using namespace phosphor::logging;
+
+constexpr auto debugFilePath = "/etc/phosphor-logging/";
+
+namespace helper
+{
+
+uint8_t getSubsystem(const std::string& subsystemName)
+{
+ // Get the actual value to use in the PEL for the string name
+ auto ss = pv::findByName(subsystemName, pv::subsystemValues);
+ if (ss == pv::subsystemValues.end())
+ {
+ // Schema validation should be catching this.
+ log<level::ERR>("Invalid subsystem name used in message registry",
+ entry("SUBSYSTEM=%s", subsystemName.c_str()));
+
+ throw std::runtime_error("Invalid subsystem used in message registry");
+ }
+
+ return std::get<pv::fieldValuePos>(*ss);
+}
+
+uint8_t getSeverity(const std::string& severityName)
+{
+ auto s = pv::findByName(severityName, pv::severityValues);
+ if (s == pv::severityValues.end())
+ {
+ // Schema validation should be catching this.
+ log<level::ERR>("Invalid severity name used in message registry",
+ entry("SEVERITY=%s", severityName.c_str()));
+
+ throw std::runtime_error("Invalid severity used in message registry");
+ }
+
+ return std::get<pv::fieldValuePos>(*s);
+}
+
+uint16_t getActionFlags(const std::vector<std::string>& flags)
+{
+ uint16_t actionFlags = 0;
+
+ // Make the bitmask based on the array of flag names
+ for (const auto& flag : flags)
+ {
+ auto s = pv::findByName(flag, pv::actionFlagsValues);
+ if (s == pv::actionFlagsValues.end())
+ {
+ // Schema validation should be catching this.
+ log<level::ERR>("Invalid action flag name used in message registry",
+ entry("FLAG=%s", flag.c_str()));
+
+ throw std::runtime_error(
+ "Invalid action flag used in message registry");
+ }
+
+ actionFlags |= std::get<pv::fieldValuePos>(*s);
+ }
+
+ return actionFlags;
+}
+
+uint8_t getEventType(const std::string& eventTypeName)
+{
+ auto t = pv::findByName(eventTypeName, pv::eventTypeValues);
+ if (t == pv::eventTypeValues.end())
+ {
+ log<level::ERR>("Invalid event type used in message registry",
+ entry("EVENT_TYPE=%s", eventTypeName.c_str()));
+
+ throw std::runtime_error("Invalid event type used in message registry");
+ }
+ return std::get<pv::fieldValuePos>(*t);
+}
+
+uint8_t getEventScope(const std::string& eventScopeName)
+{
+ auto s = pv::findByName(eventScopeName, pv::eventScopeValues);
+ if (s == pv::eventScopeValues.end())
+ {
+ log<level::ERR>("Invalid event scope used in registry",
+ entry("EVENT_SCOPE=%s", eventScopeName.c_str()));
+
+ throw std::runtime_error(
+ "Invalid event scope used in message registry");
+ }
+ return std::get<pv::fieldValuePos>(*s);
+}
+
+} // namespace helper
+
+std::optional<Entry> Registry::lookup(const std::string& name)
+{
+ // Look in /etc first in case someone put a test file there
+ fs::path debugFile{fs::path{debugFilePath} / registryFileName};
+ nlohmann::json registry;
+ std::ifstream file;
+
+ if (fs::exists(debugFile))
+ {
+ log<level::INFO>("Using debug PEL message registry");
+ file.open(debugFile);
+ }
+ else
+ {
+ file.open(_registryFile);
+ }
+
+ try
+ {
+ registry = nlohmann::json::parse(file);
+ }
+ catch (std::exception& e)
+ {
+ log<level::ERR>("Error parsing message registry JSON",
+ entry("JSON_ERROR=%s", e.what()));
+ return std::nullopt;
+ }
+
+ // Find an entry with this name in the PEL array.
+ auto e = std::find_if(registry["PELs"].begin(), registry["PELs"].end(),
+ [&name](const auto& j) { return name == j["Name"]; });
+
+ if (e != registry["PELs"].end())
+ {
+ // Fill in the Entry structure from the JSON. Most, but not all, fields
+ // are optional.
+
+ try
+ {
+ Entry entry;
+ entry.name = (*e)["Name"];
+ entry.subsystem = helper::getSubsystem((*e)["Subsystem"]);
+ entry.actionFlags = helper::getActionFlags((*e)["ActionFlags"]);
+
+ if (e->find("MfgActionFlags") != e->end())
+ {
+ entry.mfgActionFlags =
+ helper::getActionFlags((*e)["MfgActionFlags"]);
+ }
+
+ if (e->find("Severity") != e->end())
+ {
+ entry.severity = helper::getSeverity((*e)["Severity"]);
+ }
+
+ if (e->find("MfgSeverity") != e->end())
+ {
+ entry.mfgSeverity = helper::getSeverity((*e)["MfgSeverity"]);
+ }
+
+ if (e->find("EventType") != e->end())
+ {
+ entry.eventType = helper::getEventType((*e)["EventType"]);
+ }
+
+ if (e->find("EventScope") != e->end())
+ {
+ entry.eventScope = helper::getEventScope((*e)["EventScope"]);
+ }
+
+ // TODO: SRC fields
+
+ return entry;
+ }
+ catch (std::exception& e)
+ {
+ log<level::ERR>("Found invalid message registry field",
+ entry("ERROR=%s", e.what()));
+ }
+ }
+
+ return std::nullopt;
+}
+
+} // namespace message
+} // namespace pels
+} // namespace openpower
diff --git a/extensions/openpower-pels/registry.hpp b/extensions/openpower-pels/registry.hpp
new file mode 100644
index 0000000..e56bd42
--- /dev/null
+++ b/extensions/openpower-pels/registry.hpp
@@ -0,0 +1,179 @@
+#pragma once
+#include <filesystem>
+#include <nlohmann/json.hpp>
+#include <optional>
+#include <string>
+#include <vector>
+
+namespace openpower
+{
+namespace pels
+{
+namespace message
+{
+
+constexpr auto registryFileName = "message_registry.json";
+
+/**
+ * @brief Represents a message registry entry, which is used for creating a
+ * PEL from an OpenBMC event log.
+ */
+struct Entry
+{
+ /**
+ * @brief The error name, like "xyz.openbmc_project.Error.Foo".
+ */
+ std::string name;
+
+ /**
+ * @brief The PEL subsystem field.
+ */
+ uint8_t subsystem;
+
+ /**
+ * @brief The optional PEL severity field. If not specified, the PEL
+ * will use the severity of the OpenBMC event log.
+ */
+ std::optional<uint8_t> severity;
+
+ /**
+ * @brief The optional severity field to use when in manufacturing tolerance
+ * mode.
+ */
+ std::optional<uint8_t> mfgSeverity;
+
+ /**
+ * @brief The PEL action flags field.
+ */
+ uint16_t actionFlags;
+
+ /**
+ * @brief The optional action flags to use instead when in manufacturing
+ * tolerance mode.
+ */
+ std::optional<uint16_t> mfgActionFlags;
+
+ /**
+ * @brief The PEL event type field. If not specified, higher level code
+ * will decide the value.
+ */
+ std::optional<uint8_t> eventType;
+
+ /**
+ * @brief The PEL event scope field. If not specified, higher level code
+ * will decide the value.
+ */
+ std::optional<uint8_t> eventScope;
+
+ // TODO: SRC related fields
+};
+
+/**
+ * @class Registry
+ *
+ * This class wraps the message registry JSON data and allows one to find
+ * the message registry entry pertaining to the error name.
+ *
+ * So that new registry files can easily be tested, the code will look for
+ * /etc/phosphor-logging/message_registry.json before looking for the real
+ * path.
+ */
+class Registry
+{
+ public:
+ Registry() = delete;
+ ~Registry() = default;
+ Registry(const Registry&) = default;
+ Registry& operator=(const Registry&) = default;
+ Registry(Registry&&) = default;
+ Registry& operator=(Registry&&) = default;
+
+ /**
+ * @brief Constructor
+ * @param[in] registryFile - The path to the file.
+ */
+ explicit Registry(const std::filesystem::path& registryFile) :
+ _registryFile(registryFile)
+ {
+ }
+
+ /**
+ * @brief Find a registry entry based on its error name.
+ *
+ * This function does do some basic sanity checking on the JSON contents,
+ * but there is also an external program that enforces a schema on the
+ * registry JSON that should catch all of these problems ahead of time.
+ *
+ * @param[in] name - The error name, like xyz.openbmc_project.Error.Foo
+ *
+ * @return optional<Entry> A filled in message registry structure if
+ * found, otherwise an empty optional object.
+ */
+ std::optional<Entry> lookup(const std::string& name);
+
+ private:
+ /**
+ * @brief The path to the registry JSON file.
+ */
+ std::filesystem::path _registryFile;
+};
+
+namespace helper
+{
+
+/**
+ * @brief A helper function to get the PEL subsystem value based on
+ * the registry subsystem name.
+ *
+ * @param[in] subsystemName - The registry name for the subsystem
+ *
+ * @return uint8_t The PEL subsystem value
+ */
+uint8_t getSubsystem(const std::string& subsystemName);
+
+/**
+ * @brief A helper function to get the PEL severity value based on
+ * the registry severity name.
+ *
+ * @param[in] severityName - The registry name for the severity
+ *
+ * @return uint8_t The PEL severity value
+ */
+uint8_t getSeverity(const std::string& severityName);
+
+/**
+ * @brief A helper function to get the action flags value based on
+ * the action flag names used in the registry.
+ *
+ * @param[in] flags - The list of flag names from the registry.
+ *
+ * @return uint16_t - The bitfield of flags used in the PEL.
+ */
+uint16_t getActionFlags(const std::vector<std::string>& flags);
+
+/**
+ * @brief A helper function to get the PEL event type value based on
+ * the registry event type name.
+ *
+ * @param[in] eventTypeName - The registry name for the event type
+ *
+ * @return uint8_t The PEL event type value
+ */
+uint8_t getEventType(const std::string& eventTypeName);
+
+/**
+ * @brief A helper function to get the PEL event scope value based on
+ * the registry event scope name.
+ *
+ * @param[in] eventScopeName - The registry name for the event scope
+ *
+ * @return uint8_t The PEL event scope value
+ */
+uint8_t getEventScope(const std::string& eventScopeName);
+
+} // namespace helper
+
+} // namespace message
+
+} // namespace pels
+} // namespace openpower
diff --git a/test/openpower-pels/Makefile.include b/test/openpower-pels/Makefile.include
index 5705f73..18df9ec 100644
--- a/test/openpower-pels/Makefile.include
+++ b/test/openpower-pels/Makefile.include
@@ -10,6 +10,7 @@ check_PROGRAMS += \
pel_values_test \
pel_manager_test \
private_header_test \
+ registry_test \
repository_test \
section_header_test \
stream_test \
@@ -19,7 +20,9 @@ pel_objects = \
$(top_builddir)/extensions/openpower-pels/bcd_time.o \
$(top_builddir)/extensions/openpower-pels/log_id.o \
$(top_builddir)/extensions/openpower-pels/pel.o \
+ $(top_builddir)/extensions/openpower-pels/pel_values.o \
$(top_builddir)/extensions/openpower-pels/private_header.o \
+ $(top_builddir)/extensions/openpower-pels/registry.o \
$(top_builddir)/extensions/openpower-pels/user_header.o
additional_data_test_SOURCES = %reldir%/additional_data_test.cpp
@@ -108,6 +111,16 @@ pel_manager_test_LDADD = \
$(top_builddir)/extensions/openpower-pels/repository.o
pel_manager_test_LDFLAGS = $(test_ldflags)
+registry_test_SOURCES = \
+ %reldir%/registry_test.cpp %reldir%/paths.cpp
+registry_test_CPPFLAGS = $(test_cppflags)
+registry_test_CXXFLAGS = $(test_cxxflags)
+registry_test_LDADD = \
+ $(test_ldadd) \
+ $(top_builddir)/extensions/openpower-pels/registry.o \
+ $(top_builddir)/extensions/openpower-pels/pel_values.o
+registry_test_LDFLAGS = $(test_ldflags)
+
mtms_test_SOURCES = %reldir%/mtms_test.cpp
mtms_test_CPPFLAGS = $(test_cppflags)
mtms_test_CXXFLAGS = $(test_cxxflags)
diff --git a/test/openpower-pels/paths.cpp b/test/openpower-pels/paths.cpp
index 27f4bce..502fcf0 100644
--- a/test/openpower-pels/paths.cpp
+++ b/test/openpower-pels/paths.cpp
@@ -35,5 +35,18 @@ std::filesystem::path getPELRepoPath()
return repoPath;
}
+std::filesystem::path getMessageRegistryPath()
+{
+ static std::string registryPath;
+
+ if (registryPath.empty())
+ {
+ char templ[] = "/tmp/msgregtestXXXXXX";
+ registryPath = mkdtemp(templ);
+ }
+
+ return registryPath;
+}
+
} // namespace pels
} // namespace openpower
diff --git a/test/openpower-pels/pel_manager_test.cpp b/test/openpower-pels/pel_manager_test.cpp
index 0a82141..61fbedd 100644
--- a/test/openpower-pels/pel_manager_test.cpp
+++ b/test/openpower-pels/pel_manager_test.cpp
@@ -45,7 +45,8 @@ TEST_F(ManagerTest, TestCreateWithPEL)
std::vector<std::string> additionalData{adItem};
std::vector<std::string> associations;
- manager.create("error message", 42, 0, Entry::Level::Error, additionalData,
+ manager.create("error message", 42, 0,
+ phosphor::logging::Entry::Level::Error, additionalData,
associations);
// We don't know the exact name, but a file should have been added to the
diff --git a/test/openpower-pels/pel_utils.cpp b/test/openpower-pels/pel_utils.cpp
index 46ec8ed..3e0ac01 100644
--- a/test/openpower-pels/pel_utils.cpp
+++ b/test/openpower-pels/pel_utils.cpp
@@ -13,6 +13,7 @@ using namespace openpower::pels;
std::filesystem::path CleanLogID::pelIDFile{};
std::filesystem::path CleanPELFiles::pelIDFile{};
std::filesystem::path CleanPELFiles::repoPath{};
+std::filesystem::path CleanPELFiles::registryPath{};
constexpr uint8_t simplePEL[] = {
// private header section header
diff --git a/test/openpower-pels/pel_utils.hpp b/test/openpower-pels/pel_utils.hpp
index 262a6e7..e61bea2 100644
--- a/test/openpower-pels/pel_utils.hpp
+++ b/test/openpower-pels/pel_utils.hpp
@@ -33,6 +33,7 @@ class CleanPELFiles : public ::testing::Test
{
pelIDFile = openpower::pels::getPELIDFile();
repoPath = openpower::pels::getPELRepoPath();
+ registryPath = openpower::pels::getMessageRegistryPath();
}
static void TearDownTestCase()
@@ -40,10 +41,12 @@ class CleanPELFiles : public ::testing::Test
std::filesystem::remove_all(
std::filesystem::path{pelIDFile}.parent_path());
std::filesystem::remove_all(repoPath);
+ std::filesystem::remove_all(registryPath);
}
static std::filesystem::path pelIDFile;
static std::filesystem::path repoPath;
+ static std::filesystem::path registryPath;
};
/**
diff --git a/test/openpower-pels/registry_test.cpp b/test/openpower-pels/registry_test.cpp
new file mode 100644
index 0000000..2107725
--- /dev/null
+++ b/test/openpower-pels/registry_test.cpp
@@ -0,0 +1,166 @@
+#include "extensions/openpower-pels/registry.hpp"
+
+#include <filesystem>
+#include <fstream>
+#include <nlohmann/json.hpp>
+
+#include <gtest/gtest.h>
+
+using namespace openpower::pels::message;
+namespace fs = std::filesystem;
+
+const auto registryData = R"(
+{
+ "PELs":
+ [
+ {
+ "Name": "xyz.openbmc_project.Power.Fault",
+ "Subsystem": "power_supply",
+ "ActionFlags": ["service_action", "report"],
+
+ "SRC":
+ {
+ "ReasonCode": "0x2030"
+ }
+ },
+
+ {
+ "Name": "xyz.openbmc_project.Power.OverVoltage",
+ "Subsystem": "power_control_hw",
+ "Severity": "unrecoverable",
+ "MfgSeverity": "non_error",
+ "ActionFlags": ["service_action", "report", "call_home"],
+ "MfgActionFlags": ["hidden"],
+
+ "SRC":
+ {
+ "ReasonCode": "0x2333",
+ "Type": "BD",
+ "SymptomIDFields": ["SRCWord5", "SRCWord6", "SRCWord7"],
+ "PowerFault": true,
+ "Words6To9":
+ {
+ "6":
+ {
+ "description": "Failing unit number",
+ "AdditionalDataPropSource": "PS_NUM"
+ },
+
+ "7":
+ {
+ "description": "bad voltage",
+ "AdditionalDataPropSource": "VOLTAGE"
+ }
+ }
+ }
+ }
+ ]
+}
+)";
+
+class RegistryTest : public ::testing::Test
+{
+ protected:
+ static void SetUpTestCase()
+ {
+ char path[] = "/tmp/regtestXXXXXX";
+ regDir = mkdtemp(path);
+ }
+
+ static void TearDownTestCase()
+ {
+ fs::remove_all(regDir);
+ }
+
+ static std::string writeData(const char* data)
+ {
+ fs::path path = regDir / "registry.json";
+ std::ofstream stream{path};
+ stream << data;
+ return path;
+ }
+
+ static fs::path regDir;
+};
+
+fs::path RegistryTest::regDir{};
+
+TEST_F(RegistryTest, TestNoEntry)
+{
+ auto path = RegistryTest::writeData(registryData);
+ Registry registry{path};
+
+ auto entry = registry.lookup("foo");
+ EXPECT_FALSE(entry);
+}
+
+TEST_F(RegistryTest, TestFindEntry)
+{
+ auto path = RegistryTest::writeData(registryData);
+ Registry registry{path};
+
+ auto entry = registry.lookup("xyz.openbmc_project.Power.OverVoltage");
+ ASSERT_TRUE(entry);
+ EXPECT_EQ(entry->name, "xyz.openbmc_project.Power.OverVoltage");
+ EXPECT_EQ(entry->subsystem, 0x62);
+ EXPECT_EQ(*(entry->severity), 0x40);
+ EXPECT_EQ(*(entry->mfgSeverity), 0x00);
+ EXPECT_EQ(entry->actionFlags, 0xA800);
+ EXPECT_EQ(*(entry->mfgActionFlags), 0x4000);
+ EXPECT_FALSE(entry->eventType);
+ EXPECT_FALSE(entry->eventScope);
+
+ // TODO: compare SRC fields
+}
+
+// Check the entry that mostly uses defaults
+TEST_F(RegistryTest, TestFindEntryMinimal)
+{
+ auto path = RegistryTest::writeData(registryData);
+ Registry registry{path};
+
+ auto entry = registry.lookup("xyz.openbmc_project.Power.Fault");
+ ASSERT_TRUE(entry);
+ EXPECT_EQ(entry->name, "xyz.openbmc_project.Power.Fault");
+ EXPECT_EQ(entry->subsystem, 0x61);
+ EXPECT_FALSE(entry->severity);
+ EXPECT_FALSE(entry->mfgSeverity);
+ EXPECT_FALSE(entry->mfgActionFlags);
+ EXPECT_EQ(entry->actionFlags, 0xA000);
+ EXPECT_FALSE(entry->eventType);
+ EXPECT_FALSE(entry->eventScope);
+}
+
+TEST_F(RegistryTest, TestBadJSON)
+{
+ auto path = RegistryTest::writeData("bad {} json");
+
+ Registry registry{path};
+
+ EXPECT_FALSE(registry.lookup("foo"));
+}
+
+// Test the helper functions the use the pel_values data.
+TEST_F(RegistryTest, TestHelperFunctions)
+{
+ using namespace openpower::pels::message::helper;
+ EXPECT_EQ(getSubsystem("input_power_source"), 0xA1);
+ EXPECT_THROW(getSubsystem("foo"), std::runtime_error);
+
+ EXPECT_EQ(getSeverity("symptom_recovered"), 0x71);
+ EXPECT_THROW(getSeverity("foo"), std::runtime_error);
+
+ EXPECT_EQ(getEventType("dump_notification"), 0x08);
+ EXPECT_THROW(getEventType("foo"), std::runtime_error);
+
+ EXPECT_EQ(getEventScope("possibly_multiple_platforms"), 0x04);
+ EXPECT_THROW(getEventScope("foo"), std::runtime_error);
+
+ std::vector<std::string> flags{"service_action", "dont_report",
+ "termination"};
+ EXPECT_EQ(getActionFlags(flags), 0x9100);
+
+ flags.clear();
+ flags.push_back("foo");
+ EXPECT_THROW(getActionFlags(flags), std::runtime_error);
+}
OpenPOWER on IntegriCloud