blob: c5a1571318da133dcf620ce2d5fb4dd4dc352762 [file] [log] [blame]
Matt Spinler97f7abc2019-11-06 09:40:23 -06001/**
2 * Copyright © 2019 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Matt Spinlerb8323632019-09-20 15:11:04 -050016#include "elog_entry.hpp"
Matt Spinler131870c2019-09-25 13:29:04 -050017#include "extensions/openpower-pels/generic.hpp"
Matt Spinlercb6b0592019-07-16 15:58:51 -050018#include "extensions/openpower-pels/pel.hpp"
Matt Spinleraa659472019-10-23 09:26:48 -050019#include "mocks.hpp"
Matt Spinlercb6b0592019-07-16 15:58:51 -050020#include "pel_utils.hpp"
21
22#include <filesystem>
23#include <fstream>
24
25#include <gtest/gtest.h>
26
27namespace fs = std::filesystem;
28using namespace openpower::pels;
Matt Spinler56ad2a02020-03-26 14:00:52 -050029using ::testing::NiceMock;
Matt Spinler677381b2020-01-23 10:04:29 -060030using ::testing::Return;
Matt Spinlercb6b0592019-07-16 15:58:51 -050031
32class PELTest : public CleanLogID
33{
34};
35
36TEST_F(PELTest, FlattenTest)
37{
Matt Spinler42828bd2019-10-11 10:39:30 -050038 auto data = pelDataFactory(TestPELType::pelSimple);
Matt Spinler42828bd2019-10-11 10:39:30 -050039 auto pel = std::make_unique<PEL>(data);
Matt Spinlercb6b0592019-07-16 15:58:51 -050040
41 // Check a few fields
42 EXPECT_TRUE(pel->valid());
43 EXPECT_EQ(pel->id(), 0x80818283);
44 EXPECT_EQ(pel->plid(), 0x50515253);
Matt Spinler97d19b42019-10-29 11:34:03 -050045 EXPECT_EQ(pel->userHeader().subsystem(), 0x10);
46 EXPECT_EQ(pel->userHeader().actionFlags(), 0x80C0);
Matt Spinlercb6b0592019-07-16 15:58:51 -050047
48 // Test that data in == data out
49 auto flattenedData = pel->data();
Matt Spinlerf1b46ff2020-01-22 14:10:04 -060050 EXPECT_EQ(data, flattenedData);
51 EXPECT_EQ(flattenedData.size(), pel->size());
Matt Spinlercb6b0592019-07-16 15:58:51 -050052}
53
54TEST_F(PELTest, CommitTimeTest)
55{
Matt Spinler42828bd2019-10-11 10:39:30 -050056 auto data = pelDataFactory(TestPELType::pelSimple);
57 auto pel = std::make_unique<PEL>(data);
Matt Spinlercb6b0592019-07-16 15:58:51 -050058
59 auto origTime = pel->commitTime();
60 pel->setCommitTime();
61 auto newTime = pel->commitTime();
62
Matt Spinlerf1b46ff2020-01-22 14:10:04 -060063 EXPECT_NE(origTime, newTime);
Matt Spinlercb6b0592019-07-16 15:58:51 -050064
65 // Make a new PEL and check new value is still there
66 auto newData = pel->data();
67 auto newPel = std::make_unique<PEL>(newData);
Matt Spinlerf1b46ff2020-01-22 14:10:04 -060068 EXPECT_EQ(newTime, newPel->commitTime());
Matt Spinlercb6b0592019-07-16 15:58:51 -050069}
70
71TEST_F(PELTest, AssignIDTest)
72{
Matt Spinler42828bd2019-10-11 10:39:30 -050073 auto data = pelDataFactory(TestPELType::pelSimple);
74 auto pel = std::make_unique<PEL>(data);
Matt Spinlercb6b0592019-07-16 15:58:51 -050075
76 auto origID = pel->id();
77 pel->assignID();
78 auto newID = pel->id();
79
Matt Spinlerf1b46ff2020-01-22 14:10:04 -060080 EXPECT_NE(origID, newID);
Matt Spinlercb6b0592019-07-16 15:58:51 -050081
82 // Make a new PEL and check new value is still there
83 auto newData = pel->data();
84 auto newPel = std::make_unique<PEL>(newData);
Matt Spinlerf1b46ff2020-01-22 14:10:04 -060085 EXPECT_EQ(newID, newPel->id());
Matt Spinlercb6b0592019-07-16 15:58:51 -050086}
87
88TEST_F(PELTest, WithLogIDTest)
89{
Matt Spinler42828bd2019-10-11 10:39:30 -050090 auto data = pelDataFactory(TestPELType::pelSimple);
91 auto pel = std::make_unique<PEL>(data, 0x42);
Matt Spinlercb6b0592019-07-16 15:58:51 -050092
93 EXPECT_TRUE(pel->valid());
94 EXPECT_EQ(pel->obmcLogID(), 0x42);
95}
96
97TEST_F(PELTest, InvalidPELTest)
98{
Matt Spinler42828bd2019-10-11 10:39:30 -050099 auto data = pelDataFactory(TestPELType::pelSimple);
Matt Spinlercb6b0592019-07-16 15:58:51 -0500100
101 // Too small
Matt Spinler42828bd2019-10-11 10:39:30 -0500102 data.resize(PrivateHeader::flattenedSize());
Matt Spinlercb6b0592019-07-16 15:58:51 -0500103
Matt Spinler42828bd2019-10-11 10:39:30 -0500104 auto pel = std::make_unique<PEL>(data);
Matt Spinlercb6b0592019-07-16 15:58:51 -0500105
Matt Spinler97d19b42019-10-29 11:34:03 -0500106 EXPECT_TRUE(pel->privateHeader().valid());
107 EXPECT_FALSE(pel->userHeader().valid());
Matt Spinlercb6b0592019-07-16 15:58:51 -0500108 EXPECT_FALSE(pel->valid());
109
Matt Spinlercb6b0592019-07-16 15:58:51 -0500110 // Now corrupt the private header
Matt Spinler42828bd2019-10-11 10:39:30 -0500111 data = pelDataFactory(TestPELType::pelSimple);
112 data.at(0) = 0;
113 pel = std::make_unique<PEL>(data);
Matt Spinlercb6b0592019-07-16 15:58:51 -0500114
Matt Spinler97d19b42019-10-29 11:34:03 -0500115 EXPECT_FALSE(pel->privateHeader().valid());
116 EXPECT_TRUE(pel->userHeader().valid());
Matt Spinlercb6b0592019-07-16 15:58:51 -0500117 EXPECT_FALSE(pel->valid());
118}
119
120TEST_F(PELTest, EmptyDataTest)
121{
122 std::vector<uint8_t> data;
123 auto pel = std::make_unique<PEL>(data);
124
Matt Spinler97d19b42019-10-29 11:34:03 -0500125 EXPECT_FALSE(pel->privateHeader().valid());
126 EXPECT_FALSE(pel->userHeader().valid());
Matt Spinlercb6b0592019-07-16 15:58:51 -0500127 EXPECT_FALSE(pel->valid());
128}
Matt Spinlerb8323632019-09-20 15:11:04 -0500129
130TEST_F(PELTest, CreateFromRegistryTest)
131{
132 message::Entry regEntry;
133 uint64_t timestamp = 5;
134
135 regEntry.name = "test";
136 regEntry.subsystem = 5;
137 regEntry.actionFlags = 0xC000;
Matt Spinlerbd716f02019-10-15 10:54:11 -0500138 regEntry.src.type = 0xBD;
139 regEntry.src.reasonCode = 0x1234;
Matt Spinlerb8323632019-09-20 15:11:04 -0500140
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600141 std::vector<std::string> data{"KEY1=VALUE1"};
142 AdditionalData ad{data};
Matt Spinler56ad2a02020-03-26 14:00:52 -0500143 NiceMock<MockDataInterface> dataIface;
144 PelFFDC ffdc;
Matt Spinlerbd716f02019-10-15 10:54:11 -0500145
Matt Spinler56ad2a02020-03-26 14:00:52 -0500146 PEL pel{regEntry, 42, timestamp, phosphor::logging::Entry::Level::Error,
147 ad, ffdc, dataIface};
Matt Spinlerb8323632019-09-20 15:11:04 -0500148
149 EXPECT_TRUE(pel.valid());
Matt Spinler97d19b42019-10-29 11:34:03 -0500150 EXPECT_EQ(pel.privateHeader().obmcLogID(), 42);
151 EXPECT_EQ(pel.userHeader().severity(), 0x40);
Matt Spinlerb8323632019-09-20 15:11:04 -0500152
Matt Spinlerbd716f02019-10-15 10:54:11 -0500153 EXPECT_EQ(pel.primarySRC().value()->asciiString(),
154 "BD051234 ");
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600155
156 // Check that certain optional sections have been created
157 size_t mtmsCount = 0;
158 size_t euhCount = 0;
159 size_t udCount = 0;
160
161 for (const auto& section : pel.optionalSections())
162 {
163 if (section->header().id ==
164 static_cast<uint16_t>(SectionID::failingMTMS))
165 {
166 mtmsCount++;
167 }
168 else if (section->header().id ==
169 static_cast<uint16_t>(SectionID::extendedUserHeader))
170 {
171 euhCount++;
172 }
173 else if (section->header().id ==
174 static_cast<uint16_t>(SectionID::userData))
175 {
176 udCount++;
177 }
178 }
179
180 EXPECT_EQ(mtmsCount, 1);
181 EXPECT_EQ(euhCount, 1);
182 EXPECT_EQ(udCount, 2); // AD section and sysInfo section
Matt Spinlerb8323632019-09-20 15:11:04 -0500183}
Matt Spinler131870c2019-09-25 13:29:04 -0500184
Matt Spinler9b7e94f2020-03-24 15:44:41 -0500185// Test that when the AdditionalData size is over 16KB that
186// the PEL that's created is exactly 16KB since the UserData
187// section that contains all that data was pruned.
188TEST_F(PELTest, CreateTooBigADTest)
189{
190 message::Entry regEntry;
191 uint64_t timestamp = 5;
192
193 regEntry.name = "test";
194 regEntry.subsystem = 5;
195 regEntry.actionFlags = 0xC000;
196 regEntry.src.type = 0xBD;
197 regEntry.src.reasonCode = 0x1234;
Matt Spinler56ad2a02020-03-26 14:00:52 -0500198 PelFFDC ffdc;
Matt Spinler9b7e94f2020-03-24 15:44:41 -0500199
200 // Over the 16KB max PEL size
201 std::string bigAD{"KEY1="};
202 bigAD += std::string(17000, 'G');
203
204 std::vector<std::string> data{bigAD};
205 AdditionalData ad{data};
Matt Spinler56ad2a02020-03-26 14:00:52 -0500206 NiceMock<MockDataInterface> dataIface;
Matt Spinler9b7e94f2020-03-24 15:44:41 -0500207
Matt Spinler56ad2a02020-03-26 14:00:52 -0500208 PEL pel{regEntry, 42, timestamp, phosphor::logging::Entry::Level::Error,
209 ad, ffdc, dataIface};
Matt Spinler9b7e94f2020-03-24 15:44:41 -0500210
211 EXPECT_TRUE(pel.valid());
212 EXPECT_EQ(pel.size(), 16384);
213
214 // Make sure that there are still 2 UD sections.
215 size_t udCount = 0;
216 for (const auto& section : pel.optionalSections())
217 {
218 if (section->header().id == static_cast<uint16_t>(SectionID::userData))
219 {
220 udCount++;
221 }
222 }
223
224 EXPECT_EQ(udCount, 2); // AD section and sysInfo section
225}
226
Matt Spinler131870c2019-09-25 13:29:04 -0500227// Test that we'll create Generic optional sections for sections that
228// there aren't explicit classes for.
229TEST_F(PELTest, GenericSectionTest)
230{
Matt Spinler42828bd2019-10-11 10:39:30 -0500231 auto data = pelDataFactory(TestPELType::pelSimple);
Matt Spinler131870c2019-09-25 13:29:04 -0500232
233 std::vector<uint8_t> section1{0x58, 0x58, // ID 'XX'
234 0x00, 0x18, // Size
235 0x01, 0x02, // version, subtype
236 0x03, 0x04, // comp ID
237
238 // some data
239 0x20, 0x30, 0x05, 0x09, 0x11, 0x1E, 0x1, 0x63,
240 0x20, 0x31, 0x06, 0x0F, 0x09, 0x22, 0x3A,
241 0x00};
242
243 std::vector<uint8_t> section2{
244 0x59, 0x59, // ID 'YY'
245 0x00, 0x20, // Size
246 0x01, 0x02, // version, subtype
247 0x03, 0x04, // comp ID
248
249 // some data
250 0x20, 0x30, 0x05, 0x09, 0x11, 0x1E, 0x1, 0x63, 0x20, 0x31, 0x06, 0x0F,
251 0x09, 0x22, 0x3A, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
252
253 // Add the new sections at the end
Matt Spinler42828bd2019-10-11 10:39:30 -0500254 data.insert(data.end(), section1.begin(), section1.end());
255 data.insert(data.end(), section2.begin(), section2.end());
Matt Spinler131870c2019-09-25 13:29:04 -0500256
257 // Increment the section count
Matt Spinler42828bd2019-10-11 10:39:30 -0500258 data.at(27) += 2;
259 auto origData = data;
Matt Spinler131870c2019-09-25 13:29:04 -0500260
Matt Spinler42828bd2019-10-11 10:39:30 -0500261 PEL pel{data};
Matt Spinler131870c2019-09-25 13:29:04 -0500262
263 const auto& sections = pel.optionalSections();
264
265 bool foundXX = false;
266 bool foundYY = false;
267
268 // Check that we can find these 2 Generic sections
269 for (const auto& section : sections)
270 {
271 if (section->header().id == 0x5858)
272 {
273 foundXX = true;
274 EXPECT_NE(dynamic_cast<Generic*>(section.get()), nullptr);
275 }
276 else if (section->header().id == 0x5959)
277 {
278 foundYY = true;
279 EXPECT_NE(dynamic_cast<Generic*>(section.get()), nullptr);
280 }
281 }
282
283 EXPECT_TRUE(foundXX);
284 EXPECT_TRUE(foundYY);
Matt Spinler07eefc52019-09-26 11:18:26 -0500285
286 // Now flatten and check
287 auto newData = pel.data();
288
289 EXPECT_EQ(origData, newData);
Matt Spinler131870c2019-09-25 13:29:04 -0500290}
291
292// Test that an invalid section will still get a Generic object
293TEST_F(PELTest, InvalidGenericTest)
294{
Matt Spinler42828bd2019-10-11 10:39:30 -0500295 auto data = pelDataFactory(TestPELType::pelSimple);
Matt Spinler131870c2019-09-25 13:29:04 -0500296
297 // Not a valid section
298 std::vector<uint8_t> section1{0x01, 0x02, 0x03};
299
Matt Spinler42828bd2019-10-11 10:39:30 -0500300 data.insert(data.end(), section1.begin(), section1.end());
Matt Spinler131870c2019-09-25 13:29:04 -0500301
302 // Increment the section count
Matt Spinler42828bd2019-10-11 10:39:30 -0500303 data.at(27) += 1;
Matt Spinler131870c2019-09-25 13:29:04 -0500304
Matt Spinler42828bd2019-10-11 10:39:30 -0500305 PEL pel{data};
Matt Spinler131870c2019-09-25 13:29:04 -0500306 EXPECT_FALSE(pel.valid());
307
308 const auto& sections = pel.optionalSections();
309
310 bool foundGeneric = false;
311 for (const auto& section : sections)
312 {
313 if (dynamic_cast<Generic*>(section.get()) != nullptr)
314 {
315 foundGeneric = true;
316 EXPECT_EQ(section->valid(), false);
317 break;
318 }
319 }
320
321 EXPECT_TRUE(foundGeneric);
322}
Matt Spinlerafa857c2019-10-24 13:03:46 -0500323
324// Create a UserData section out of AdditionalData
325TEST_F(PELTest, MakeUDSectionTest)
326{
327 std::vector<std::string> ad{"KEY1=VALUE1", "KEY2=VALUE2", "KEY3=VALUE3",
328 "ESEL=TEST"};
329 AdditionalData additionalData{ad};
330
331 auto ud = util::makeADUserDataSection(additionalData);
332
333 EXPECT_TRUE(ud->valid());
334 EXPECT_EQ(ud->header().id, 0x5544);
335 EXPECT_EQ(ud->header().version, 0x01);
336 EXPECT_EQ(ud->header().subType, 0x01);
337 EXPECT_EQ(ud->header().componentID, 0x2000);
338
339 const auto& d = ud->data();
340
341 std::string jsonString{d.begin(), d.end()};
Matt Spinler53407be2019-11-18 09:16:31 -0600342
343 std::string expectedJSON =
Matt Spinlerafa857c2019-10-24 13:03:46 -0500344 R"({"KEY1":"VALUE1","KEY2":"VALUE2","KEY3":"VALUE3"})";
Matt Spinler53407be2019-11-18 09:16:31 -0600345
346 // The actual data is null padded to a 4B boundary.
347 std::vector<uint8_t> expectedData;
348 expectedData.resize(52, '\0');
349 memcpy(expectedData.data(), expectedJSON.data(), expectedJSON.size());
350
351 EXPECT_EQ(d, expectedData);
Matt Spinlerafa857c2019-10-24 13:03:46 -0500352
353 // Ensure we can read this as JSON
354 auto newJSON = nlohmann::json::parse(jsonString);
355 EXPECT_EQ(newJSON["KEY1"], "VALUE1");
356 EXPECT_EQ(newJSON["KEY2"], "VALUE2");
357 EXPECT_EQ(newJSON["KEY3"], "VALUE3");
Matt Spinler97d19b42019-10-29 11:34:03 -0500358}
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600359
360// Create the UserData section that contains system info
Matt Spinler677381b2020-01-23 10:04:29 -0600361TEST_F(PELTest, SysInfoSectionTest)
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600362{
363 MockDataInterface dataIface;
364
Matt Spinler677381b2020-01-23 10:04:29 -0600365 EXPECT_CALL(dataIface, getBMCFWVersionID()).WillOnce(Return("ABCD1234"));
Matt Spinler4aa23a12020-02-03 15:05:09 -0600366 EXPECT_CALL(dataIface, getBMCState()).WillOnce(Return("State.Ready"));
367 EXPECT_CALL(dataIface, getChassisState()).WillOnce(Return("State.On"));
368 EXPECT_CALL(dataIface, getHostState()).WillOnce(Return("State.Off"));
Matt Spinler677381b2020-01-23 10:04:29 -0600369
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600370 std::string pid = "_PID=" + std::to_string(getpid());
371 std::vector<std::string> ad{pid};
372 AdditionalData additionalData{ad};
373
374 auto ud = util::makeSysInfoUserDataSection(additionalData, dataIface);
375
376 EXPECT_TRUE(ud->valid());
377 EXPECT_EQ(ud->header().id, 0x5544);
378 EXPECT_EQ(ud->header().version, 0x01);
379 EXPECT_EQ(ud->header().subType, 0x01);
380 EXPECT_EQ(ud->header().componentID, 0x2000);
381
382 // Pull out the JSON data and check it.
383 const auto& d = ud->data();
384 std::string jsonString{d.begin(), d.end()};
385 auto json = nlohmann::json::parse(jsonString);
386
387 // Ensure the 'Process Name' entry contains 'pel_test'
388 auto name = json["Process Name"].get<std::string>();
389 EXPECT_NE(name.find("pel_test"), std::string::npos);
Matt Spinler677381b2020-01-23 10:04:29 -0600390
391 auto version = json["BMC Version ID"].get<std::string>();
392 EXPECT_EQ(version, "ABCD1234");
Matt Spinler4aa23a12020-02-03 15:05:09 -0600393
394 auto state = json["BMCState"].get<std::string>();
395 EXPECT_EQ(state, "Ready");
396
397 state = json["ChassisState"].get<std::string>();
398 EXPECT_EQ(state, "On");
399
400 state = json["HostState"].get<std::string>();
401 EXPECT_EQ(state, "Off");
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600402}
Matt Spinlerce3f4502020-01-22 15:44:35 -0600403
404// Test that the sections that override
405// virtual std::optional<std::string> Section::getJSON() const
406// return valid JSON.
407TEST_F(PELTest, SectionJSONTest)
408{
409 auto data = pelDataFactory(TestPELType::pelSimple);
410 PEL pel{data};
411
412 // Check that all JSON returned from the sections is
413 // parseable by nlohmann::json, which will throw an
414 // exception and fail the test if there is a problem.
415
416 // The getJSON() response needs to be wrapped in a { } to make
417 // actual valid JSON (PEL::toJSON() usually handles that).
418
419 auto jsonString = pel.privateHeader().getJSON();
420
421 // PrivateHeader always prints JSON
422 ASSERT_TRUE(jsonString);
423 *jsonString = '{' + *jsonString + '}';
424 auto json = nlohmann::json::parse(*jsonString);
425
426 jsonString = pel.userHeader().getJSON();
427
428 // UserHeader always prints JSON
429 ASSERT_TRUE(jsonString);
430 *jsonString = '{' + *jsonString + '}';
431 json = nlohmann::json::parse(*jsonString);
432
433 for (const auto& section : pel.optionalSections())
434 {
435 // The optional sections may or may not have implemented getJSON().
436 jsonString = section->getJSON();
437 if (jsonString)
438 {
439 *jsonString = '{' + *jsonString + '}';
440 auto json = nlohmann::json::parse(*jsonString);
441 }
442 }
443}