blob: ea1842d8750aa4779481b4966553aba44a53ad3a [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 Spinler677381b2020-01-23 10:04:29 -060029using ::testing::Return;
Matt Spinlercb6b0592019-07-16 15:58:51 -050030
31class PELTest : public CleanLogID
32{
33};
34
35TEST_F(PELTest, FlattenTest)
36{
Matt Spinler42828bd2019-10-11 10:39:30 -050037 auto data = pelDataFactory(TestPELType::pelSimple);
Matt Spinler42828bd2019-10-11 10:39:30 -050038 auto pel = std::make_unique<PEL>(data);
Matt Spinlercb6b0592019-07-16 15:58:51 -050039
40 // Check a few fields
41 EXPECT_TRUE(pel->valid());
42 EXPECT_EQ(pel->id(), 0x80818283);
43 EXPECT_EQ(pel->plid(), 0x50515253);
Matt Spinler97d19b42019-10-29 11:34:03 -050044 EXPECT_EQ(pel->userHeader().subsystem(), 0x10);
45 EXPECT_EQ(pel->userHeader().actionFlags(), 0x80C0);
Matt Spinlercb6b0592019-07-16 15:58:51 -050046
47 // Test that data in == data out
48 auto flattenedData = pel->data();
Matt Spinlerf1b46ff2020-01-22 14:10:04 -060049 EXPECT_EQ(data, flattenedData);
50 EXPECT_EQ(flattenedData.size(), pel->size());
Matt Spinlercb6b0592019-07-16 15:58:51 -050051}
52
53TEST_F(PELTest, CommitTimeTest)
54{
Matt Spinler42828bd2019-10-11 10:39:30 -050055 auto data = pelDataFactory(TestPELType::pelSimple);
56 auto pel = std::make_unique<PEL>(data);
Matt Spinlercb6b0592019-07-16 15:58:51 -050057
58 auto origTime = pel->commitTime();
59 pel->setCommitTime();
60 auto newTime = pel->commitTime();
61
Matt Spinlerf1b46ff2020-01-22 14:10:04 -060062 EXPECT_NE(origTime, newTime);
Matt Spinlercb6b0592019-07-16 15:58:51 -050063
64 // Make a new PEL and check new value is still there
65 auto newData = pel->data();
66 auto newPel = std::make_unique<PEL>(newData);
Matt Spinlerf1b46ff2020-01-22 14:10:04 -060067 EXPECT_EQ(newTime, newPel->commitTime());
Matt Spinlercb6b0592019-07-16 15:58:51 -050068}
69
70TEST_F(PELTest, AssignIDTest)
71{
Matt Spinler42828bd2019-10-11 10:39:30 -050072 auto data = pelDataFactory(TestPELType::pelSimple);
73 auto pel = std::make_unique<PEL>(data);
Matt Spinlercb6b0592019-07-16 15:58:51 -050074
75 auto origID = pel->id();
76 pel->assignID();
77 auto newID = pel->id();
78
Matt Spinlerf1b46ff2020-01-22 14:10:04 -060079 EXPECT_NE(origID, newID);
Matt Spinlercb6b0592019-07-16 15:58:51 -050080
81 // Make a new PEL and check new value is still there
82 auto newData = pel->data();
83 auto newPel = std::make_unique<PEL>(newData);
Matt Spinlerf1b46ff2020-01-22 14:10:04 -060084 EXPECT_EQ(newID, newPel->id());
Matt Spinlercb6b0592019-07-16 15:58:51 -050085}
86
87TEST_F(PELTest, WithLogIDTest)
88{
Matt Spinler42828bd2019-10-11 10:39:30 -050089 auto data = pelDataFactory(TestPELType::pelSimple);
90 auto pel = std::make_unique<PEL>(data, 0x42);
Matt Spinlercb6b0592019-07-16 15:58:51 -050091
92 EXPECT_TRUE(pel->valid());
93 EXPECT_EQ(pel->obmcLogID(), 0x42);
94}
95
96TEST_F(PELTest, InvalidPELTest)
97{
Matt Spinler42828bd2019-10-11 10:39:30 -050098 auto data = pelDataFactory(TestPELType::pelSimple);
Matt Spinlercb6b0592019-07-16 15:58:51 -050099
100 // Too small
Matt Spinler42828bd2019-10-11 10:39:30 -0500101 data.resize(PrivateHeader::flattenedSize());
Matt Spinlercb6b0592019-07-16 15:58:51 -0500102
Matt Spinler42828bd2019-10-11 10:39:30 -0500103 auto pel = std::make_unique<PEL>(data);
Matt Spinlercb6b0592019-07-16 15:58:51 -0500104
Matt Spinler97d19b42019-10-29 11:34:03 -0500105 EXPECT_TRUE(pel->privateHeader().valid());
106 EXPECT_FALSE(pel->userHeader().valid());
Matt Spinlercb6b0592019-07-16 15:58:51 -0500107 EXPECT_FALSE(pel->valid());
108
Matt Spinlercb6b0592019-07-16 15:58:51 -0500109 // Now corrupt the private header
Matt Spinler42828bd2019-10-11 10:39:30 -0500110 data = pelDataFactory(TestPELType::pelSimple);
111 data.at(0) = 0;
112 pel = std::make_unique<PEL>(data);
Matt Spinlercb6b0592019-07-16 15:58:51 -0500113
Matt Spinler97d19b42019-10-29 11:34:03 -0500114 EXPECT_FALSE(pel->privateHeader().valid());
115 EXPECT_TRUE(pel->userHeader().valid());
Matt Spinlercb6b0592019-07-16 15:58:51 -0500116 EXPECT_FALSE(pel->valid());
117}
118
119TEST_F(PELTest, EmptyDataTest)
120{
121 std::vector<uint8_t> data;
122 auto pel = std::make_unique<PEL>(data);
123
Matt Spinler97d19b42019-10-29 11:34:03 -0500124 EXPECT_FALSE(pel->privateHeader().valid());
125 EXPECT_FALSE(pel->userHeader().valid());
Matt Spinlercb6b0592019-07-16 15:58:51 -0500126 EXPECT_FALSE(pel->valid());
127}
Matt Spinlerb8323632019-09-20 15:11:04 -0500128
129TEST_F(PELTest, CreateFromRegistryTest)
130{
131 message::Entry regEntry;
132 uint64_t timestamp = 5;
133
134 regEntry.name = "test";
135 regEntry.subsystem = 5;
136 regEntry.actionFlags = 0xC000;
Matt Spinlerbd716f02019-10-15 10:54:11 -0500137 regEntry.src.type = 0xBD;
138 regEntry.src.reasonCode = 0x1234;
Matt Spinlerb8323632019-09-20 15:11:04 -0500139
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600140 std::vector<std::string> data{"KEY1=VALUE1"};
141 AdditionalData ad{data};
Matt Spinleraa659472019-10-23 09:26:48 -0500142 MockDataInterface dataIface;
Matt Spinlerbd716f02019-10-15 10:54:11 -0500143
Matt Spinleraa659472019-10-23 09:26:48 -0500144 PEL pel{regEntry, 42, timestamp, phosphor::logging::Entry::Level::Error, ad,
145 dataIface};
Matt Spinlerb8323632019-09-20 15:11:04 -0500146
147 EXPECT_TRUE(pel.valid());
Matt Spinler97d19b42019-10-29 11:34:03 -0500148 EXPECT_EQ(pel.privateHeader().obmcLogID(), 42);
149 EXPECT_EQ(pel.userHeader().severity(), 0x40);
Matt Spinlerb8323632019-09-20 15:11:04 -0500150
Matt Spinlerbd716f02019-10-15 10:54:11 -0500151 EXPECT_EQ(pel.primarySRC().value()->asciiString(),
152 "BD051234 ");
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600153
154 // Check that certain optional sections have been created
155 size_t mtmsCount = 0;
156 size_t euhCount = 0;
157 size_t udCount = 0;
158
159 for (const auto& section : pel.optionalSections())
160 {
161 if (section->header().id ==
162 static_cast<uint16_t>(SectionID::failingMTMS))
163 {
164 mtmsCount++;
165 }
166 else if (section->header().id ==
167 static_cast<uint16_t>(SectionID::extendedUserHeader))
168 {
169 euhCount++;
170 }
171 else if (section->header().id ==
172 static_cast<uint16_t>(SectionID::userData))
173 {
174 udCount++;
175 }
176 }
177
178 EXPECT_EQ(mtmsCount, 1);
179 EXPECT_EQ(euhCount, 1);
180 EXPECT_EQ(udCount, 2); // AD section and sysInfo section
Matt Spinlerb8323632019-09-20 15:11:04 -0500181}
Matt Spinler131870c2019-09-25 13:29:04 -0500182
Matt Spinler9b7e94f2020-03-24 15:44:41 -0500183// Test that when the AdditionalData size is over 16KB that
184// the PEL that's created is exactly 16KB since the UserData
185// section that contains all that data was pruned.
186TEST_F(PELTest, CreateTooBigADTest)
187{
188 message::Entry regEntry;
189 uint64_t timestamp = 5;
190
191 regEntry.name = "test";
192 regEntry.subsystem = 5;
193 regEntry.actionFlags = 0xC000;
194 regEntry.src.type = 0xBD;
195 regEntry.src.reasonCode = 0x1234;
196
197 // Over the 16KB max PEL size
198 std::string bigAD{"KEY1="};
199 bigAD += std::string(17000, 'G');
200
201 std::vector<std::string> data{bigAD};
202 AdditionalData ad{data};
203 MockDataInterface dataIface;
204
205 PEL pel{regEntry, 42, timestamp, phosphor::logging::Entry::Level::Error, ad,
206 dataIface};
207
208 EXPECT_TRUE(pel.valid());
209 EXPECT_EQ(pel.size(), 16384);
210
211 // Make sure that there are still 2 UD sections.
212 size_t udCount = 0;
213 for (const auto& section : pel.optionalSections())
214 {
215 if (section->header().id == static_cast<uint16_t>(SectionID::userData))
216 {
217 udCount++;
218 }
219 }
220
221 EXPECT_EQ(udCount, 2); // AD section and sysInfo section
222}
223
Matt Spinler131870c2019-09-25 13:29:04 -0500224// Test that we'll create Generic optional sections for sections that
225// there aren't explicit classes for.
226TEST_F(PELTest, GenericSectionTest)
227{
Matt Spinler42828bd2019-10-11 10:39:30 -0500228 auto data = pelDataFactory(TestPELType::pelSimple);
Matt Spinler131870c2019-09-25 13:29:04 -0500229
230 std::vector<uint8_t> section1{0x58, 0x58, // ID 'XX'
231 0x00, 0x18, // Size
232 0x01, 0x02, // version, subtype
233 0x03, 0x04, // comp ID
234
235 // some data
236 0x20, 0x30, 0x05, 0x09, 0x11, 0x1E, 0x1, 0x63,
237 0x20, 0x31, 0x06, 0x0F, 0x09, 0x22, 0x3A,
238 0x00};
239
240 std::vector<uint8_t> section2{
241 0x59, 0x59, // ID 'YY'
242 0x00, 0x20, // Size
243 0x01, 0x02, // version, subtype
244 0x03, 0x04, // comp ID
245
246 // some data
247 0x20, 0x30, 0x05, 0x09, 0x11, 0x1E, 0x1, 0x63, 0x20, 0x31, 0x06, 0x0F,
248 0x09, 0x22, 0x3A, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
249
250 // Add the new sections at the end
Matt Spinler42828bd2019-10-11 10:39:30 -0500251 data.insert(data.end(), section1.begin(), section1.end());
252 data.insert(data.end(), section2.begin(), section2.end());
Matt Spinler131870c2019-09-25 13:29:04 -0500253
254 // Increment the section count
Matt Spinler42828bd2019-10-11 10:39:30 -0500255 data.at(27) += 2;
256 auto origData = data;
Matt Spinler131870c2019-09-25 13:29:04 -0500257
Matt Spinler42828bd2019-10-11 10:39:30 -0500258 PEL pel{data};
Matt Spinler131870c2019-09-25 13:29:04 -0500259
260 const auto& sections = pel.optionalSections();
261
262 bool foundXX = false;
263 bool foundYY = false;
264
265 // Check that we can find these 2 Generic sections
266 for (const auto& section : sections)
267 {
268 if (section->header().id == 0x5858)
269 {
270 foundXX = true;
271 EXPECT_NE(dynamic_cast<Generic*>(section.get()), nullptr);
272 }
273 else if (section->header().id == 0x5959)
274 {
275 foundYY = true;
276 EXPECT_NE(dynamic_cast<Generic*>(section.get()), nullptr);
277 }
278 }
279
280 EXPECT_TRUE(foundXX);
281 EXPECT_TRUE(foundYY);
Matt Spinler07eefc52019-09-26 11:18:26 -0500282
283 // Now flatten and check
284 auto newData = pel.data();
285
286 EXPECT_EQ(origData, newData);
Matt Spinler131870c2019-09-25 13:29:04 -0500287}
288
289// Test that an invalid section will still get a Generic object
290TEST_F(PELTest, InvalidGenericTest)
291{
Matt Spinler42828bd2019-10-11 10:39:30 -0500292 auto data = pelDataFactory(TestPELType::pelSimple);
Matt Spinler131870c2019-09-25 13:29:04 -0500293
294 // Not a valid section
295 std::vector<uint8_t> section1{0x01, 0x02, 0x03};
296
Matt Spinler42828bd2019-10-11 10:39:30 -0500297 data.insert(data.end(), section1.begin(), section1.end());
Matt Spinler131870c2019-09-25 13:29:04 -0500298
299 // Increment the section count
Matt Spinler42828bd2019-10-11 10:39:30 -0500300 data.at(27) += 1;
Matt Spinler131870c2019-09-25 13:29:04 -0500301
Matt Spinler42828bd2019-10-11 10:39:30 -0500302 PEL pel{data};
Matt Spinler131870c2019-09-25 13:29:04 -0500303 EXPECT_FALSE(pel.valid());
304
305 const auto& sections = pel.optionalSections();
306
307 bool foundGeneric = false;
308 for (const auto& section : sections)
309 {
310 if (dynamic_cast<Generic*>(section.get()) != nullptr)
311 {
312 foundGeneric = true;
313 EXPECT_EQ(section->valid(), false);
314 break;
315 }
316 }
317
318 EXPECT_TRUE(foundGeneric);
319}
Matt Spinlerafa857c2019-10-24 13:03:46 -0500320
321// Create a UserData section out of AdditionalData
322TEST_F(PELTest, MakeUDSectionTest)
323{
324 std::vector<std::string> ad{"KEY1=VALUE1", "KEY2=VALUE2", "KEY3=VALUE3",
325 "ESEL=TEST"};
326 AdditionalData additionalData{ad};
327
328 auto ud = util::makeADUserDataSection(additionalData);
329
330 EXPECT_TRUE(ud->valid());
331 EXPECT_EQ(ud->header().id, 0x5544);
332 EXPECT_EQ(ud->header().version, 0x01);
333 EXPECT_EQ(ud->header().subType, 0x01);
334 EXPECT_EQ(ud->header().componentID, 0x2000);
335
336 const auto& d = ud->data();
337
338 std::string jsonString{d.begin(), d.end()};
Matt Spinler53407be2019-11-18 09:16:31 -0600339
340 std::string expectedJSON =
Matt Spinlerafa857c2019-10-24 13:03:46 -0500341 R"({"KEY1":"VALUE1","KEY2":"VALUE2","KEY3":"VALUE3"})";
Matt Spinler53407be2019-11-18 09:16:31 -0600342
343 // The actual data is null padded to a 4B boundary.
344 std::vector<uint8_t> expectedData;
345 expectedData.resize(52, '\0');
346 memcpy(expectedData.data(), expectedJSON.data(), expectedJSON.size());
347
348 EXPECT_EQ(d, expectedData);
Matt Spinlerafa857c2019-10-24 13:03:46 -0500349
350 // Ensure we can read this as JSON
351 auto newJSON = nlohmann::json::parse(jsonString);
352 EXPECT_EQ(newJSON["KEY1"], "VALUE1");
353 EXPECT_EQ(newJSON["KEY2"], "VALUE2");
354 EXPECT_EQ(newJSON["KEY3"], "VALUE3");
Matt Spinler97d19b42019-10-29 11:34:03 -0500355}
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600356
357// Create the UserData section that contains system info
Matt Spinler677381b2020-01-23 10:04:29 -0600358TEST_F(PELTest, SysInfoSectionTest)
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600359{
360 MockDataInterface dataIface;
361
Matt Spinler677381b2020-01-23 10:04:29 -0600362 EXPECT_CALL(dataIface, getBMCFWVersionID()).WillOnce(Return("ABCD1234"));
Matt Spinler4aa23a12020-02-03 15:05:09 -0600363 EXPECT_CALL(dataIface, getBMCState()).WillOnce(Return("State.Ready"));
364 EXPECT_CALL(dataIface, getChassisState()).WillOnce(Return("State.On"));
365 EXPECT_CALL(dataIface, getHostState()).WillOnce(Return("State.Off"));
Matt Spinler677381b2020-01-23 10:04:29 -0600366
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600367 std::string pid = "_PID=" + std::to_string(getpid());
368 std::vector<std::string> ad{pid};
369 AdditionalData additionalData{ad};
370
371 auto ud = util::makeSysInfoUserDataSection(additionalData, dataIface);
372
373 EXPECT_TRUE(ud->valid());
374 EXPECT_EQ(ud->header().id, 0x5544);
375 EXPECT_EQ(ud->header().version, 0x01);
376 EXPECT_EQ(ud->header().subType, 0x01);
377 EXPECT_EQ(ud->header().componentID, 0x2000);
378
379 // Pull out the JSON data and check it.
380 const auto& d = ud->data();
381 std::string jsonString{d.begin(), d.end()};
382 auto json = nlohmann::json::parse(jsonString);
383
384 // Ensure the 'Process Name' entry contains 'pel_test'
385 auto name = json["Process Name"].get<std::string>();
386 EXPECT_NE(name.find("pel_test"), std::string::npos);
Matt Spinler677381b2020-01-23 10:04:29 -0600387
388 auto version = json["BMC Version ID"].get<std::string>();
389 EXPECT_EQ(version, "ABCD1234");
Matt Spinler4aa23a12020-02-03 15:05:09 -0600390
391 auto state = json["BMCState"].get<std::string>();
392 EXPECT_EQ(state, "Ready");
393
394 state = json["ChassisState"].get<std::string>();
395 EXPECT_EQ(state, "On");
396
397 state = json["HostState"].get<std::string>();
398 EXPECT_EQ(state, "Off");
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600399}
Matt Spinlerce3f4502020-01-22 15:44:35 -0600400
401// Test that the sections that override
402// virtual std::optional<std::string> Section::getJSON() const
403// return valid JSON.
404TEST_F(PELTest, SectionJSONTest)
405{
406 auto data = pelDataFactory(TestPELType::pelSimple);
407 PEL pel{data};
408
409 // Check that all JSON returned from the sections is
410 // parseable by nlohmann::json, which will throw an
411 // exception and fail the test if there is a problem.
412
413 // The getJSON() response needs to be wrapped in a { } to make
414 // actual valid JSON (PEL::toJSON() usually handles that).
415
416 auto jsonString = pel.privateHeader().getJSON();
417
418 // PrivateHeader always prints JSON
419 ASSERT_TRUE(jsonString);
420 *jsonString = '{' + *jsonString + '}';
421 auto json = nlohmann::json::parse(*jsonString);
422
423 jsonString = pel.userHeader().getJSON();
424
425 // UserHeader always prints JSON
426 ASSERT_TRUE(jsonString);
427 *jsonString = '{' + *jsonString + '}';
428 json = nlohmann::json::parse(*jsonString);
429
430 for (const auto& section : pel.optionalSections())
431 {
432 // The optional sections may or may not have implemented getJSON().
433 jsonString = section->getJSON();
434 if (jsonString)
435 {
436 *jsonString = '{' + *jsonString + '}';
437 auto json = nlohmann::json::parse(*jsonString);
438 }
439 }
440}