PEL: Don't allow duplicate callouts

When adding callouts, check if the callout being added already exists.
If it does, don't add it and rather just update the priority of the
existing one to be the highest of the two.

Callouts are considered to be equal if their location code matches, or
if they have the same maintenance procedure, or if they have the same
symbolic FRU.

The change entails adding an operator== on the Callout object, as well
as an operator> so that the callout with the highest priority can be
determined.  Also use this new operator> in the sort of the callout list
that happens after a callout is added or changed.

Signed-off-by: Matt Spinler <spinler@us.ibm.com>
Change-Id: I5ee148cc12e92f67fb3da233c3615e9665e95355
diff --git a/test/openpower-pels/src_callout_test.cpp b/test/openpower-pels/src_callout_test.cpp
index daa2ab6..a03b9b0 100644
--- a/test/openpower-pels/src_callout_test.cpp
+++ b/test/openpower-pels/src_callout_test.cpp
@@ -432,3 +432,128 @@
         }
     }
 }
+
+TEST(CalloutTest, OperatorEqualTest)
+{
+    {
+        Callout c1{CalloutPriority::high, "A1", "1234567", "ABCD",
+                   "123456789ABC"};
+        Callout c2{CalloutPriority::high, "A1", "1234567", "ABCD",
+                   "123456789ABC"};
+        EXPECT_EQ(c1, c2);
+    }
+
+    {
+        // Different location code
+        Callout c1{CalloutPriority::high, "A1", "1234567", "ABCD",
+                   "123456789ABC"};
+        Callout c2{CalloutPriority::high, "A2", "1234567", "ABCD",
+                   "123456789ABC"};
+        EXPECT_NE(c1, c2);
+    }
+
+    {
+        // maintenance procedure
+        Callout c1{CalloutPriority::medium, "bmc_code"};
+        Callout c2{CalloutPriority::medium, "bmc_code"};
+        EXPECT_EQ(c1, c2);
+    }
+
+    {
+        // different maintenance procedures
+        Callout c1{CalloutPriority::medium, "bmc_code"};
+        Callout c2{CalloutPriority::medium, "sbe_code"};
+        EXPECT_NE(c1, c2);
+    }
+
+    {
+        // symbolic FRU
+        Callout c1{CalloutPriority::high, "service_docs", "", false};
+        Callout c2{CalloutPriority::high, "service_docs", "", false};
+        EXPECT_EQ(c1, c2);
+    }
+
+    {
+        // different symbolic FRUs
+        Callout c1{CalloutPriority::high, "service_docs", "", false};
+        Callout c2{CalloutPriority::high, "air_mover", "", false};
+        EXPECT_NE(c1, c2);
+    }
+
+    {
+        // HW callout vs symbolic FRU
+        Callout c1{CalloutPriority::high, "A1", "1234567", "ABCD",
+                   "123456789ABC"};
+        Callout c2{CalloutPriority::high, "service_docs", "", false};
+        EXPECT_NE(c1, c2);
+    }
+
+    {
+        // HW callout vs maintenance procedure
+        Callout c1{CalloutPriority::high, "A1", "1234567", "ABCD",
+                   "123456789ABC"};
+        Callout c2{CalloutPriority::medium, "bmc_code"};
+        EXPECT_NE(c1, c2);
+    }
+
+    {
+        // symbolic FRU vs maintenance procedure
+        Callout c1{CalloutPriority::high, "service_docs", "", false};
+        Callout c2{CalloutPriority::medium, "bmc_code"};
+        EXPECT_NE(c1, c2);
+    }
+
+    {
+        // HW callout vs symbolic FRU is still considered equal if
+        // the location code is the same
+        Callout c1{CalloutPriority::high, "A1", "1234567", "ABCD",
+                   "123456789ABC"};
+        Callout c2{CalloutPriority::high, "service_docs", "A1", true};
+        EXPECT_EQ(c1, c2);
+    }
+}
+
+TEST(CalloutTest, OperatorGreaterThanTest)
+{
+    {
+        Callout c1{CalloutPriority::high, "bmc_code"};
+        Callout c2{CalloutPriority::medium, "bmc_code"};
+        EXPECT_TRUE(c1 > c2);
+    }
+    {
+        Callout c1{CalloutPriority::high, "bmc_code"};
+        Callout c2{CalloutPriority::low, "bmc_code"};
+        EXPECT_TRUE(c1 > c2);
+    }
+    {
+        Callout c1{CalloutPriority::medium, "bmc_code"};
+        Callout c2{CalloutPriority::low, "bmc_code"};
+        EXPECT_TRUE(c1 > c2);
+    }
+    {
+        Callout c1{CalloutPriority::mediumGroupA, "bmc_code"};
+        Callout c2{CalloutPriority::low, "bmc_code"};
+        EXPECT_TRUE(c1 > c2);
+    }
+    {
+        Callout c1{CalloutPriority::medium, "bmc_code"};
+        Callout c2{CalloutPriority::high, "bmc_code"};
+        EXPECT_FALSE(c1 > c2);
+    }
+    {
+        Callout c1{CalloutPriority::high, "bmc_code"};
+        Callout c2{CalloutPriority::high, "bmc_code"};
+        EXPECT_FALSE(c1 > c2);
+    }
+    {
+        Callout c1{CalloutPriority::low, "bmc_code"};
+        Callout c2{CalloutPriority::high, "bmc_code"};
+        EXPECT_FALSE(c1 > c2);
+    }
+    {
+        // Treat the different mediums the same
+        Callout c1{CalloutPriority::medium, "bmc_code"};
+        Callout c2{CalloutPriority::mediumGroupA, "bmc_code"};
+        EXPECT_FALSE(c1 > c2);
+    }
+}