xref: /openbmc/phosphor-logging/test/openpower-pels/src_test.cpp (revision 7b92372da378fa751c6596e5ea93936f61e61022)
197f7abcfSMatt Spinler /**
297f7abcfSMatt Spinler  * Copyright © 2019 IBM Corporation
397f7abcfSMatt Spinler  *
497f7abcfSMatt Spinler  * Licensed under the Apache License, Version 2.0 (the "License");
597f7abcfSMatt Spinler  * you may not use this file except in compliance with the License.
697f7abcfSMatt Spinler  * You may obtain a copy of the License at
797f7abcfSMatt Spinler  *
897f7abcfSMatt Spinler  *     http://www.apache.org/licenses/LICENSE-2.0
997f7abcfSMatt Spinler  *
1097f7abcfSMatt Spinler  * Unless required by applicable law or agreed to in writing, software
1197f7abcfSMatt Spinler  * distributed under the License is distributed on an "AS IS" BASIS,
1297f7abcfSMatt Spinler  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1397f7abcfSMatt Spinler  * See the License for the specific language governing permissions and
1497f7abcfSMatt Spinler  * limitations under the License.
1597f7abcfSMatt Spinler  */
16f9bae185SMatt Spinler #include "extensions/openpower-pels/src.hpp"
17075e5bafSMatt Spinler #include "mocks.hpp"
18f9bae185SMatt Spinler #include "pel_utils.hpp"
19f9bae185SMatt Spinler 
206fd0c1e7SHarisuddin Mohamed Isa #include <fstream>
216fd0c1e7SHarisuddin Mohamed Isa 
22f9bae185SMatt Spinler #include <gtest/gtest.h>
23f9bae185SMatt Spinler 
24f9bae185SMatt Spinler using namespace openpower::pels;
25ed046856SMatt Spinler using ::testing::_;
26b41fa54bSWilliam A. Kennington III using ::testing::DoAll;
27ed046856SMatt Spinler using ::testing::InvokeWithoutArgs;
28075e5bafSMatt Spinler using ::testing::NiceMock;
29075e5bafSMatt Spinler using ::testing::Return;
30ed046856SMatt Spinler using ::testing::SetArgReferee;
313bdd0110SMatt Spinler using ::testing::Throw;
326fd0c1e7SHarisuddin Mohamed Isa namespace fs = std::filesystem;
33f9bae185SMatt Spinler 
346fd0c1e7SHarisuddin Mohamed Isa const auto testRegistry = R"(
356fd0c1e7SHarisuddin Mohamed Isa {
366fd0c1e7SHarisuddin Mohamed Isa "PELs":
376fd0c1e7SHarisuddin Mohamed Isa [
386fd0c1e7SHarisuddin Mohamed Isa     {
396fd0c1e7SHarisuddin Mohamed Isa         "Name": "xyz.openbmc_project.Error.Test",
406fd0c1e7SHarisuddin Mohamed Isa         "Subsystem": "bmc_firmware",
416fd0c1e7SHarisuddin Mohamed Isa         "SRC":
426fd0c1e7SHarisuddin Mohamed Isa         {
436fd0c1e7SHarisuddin Mohamed Isa             "ReasonCode": "0xABCD",
446fd0c1e7SHarisuddin Mohamed Isa             "Words6To9":
456fd0c1e7SHarisuddin Mohamed Isa             {
466fd0c1e7SHarisuddin Mohamed Isa                 "6":
476fd0c1e7SHarisuddin Mohamed Isa                 {
486fd0c1e7SHarisuddin Mohamed Isa                     "Description": "Component ID",
496fd0c1e7SHarisuddin Mohamed Isa                     "AdditionalDataPropSource": "COMPID"
506fd0c1e7SHarisuddin Mohamed Isa                 },
516fd0c1e7SHarisuddin Mohamed Isa                 "7":
526fd0c1e7SHarisuddin Mohamed Isa                 {
536fd0c1e7SHarisuddin Mohamed Isa                     "Description": "Failure count",
546fd0c1e7SHarisuddin Mohamed Isa                     "AdditionalDataPropSource": "FREQUENCY"
556fd0c1e7SHarisuddin Mohamed Isa                 },
566fd0c1e7SHarisuddin Mohamed Isa                 "8":
576fd0c1e7SHarisuddin Mohamed Isa                 {
586fd0c1e7SHarisuddin Mohamed Isa                     "Description": "Time period",
596fd0c1e7SHarisuddin Mohamed Isa                     "AdditionalDataPropSource": "DURATION"
606fd0c1e7SHarisuddin Mohamed Isa                 },
616fd0c1e7SHarisuddin Mohamed Isa                 "9":
626fd0c1e7SHarisuddin Mohamed Isa                 {
636fd0c1e7SHarisuddin Mohamed Isa                     "Description": "Error code",
646fd0c1e7SHarisuddin Mohamed Isa                     "AdditionalDataPropSource": "ERRORCODE"
656fd0c1e7SHarisuddin Mohamed Isa                 }
666fd0c1e7SHarisuddin Mohamed Isa             }
676fd0c1e7SHarisuddin Mohamed Isa         },
686fd0c1e7SHarisuddin Mohamed Isa         "Documentation":
696fd0c1e7SHarisuddin Mohamed Isa         {
706fd0c1e7SHarisuddin Mohamed Isa             "Description": "A Component Fault",
716fd0c1e7SHarisuddin Mohamed Isa             "Message": "Comp %1 failed %2 times over %3 secs with ErrorCode %4",
726fd0c1e7SHarisuddin Mohamed Isa             "MessageArgSources":
736fd0c1e7SHarisuddin Mohamed Isa             [
746fd0c1e7SHarisuddin Mohamed Isa                 "SRCWord6", "SRCWord7", "SRCWord8", "SRCWord9"
756fd0c1e7SHarisuddin Mohamed Isa             ]
766fd0c1e7SHarisuddin Mohamed Isa         }
776fd0c1e7SHarisuddin Mohamed Isa     }
786fd0c1e7SHarisuddin Mohamed Isa ]
796fd0c1e7SHarisuddin Mohamed Isa }
806fd0c1e7SHarisuddin Mohamed Isa )";
816fd0c1e7SHarisuddin Mohamed Isa 
826fd0c1e7SHarisuddin Mohamed Isa class SRCTest : public ::testing::Test
836fd0c1e7SHarisuddin Mohamed Isa {
846fd0c1e7SHarisuddin Mohamed Isa   protected:
SetUpTestCase()856fd0c1e7SHarisuddin Mohamed Isa     static void SetUpTestCase()
866fd0c1e7SHarisuddin Mohamed Isa     {
876fd0c1e7SHarisuddin Mohamed Isa         char path[] = "/tmp/srctestXXXXXX";
886fd0c1e7SHarisuddin Mohamed Isa         regDir = mkdtemp(path);
896fd0c1e7SHarisuddin Mohamed Isa     }
906fd0c1e7SHarisuddin Mohamed Isa 
TearDownTestCase()916fd0c1e7SHarisuddin Mohamed Isa     static void TearDownTestCase()
926fd0c1e7SHarisuddin Mohamed Isa     {
936fd0c1e7SHarisuddin Mohamed Isa         fs::remove_all(regDir);
946fd0c1e7SHarisuddin Mohamed Isa     }
956fd0c1e7SHarisuddin Mohamed Isa 
writeData(const char * data)966fd0c1e7SHarisuddin Mohamed Isa     static std::string writeData(const char* data)
976fd0c1e7SHarisuddin Mohamed Isa     {
986fd0c1e7SHarisuddin Mohamed Isa         fs::path path = regDir / "registry.json";
996fd0c1e7SHarisuddin Mohamed Isa         std::ofstream stream{path};
1006fd0c1e7SHarisuddin Mohamed Isa         stream << data;
1016fd0c1e7SHarisuddin Mohamed Isa         return path;
1026fd0c1e7SHarisuddin Mohamed Isa     }
1036fd0c1e7SHarisuddin Mohamed Isa 
1046fd0c1e7SHarisuddin Mohamed Isa     static fs::path regDir;
1056fd0c1e7SHarisuddin Mohamed Isa };
1066fd0c1e7SHarisuddin Mohamed Isa 
1076fd0c1e7SHarisuddin Mohamed Isa fs::path SRCTest::regDir{};
1086fd0c1e7SHarisuddin Mohamed Isa 
TEST_F(SRCTest,UnflattenFlattenTestNoCallouts)1096fd0c1e7SHarisuddin Mohamed Isa TEST_F(SRCTest, UnflattenFlattenTestNoCallouts)
110f9bae185SMatt Spinler {
11142828bd9SMatt Spinler     auto data = pelDataFactory(TestPELType::primarySRCSection);
112f9bae185SMatt Spinler 
113f9bae185SMatt Spinler     Stream stream{data};
114f9bae185SMatt Spinler     SRC src{stream};
115f9bae185SMatt Spinler 
116f9bae185SMatt Spinler     EXPECT_TRUE(src.valid());
117f9bae185SMatt Spinler 
118f9bae185SMatt Spinler     EXPECT_EQ(src.header().id, 0x5053);
119f1b46ff4SMatt Spinler     EXPECT_EQ(src.header().size, 0x50);
120f9bae185SMatt Spinler     EXPECT_EQ(src.header().version, 0x01);
121f9bae185SMatt Spinler     EXPECT_EQ(src.header().subType, 0x01);
122f9bae185SMatt Spinler     EXPECT_EQ(src.header().componentID, 0x0202);
123f9bae185SMatt Spinler 
124f9bae185SMatt Spinler     EXPECT_EQ(src.version(), 0x02);
125f9bae185SMatt Spinler     EXPECT_EQ(src.flags(), 0x00);
126f9bae185SMatt Spinler     EXPECT_EQ(src.hexWordCount(), 9);
127f9bae185SMatt Spinler     EXPECT_EQ(src.size(), 0x48);
128f9bae185SMatt Spinler 
129f9bae185SMatt Spinler     const auto& hexwords = src.hexwordData();
130bd716f00SMatt Spinler     EXPECT_EQ(0x02020255, hexwords[0]);
131bd716f00SMatt Spinler     EXPECT_EQ(0x03030310, hexwords[1]);
132f9bae185SMatt Spinler     EXPECT_EQ(0x04040404, hexwords[2]);
133f9bae185SMatt Spinler     EXPECT_EQ(0x05050505, hexwords[3]);
134f9bae185SMatt Spinler     EXPECT_EQ(0x06060606, hexwords[4]);
135f9bae185SMatt Spinler     EXPECT_EQ(0x07070707, hexwords[5]);
136f9bae185SMatt Spinler     EXPECT_EQ(0x08080808, hexwords[6]);
137f9bae185SMatt Spinler     EXPECT_EQ(0x09090909, hexwords[7]);
138f9bae185SMatt Spinler 
139f9bae185SMatt Spinler     EXPECT_EQ(src.asciiString(), "BD8D5678                        ");
140f9bae185SMatt Spinler     EXPECT_FALSE(src.callouts());
141f9bae185SMatt Spinler 
142f9bae185SMatt Spinler     // Flatten
143f9bae185SMatt Spinler     std::vector<uint8_t> newData;
144f9bae185SMatt Spinler     Stream newStream{newData};
145f9bae185SMatt Spinler 
146f9bae185SMatt Spinler     src.flatten(newStream);
147f9bae185SMatt Spinler     EXPECT_EQ(data, newData);
148f9bae185SMatt Spinler }
149f9bae185SMatt Spinler 
TEST_F(SRCTest,UnflattenFlattenTest2Callouts)1506fd0c1e7SHarisuddin Mohamed Isa TEST_F(SRCTest, UnflattenFlattenTest2Callouts)
151f9bae185SMatt Spinler {
15242828bd9SMatt Spinler     auto data = pelDataFactory(TestPELType::primarySRCSection2Callouts);
153f9bae185SMatt Spinler 
154f9bae185SMatt Spinler     Stream stream{data};
155f9bae185SMatt Spinler     SRC src{stream};
156f9bae185SMatt Spinler 
157f9bae185SMatt Spinler     EXPECT_TRUE(src.valid());
158bd716f00SMatt Spinler     EXPECT_EQ(src.flags(), 0x01); // Additional sections within the SRC.
159f9bae185SMatt Spinler 
160f9bae185SMatt Spinler     // Spot check the SRC fields, but they're the same as above
161f9bae185SMatt Spinler     EXPECT_EQ(src.asciiString(), "BD8D5678                        ");
162f9bae185SMatt Spinler 
163f9bae185SMatt Spinler     // There should be 2 callouts
164f9bae185SMatt Spinler     const auto& calloutsSection = src.callouts();
165f9bae185SMatt Spinler     ASSERT_TRUE(calloutsSection);
166f9bae185SMatt Spinler     const auto& callouts = calloutsSection->callouts();
167f9bae185SMatt Spinler     EXPECT_EQ(callouts.size(), 2);
168f9bae185SMatt Spinler 
169f9bae185SMatt Spinler     // spot check that each callout has the right substructures
170f9bae185SMatt Spinler     EXPECT_TRUE(callouts.front()->fruIdentity());
171f9bae185SMatt Spinler     EXPECT_FALSE(callouts.front()->pceIdentity());
172f9bae185SMatt Spinler     EXPECT_FALSE(callouts.front()->mru());
173f9bae185SMatt Spinler 
174f9bae185SMatt Spinler     EXPECT_TRUE(callouts.back()->fruIdentity());
175f9bae185SMatt Spinler     EXPECT_TRUE(callouts.back()->pceIdentity());
176f9bae185SMatt Spinler     EXPECT_TRUE(callouts.back()->mru());
177f9bae185SMatt Spinler 
178f9bae185SMatt Spinler     // Flatten
179f9bae185SMatt Spinler     std::vector<uint8_t> newData;
180f9bae185SMatt Spinler     Stream newStream{newData};
181f9bae185SMatt Spinler 
182f9bae185SMatt Spinler     src.flatten(newStream);
183f9bae185SMatt Spinler     EXPECT_EQ(data, newData);
184f9bae185SMatt Spinler }
185bd716f00SMatt Spinler 
186bd716f00SMatt Spinler // Create an SRC from the message registry
TEST_F(SRCTest,CreateTestNoCallouts)1876fd0c1e7SHarisuddin Mohamed Isa TEST_F(SRCTest, CreateTestNoCallouts)
188bd716f00SMatt Spinler {
189bd716f00SMatt Spinler     message::Entry entry;
190bd716f00SMatt Spinler     entry.src.type = 0xBD;
191bd716f00SMatt Spinler     entry.src.reasonCode = 0xABCD;
192bd716f00SMatt Spinler     entry.subsystem = 0x42;
1931a1b0dfbSHarisuddin Mohamed Isa     entry.src.hexwordADFields = {
1941a1b0dfbSHarisuddin Mohamed Isa         {5, {"TEST1", "DESCR1"}}, // Not a user defined word
1951a1b0dfbSHarisuddin Mohamed Isa         {6, {"TEST1", "DESCR1"}},
1961a1b0dfbSHarisuddin Mohamed Isa         {7, {"TEST2", "DESCR2"}},
1971a1b0dfbSHarisuddin Mohamed Isa         {8, {"TEST3", "DESCR3"}},
1981a1b0dfbSHarisuddin Mohamed Isa         {9, {"TEST4", "DESCR4"}}};
199bd716f00SMatt Spinler 
200bd716f00SMatt Spinler     // Values for the SRC words pointed to above
201e5940634SPatrick Williams     std::map<std::string, std::string> adData{
202e5940634SPatrick Williams         {"TEST1", "0x12345678"},
203e5940634SPatrick Williams         {"TEST2", "12345678"},
204e5940634SPatrick Williams         {"TEST3", "0XDEF"},
205e5940634SPatrick Williams         {"TEST4", "Z"}};
206bd716f00SMatt Spinler     AdditionalData ad{adData};
207075e5bafSMatt Spinler     NiceMock<MockDataInterface> dataIface;
208075e5bafSMatt Spinler 
209075e5bafSMatt Spinler     EXPECT_CALL(dataIface, getMotherboardCCIN).WillOnce(Return("ABCD"));
210075e5bafSMatt Spinler 
211075e5bafSMatt Spinler     SRC src{entry, ad, dataIface};
212bd716f00SMatt Spinler 
213bd716f00SMatt Spinler     EXPECT_TRUE(src.valid());
214a2d7b775SMike Capps     EXPECT_FALSE(src.isPowerFaultEvent());
215bd716f00SMatt Spinler     EXPECT_EQ(src.size(), baseSRCSize);
216bd716f00SMatt Spinler 
217bd716f00SMatt Spinler     const auto& hexwords = src.hexwordData();
218bd716f00SMatt Spinler 
219bd716f00SMatt Spinler     // The spec always refers to SRC words 2 - 9, and as the hexwordData()
220bd716f00SMatt Spinler     // array index starts at 0 use the math in the [] below to make it easier
221bd716f00SMatt Spinler     // to tell what is being accessed.
222bd716f00SMatt Spinler     EXPECT_EQ(hexwords[2 - 2] & 0xF0000000, 0);    // Partition dump status
223bd716f00SMatt Spinler     EXPECT_EQ(hexwords[2 - 2] & 0x00F00000, 0);    // Partition boot type
224bd716f00SMatt Spinler     EXPECT_EQ(hexwords[2 - 2] & 0x000000FF, 0x55); // SRC format
225bd716f00SMatt Spinler     EXPECT_EQ(hexwords[3 - 2] & 0x000000FF, 0x10); // BMC position
226075e5bafSMatt Spinler     EXPECT_EQ(hexwords[3 - 2] & 0xFFFF0000, 0xABCD0000); // Motherboard CCIN
227bd716f00SMatt Spinler 
228bd716f00SMatt Spinler     // Validate more fields here as the code starts filling them in.
229bd716f00SMatt Spinler 
230bd716f00SMatt Spinler     // Ensure hex word 5 wasn't allowed to be set to TEST1's contents
2313fe93e96SMatt Spinler     // And that none of the error status flags are set
232bd716f00SMatt Spinler     EXPECT_EQ(hexwords[5 - 2], 0);
233bd716f00SMatt Spinler 
234bd716f00SMatt Spinler     // The user defined hex word fields specifed in the additional data.
235bd716f00SMatt Spinler     EXPECT_EQ(hexwords[6 - 2], 0x12345678); // TEST1
236bd716f00SMatt Spinler     EXPECT_EQ(hexwords[7 - 2], 12345678);   // TEST2
237bd716f00SMatt Spinler     EXPECT_EQ(hexwords[8 - 2], 0xdef);      // TEST3
238bd716f00SMatt Spinler     EXPECT_EQ(hexwords[9 - 2], 0);          // TEST4, but can't convert a 'Z'
239bd716f00SMatt Spinler 
240bd716f00SMatt Spinler     EXPECT_EQ(src.asciiString(), "BD42ABCD                        ");
241bd716f00SMatt Spinler 
242bd716f00SMatt Spinler     // No callouts
243bd716f00SMatt Spinler     EXPECT_FALSE(src.callouts());
244bd716f00SMatt Spinler 
245bd716f00SMatt Spinler     // May as well spot check the flatten/unflatten
246bd716f00SMatt Spinler     std::vector<uint8_t> data;
247bd716f00SMatt Spinler     Stream stream{data};
248bd716f00SMatt Spinler     src.flatten(stream);
249bd716f00SMatt Spinler 
250bd716f00SMatt Spinler     stream.offset(0);
251bd716f00SMatt Spinler     SRC newSRC{stream};
252bd716f00SMatt Spinler 
253bd716f00SMatt Spinler     EXPECT_TRUE(newSRC.valid());
254bd716f00SMatt Spinler     EXPECT_EQ(newSRC.asciiString(), src.asciiString());
255bd716f00SMatt Spinler     EXPECT_FALSE(newSRC.callouts());
256bd716f00SMatt Spinler }
2576fd0c1e7SHarisuddin Mohamed Isa 
258075e5bafSMatt Spinler // Test when the CCIN string isn't a 4 character number
TEST_F(SRCTest,BadCCINTest)259075e5bafSMatt Spinler TEST_F(SRCTest, BadCCINTest)
260075e5bafSMatt Spinler {
261075e5bafSMatt Spinler     message::Entry entry;
262075e5bafSMatt Spinler     entry.src.type = 0xBD;
263075e5bafSMatt Spinler     entry.src.reasonCode = 0xABCD;
264075e5bafSMatt Spinler     entry.subsystem = 0x42;
265075e5bafSMatt Spinler 
266e5940634SPatrick Williams     std::map<std::string, std::string> adData{};
267075e5bafSMatt Spinler     AdditionalData ad{adData};
268075e5bafSMatt Spinler     NiceMock<MockDataInterface> dataIface;
269075e5bafSMatt Spinler 
270075e5bafSMatt Spinler     // First it isn't a number, then it is too long,
271075e5bafSMatt Spinler     // then it is empty.
272075e5bafSMatt Spinler     EXPECT_CALL(dataIface, getMotherboardCCIN)
273075e5bafSMatt Spinler         .WillOnce(Return("X"))
274075e5bafSMatt Spinler         .WillOnce(Return("12345"))
275075e5bafSMatt Spinler         .WillOnce(Return(""));
276075e5bafSMatt Spinler 
277075e5bafSMatt Spinler     // The CCIN in the first half should still be 0 each time.
278075e5bafSMatt Spinler     {
279075e5bafSMatt Spinler         SRC src{entry, ad, dataIface};
280075e5bafSMatt Spinler         EXPECT_TRUE(src.valid());
281075e5bafSMatt Spinler         const auto& hexwords = src.hexwordData();
282075e5bafSMatt Spinler         EXPECT_EQ(hexwords[3 - 2] & 0xFFFF0000, 0x00000000);
283075e5bafSMatt Spinler     }
284075e5bafSMatt Spinler 
285075e5bafSMatt Spinler     {
286075e5bafSMatt Spinler         SRC src{entry, ad, dataIface};
287075e5bafSMatt Spinler         EXPECT_TRUE(src.valid());
288075e5bafSMatt Spinler         const auto& hexwords = src.hexwordData();
289075e5bafSMatt Spinler         EXPECT_EQ(hexwords[3 - 2] & 0xFFFF0000, 0x00000000);
290075e5bafSMatt Spinler     }
291075e5bafSMatt Spinler 
292075e5bafSMatt Spinler     {
293075e5bafSMatt Spinler         SRC src{entry, ad, dataIface};
294075e5bafSMatt Spinler         EXPECT_TRUE(src.valid());
295075e5bafSMatt Spinler         const auto& hexwords = src.hexwordData();
296075e5bafSMatt Spinler         EXPECT_EQ(hexwords[3 - 2] & 0xFFFF0000, 0x00000000);
297075e5bafSMatt Spinler     }
298075e5bafSMatt Spinler }
299075e5bafSMatt Spinler 
3006fd0c1e7SHarisuddin Mohamed Isa // Test the getErrorDetails function
TEST_F(SRCTest,MessageSubstitutionTest)3016fd0c1e7SHarisuddin Mohamed Isa TEST_F(SRCTest, MessageSubstitutionTest)
3026fd0c1e7SHarisuddin Mohamed Isa {
3036fd0c1e7SHarisuddin Mohamed Isa     auto path = SRCTest::writeData(testRegistry);
3046fd0c1e7SHarisuddin Mohamed Isa     message::Registry registry{path};
3056fd0c1e7SHarisuddin Mohamed Isa     auto entry = registry.lookup("0xABCD", message::LookupType::reasonCode);
3066fd0c1e7SHarisuddin Mohamed Isa 
307e5940634SPatrick Williams     std::map<std::string, std::string> adData{
308e5940634SPatrick Williams         {"COMPID", "0x1"},
309e5940634SPatrick Williams         {"FREQUENCY", "0x4"},
310e5940634SPatrick Williams         {"DURATION", "30"},
311e5940634SPatrick Williams         {"ERRORCODE", "0x01ABCDEF"}};
3126fd0c1e7SHarisuddin Mohamed Isa     AdditionalData ad{adData};
313075e5bafSMatt Spinler     NiceMock<MockDataInterface> dataIface;
3146fd0c1e7SHarisuddin Mohamed Isa 
315075e5bafSMatt Spinler     SRC src{*entry, ad, dataIface};
3166fd0c1e7SHarisuddin Mohamed Isa     EXPECT_TRUE(src.valid());
3176fd0c1e7SHarisuddin Mohamed Isa 
3186fd0c1e7SHarisuddin Mohamed Isa     auto errorDetails = src.getErrorDetails(registry, DetailLevel::message);
3196fd0c1e7SHarisuddin Mohamed Isa     ASSERT_TRUE(errorDetails);
32039936e34SZane Shelley     EXPECT_EQ(errorDetails.value(),
32139936e34SZane Shelley               "Comp 0x00000001 failed 0x00000004 times over 0x0000001E secs "
32239936e34SZane Shelley               "with ErrorCode 0x01ABCDEF");
3236fd0c1e7SHarisuddin Mohamed Isa }
324ed046856SMatt Spinler // Test that an inventory path callout string is
325ed046856SMatt Spinler // converted into the appropriate FRU callout.
TEST_F(SRCTest,InventoryCalloutTest)326ed046856SMatt Spinler TEST_F(SRCTest, InventoryCalloutTest)
327ed046856SMatt Spinler {
328ed046856SMatt Spinler     message::Entry entry;
329ed046856SMatt Spinler     entry.src.type = 0xBD;
330ed046856SMatt Spinler     entry.src.reasonCode = 0xABCD;
331ed046856SMatt Spinler     entry.subsystem = 0x42;
332ed046856SMatt Spinler 
333e5940634SPatrick Williams     std::map<std::string, std::string> adData{
334e5940634SPatrick Williams         {"CALLOUT_INVENTORY_PATH", "motherboard"}};
335ed046856SMatt Spinler     AdditionalData ad{adData};
336ed046856SMatt Spinler     NiceMock<MockDataInterface> dataIface;
337ed046856SMatt Spinler 
3389b90e2a2SMatt Spinler     EXPECT_CALL(dataIface, getLocationCode("motherboard"))
3399b90e2a2SMatt Spinler         .WillOnce(Return("UTMS-P1"));
3409b90e2a2SMatt Spinler 
3419b90e2a2SMatt Spinler     EXPECT_CALL(dataIface, getHWCalloutFields("motherboard", _, _, _))
342ed046856SMatt Spinler         .Times(1)
3439b90e2a2SMatt Spinler         .WillOnce(DoAll(SetArgReferee<1>("1234567"), SetArgReferee<2>("CCCC"),
3449b90e2a2SMatt Spinler                         SetArgReferee<3>("123456789ABC")));
345ed046856SMatt Spinler 
346ed046856SMatt Spinler     SRC src{entry, ad, dataIface};
347ed046856SMatt Spinler     EXPECT_TRUE(src.valid());
348ed046856SMatt Spinler 
349ed046856SMatt Spinler     ASSERT_TRUE(src.callouts());
350ed046856SMatt Spinler 
351ed046856SMatt Spinler     EXPECT_EQ(src.callouts()->callouts().size(), 1);
352ed046856SMatt Spinler 
353ed046856SMatt Spinler     auto& callout = src.callouts()->callouts().front();
354ed046856SMatt Spinler 
355ed046856SMatt Spinler     EXPECT_EQ(callout->locationCode(), "UTMS-P1");
356717de428SMatt Spinler     EXPECT_EQ(callout->priority(), 'H');
357ed046856SMatt Spinler 
358ed046856SMatt Spinler     auto& fru = callout->fruIdentity();
359ed046856SMatt Spinler 
360ed046856SMatt Spinler     EXPECT_EQ(fru->getPN().value(), "1234567");
361ed046856SMatt Spinler     EXPECT_EQ(fru->getCCIN().value(), "CCCC");
362ed046856SMatt Spinler     EXPECT_EQ(fru->getSN().value(), "123456789ABC");
363ed046856SMatt Spinler 
364ed046856SMatt Spinler     // flatten and unflatten
365ed046856SMatt Spinler     std::vector<uint8_t> data;
366ed046856SMatt Spinler     Stream stream{data};
367ed046856SMatt Spinler     src.flatten(stream);
368ed046856SMatt Spinler 
369ed046856SMatt Spinler     stream.offset(0);
370ed046856SMatt Spinler     SRC newSRC{stream};
371ed046856SMatt Spinler     EXPECT_TRUE(newSRC.valid());
372ed046856SMatt Spinler     ASSERT_TRUE(src.callouts());
373ed046856SMatt Spinler     EXPECT_EQ(src.callouts()->callouts().size(), 1);
374ed046856SMatt Spinler }
375ed046856SMatt Spinler 
3769b90e2a2SMatt Spinler // Test that when the location code can't be obtained that
377479b6927SMatt Spinler // no callout is added.
TEST_F(SRCTest,InventoryCalloutNoLocCodeTest)3789b90e2a2SMatt Spinler TEST_F(SRCTest, InventoryCalloutNoLocCodeTest)
3799b90e2a2SMatt Spinler {
3809b90e2a2SMatt Spinler     message::Entry entry;
3819b90e2a2SMatt Spinler     entry.src.type = 0xBD;
3829b90e2a2SMatt Spinler     entry.src.reasonCode = 0xABCD;
3839b90e2a2SMatt Spinler     entry.subsystem = 0x42;
3849b90e2a2SMatt Spinler 
385e5940634SPatrick Williams     std::map<std::string, std::string> adData{
386e5940634SPatrick Williams         {"CALLOUT_INVENTORY_PATH", "motherboard"}};
3879b90e2a2SMatt Spinler     AdditionalData ad{adData};
3889b90e2a2SMatt Spinler     NiceMock<MockDataInterface> dataIface;
3899b90e2a2SMatt Spinler 
3909b90e2a2SMatt Spinler     auto func = []() {
3919b90e2a2SMatt Spinler         throw sdbusplus::exception::SdBusError(5, "Error");
3929b90e2a2SMatt Spinler         return std::string{};
3939b90e2a2SMatt Spinler     };
3949b90e2a2SMatt Spinler 
3959b90e2a2SMatt Spinler     EXPECT_CALL(dataIface, getLocationCode("motherboard"))
3969b90e2a2SMatt Spinler         .Times(1)
3979b90e2a2SMatt Spinler         .WillOnce(InvokeWithoutArgs(func));
3989b90e2a2SMatt Spinler 
3999b90e2a2SMatt Spinler     EXPECT_CALL(dataIface, getHWCalloutFields(_, _, _, _)).Times(0);
4009b90e2a2SMatt Spinler 
4019b90e2a2SMatt Spinler     SRC src{entry, ad, dataIface};
4029b90e2a2SMatt Spinler     EXPECT_TRUE(src.valid());
4039b90e2a2SMatt Spinler 
404479b6927SMatt Spinler     ASSERT_FALSE(src.callouts());
4059b90e2a2SMatt Spinler 
4069b90e2a2SMatt Spinler     // flatten and unflatten
4079b90e2a2SMatt Spinler     std::vector<uint8_t> data;
4089b90e2a2SMatt Spinler     Stream stream{data};
4099b90e2a2SMatt Spinler     src.flatten(stream);
4109b90e2a2SMatt Spinler 
4119b90e2a2SMatt Spinler     stream.offset(0);
4129b90e2a2SMatt Spinler     SRC newSRC{stream};
4139b90e2a2SMatt Spinler     EXPECT_TRUE(newSRC.valid());
414479b6927SMatt Spinler     ASSERT_FALSE(src.callouts());
4159b90e2a2SMatt Spinler }
4169b90e2a2SMatt Spinler 
4179b90e2a2SMatt Spinler // Test that when the VPD can't be obtained that
4189b90e2a2SMatt Spinler // a callout is still created.
TEST_F(SRCTest,InventoryCalloutNoVPDTest)419ed046856SMatt Spinler TEST_F(SRCTest, InventoryCalloutNoVPDTest)
420ed046856SMatt Spinler {
421ed046856SMatt Spinler     message::Entry entry;
422ed046856SMatt Spinler     entry.src.type = 0xBD;
423ed046856SMatt Spinler     entry.src.reasonCode = 0xABCD;
424ed046856SMatt Spinler     entry.subsystem = 0x42;
425ed046856SMatt Spinler 
426e5940634SPatrick Williams     std::map<std::string, std::string> adData{
427e5940634SPatrick Williams         {"CALLOUT_INVENTORY_PATH", "motherboard"}};
428ed046856SMatt Spinler     AdditionalData ad{adData};
429ed046856SMatt Spinler     NiceMock<MockDataInterface> dataIface;
430ed046856SMatt Spinler 
4319b90e2a2SMatt Spinler     EXPECT_CALL(dataIface, getLocationCode("motherboard"))
4329b90e2a2SMatt Spinler         .Times(1)
4339b90e2a2SMatt Spinler         .WillOnce(Return("UTMS-P10"));
4349b90e2a2SMatt Spinler 
435ed046856SMatt Spinler     auto func = []() { throw sdbusplus::exception::SdBusError(5, "Error"); };
436ed046856SMatt Spinler 
4379b90e2a2SMatt Spinler     EXPECT_CALL(dataIface, getHWCalloutFields("motherboard", _, _, _))
438ed046856SMatt Spinler         .Times(1)
439ed046856SMatt Spinler         .WillOnce(InvokeWithoutArgs(func));
440ed046856SMatt Spinler 
441ed046856SMatt Spinler     SRC src{entry, ad, dataIface};
442ed046856SMatt Spinler     EXPECT_TRUE(src.valid());
443ed046856SMatt Spinler     ASSERT_TRUE(src.callouts());
444ed046856SMatt Spinler     EXPECT_EQ(src.callouts()->callouts().size(), 1);
445ed046856SMatt Spinler 
446ed046856SMatt Spinler     auto& callout = src.callouts()->callouts().front();
4479b90e2a2SMatt Spinler     EXPECT_EQ(callout->locationCode(), "UTMS-P10");
448717de428SMatt Spinler     EXPECT_EQ(callout->priority(), 'H');
449ed046856SMatt Spinler 
450ed046856SMatt Spinler     auto& fru = callout->fruIdentity();
451ed046856SMatt Spinler 
4529b90e2a2SMatt Spinler     EXPECT_EQ(fru->getPN(), "");
4539b90e2a2SMatt Spinler     EXPECT_EQ(fru->getCCIN(), "");
4549b90e2a2SMatt Spinler     EXPECT_EQ(fru->getSN(), "");
4559b90e2a2SMatt Spinler     EXPECT_FALSE(fru->getMaintProc());
4569b90e2a2SMatt Spinler 
457ed046856SMatt Spinler     // flatten and unflatten
458ed046856SMatt Spinler     std::vector<uint8_t> data;
459ed046856SMatt Spinler     Stream stream{data};
460ed046856SMatt Spinler     src.flatten(stream);
461ed046856SMatt Spinler 
462ed046856SMatt Spinler     stream.offset(0);
463ed046856SMatt Spinler     SRC newSRC{stream};
464ed046856SMatt Spinler     EXPECT_TRUE(newSRC.valid());
465ed046856SMatt Spinler     ASSERT_TRUE(src.callouts());
466ed046856SMatt Spinler     EXPECT_EQ(src.callouts()->callouts().size(), 1);
467ed046856SMatt Spinler }
4680398458dSMatt Spinler 
TEST_F(SRCTest,RegistryCalloutTest)4690398458dSMatt Spinler TEST_F(SRCTest, RegistryCalloutTest)
4700398458dSMatt Spinler {
4710398458dSMatt Spinler     message::Entry entry;
4720398458dSMatt Spinler     entry.src.type = 0xBD;
4730398458dSMatt Spinler     entry.src.reasonCode = 0xABCD;
4743fe93e96SMatt Spinler     entry.src.deconfigFlag = true;
475da5b76b2SMatt Spinler     entry.src.checkstopFlag = true;
4760398458dSMatt Spinler     entry.subsystem = 0x42;
4770398458dSMatt Spinler 
4780398458dSMatt Spinler     entry.callouts = R"(
4790398458dSMatt Spinler         [
4800398458dSMatt Spinler         {
4810398458dSMatt Spinler             "System": "systemA",
4820398458dSMatt Spinler             "CalloutList":
4830398458dSMatt Spinler             [
4840398458dSMatt Spinler                 {
4850398458dSMatt Spinler                     "Priority": "high",
4860398458dSMatt Spinler                     "SymbolicFRU": "service_docs"
4870398458dSMatt Spinler                 },
4880398458dSMatt Spinler                 {
4890398458dSMatt Spinler                     "Priority": "medium",
4902edce4e2SMatt Spinler                     "Procedure": "BMC0001"
4910398458dSMatt Spinler                 }
4920398458dSMatt Spinler             ]
4930398458dSMatt Spinler         },
4940398458dSMatt Spinler         {
4950398458dSMatt Spinler             "System": "systemB",
4960398458dSMatt Spinler             "CalloutList":
4970398458dSMatt Spinler             [
4980398458dSMatt Spinler                 {
4990398458dSMatt Spinler                     "Priority": "high",
5000398458dSMatt Spinler                     "LocCode": "P0-C8",
5010398458dSMatt Spinler                     "SymbolicFRUTrusted": "service_docs"
5020398458dSMatt Spinler                 },
5030398458dSMatt Spinler                 {
5040398458dSMatt Spinler                     "Priority": "medium",
5050398458dSMatt Spinler                     "SymbolicFRUTrusted": "service_docs"
5060398458dSMatt Spinler                 }
5070398458dSMatt Spinler             ]
508af191c7aSMatt Spinler         },
509af191c7aSMatt Spinler         {
510af191c7aSMatt Spinler             "System": "systemC",
511af191c7aSMatt Spinler             "CalloutList":
512af191c7aSMatt Spinler             [
513af191c7aSMatt Spinler                 {
514af191c7aSMatt Spinler                     "Priority": "high",
515af191c7aSMatt Spinler                     "LocCode": "P0-C8"
516af191c7aSMatt Spinler                 },
517af191c7aSMatt Spinler                 {
518af191c7aSMatt Spinler                     "Priority": "medium",
519af191c7aSMatt Spinler                     "LocCode": "P0-C9"
520af191c7aSMatt Spinler                 }
521af191c7aSMatt Spinler             ]
5220398458dSMatt Spinler         }
5230398458dSMatt Spinler         ])"_json;
5240398458dSMatt Spinler 
5250398458dSMatt Spinler     {
5260398458dSMatt Spinler         // Call out a symbolic FRU and a procedure
5270398458dSMatt Spinler         AdditionalData ad;
5280398458dSMatt Spinler         NiceMock<MockDataInterface> dataIface;
5296ea4d5f7SMatt Spinler         std::vector<std::string> names{"systemA"};
5306ea4d5f7SMatt Spinler 
5311ab6696fSMatt Spinler         EXPECT_CALL(dataIface, getSystemNames).WillOnce(Return(names));
5320398458dSMatt Spinler 
5330398458dSMatt Spinler         SRC src{entry, ad, dataIface};
5340398458dSMatt Spinler 
535da5b76b2SMatt Spinler         EXPECT_TRUE(
536da5b76b2SMatt Spinler             src.getErrorStatusFlag(SRC::ErrorStatusFlags::deconfigured));
537da5b76b2SMatt Spinler         EXPECT_TRUE(src.getErrorStatusFlag(SRC::ErrorStatusFlags::hwCheckstop));
538da5b76b2SMatt Spinler 
5393fe93e96SMatt Spinler         const auto& hexwords = src.hexwordData();
540da5b76b2SMatt Spinler         auto mask = static_cast<uint32_t>(SRC::ErrorStatusFlags::deconfigured) |
541da5b76b2SMatt Spinler                     static_cast<uint32_t>(SRC::ErrorStatusFlags::hwCheckstop);
5423fe93e96SMatt Spinler         EXPECT_EQ(hexwords[5 - 2] & mask, mask);
5433fe93e96SMatt Spinler 
5440398458dSMatt Spinler         auto& callouts = src.callouts()->callouts();
5450398458dSMatt Spinler         ASSERT_EQ(callouts.size(), 2);
5460398458dSMatt Spinler 
5470398458dSMatt Spinler         EXPECT_EQ(callouts[0]->locationCodeSize(), 0);
5480398458dSMatt Spinler         EXPECT_EQ(callouts[0]->priority(), 'H');
5490398458dSMatt Spinler 
5500398458dSMatt Spinler         EXPECT_EQ(callouts[1]->locationCodeSize(), 0);
5510398458dSMatt Spinler         EXPECT_EQ(callouts[1]->priority(), 'M');
5520398458dSMatt Spinler 
5530398458dSMatt Spinler         auto& fru1 = callouts[0]->fruIdentity();
5540398458dSMatt Spinler         EXPECT_EQ(fru1->getPN().value(), "SVCDOCS");
5550398458dSMatt Spinler         EXPECT_EQ(fru1->failingComponentType(), src::FRUIdentity::symbolicFRU);
5560398458dSMatt Spinler         EXPECT_FALSE(fru1->getMaintProc());
5570398458dSMatt Spinler         EXPECT_FALSE(fru1->getSN());
5580398458dSMatt Spinler         EXPECT_FALSE(fru1->getCCIN());
5590398458dSMatt Spinler 
5600398458dSMatt Spinler         auto& fru2 = callouts[1]->fruIdentity();
561ea2873ddSMatt Spinler         EXPECT_EQ(fru2->getMaintProc().value(), "BMC0001");
5620398458dSMatt Spinler         EXPECT_EQ(fru2->failingComponentType(),
5630398458dSMatt Spinler                   src::FRUIdentity::maintenanceProc);
5640398458dSMatt Spinler         EXPECT_FALSE(fru2->getPN());
5650398458dSMatt Spinler         EXPECT_FALSE(fru2->getSN());
5660398458dSMatt Spinler         EXPECT_FALSE(fru2->getCCIN());
5670398458dSMatt Spinler     }
5680398458dSMatt Spinler 
5690398458dSMatt Spinler     {
5700398458dSMatt Spinler         // Call out a trusted symbolic FRU with a location code, and
5710398458dSMatt Spinler         // another one without.
5720398458dSMatt Spinler         AdditionalData ad;
5730398458dSMatt Spinler         NiceMock<MockDataInterface> dataIface;
5746ea4d5f7SMatt Spinler         std::vector<std::string> names{"systemB"};
5756ea4d5f7SMatt Spinler 
576af191c7aSMatt Spinler         EXPECT_CALL(dataIface, expandLocationCode).WillOnce(Return("P0-C8"));
5771ab6696fSMatt Spinler         EXPECT_CALL(dataIface, getSystemNames).WillOnce(Return(names));
5780398458dSMatt Spinler 
5790398458dSMatt Spinler         SRC src{entry, ad, dataIface};
5800398458dSMatt Spinler 
5810398458dSMatt Spinler         auto& callouts = src.callouts()->callouts();
5820398458dSMatt Spinler         EXPECT_EQ(callouts.size(), 2);
5830398458dSMatt Spinler 
5840398458dSMatt Spinler         EXPECT_EQ(callouts[0]->locationCode(), "P0-C8");
5850398458dSMatt Spinler         EXPECT_EQ(callouts[0]->priority(), 'H');
5860398458dSMatt Spinler 
5870398458dSMatt Spinler         EXPECT_EQ(callouts[1]->locationCodeSize(), 0);
5880398458dSMatt Spinler         EXPECT_EQ(callouts[1]->priority(), 'M');
5890398458dSMatt Spinler 
5900398458dSMatt Spinler         auto& fru1 = callouts[0]->fruIdentity();
5910398458dSMatt Spinler         EXPECT_EQ(fru1->getPN().value(), "SVCDOCS");
5920398458dSMatt Spinler         EXPECT_EQ(fru1->failingComponentType(),
5930398458dSMatt Spinler                   src::FRUIdentity::symbolicFRUTrustedLocCode);
5940398458dSMatt Spinler         EXPECT_FALSE(fru1->getMaintProc());
5950398458dSMatt Spinler         EXPECT_FALSE(fru1->getSN());
5960398458dSMatt Spinler         EXPECT_FALSE(fru1->getCCIN());
5970398458dSMatt Spinler 
5980398458dSMatt Spinler         // It asked for a trusted symbolic FRU, but no location code
5990398458dSMatt Spinler         // was provided so it is switched back to a normal one
6000398458dSMatt Spinler         auto& fru2 = callouts[1]->fruIdentity();
6010398458dSMatt Spinler         EXPECT_EQ(fru2->getPN().value(), "SVCDOCS");
6020398458dSMatt Spinler         EXPECT_EQ(fru2->failingComponentType(), src::FRUIdentity::symbolicFRU);
6030398458dSMatt Spinler         EXPECT_FALSE(fru2->getMaintProc());
6040398458dSMatt Spinler         EXPECT_FALSE(fru2->getSN());
6050398458dSMatt Spinler         EXPECT_FALSE(fru2->getCCIN());
6060398458dSMatt Spinler     }
607af191c7aSMatt Spinler 
608af191c7aSMatt Spinler     {
609af191c7aSMatt Spinler         // Two hardware callouts
610af191c7aSMatt Spinler         AdditionalData ad;
611af191c7aSMatt Spinler         NiceMock<MockDataInterface> dataIface;
612af191c7aSMatt Spinler         std::vector<std::string> names{"systemC"};
613af191c7aSMatt Spinler 
6141ab6696fSMatt Spinler         EXPECT_CALL(dataIface, getSystemNames).WillOnce(Return(names));
615af191c7aSMatt Spinler 
616af191c7aSMatt Spinler         EXPECT_CALL(dataIface, expandLocationCode("P0-C8", 0))
617af191c7aSMatt Spinler             .WillOnce(Return("UXXX-P0-C8"));
618af191c7aSMatt Spinler 
619af191c7aSMatt Spinler         EXPECT_CALL(dataIface, expandLocationCode("P0-C9", 0))
620af191c7aSMatt Spinler             .WillOnce(Return("UXXX-P0-C9"));
621af191c7aSMatt Spinler 
6222f9225a4SMatt Spinler         EXPECT_CALL(dataIface, getInventoryFromLocCode("P0-C8", 0, false))
623bad056beSMatt Spinler             .WillOnce(Return(std::vector<std::string>{
624bad056beSMatt Spinler                 "/xyz/openbmc_project/inventory/chassis/motherboard/cpu0"}));
625af191c7aSMatt Spinler 
6262f9225a4SMatt Spinler         EXPECT_CALL(dataIface, getInventoryFromLocCode("P0-C9", 0, false))
627bad056beSMatt Spinler             .WillOnce(Return(std::vector<std::string>{
628bad056beSMatt Spinler                 "/xyz/openbmc_project/inventory/chassis/motherboard/cpu1"}));
629af191c7aSMatt Spinler 
630af191c7aSMatt Spinler         EXPECT_CALL(
631af191c7aSMatt Spinler             dataIface,
632af191c7aSMatt Spinler             getHWCalloutFields(
633af191c7aSMatt Spinler                 "/xyz/openbmc_project/inventory/chassis/motherboard/cpu0", _, _,
634af191c7aSMatt Spinler                 _))
635af191c7aSMatt Spinler             .Times(1)
636075c7923SPatrick Williams             .WillOnce(
637075c7923SPatrick Williams                 DoAll(SetArgReferee<1>("1234567"), SetArgReferee<2>("CCCC"),
638af191c7aSMatt Spinler                       SetArgReferee<3>("123456789ABC")));
639af191c7aSMatt Spinler 
640af191c7aSMatt Spinler         EXPECT_CALL(
641af191c7aSMatt Spinler             dataIface,
642af191c7aSMatt Spinler             getHWCalloutFields(
643af191c7aSMatt Spinler                 "/xyz/openbmc_project/inventory/chassis/motherboard/cpu1", _, _,
644af191c7aSMatt Spinler                 _))
645af191c7aSMatt Spinler             .Times(1)
646075c7923SPatrick Williams             .WillOnce(
647075c7923SPatrick Williams                 DoAll(SetArgReferee<1>("2345678"), SetArgReferee<2>("DDDD"),
648af191c7aSMatt Spinler                       SetArgReferee<3>("23456789ABCD")));
649af191c7aSMatt Spinler 
650af191c7aSMatt Spinler         SRC src{entry, ad, dataIface};
651af191c7aSMatt Spinler 
652af191c7aSMatt Spinler         auto& callouts = src.callouts()->callouts();
653af191c7aSMatt Spinler         EXPECT_EQ(callouts.size(), 2);
654af191c7aSMatt Spinler 
655af191c7aSMatt Spinler         EXPECT_EQ(callouts[0]->locationCode(), "UXXX-P0-C8");
656af191c7aSMatt Spinler         EXPECT_EQ(callouts[0]->priority(), 'H');
657af191c7aSMatt Spinler 
658af191c7aSMatt Spinler         auto& fru1 = callouts[0]->fruIdentity();
659af191c7aSMatt Spinler         EXPECT_EQ(fru1->getPN().value(), "1234567");
660af191c7aSMatt Spinler         EXPECT_EQ(fru1->getCCIN().value(), "CCCC");
661af191c7aSMatt Spinler         EXPECT_EQ(fru1->getSN().value(), "123456789ABC");
662af191c7aSMatt Spinler 
663af191c7aSMatt Spinler         EXPECT_EQ(callouts[1]->locationCode(), "UXXX-P0-C9");
664af191c7aSMatt Spinler         EXPECT_EQ(callouts[1]->priority(), 'M');
665af191c7aSMatt Spinler 
666af191c7aSMatt Spinler         auto& fru2 = callouts[1]->fruIdentity();
667af191c7aSMatt Spinler         EXPECT_EQ(fru2->getPN().value(), "2345678");
668af191c7aSMatt Spinler         EXPECT_EQ(fru2->getCCIN().value(), "DDDD");
669af191c7aSMatt Spinler         EXPECT_EQ(fru2->getSN().value(), "23456789ABCD");
670af191c7aSMatt Spinler     }
6710398458dSMatt Spinler }
672717de428SMatt Spinler 
673f00f9d0fSMatt Spinler // Test that a symbolic FRU with a trusted location code callout
674f00f9d0fSMatt Spinler // from the registry can get its location from the
675f00f9d0fSMatt Spinler // CALLOUT_INVENTORY_PATH AdditionalData entry.
TEST_F(SRCTest,SymbolicFRUWithInvPathTest)676f00f9d0fSMatt Spinler TEST_F(SRCTest, SymbolicFRUWithInvPathTest)
677f00f9d0fSMatt Spinler {
678f00f9d0fSMatt Spinler     message::Entry entry;
679f00f9d0fSMatt Spinler     entry.src.type = 0xBD;
680f00f9d0fSMatt Spinler     entry.src.reasonCode = 0xABCD;
681f00f9d0fSMatt Spinler     entry.subsystem = 0x42;
682f00f9d0fSMatt Spinler 
683f00f9d0fSMatt Spinler     entry.callouts = R"(
684f00f9d0fSMatt Spinler         [{
685f00f9d0fSMatt Spinler             "CalloutList":
686f00f9d0fSMatt Spinler             [
687f00f9d0fSMatt Spinler                 {
688f00f9d0fSMatt Spinler                     "Priority": "high",
689f00f9d0fSMatt Spinler                     "SymbolicFRUTrusted": "service_docs",
690f00f9d0fSMatt Spinler                     "UseInventoryLocCode": true
691f00f9d0fSMatt Spinler                 },
692f00f9d0fSMatt Spinler                 {
693f00f9d0fSMatt Spinler                     "Priority": "medium",
694f00f9d0fSMatt Spinler                     "LocCode": "P0-C8",
695f00f9d0fSMatt Spinler                     "SymbolicFRUTrusted": "pwrsply"
696f00f9d0fSMatt Spinler                 }
697f00f9d0fSMatt Spinler             ]
698f00f9d0fSMatt Spinler         }])"_json;
699f00f9d0fSMatt Spinler 
700f00f9d0fSMatt Spinler     {
701f00f9d0fSMatt Spinler         // The location code for the first symbolic FRU callout will
702f00f9d0fSMatt Spinler         // come from this inventory path since UseInventoryLocCode is set.
703f00f9d0fSMatt Spinler         // In this case there will be no normal FRU callout for the motherboard.
704e5940634SPatrick Williams         std::map<std::string, std::string> adData{
705e5940634SPatrick Williams             {"CALLOUT_INVENTORY_PATH", "motherboard"}};
706f00f9d0fSMatt Spinler         AdditionalData ad{adData};
707f00f9d0fSMatt Spinler         NiceMock<MockDataInterface> dataIface;
708f00f9d0fSMatt Spinler         std::vector<std::string> names{"systemA"};
709f00f9d0fSMatt Spinler 
7101ab6696fSMatt Spinler         EXPECT_CALL(dataIface, getSystemNames).WillOnce(Return(names));
711f00f9d0fSMatt Spinler 
712f00f9d0fSMatt Spinler         EXPECT_CALL(dataIface, getLocationCode("motherboard"))
713f00f9d0fSMatt Spinler             .Times(1)
714f00f9d0fSMatt Spinler             .WillOnce(Return("Ufcs-P10"));
715f00f9d0fSMatt Spinler 
716f00f9d0fSMatt Spinler         EXPECT_CALL(dataIface, expandLocationCode("P0-C8", 0))
717f00f9d0fSMatt Spinler             .WillOnce(Return("Ufcs-P0-C8"));
718f00f9d0fSMatt Spinler 
719f00f9d0fSMatt Spinler         SRC src{entry, ad, dataIface};
720f00f9d0fSMatt Spinler 
721f00f9d0fSMatt Spinler         auto& callouts = src.callouts()->callouts();
722f00f9d0fSMatt Spinler         EXPECT_EQ(callouts.size(), 2);
723f00f9d0fSMatt Spinler 
724f00f9d0fSMatt Spinler         // The location code for the first symbolic FRU callout with a
725f00f9d0fSMatt Spinler         // trusted location code comes from the motherboard.
726f00f9d0fSMatt Spinler         EXPECT_EQ(callouts[0]->locationCode(), "Ufcs-P10");
727f00f9d0fSMatt Spinler         EXPECT_EQ(callouts[0]->priority(), 'H');
728f00f9d0fSMatt Spinler         auto& fru1 = callouts[0]->fruIdentity();
729f00f9d0fSMatt Spinler         EXPECT_EQ(fru1->getPN().value(), "SVCDOCS");
730f00f9d0fSMatt Spinler         EXPECT_EQ(fru1->failingComponentType(),
731f00f9d0fSMatt Spinler                   src::FRUIdentity::symbolicFRUTrustedLocCode);
732f00f9d0fSMatt Spinler 
733f00f9d0fSMatt Spinler         // The second trusted symbolic FRU callouts uses the location
734f00f9d0fSMatt Spinler         // code in the registry as usual.
735f00f9d0fSMatt Spinler         EXPECT_EQ(callouts[1]->locationCode(), "Ufcs-P0-C8");
736f00f9d0fSMatt Spinler         EXPECT_EQ(callouts[1]->priority(), 'M');
737f00f9d0fSMatt Spinler         auto& fru2 = callouts[1]->fruIdentity();
738f00f9d0fSMatt Spinler         EXPECT_EQ(fru2->getPN().value(), "PWRSPLY");
739f00f9d0fSMatt Spinler         EXPECT_EQ(fru2->failingComponentType(),
740f00f9d0fSMatt Spinler                   src::FRUIdentity::symbolicFRUTrustedLocCode);
741f00f9d0fSMatt Spinler     }
742f00f9d0fSMatt Spinler 
743f00f9d0fSMatt Spinler     {
744f00f9d0fSMatt Spinler         // This time say we want to use the location code from
745f00f9d0fSMatt Spinler         // the inventory, but don't pass it in and the callout should
746f00f9d0fSMatt Spinler         // end up a regular symbolic FRU
747f00f9d0fSMatt Spinler         entry.callouts = R"(
748f00f9d0fSMatt Spinler         [{
749f00f9d0fSMatt Spinler             "CalloutList":
750f00f9d0fSMatt Spinler             [
751f00f9d0fSMatt Spinler                 {
752f00f9d0fSMatt Spinler                     "Priority": "high",
753f00f9d0fSMatt Spinler                     "SymbolicFRUTrusted": "service_docs",
754f00f9d0fSMatt Spinler                     "UseInventoryLocCode": true
755f00f9d0fSMatt Spinler                 }
756f00f9d0fSMatt Spinler             ]
757f00f9d0fSMatt Spinler         }])"_json;
758f00f9d0fSMatt Spinler 
759f00f9d0fSMatt Spinler         AdditionalData ad;
760f00f9d0fSMatt Spinler         NiceMock<MockDataInterface> dataIface;
761f00f9d0fSMatt Spinler         std::vector<std::string> names{"systemA"};
762f00f9d0fSMatt Spinler 
7631ab6696fSMatt Spinler         EXPECT_CALL(dataIface, getSystemNames).WillOnce(Return(names));
764f00f9d0fSMatt Spinler 
765f00f9d0fSMatt Spinler         SRC src{entry, ad, dataIface};
766f00f9d0fSMatt Spinler 
767f00f9d0fSMatt Spinler         auto& callouts = src.callouts()->callouts();
768f00f9d0fSMatt Spinler         EXPECT_EQ(callouts.size(), 1);
769f00f9d0fSMatt Spinler 
770f00f9d0fSMatt Spinler         EXPECT_EQ(callouts[0]->locationCode(), "");
771f00f9d0fSMatt Spinler         EXPECT_EQ(callouts[0]->priority(), 'H');
772f00f9d0fSMatt Spinler         auto& fru1 = callouts[0]->fruIdentity();
773f00f9d0fSMatt Spinler         EXPECT_EQ(fru1->getPN().value(), "SVCDOCS");
774f00f9d0fSMatt Spinler         EXPECT_EQ(fru1->failingComponentType(), src::FRUIdentity::symbolicFRU);
775f00f9d0fSMatt Spinler     }
776f00f9d0fSMatt Spinler }
777f00f9d0fSMatt Spinler 
TEST_F(SRCTest,RegistryCalloutCantGetLocTest)778*7b92372dSMatt Spinler TEST_F(SRCTest, RegistryCalloutCantGetLocTest)
779*7b92372dSMatt Spinler {
780*7b92372dSMatt Spinler     message::Entry entry;
781*7b92372dSMatt Spinler     entry.src.type = 0xBD;
782*7b92372dSMatt Spinler     entry.src.reasonCode = 0xABCD;
783*7b92372dSMatt Spinler     entry.src.deconfigFlag = true;
784*7b92372dSMatt Spinler     entry.src.checkstopFlag = true;
785*7b92372dSMatt Spinler     entry.subsystem = 0x42;
786*7b92372dSMatt Spinler 
787*7b92372dSMatt Spinler     entry.callouts = R"(
788*7b92372dSMatt Spinler         [{
789*7b92372dSMatt Spinler             "CalloutList":
790*7b92372dSMatt Spinler             [
791*7b92372dSMatt Spinler                 {
792*7b92372dSMatt Spinler                     "Priority": "high",
793*7b92372dSMatt Spinler                     "LocCode": "P0-C8"
794*7b92372dSMatt Spinler                 },
795*7b92372dSMatt Spinler                 {
796*7b92372dSMatt Spinler                     "Priority": "medium",
797*7b92372dSMatt Spinler                     "LocCode": "P0-C9"
798*7b92372dSMatt Spinler                 }
799*7b92372dSMatt Spinler             ]
800*7b92372dSMatt Spinler         }])"_json;
801*7b92372dSMatt Spinler 
802*7b92372dSMatt Spinler     {
803*7b92372dSMatt Spinler         // The calls to expand the location codes will fail, but it should
804*7b92372dSMatt Spinler         // still create the callouts with the unexpanded values and no HW
805*7b92372dSMatt Spinler         // fields.
806*7b92372dSMatt Spinler         AdditionalData ad;
807*7b92372dSMatt Spinler         NiceMock<MockDataInterface> dataIface;
808*7b92372dSMatt Spinler         std::vector<std::string> names{"systemC"};
809*7b92372dSMatt Spinler 
810*7b92372dSMatt Spinler         EXPECT_CALL(dataIface, getSystemNames).WillOnce(Return(names));
811*7b92372dSMatt Spinler 
812*7b92372dSMatt Spinler         EXPECT_CALL(dataIface, expandLocationCode("P0-C8", 0))
813*7b92372dSMatt Spinler             .WillRepeatedly(Throw(std::runtime_error("Fail")));
814*7b92372dSMatt Spinler 
815*7b92372dSMatt Spinler         EXPECT_CALL(dataIface, expandLocationCode("P0-C9", 0))
816*7b92372dSMatt Spinler             .WillRepeatedly(Throw(std::runtime_error("Fail")));
817*7b92372dSMatt Spinler 
818*7b92372dSMatt Spinler         EXPECT_CALL(dataIface, getInventoryFromLocCode(_, _, _)).Times(0);
819*7b92372dSMatt Spinler 
820*7b92372dSMatt Spinler         EXPECT_CALL(dataIface, getHWCalloutFields(_, _, _, _)).Times(0);
821*7b92372dSMatt Spinler 
822*7b92372dSMatt Spinler         SRC src{entry, ad, dataIface};
823*7b92372dSMatt Spinler 
824*7b92372dSMatt Spinler         auto& callouts = src.callouts()->callouts();
825*7b92372dSMatt Spinler         ASSERT_EQ(callouts.size(), 2);
826*7b92372dSMatt Spinler 
827*7b92372dSMatt Spinler         // Only unexpanded location codes
828*7b92372dSMatt Spinler         EXPECT_EQ(callouts[0]->locationCode(), "P0-C8");
829*7b92372dSMatt Spinler         EXPECT_EQ(callouts[0]->priority(), 'H');
830*7b92372dSMatt Spinler 
831*7b92372dSMatt Spinler         auto& fru1 = callouts[0]->fruIdentity();
832*7b92372dSMatt Spinler         EXPECT_EQ(fru1->getPN().value(), "");
833*7b92372dSMatt Spinler         EXPECT_EQ(fru1->getCCIN().value(), "");
834*7b92372dSMatt Spinler         EXPECT_EQ(fru1->getSN().value(), "");
835*7b92372dSMatt Spinler 
836*7b92372dSMatt Spinler         EXPECT_EQ(callouts[1]->locationCode(), "P0-C9");
837*7b92372dSMatt Spinler         EXPECT_EQ(callouts[1]->priority(), 'M');
838*7b92372dSMatt Spinler 
839*7b92372dSMatt Spinler         auto& fru2 = callouts[1]->fruIdentity();
840*7b92372dSMatt Spinler         EXPECT_EQ(fru2->getPN().value(), "");
841*7b92372dSMatt Spinler         EXPECT_EQ(fru2->getCCIN().value(), "");
842*7b92372dSMatt Spinler         EXPECT_EQ(fru2->getSN().value(), "");
843*7b92372dSMatt Spinler     }
844*7b92372dSMatt Spinler }
845*7b92372dSMatt Spinler 
TEST_F(SRCTest,TrustedSymbolicFRUCantGetLocTest)846*7b92372dSMatt Spinler TEST_F(SRCTest, TrustedSymbolicFRUCantGetLocTest)
847*7b92372dSMatt Spinler {
848*7b92372dSMatt Spinler     message::Entry entry;
849*7b92372dSMatt Spinler     entry.src.type = 0xBD;
850*7b92372dSMatt Spinler     entry.src.reasonCode = 0xABCD;
851*7b92372dSMatt Spinler     entry.subsystem = 0x42;
852*7b92372dSMatt Spinler 
853*7b92372dSMatt Spinler     entry.callouts = R"(
854*7b92372dSMatt Spinler         [{
855*7b92372dSMatt Spinler             "CalloutList":
856*7b92372dSMatt Spinler             [
857*7b92372dSMatt Spinler                 {
858*7b92372dSMatt Spinler                     "Priority": "medium",
859*7b92372dSMatt Spinler                     "LocCode": "P0-C8",
860*7b92372dSMatt Spinler                     "SymbolicFRUTrusted": "pwrsply"
861*7b92372dSMatt Spinler                 }
862*7b92372dSMatt Spinler             ]
863*7b92372dSMatt Spinler         }])"_json;
864*7b92372dSMatt Spinler 
865*7b92372dSMatt Spinler     std::map<std::string, std::string> adData;
866*7b92372dSMatt Spinler     AdditionalData ad{adData};
867*7b92372dSMatt Spinler     NiceMock<MockDataInterface> dataIface;
868*7b92372dSMatt Spinler     std::vector<std::string> names{"systemA"};
869*7b92372dSMatt Spinler 
870*7b92372dSMatt Spinler     EXPECT_CALL(dataIface, getSystemNames).WillOnce(Return(names));
871*7b92372dSMatt Spinler 
872*7b92372dSMatt Spinler     // The call to expand the location code will fail, but it should
873*7b92372dSMatt Spinler     // still create the callout with the unexpanded value and the
874*7b92372dSMatt Spinler     // symbolic FRU can't be trusted.
875*7b92372dSMatt Spinler     EXPECT_CALL(dataIface, expandLocationCode("P0-C8", 0))
876*7b92372dSMatt Spinler         .WillRepeatedly(Throw(std::runtime_error("Fail")));
877*7b92372dSMatt Spinler 
878*7b92372dSMatt Spinler     SRC src{entry, ad, dataIface};
879*7b92372dSMatt Spinler 
880*7b92372dSMatt Spinler     auto& callouts = src.callouts()->callouts();
881*7b92372dSMatt Spinler     ASSERT_EQ(callouts.size(), 1);
882*7b92372dSMatt Spinler 
883*7b92372dSMatt Spinler     EXPECT_EQ(callouts[0]->locationCode(), "P0-C8");
884*7b92372dSMatt Spinler     EXPECT_EQ(callouts[0]->priority(), 'M');
885*7b92372dSMatt Spinler     auto& fru = callouts[0]->fruIdentity();
886*7b92372dSMatt Spinler     EXPECT_EQ(fru->getPN().value(), "PWRSPLY");
887*7b92372dSMatt Spinler     EXPECT_EQ(fru->failingComponentType(), src::FRUIdentity::symbolicFRU);
888*7b92372dSMatt Spinler }
889*7b92372dSMatt Spinler 
890717de428SMatt Spinler // Test looking up device path fails in the callout jSON.
TEST_F(SRCTest,DevicePathCalloutTest)891717de428SMatt Spinler TEST_F(SRCTest, DevicePathCalloutTest)
892717de428SMatt Spinler {
893717de428SMatt Spinler     message::Entry entry;
894717de428SMatt Spinler     entry.src.type = 0xBD;
895717de428SMatt Spinler     entry.src.reasonCode = 0xABCD;
896717de428SMatt Spinler     entry.subsystem = 0x42;
897717de428SMatt Spinler 
898717de428SMatt Spinler     const auto calloutJSON = R"(
899717de428SMatt Spinler     {
900717de428SMatt Spinler         "I2C":
901717de428SMatt Spinler         {
902717de428SMatt Spinler             "14":
903717de428SMatt Spinler             {
904717de428SMatt Spinler                 "114":
905717de428SMatt Spinler                 {
906717de428SMatt Spinler                     "Callouts":[
907717de428SMatt Spinler                     {
908717de428SMatt Spinler                         "Name": "/chassis/motherboard/cpu0",
909717de428SMatt Spinler                         "LocationCode": "P1-C40",
910717de428SMatt Spinler                         "Priority": "H"
911717de428SMatt Spinler                     },
912717de428SMatt Spinler                     {
913717de428SMatt Spinler                         "Name": "/chassis/motherboard",
914717de428SMatt Spinler                         "LocationCode": "P1",
915717de428SMatt Spinler                         "Priority": "M"
916717de428SMatt Spinler                     },
917717de428SMatt Spinler                     {
918717de428SMatt Spinler                         "Name": "/chassis/motherboard/bmc",
919717de428SMatt Spinler                         "LocationCode": "P1-C15",
920717de428SMatt Spinler                         "Priority": "L"
921717de428SMatt Spinler                     }
922717de428SMatt Spinler                     ],
923717de428SMatt Spinler                     "Dest": "proc 0 target"
924717de428SMatt Spinler                 }
925717de428SMatt Spinler             }
926717de428SMatt Spinler         }
927717de428SMatt Spinler     })";
928717de428SMatt Spinler 
929717de428SMatt Spinler     auto dataPath = getPELReadOnlyDataPath();
930717de428SMatt Spinler     std::ofstream file{dataPath / "systemA_dev_callouts.json"};
931717de428SMatt Spinler     file << calloutJSON;
932717de428SMatt Spinler     file.close();
933717de428SMatt Spinler 
934717de428SMatt Spinler     NiceMock<MockDataInterface> dataIface;
935717de428SMatt Spinler     std::vector<std::string> names{"systemA"};
936717de428SMatt Spinler 
937717de428SMatt Spinler     EXPECT_CALL(dataIface, getSystemNames)
938717de428SMatt Spinler         .Times(5)
9391ab6696fSMatt Spinler         .WillRepeatedly(Return(names));
940717de428SMatt Spinler 
9412f9225a4SMatt Spinler     EXPECT_CALL(dataIface, getInventoryFromLocCode("P1-C40", 0, false))
942717de428SMatt Spinler         .Times(3)
943bad056beSMatt Spinler         .WillRepeatedly(Return(std::vector<std::string>{
944bad056beSMatt Spinler             "/xyz/openbmc_project/inventory/chassis/motherboard/cpu0"}));
945717de428SMatt Spinler 
9462f9225a4SMatt Spinler     EXPECT_CALL(dataIface, getInventoryFromLocCode("P1", 0, false))
947717de428SMatt Spinler         .Times(3)
948bad056beSMatt Spinler         .WillRepeatedly(Return(std::vector<std::string>{
949bad056beSMatt Spinler             "/xyz/openbmc_project/inventory/chassis/motherboard"}));
950717de428SMatt Spinler 
9512f9225a4SMatt Spinler     EXPECT_CALL(dataIface, getInventoryFromLocCode("P1-C15", 0, false))
952717de428SMatt Spinler         .Times(3)
953bad056beSMatt Spinler         .WillRepeatedly(Return(std::vector<std::string>{
954bad056beSMatt Spinler             "/xyz/openbmc_project/inventory/chassis/motherboard/bmc"}));
955717de428SMatt Spinler 
9560d92b528SMatt Spinler     EXPECT_CALL(dataIface, expandLocationCode("P1-C40", 0))
957717de428SMatt Spinler         .Times(3)
958717de428SMatt Spinler         .WillRepeatedly(Return("Ufcs-P1-C40"));
9590d92b528SMatt Spinler 
9600d92b528SMatt Spinler     EXPECT_CALL(dataIface, expandLocationCode("P1", 0))
961717de428SMatt Spinler         .Times(3)
962717de428SMatt Spinler         .WillRepeatedly(Return("Ufcs-P1"));
9630d92b528SMatt Spinler 
9640d92b528SMatt Spinler     EXPECT_CALL(dataIface, expandLocationCode("P1-C15", 0))
965717de428SMatt Spinler         .Times(3)
966717de428SMatt Spinler         .WillRepeatedly(Return("Ufcs-P1-C15"));
967717de428SMatt Spinler 
968075c7923SPatrick Williams     EXPECT_CALL(dataIface,
969717de428SMatt Spinler                 getHWCalloutFields(
970075c7923SPatrick Williams                     "/xyz/openbmc_project/inventory/chassis/motherboard/cpu0",
971075c7923SPatrick Williams                     _, _, _))
972717de428SMatt Spinler         .Times(3)
973075c7923SPatrick Williams         .WillRepeatedly(
974075c7923SPatrick Williams             DoAll(SetArgReferee<1>("1234567"), SetArgReferee<2>("CCCC"),
975717de428SMatt Spinler                   SetArgReferee<3>("123456789ABC")));
976717de428SMatt Spinler     EXPECT_CALL(
977717de428SMatt Spinler         dataIface,
978717de428SMatt Spinler         getHWCalloutFields("/xyz/openbmc_project/inventory/chassis/motherboard",
979717de428SMatt Spinler                            _, _, _))
980717de428SMatt Spinler         .Times(3)
981075c7923SPatrick Williams         .WillRepeatedly(
982075c7923SPatrick Williams             DoAll(SetArgReferee<1>("7654321"), SetArgReferee<2>("MMMM"),
983717de428SMatt Spinler                   SetArgReferee<3>("CBA987654321")));
984075c7923SPatrick Williams     EXPECT_CALL(dataIface,
985717de428SMatt Spinler                 getHWCalloutFields(
986075c7923SPatrick Williams                     "/xyz/openbmc_project/inventory/chassis/motherboard/bmc", _,
987075c7923SPatrick Williams                     _, _))
988717de428SMatt Spinler         .Times(3)
989075c7923SPatrick Williams         .WillRepeatedly(
990075c7923SPatrick Williams             DoAll(SetArgReferee<1>("7123456"), SetArgReferee<2>("BBBB"),
991717de428SMatt Spinler                   SetArgReferee<3>("C123456789AB")));
992717de428SMatt Spinler 
993717de428SMatt Spinler     // Call this below with different AdditionalData values that
994717de428SMatt Spinler     // result in the same callouts.
995717de428SMatt Spinler     auto checkCallouts = [&entry, &dataIface](const auto& items) {
996717de428SMatt Spinler         AdditionalData ad{items};
997717de428SMatt Spinler         SRC src{entry, ad, dataIface};
998717de428SMatt Spinler 
999717de428SMatt Spinler         ASSERT_TRUE(src.callouts());
1000717de428SMatt Spinler         auto& callouts = src.callouts()->callouts();
1001717de428SMatt Spinler 
1002717de428SMatt Spinler         ASSERT_EQ(callouts.size(), 3);
1003717de428SMatt Spinler 
1004717de428SMatt Spinler         {
1005717de428SMatt Spinler             EXPECT_EQ(callouts[0]->priority(), 'H');
1006717de428SMatt Spinler             EXPECT_EQ(callouts[0]->locationCode(), "Ufcs-P1-C40");
1007717de428SMatt Spinler 
1008717de428SMatt Spinler             auto& fru = callouts[0]->fruIdentity();
1009717de428SMatt Spinler             EXPECT_EQ(fru->getPN().value(), "1234567");
1010717de428SMatt Spinler             EXPECT_EQ(fru->getCCIN().value(), "CCCC");
1011717de428SMatt Spinler             EXPECT_EQ(fru->getSN().value(), "123456789ABC");
1012717de428SMatt Spinler         }
1013717de428SMatt Spinler         {
1014717de428SMatt Spinler             EXPECT_EQ(callouts[1]->priority(), 'M');
1015717de428SMatt Spinler             EXPECT_EQ(callouts[1]->locationCode(), "Ufcs-P1");
1016717de428SMatt Spinler 
1017717de428SMatt Spinler             auto& fru = callouts[1]->fruIdentity();
1018717de428SMatt Spinler             EXPECT_EQ(fru->getPN().value(), "7654321");
1019717de428SMatt Spinler             EXPECT_EQ(fru->getCCIN().value(), "MMMM");
1020717de428SMatt Spinler             EXPECT_EQ(fru->getSN().value(), "CBA987654321");
1021717de428SMatt Spinler         }
1022717de428SMatt Spinler         {
1023717de428SMatt Spinler             EXPECT_EQ(callouts[2]->priority(), 'L');
1024717de428SMatt Spinler             EXPECT_EQ(callouts[2]->locationCode(), "Ufcs-P1-C15");
1025717de428SMatt Spinler 
1026717de428SMatt Spinler             auto& fru = callouts[2]->fruIdentity();
1027717de428SMatt Spinler             EXPECT_EQ(fru->getPN().value(), "7123456");
1028717de428SMatt Spinler             EXPECT_EQ(fru->getCCIN().value(), "BBBB");
1029717de428SMatt Spinler             EXPECT_EQ(fru->getSN().value(), "C123456789AB");
1030717de428SMatt Spinler         }
1031717de428SMatt Spinler     };
1032717de428SMatt Spinler 
1033717de428SMatt Spinler     {
1034717de428SMatt Spinler         // Callouts based on the device path
1035e5940634SPatrick Williams         std::map<std::string, std::string> items{
1036e5940634SPatrick Williams             {"CALLOUT_ERRNO", "5"},
1037e5940634SPatrick Williams             {"CALLOUT_DEVICE_PATH",
1038e5940634SPatrick Williams              "/sys/devices/platform/ahb/ahb:apb/ahb:apb:bus@1e78a000/1e78a340.i2c-bus/i2c-14/14-0072"}};
1039717de428SMatt Spinler 
1040717de428SMatt Spinler         checkCallouts(items);
1041717de428SMatt Spinler     }
1042717de428SMatt Spinler 
1043717de428SMatt Spinler     {
1044717de428SMatt Spinler         // Callouts based on the I2C bus and address
1045e5940634SPatrick Williams         std::map<std::string, std::string> items{{"CALLOUT_ERRNO", "5"},
1046e5940634SPatrick Williams                                                  {"CALLOUT_IIC_BUS", "14"},
1047e5940634SPatrick Williams                                                  {"CALLOUT_IIC_ADDR", "0x72"}};
1048717de428SMatt Spinler         checkCallouts(items);
1049717de428SMatt Spinler     }
1050717de428SMatt Spinler 
1051717de428SMatt Spinler     {
1052717de428SMatt Spinler         // Also based on I2C bus and address, but with bus = /dev/i2c-14
1053e5940634SPatrick Williams         std::map<std::string, std::string> items{{"CALLOUT_ERRNO", "5"},
1054e5940634SPatrick Williams                                                  {"CALLOUT_IIC_BUS", "14"},
1055e5940634SPatrick Williams                                                  {"CALLOUT_IIC_ADDR", "0x72"}};
1056717de428SMatt Spinler         checkCallouts(items);
1057717de428SMatt Spinler     }
1058717de428SMatt Spinler 
1059717de428SMatt Spinler     {
1060717de428SMatt Spinler         // Callout not found
1061e5940634SPatrick Williams         std::map<std::string, std::string> items{
1062e5940634SPatrick Williams             {"CALLOUT_ERRNO", "5"},
1063e5940634SPatrick Williams             {"CALLOUT_DEVICE_PATH",
1064e5940634SPatrick Williams              "/sys/devices/platform/ahb/ahb:apb/ahb:apb:bus@1e78a000/1e78a340.i2c-bus/i2c-24/24-0012"}};
1065717de428SMatt Spinler 
1066717de428SMatt Spinler         AdditionalData ad{items};
1067717de428SMatt Spinler         SRC src{entry, ad, dataIface};
1068717de428SMatt Spinler 
1069717de428SMatt Spinler         EXPECT_FALSE(src.callouts());
1070717de428SMatt Spinler         ASSERT_EQ(src.getDebugData().size(), 1);
1071717de428SMatt Spinler         EXPECT_EQ(src.getDebugData()[0],
1072717de428SMatt Spinler                   "Problem looking up I2C callouts on 24 18: "
1073717de428SMatt Spinler                   "[json.exception.out_of_range.403] key '24' not found");
1074717de428SMatt Spinler     }
1075717de428SMatt Spinler 
1076717de428SMatt Spinler     {
1077717de428SMatt Spinler         // Callout not found
1078e5940634SPatrick Williams         std::map<std::string, std::string> items{{"CALLOUT_ERRNO", "5"},
1079e5940634SPatrick Williams                                                  {"CALLOUT_IIC_BUS", "22"},
1080e5940634SPatrick Williams                                                  {"CALLOUT_IIC_ADDR", "0x99"}};
1081717de428SMatt Spinler         AdditionalData ad{items};
1082717de428SMatt Spinler         SRC src{entry, ad, dataIface};
1083717de428SMatt Spinler 
1084717de428SMatt Spinler         EXPECT_FALSE(src.callouts());
1085717de428SMatt Spinler         ASSERT_EQ(src.getDebugData().size(), 1);
1086717de428SMatt Spinler         EXPECT_EQ(src.getDebugData()[0],
1087717de428SMatt Spinler                   "Problem looking up I2C callouts on 22 153: "
1088717de428SMatt Spinler                   "[json.exception.out_of_range.403] key '22' not found");
1089717de428SMatt Spinler     }
1090*7b92372dSMatt Spinler }
1091*7b92372dSMatt Spinler 
TEST_F(SRCTest,DevicePathCantGetLocTest)1092*7b92372dSMatt Spinler TEST_F(SRCTest, DevicePathCantGetLocTest)
1093*7b92372dSMatt Spinler {
1094*7b92372dSMatt Spinler     message::Entry entry;
1095*7b92372dSMatt Spinler     entry.src.type = 0xBD;
1096*7b92372dSMatt Spinler     entry.src.reasonCode = 0xABCD;
1097*7b92372dSMatt Spinler     entry.subsystem = 0x42;
1098*7b92372dSMatt Spinler 
1099*7b92372dSMatt Spinler     const auto calloutJSON = R"(
1100*7b92372dSMatt Spinler     {
1101*7b92372dSMatt Spinler         "I2C":
1102*7b92372dSMatt Spinler         {
1103*7b92372dSMatt Spinler             "14":
1104*7b92372dSMatt Spinler             {
1105*7b92372dSMatt Spinler                 "114":
1106*7b92372dSMatt Spinler                 {
1107*7b92372dSMatt Spinler                     "Callouts":[
1108*7b92372dSMatt Spinler                     {
1109*7b92372dSMatt Spinler                         "Name": "/chassis/motherboard/cpu0",
1110*7b92372dSMatt Spinler                         "LocationCode": "P1-C40",
1111*7b92372dSMatt Spinler                         "Priority": "H"
1112*7b92372dSMatt Spinler                     },
1113*7b92372dSMatt Spinler                     {
1114*7b92372dSMatt Spinler                         "Name": "/chassis/motherboard",
1115*7b92372dSMatt Spinler                         "LocationCode": "P1",
1116*7b92372dSMatt Spinler                         "Priority": "M"
1117*7b92372dSMatt Spinler                     }
1118*7b92372dSMatt Spinler                     ],
1119*7b92372dSMatt Spinler                     "Dest": "proc 0 target"
1120*7b92372dSMatt Spinler                 }
1121*7b92372dSMatt Spinler             }
1122*7b92372dSMatt Spinler         }
1123*7b92372dSMatt Spinler     })";
1124*7b92372dSMatt Spinler 
1125*7b92372dSMatt Spinler     auto dataPath = getPELReadOnlyDataPath();
1126*7b92372dSMatt Spinler     std::ofstream file{dataPath / "systemA_dev_callouts.json"};
1127*7b92372dSMatt Spinler     file << calloutJSON;
1128*7b92372dSMatt Spinler     file.close();
1129*7b92372dSMatt Spinler 
1130*7b92372dSMatt Spinler     NiceMock<MockDataInterface> dataIface;
1131*7b92372dSMatt Spinler     std::vector<std::string> names{"systemA"};
1132*7b92372dSMatt Spinler 
1133*7b92372dSMatt Spinler     EXPECT_CALL(dataIface, getSystemNames).WillRepeatedly(Return(names));
1134*7b92372dSMatt Spinler 
1135*7b92372dSMatt Spinler     // The calls to expand the location codes will fail, so still create
1136*7b92372dSMatt Spinler     // the callouts with the unexpanded values and no HW fields
1137*7b92372dSMatt Spinler 
1138*7b92372dSMatt Spinler     EXPECT_CALL(dataIface, expandLocationCode("P1-C40", 0))
1139*7b92372dSMatt Spinler         .WillRepeatedly(Throw(std::runtime_error("Fail")));
1140*7b92372dSMatt Spinler 
1141*7b92372dSMatt Spinler     EXPECT_CALL(dataIface, expandLocationCode("P1", 0))
1142*7b92372dSMatt Spinler         .WillRepeatedly(Throw(std::runtime_error("Fail")));
1143*7b92372dSMatt Spinler 
1144*7b92372dSMatt Spinler     EXPECT_CALL(dataIface, getInventoryFromLocCode("P1-C40", 0, false))
1145*7b92372dSMatt Spinler         .Times(0);
1146*7b92372dSMatt Spinler     EXPECT_CALL(dataIface, getInventoryFromLocCode("P1", 0, false)).Times(0);
1147*7b92372dSMatt Spinler 
1148*7b92372dSMatt Spinler     std::map<std::string, std::string> items{
1149*7b92372dSMatt Spinler         {"CALLOUT_ERRNO", "5"},
1150*7b92372dSMatt Spinler         {"CALLOUT_DEVICE_PATH",
1151*7b92372dSMatt Spinler          "/sys/devices/platform/ahb/ahb:apb/ahb:apb:bus@1e78a000/1e78a340.i2c-bus/i2c-14/14-0072"}};
1152*7b92372dSMatt Spinler 
1153*7b92372dSMatt Spinler     AdditionalData ad{items};
1154*7b92372dSMatt Spinler     SRC src{entry, ad, dataIface};
1155*7b92372dSMatt Spinler 
1156*7b92372dSMatt Spinler     ASSERT_TRUE(src.callouts());
1157*7b92372dSMatt Spinler     auto& callouts = src.callouts()->callouts();
1158*7b92372dSMatt Spinler 
1159*7b92372dSMatt Spinler     ASSERT_EQ(callouts.size(), 2);
1160*7b92372dSMatt Spinler 
1161*7b92372dSMatt Spinler     // Should just contain the unexpanded location codes
1162*7b92372dSMatt Spinler     {
1163*7b92372dSMatt Spinler         EXPECT_EQ(callouts[0]->priority(), 'H');
1164*7b92372dSMatt Spinler         EXPECT_EQ(callouts[0]->locationCode(), "P1-C40");
1165*7b92372dSMatt Spinler 
1166*7b92372dSMatt Spinler         auto& fru = callouts[0]->fruIdentity();
1167*7b92372dSMatt Spinler         EXPECT_EQ(fru->getPN().value(), "");
1168*7b92372dSMatt Spinler         EXPECT_EQ(fru->getCCIN().value(), "");
1169*7b92372dSMatt Spinler         EXPECT_EQ(fru->getSN().value(), "");
1170*7b92372dSMatt Spinler     }
1171*7b92372dSMatt Spinler     {
1172*7b92372dSMatt Spinler         EXPECT_EQ(callouts[1]->priority(), 'M');
1173*7b92372dSMatt Spinler         EXPECT_EQ(callouts[1]->locationCode(), "P1");
1174*7b92372dSMatt Spinler 
1175*7b92372dSMatt Spinler         auto& fru = callouts[1]->fruIdentity();
1176*7b92372dSMatt Spinler         EXPECT_EQ(fru->getPN().value(), "");
1177*7b92372dSMatt Spinler         EXPECT_EQ(fru->getCCIN().value(), "");
1178*7b92372dSMatt Spinler         EXPECT_EQ(fru->getSN().value(), "");
1179*7b92372dSMatt Spinler     }
1180717de428SMatt Spinler 
1181717de428SMatt Spinler     fs::remove_all(dataPath);
1182717de428SMatt Spinler }
11833bdd0110SMatt Spinler 
11843bdd0110SMatt Spinler // Test when callouts are passed in via JSON
TEST_F(SRCTest,JsonCalloutsTest)11853bdd0110SMatt Spinler TEST_F(SRCTest, JsonCalloutsTest)
11863bdd0110SMatt Spinler {
11873bdd0110SMatt Spinler     const auto jsonCallouts = R"(
11883bdd0110SMatt Spinler         [
11893bdd0110SMatt Spinler             {
11903bdd0110SMatt Spinler                 "LocationCode": "P0-C1",
11913bdd0110SMatt Spinler                 "Priority": "H",
11923bdd0110SMatt Spinler                 "MRUs": [
11933bdd0110SMatt Spinler                     {
11943bdd0110SMatt Spinler                         "ID": 42,
11953bdd0110SMatt Spinler                         "Priority": "H"
11963bdd0110SMatt Spinler                     },
11973bdd0110SMatt Spinler                     {
11983bdd0110SMatt Spinler                         "ID": 43,
11993bdd0110SMatt Spinler                         "Priority": "M"
12003bdd0110SMatt Spinler                     }
12013bdd0110SMatt Spinler                 ]
12023bdd0110SMatt Spinler             },
12033bdd0110SMatt Spinler             {
12043bdd0110SMatt Spinler                 "InventoryPath": "/inv/system/chassis/motherboard/cpu0",
12053bdd0110SMatt Spinler                 "Priority": "M",
12063bdd0110SMatt Spinler                 "Guarded": true,
12073bdd0110SMatt Spinler                 "Deconfigured": true
12083bdd0110SMatt Spinler             },
12093bdd0110SMatt Spinler             {
12103bdd0110SMatt Spinler                 "Procedure": "PROCEDU",
12113bdd0110SMatt Spinler                 "Priority": "A"
12123bdd0110SMatt Spinler             },
12133bdd0110SMatt Spinler             {
12143bdd0110SMatt Spinler                 "SymbolicFRU": "TRUSTED",
12153bdd0110SMatt Spinler                 "Priority": "B",
12163bdd0110SMatt Spinler                 "TrustedLocationCode": true,
12173bdd0110SMatt Spinler                 "LocationCode": "P1-C23"
12183bdd0110SMatt Spinler             },
12193bdd0110SMatt Spinler             {
12203bdd0110SMatt Spinler                 "SymbolicFRU": "FRUTST1",
12213bdd0110SMatt Spinler                 "Priority": "C",
12223bdd0110SMatt Spinler                 "LocationCode": "P1-C24"
12233bdd0110SMatt Spinler             },
12243bdd0110SMatt Spinler             {
12253bdd0110SMatt Spinler                 "SymbolicFRU": "FRUTST2LONG",
12263bdd0110SMatt Spinler                 "Priority": "L"
12273c7ec6d8SMatt Spinler             },
12283c7ec6d8SMatt Spinler             {
12293c7ec6d8SMatt Spinler                 "Procedure": "fsi_path",
12303c7ec6d8SMatt Spinler                 "Priority": "L"
12313c7ec6d8SMatt Spinler             },
12323c7ec6d8SMatt Spinler             {
12333c7ec6d8SMatt Spinler                 "SymbolicFRU": "ambient_temp",
12343c7ec6d8SMatt Spinler                 "Priority": "L"
12353bdd0110SMatt Spinler             }
12363bdd0110SMatt Spinler         ]
12373bdd0110SMatt Spinler     )"_json;
12383bdd0110SMatt Spinler 
12393bdd0110SMatt Spinler     message::Entry entry;
12403bdd0110SMatt Spinler     entry.src.type = 0xBD;
12413bdd0110SMatt Spinler     entry.src.reasonCode = 0xABCD;
12423bdd0110SMatt Spinler     entry.subsystem = 0x42;
12433bdd0110SMatt Spinler 
12443bdd0110SMatt Spinler     AdditionalData ad;
12453bdd0110SMatt Spinler     NiceMock<MockDataInterface> dataIface;
12463bdd0110SMatt Spinler 
12473bdd0110SMatt Spinler     // Callout 0 mock calls
12483bdd0110SMatt Spinler     {
12493bdd0110SMatt Spinler         EXPECT_CALL(dataIface, expandLocationCode("P0-C1", 0))
12503bdd0110SMatt Spinler             .Times(1)
12513bdd0110SMatt Spinler             .WillOnce(Return("UXXX-P0-C1"));
12523bdd0110SMatt Spinler         EXPECT_CALL(dataIface, getInventoryFromLocCode("P0-C1", 0, false))
12533bdd0110SMatt Spinler             .Times(1)
1254bad056beSMatt Spinler             .WillOnce(Return(std::vector<std::string>{
1255bad056beSMatt Spinler                 "/inv/system/chassis/motherboard/bmc"}));
12563bdd0110SMatt Spinler         EXPECT_CALL(
12573bdd0110SMatt Spinler             dataIface,
12583bdd0110SMatt Spinler             getHWCalloutFields("/inv/system/chassis/motherboard/bmc", _, _, _))
12593bdd0110SMatt Spinler             .Times(1)
1260075c7923SPatrick Williams             .WillOnce(
1261075c7923SPatrick Williams                 DoAll(SetArgReferee<1>("1234567"), SetArgReferee<2>("CCCC"),
12623bdd0110SMatt Spinler                       SetArgReferee<3>("123456789ABC")));
12633bdd0110SMatt Spinler     }
12643bdd0110SMatt Spinler     // Callout 1 mock calls
12653bdd0110SMatt Spinler     {
12663bdd0110SMatt Spinler         EXPECT_CALL(dataIface,
12673bdd0110SMatt Spinler                     getLocationCode("/inv/system/chassis/motherboard/cpu0"))
12683bdd0110SMatt Spinler             .WillOnce(Return("UYYY-P5"));
12693bdd0110SMatt Spinler         EXPECT_CALL(
12703bdd0110SMatt Spinler             dataIface,
12713bdd0110SMatt Spinler             getHWCalloutFields("/inv/system/chassis/motherboard/cpu0", _, _, _))
12723bdd0110SMatt Spinler             .Times(1)
1273075c7923SPatrick Williams             .WillOnce(
1274075c7923SPatrick Williams                 DoAll(SetArgReferee<1>("2345678"), SetArgReferee<2>("DDDD"),
12753bdd0110SMatt Spinler                       SetArgReferee<3>("23456789ABCD")));
12763bdd0110SMatt Spinler     }
12773bdd0110SMatt Spinler     // Callout 3 mock calls
12783bdd0110SMatt Spinler     {
12793bdd0110SMatt Spinler         EXPECT_CALL(dataIface, expandLocationCode("P1-C23", 0))
12803bdd0110SMatt Spinler             .Times(1)
12813bdd0110SMatt Spinler             .WillOnce(Return("UXXX-P1-C23"));
12823bdd0110SMatt Spinler     }
12833bdd0110SMatt Spinler     // Callout 4 mock calls
12843bdd0110SMatt Spinler     {
12853bdd0110SMatt Spinler         EXPECT_CALL(dataIface, expandLocationCode("P1-C24", 0))
12863bdd0110SMatt Spinler             .Times(1)
12873bdd0110SMatt Spinler             .WillOnce(Return("UXXX-P1-C24"));
12883bdd0110SMatt Spinler     }
12893bdd0110SMatt Spinler 
12903bdd0110SMatt Spinler     SRC src{entry, ad, jsonCallouts, dataIface};
12913bdd0110SMatt Spinler     ASSERT_TRUE(src.callouts());
12923bdd0110SMatt Spinler 
1293afa2c799SMatt Spinler     // Check the guarded and deconfigured flags
1294afa2c799SMatt Spinler     EXPECT_TRUE(src.hexwordData()[3] & 0x03000000);
1295afa2c799SMatt Spinler 
12963bdd0110SMatt Spinler     const auto& callouts = src.callouts()->callouts();
12973c7ec6d8SMatt Spinler     ASSERT_EQ(callouts.size(), 8);
12983bdd0110SMatt Spinler 
12993bdd0110SMatt Spinler     // Check callout 0
13003bdd0110SMatt Spinler     {
13013bdd0110SMatt Spinler         EXPECT_EQ(callouts[0]->priority(), 'H');
13023bdd0110SMatt Spinler         EXPECT_EQ(callouts[0]->locationCode(), "UXXX-P0-C1");
13033bdd0110SMatt Spinler 
13043bdd0110SMatt Spinler         auto& fru = callouts[0]->fruIdentity();
13053bdd0110SMatt Spinler         EXPECT_EQ(fru->getPN().value(), "1234567");
13063bdd0110SMatt Spinler         EXPECT_EQ(fru->getCCIN().value(), "CCCC");
13073bdd0110SMatt Spinler         EXPECT_EQ(fru->getSN().value(), "123456789ABC");
13083bdd0110SMatt Spinler         EXPECT_EQ(fru->failingComponentType(), src::FRUIdentity::hardwareFRU);
1309b8cb60feSMatt Spinler 
1310b8cb60feSMatt Spinler         auto& mruCallouts = callouts[0]->mru();
1311b8cb60feSMatt Spinler         ASSERT_TRUE(mruCallouts);
1312b8cb60feSMatt Spinler         auto& mrus = mruCallouts->mrus();
1313b8cb60feSMatt Spinler         ASSERT_EQ(mrus.size(), 2);
1314b8cb60feSMatt Spinler         EXPECT_EQ(mrus[0].id, 42);
1315b8cb60feSMatt Spinler         EXPECT_EQ(mrus[0].priority, 'H');
1316b8cb60feSMatt Spinler         EXPECT_EQ(mrus[1].id, 43);
1317b8cb60feSMatt Spinler         EXPECT_EQ(mrus[1].priority, 'M');
13183bdd0110SMatt Spinler     }
13193bdd0110SMatt Spinler 
13203bdd0110SMatt Spinler     // Check callout 1
13213bdd0110SMatt Spinler     {
13223bdd0110SMatt Spinler         EXPECT_EQ(callouts[1]->priority(), 'M');
13233bdd0110SMatt Spinler         EXPECT_EQ(callouts[1]->locationCode(), "UYYY-P5");
13243bdd0110SMatt Spinler 
13253bdd0110SMatt Spinler         auto& fru = callouts[1]->fruIdentity();
13263bdd0110SMatt Spinler         EXPECT_EQ(fru->getPN().value(), "2345678");
13273bdd0110SMatt Spinler         EXPECT_EQ(fru->getCCIN().value(), "DDDD");
13283bdd0110SMatt Spinler         EXPECT_EQ(fru->getSN().value(), "23456789ABCD");
13293bdd0110SMatt Spinler         EXPECT_EQ(fru->failingComponentType(), src::FRUIdentity::hardwareFRU);
13303bdd0110SMatt Spinler     }
13313bdd0110SMatt Spinler 
13323bdd0110SMatt Spinler     // Check callout 2
13333bdd0110SMatt Spinler     {
13343bdd0110SMatt Spinler         EXPECT_EQ(callouts[2]->priority(), 'A');
13353bdd0110SMatt Spinler         EXPECT_EQ(callouts[2]->locationCode(), "");
13363bdd0110SMatt Spinler 
13373bdd0110SMatt Spinler         auto& fru = callouts[2]->fruIdentity();
13383bdd0110SMatt Spinler         EXPECT_EQ(fru->getMaintProc().value(), "PROCEDU");
13393bdd0110SMatt Spinler         EXPECT_EQ(fru->failingComponentType(),
13403bdd0110SMatt Spinler                   src::FRUIdentity::maintenanceProc);
13413bdd0110SMatt Spinler     }
13423bdd0110SMatt Spinler 
13433bdd0110SMatt Spinler     // Check callout 3
13443bdd0110SMatt Spinler     {
13453bdd0110SMatt Spinler         EXPECT_EQ(callouts[3]->priority(), 'B');
13463bdd0110SMatt Spinler         EXPECT_EQ(callouts[3]->locationCode(), "UXXX-P1-C23");
13473bdd0110SMatt Spinler 
13483bdd0110SMatt Spinler         auto& fru = callouts[3]->fruIdentity();
13493bdd0110SMatt Spinler         EXPECT_EQ(fru->getPN().value(), "TRUSTED");
13503bdd0110SMatt Spinler         EXPECT_EQ(fru->failingComponentType(),
13513bdd0110SMatt Spinler                   src::FRUIdentity::symbolicFRUTrustedLocCode);
13523bdd0110SMatt Spinler     }
13533bdd0110SMatt Spinler 
13543bdd0110SMatt Spinler     // Check callout 4
13553bdd0110SMatt Spinler     {
13563bdd0110SMatt Spinler         EXPECT_EQ(callouts[4]->priority(), 'C');
13573bdd0110SMatt Spinler         EXPECT_EQ(callouts[4]->locationCode(), "UXXX-P1-C24");
13583bdd0110SMatt Spinler 
13593bdd0110SMatt Spinler         auto& fru = callouts[4]->fruIdentity();
13603bdd0110SMatt Spinler         EXPECT_EQ(fru->getPN().value(), "FRUTST1");
13613bdd0110SMatt Spinler         EXPECT_EQ(fru->failingComponentType(), src::FRUIdentity::symbolicFRU);
13623bdd0110SMatt Spinler     }
13633bdd0110SMatt Spinler 
13643bdd0110SMatt Spinler     // Check callout 5
13653bdd0110SMatt Spinler     {
13663bdd0110SMatt Spinler         EXPECT_EQ(callouts[5]->priority(), 'L');
13673bdd0110SMatt Spinler         EXPECT_EQ(callouts[5]->locationCode(), "");
13683bdd0110SMatt Spinler 
13693bdd0110SMatt Spinler         auto& fru = callouts[5]->fruIdentity();
13703bdd0110SMatt Spinler         EXPECT_EQ(fru->getPN().value(), "FRUTST2");
13713bdd0110SMatt Spinler         EXPECT_EQ(fru->failingComponentType(), src::FRUIdentity::symbolicFRU);
13723bdd0110SMatt Spinler     }
13733bdd0110SMatt Spinler 
13743c7ec6d8SMatt Spinler     // Check callout 6
13753c7ec6d8SMatt Spinler     {
13763c7ec6d8SMatt Spinler         EXPECT_EQ(callouts[6]->priority(), 'L');
13773c7ec6d8SMatt Spinler         EXPECT_EQ(callouts[6]->locationCode(), "");
13783c7ec6d8SMatt Spinler 
13793c7ec6d8SMatt Spinler         auto& fru = callouts[6]->fruIdentity();
13803c7ec6d8SMatt Spinler         EXPECT_EQ(fru->getMaintProc().value(), "BMC0004");
13813c7ec6d8SMatt Spinler         EXPECT_EQ(fru->failingComponentType(),
13823c7ec6d8SMatt Spinler                   src::FRUIdentity::maintenanceProc);
13833c7ec6d8SMatt Spinler     }
13843c7ec6d8SMatt Spinler 
13853c7ec6d8SMatt Spinler     // Check callout 7
13863c7ec6d8SMatt Spinler     {
13873c7ec6d8SMatt Spinler         EXPECT_EQ(callouts[7]->priority(), 'L');
13883c7ec6d8SMatt Spinler         EXPECT_EQ(callouts[7]->locationCode(), "");
13893c7ec6d8SMatt Spinler 
13903c7ec6d8SMatt Spinler         auto& fru = callouts[7]->fruIdentity();
13913c7ec6d8SMatt Spinler         EXPECT_EQ(fru->getPN().value(), "AMBTEMP");
13923c7ec6d8SMatt Spinler         EXPECT_EQ(fru->failingComponentType(), src::FRUIdentity::symbolicFRU);
13933c7ec6d8SMatt Spinler     }
13943c7ec6d8SMatt Spinler 
13953bdd0110SMatt Spinler     // Check that it didn't find any errors
13963bdd0110SMatt Spinler     const auto& data = src.getDebugData();
13973bdd0110SMatt Spinler     EXPECT_TRUE(data.empty());
13983bdd0110SMatt Spinler }
13993bdd0110SMatt Spinler 
TEST_F(SRCTest,JsonBadCalloutsTest)14003bdd0110SMatt Spinler TEST_F(SRCTest, JsonBadCalloutsTest)
14013bdd0110SMatt Spinler {
14023bdd0110SMatt Spinler     // The first call will have a Throw in a mock call.
14033bdd0110SMatt Spinler     // The second will have a different Throw in a mock call.
14043bdd0110SMatt Spinler     // The others have issues with the Priority field.
14053bdd0110SMatt Spinler     const auto jsonCallouts = R"(
14063bdd0110SMatt Spinler         [
14073bdd0110SMatt Spinler             {
14083bdd0110SMatt Spinler                 "LocationCode": "P0-C1",
14093bdd0110SMatt Spinler                 "Priority": "H"
14103bdd0110SMatt Spinler             },
14113bdd0110SMatt Spinler             {
14123bdd0110SMatt Spinler                 "LocationCode": "P0-C2",
14133bdd0110SMatt Spinler                 "Priority": "H"
14143bdd0110SMatt Spinler             },
14153bdd0110SMatt Spinler             {
14163bdd0110SMatt Spinler                 "LocationCode": "P0-C3"
14173bdd0110SMatt Spinler             },
14183bdd0110SMatt Spinler             {
14193bdd0110SMatt Spinler                 "LocationCode": "P0-C4",
14203bdd0110SMatt Spinler                 "Priority": "X"
14213bdd0110SMatt Spinler             }
14223bdd0110SMatt Spinler         ]
14233bdd0110SMatt Spinler     )"_json;
14243bdd0110SMatt Spinler 
14253bdd0110SMatt Spinler     message::Entry entry;
14263bdd0110SMatt Spinler     entry.src.type = 0xBD;
14273bdd0110SMatt Spinler     entry.src.reasonCode = 0xABCD;
14283bdd0110SMatt Spinler     entry.subsystem = 0x42;
14293bdd0110SMatt Spinler 
14303bdd0110SMatt Spinler     AdditionalData ad;
14313bdd0110SMatt Spinler     NiceMock<MockDataInterface> dataIface;
14323bdd0110SMatt Spinler 
14333bdd0110SMatt Spinler     // Callout 0 mock calls
14343bdd0110SMatt Spinler     // Expand location code will fail, so the unexpanded location
14353bdd0110SMatt Spinler     // code should show up in the callout instead.
14363bdd0110SMatt Spinler     {
14373bdd0110SMatt Spinler         EXPECT_CALL(dataIface, expandLocationCode("P0-C1", 0))
14383bdd0110SMatt Spinler             .WillOnce(Throw(std::runtime_error("Fail")));
14393bdd0110SMatt Spinler 
14403bdd0110SMatt Spinler         EXPECT_CALL(dataIface, getInventoryFromLocCode("P0-C1", 0, false))
14413bdd0110SMatt Spinler             .Times(1)
1442bad056beSMatt Spinler             .WillOnce(Return(std::vector<std::string>{
1443bad056beSMatt Spinler                 "/inv/system/chassis/motherboard/bmc"}));
14443bdd0110SMatt Spinler         EXPECT_CALL(
14453bdd0110SMatt Spinler             dataIface,
14463bdd0110SMatt Spinler             getHWCalloutFields("/inv/system/chassis/motherboard/bmc", _, _, _))
14473bdd0110SMatt Spinler             .Times(1)
1448075c7923SPatrick Williams             .WillOnce(
1449075c7923SPatrick Williams                 DoAll(SetArgReferee<1>("1234567"), SetArgReferee<2>("CCCC"),
14503bdd0110SMatt Spinler                       SetArgReferee<3>("123456789ABC")));
14513bdd0110SMatt Spinler     }
14523bdd0110SMatt Spinler 
14533bdd0110SMatt Spinler     // Callout 1 mock calls
1454*7b92372dSMatt Spinler     // getInventoryFromLocCode will fail, so a callout with just the
1455*7b92372dSMatt Spinler     // location code will be created.
14563bdd0110SMatt Spinler     {
14573bdd0110SMatt Spinler         EXPECT_CALL(dataIface, expandLocationCode("P0-C2", 0))
14583bdd0110SMatt Spinler             .Times(1)
14593bdd0110SMatt Spinler             .WillOnce(Return("UXXX-P0-C2"));
14603bdd0110SMatt Spinler 
14613bdd0110SMatt Spinler         EXPECT_CALL(dataIface, getInventoryFromLocCode("P0-C2", 0, false))
14623bdd0110SMatt Spinler             .Times(1)
14633bdd0110SMatt Spinler             .WillOnce(Throw(std::runtime_error("Fail")));
14643bdd0110SMatt Spinler     }
14653bdd0110SMatt Spinler 
14663bdd0110SMatt Spinler     SRC src{entry, ad, jsonCallouts, dataIface};
14673bdd0110SMatt Spinler 
14683bdd0110SMatt Spinler     ASSERT_TRUE(src.callouts());
14693bdd0110SMatt Spinler 
14703bdd0110SMatt Spinler     const auto& callouts = src.callouts()->callouts();
14713bdd0110SMatt Spinler 
1472*7b92372dSMatt Spinler     // The first callout will have the unexpanded location code.
1473*7b92372dSMatt Spinler     ASSERT_EQ(callouts.size(), 2);
14743bdd0110SMatt Spinler 
14753bdd0110SMatt Spinler     EXPECT_EQ(callouts[0]->priority(), 'H');
14763bdd0110SMatt Spinler     EXPECT_EQ(callouts[0]->locationCode(), "P0-C1");
14773bdd0110SMatt Spinler 
1478*7b92372dSMatt Spinler     auto& fru0 = callouts[0]->fruIdentity();
1479*7b92372dSMatt Spinler     EXPECT_EQ(fru0->getPN().value(), "1234567");
1480*7b92372dSMatt Spinler     EXPECT_EQ(fru0->getCCIN().value(), "CCCC");
1481*7b92372dSMatt Spinler     EXPECT_EQ(fru0->getSN().value(), "123456789ABC");
1482*7b92372dSMatt Spinler     EXPECT_EQ(fru0->failingComponentType(), src::FRUIdentity::hardwareFRU);
1483*7b92372dSMatt Spinler 
1484*7b92372dSMatt Spinler     // The second callout will have empty HW details.
1485*7b92372dSMatt Spinler     EXPECT_EQ(callouts[1]->priority(), 'H');
1486*7b92372dSMatt Spinler     EXPECT_EQ(callouts[1]->locationCode(), "UXXX-P0-C2");
1487*7b92372dSMatt Spinler 
1488*7b92372dSMatt Spinler     auto& fru1 = callouts[1]->fruIdentity();
1489*7b92372dSMatt Spinler     EXPECT_EQ(fru1->getPN().value(), "");
1490*7b92372dSMatt Spinler     EXPECT_EQ(fru1->getCCIN().value(), "");
1491*7b92372dSMatt Spinler     EXPECT_EQ(fru1->getSN().value(), "");
1492*7b92372dSMatt Spinler     EXPECT_EQ(fru1->failingComponentType(), src::FRUIdentity::hardwareFRU);
14933bdd0110SMatt Spinler 
14943bdd0110SMatt Spinler     const auto& data = src.getDebugData();
14953bdd0110SMatt Spinler     ASSERT_EQ(data.size(), 4);
14963bdd0110SMatt Spinler     EXPECT_STREQ(data[0].c_str(), "Unable to expand location code P0-C1: Fail");
1497*7b92372dSMatt Spinler     EXPECT_STREQ(
1498*7b92372dSMatt Spinler         data[1].c_str(),
1499*7b92372dSMatt Spinler         "Unable to get inventory path from location code: P0-C2: Fail");
15003bdd0110SMatt Spinler     EXPECT_STREQ(data[2].c_str(),
15013bdd0110SMatt Spinler                  "Failed extracting callout data from JSON: "
15023bdd0110SMatt Spinler                  "[json.exception.out_of_range.403] key 'Priority' not found");
15033bdd0110SMatt Spinler     EXPECT_STREQ(data[3].c_str(),
15043bdd0110SMatt Spinler                  "Failed extracting callout data from JSON: Invalid "
15053bdd0110SMatt Spinler                  "priority 'X' found in JSON callout");
15063bdd0110SMatt Spinler }
150753ef1552SMiguel Gomez 
150853ef1552SMiguel Gomez // Test that an inventory path callout can have
150953ef1552SMiguel Gomez // a different priority than H.
TEST_F(SRCTest,InventoryCalloutTestPriority)151053ef1552SMiguel Gomez TEST_F(SRCTest, InventoryCalloutTestPriority)
151153ef1552SMiguel Gomez {
151253ef1552SMiguel Gomez     message::Entry entry;
151353ef1552SMiguel Gomez     entry.src.type = 0xBD;
151453ef1552SMiguel Gomez     entry.src.reasonCode = 0xABCD;
151553ef1552SMiguel Gomez     entry.subsystem = 0x42;
151653ef1552SMiguel Gomez 
1517e5940634SPatrick Williams     std::map<std::string, std::string> adData{
1518e5940634SPatrick Williams         {"CALLOUT_INVENTORY_PATH", "motherboard"}, {"CALLOUT_PRIORITY", "M"}};
151953ef1552SMiguel Gomez     AdditionalData ad{adData};
152053ef1552SMiguel Gomez     NiceMock<MockDataInterface> dataIface;
152153ef1552SMiguel Gomez 
152253ef1552SMiguel Gomez     EXPECT_CALL(dataIface, getLocationCode("motherboard"))
152353ef1552SMiguel Gomez         .WillOnce(Return("UTMS-P1"));
152453ef1552SMiguel Gomez 
152553ef1552SMiguel Gomez     EXPECT_CALL(dataIface, getHWCalloutFields("motherboard", _, _, _))
152653ef1552SMiguel Gomez         .Times(1)
152753ef1552SMiguel Gomez         .WillOnce(DoAll(SetArgReferee<1>("1234567"), SetArgReferee<2>("CCCC"),
152853ef1552SMiguel Gomez                         SetArgReferee<3>("123456789ABC")));
152953ef1552SMiguel Gomez 
153053ef1552SMiguel Gomez     SRC src{entry, ad, dataIface};
153153ef1552SMiguel Gomez     EXPECT_TRUE(src.valid());
153253ef1552SMiguel Gomez 
153353ef1552SMiguel Gomez     ASSERT_TRUE(src.callouts());
153453ef1552SMiguel Gomez 
153553ef1552SMiguel Gomez     EXPECT_EQ(src.callouts()->callouts().size(), 1);
153653ef1552SMiguel Gomez 
153753ef1552SMiguel Gomez     auto& callout = src.callouts()->callouts().front();
153853ef1552SMiguel Gomez 
153953ef1552SMiguel Gomez     EXPECT_EQ(callout->locationCode(), "UTMS-P1");
154053ef1552SMiguel Gomez     EXPECT_EQ(callout->priority(), 'M');
154153ef1552SMiguel Gomez }
15429d43a727SSumit Kumar 
154350bfa69aSSumit Kumar // Test SRC with additional data - PEL_SUBSYSTEM
TEST_F(SRCTest,TestPELSubsystem)154450bfa69aSSumit Kumar TEST_F(SRCTest, TestPELSubsystem)
154550bfa69aSSumit Kumar {
154650bfa69aSSumit Kumar     message::Entry entry;
154750bfa69aSSumit Kumar     entry.src.type = 0xBD;
154850bfa69aSSumit Kumar     entry.src.reasonCode = 0xABCD;
154950bfa69aSSumit Kumar     entry.subsystem = 0x42;
155050bfa69aSSumit Kumar 
155150bfa69aSSumit Kumar     // Values for the SRC words pointed to above
1552e5940634SPatrick Williams     std::map<std::string, std::string> adData{{"PEL_SUBSYSTEM", "0x20"}};
155350bfa69aSSumit Kumar     AdditionalData ad{adData};
155450bfa69aSSumit Kumar     NiceMock<MockDataInterface> dataIface;
155550bfa69aSSumit Kumar 
155650bfa69aSSumit Kumar     EXPECT_CALL(dataIface, getMotherboardCCIN).WillOnce(Return("ABCD"));
155750bfa69aSSumit Kumar 
155850bfa69aSSumit Kumar     SRC src{entry, ad, dataIface};
155950bfa69aSSumit Kumar 
156050bfa69aSSumit Kumar     EXPECT_TRUE(src.valid());
156150bfa69aSSumit Kumar 
156250bfa69aSSumit Kumar     EXPECT_EQ(src.asciiString(), "BD20ABCD                        ");
156350bfa69aSSumit Kumar }
1564875b6c7bSVijay Lobo 
setAsciiString(std::vector<uint8_t> & src,const std::string & value)1565875b6c7bSVijay Lobo void setAsciiString(std::vector<uint8_t>& src, const std::string& value)
1566875b6c7bSVijay Lobo {
1567875b6c7bSVijay Lobo     assert(40 + value.size() <= src.size());
1568875b6c7bSVijay Lobo 
1569875b6c7bSVijay Lobo     for (size_t i = 0; i < value.size(); i++)
1570875b6c7bSVijay Lobo     {
1571875b6c7bSVijay Lobo         src[40 + i] = value[i];
1572875b6c7bSVijay Lobo     }
1573875b6c7bSVijay Lobo }
1574875b6c7bSVijay Lobo 
TEST_F(SRCTest,TestGetProgressCode)1575875b6c7bSVijay Lobo TEST_F(SRCTest, TestGetProgressCode)
1576875b6c7bSVijay Lobo {
1577875b6c7bSVijay Lobo     {
1578875b6c7bSVijay Lobo         // A real SRC with CC009184
1579875b6c7bSVijay Lobo         std::vector<uint8_t> src{
1580875b6c7bSVijay Lobo             2,  8,   0,  9,   0,   0,  0,  72, 0,  0,  0,  224, 0,  0,  0,
1581875b6c7bSVijay Lobo             0,  204, 0,  145, 132, 0,  0,  0,  0,  0,  0,  0,   0,  0,  0,
1582875b6c7bSVijay Lobo             0,  0,   0,  0,   0,   0,  0,  0,  0,  0,  67, 67,  48, 48, 57,
1583875b6c7bSVijay Lobo             49, 56,  52, 32,  32,  32, 32, 32, 32, 32, 32, 32,  32, 32, 32,
1584875b6c7bSVijay Lobo             32, 32,  32, 32,  32,  32, 32, 32, 32, 32, 32, 32};
1585875b6c7bSVijay Lobo 
1586875b6c7bSVijay Lobo         EXPECT_EQ(SRC::getProgressCode(src), 0xCC009184);
1587875b6c7bSVijay Lobo     }
1588875b6c7bSVijay Lobo 
1589875b6c7bSVijay Lobo     {
1590875b6c7bSVijay Lobo         // A real SRC with STANDBY
1591875b6c7bSVijay Lobo         std::vector<uint8_t> src{
1592875b6c7bSVijay Lobo             2,  0,  0,  1,  0,  0,  0,  72, 0,  0,  0,  0,  0,  0,  0,
1593875b6c7bSVijay Lobo             0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
1594875b6c7bSVijay Lobo             0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  83, 84, 65, 78, 68,
1595875b6c7bSVijay Lobo             66, 89, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1596875b6c7bSVijay Lobo             32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32};
1597875b6c7bSVijay Lobo 
1598875b6c7bSVijay Lobo         EXPECT_EQ(SRC::getProgressCode(src), 0);
1599875b6c7bSVijay Lobo     }
1600875b6c7bSVijay Lobo 
1601875b6c7bSVijay Lobo     {
1602875b6c7bSVijay Lobo         // A real SRC with CC009184, but 1 byte too short
1603875b6c7bSVijay Lobo         std::vector<uint8_t> src{
1604875b6c7bSVijay Lobo             2,  8,   0,  9,   0,   0,  0,  72, 0,  0,  0,  224, 0,  0,  0,
1605875b6c7bSVijay Lobo             0,  204, 0,  145, 132, 0,  0,  0,  0,  0,  0,  0,   0,  0,  0,
1606875b6c7bSVijay Lobo             0,  0,   0,  0,   0,   0,  0,  0,  0,  0,  67, 67,  48, 48, 57,
1607875b6c7bSVijay Lobo             49, 56,  52, 32,  32,  32, 32, 32, 32, 32, 32, 32,  32, 32, 32,
1608875b6c7bSVijay Lobo             32, 32,  32, 32,  32,  32, 32, 32, 32, 32, 32, 32};
1609875b6c7bSVijay Lobo         src.resize(71);
1610875b6c7bSVijay Lobo         EXPECT_EQ(SRC::getProgressCode(src), 0);
1611875b6c7bSVijay Lobo     }
1612875b6c7bSVijay Lobo 
1613875b6c7bSVijay Lobo     {
1614875b6c7bSVijay Lobo         // A few different ones
1615875b6c7bSVijay Lobo         const std::map<std::string, uint32_t> progressCodes{
1616875b6c7bSVijay Lobo             {"12345678", 0x12345678}, {"ABCDEF00", 0xABCDEF00},
1617875b6c7bSVijay Lobo             {"abcdef00", 0xABCDEF00}, {"X1234567", 0},
1618875b6c7bSVijay Lobo             {"1234567X", 0},          {"1       ", 0}};
1619875b6c7bSVijay Lobo 
1620875b6c7bSVijay Lobo         std::vector<uint8_t> src(72, 0x0);
1621875b6c7bSVijay Lobo 
1622875b6c7bSVijay Lobo         for (const auto& [code, expected] : progressCodes)
1623875b6c7bSVijay Lobo         {
1624875b6c7bSVijay Lobo             setAsciiString(src, code);
1625875b6c7bSVijay Lobo             EXPECT_EQ(SRC::getProgressCode(src), expected);
1626875b6c7bSVijay Lobo         }
1627875b6c7bSVijay Lobo 
1628875b6c7bSVijay Lobo         // empty
1629875b6c7bSVijay Lobo         src.clear();
1630875b6c7bSVijay Lobo         EXPECT_EQ(SRC::getProgressCode(src), 0);
1631875b6c7bSVijay Lobo     }
1632875b6c7bSVijay Lobo }
1633875b6c7bSVijay Lobo 
1634875b6c7bSVijay Lobo // Test progress is in right SRC hex data field
TEST_F(SRCTest,TestProgressCodeField)1635875b6c7bSVijay Lobo TEST_F(SRCTest, TestProgressCodeField)
1636875b6c7bSVijay Lobo {
1637875b6c7bSVijay Lobo     message::Entry entry;
1638875b6c7bSVijay Lobo     entry.src.type = 0xBD;
1639875b6c7bSVijay Lobo     entry.src.reasonCode = 0xABCD;
1640875b6c7bSVijay Lobo     entry.subsystem = 0x42;
1641875b6c7bSVijay Lobo 
1642875b6c7bSVijay Lobo     AdditionalData ad;
1643875b6c7bSVijay Lobo     NiceMock<MockDataInterface> dataIface;
1644875b6c7bSVijay Lobo     EXPECT_CALL(dataIface, getRawProgressSRC())
1645875b6c7bSVijay Lobo         .WillOnce(Return(std::vector<uint8_t>{
1646875b6c7bSVijay Lobo             2,  8,   0,  9,   0,   0,  0,  72, 0,  0,  0,  224, 0,  0,  0,
1647875b6c7bSVijay Lobo             0,  204, 0,  145, 132, 0,  0,  0,  0,  0,  0,  0,   0,  0,  0,
1648875b6c7bSVijay Lobo             0,  0,   0,  0,   0,   0,  0,  0,  0,  0,  67, 67,  48, 48, 57,
1649875b6c7bSVijay Lobo             49, 56,  52, 32,  32,  32, 32, 32, 32, 32, 32, 32,  32, 32, 32,
1650875b6c7bSVijay Lobo             32, 32,  32, 32,  32,  32, 32, 32, 32, 32, 32, 32}));
1651875b6c7bSVijay Lobo 
1652875b6c7bSVijay Lobo     SRC src{entry, ad, dataIface};
1653875b6c7bSVijay Lobo     EXPECT_TRUE(src.valid());
1654875b6c7bSVijay Lobo 
1655875b6c7bSVijay Lobo     // Verify that the hex vlue is set at the right hexword
1656875b6c7bSVijay Lobo     EXPECT_EQ(src.hexwordData()[2], 0xCC009184);
1657875b6c7bSVijay Lobo }
1658