blob: c193c3f0c3118849e1500aabdce092b82b1ca2b3 [file] [log] [blame]
/**
* 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 "extensions/openpower-pels/registry.hpp"
#include <filesystem>
#include <fstream>
#include <nlohmann/json.hpp>
#include <gtest/gtest.h>
using namespace openpower::pels::message;
namespace fs = std::filesystem;
const auto registryData = R"(
{
"PELs":
[
{
"Name": "xyz.openbmc_project.Power.Fault",
"Subsystem": "power_supply",
"SRC":
{
"ReasonCode": "0x2030"
}
},
{
"Name": "xyz.openbmc_project.Power.OverVoltage",
"Subsystem": "power_control_hw",
"Severity": "unrecoverable",
"MfgSeverity": "non_error",
"ActionFlags": ["service_action", "report", "call_home"],
"MfgActionFlags": ["hidden"],
"SRC":
{
"ReasonCode": "0x2333",
"Type": "BD",
"SymptomIDFields": ["SRCWord5", "SRCWord6", "SRCWord7"],
"PowerFault": true,
"Words6To9":
{
"6":
{
"description": "Failing unit number",
"AdditionalDataPropSource": "PS_NUM"
},
"7":
{
"description": "bad voltage",
"AdditionalDataPropSource": "VOLTAGE"
}
}
}
}
]
}
)";
class RegistryTest : public ::testing::Test
{
protected:
static void SetUpTestCase()
{
char path[] = "/tmp/regtestXXXXXX";
regDir = mkdtemp(path);
}
static void TearDownTestCase()
{
fs::remove_all(regDir);
}
static std::string writeData(const char* data)
{
fs::path path = regDir / "registry.json";
std::ofstream stream{path};
stream << data;
return path;
}
static fs::path regDir;
};
fs::path RegistryTest::regDir{};
TEST_F(RegistryTest, TestNoEntry)
{
auto path = RegistryTest::writeData(registryData);
Registry registry{path};
auto entry = registry.lookup("foo");
EXPECT_FALSE(entry);
}
TEST_F(RegistryTest, TestFindEntry)
{
auto path = RegistryTest::writeData(registryData);
Registry registry{path};
auto entry = registry.lookup("xyz.openbmc_project.Power.OverVoltage");
ASSERT_TRUE(entry);
EXPECT_EQ(entry->name, "xyz.openbmc_project.Power.OverVoltage");
EXPECT_EQ(entry->subsystem, 0x62);
EXPECT_EQ(*(entry->severity), 0x40);
EXPECT_EQ(*(entry->mfgSeverity), 0x00);
EXPECT_EQ(*(entry->actionFlags), 0xA800);
EXPECT_EQ(*(entry->mfgActionFlags), 0x4000);
EXPECT_EQ(entry->componentID, 0x2300);
EXPECT_FALSE(entry->eventType);
EXPECT_FALSE(entry->eventScope);
EXPECT_EQ(entry->src.type, 0xBD);
EXPECT_EQ(entry->src.reasonCode, 0x2333);
EXPECT_EQ(*(entry->src.powerFault), true);
auto& hexwords = entry->src.hexwordADFields;
EXPECT_TRUE(hexwords);
EXPECT_EQ((*hexwords).size(), 2);
auto word = (*hexwords).find(6);
EXPECT_NE(word, (*hexwords).end());
EXPECT_EQ(word->second, "PS_NUM");
word = (*hexwords).find(7);
EXPECT_NE(word, (*hexwords).end());
EXPECT_EQ(word->second, "VOLTAGE");
auto& sid = entry->src.symptomID;
EXPECT_TRUE(sid);
EXPECT_EQ((*sid).size(), 3);
EXPECT_NE(std::find((*sid).begin(), (*sid).end(), 5), (*sid).end());
EXPECT_NE(std::find((*sid).begin(), (*sid).end(), 6), (*sid).end());
EXPECT_NE(std::find((*sid).begin(), (*sid).end(), 7), (*sid).end());
}
// Check the entry that mostly uses defaults
TEST_F(RegistryTest, TestFindEntryMinimal)
{
auto path = RegistryTest::writeData(registryData);
Registry registry{path};
auto entry = registry.lookup("xyz.openbmc_project.Power.Fault");
ASSERT_TRUE(entry);
EXPECT_EQ(entry->name, "xyz.openbmc_project.Power.Fault");
EXPECT_EQ(entry->subsystem, 0x61);
EXPECT_FALSE(entry->severity);
EXPECT_FALSE(entry->mfgSeverity);
EXPECT_FALSE(entry->mfgActionFlags);
EXPECT_FALSE(entry->actionFlags);
EXPECT_EQ(entry->componentID, 0x2000);
EXPECT_FALSE(entry->eventType);
EXPECT_FALSE(entry->eventScope);
EXPECT_EQ(entry->src.reasonCode, 0x2030);
EXPECT_EQ(entry->src.type, 0xBD);
EXPECT_FALSE(entry->src.powerFault);
EXPECT_FALSE(entry->src.hexwordADFields);
EXPECT_FALSE(entry->src.symptomID);
}
TEST_F(RegistryTest, TestBadJSON)
{
auto path = RegistryTest::writeData("bad {} json");
Registry registry{path};
EXPECT_FALSE(registry.lookup("foo"));
}
// Test the helper functions the use the pel_values data.
TEST_F(RegistryTest, TestHelperFunctions)
{
using namespace openpower::pels::message::helper;
EXPECT_EQ(getSubsystem("input_power_source"), 0xA1);
EXPECT_THROW(getSubsystem("foo"), std::runtime_error);
EXPECT_EQ(getSeverity("symptom_recovered"), 0x71);
EXPECT_THROW(getSeverity("foo"), std::runtime_error);
EXPECT_EQ(getEventType("dump_notification"), 0x08);
EXPECT_THROW(getEventType("foo"), std::runtime_error);
EXPECT_EQ(getEventScope("possibly_multiple_platforms"), 0x04);
EXPECT_THROW(getEventScope("foo"), std::runtime_error);
std::vector<std::string> flags{"service_action", "dont_report",
"termination"};
EXPECT_EQ(getActionFlags(flags), 0x9100);
flags.clear();
flags.push_back("foo");
EXPECT_THROW(getActionFlags(flags), std::runtime_error);
}
TEST_F(RegistryTest, TestGetSRCReasonCode)
{
using namespace openpower::pels::message::helper;
EXPECT_EQ(getSRCReasonCode(R"({"ReasonCode": "0x5555"})"_json, "foo"),
0x5555);
EXPECT_THROW(getSRCReasonCode(R"({"ReasonCode": "ZZZZ"})"_json, "foo"),
std::runtime_error);
}
TEST_F(RegistryTest, TestGetSRCType)
{
using namespace openpower::pels::message::helper;
EXPECT_EQ(getSRCType(R"({"Type": "11"})"_json, "foo"), 0x11);
EXPECT_EQ(getSRCType(R"({"Type": "BF"})"_json, "foo"), 0xBF);
EXPECT_THROW(getSRCType(R"({"Type": "1"})"_json, "foo"),
std::runtime_error);
EXPECT_THROW(getSRCType(R"({"Type": "111"})"_json, "foo"),
std::runtime_error);
}
TEST_F(RegistryTest, TestGetSRCHexwordFields)
{
using namespace openpower::pels::message::helper;
const auto hexwords = R"(
{"Words6To9":
{
"8":
{
"AdditionalDataPropSource": "TEST"
}
}
})"_json;
auto fields = getSRCHexwordFields(hexwords, "foo");
EXPECT_TRUE(fields);
auto word = fields->find(8);
EXPECT_NE(word, fields->end());
const auto theInvalidRWord = R"(
{"Words6To9":
{
"R":
{
"AdditionalDataPropSource": "TEST"
}
}
})"_json;
EXPECT_THROW(getSRCHexwordFields(theInvalidRWord, "foo"),
std::runtime_error);
}
TEST_F(RegistryTest, TestGetSRCSymptomIDFields)
{
using namespace openpower::pels::message::helper;
const auto sID = R"(
{
"SymptomIDFields": ["SRCWord3", "SRCWord4", "SRCWord5"]
})"_json;
auto fields = getSRCSymptomIDFields(sID, "foo");
EXPECT_NE(std::find(fields->begin(), fields->end(), 3), fields->end());
EXPECT_NE(std::find(fields->begin(), fields->end(), 4), fields->end());
EXPECT_NE(std::find(fields->begin(), fields->end(), 5), fields->end());
const auto badField = R"(
{
"SymptomIDFields": ["SRCWord3", "SRCWord4", "SRCWord"]
})"_json;
EXPECT_THROW(getSRCSymptomIDFields(badField, "foo"), std::runtime_error);
}
TEST_F(RegistryTest, TestGetComponentID)
{
using namespace openpower::pels::message::helper;
// Get it from the JSON
auto id =
getComponentID(0xBD, 0x4200, R"({"ComponentID":"0x4200"})"_json, "foo");
EXPECT_EQ(id, 0x4200);
// Get it from the reason code on a 0xBD SRC
id = getComponentID(0xBD, 0x6700, R"({})"_json, "foo");
EXPECT_EQ(id, 0x6700);
// Not present on a 0x11 SRC
EXPECT_THROW(getComponentID(0x11, 0x8800, R"({})"_json, "foo"),
std::runtime_error);
}