PEL: Support a default device callouts file

Normally, the device callouts code, which finds the callouts to use for
FRUs along a specific device path, will look for a JSON file to use by
looping through the list of compatible system names and adding
'_dev_callouts.json' to the name.

However at this point in time, the code that is supposed to populate
that list isn't done yet, so it will always be empty.  In order to still
be able find a file, have it look for a default file called just
_dev_callouts.json after it tries and fails to find one based on system
name.

This file will be installed into the flash image from a bitbake recipe,
and eventually when that list of names field is populated, it can be
renamed in the recipe without having to make a code change here.

Signed-off-by: Matt Spinler <spinler@us.ibm.com>
Change-Id: I39e9dbb3e921eb5e5be30717a277b07febd2de55
diff --git a/extensions/openpower-pels/device_callouts.cpp b/extensions/openpower-pels/device_callouts.cpp
index 7e89228..4b7e590 100644
--- a/extensions/openpower-pels/device_callouts.cpp
+++ b/extensions/openpower-pels/device_callouts.cpp
@@ -35,13 +35,18 @@
 
 fs::path getJSONFilename(const std::vector<std::string>& compatibleList)
 {
+    std::vector<std::string> names{compatibleList};
     auto basePath = getPELReadOnlyDataPath();
     fs::path fullPath;
 
     // Find an entry in the list of compatible system names that
     // matches a filename we have.
 
-    for (const auto& name : compatibleList)
+    // Also match on just _dev_callouts.json, which may be present
+    // when it's known that compatibleList won't be correct.
+    names.push_back("");
+
+    for (const auto& name : names)
     {
         fs::path filename = name + calloutFileSuffix;
 
diff --git a/test/openpower-pels/device_callouts_test.cpp b/test/openpower-pels/device_callouts_test.cpp
index eacf4b9..71dff13 100644
--- a/test/openpower-pels/device_callouts_test.cpp
+++ b/test/openpower-pels/device_callouts_test.cpp
@@ -283,6 +283,30 @@
         std::vector<std::string> compatibles{"system5", "system6"};
         EXPECT_THROW(util::getJSONFilename(compatibles), std::invalid_argument);
     }
+
+    // Test using the fallback name
+    {
+        // If _dev_callouts.json is there, it will be used if no other
+        // match is found.
+        fs::path fallbackFile{dataPath / "_dev_callouts.json"};
+        std::ofstream file{fallbackFile};
+        file << calloutJSON.dump();
+        file.close();
+
+        // Fallback shouldn't be used because the actual systemA file is there
+        {
+            std::vector<std::string> compatibles{"system1", "systemA",
+                                                 "system3"};
+            EXPECT_EQ(util::getJSONFilename(compatibles),
+                      fs::path{dataPath / filename});
+        }
+
+        // Fallback should be used because no other match
+        {
+            std::vector<std::string> compatibles{"systemX", "systemY"};
+            EXPECT_EQ(util::getJSONFilename(compatibles), fallbackFile);
+        }
+    }
 }
 
 // Test determining the callout type from the device path