summaryrefslogtreecommitdiffstats
path: root/test/openpower-pels/pel_test.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'test/openpower-pels/pel_test.cpp')
-rw-r--r--test/openpower-pels/pel_test.cpp387
1 files changed, 387 insertions, 0 deletions
diff --git a/test/openpower-pels/pel_test.cpp b/test/openpower-pels/pel_test.cpp
new file mode 100644
index 0000000..2cf58d7
--- /dev/null
+++ b/test/openpower-pels/pel_test.cpp
@@ -0,0 +1,387 @@
+/**
+ * Copyright © 2019 IBM Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "elog_entry.hpp"
+#include "extensions/openpower-pels/generic.hpp"
+#include "extensions/openpower-pels/pel.hpp"
+#include "mocks.hpp"
+#include "pel_utils.hpp"
+
+#include <filesystem>
+#include <fstream>
+
+#include <gtest/gtest.h>
+
+namespace fs = std::filesystem;
+using namespace openpower::pels;
+using ::testing::Return;
+
+class PELTest : public CleanLogID
+{
+};
+
+TEST_F(PELTest, FlattenTest)
+{
+ auto data = pelDataFactory(TestPELType::pelSimple);
+ auto pel = std::make_unique<PEL>(data);
+
+ // Check a few fields
+ EXPECT_TRUE(pel->valid());
+ EXPECT_EQ(pel->id(), 0x80818283);
+ EXPECT_EQ(pel->plid(), 0x50515253);
+ EXPECT_EQ(pel->userHeader().subsystem(), 0x10);
+ EXPECT_EQ(pel->userHeader().actionFlags(), 0x80C0);
+
+ // Test that data in == data out
+ auto flattenedData = pel->data();
+ EXPECT_EQ(data, flattenedData);
+ EXPECT_EQ(flattenedData.size(), pel->size());
+}
+
+TEST_F(PELTest, CommitTimeTest)
+{
+ auto data = pelDataFactory(TestPELType::pelSimple);
+ auto pel = std::make_unique<PEL>(data);
+
+ auto origTime = pel->commitTime();
+ pel->setCommitTime();
+ auto newTime = pel->commitTime();
+
+ EXPECT_NE(origTime, newTime);
+
+ // Make a new PEL and check new value is still there
+ auto newData = pel->data();
+ auto newPel = std::make_unique<PEL>(newData);
+ EXPECT_EQ(newTime, newPel->commitTime());
+}
+
+TEST_F(PELTest, AssignIDTest)
+{
+ auto data = pelDataFactory(TestPELType::pelSimple);
+ auto pel = std::make_unique<PEL>(data);
+
+ auto origID = pel->id();
+ pel->assignID();
+ auto newID = pel->id();
+
+ EXPECT_NE(origID, newID);
+
+ // Make a new PEL and check new value is still there
+ auto newData = pel->data();
+ auto newPel = std::make_unique<PEL>(newData);
+ EXPECT_EQ(newID, newPel->id());
+}
+
+TEST_F(PELTest, WithLogIDTest)
+{
+ auto data = pelDataFactory(TestPELType::pelSimple);
+ auto pel = std::make_unique<PEL>(data, 0x42);
+
+ EXPECT_TRUE(pel->valid());
+ EXPECT_EQ(pel->obmcLogID(), 0x42);
+}
+
+TEST_F(PELTest, InvalidPELTest)
+{
+ auto data = pelDataFactory(TestPELType::pelSimple);
+
+ // Too small
+ data.resize(PrivateHeader::flattenedSize());
+
+ auto pel = std::make_unique<PEL>(data);
+
+ EXPECT_TRUE(pel->privateHeader().valid());
+ EXPECT_FALSE(pel->userHeader().valid());
+ EXPECT_FALSE(pel->valid());
+
+ // Now corrupt the private header
+ data = pelDataFactory(TestPELType::pelSimple);
+ data.at(0) = 0;
+ pel = std::make_unique<PEL>(data);
+
+ EXPECT_FALSE(pel->privateHeader().valid());
+ EXPECT_TRUE(pel->userHeader().valid());
+ EXPECT_FALSE(pel->valid());
+}
+
+TEST_F(PELTest, EmptyDataTest)
+{
+ std::vector<uint8_t> data;
+ auto pel = std::make_unique<PEL>(data);
+
+ EXPECT_FALSE(pel->privateHeader().valid());
+ EXPECT_FALSE(pel->userHeader().valid());
+ EXPECT_FALSE(pel->valid());
+}
+
+TEST_F(PELTest, CreateFromRegistryTest)
+{
+ message::Entry regEntry;
+ uint64_t timestamp = 5;
+
+ regEntry.name = "test";
+ regEntry.subsystem = 5;
+ regEntry.actionFlags = 0xC000;
+ regEntry.src.type = 0xBD;
+ regEntry.src.reasonCode = 0x1234;
+
+ std::vector<std::string> data{"KEY1=VALUE1"};
+ AdditionalData ad{data};
+ MockDataInterface dataIface;
+
+ PEL pel{regEntry, 42, timestamp, phosphor::logging::Entry::Level::Error, ad,
+ dataIface};
+
+ EXPECT_TRUE(pel.valid());
+ EXPECT_EQ(pel.privateHeader().obmcLogID(), 42);
+ EXPECT_EQ(pel.userHeader().severity(), 0x40);
+
+ EXPECT_EQ(pel.primarySRC().value()->asciiString(),
+ "BD051234 ");
+
+ // Check that certain optional sections have been created
+ size_t mtmsCount = 0;
+ size_t euhCount = 0;
+ size_t udCount = 0;
+
+ for (const auto& section : pel.optionalSections())
+ {
+ if (section->header().id ==
+ static_cast<uint16_t>(SectionID::failingMTMS))
+ {
+ mtmsCount++;
+ }
+ else if (section->header().id ==
+ static_cast<uint16_t>(SectionID::extendedUserHeader))
+ {
+ euhCount++;
+ }
+ else if (section->header().id ==
+ static_cast<uint16_t>(SectionID::userData))
+ {
+ udCount++;
+ }
+ }
+
+ EXPECT_EQ(mtmsCount, 1);
+ EXPECT_EQ(euhCount, 1);
+ EXPECT_EQ(udCount, 2); // AD section and sysInfo section
+}
+
+// Test that we'll create Generic optional sections for sections that
+// there aren't explicit classes for.
+TEST_F(PELTest, GenericSectionTest)
+{
+ auto data = pelDataFactory(TestPELType::pelSimple);
+
+ std::vector<uint8_t> section1{0x58, 0x58, // ID 'XX'
+ 0x00, 0x18, // Size
+ 0x01, 0x02, // version, subtype
+ 0x03, 0x04, // comp ID
+
+ // some data
+ 0x20, 0x30, 0x05, 0x09, 0x11, 0x1E, 0x1, 0x63,
+ 0x20, 0x31, 0x06, 0x0F, 0x09, 0x22, 0x3A,
+ 0x00};
+
+ std::vector<uint8_t> section2{
+ 0x59, 0x59, // ID 'YY'
+ 0x00, 0x20, // Size
+ 0x01, 0x02, // version, subtype
+ 0x03, 0x04, // comp ID
+
+ // some data
+ 0x20, 0x30, 0x05, 0x09, 0x11, 0x1E, 0x1, 0x63, 0x20, 0x31, 0x06, 0x0F,
+ 0x09, 0x22, 0x3A, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
+
+ // Add the new sections at the end
+ data.insert(data.end(), section1.begin(), section1.end());
+ data.insert(data.end(), section2.begin(), section2.end());
+
+ // Increment the section count
+ data.at(27) += 2;
+ auto origData = data;
+
+ PEL pel{data};
+
+ const auto& sections = pel.optionalSections();
+
+ bool foundXX = false;
+ bool foundYY = false;
+
+ // Check that we can find these 2 Generic sections
+ for (const auto& section : sections)
+ {
+ if (section->header().id == 0x5858)
+ {
+ foundXX = true;
+ EXPECT_NE(dynamic_cast<Generic*>(section.get()), nullptr);
+ }
+ else if (section->header().id == 0x5959)
+ {
+ foundYY = true;
+ EXPECT_NE(dynamic_cast<Generic*>(section.get()), nullptr);
+ }
+ }
+
+ EXPECT_TRUE(foundXX);
+ EXPECT_TRUE(foundYY);
+
+ // Now flatten and check
+ auto newData = pel.data();
+
+ EXPECT_EQ(origData, newData);
+}
+
+// Test that an invalid section will still get a Generic object
+TEST_F(PELTest, InvalidGenericTest)
+{
+ auto data = pelDataFactory(TestPELType::pelSimple);
+
+ // Not a valid section
+ std::vector<uint8_t> section1{0x01, 0x02, 0x03};
+
+ data.insert(data.end(), section1.begin(), section1.end());
+
+ // Increment the section count
+ data.at(27) += 1;
+
+ PEL pel{data};
+ EXPECT_FALSE(pel.valid());
+
+ const auto& sections = pel.optionalSections();
+
+ bool foundGeneric = false;
+ for (const auto& section : sections)
+ {
+ if (dynamic_cast<Generic*>(section.get()) != nullptr)
+ {
+ foundGeneric = true;
+ EXPECT_EQ(section->valid(), false);
+ break;
+ }
+ }
+
+ EXPECT_TRUE(foundGeneric);
+}
+
+// Create a UserData section out of AdditionalData
+TEST_F(PELTest, MakeUDSectionTest)
+{
+ std::vector<std::string> ad{"KEY1=VALUE1", "KEY2=VALUE2", "KEY3=VALUE3",
+ "ESEL=TEST"};
+ AdditionalData additionalData{ad};
+
+ auto ud = util::makeADUserDataSection(additionalData);
+
+ EXPECT_TRUE(ud->valid());
+ EXPECT_EQ(ud->header().id, 0x5544);
+ EXPECT_EQ(ud->header().version, 0x01);
+ EXPECT_EQ(ud->header().subType, 0x01);
+ EXPECT_EQ(ud->header().componentID, 0x2000);
+
+ const auto& d = ud->data();
+
+ std::string jsonString{d.begin(), d.end()};
+
+ std::string expectedJSON =
+ R"({"KEY1":"VALUE1","KEY2":"VALUE2","KEY3":"VALUE3"})";
+
+ // The actual data is null padded to a 4B boundary.
+ std::vector<uint8_t> expectedData;
+ expectedData.resize(52, '\0');
+ memcpy(expectedData.data(), expectedJSON.data(), expectedJSON.size());
+
+ EXPECT_EQ(d, expectedData);
+
+ // Ensure we can read this as JSON
+ auto newJSON = nlohmann::json::parse(jsonString);
+ EXPECT_EQ(newJSON["KEY1"], "VALUE1");
+ EXPECT_EQ(newJSON["KEY2"], "VALUE2");
+ EXPECT_EQ(newJSON["KEY3"], "VALUE3");
+}
+
+// Create the UserData section that contains system info
+TEST_F(PELTest, SysInfoSectionTest)
+{
+ MockDataInterface dataIface;
+
+ EXPECT_CALL(dataIface, getBMCFWVersionID()).WillOnce(Return("ABCD1234"));
+
+ std::string pid = "_PID=" + std::to_string(getpid());
+ std::vector<std::string> ad{pid};
+ AdditionalData additionalData{ad};
+
+ auto ud = util::makeSysInfoUserDataSection(additionalData, dataIface);
+
+ EXPECT_TRUE(ud->valid());
+ EXPECT_EQ(ud->header().id, 0x5544);
+ EXPECT_EQ(ud->header().version, 0x01);
+ EXPECT_EQ(ud->header().subType, 0x01);
+ EXPECT_EQ(ud->header().componentID, 0x2000);
+
+ // Pull out the JSON data and check it.
+ const auto& d = ud->data();
+ std::string jsonString{d.begin(), d.end()};
+ auto json = nlohmann::json::parse(jsonString);
+
+ // Ensure the 'Process Name' entry contains 'pel_test'
+ auto name = json["Process Name"].get<std::string>();
+ EXPECT_NE(name.find("pel_test"), std::string::npos);
+
+ auto version = json["BMC Version ID"].get<std::string>();
+ EXPECT_EQ(version, "ABCD1234");
+}
+
+// Test that the sections that override
+// virtual std::optional<std::string> Section::getJSON() const
+// return valid JSON.
+TEST_F(PELTest, SectionJSONTest)
+{
+ auto data = pelDataFactory(TestPELType::pelSimple);
+ PEL pel{data};
+
+ // Check that all JSON returned from the sections is
+ // parseable by nlohmann::json, which will throw an
+ // exception and fail the test if there is a problem.
+
+ // The getJSON() response needs to be wrapped in a { } to make
+ // actual valid JSON (PEL::toJSON() usually handles that).
+
+ auto jsonString = pel.privateHeader().getJSON();
+
+ // PrivateHeader always prints JSON
+ ASSERT_TRUE(jsonString);
+ *jsonString = '{' + *jsonString + '}';
+ auto json = nlohmann::json::parse(*jsonString);
+
+ jsonString = pel.userHeader().getJSON();
+
+ // UserHeader always prints JSON
+ ASSERT_TRUE(jsonString);
+ *jsonString = '{' + *jsonString + '}';
+ json = nlohmann::json::parse(*jsonString);
+
+ for (const auto& section : pel.optionalSections())
+ {
+ // The optional sections may or may not have implemented getJSON().
+ jsonString = section->getJSON();
+ if (jsonString)
+ {
+ *jsonString = '{' + *jsonString + '}';
+ auto json = nlohmann::json::parse(*jsonString);
+ }
+ }
+}
OpenPOWER on IntegriCloud