diff options
-rw-r--r-- | configure.ac | 7 | ||||
-rw-r--r-- | extensions/openpower-pels/manager.cpp | 1 | ||||
-rw-r--r-- | extensions/openpower-pels/manager.hpp | 18 | ||||
-rw-r--r-- | extensions/openpower-pels/openpower-pels.mk | 1 | ||||
-rw-r--r-- | extensions/openpower-pels/paths.cpp | 6 | ||||
-rw-r--r-- | extensions/openpower-pels/paths.hpp | 4 | ||||
-rw-r--r-- | extensions/openpower-pels/registry.cpp | 195 | ||||
-rw-r--r-- | extensions/openpower-pels/registry.hpp | 179 | ||||
-rw-r--r-- | test/openpower-pels/Makefile.include | 13 | ||||
-rw-r--r-- | test/openpower-pels/paths.cpp | 13 | ||||
-rw-r--r-- | test/openpower-pels/pel_manager_test.cpp | 3 | ||||
-rw-r--r-- | test/openpower-pels/pel_utils.cpp | 1 | ||||
-rw-r--r-- | test/openpower-pels/pel_utils.hpp | 3 | ||||
-rw-r--r-- | test/openpower-pels/registry_test.cpp | 166 |
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); +} |