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