PEL: Still create PEL when error not in registry

When an OpenBMC event log is created for an error that isn't in the PEL
message registry, the code will now find a registry entry using another
default error name.  This default PEL will contain the severity and any
callouts specified by the original event log, and its message used by
peltool and possibly Redfish will state that the actual meaning for the
error is unknown.

The error name property that was missing from the registry will be
placed in the JSON UserData section that hold the AdditionalData
property fields under the key ERROR_NAME.

Doing this allows one to see all errors on a system just by looking at
PELs, and not miss important ones just because a developer doesn't have
their error in the registry yet.

When these are seen, it may be a good idea to create bug reports as a
reminder that the missing error needs to be added.

Change-Id: Ifa3db21af96745dd651da5f5af0ab970a952f46a
diff --git a/test/openpower-pels/pel_manager_test.cpp b/test/openpower-pels/pel_manager_test.cpp
index b7146c9..bf1a18f 100644
--- a/test/openpower-pels/pel_manager_test.cpp
+++ b/test/openpower-pels/pel_manager_test.cpp
@@ -235,6 +235,19 @@
                 "Description": "A PGOOD Fault",
                 "Message": "PS had a PGOOD Fault"
             }
+        },
+        {
+            "Name": "xyz.openbmc_project.Logging.Error.Default",
+            "Subsystem": "bmc_firmware",
+            "SRC":
+            {
+                "ReasonCode": "0x2031"
+            },
+            "Documentation":
+            {
+                "Description": "The entry used when no match found",
+                "Message": "This is a generic SRC"
+            }
         }
     ]
 }
@@ -256,7 +269,7 @@
         std::bind(std::mem_fn(&TestLogger::log), &logger, std::placeholders::_1,
                   std::placeholders::_2, std::placeholders::_3)};
 
-    std::vector<std::string> additionalData;
+    std::vector<std::string> additionalData{"FOO=BAR"};
     std::vector<std::string> associations;
 
     // Create the event log to create the PEL from.
@@ -283,14 +296,64 @@
     EXPECT_FALSE(pelFile);
 
     // Create an event log that can't be found in the registry.
-    manager.create("xyz.openbmc_project.Error.Foo", 33, 0,
+    // In this case, xyz.openbmc_project.Logging.Error.Default will
+    // be used as the key instead to find a registry match.
+    manager.create("xyz.openbmc_project.Error.Foo", 42, 0,
                    phosphor::logging::Entry::Level::Error, additionalData,
                    associations);
 
-    // Currently, no PEL should be created.  Eventually, a 'missing registry
-    // entry' PEL will be there.
+    // Ensure a PEL was still created in the repository
     pelFile = findAnyPELInRepo();
-    EXPECT_FALSE(pelFile);
+    ASSERT_TRUE(pelFile);
+
+    data = readPELFile(*pelFile);
+    PEL newPEL(*data);
+
+    EXPECT_TRUE(newPEL.valid());
+    EXPECT_EQ(newPEL.obmcLogID(), 42);
+    EXPECT_EQ(newPEL.primarySRC().value()->asciiString(),
+              "BD8D2031                        ");
+
+    // Check for both the original AdditionalData item as well as
+    // the ERROR_NAME item that should contain the error message
+    // property that wasn't found.
+    std::string errorName;
+    std::string adItem;
+
+    for (const auto& section : newPEL.optionalSections())
+    {
+        if (SectionID::userData == static_cast<SectionID>(section->header().id))
+        {
+            if (UserDataFormat::json ==
+                static_cast<UserDataFormat>(section->header().subType))
+            {
+                auto ud = static_cast<UserData*>(section.get());
+
+                // Check that there was a UserData section added that
+                // contains debug details about the device.
+                const auto& d = ud->data();
+                std::string jsonString{d.begin(), d.end()};
+                auto json = nlohmann::json::parse(jsonString);
+
+                if (json.contains("ERROR_NAME"))
+                {
+                    errorName = json["ERROR_NAME"].get<std::string>();
+                }
+
+                if (json.contains("FOO"))
+                {
+                    adItem = json["FOO"].get<std::string>();
+                }
+            }
+        }
+        if (!errorName.empty())
+        {
+            break;
+        }
+    }
+
+    EXPECT_EQ(errorName, "xyz.openbmc_project.Error.Foo");
+    EXPECT_EQ(adItem, "BAR");
 }
 
 TEST_F(ManagerTest, TestDBusMethods)