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 */
16b832363dSMatt Spinler #include "elog_entry.hpp"
17131870c7SMatt Spinler #include "extensions/openpower-pels/generic.hpp"
18cb6b059eSMatt Spinler #include "extensions/openpower-pels/pel.hpp"
19aa659477SMatt Spinler #include "mocks.hpp"
20cb6b059eSMatt Spinler #include "pel_utils.hpp"
21cb6b059eSMatt Spinler
22cb6b059eSMatt Spinler #include <filesystem>
23cb6b059eSMatt Spinler #include <fstream>
24d8ae618aSArya K Padman #include <optional>
25cb6b059eSMatt Spinler
26cb6b059eSMatt Spinler #include <gtest/gtest.h>
27cb6b059eSMatt Spinler
28cb6b059eSMatt Spinler namespace fs = std::filesystem;
29cb6b059eSMatt Spinler using namespace openpower::pels;
300a90a852SMatt Spinler using ::testing::_;
31b41fa54bSWilliam A. Kennington III using ::testing::DoAll;
3256ad2a0eSMatt Spinler using ::testing::NiceMock;
33677381b8SMatt Spinler using ::testing::Return;
340a90a852SMatt Spinler using ::testing::SetArgReferee;
35cb6b059eSMatt Spinler
36cb6b059eSMatt Spinler class PELTest : public CleanLogID
372544b419SPatrick Williams {};
38cb6b059eSMatt Spinler
makeTempDir()395b289b23SMatt Spinler fs::path makeTempDir()
405b289b23SMatt Spinler {
415b289b23SMatt Spinler char path[] = "/tmp/tempdirXXXXXX";
425b289b23SMatt Spinler std::filesystem::path dir = mkdtemp(path);
435b289b23SMatt Spinler return dir;
445b289b23SMatt Spinler }
455b289b23SMatt Spinler
writeFileAndGetFD(const fs::path & dir,const std::vector<uint8_t> & data)465b289b23SMatt Spinler int writeFileAndGetFD(const fs::path& dir, const std::vector<uint8_t>& data)
475b289b23SMatt Spinler {
485b289b23SMatt Spinler static size_t count = 0;
495b289b23SMatt Spinler fs::path path = dir / (std::string{"file"} + std::to_string(count));
505b289b23SMatt Spinler std::ofstream stream{path};
515b289b23SMatt Spinler count++;
525b289b23SMatt Spinler
535b289b23SMatt Spinler stream.write(reinterpret_cast<const char*>(data.data()), data.size());
545b289b23SMatt Spinler stream.close();
555b289b23SMatt Spinler
565b289b23SMatt Spinler FILE* fp = fopen(path.c_str(), "r");
575b289b23SMatt Spinler return fileno(fp);
585b289b23SMatt Spinler }
595b289b23SMatt Spinler
TEST_F(PELTest,FlattenTest)60cb6b059eSMatt Spinler TEST_F(PELTest, FlattenTest)
61cb6b059eSMatt Spinler {
6242828bd9SMatt Spinler auto data = pelDataFactory(TestPELType::pelSimple);
6342828bd9SMatt Spinler auto pel = std::make_unique<PEL>(data);
64cb6b059eSMatt Spinler
65cb6b059eSMatt Spinler // Check a few fields
66cb6b059eSMatt Spinler EXPECT_TRUE(pel->valid());
67cb6b059eSMatt Spinler EXPECT_EQ(pel->id(), 0x80818283);
68cb6b059eSMatt Spinler EXPECT_EQ(pel->plid(), 0x50515253);
6997d19b48SMatt Spinler EXPECT_EQ(pel->userHeader().subsystem(), 0x10);
7097d19b48SMatt Spinler EXPECT_EQ(pel->userHeader().actionFlags(), 0x80C0);
71cb6b059eSMatt Spinler
72cb6b059eSMatt Spinler // Test that data in == data out
73cb6b059eSMatt Spinler auto flattenedData = pel->data();
74f1b46ff4SMatt Spinler EXPECT_EQ(data, flattenedData);
75f1b46ff4SMatt Spinler EXPECT_EQ(flattenedData.size(), pel->size());
76cb6b059eSMatt Spinler }
77cb6b059eSMatt Spinler
TEST_F(PELTest,CommitTimeTest)78cb6b059eSMatt Spinler TEST_F(PELTest, CommitTimeTest)
79cb6b059eSMatt Spinler {
8042828bd9SMatt Spinler auto data = pelDataFactory(TestPELType::pelSimple);
8142828bd9SMatt Spinler auto pel = std::make_unique<PEL>(data);
82cb6b059eSMatt Spinler
83cb6b059eSMatt Spinler auto origTime = pel->commitTime();
84cb6b059eSMatt Spinler pel->setCommitTime();
85cb6b059eSMatt Spinler auto newTime = pel->commitTime();
86cb6b059eSMatt Spinler
87f1b46ff4SMatt Spinler EXPECT_NE(origTime, newTime);
88cb6b059eSMatt Spinler
89cb6b059eSMatt Spinler // Make a new PEL and check new value is still there
90cb6b059eSMatt Spinler auto newData = pel->data();
91cb6b059eSMatt Spinler auto newPel = std::make_unique<PEL>(newData);
92f1b46ff4SMatt Spinler EXPECT_EQ(newTime, newPel->commitTime());
93cb6b059eSMatt Spinler }
94cb6b059eSMatt Spinler
TEST_F(PELTest,AssignIDTest)95cb6b059eSMatt Spinler TEST_F(PELTest, AssignIDTest)
96cb6b059eSMatt Spinler {
9742828bd9SMatt Spinler auto data = pelDataFactory(TestPELType::pelSimple);
9842828bd9SMatt Spinler auto pel = std::make_unique<PEL>(data);
99cb6b059eSMatt Spinler
100cb6b059eSMatt Spinler auto origID = pel->id();
101cb6b059eSMatt Spinler pel->assignID();
102cb6b059eSMatt Spinler auto newID = pel->id();
103cb6b059eSMatt Spinler
104f1b46ff4SMatt Spinler EXPECT_NE(origID, newID);
105cb6b059eSMatt Spinler
106cb6b059eSMatt Spinler // Make a new PEL and check new value is still there
107cb6b059eSMatt Spinler auto newData = pel->data();
108cb6b059eSMatt Spinler auto newPel = std::make_unique<PEL>(newData);
109f1b46ff4SMatt Spinler EXPECT_EQ(newID, newPel->id());
110cb6b059eSMatt Spinler }
111cb6b059eSMatt Spinler
TEST_F(PELTest,WithLogIDTest)112cb6b059eSMatt Spinler TEST_F(PELTest, WithLogIDTest)
113cb6b059eSMatt Spinler {
11442828bd9SMatt Spinler auto data = pelDataFactory(TestPELType::pelSimple);
11542828bd9SMatt Spinler auto pel = std::make_unique<PEL>(data, 0x42);
116cb6b059eSMatt Spinler
117cb6b059eSMatt Spinler EXPECT_TRUE(pel->valid());
118cb6b059eSMatt Spinler EXPECT_EQ(pel->obmcLogID(), 0x42);
119cb6b059eSMatt Spinler }
120cb6b059eSMatt Spinler
TEST_F(PELTest,InvalidPELTest)121cb6b059eSMatt Spinler TEST_F(PELTest, InvalidPELTest)
122cb6b059eSMatt Spinler {
12342828bd9SMatt Spinler auto data = pelDataFactory(TestPELType::pelSimple);
124cb6b059eSMatt Spinler
125cb6b059eSMatt Spinler // Too small
12642828bd9SMatt Spinler data.resize(PrivateHeader::flattenedSize());
127cb6b059eSMatt Spinler
12842828bd9SMatt Spinler auto pel = std::make_unique<PEL>(data);
129cb6b059eSMatt Spinler
13097d19b48SMatt Spinler EXPECT_TRUE(pel->privateHeader().valid());
13197d19b48SMatt Spinler EXPECT_FALSE(pel->userHeader().valid());
132cb6b059eSMatt Spinler EXPECT_FALSE(pel->valid());
133cb6b059eSMatt Spinler
134cb6b059eSMatt Spinler // Now corrupt the private header
13542828bd9SMatt Spinler data = pelDataFactory(TestPELType::pelSimple);
13642828bd9SMatt Spinler data.at(0) = 0;
13742828bd9SMatt Spinler pel = std::make_unique<PEL>(data);
138cb6b059eSMatt Spinler
13997d19b48SMatt Spinler EXPECT_FALSE(pel->privateHeader().valid());
14097d19b48SMatt Spinler EXPECT_TRUE(pel->userHeader().valid());
141cb6b059eSMatt Spinler EXPECT_FALSE(pel->valid());
142cb6b059eSMatt Spinler }
143cb6b059eSMatt Spinler
TEST_F(PELTest,EmptyDataTest)144cb6b059eSMatt Spinler TEST_F(PELTest, EmptyDataTest)
145cb6b059eSMatt Spinler {
146cb6b059eSMatt Spinler std::vector<uint8_t> data;
147cb6b059eSMatt Spinler auto pel = std::make_unique<PEL>(data);
148cb6b059eSMatt Spinler
14997d19b48SMatt Spinler EXPECT_FALSE(pel->privateHeader().valid());
15097d19b48SMatt Spinler EXPECT_FALSE(pel->userHeader().valid());
151cb6b059eSMatt Spinler EXPECT_FALSE(pel->valid());
152cb6b059eSMatt Spinler }
153b832363dSMatt Spinler
TEST_F(PELTest,CreateFromRegistryTest)154b832363dSMatt Spinler TEST_F(PELTest, CreateFromRegistryTest)
155b832363dSMatt Spinler {
156b832363dSMatt Spinler message::Entry regEntry;
157b832363dSMatt Spinler uint64_t timestamp = 5;
158b832363dSMatt Spinler
159b832363dSMatt Spinler regEntry.name = "test";
160b832363dSMatt Spinler regEntry.subsystem = 5;
161b832363dSMatt Spinler regEntry.actionFlags = 0xC000;
162bd716f00SMatt Spinler regEntry.src.type = 0xBD;
163bd716f00SMatt Spinler regEntry.src.reasonCode = 0x1234;
164b832363dSMatt Spinler
165*e5940634SPatrick Williams std::map<std::string, std::string> data{{"KEY1", "VALUE1"}};
1664dcd3f46SMatt Spinler AdditionalData ad{data};
16756ad2a0eSMatt Spinler NiceMock<MockDataInterface> dataIface;
1689d921096SMatt Spinler NiceMock<MockJournal> journal;
16956ad2a0eSMatt Spinler PelFFDC ffdc;
170bd716f00SMatt Spinler
17156ad2a0eSMatt Spinler PEL pel{regEntry, 42, timestamp, phosphor::logging::Entry::Level::Error,
1729d921096SMatt Spinler ad, ffdc, dataIface, journal};
173b832363dSMatt Spinler
174b832363dSMatt Spinler EXPECT_TRUE(pel.valid());
17597d19b48SMatt Spinler EXPECT_EQ(pel.privateHeader().obmcLogID(), 42);
17697d19b48SMatt Spinler EXPECT_EQ(pel.userHeader().severity(), 0x40);
177b832363dSMatt Spinler
178bd716f00SMatt Spinler EXPECT_EQ(pel.primarySRC().value()->asciiString(),
179bd716f00SMatt Spinler "BD051234 ");
1804dcd3f46SMatt Spinler
1814dcd3f46SMatt Spinler // Check that certain optional sections have been created
1824dcd3f46SMatt Spinler size_t mtmsCount = 0;
1834dcd3f46SMatt Spinler size_t euhCount = 0;
1844dcd3f46SMatt Spinler size_t udCount = 0;
1854dcd3f46SMatt Spinler
1864dcd3f46SMatt Spinler for (const auto& section : pel.optionalSections())
1874dcd3f46SMatt Spinler {
1884dcd3f46SMatt Spinler if (section->header().id ==
1894dcd3f46SMatt Spinler static_cast<uint16_t>(SectionID::failingMTMS))
1904dcd3f46SMatt Spinler {
1914dcd3f46SMatt Spinler mtmsCount++;
1924dcd3f46SMatt Spinler }
1934dcd3f46SMatt Spinler else if (section->header().id ==
1944dcd3f46SMatt Spinler static_cast<uint16_t>(SectionID::extendedUserHeader))
1954dcd3f46SMatt Spinler {
1964dcd3f46SMatt Spinler euhCount++;
1974dcd3f46SMatt Spinler }
1984dcd3f46SMatt Spinler else if (section->header().id ==
1994dcd3f46SMatt Spinler static_cast<uint16_t>(SectionID::userData))
2004dcd3f46SMatt Spinler {
2014dcd3f46SMatt Spinler udCount++;
2024dcd3f46SMatt Spinler }
2034dcd3f46SMatt Spinler }
2044dcd3f46SMatt Spinler
2054dcd3f46SMatt Spinler EXPECT_EQ(mtmsCount, 1);
2064dcd3f46SMatt Spinler EXPECT_EQ(euhCount, 1);
2074dcd3f46SMatt Spinler EXPECT_EQ(udCount, 2); // AD section and sysInfo section
208f8e750ddSAndrew Geissler ASSERT_FALSE(pel.isHwCalloutPresent());
2091f93c590SMatt Spinler
2101f93c590SMatt Spinler {
2111f93c590SMatt Spinler // The same thing, but without the action flags specified
2121f93c590SMatt Spinler // in the registry, so the constructor should set them.
2131f93c590SMatt Spinler regEntry.actionFlags = std::nullopt;
2141f93c590SMatt Spinler
215075c7923SPatrick Williams PEL pel2{regEntry, 42,
216075c7923SPatrick Williams timestamp, phosphor::logging::Entry::Level::Error,
217075c7923SPatrick Williams ad, ffdc,
218075c7923SPatrick Williams dataIface, journal};
2191f93c590SMatt Spinler
2201f93c590SMatt Spinler EXPECT_EQ(pel2.userHeader().actionFlags(), 0xA800);
2211f93c590SMatt Spinler }
222b832363dSMatt Spinler }
223131870c7SMatt Spinler
2249b7e94ffSMatt Spinler // Test that when the AdditionalData size is over 16KB that
2259b7e94ffSMatt Spinler // the PEL that's created is exactly 16KB since the UserData
2269b7e94ffSMatt Spinler // section that contains all that data was pruned.
TEST_F(PELTest,CreateTooBigADTest)2279b7e94ffSMatt Spinler TEST_F(PELTest, CreateTooBigADTest)
2289b7e94ffSMatt Spinler {
2299b7e94ffSMatt Spinler message::Entry regEntry;
2309b7e94ffSMatt Spinler uint64_t timestamp = 5;
2319b7e94ffSMatt Spinler
2329b7e94ffSMatt Spinler regEntry.name = "test";
2339b7e94ffSMatt Spinler regEntry.subsystem = 5;
2349b7e94ffSMatt Spinler regEntry.actionFlags = 0xC000;
2359b7e94ffSMatt Spinler regEntry.src.type = 0xBD;
2369b7e94ffSMatt Spinler regEntry.src.reasonCode = 0x1234;
23756ad2a0eSMatt Spinler PelFFDC ffdc;
2389b7e94ffSMatt Spinler
2399b7e94ffSMatt Spinler // Over the 16KB max PEL size
240*e5940634SPatrick Williams std::map<std::string, std::string> data{{"KEY1", std::string(17000, 'G')}};
2419b7e94ffSMatt Spinler AdditionalData ad{data};
24256ad2a0eSMatt Spinler NiceMock<MockDataInterface> dataIface;
2439d921096SMatt Spinler NiceMock<MockJournal> journal;
2449b7e94ffSMatt Spinler
24556ad2a0eSMatt Spinler PEL pel{regEntry, 42, timestamp, phosphor::logging::Entry::Level::Error,
2469d921096SMatt Spinler ad, ffdc, dataIface, journal};
2479b7e94ffSMatt Spinler
2489b7e94ffSMatt Spinler EXPECT_TRUE(pel.valid());
2499b7e94ffSMatt Spinler EXPECT_EQ(pel.size(), 16384);
2509b7e94ffSMatt Spinler
2519b7e94ffSMatt Spinler // Make sure that there are still 2 UD sections.
252be952d2eSMatt Spinler const auto& optSections = pel.optionalSections();
253075c7923SPatrick Williams auto udCount = std::count_if(
254075c7923SPatrick Williams optSections.begin(), optSections.end(), [](const auto& section) {
255be952d2eSMatt Spinler return section->header().id ==
256be952d2eSMatt Spinler static_cast<uint16_t>(SectionID::userData);
257be952d2eSMatt Spinler });
2589b7e94ffSMatt Spinler
2599b7e94ffSMatt Spinler EXPECT_EQ(udCount, 2); // AD section and sysInfo section
2609b7e94ffSMatt Spinler }
2619b7e94ffSMatt Spinler
262131870c7SMatt Spinler // Test that we'll create Generic optional sections for sections that
263131870c7SMatt Spinler // there aren't explicit classes for.
TEST_F(PELTest,GenericSectionTest)264131870c7SMatt Spinler TEST_F(PELTest, GenericSectionTest)
265131870c7SMatt Spinler {
26642828bd9SMatt Spinler auto data = pelDataFactory(TestPELType::pelSimple);
267131870c7SMatt Spinler
268075c7923SPatrick Williams std::vector<uint8_t> section1{
269075c7923SPatrick Williams 0x58, 0x58, // ID 'XX'
270131870c7SMatt Spinler 0x00, 0x18, // Size
271131870c7SMatt Spinler 0x01, 0x02, // version, subtype
272131870c7SMatt Spinler 0x03, 0x04, // comp ID
273131870c7SMatt Spinler
274131870c7SMatt Spinler // some data
275075c7923SPatrick Williams 0x20, 0x30, 0x05, 0x09, 0x11, 0x1E, 0x1, 0x63, 0x20, 0x31, 0x06, 0x0F,
276075c7923SPatrick Williams 0x09, 0x22, 0x3A, 0x00};
277131870c7SMatt Spinler
278131870c7SMatt Spinler std::vector<uint8_t> section2{
279131870c7SMatt Spinler 0x59, 0x59, // ID 'YY'
280131870c7SMatt Spinler 0x00, 0x20, // Size
281131870c7SMatt Spinler 0x01, 0x02, // version, subtype
282131870c7SMatt Spinler 0x03, 0x04, // comp ID
283131870c7SMatt Spinler
284131870c7SMatt Spinler // some data
285131870c7SMatt Spinler 0x20, 0x30, 0x05, 0x09, 0x11, 0x1E, 0x1, 0x63, 0x20, 0x31, 0x06, 0x0F,
286131870c7SMatt Spinler 0x09, 0x22, 0x3A, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
287131870c7SMatt Spinler
288131870c7SMatt Spinler // Add the new sections at the end
28942828bd9SMatt Spinler data.insert(data.end(), section1.begin(), section1.end());
29042828bd9SMatt Spinler data.insert(data.end(), section2.begin(), section2.end());
291131870c7SMatt Spinler
292131870c7SMatt Spinler // Increment the section count
29342828bd9SMatt Spinler data.at(27) += 2;
29442828bd9SMatt Spinler auto origData = data;
295131870c7SMatt Spinler
29642828bd9SMatt Spinler PEL pel{data};
297131870c7SMatt Spinler
298131870c7SMatt Spinler const auto& sections = pel.optionalSections();
299131870c7SMatt Spinler
300131870c7SMatt Spinler bool foundXX = false;
301131870c7SMatt Spinler bool foundYY = false;
302131870c7SMatt Spinler
303131870c7SMatt Spinler // Check that we can find these 2 Generic sections
304131870c7SMatt Spinler for (const auto& section : sections)
305131870c7SMatt Spinler {
306131870c7SMatt Spinler if (section->header().id == 0x5858)
307131870c7SMatt Spinler {
308131870c7SMatt Spinler foundXX = true;
309131870c7SMatt Spinler EXPECT_NE(dynamic_cast<Generic*>(section.get()), nullptr);
310131870c7SMatt Spinler }
311131870c7SMatt Spinler else if (section->header().id == 0x5959)
312131870c7SMatt Spinler {
313131870c7SMatt Spinler foundYY = true;
314131870c7SMatt Spinler EXPECT_NE(dynamic_cast<Generic*>(section.get()), nullptr);
315131870c7SMatt Spinler }
316131870c7SMatt Spinler }
317131870c7SMatt Spinler
318131870c7SMatt Spinler EXPECT_TRUE(foundXX);
319131870c7SMatt Spinler EXPECT_TRUE(foundYY);
32007eefc54SMatt Spinler
32107eefc54SMatt Spinler // Now flatten and check
32207eefc54SMatt Spinler auto newData = pel.data();
32307eefc54SMatt Spinler
32407eefc54SMatt Spinler EXPECT_EQ(origData, newData);
325131870c7SMatt Spinler }
326131870c7SMatt Spinler
327131870c7SMatt Spinler // Test that an invalid section will still get a Generic object
TEST_F(PELTest,InvalidGenericTest)328131870c7SMatt Spinler TEST_F(PELTest, InvalidGenericTest)
329131870c7SMatt Spinler {
33042828bd9SMatt Spinler auto data = pelDataFactory(TestPELType::pelSimple);
331131870c7SMatt Spinler
332131870c7SMatt Spinler // Not a valid section
333131870c7SMatt Spinler std::vector<uint8_t> section1{0x01, 0x02, 0x03};
334131870c7SMatt Spinler
33542828bd9SMatt Spinler data.insert(data.end(), section1.begin(), section1.end());
336131870c7SMatt Spinler
337131870c7SMatt Spinler // Increment the section count
33842828bd9SMatt Spinler data.at(27) += 1;
339131870c7SMatt Spinler
34042828bd9SMatt Spinler PEL pel{data};
341131870c7SMatt Spinler EXPECT_FALSE(pel.valid());
342131870c7SMatt Spinler
343131870c7SMatt Spinler const auto& sections = pel.optionalSections();
344131870c7SMatt Spinler
345131870c7SMatt Spinler bool foundGeneric = false;
346131870c7SMatt Spinler for (const auto& section : sections)
347131870c7SMatt Spinler {
348131870c7SMatt Spinler if (dynamic_cast<Generic*>(section.get()) != nullptr)
349131870c7SMatt Spinler {
350131870c7SMatt Spinler foundGeneric = true;
351131870c7SMatt Spinler EXPECT_EQ(section->valid(), false);
352131870c7SMatt Spinler break;
353131870c7SMatt Spinler }
354131870c7SMatt Spinler }
355131870c7SMatt Spinler
356131870c7SMatt Spinler EXPECT_TRUE(foundGeneric);
357131870c7SMatt Spinler }
358afa857c7SMatt Spinler
359afa857c7SMatt Spinler // Create a UserData section out of AdditionalData
TEST_F(PELTest,MakeUDSectionTest)360afa857c7SMatt Spinler TEST_F(PELTest, MakeUDSectionTest)
361afa857c7SMatt Spinler {
362*e5940634SPatrick Williams std::map<std::string, std::string> ad{{"KEY1", "VALUE1"},
363*e5940634SPatrick Williams {"KEY2", "VALUE2"},
364*e5940634SPatrick Williams {"KEY3", "VALUE3"},
365*e5940634SPatrick Williams {"ESEL", "TEST"}};
366afa857c7SMatt Spinler AdditionalData additionalData{ad};
367afa857c7SMatt Spinler
368afa857c7SMatt Spinler auto ud = util::makeADUserDataSection(additionalData);
369afa857c7SMatt Spinler
370afa857c7SMatt Spinler EXPECT_TRUE(ud->valid());
371afa857c7SMatt Spinler EXPECT_EQ(ud->header().id, 0x5544);
372afa857c7SMatt Spinler EXPECT_EQ(ud->header().version, 0x01);
373afa857c7SMatt Spinler EXPECT_EQ(ud->header().subType, 0x01);
374afa857c7SMatt Spinler EXPECT_EQ(ud->header().componentID, 0x2000);
375afa857c7SMatt Spinler
376afa857c7SMatt Spinler const auto& d = ud->data();
377afa857c7SMatt Spinler
378afa857c7SMatt Spinler std::string jsonString{d.begin(), d.end()};
37953407be3SMatt Spinler
38053407be3SMatt Spinler std::string expectedJSON =
381afa857c7SMatt Spinler R"({"KEY1":"VALUE1","KEY2":"VALUE2","KEY3":"VALUE3"})";
38253407be3SMatt Spinler
38353407be3SMatt Spinler // The actual data is null padded to a 4B boundary.
38453407be3SMatt Spinler std::vector<uint8_t> expectedData;
38553407be3SMatt Spinler expectedData.resize(52, '\0');
38653407be3SMatt Spinler memcpy(expectedData.data(), expectedJSON.data(), expectedJSON.size());
38753407be3SMatt Spinler
38853407be3SMatt Spinler EXPECT_EQ(d, expectedData);
389afa857c7SMatt Spinler
390afa857c7SMatt Spinler // Ensure we can read this as JSON
391afa857c7SMatt Spinler auto newJSON = nlohmann::json::parse(jsonString);
392afa857c7SMatt Spinler EXPECT_EQ(newJSON["KEY1"], "VALUE1");
393afa857c7SMatt Spinler EXPECT_EQ(newJSON["KEY2"], "VALUE2");
394afa857c7SMatt Spinler EXPECT_EQ(newJSON["KEY3"], "VALUE3");
395afa857c7SMatt Spinler }
3964dcd3f46SMatt Spinler
3974dcd3f46SMatt Spinler // Create the UserData section that contains system info
TEST_F(PELTest,SysInfoSectionTest)398677381b8SMatt Spinler TEST_F(PELTest, SysInfoSectionTest)
3994dcd3f46SMatt Spinler {
4004dcd3f46SMatt Spinler MockDataInterface dataIface;
4014dcd3f46SMatt Spinler
402677381b8SMatt Spinler EXPECT_CALL(dataIface, getBMCFWVersionID()).WillOnce(Return("ABCD1234"));
4034aa23a1fSMatt Spinler EXPECT_CALL(dataIface, getBMCState()).WillOnce(Return("State.Ready"));
4044aa23a1fSMatt Spinler EXPECT_CALL(dataIface, getChassisState()).WillOnce(Return("State.On"));
4054aa23a1fSMatt Spinler EXPECT_CALL(dataIface, getHostState()).WillOnce(Return("State.Off"));
4062c36fddcSSumit Kumar EXPECT_CALL(dataIface, getBootState())
4072c36fddcSSumit Kumar .WillOnce(Return("State.SystemInitComplete"));
408e32b7e76SBen Tyner EXPECT_CALL(dataIface, getSystemIMKeyword())
409e32b7e76SBen Tyner .WillOnce(Return(std::vector<uint8_t>{0, 1, 0x55, 0xAA}));
410677381b8SMatt Spinler
411*e5940634SPatrick Williams std::map<std::string, std::string> ad{{"_PID", std::to_string(getpid())}};
4124dcd3f46SMatt Spinler AdditionalData additionalData{ad};
4134dcd3f46SMatt Spinler
4144dcd3f46SMatt Spinler auto ud = util::makeSysInfoUserDataSection(additionalData, dataIface);
4154dcd3f46SMatt Spinler
4164dcd3f46SMatt Spinler EXPECT_TRUE(ud->valid());
4174dcd3f46SMatt Spinler EXPECT_EQ(ud->header().id, 0x5544);
4184dcd3f46SMatt Spinler EXPECT_EQ(ud->header().version, 0x01);
4194dcd3f46SMatt Spinler EXPECT_EQ(ud->header().subType, 0x01);
4204dcd3f46SMatt Spinler EXPECT_EQ(ud->header().componentID, 0x2000);
4214dcd3f46SMatt Spinler
4224dcd3f46SMatt Spinler // Pull out the JSON data and check it.
4234dcd3f46SMatt Spinler const auto& d = ud->data();
4244dcd3f46SMatt Spinler std::string jsonString{d.begin(), d.end()};
4254dcd3f46SMatt Spinler auto json = nlohmann::json::parse(jsonString);
4264dcd3f46SMatt Spinler
427d9f0d646SPatrick Williams // Ensure the 'Process Name' entry contains the name of this test
428d9f0d646SPatrick Williams // executable.
4294dcd3f46SMatt Spinler auto name = json["Process Name"].get<std::string>();
430d9f0d646SPatrick Williams auto found = (name.find("pel_test") != std::string::npos) ||
431d9f0d646SPatrick Williams (name.find("test-openpower-pels-pel") != std::string::npos);
432d9f0d646SPatrick Williams EXPECT_TRUE(found);
433d9f0d646SPatrick Williams // @TODO(stwcx): remove 'pel_test' when removing autotools.
434677381b8SMatt Spinler
435c2b8a517SMatt Spinler auto version = json["FW Version ID"].get<std::string>();
436677381b8SMatt Spinler EXPECT_EQ(version, "ABCD1234");
4374aa23a1fSMatt Spinler
4384aa23a1fSMatt Spinler auto state = json["BMCState"].get<std::string>();
4394aa23a1fSMatt Spinler EXPECT_EQ(state, "Ready");
4404aa23a1fSMatt Spinler
4414aa23a1fSMatt Spinler state = json["ChassisState"].get<std::string>();
4424aa23a1fSMatt Spinler EXPECT_EQ(state, "On");
4434aa23a1fSMatt Spinler
4444aa23a1fSMatt Spinler state = json["HostState"].get<std::string>();
4454aa23a1fSMatt Spinler EXPECT_EQ(state, "Off");
446e32b7e76SBen Tyner
4472c36fddcSSumit Kumar state = json["BootState"].get<std::string>();
4482c36fddcSSumit Kumar EXPECT_EQ(state, "SystemInitComplete");
4492c36fddcSSumit Kumar
450e32b7e76SBen Tyner auto keyword = json["System IM"].get<std::string>();
451e32b7e76SBen Tyner EXPECT_EQ(keyword, "000155AA");
4524dcd3f46SMatt Spinler }
453ce3f450bSMatt Spinler
454ce3f450bSMatt Spinler // Test that the sections that override
455ce3f450bSMatt Spinler // virtual std::optional<std::string> Section::getJSON() const
456ce3f450bSMatt Spinler // return valid JSON.
TEST_F(PELTest,SectionJSONTest)457ce3f450bSMatt Spinler TEST_F(PELTest, SectionJSONTest)
458ce3f450bSMatt Spinler {
459ce3f450bSMatt Spinler auto data = pelDataFactory(TestPELType::pelSimple);
460ce3f450bSMatt Spinler PEL pel{data};
461ce3f450bSMatt Spinler
462ce3f450bSMatt Spinler // Check that all JSON returned from the sections is
463ce3f450bSMatt Spinler // parseable by nlohmann::json, which will throw an
464ce3f450bSMatt Spinler // exception and fail the test if there is a problem.
465ce3f450bSMatt Spinler
466ce3f450bSMatt Spinler // The getJSON() response needs to be wrapped in a { } to make
467ce3f450bSMatt Spinler // actual valid JSON (PEL::toJSON() usually handles that).
468ce3f450bSMatt Spinler
469b832aa5eSMatt Spinler auto jsonString = pel.privateHeader().getJSON('O');
470ce3f450bSMatt Spinler
471ce3f450bSMatt Spinler // PrivateHeader always prints JSON
472ce3f450bSMatt Spinler ASSERT_TRUE(jsonString);
473ce3f450bSMatt Spinler *jsonString = '{' + *jsonString + '}';
474ce3f450bSMatt Spinler auto json = nlohmann::json::parse(*jsonString);
475ce3f450bSMatt Spinler
476b832aa5eSMatt Spinler jsonString = pel.userHeader().getJSON('O');
477ce3f450bSMatt Spinler
478ce3f450bSMatt Spinler // UserHeader always prints JSON
479ce3f450bSMatt Spinler ASSERT_TRUE(jsonString);
480ce3f450bSMatt Spinler *jsonString = '{' + *jsonString + '}';
481ce3f450bSMatt Spinler json = nlohmann::json::parse(*jsonString);
482ce3f450bSMatt Spinler
483ce3f450bSMatt Spinler for (const auto& section : pel.optionalSections())
484ce3f450bSMatt Spinler {
485ce3f450bSMatt Spinler // The optional sections may or may not have implemented getJSON().
486b832aa5eSMatt Spinler jsonString = section->getJSON('O');
487ce3f450bSMatt Spinler if (jsonString)
488ce3f450bSMatt Spinler {
489ce3f450bSMatt Spinler *jsonString = '{' + *jsonString + '}';
490ce3f450bSMatt Spinler auto json = nlohmann::json::parse(*jsonString);
491ce3f450bSMatt Spinler }
492ce3f450bSMatt Spinler }
493ce3f450bSMatt Spinler }
4945b289b23SMatt Spinler
getJSONFFDC(const fs::path & dir)4955b289b23SMatt Spinler PelFFDCfile getJSONFFDC(const fs::path& dir)
4965b289b23SMatt Spinler {
4975b289b23SMatt Spinler PelFFDCfile ffdc;
4985b289b23SMatt Spinler ffdc.format = UserDataFormat::json;
4995b289b23SMatt Spinler ffdc.subType = 5;
5005b289b23SMatt Spinler ffdc.version = 42;
5015b289b23SMatt Spinler
5025b289b23SMatt Spinler auto inputJSON = R"({
5035b289b23SMatt Spinler "key1": "value1",
5045b289b23SMatt Spinler "key2": 42,
5055b289b23SMatt Spinler "key3" : [1, 2, 3, 4, 5],
5065b289b23SMatt Spinler "key4": {"key5": "value5"}
5075b289b23SMatt Spinler })"_json;
5085b289b23SMatt Spinler
5095b289b23SMatt Spinler // Write the JSON to a file and get its descriptor.
5105b289b23SMatt Spinler auto s = inputJSON.dump();
5115b289b23SMatt Spinler std::vector<uint8_t> data{s.begin(), s.end()};
5125b289b23SMatt Spinler ffdc.fd = writeFileAndGetFD(dir, data);
5135b289b23SMatt Spinler
5145b289b23SMatt Spinler return ffdc;
5155b289b23SMatt Spinler }
5165b289b23SMatt Spinler
TEST_F(PELTest,MakeJSONFileUDSectionTest)5175b289b23SMatt Spinler TEST_F(PELTest, MakeJSONFileUDSectionTest)
5185b289b23SMatt Spinler {
5195b289b23SMatt Spinler auto dir = makeTempDir();
5205b289b23SMatt Spinler
5215b289b23SMatt Spinler {
5225b289b23SMatt Spinler auto ffdc = getJSONFFDC(dir);
5235b289b23SMatt Spinler
5245b289b23SMatt Spinler auto ud = util::makeFFDCuserDataSection(0x2002, ffdc);
5255b289b23SMatt Spinler close(ffdc.fd);
5265b289b23SMatt Spinler ASSERT_TRUE(ud);
5275b289b23SMatt Spinler ASSERT_TRUE(ud->valid());
5285b289b23SMatt Spinler EXPECT_EQ(ud->header().id, 0x5544);
5295b289b23SMatt Spinler
5305b289b23SMatt Spinler EXPECT_EQ(ud->header().version,
5315b289b23SMatt Spinler static_cast<uint8_t>(UserDataFormatVersion::json));
5325b289b23SMatt Spinler EXPECT_EQ(ud->header().subType,
5335b289b23SMatt Spinler static_cast<uint8_t>(UserDataFormat::json));
5345b289b23SMatt Spinler EXPECT_EQ(ud->header().componentID,
5355b289b23SMatt Spinler static_cast<uint16_t>(ComponentID::phosphorLogging));
5365b289b23SMatt Spinler
5375b289b23SMatt Spinler // Pull the JSON back out of the the UserData section
5385b289b23SMatt Spinler const auto& d = ud->data();
5395b289b23SMatt Spinler std::string js{d.begin(), d.end()};
5405b289b23SMatt Spinler auto json = nlohmann::json::parse(js);
5415b289b23SMatt Spinler
5425b289b23SMatt Spinler EXPECT_EQ("value1", json["key1"].get<std::string>());
5435b289b23SMatt Spinler EXPECT_EQ(42, json["key2"].get<int>());
5445b289b23SMatt Spinler
5455b289b23SMatt Spinler std::vector<int> key3Values{1, 2, 3, 4, 5};
5465b289b23SMatt Spinler EXPECT_EQ(key3Values, json["key3"].get<std::vector<int>>());
5475b289b23SMatt Spinler
5485b289b23SMatt Spinler std::map<std::string, std::string> key4Values{{"key5", "value5"}};
5495b289b23SMatt Spinler auto actual = json["key4"].get<std::map<std::string, std::string>>();
5505b289b23SMatt Spinler EXPECT_EQ(key4Values, actual);
5515b289b23SMatt Spinler }
5525b289b23SMatt Spinler
5535b289b23SMatt Spinler {
5545b289b23SMatt Spinler // A bad FD
5555b289b23SMatt Spinler PelFFDCfile ffdc;
5565b289b23SMatt Spinler ffdc.format = UserDataFormat::json;
5575b289b23SMatt Spinler ffdc.subType = 5;
5585b289b23SMatt Spinler ffdc.version = 42;
5595b289b23SMatt Spinler ffdc.fd = 10000;
5605b289b23SMatt Spinler
5615b289b23SMatt Spinler // The section shouldn't get made
5625b289b23SMatt Spinler auto ud = util::makeFFDCuserDataSection(0x2002, ffdc);
5635b289b23SMatt Spinler ASSERT_FALSE(ud);
5645b289b23SMatt Spinler }
5655b289b23SMatt Spinler
5665b289b23SMatt Spinler fs::remove_all(dir);
5675b289b23SMatt Spinler }
5685b289b23SMatt Spinler
getCBORFFDC(const fs::path & dir)5695b289b23SMatt Spinler PelFFDCfile getCBORFFDC(const fs::path& dir)
5705b289b23SMatt Spinler {
5715b289b23SMatt Spinler PelFFDCfile ffdc;
5725b289b23SMatt Spinler ffdc.format = UserDataFormat::cbor;
5735b289b23SMatt Spinler ffdc.subType = 5;
5745b289b23SMatt Spinler ffdc.version = 42;
5755b289b23SMatt Spinler
5765b289b23SMatt Spinler auto inputJSON = R"({
5775b289b23SMatt Spinler "key1": "value1",
5785b289b23SMatt Spinler "key2": 42,
5795b289b23SMatt Spinler "key3" : [1, 2, 3, 4, 5],
5805b289b23SMatt Spinler "key4": {"key5": "value5"}
5815b289b23SMatt Spinler })"_json;
5825b289b23SMatt Spinler
5835b289b23SMatt Spinler // Convert the JSON to CBOR and write it to a file
5845b289b23SMatt Spinler auto data = nlohmann::json::to_cbor(inputJSON);
5855b289b23SMatt Spinler ffdc.fd = writeFileAndGetFD(dir, data);
5865b289b23SMatt Spinler
5875b289b23SMatt Spinler return ffdc;
5885b289b23SMatt Spinler }
5895b289b23SMatt Spinler
TEST_F(PELTest,MakeCBORFileUDSectionTest)5905b289b23SMatt Spinler TEST_F(PELTest, MakeCBORFileUDSectionTest)
5915b289b23SMatt Spinler {
5925b289b23SMatt Spinler auto dir = makeTempDir();
5935b289b23SMatt Spinler
5945b289b23SMatt Spinler auto ffdc = getCBORFFDC(dir);
5955b289b23SMatt Spinler auto ud = util::makeFFDCuserDataSection(0x2002, ffdc);
5965b289b23SMatt Spinler close(ffdc.fd);
5975b289b23SMatt Spinler ASSERT_TRUE(ud);
5985b289b23SMatt Spinler ASSERT_TRUE(ud->valid());
5995b289b23SMatt Spinler EXPECT_EQ(ud->header().id, 0x5544);
6005b289b23SMatt Spinler
6015b289b23SMatt Spinler EXPECT_EQ(ud->header().version,
6025b289b23SMatt Spinler static_cast<uint8_t>(UserDataFormatVersion::cbor));
6035b289b23SMatt Spinler EXPECT_EQ(ud->header().subType, static_cast<uint8_t>(UserDataFormat::cbor));
6045b289b23SMatt Spinler EXPECT_EQ(ud->header().componentID,
6055b289b23SMatt Spinler static_cast<uint16_t>(ComponentID::phosphorLogging));
6065b289b23SMatt Spinler
6075b289b23SMatt Spinler // Pull the CBOR back out of the PEL section
6085b289b23SMatt Spinler // The number of pad bytes to make the section be 4B aligned
6095b289b23SMatt Spinler // was added at the end, read it and then remove it and the
6105b289b23SMatt Spinler // padding before parsing it.
6115b289b23SMatt Spinler auto data = ud->data();
6125b289b23SMatt Spinler Stream stream{data};
6135b289b23SMatt Spinler stream.offset(data.size() - 4);
6145b289b23SMatt Spinler uint32_t pad;
6155b289b23SMatt Spinler stream >> pad;
6165b289b23SMatt Spinler
6175b289b23SMatt Spinler data.resize(data.size() - 4 - pad);
6185b289b23SMatt Spinler
6195b289b23SMatt Spinler auto json = nlohmann::json::from_cbor(data);
6205b289b23SMatt Spinler
6215b289b23SMatt Spinler EXPECT_EQ("value1", json["key1"].get<std::string>());
6225b289b23SMatt Spinler EXPECT_EQ(42, json["key2"].get<int>());
6235b289b23SMatt Spinler
6245b289b23SMatt Spinler std::vector<int> key3Values{1, 2, 3, 4, 5};
6255b289b23SMatt Spinler EXPECT_EQ(key3Values, json["key3"].get<std::vector<int>>());
6265b289b23SMatt Spinler
6275b289b23SMatt Spinler std::map<std::string, std::string> key4Values{{"key5", "value5"}};
6285b289b23SMatt Spinler auto actual = json["key4"].get<std::map<std::string, std::string>>();
6295b289b23SMatt Spinler EXPECT_EQ(key4Values, actual);
6305b289b23SMatt Spinler
6315b289b23SMatt Spinler fs::remove_all(dir);
6325b289b23SMatt Spinler }
6335b289b23SMatt Spinler
getTextFFDC(const fs::path & dir)6345b289b23SMatt Spinler PelFFDCfile getTextFFDC(const fs::path& dir)
6355b289b23SMatt Spinler {
6365b289b23SMatt Spinler PelFFDCfile ffdc;
6375b289b23SMatt Spinler ffdc.format = UserDataFormat::text;
6385b289b23SMatt Spinler ffdc.subType = 5;
6395b289b23SMatt Spinler ffdc.version = 42;
6405b289b23SMatt Spinler
6415b289b23SMatt Spinler std::string text{"this is some text that will be used for FFDC"};
6425b289b23SMatt Spinler std::vector<uint8_t> data{text.begin(), text.end()};
6435b289b23SMatt Spinler
6445b289b23SMatt Spinler ffdc.fd = writeFileAndGetFD(dir, data);
6455b289b23SMatt Spinler
6465b289b23SMatt Spinler return ffdc;
6475b289b23SMatt Spinler }
6485b289b23SMatt Spinler
TEST_F(PELTest,MakeTextFileUDSectionTest)6495b289b23SMatt Spinler TEST_F(PELTest, MakeTextFileUDSectionTest)
6505b289b23SMatt Spinler {
6515b289b23SMatt Spinler auto dir = makeTempDir();
6525b289b23SMatt Spinler
6535b289b23SMatt Spinler auto ffdc = getTextFFDC(dir);
6545b289b23SMatt Spinler auto ud = util::makeFFDCuserDataSection(0x2002, ffdc);
6555b289b23SMatt Spinler close(ffdc.fd);
6565b289b23SMatt Spinler ASSERT_TRUE(ud);
6575b289b23SMatt Spinler ASSERT_TRUE(ud->valid());
6585b289b23SMatt Spinler EXPECT_EQ(ud->header().id, 0x5544);
6595b289b23SMatt Spinler
6605b289b23SMatt Spinler EXPECT_EQ(ud->header().version,
6615b289b23SMatt Spinler static_cast<uint8_t>(UserDataFormatVersion::text));
6625b289b23SMatt Spinler EXPECT_EQ(ud->header().subType, static_cast<uint8_t>(UserDataFormat::text));
6635b289b23SMatt Spinler EXPECT_EQ(ud->header().componentID,
6645b289b23SMatt Spinler static_cast<uint16_t>(ComponentID::phosphorLogging));
6655b289b23SMatt Spinler
6665b289b23SMatt Spinler // Get the text back out
6675b289b23SMatt Spinler std::string text{ud->data().begin(), ud->data().end()};
6685b289b23SMatt Spinler EXPECT_EQ(text, "this is some text that will be used for FFDC");
6695b289b23SMatt Spinler
6705b289b23SMatt Spinler fs::remove_all(dir);
6715b289b23SMatt Spinler }
6725b289b23SMatt Spinler
getCustomFFDC(const fs::path & dir,const std::vector<uint8_t> & data)6735b289b23SMatt Spinler PelFFDCfile getCustomFFDC(const fs::path& dir, const std::vector<uint8_t>& data)
6745b289b23SMatt Spinler {
6755b289b23SMatt Spinler PelFFDCfile ffdc;
6765b289b23SMatt Spinler ffdc.format = UserDataFormat::custom;
6775b289b23SMatt Spinler ffdc.subType = 5;
6785b289b23SMatt Spinler ffdc.version = 42;
6795b289b23SMatt Spinler
6805b289b23SMatt Spinler ffdc.fd = writeFileAndGetFD(dir, data);
6815b289b23SMatt Spinler
6825b289b23SMatt Spinler return ffdc;
6835b289b23SMatt Spinler }
6845b289b23SMatt Spinler
TEST_F(PELTest,MakeCustomFileUDSectionTest)6855b289b23SMatt Spinler TEST_F(PELTest, MakeCustomFileUDSectionTest)
6865b289b23SMatt Spinler {
6875b289b23SMatt Spinler auto dir = makeTempDir();
6885b289b23SMatt Spinler
6895b289b23SMatt Spinler {
6905b289b23SMatt Spinler std::vector<uint8_t> data{1, 2, 3, 4, 5, 6, 7, 8};
6915b289b23SMatt Spinler
6925b289b23SMatt Spinler auto ffdc = getCustomFFDC(dir, data);
6935b289b23SMatt Spinler auto ud = util::makeFFDCuserDataSection(0x2002, ffdc);
6945b289b23SMatt Spinler close(ffdc.fd);
6955b289b23SMatt Spinler ASSERT_TRUE(ud);
6965b289b23SMatt Spinler ASSERT_TRUE(ud->valid());
6975b289b23SMatt Spinler EXPECT_EQ(ud->header().size, 8 + 8); // data size + header size
6985b289b23SMatt Spinler EXPECT_EQ(ud->header().id, 0x5544);
6995b289b23SMatt Spinler
7005b289b23SMatt Spinler EXPECT_EQ(ud->header().version, 42);
7015b289b23SMatt Spinler EXPECT_EQ(ud->header().subType, 5);
7025b289b23SMatt Spinler EXPECT_EQ(ud->header().componentID, 0x2002);
7035b289b23SMatt Spinler
7045b289b23SMatt Spinler // Get the data back out
7055b289b23SMatt Spinler std::vector<uint8_t> newData{ud->data().begin(), ud->data().end()};
7065b289b23SMatt Spinler EXPECT_EQ(data, newData);
7075b289b23SMatt Spinler }
7085b289b23SMatt Spinler
7095b289b23SMatt Spinler // Do the same thing again, but make it be non 4B aligned
7105b289b23SMatt Spinler // so the data gets padded.
7115b289b23SMatt Spinler {
7125b289b23SMatt Spinler std::vector<uint8_t> data{1, 2, 3, 4, 5, 6, 7, 8, 9};
7135b289b23SMatt Spinler
7145b289b23SMatt Spinler auto ffdc = getCustomFFDC(dir, data);
7155b289b23SMatt Spinler auto ud = util::makeFFDCuserDataSection(0x2002, ffdc);
7165b289b23SMatt Spinler close(ffdc.fd);
7175b289b23SMatt Spinler ASSERT_TRUE(ud);
7185b289b23SMatt Spinler ASSERT_TRUE(ud->valid());
7195b289b23SMatt Spinler EXPECT_EQ(ud->header().size, 12 + 8); // data size + header size
7205b289b23SMatt Spinler EXPECT_EQ(ud->header().id, 0x5544);
7215b289b23SMatt Spinler
7225b289b23SMatt Spinler EXPECT_EQ(ud->header().version, 42);
7235b289b23SMatt Spinler EXPECT_EQ(ud->header().subType, 5);
7245b289b23SMatt Spinler EXPECT_EQ(ud->header().componentID, 0x2002);
7255b289b23SMatt Spinler
7265b289b23SMatt Spinler // Get the data back out
7275b289b23SMatt Spinler std::vector<uint8_t> newData{ud->data().begin(), ud->data().end()};
7285b289b23SMatt Spinler
7295b289b23SMatt Spinler // pad the original to 12B so we can compare
7305b289b23SMatt Spinler data.push_back(0);
7315b289b23SMatt Spinler data.push_back(0);
7325b289b23SMatt Spinler data.push_back(0);
7335b289b23SMatt Spinler
7345b289b23SMatt Spinler EXPECT_EQ(data, newData);
7355b289b23SMatt Spinler }
7365b289b23SMatt Spinler
7375b289b23SMatt Spinler fs::remove_all(dir);
7385b289b23SMatt Spinler }
7395b289b23SMatt Spinler
7405b289b23SMatt Spinler // Test Adding FFDC from files to a PEL
TEST_F(PELTest,CreateWithFFDCTest)7415b289b23SMatt Spinler TEST_F(PELTest, CreateWithFFDCTest)
7425b289b23SMatt Spinler {
7435b289b23SMatt Spinler auto dir = makeTempDir();
7445b289b23SMatt Spinler message::Entry regEntry;
7455b289b23SMatt Spinler uint64_t timestamp = 5;
7465b289b23SMatt Spinler
7475b289b23SMatt Spinler regEntry.name = "test";
7485b289b23SMatt Spinler regEntry.subsystem = 5;
7495b289b23SMatt Spinler regEntry.actionFlags = 0xC000;
7505b289b23SMatt Spinler regEntry.src.type = 0xBD;
7515b289b23SMatt Spinler regEntry.src.reasonCode = 0x1234;
7525b289b23SMatt Spinler
753*e5940634SPatrick Williams std::map<std::string, std::string> additionalData{{"KEY1", "VALUE1"}};
7545b289b23SMatt Spinler AdditionalData ad{additionalData};
7555b289b23SMatt Spinler NiceMock<MockDataInterface> dataIface;
7569d921096SMatt Spinler NiceMock<MockJournal> journal;
7575b289b23SMatt Spinler PelFFDC ffdc;
7585b289b23SMatt Spinler
7595b289b23SMatt Spinler std::vector<uint8_t> customData{1, 2, 3, 4, 5, 6, 7, 8};
7605b289b23SMatt Spinler
7615b289b23SMatt Spinler // This will be trimmed when added
7625b289b23SMatt Spinler std::vector<uint8_t> hugeCustomData(17000, 0x42);
7635b289b23SMatt Spinler
7645b289b23SMatt Spinler ffdc.emplace_back(std::move(getJSONFFDC(dir)));
7655b289b23SMatt Spinler ffdc.emplace_back(std::move(getCBORFFDC(dir)));
7665b289b23SMatt Spinler ffdc.emplace_back(std::move(getTextFFDC(dir)));
7675b289b23SMatt Spinler ffdc.emplace_back(std::move(getCustomFFDC(dir, customData)));
7685b289b23SMatt Spinler ffdc.emplace_back(std::move(getCustomFFDC(dir, hugeCustomData)));
7695b289b23SMatt Spinler
7705b289b23SMatt Spinler PEL pel{regEntry, 42, timestamp, phosphor::logging::Entry::Level::Error,
7719d921096SMatt Spinler ad, ffdc, dataIface, journal};
7725b289b23SMatt Spinler
7735b289b23SMatt Spinler EXPECT_TRUE(pel.valid());
7745b289b23SMatt Spinler
7755b289b23SMatt Spinler // Clipped to the max
7765b289b23SMatt Spinler EXPECT_EQ(pel.size(), 16384);
7775b289b23SMatt Spinler
7785b289b23SMatt Spinler // Check for the FFDC sections
7795b289b23SMatt Spinler size_t udCount = 0;
7805b289b23SMatt Spinler Section* ud = nullptr;
7815b289b23SMatt Spinler
7825b289b23SMatt Spinler for (const auto& section : pel.optionalSections())
7835b289b23SMatt Spinler {
7845b289b23SMatt Spinler if (section->header().id == static_cast<uint16_t>(SectionID::userData))
7855b289b23SMatt Spinler {
7865b289b23SMatt Spinler udCount++;
7875b289b23SMatt Spinler ud = section.get();
7885b289b23SMatt Spinler }
7895b289b23SMatt Spinler }
7905b289b23SMatt Spinler
7915b289b23SMatt Spinler EXPECT_EQ(udCount, 7); // AD section, sysInfo, 5 ffdc sections
7925b289b23SMatt Spinler
7935b289b23SMatt Spinler // Check the last section was trimmed to
7945b289b23SMatt Spinler // something a bit less that 17000.
7955b289b23SMatt Spinler EXPECT_GT(ud->header().size, 14000);
7965b289b23SMatt Spinler EXPECT_LT(ud->header().size, 16000);
7975b289b23SMatt Spinler
7985b289b23SMatt Spinler fs::remove_all(dir);
7995b289b23SMatt Spinler }
8000a90a852SMatt Spinler
8010a90a852SMatt Spinler // Create a PEL with device callouts
TEST_F(PELTest,CreateWithDevCalloutsTest)8020a90a852SMatt Spinler TEST_F(PELTest, CreateWithDevCalloutsTest)
8030a90a852SMatt Spinler {
8040a90a852SMatt Spinler message::Entry regEntry;
8050a90a852SMatt Spinler uint64_t timestamp = 5;
8060a90a852SMatt Spinler
8070a90a852SMatt Spinler regEntry.name = "test";
8080a90a852SMatt Spinler regEntry.subsystem = 5;
8090a90a852SMatt Spinler regEntry.actionFlags = 0xC000;
8100a90a852SMatt Spinler regEntry.src.type = 0xBD;
8110a90a852SMatt Spinler regEntry.src.reasonCode = 0x1234;
8120a90a852SMatt Spinler
8130a90a852SMatt Spinler NiceMock<MockDataInterface> dataIface;
8149d921096SMatt Spinler NiceMock<MockJournal> journal;
8150a90a852SMatt Spinler PelFFDC ffdc;
8160a90a852SMatt Spinler
8170a90a852SMatt Spinler const auto calloutJSON = R"(
8180a90a852SMatt Spinler {
8190a90a852SMatt Spinler "I2C":
8200a90a852SMatt Spinler {
8210a90a852SMatt Spinler "14":
8220a90a852SMatt Spinler {
8230a90a852SMatt Spinler "114":
8240a90a852SMatt Spinler {
8250a90a852SMatt Spinler "Callouts":[
8260a90a852SMatt Spinler {
8270a90a852SMatt Spinler "Name": "/chassis/motherboard/cpu0",
8280a90a852SMatt Spinler "LocationCode": "P1",
8290a90a852SMatt Spinler "Priority": "H"
8300a90a852SMatt Spinler }
8310a90a852SMatt Spinler ],
8320a90a852SMatt Spinler "Dest": "proc 0 target"
8330a90a852SMatt Spinler }
8340a90a852SMatt Spinler }
8350a90a852SMatt Spinler }
8360a90a852SMatt Spinler })";
8370a90a852SMatt Spinler
8380a90a852SMatt Spinler std::vector<std::string> names{"systemA"};
8390a90a852SMatt Spinler EXPECT_CALL(dataIface, getSystemNames)
8400a90a852SMatt Spinler .Times(2)
8411ab6696fSMatt Spinler .WillRepeatedly(Return(names));
8420a90a852SMatt Spinler
8430d92b528SMatt Spinler EXPECT_CALL(dataIface, expandLocationCode("P1", 0))
8440d92b528SMatt Spinler .Times(1)
8450a90a852SMatt Spinler .WillOnce(Return("UXXX-P1"));
8460a90a852SMatt Spinler
8472f9225a4SMatt Spinler EXPECT_CALL(dataIface, getInventoryFromLocCode("P1", 0, false))
848bad056beSMatt Spinler .WillOnce(Return(std::vector<std::string>{
849bad056beSMatt Spinler "/xyz/openbmc_project/inventory/chassis/motherboard/cpu0"}));
8500a90a852SMatt Spinler
851075c7923SPatrick Williams EXPECT_CALL(dataIface,
8520a90a852SMatt Spinler getHWCalloutFields(
853075c7923SPatrick Williams "/xyz/openbmc_project/inventory/chassis/motherboard/cpu0",
854075c7923SPatrick Williams _, _, _))
8550a90a852SMatt Spinler .WillOnce(DoAll(SetArgReferee<1>("1234567"), SetArgReferee<2>("CCCC"),
8560a90a852SMatt Spinler SetArgReferee<3>("123456789ABC")));
8570a90a852SMatt Spinler
8580a90a852SMatt Spinler auto dataPath = getPELReadOnlyDataPath();
8590a90a852SMatt Spinler std::ofstream file{dataPath / "systemA_dev_callouts.json"};
8600a90a852SMatt Spinler file << calloutJSON;
8610a90a852SMatt Spinler file.close();
8620a90a852SMatt Spinler
8630a90a852SMatt Spinler {
864*e5940634SPatrick Williams std::map<std::string, std::string> data{
865*e5940634SPatrick Williams {"CALLOUT_ERRNO", "5"},
866*e5940634SPatrick Williams {"CALLOUT_DEVICE_PATH",
867*e5940634SPatrick Williams "/sys/devices/platform/ahb/ahb:apb/ahb:apb:bus@1e78a000/1e78a340.i2c-bus/i2c-14/14-0072"}};
8680a90a852SMatt Spinler
8690a90a852SMatt Spinler AdditionalData ad{data};
8700a90a852SMatt Spinler
871075c7923SPatrick Williams PEL pel{regEntry, 42,
872075c7923SPatrick Williams timestamp, phosphor::logging::Entry::Level::Error,
873075c7923SPatrick Williams ad, ffdc,
874075c7923SPatrick Williams dataIface, journal};
8750a90a852SMatt Spinler
8760a90a852SMatt Spinler ASSERT_TRUE(pel.primarySRC().value()->callouts());
8770a90a852SMatt Spinler auto& callouts = pel.primarySRC().value()->callouts()->callouts();
8780a90a852SMatt Spinler ASSERT_EQ(callouts.size(), 1);
879f8e750ddSAndrew Geissler ASSERT_TRUE(pel.isHwCalloutPresent());
8800a90a852SMatt Spinler
8810a90a852SMatt Spinler EXPECT_EQ(callouts[0]->priority(), 'H');
8820a90a852SMatt Spinler EXPECT_EQ(callouts[0]->locationCode(), "UXXX-P1");
8830a90a852SMatt Spinler
8840a90a852SMatt Spinler auto& fru = callouts[0]->fruIdentity();
8850a90a852SMatt Spinler EXPECT_EQ(fru->getPN().value(), "1234567");
8860a90a852SMatt Spinler EXPECT_EQ(fru->getCCIN().value(), "CCCC");
8870a90a852SMatt Spinler EXPECT_EQ(fru->getSN().value(), "123456789ABC");
8880a90a852SMatt Spinler
8890a90a852SMatt Spinler const auto& section = pel.optionalSections().back();
8900a90a852SMatt Spinler
8910a90a852SMatt Spinler ASSERT_EQ(section->header().id, 0x5544); // UD
8920a90a852SMatt Spinler auto ud = static_cast<UserData*>(section.get());
8930a90a852SMatt Spinler
8940a90a852SMatt Spinler // Check that there was a UserData section added that
8950a90a852SMatt Spinler // contains debug details about the device.
8960a90a852SMatt Spinler const auto& d = ud->data();
8970a90a852SMatt Spinler std::string jsonString{d.begin(), d.end()};
8980a90a852SMatt Spinler auto actualJSON = nlohmann::json::parse(jsonString);
8990a90a852SMatt Spinler
9000a90a852SMatt Spinler auto expectedJSON = R"(
9010a90a852SMatt Spinler {
9020a90a852SMatt Spinler "PEL Internal Debug Data": {
9030a90a852SMatt Spinler "SRC": [
9040a90a852SMatt Spinler "I2C: bus: 14 address: 114 dest: proc 0 target"
9050a90a852SMatt Spinler ]
9060a90a852SMatt Spinler }
9070a90a852SMatt Spinler }
9080a90a852SMatt Spinler )"_json;
9090a90a852SMatt Spinler
910d8ae618aSArya K Padman EXPECT_TRUE(
911d8ae618aSArya K Padman actualJSON.contains("/PEL Internal Debug Data/SRC"_json_pointer));
912d8ae618aSArya K Padman EXPECT_EQ(actualJSON["PEL Internal Debug Data"]["SRC"],
913d8ae618aSArya K Padman expectedJSON["PEL Internal Debug Data"]["SRC"]);
9140a90a852SMatt Spinler }
9150a90a852SMatt Spinler
9160a90a852SMatt Spinler {
9170a90a852SMatt Spinler // Device path not found (wrong i2c addr), so no callouts
918*e5940634SPatrick Williams std::map<std::string, std::string> data{
919*e5940634SPatrick Williams {"CALLOUT_ERRNO", "5"},
920*e5940634SPatrick Williams {"CALLOUT_DEVICE_PATH",
921*e5940634SPatrick Williams "/sys/devices/platform/ahb/ahb:apb/ahb:apb:bus@1e78a000/1e78a340.i2c-bus/i2c-14/14-0099"}};
9220a90a852SMatt Spinler
9230a90a852SMatt Spinler AdditionalData ad{data};
9240a90a852SMatt Spinler
925075c7923SPatrick Williams PEL pel{regEntry, 42,
926075c7923SPatrick Williams timestamp, phosphor::logging::Entry::Level::Error,
927075c7923SPatrick Williams ad, ffdc,
928075c7923SPatrick Williams dataIface, journal};
9290a90a852SMatt Spinler
9300a90a852SMatt Spinler // no callouts
9310a90a852SMatt Spinler EXPECT_FALSE(pel.primarySRC().value()->callouts());
9320a90a852SMatt Spinler
9330a90a852SMatt Spinler // Now check that there was a UserData section
9340a90a852SMatt Spinler // that contains the lookup error.
9350a90a852SMatt Spinler const auto& section = pel.optionalSections().back();
9360a90a852SMatt Spinler
9370a90a852SMatt Spinler ASSERT_EQ(section->header().id, 0x5544); // UD
9380a90a852SMatt Spinler auto ud = static_cast<UserData*>(section.get());
9390a90a852SMatt Spinler
9400a90a852SMatt Spinler const auto& d = ud->data();
9410a90a852SMatt Spinler
9420a90a852SMatt Spinler std::string jsonString{d.begin(), d.end()};
9430a90a852SMatt Spinler
9440a90a852SMatt Spinler auto actualJSON = nlohmann::json::parse(jsonString);
9450a90a852SMatt Spinler
9460a90a852SMatt Spinler auto expectedJSON =
9470a90a852SMatt Spinler "{\"PEL Internal Debug Data\":{\"SRC\":"
9480a90a852SMatt Spinler "[\"Problem looking up I2C callouts on 14 153: "
9490a90a852SMatt Spinler "[json.exception.out_of_range.403] key '153' not found\"]}}"_json;
9500a90a852SMatt Spinler
951d8ae618aSArya K Padman EXPECT_TRUE(
952d8ae618aSArya K Padman actualJSON.contains("/PEL Internal Debug Data/SRC"_json_pointer));
953d8ae618aSArya K Padman EXPECT_EQ(actualJSON["PEL Internal Debug Data"]["SRC"],
954d8ae618aSArya K Padman expectedJSON["PEL Internal Debug Data"]["SRC"]);
9550a90a852SMatt Spinler }
9560a90a852SMatt Spinler
9570a90a852SMatt Spinler fs::remove_all(dataPath);
9580a90a852SMatt Spinler }
959e513dbc4SMatt Spinler
960e513dbc4SMatt Spinler // Test PELs when the callouts are passed in using a JSON file.
TEST_F(PELTest,CreateWithJSONCalloutsTest)961e513dbc4SMatt Spinler TEST_F(PELTest, CreateWithJSONCalloutsTest)
962e513dbc4SMatt Spinler {
963e513dbc4SMatt Spinler PelFFDCfile ffdcFile;
964e513dbc4SMatt Spinler ffdcFile.format = UserDataFormat::json;
965e513dbc4SMatt Spinler ffdcFile.subType = 0xCA; // Callout JSON
966e513dbc4SMatt Spinler ffdcFile.version = 1;
967e513dbc4SMatt Spinler
968e513dbc4SMatt Spinler // Write these callouts to a JSON file and pass it into
9694efed0efSMatt Spinler // the PEL as an FFDC file. Also has a duplicate that
9704efed0efSMatt Spinler // will be removed.
971e513dbc4SMatt Spinler auto inputJSON = R"([
972e513dbc4SMatt Spinler {
973e513dbc4SMatt Spinler "Priority": "H",
974e513dbc4SMatt Spinler "LocationCode": "P0-C1"
975e513dbc4SMatt Spinler },
976e513dbc4SMatt Spinler {
977e513dbc4SMatt Spinler "Priority": "M",
978e513dbc4SMatt Spinler "Procedure": "PROCEDURE"
9794efed0efSMatt Spinler },
9804efed0efSMatt Spinler {
9814efed0efSMatt Spinler "Priority": "L",
9824efed0efSMatt Spinler "Procedure": "PROCEDURE"
983e513dbc4SMatt Spinler }
984e513dbc4SMatt Spinler ])"_json;
985e513dbc4SMatt Spinler
986e513dbc4SMatt Spinler auto s = inputJSON.dump();
987e513dbc4SMatt Spinler std::vector<uint8_t> data{s.begin(), s.end()};
988e513dbc4SMatt Spinler auto dir = makeTempDir();
989e513dbc4SMatt Spinler ffdcFile.fd = writeFileAndGetFD(dir, data);
990e513dbc4SMatt Spinler
991e513dbc4SMatt Spinler PelFFDC ffdc;
992e513dbc4SMatt Spinler ffdc.push_back(std::move(ffdcFile));
993e513dbc4SMatt Spinler
994e513dbc4SMatt Spinler AdditionalData ad;
995e513dbc4SMatt Spinler NiceMock<MockDataInterface> dataIface;
9969d921096SMatt Spinler NiceMock<MockJournal> journal;
997e513dbc4SMatt Spinler
998e513dbc4SMatt Spinler EXPECT_CALL(dataIface, expandLocationCode("P0-C1", 0))
999e513dbc4SMatt Spinler .Times(1)
1000e513dbc4SMatt Spinler .WillOnce(Return("UXXX-P0-C1"));
1001e513dbc4SMatt Spinler EXPECT_CALL(dataIface, getInventoryFromLocCode("P0-C1", 0, false))
1002e513dbc4SMatt Spinler .Times(1)
1003bad056beSMatt Spinler .WillOnce(Return(
1004bad056beSMatt Spinler std::vector<std::string>{"/inv/system/chassis/motherboard/bmc"}));
1005e513dbc4SMatt Spinler EXPECT_CALL(dataIface, getHWCalloutFields(
1006e513dbc4SMatt Spinler "/inv/system/chassis/motherboard/bmc", _, _, _))
1007e513dbc4SMatt Spinler .Times(1)
1008e513dbc4SMatt Spinler .WillOnce(DoAll(SetArgReferee<1>("1234567"), SetArgReferee<2>("CCCC"),
1009e513dbc4SMatt Spinler SetArgReferee<3>("123456789ABC")));
1010e513dbc4SMatt Spinler
1011e513dbc4SMatt Spinler message::Entry regEntry;
1012e513dbc4SMatt Spinler regEntry.name = "test";
1013e513dbc4SMatt Spinler regEntry.subsystem = 5;
1014e513dbc4SMatt Spinler regEntry.actionFlags = 0xC000;
1015e513dbc4SMatt Spinler regEntry.src.type = 0xBD;
1016e513dbc4SMatt Spinler regEntry.src.reasonCode = 0x1234;
1017e513dbc4SMatt Spinler
1018e513dbc4SMatt Spinler PEL pel{regEntry, 42, 5, phosphor::logging::Entry::Level::Error,
10199d921096SMatt Spinler ad, ffdc, dataIface, journal};
1020e513dbc4SMatt Spinler
1021e513dbc4SMatt Spinler ASSERT_TRUE(pel.valid());
1022e513dbc4SMatt Spinler ASSERT_TRUE(pel.primarySRC().value()->callouts());
1023e513dbc4SMatt Spinler const auto& callouts = pel.primarySRC().value()->callouts()->callouts();
1024e513dbc4SMatt Spinler ASSERT_EQ(callouts.size(), 2);
1025f8e750ddSAndrew Geissler ASSERT_TRUE(pel.isHwCalloutPresent());
1026e513dbc4SMatt Spinler
1027e513dbc4SMatt Spinler {
1028e513dbc4SMatt Spinler EXPECT_EQ(callouts[0]->priority(), 'H');
1029e513dbc4SMatt Spinler EXPECT_EQ(callouts[0]->locationCode(), "UXXX-P0-C1");
1030e513dbc4SMatt Spinler
1031e513dbc4SMatt Spinler auto& fru = callouts[0]->fruIdentity();
1032e513dbc4SMatt Spinler EXPECT_EQ(fru->getPN().value(), "1234567");
1033e513dbc4SMatt Spinler EXPECT_EQ(fru->getCCIN().value(), "CCCC");
1034e513dbc4SMatt Spinler EXPECT_EQ(fru->getSN().value(), "123456789ABC");
1035e513dbc4SMatt Spinler EXPECT_EQ(fru->failingComponentType(), src::FRUIdentity::hardwareFRU);
1036e513dbc4SMatt Spinler }
1037e513dbc4SMatt Spinler {
1038e513dbc4SMatt Spinler EXPECT_EQ(callouts[1]->priority(), 'M');
1039e513dbc4SMatt Spinler EXPECT_EQ(callouts[1]->locationCode(), "");
1040e513dbc4SMatt Spinler
1041e513dbc4SMatt Spinler auto& fru = callouts[1]->fruIdentity();
1042e513dbc4SMatt Spinler EXPECT_EQ(fru->getMaintProc().value(), "PROCEDU");
1043e513dbc4SMatt Spinler EXPECT_EQ(fru->failingComponentType(),
1044e513dbc4SMatt Spinler src::FRUIdentity::maintenanceProc);
1045e513dbc4SMatt Spinler }
1046e513dbc4SMatt Spinler fs::remove_all(dir);
1047e513dbc4SMatt Spinler }
1048f8e750ddSAndrew Geissler
1049f8e750ddSAndrew Geissler // Test PELs with symblic FRU callout.
TEST_F(PELTest,CreateWithJSONSymblicCalloutTest)1050f8e750ddSAndrew Geissler TEST_F(PELTest, CreateWithJSONSymblicCalloutTest)
1051f8e750ddSAndrew Geissler {
1052f8e750ddSAndrew Geissler PelFFDCfile ffdcFile;
1053f8e750ddSAndrew Geissler ffdcFile.format = UserDataFormat::json;
1054f8e750ddSAndrew Geissler ffdcFile.subType = 0xCA; // Callout JSON
1055f8e750ddSAndrew Geissler ffdcFile.version = 1;
1056f8e750ddSAndrew Geissler
1057f8e750ddSAndrew Geissler // Write these callouts to a JSON file and pass it into
1058f8e750ddSAndrew Geissler // the PEL as an FFDC file.
1059f8e750ddSAndrew Geissler auto inputJSON = R"([
1060f8e750ddSAndrew Geissler {
1061f8e750ddSAndrew Geissler "Priority": "M",
1062f8e750ddSAndrew Geissler "Procedure": "SVCDOCS"
1063f8e750ddSAndrew Geissler }
1064f8e750ddSAndrew Geissler ])"_json;
1065f8e750ddSAndrew Geissler
1066f8e750ddSAndrew Geissler auto s = inputJSON.dump();
1067f8e750ddSAndrew Geissler std::vector<uint8_t> data{s.begin(), s.end()};
1068f8e750ddSAndrew Geissler auto dir = makeTempDir();
1069f8e750ddSAndrew Geissler ffdcFile.fd = writeFileAndGetFD(dir, data);
1070f8e750ddSAndrew Geissler
1071f8e750ddSAndrew Geissler PelFFDC ffdc;
1072f8e750ddSAndrew Geissler ffdc.push_back(std::move(ffdcFile));
1073f8e750ddSAndrew Geissler
1074f8e750ddSAndrew Geissler AdditionalData ad;
1075f8e750ddSAndrew Geissler NiceMock<MockDataInterface> dataIface;
10769d921096SMatt Spinler NiceMock<MockJournal> journal;
1077f8e750ddSAndrew Geissler
1078f8e750ddSAndrew Geissler message::Entry regEntry;
1079f8e750ddSAndrew Geissler regEntry.name = "test";
1080f8e750ddSAndrew Geissler regEntry.subsystem = 5;
1081f8e750ddSAndrew Geissler regEntry.actionFlags = 0xC000;
1082f8e750ddSAndrew Geissler regEntry.src.type = 0xBD;
1083f8e750ddSAndrew Geissler regEntry.src.reasonCode = 0x1234;
1084f8e750ddSAndrew Geissler
1085f8e750ddSAndrew Geissler PEL pel{regEntry, 42, 5, phosphor::logging::Entry::Level::Error,
10869d921096SMatt Spinler ad, ffdc, dataIface, journal};
1087f8e750ddSAndrew Geissler
1088f8e750ddSAndrew Geissler ASSERT_TRUE(pel.valid());
1089f8e750ddSAndrew Geissler ASSERT_TRUE(pel.primarySRC().value()->callouts());
1090f8e750ddSAndrew Geissler const auto& callouts = pel.primarySRC().value()->callouts()->callouts();
1091f8e750ddSAndrew Geissler ASSERT_EQ(callouts.size(), 1);
1092f8e750ddSAndrew Geissler ASSERT_FALSE(pel.isHwCalloutPresent());
1093f8e750ddSAndrew Geissler
1094f8e750ddSAndrew Geissler {
1095f8e750ddSAndrew Geissler EXPECT_EQ(callouts[0]->priority(), 'M');
1096f8e750ddSAndrew Geissler EXPECT_EQ(callouts[0]->locationCode(), "");
1097f8e750ddSAndrew Geissler
1098f8e750ddSAndrew Geissler auto& fru = callouts[0]->fruIdentity();
1099f8e750ddSAndrew Geissler EXPECT_EQ(fru->getMaintProc().value(), "SVCDOCS");
1100f8e750ddSAndrew Geissler }
1101f8e750ddSAndrew Geissler fs::remove_all(dir);
1102f8e750ddSAndrew Geissler }
11039d921096SMatt Spinler
TEST_F(PELTest,FlattenLinesTest)11049d921096SMatt Spinler TEST_F(PELTest, FlattenLinesTest)
11059d921096SMatt Spinler {
11069d921096SMatt Spinler std::vector<std::string> msgs{"test1 test2", "test3 test4", "test5 test6"};
11079d921096SMatt Spinler
11089d921096SMatt Spinler auto buffer = util::flattenLines(msgs);
11099d921096SMatt Spinler
11109d921096SMatt Spinler std::string string{"test1 test2\ntest3 test4\ntest5 test6\n"};
11119d921096SMatt Spinler std::vector<uint8_t> expected(string.begin(), string.end());
11129d921096SMatt Spinler
11139d921096SMatt Spinler EXPECT_EQ(buffer, expected);
11149d921096SMatt Spinler }
11159d921096SMatt Spinler
checkJournalSection(const std::unique_ptr<Section> & section,const std::string & expected)11169d921096SMatt Spinler void checkJournalSection(const std::unique_ptr<Section>& section,
11179d921096SMatt Spinler const std::string& expected)
11189d921096SMatt Spinler {
11199d921096SMatt Spinler ASSERT_EQ(SectionID::userData,
11209d921096SMatt Spinler static_cast<SectionID>(section->header().id));
11219d921096SMatt Spinler ASSERT_EQ(UserDataFormat::text,
11229d921096SMatt Spinler static_cast<UserDataFormat>(section->header().subType));
11239d921096SMatt Spinler ASSERT_EQ(section->header().version,
11249d921096SMatt Spinler static_cast<uint8_t>(UserDataFormatVersion::text));
11259d921096SMatt Spinler
11269d921096SMatt Spinler auto ud = static_cast<UserData*>(section.get());
11279d921096SMatt Spinler
11289d921096SMatt Spinler std::vector<uint8_t> expectedData(expected.begin(), expected.end());
11299d921096SMatt Spinler
11309d921096SMatt Spinler // PEL sections are 4B aligned so add padding before the compare
11319d921096SMatt Spinler while (expectedData.size() % 4 != 0)
11329d921096SMatt Spinler {
11339d921096SMatt Spinler expectedData.push_back('\0');
11349d921096SMatt Spinler }
11359d921096SMatt Spinler
11369d921096SMatt Spinler EXPECT_EQ(ud->data(), expectedData);
11379d921096SMatt Spinler }
11389d921096SMatt Spinler
TEST_F(PELTest,CaptureJournalTest)11399d921096SMatt Spinler TEST_F(PELTest, CaptureJournalTest)
11409d921096SMatt Spinler {
11419d921096SMatt Spinler message::Entry regEntry;
11429d921096SMatt Spinler uint64_t timestamp = 5;
11439d921096SMatt Spinler
11449d921096SMatt Spinler regEntry.name = "test";
11459d921096SMatt Spinler regEntry.subsystem = 5;
11469d921096SMatt Spinler regEntry.actionFlags = 0xC000;
11479d921096SMatt Spinler regEntry.src.type = 0xBD;
11489d921096SMatt Spinler regEntry.src.reasonCode = 0x1234;
11499d921096SMatt Spinler
1150*e5940634SPatrick Williams std::map<std::string, std::string> data{};
11519d921096SMatt Spinler AdditionalData ad{data};
11529d921096SMatt Spinler NiceMock<MockDataInterface> dataIface;
11539d921096SMatt Spinler NiceMock<MockJournal> journal;
11549d921096SMatt Spinler PelFFDC ffdc;
11559d921096SMatt Spinler
11569d921096SMatt Spinler size_t pelSectsWithOneUD{0};
11579d921096SMatt Spinler
11589d921096SMatt Spinler {
11599d921096SMatt Spinler // Capture 5 lines from the journal into a single UD section
11609d921096SMatt Spinler message::JournalCapture jc = size_t{5};
11619d921096SMatt Spinler regEntry.journalCapture = jc;
11629d921096SMatt Spinler
11639d921096SMatt Spinler std::vector<std::string> msgs{"test1 test2", "test3 test4",
11649d921096SMatt Spinler "test5 test6", "4", "5"};
11659d921096SMatt Spinler
11669d921096SMatt Spinler EXPECT_CALL(journal, getMessages("", 5)).WillOnce(Return(msgs));
11679d921096SMatt Spinler
1168075c7923SPatrick Williams PEL pel{regEntry, 42,
1169075c7923SPatrick Williams timestamp, phosphor::logging::Entry::Level::Error,
1170075c7923SPatrick Williams ad, ffdc,
1171075c7923SPatrick Williams dataIface, journal};
11729d921096SMatt Spinler
11739d921096SMatt Spinler // Check the generated UserData section
11749d921096SMatt Spinler std::string expected{"test1 test2\ntest3 test4\ntest5 test6\n4\n5\n"};
11759d921096SMatt Spinler
11769d921096SMatt Spinler checkJournalSection(pel.optionalSections().back(), expected);
11779d921096SMatt Spinler
11789d921096SMatt Spinler // Save for upcoming testcases
11799d921096SMatt Spinler pelSectsWithOneUD = pel.privateHeader().sectionCount();
11809d921096SMatt Spinler }
11819d921096SMatt Spinler
11829d921096SMatt Spinler {
11839d921096SMatt Spinler // Attempt to capture too many journal entries so the
11849d921096SMatt Spinler // section gets dropped.
11859d921096SMatt Spinler message::JournalCapture jc = size_t{1};
11869d921096SMatt Spinler regEntry.journalCapture = jc;
11879d921096SMatt Spinler
11889d921096SMatt Spinler EXPECT_CALL(journal, sync()).Times(1);
11899d921096SMatt Spinler
11909d921096SMatt Spinler // A 20000 byte line won't fit in a PEL
11919d921096SMatt Spinler EXPECT_CALL(journal, getMessages("", 1))
11929d921096SMatt Spinler .WillOnce(
11939d921096SMatt Spinler Return(std::vector<std::string>{std::string(20000, 'x')}));
11949d921096SMatt Spinler
1195075c7923SPatrick Williams PEL pel{regEntry, 42,
1196075c7923SPatrick Williams timestamp, phosphor::logging::Entry::Level::Error,
1197075c7923SPatrick Williams ad, ffdc,
1198075c7923SPatrick Williams dataIface, journal};
11999d921096SMatt Spinler
12009d921096SMatt Spinler // Check for 1 fewer sections than in the previous PEL
12019d921096SMatt Spinler EXPECT_EQ(pel.privateHeader().sectionCount(), pelSectsWithOneUD - 1);
12029d921096SMatt Spinler }
12039d921096SMatt Spinler
12049d921096SMatt Spinler // Capture 3 different journal sections
12059d921096SMatt Spinler {
12069d921096SMatt Spinler message::AppCaptureList captureList{
12079d921096SMatt Spinler message::AppCapture{"app1", 3},
12089d921096SMatt Spinler message::AppCapture{"app2", 4},
12099d921096SMatt Spinler message::AppCapture{"app3", 1},
12109d921096SMatt Spinler };
12119d921096SMatt Spinler message::JournalCapture jc = captureList;
12129d921096SMatt Spinler regEntry.journalCapture = jc;
12139d921096SMatt Spinler
12149d921096SMatt Spinler std::vector<std::string> app1{"A B", "C D", "E F"};
12159d921096SMatt Spinler std::vector<std::string> app2{"1 2", "3 4", "5 6", "7 8"};
12169d921096SMatt Spinler std::vector<std::string> app3{"a b c"};
12179d921096SMatt Spinler
12189d921096SMatt Spinler std::string expected1{"A B\nC D\nE F\n"};
12199d921096SMatt Spinler std::string expected2{"1 2\n3 4\n5 6\n7 8\n"};
12209d921096SMatt Spinler std::string expected3{"a b c\n"};
12219d921096SMatt Spinler
12229d921096SMatt Spinler EXPECT_CALL(journal, sync()).Times(1);
12239d921096SMatt Spinler EXPECT_CALL(journal, getMessages("app1", 3)).WillOnce(Return(app1));
12249d921096SMatt Spinler EXPECT_CALL(journal, getMessages("app2", 4)).WillOnce(Return(app2));
12259d921096SMatt Spinler EXPECT_CALL(journal, getMessages("app3", 1)).WillOnce(Return(app3));
12269d921096SMatt Spinler
1227075c7923SPatrick Williams PEL pel{regEntry, 42,
1228075c7923SPatrick Williams timestamp, phosphor::logging::Entry::Level::Error,
1229075c7923SPatrick Williams ad, ffdc,
1230075c7923SPatrick Williams dataIface, journal};
12319d921096SMatt Spinler
1232*e5940634SPatrick Williams // Two more sections than the 1 extra UD section in the first
1233*e5940634SPatrick Williams // testcase
12349d921096SMatt Spinler ASSERT_EQ(pel.privateHeader().sectionCount(), pelSectsWithOneUD + 2);
12359d921096SMatt Spinler
12369d921096SMatt Spinler const auto& optionalSections = pel.optionalSections();
12379d921096SMatt Spinler auto numOptSections = optionalSections.size();
12389d921096SMatt Spinler
12399d921096SMatt Spinler checkJournalSection(optionalSections[numOptSections - 3], expected1);
12409d921096SMatt Spinler checkJournalSection(optionalSections[numOptSections - 2], expected2);
12419d921096SMatt Spinler checkJournalSection(optionalSections[numOptSections - 1], expected3);
12429d921096SMatt Spinler }
12439d921096SMatt Spinler
12449d921096SMatt Spinler {
12459d921096SMatt Spinler // One section gets saved, and one is too big and gets dropped
12469d921096SMatt Spinler message::AppCaptureList captureList{
12479d921096SMatt Spinler message::AppCapture{"app4", 2},
12489d921096SMatt Spinler message::AppCapture{"app5", 1},
12499d921096SMatt Spinler };
12509d921096SMatt Spinler message::JournalCapture jc = captureList;
12519d921096SMatt Spinler regEntry.journalCapture = jc;
12529d921096SMatt Spinler
12539d921096SMatt Spinler std::vector<std::string> app4{"w x", "y z"};
12549d921096SMatt Spinler std::string expected4{"w x\ny z\n"};
12559d921096SMatt Spinler
12569d921096SMatt Spinler EXPECT_CALL(journal, sync()).Times(1);
12579d921096SMatt Spinler
12589d921096SMatt Spinler EXPECT_CALL(journal, getMessages("app4", 2)).WillOnce(Return(app4));
12599d921096SMatt Spinler
12609d921096SMatt Spinler // A 20000 byte line won't fit in a PEL
12619d921096SMatt Spinler EXPECT_CALL(journal, getMessages("app5", 1))
12629d921096SMatt Spinler .WillOnce(
12639d921096SMatt Spinler Return(std::vector<std::string>{std::string(20000, 'x')}));
12649d921096SMatt Spinler
1265075c7923SPatrick Williams PEL pel{regEntry, 42,
1266075c7923SPatrick Williams timestamp, phosphor::logging::Entry::Level::Error,
1267075c7923SPatrick Williams ad, ffdc,
1268075c7923SPatrick Williams dataIface, journal};
12699d921096SMatt Spinler
12709d921096SMatt Spinler // The last section should have been dropped, so same as first TC
12719d921096SMatt Spinler ASSERT_EQ(pel.privateHeader().sectionCount(), pelSectsWithOneUD);
12729d921096SMatt Spinler
12739d921096SMatt Spinler checkJournalSection(pel.optionalSections().back(), expected4);
12749d921096SMatt Spinler }
12759d921096SMatt Spinler }
1276d8ae618aSArya K Padman
1277d8ae618aSArya K Padman // API to collect and parse the User Data section of the PEL.
getDIMMInfo(const auto & pel)1278d8ae618aSArya K Padman nlohmann::json getDIMMInfo(const auto& pel)
1279d8ae618aSArya K Padman {
1280d8ae618aSArya K Padman nlohmann::json dimmInfo{};
1281d8ae618aSArya K Padman auto hasDIMMInfo = [&dimmInfo](const auto& optionalSection) {
1282d8ae618aSArya K Padman if (optionalSection->header().id !=
1283d8ae618aSArya K Padman static_cast<uint16_t>(SectionID::userData))
1284d8ae618aSArya K Padman {
1285d8ae618aSArya K Padman return false;
1286d8ae618aSArya K Padman }
1287d8ae618aSArya K Padman else
1288d8ae618aSArya K Padman {
1289d8ae618aSArya K Padman auto userData = static_cast<UserData*>(optionalSection.get());
1290d8ae618aSArya K Padman
1291*e5940634SPatrick Williams // convert the userdata section to string and then parse in to
1292*e5940634SPatrick Williams // json format
1293d8ae618aSArya K Padman std::string userDataString{userData->data().begin(),
1294d8ae618aSArya K Padman userData->data().end()};
1295d8ae618aSArya K Padman nlohmann::json userDataJson = nlohmann::json::parse(userDataString);
1296d8ae618aSArya K Padman
1297d8ae618aSArya K Padman if (userDataJson.contains("DIMMs Additional Info"))
1298d8ae618aSArya K Padman {
1299d8ae618aSArya K Padman dimmInfo = userDataJson.at("DIMMs Additional Info");
1300d8ae618aSArya K Padman }
1301d8ae618aSArya K Padman else if (
1302d8ae618aSArya K Padman userDataJson.contains(
1303d8ae618aSArya K Padman "/PEL Internal Debug Data/DIMMs Info Fetch Error"_json_pointer))
1304d8ae618aSArya K Padman {
1305d8ae618aSArya K Padman dimmInfo = userDataJson.at(
1306d8ae618aSArya K Padman "/PEL Internal Debug Data/DIMMs Info Fetch Error"_json_pointer);
1307d8ae618aSArya K Padman }
1308d8ae618aSArya K Padman else
1309d8ae618aSArya K Padman {
1310d8ae618aSArya K Padman return false;
1311d8ae618aSArya K Padman }
1312d8ae618aSArya K Padman return true;
1313d8ae618aSArya K Padman }
1314d8ae618aSArya K Padman };
1315d8ae618aSArya K Padman std::ranges::any_of(pel.optionalSections(), hasDIMMInfo);
1316d8ae618aSArya K Padman
1317d8ae618aSArya K Padman return dimmInfo;
1318d8ae618aSArya K Padman }
1319d8ae618aSArya K Padman
1320d8ae618aSArya K Padman // Test whether the DIMM callouts manufacturing info is getting added to the
1321d8ae618aSArya K Padman // SysInfo User Data section of the PEL
TEST_F(PELTest,TestDimmsCalloutInfo)1322d8ae618aSArya K Padman TEST_F(PELTest, TestDimmsCalloutInfo)
1323d8ae618aSArya K Padman {
1324d8ae618aSArya K Padman {
1325d8ae618aSArya K Padman message::Entry entry;
1326d8ae618aSArya K Padman uint64_t timestamp = 5;
1327d8ae618aSArya K Padman AdditionalData ad;
1328d8ae618aSArya K Padman NiceMock<MockDataInterface> dataIface;
1329d8ae618aSArya K Padman NiceMock<MockJournal> journal;
1330d8ae618aSArya K Padman PelFFDC ffdc;
1331d8ae618aSArya K Padman
1332d8ae618aSArya K Padman // When callouts contain DIMM callouts.
1333d8ae618aSArya K Padman entry.callouts = R"(
1334d8ae618aSArya K Padman [
1335d8ae618aSArya K Padman {
1336d8ae618aSArya K Padman "CalloutList": [
1337d8ae618aSArya K Padman {
1338d8ae618aSArya K Padman "Priority": "high",
1339d8ae618aSArya K Padman "LocCode": "P0-DIMM0"
1340d8ae618aSArya K Padman },
1341d8ae618aSArya K Padman {
1342d8ae618aSArya K Padman "Priority": "low",
1343d8ae618aSArya K Padman "LocCode": "P0-DIMM1"
1344d8ae618aSArya K Padman }
1345d8ae618aSArya K Padman ]
1346d8ae618aSArya K Padman }
1347d8ae618aSArya K Padman ]
1348d8ae618aSArya K Padman )"_json;
1349d8ae618aSArya K Padman
1350d8ae618aSArya K Padman EXPECT_CALL(dataIface, expandLocationCode("P0-DIMM0", 0))
1351d8ae618aSArya K Padman .WillOnce(Return("U98D-P0-DIMM0"));
1352d8ae618aSArya K Padman EXPECT_CALL(dataIface, expandLocationCode("P0-DIMM1", 0))
1353d8ae618aSArya K Padman .WillOnce(Return("U98D-P0-DIMM1"));
1354d8ae618aSArya K Padman
1355d8ae618aSArya K Padman EXPECT_CALL(dataIface, getInventoryFromLocCode("P0-DIMM0", 0, false))
1356d8ae618aSArya K Padman .WillOnce(Return(std::vector<std::string>{
1357d8ae618aSArya K Padman "/xyz/openbmc_project/inventory/system/chassis/motherboard/dimm0"}));
1358d8ae618aSArya K Padman EXPECT_CALL(dataIface, getInventoryFromLocCode("P0-DIMM1", 0, false))
1359d8ae618aSArya K Padman .WillOnce(Return(std::vector<std::string>{
1360d8ae618aSArya K Padman "/xyz/openbmc_project/inventory/system/chassis/motherboard/dimm1"}));
1361d8ae618aSArya K Padman
1362d8ae618aSArya K Padman std::vector<uint8_t> diValue{128, 74};
1363d8ae618aSArya K Padman EXPECT_CALL(dataIface, getDIProperty("U98D-P0-DIMM0"))
1364d8ae618aSArya K Padman .WillOnce(Return(diValue));
1365d8ae618aSArya K Padman EXPECT_CALL(dataIface, getDIProperty("U98D-P0-DIMM1"))
1366d8ae618aSArya K Padman .WillOnce(Return(diValue));
1367d8ae618aSArya K Padman
1368d8ae618aSArya K Padman // Add some location code in expanded format to DIMM cache memory
1369d8ae618aSArya K Padman dataIface.addDIMMLocCode("U98D-P0-DIMM0", true);
1370d8ae618aSArya K Padman dataIface.addDIMMLocCode("U98D-P0-DIMM1", true);
1371d8ae618aSArya K Padman
1372d8ae618aSArya K Padman PEL pel{entry, 42, timestamp, phosphor::logging::Entry::Level::Error,
1373d8ae618aSArya K Padman ad, ffdc, dataIface, journal};
1374d8ae618aSArya K Padman nlohmann::json dimmInfoJson = getDIMMInfo(pel);
1375d8ae618aSArya K Padman
1376d8ae618aSArya K Padman nlohmann::json expected_data = R"(
1377d8ae618aSArya K Padman [
1378d8ae618aSArya K Padman {
1379d8ae618aSArya K Padman "Location Code": "U98D-P0-DIMM0",
1380d8ae618aSArya K Padman "DRAM Manufacturer ID": [
1381d8ae618aSArya K Padman "0x80",
1382d8ae618aSArya K Padman "0x4a"
1383d8ae618aSArya K Padman ]
1384d8ae618aSArya K Padman },
1385d8ae618aSArya K Padman {
1386d8ae618aSArya K Padman "Location Code": "U98D-P0-DIMM1",
1387d8ae618aSArya K Padman "DRAM Manufacturer ID": [
1388d8ae618aSArya K Padman "0x80",
1389d8ae618aSArya K Padman "0x4a"
1390d8ae618aSArya K Padman ]
1391d8ae618aSArya K Padman }
1392d8ae618aSArya K Padman ]
1393d8ae618aSArya K Padman )"_json;
1394d8ae618aSArya K Padman EXPECT_EQ(expected_data, dimmInfoJson);
1395d8ae618aSArya K Padman }
1396d8ae618aSArya K Padman }
1397d8ae618aSArya K Padman
1398d8ae618aSArya K Padman // When PEL has FRU callouts but PHAL is not enabled.
TEST_F(PELTest,TestNoDimmsCallout)1399ced8ed77SArya K Padman TEST_F(PELTest, TestNoDimmsCallout)
1400d8ae618aSArya K Padman {
1401d8ae618aSArya K Padman message::Entry entry;
1402d8ae618aSArya K Padman uint64_t timestamp = 5;
1403d8ae618aSArya K Padman AdditionalData ad;
1404d8ae618aSArya K Padman NiceMock<MockDataInterface> dataIface;
1405d8ae618aSArya K Padman NiceMock<MockJournal> journal;
1406d8ae618aSArya K Padman PelFFDC ffdc;
1407d8ae618aSArya K Padman
1408d8ae618aSArya K Padman entry.callouts = R"(
1409d8ae618aSArya K Padman [
1410d8ae618aSArya K Padman {
1411d8ae618aSArya K Padman "CalloutList": [
1412d8ae618aSArya K Padman {
1413d8ae618aSArya K Padman "Priority": "high",
1414ced8ed77SArya K Padman "LocCode": "P0-PROC0"
1415d8ae618aSArya K Padman }
1416d8ae618aSArya K Padman ]
1417d8ae618aSArya K Padman }
1418d8ae618aSArya K Padman ]
1419d8ae618aSArya K Padman )"_json;
1420d8ae618aSArya K Padman
1421ced8ed77SArya K Padman EXPECT_CALL(dataIface, expandLocationCode("P0-PROC0", 0))
1422ced8ed77SArya K Padman .WillOnce(Return("U98D-P0-PROC0"));
1423d8ae618aSArya K Padman
1424ced8ed77SArya K Padman EXPECT_CALL(dataIface, getInventoryFromLocCode("P0-PROC0", 0, false))
1425d8ae618aSArya K Padman .WillOnce(Return(std::vector<std::string>{
1426ced8ed77SArya K Padman "/xyz/openbmc_project/inventory/system/chassis/motherboard/dcm0/cpu0"}));
1427ced8ed77SArya K Padman
1428ced8ed77SArya K Padman // Add some location code in expanded format to DIMM cache memory
1429ced8ed77SArya K Padman dataIface.addDIMMLocCode("U98D-P0-PROC0", false);
1430d8ae618aSArya K Padman
1431d8ae618aSArya K Padman PEL pel{entry, 42, timestamp, phosphor::logging::Entry::Level::Error,
1432d8ae618aSArya K Padman ad, ffdc, dataIface, journal};
1433d8ae618aSArya K Padman
1434d8ae618aSArya K Padman nlohmann::json dimmInfoJson = getDIMMInfo(pel);
1435d8ae618aSArya K Padman
1436ced8ed77SArya K Padman nlohmann::json expected_data{};
1437d8ae618aSArya K Padman
1438d8ae618aSArya K Padman EXPECT_EQ(expected_data, dimmInfoJson);
1439d8ae618aSArya K Padman }
1440d8ae618aSArya K Padman
1441d8ae618aSArya K Padman // When the PEL doesn't contain any type of callouts
TEST_F(PELTest,TestDimmsCalloutInfoWithNoCallouts)1442d8ae618aSArya K Padman TEST_F(PELTest, TestDimmsCalloutInfoWithNoCallouts)
1443d8ae618aSArya K Padman {
1444d8ae618aSArya K Padman message::Entry entry;
1445d8ae618aSArya K Padman uint64_t timestamp = 5;
1446d8ae618aSArya K Padman AdditionalData ad;
1447d8ae618aSArya K Padman NiceMock<MockDataInterface> dataIface;
1448d8ae618aSArya K Padman NiceMock<MockJournal> journal;
1449d8ae618aSArya K Padman PelFFDC ffdc;
1450d8ae618aSArya K Padman
1451d8ae618aSArya K Padman PEL pel{entry, 42, timestamp, phosphor::logging::Entry::Level::Error,
1452d8ae618aSArya K Padman ad, ffdc, dataIface, journal};
1453d8ae618aSArya K Padman
1454d8ae618aSArya K Padman nlohmann::json dimmInfoJson = getDIMMInfo(pel);
1455d8ae618aSArya K Padman
1456d8ae618aSArya K Padman nlohmann::json expected_data{};
1457d8ae618aSArya K Padman
1458d8ae618aSArya K Padman EXPECT_EQ(expected_data, dimmInfoJson);
1459d8ae618aSArya K Padman }
1460d8ae618aSArya K Padman
1461d8ae618aSArya K Padman // When the PEL has DIMM callouts, but failed to fetch DI property value
TEST_F(PELTest,TestDimmsCalloutInfoDIFailure)1462d8ae618aSArya K Padman TEST_F(PELTest, TestDimmsCalloutInfoDIFailure)
1463d8ae618aSArya K Padman {
1464d8ae618aSArya K Padman {
1465d8ae618aSArya K Padman message::Entry entry;
1466d8ae618aSArya K Padman uint64_t timestamp = 5;
1467d8ae618aSArya K Padman AdditionalData ad;
1468d8ae618aSArya K Padman NiceMock<MockDataInterface> dataIface;
1469d8ae618aSArya K Padman NiceMock<MockJournal> journal;
1470d8ae618aSArya K Padman PelFFDC ffdc;
1471d8ae618aSArya K Padman
1472d8ae618aSArya K Padman entry.callouts = R"(
1473d8ae618aSArya K Padman [
1474d8ae618aSArya K Padman {
1475d8ae618aSArya K Padman "CalloutList": [
1476d8ae618aSArya K Padman {
1477d8ae618aSArya K Padman "Priority": "high",
1478d8ae618aSArya K Padman "LocCode": "P0-DIMM0"
1479d8ae618aSArya K Padman }
1480d8ae618aSArya K Padman ]
1481d8ae618aSArya K Padman }
1482d8ae618aSArya K Padman ]
1483d8ae618aSArya K Padman )"_json;
1484d8ae618aSArya K Padman
1485d8ae618aSArya K Padman EXPECT_CALL(dataIface, expandLocationCode("P0-DIMM0", 0))
1486d8ae618aSArya K Padman .WillOnce(Return("U98D-P0-DIMM0"));
1487d8ae618aSArya K Padman
1488d8ae618aSArya K Padman EXPECT_CALL(dataIface, getInventoryFromLocCode("P0-DIMM0", 0, false))
1489d8ae618aSArya K Padman .WillOnce(Return(std::vector<std::string>{
1490d8ae618aSArya K Padman "/xyz/openbmc_project/inventory/system/chassis/motherboard/dimm0"}));
1491d8ae618aSArya K Padman
1492d8ae618aSArya K Padman EXPECT_CALL(dataIface, getDIProperty("U98D-P0-DIMM0"))
1493d8ae618aSArya K Padman .WillOnce(Return(std::nullopt));
1494d8ae618aSArya K Padman
1495d8ae618aSArya K Padman // Add some location code in expanded format to DIMM cache memory
1496d8ae618aSArya K Padman dataIface.addDIMMLocCode("U98D-P0-DIMM0", true);
1497d8ae618aSArya K Padman
1498d8ae618aSArya K Padman PEL pel{entry, 42, timestamp, phosphor::logging::Entry::Level::Error,
1499d8ae618aSArya K Padman ad, ffdc, dataIface, journal};
1500d8ae618aSArya K Padman
1501d8ae618aSArya K Padman nlohmann::json dimmInfoJson = getDIMMInfo(pel);
1502d8ae618aSArya K Padman
1503d8ae618aSArya K Padman nlohmann::json expected_data = R"(
1504d8ae618aSArya K Padman [
1505d8ae618aSArya K Padman "Failed reading DI property from VINI Interface for the LocationCode:[U98D-P0-DIMM0]"
1506d8ae618aSArya K Padman ]
1507d8ae618aSArya K Padman )"_json;
1508d8ae618aSArya K Padman
1509d8ae618aSArya K Padman EXPECT_EQ(expected_data, dimmInfoJson);
1510d8ae618aSArya K Padman }
1511d8ae618aSArya K Padman }
1512