Validate the priority of an LED is same

Need to make sure that the priority of a particular LED is the same
across all groups, it needs to throw the std::runtime_error if not
the same.

Tested: Manually changed the JSON file to have priority of a particular
LED different across groups and saw ledManager throw a runtime exception
and failed to run.

Signed-off-by: George Liu <liuxiwei@inspur.com>
Change-Id: I9d3e788dd86defb9a781dc958976b51ec7d3fd19
diff --git a/json-config.hpp b/json-config.hpp
index d47bfd5..e0448c5 100644
--- a/json-config.hpp
+++ b/json-config.hpp
@@ -15,6 +15,10 @@
 using LedAction = std::set<phosphor::led::Layout::LedAction>;
 using LedMap = std::map<std::string, LedAction>;
 
+// Priority for a particular LED needs to stay SAME across all groups
+// phosphor::led::Layout::Action can only be one of `Blink` and `On`
+using PriorityMap = std::map<std::string, phosphor::led::Layout::Action>;
+
 /** @brief Parse LED JSON file and output Json object
  *
  *  @param[in] path - path of LED JSON file
@@ -60,6 +64,39 @@
                              : phosphor::led::Layout::On;
 }
 
+/** @brief Validate the Priority of an LED is same across ALL groups
+ *
+ *  @param[in] name - led name member of each group
+ *  @param[in] priority - member priority of each group
+ *  @param[out] priorityMap - std::map, key:name, value:priority
+ *
+ *  @return
+ */
+void validatePriority(const std::string& name,
+                      const phosphor::led::Layout::Action& priority,
+                      PriorityMap& priorityMap)
+{
+    using namespace phosphor::logging;
+
+    auto iter = priorityMap.find(name);
+    if (iter == priorityMap.end())
+    {
+        priorityMap.emplace(name, priority);
+        return;
+    }
+
+    if (iter->second != priority)
+    {
+        log<level::ERR>("Priority of LED is not same across all",
+                        entry("Name=%s", name.c_str()),
+                        entry(" Old Priority=%d", iter->second),
+                        entry(" New priority=%d", priority));
+
+        throw std::runtime_error(
+            "Priority of at least one LED is not same across groups");
+    }
+}
+
 /** @brief Load JSON config and return led map
  *
  *  @return LedMap - Generated an std::map of LedAction
@@ -67,12 +104,13 @@
 const LedMap loadJsonConfig(const fs::path& path)
 {
     LedMap ledMap{};
+    PriorityMap priorityMap{};
 
     // define the default JSON as empty
     const Json empty{};
     auto json = readJson(path);
-
     auto leds = json.value("leds", empty);
+
     for (const auto& entry : leds)
     {
         fs::path tmpPath(std::string{OBJPATH});
@@ -90,6 +128,11 @@
 
             // Since only have Blink/On and default priority is Blink
             auto priority = getAction(member.value("Priority", "Blink"));
+
+            // Same LEDs can be part of multiple groups. However, their
+            // priorities across groups need to match.
+            validatePriority(name, priority, priorityMap);
+
             phosphor::led::Layout::LedAction ledAction{name, action, dutyOn,
                                                        period, priority};
             ledActions.emplace(ledAction);
diff --git a/test/utest-led-json.cpp b/test/utest-led-json.cpp
index 32d89a8..f0ca022 100644
--- a/test/utest-led-json.cpp
+++ b/test/utest-led-json.cpp
@@ -65,4 +65,25 @@
 {
     static constexpr auto jsonPath = "config/led-group-config-malformed.json";
     ASSERT_THROW(loadJsonConfig(jsonPath), std::exception);
+}
+
+TEST(validatePriority, testGoodPriority)
+{
+    PriorityMap priorityMap{};
+    validatePriority("heartbeat", phosphor::led::Layout::Blink, priorityMap);
+    validatePriority("power", phosphor::led::Layout::On, priorityMap);
+
+    ASSERT_EQ(priorityMap.at("heartbeat"), phosphor::led::Layout::Blink);
+    ASSERT_EQ(priorityMap.at("power"), phosphor::led::Layout::On);
+}
+
+TEST(validatePriority, testBadPriority)
+{
+    PriorityMap priorityMap{};
+    validatePriority("heartbeat", phosphor::led::Layout::Blink, priorityMap);
+
+    ASSERT_EQ(priorityMap.at("heartbeat"), phosphor::led::Layout::Blink);
+    ASSERT_THROW(
+        validatePriority("heartbeat", phosphor::led::Layout::On, priorityMap),
+        std::runtime_error);
 }
\ No newline at end of file