blob: 593a325ef7366e3997778ec2da1a2ddf4ae9cc1d [file]
#include "sse_plugin/event.h"
#include <string>
#include <utility>
#include "quality/actions/offline/android/portable_protos/portable_message.h"
#include "gmock.h"
#include "gunit.h"
#include "absl/container/flat_hash_map.h"
#include "absl/status/status.h"
#include "absl/strings/str_format.h"
#include "absl/strings/string_view.h"
#include "redfish_query_engine/protobuf/parse.h"
#include "proxy_config.pb.h"
#include "events.pb.h"
#include "vendor_events.pb.h"
#include "google/protobuf/repeated_ptr_field.h"
namespace milotic {
namespace {
using testing::AllOf;
using testing::EqualsProto;
using testing::Property;
using testing::SizeIs;
using testing::status::IsOkAndHolds;
using testing::status::StatusIs;
TEST(ParseRedfishEventTest, InvalidJson) {
constexpr absl::string_view kEventJson = R"json(invalid-json)json";
EventParseConfig parse_config;
EXPECT_THAT(
Event::ParseRedfishEvent(parse_config, kEventJson),
StatusIs(absl::StatusCode::kInvalidArgument, "Failed to parse json"));
}
TEST(ParseRedfishEventTest, InvalidEventJsonNotArray) {
constexpr absl::string_view kEventJson =
R"json({"Id" : "1","Events": {"MessageSeverity": "OK", "EventId":
"1"}})json";
EventParseConfig parse_config;
EXPECT_THAT(
Event::ParseRedfishEvent(parse_config, kEventJson),
StatusIs(
absl::StatusCode::kInvalidArgument,
"Invalid event json, Events should be an array with single element"));
}
TEST(ParseRedfishEventTest, InvalidEventJsonArraySizeZero) {
constexpr absl::string_view kEventJson =
R"json({"Id" : "1","Events": []})json";
EventParseConfig parse_config;
EXPECT_THAT(
Event::ParseRedfishEvent(parse_config, kEventJson),
StatusIs(
absl::StatusCode::kInvalidArgument,
"Invalid event json, Events should be an array with single element"));
}
TEST(ParseRedfishEventTest, InvalidEventJsonArraySizeGTOne) {
constexpr absl::string_view kEventJson =
R"json({"Id" : "1","Events": [{"MessageSeverity": "OK", "EventId":
"1"}, {"MessageSeverity": "OK", "EventId": "2"}]})json";
EventParseConfig parse_config;
EXPECT_THAT(
Event::ParseRedfishEvent(parse_config, kEventJson),
StatusIs(
absl::StatusCode::kInvalidArgument,
"Invalid event json, Events should be an array with single element"));
}
TEST(ParseRedfishEventTest, SSEIdEventIdMismatch) {
constexpr absl::string_view kEventJson =
R"json({"Id" : "1","Events": [{"MessageSeverity": "OK", "EventId":
"2"}]})json";
EventParseConfig parse_config;
EXPECT_THAT(Event::ParseRedfishEvent(parse_config, kEventJson),
StatusIs(absl::StatusCode::kInvalidArgument,
"EventId mismatch, Id: 1, Events[0][EventId]: 2"));
}
TEST(ParseRedfishEventTest, EventIdNotNumber) {
constexpr absl::string_view kEventJson =
R"json({"Id" : "a","Events": [{"MessageSeverity": "OK", "EventId":
"a"}]})json";
EventParseConfig parse_config;
EXPECT_THAT(
Event::ParseRedfishEvent(parse_config, kEventJson),
StatusIs(absl::StatusCode::kInvalidArgument, "EventId is not a number"));
}
TEST(ParseRedfishEventTest, InvalidMessageSev) {
constexpr absl::string_view kEventJson =
R"json({"Id" : "1","Events": [{"MessageSeverity": "Invalid", "EventId":
"1"}]})json";
EventParseConfig parse_config;
EXPECT_THAT(
Event::ParseRedfishEvent(parse_config, kEventJson),
StatusIs(absl::StatusCode::kInvalidArgument, "Invalid message severity"));
}
TEST(ParseRedfishEventTest, OkEvent) {
constexpr absl::string_view kEventJson =
R"json({"Id" : "1","Events": [{"MessageSeverity": "OK", "EventId":
"1"}]})json";
EventParseConfig parse_config;
EXPECT_THAT(Event::ParseRedfishEvent(parse_config, kEventJson),
IsOkAndHolds(
Contains(AllOf(Property(&Event::severity, EventSeverity::kOk),
Property(&Event::event_id, 1)))));
}
TEST(ParseRedfishEventTest, WarningEvent) {
constexpr absl::string_view kEventJson =
R"json({"Id" : "1","Events": [{"MessageSeverity": "Warning", "EventId":
"1"}]})json";
EventParseConfig parse_config;
EXPECT_THAT(Event::ParseRedfishEvent(parse_config, kEventJson),
IsOkAndHolds(Contains(
AllOf(Property(&Event::severity, EventSeverity::kWarning),
Property(&Event::event_id, 1)))));
}
TEST(ParseRedfishEventTest, CriticalEvent) {
constexpr absl::string_view kEventJson =
R"json({"Id" : "1","Events": [{"MessageSeverity": "Critical",
"EventId": "1"}]})json";
EventParseConfig parse_config;
EXPECT_THAT(Event::ParseRedfishEvent(parse_config, kEventJson),
IsOkAndHolds(Contains(
AllOf(Property(&Event::severity, EventSeverity::kCritical),
Property(&Event::event_id, 1)))));
}
milotic_grpc_proxy::EventParse GetEventParseProtoWithOemPathReasonId() {
return ecclesia::ParseTextAsProtoOrDie<milotic_grpc_proxy::EventParse>(R"pb(
reason_id_parse: { oem_field_path: "/OriginOfCondition/Oem/Hpe/Faults" }
)pb");
}
// Test various failure conditions on FindReasonId, such that event severity
// falls to MessageSeverity
TEST(FindReasonIdOemPathTest, EventWithInvalidReasonID) {
// ReasonID should be int
constexpr absl::string_view kEventJson =
R"json({"Id" : "1","Events": [{"MessageSeverity": "Warning", "EventId":
"1", "OriginOfCondition": {"Oem": {"Hpe": {"Faults": [{"Reasons":
[{"ReasonId": "302", "DateTime": "2023-05-12T01:51:50Z"}]}]}}}
}]})json";
absl::flat_hash_map<int, platforms_vbmc::VendorEvent> registry;
auto vendor_event = platforms_vbmc::VendorEvent();
vendor_event.set_severity(platforms_vbmc::OtsEvent::SEVERITY_CRITICAL);
vendor_event.set_reason_id(302);
registry.emplace(302, vendor_event);
EventParseConfig parse_config = {
.registry = registry,
.event_parse = GetEventParseProtoWithOemPathReasonId()};
EXPECT_THAT(Event::ParseRedfishEvent(parse_config, kEventJson),
IsOkAndHolds(Contains(
AllOf(Property(&Event::severity, EventSeverity::kWarning),
Property(&Event::event_id, 1),
Property(&Event::reason_id, kInvalidReasonId)))));
}
TEST(FindReasonIdOemPathTest, EventWithInvalidDateTime1) {
// DateTime should be string
constexpr absl::string_view kEventJson =
R"json({"Id" : "1","Events": [{"MessageSeverity": "Warning", "EventId":
"1", "OriginOfCondition": {"Oem": {"Hpe": {"Faults": [{"Reasons":
[{"ReasonId": 302, "DateTime": 123}]}]}}}
}]})json";
absl::flat_hash_map<int, platforms_vbmc::VendorEvent> registry;
auto vendor_event = platforms_vbmc::VendorEvent();
vendor_event.set_severity(platforms_vbmc::OtsEvent::SEVERITY_CRITICAL);
vendor_event.set_reason_id(302);
registry.emplace(302, vendor_event);
EventParseConfig parse_config = {
.registry = registry,
.event_parse = GetEventParseProtoWithOemPathReasonId()};
EXPECT_THAT(Event::ParseRedfishEvent(parse_config, kEventJson),
IsOkAndHolds(Contains(
AllOf(Property(&Event::severity, EventSeverity::kWarning),
Property(&Event::event_id, 1),
Property(&Event::reason_id, kInvalidReasonId)))));
}
TEST(FindReasonIdOemPathTest, EventWithInvalidDateTime2) {
// DateTime should be valid
constexpr absl::string_view kEventJson =
R"json({"Id" : "1","Events": [{"MessageSeverity": "Warning", "EventId":
"1", "OriginOfCondition": {"Oem": {"Hpe": {"Faults": [{"Reasons":
[{"ReasonId": "302", "DateTime": "2023-05-12T01:51:90Z"}]}]}}}
}]})json";
absl::flat_hash_map<int, platforms_vbmc::VendorEvent> registry;
auto vendor_event = platforms_vbmc::VendorEvent();
vendor_event.set_severity(platforms_vbmc::OtsEvent::SEVERITY_CRITICAL);
vendor_event.set_reason_id(302);
registry.emplace(302, vendor_event);
EventParseConfig parse_config = {
.registry = registry,
.event_parse = GetEventParseProtoWithOemPathReasonId()};
EXPECT_THAT(Event::ParseRedfishEvent(parse_config, kEventJson),
IsOkAndHolds(Contains(
AllOf(Property(&Event::severity, EventSeverity::kWarning),
Property(&Event::event_id, 1),
Property(&Event::reason_id, kInvalidReasonId)))));
}
TEST(FindReasonIdOemPathTest, EventWithNoReasonId) {
// No Reason ID in event
constexpr absl::string_view kEventJson =
R"json({"Id" : "1","Events": [{"MessageSeverity": "Warning", "EventId":
"1", "OriginOfCondition": {"Oem": {"Hpe": {"Faults": [{"Reasons":
[]}]}}}
}]})json";
absl::flat_hash_map<int, platforms_vbmc::VendorEvent> registry;
auto vendor_event = platforms_vbmc::VendorEvent();
vendor_event.set_severity(platforms_vbmc::OtsEvent::SEVERITY_CRITICAL);
vendor_event.set_reason_id(302);
registry.emplace(302, vendor_event);
EventParseConfig parse_config = {
.registry = registry,
.event_parse = GetEventParseProtoWithOemPathReasonId()};
EXPECT_THAT(Event::ParseRedfishEvent(parse_config, kEventJson),
IsOkAndHolds(Contains(
AllOf(Property(&Event::severity, EventSeverity::kWarning),
Property(&Event::event_id, 1),
Property(&Event::reason_id, kInvalidReasonId)))));
}
TEST(FindReasonIdOemPathTest, EventWithReasonsNotArray) {
// Reasons is not array
constexpr absl::string_view kEventJson =
R"json({"Id" : "1","Events": [{"MessageSeverity": "Warning", "EventId":
"1", "OriginOfCondition": {"Oem": {"Hpe": {"Faults": [{"Reasons":
{}}]}}}
}]})json";
absl::flat_hash_map<int, platforms_vbmc::VendorEvent> registry;
auto vendor_event = platforms_vbmc::VendorEvent();
vendor_event.set_severity(platforms_vbmc::OtsEvent::SEVERITY_CRITICAL);
vendor_event.set_reason_id(302);
registry.emplace(302, vendor_event);
EventParseConfig parse_config = {
.registry = registry,
.event_parse = GetEventParseProtoWithOemPathReasonId()};
EXPECT_THAT(Event::ParseRedfishEvent(parse_config, kEventJson),
IsOkAndHolds(Contains(
AllOf(Property(&Event::severity, EventSeverity::kWarning),
Property(&Event::event_id, 1),
Property(&Event::reason_id, kInvalidReasonId)))));
}
TEST(FindReasonIdOemPathTest, EventWithNoReasonsInFaults) {
// No Reasons in Faults
constexpr absl::string_view kEventJson =
R"json({"Id" : "1","Events": [{"MessageSeverity": "Warning", "EventId":
"1", "OriginOfCondition": {"Oem": {"Hpe": {"Faults": []}}}
}]})json";
absl::flat_hash_map<int, platforms_vbmc::VendorEvent> registry;
auto vendor_event = platforms_vbmc::VendorEvent();
vendor_event.set_severity(platforms_vbmc::OtsEvent::SEVERITY_CRITICAL);
vendor_event.set_reason_id(302);
registry.emplace(302, vendor_event);
EventParseConfig parse_config = {
.registry = registry,
.event_parse = GetEventParseProtoWithOemPathReasonId()};
EXPECT_THAT(Event::ParseRedfishEvent(parse_config, kEventJson),
IsOkAndHolds(Contains(
AllOf(Property(&Event::severity, EventSeverity::kWarning),
Property(&Event::event_id, 1),
Property(&Event::reason_id, kInvalidReasonId)))));
}
TEST(FindReasonIdOemPathTest, EventWithFaultsNotArray) {
// Faults is not array
constexpr absl::string_view kEventJson =
R"json({"Id" : "1","Events": [{"MessageSeverity": "Warning", "EventId":
"1", "OriginOfCondition": {"Oem": {"Hpe": {"Faults": {}}}}
}]})json";
absl::flat_hash_map<int, platforms_vbmc::VendorEvent> registry;
auto vendor_event = platforms_vbmc::VendorEvent();
vendor_event.set_severity(platforms_vbmc::OtsEvent::SEVERITY_CRITICAL);
vendor_event.set_reason_id(302);
registry.emplace(302, vendor_event);
EventParseConfig parse_config = {
.registry = registry,
.event_parse = GetEventParseProtoWithOemPathReasonId()};
EXPECT_THAT(Event::ParseRedfishEvent(parse_config, kEventJson),
IsOkAndHolds(Contains(
AllOf(Property(&Event::severity, EventSeverity::kWarning),
Property(&Event::event_id, 1),
Property(&Event::reason_id, kInvalidReasonId)))));
}
TEST(FindReasonIdOemPathTest, EventWithFaultPathNotPresent1) {
// Faults path not present
constexpr absl::string_view kEventJson =
R"json({"Id" : "1","Events": [{"MessageSeverity": "Warning", "EventId":
"1", "OriginOfCondition": {"Oem": {"Hpe": {"Faults1": {}}}}
}]})json";
absl::flat_hash_map<int, platforms_vbmc::VendorEvent> registry;
auto vendor_event = platforms_vbmc::VendorEvent();
vendor_event.set_severity(platforms_vbmc::OtsEvent::SEVERITY_CRITICAL);
vendor_event.set_reason_id(302);
registry.emplace(302, vendor_event);
EventParseConfig parse_config = {
.registry = registry,
.event_parse = GetEventParseProtoWithOemPathReasonId()};
EXPECT_THAT(Event::ParseRedfishEvent(parse_config, kEventJson),
IsOkAndHolds(Contains(
AllOf(Property(&Event::severity, EventSeverity::kWarning),
Property(&Event::event_id, 1),
Property(&Event::reason_id, kInvalidReasonId)))));
}
TEST(FindReasonIdOemPathTest, EventWithFaultPathNotPresent2) {
// Faults path not present
constexpr absl::string_view kEventJson =
R"json({"Id" : "1","Events": [{"MessageSeverity": "Warning", "EventId":
"1", "OriginOfCondition": {"Oem": {"Hpe": {}}}
}]})json";
absl::flat_hash_map<int, platforms_vbmc::VendorEvent> registry;
auto vendor_event = platforms_vbmc::VendorEvent();
vendor_event.set_severity(platforms_vbmc::OtsEvent::SEVERITY_CRITICAL);
vendor_event.set_reason_id(302);
registry.emplace(302, vendor_event);
EventParseConfig parse_config = {
.registry = registry,
.event_parse = GetEventParseProtoWithOemPathReasonId()};
EXPECT_THAT(Event::ParseRedfishEvent(parse_config, kEventJson),
IsOkAndHolds(Contains(
AllOf(Property(&Event::severity, EventSeverity::kWarning),
Property(&Event::event_id, 1),
Property(&Event::reason_id, kInvalidReasonId)))));
}
TEST(FindReasonIdOemPathTest, EventWithFaultPathNotPresent3) {
// Faults path not present
constexpr absl::string_view kEventJson =
R"json({"Id" : "1","Events": [{"MessageSeverity": "Warning", "EventId":
"1", "OriginOfCondition": {"Oem": {"Hpe": []}}
}]})json";
absl::flat_hash_map<int, platforms_vbmc::VendorEvent> registry;
auto vendor_event = platforms_vbmc::VendorEvent();
vendor_event.set_severity(platforms_vbmc::OtsEvent::SEVERITY_CRITICAL);
vendor_event.set_reason_id(302);
registry.emplace(302, vendor_event);
EventParseConfig parse_config = {
.registry = registry,
.event_parse = GetEventParseProtoWithOemPathReasonId()};
EXPECT_THAT(Event::ParseRedfishEvent(parse_config, kEventJson),
IsOkAndHolds(Contains(
AllOf(Property(&Event::severity, EventSeverity::kWarning),
Property(&Event::event_id, 1),
Property(&Event::reason_id, kInvalidReasonId)))));
}
TEST(FindReasonIdOemPathTest, EventWithFaultPathNotPresent4) {
// Faults path not present
constexpr absl::string_view kEventJson =
R"json({"Id" : "1","Events": [{"MessageSeverity": "Warning", "EventId":
"1", "OriginOfCondition": {"Oem": []}
}]})json";
absl::flat_hash_map<int, platforms_vbmc::VendorEvent> registry;
auto vendor_event = platforms_vbmc::VendorEvent();
vendor_event.set_severity(platforms_vbmc::OtsEvent::SEVERITY_CRITICAL);
vendor_event.set_reason_id(302);
registry.emplace(302, vendor_event);
EventParseConfig parse_config = {
.registry = registry,
.event_parse = GetEventParseProtoWithOemPathReasonId()};
EXPECT_THAT(Event::ParseRedfishEvent(parse_config, kEventJson),
IsOkAndHolds(Contains(
AllOf(Property(&Event::severity, EventSeverity::kWarning),
Property(&Event::event_id, 1),
Property(&Event::reason_id, kInvalidReasonId)))));
}
TEST(FindReasonIdOemPathTest, EventWithValidReasonID) {
// Registry severity should be used instead of MessageSeverity
constexpr absl::string_view kEventJson =
R"json({"Id" : "1","Events": [{"MessageSeverity": "Warning", "EventId":
"1", "OriginOfCondition": {"Oem": {"Hpe": {"Faults": [{"Reasons":
[{"ReasonId": 302, "DateTime": "2023-05-12T01:51:50Z"}]}]}}}
}]})json";
absl::flat_hash_map<int, platforms_vbmc::VendorEvent> registry;
auto vendor_event = platforms_vbmc::VendorEvent();
vendor_event.set_severity(platforms_vbmc::OtsEvent::SEVERITY_CRITICAL);
vendor_event.set_reason_id(302);
registry.emplace(302, vendor_event);
EventParseConfig parse_config = {
.registry = registry,
.event_parse = GetEventParseProtoWithOemPathReasonId()};
EXPECT_THAT(
Event::ParseRedfishEvent(parse_config, kEventJson),
IsOkAndHolds(Contains(AllOf(
Property(&Event::severity, EventSeverity::kCritical),
Property(&Event::event_id, 1), Property(&Event::reason_id, 302)))));
}
TEST(FindReasonIdOemPathTest, EventWithMultipleReasonID) {
// Registry severity should be used of reason ID with max DateTime
// even if severity of other reason is higher
constexpr absl::string_view kEventJson =
R"json({"Id" : "1","Events": [{"MessageSeverity": "Ok", "EventId": "1",
"OriginOfCondition": {"Oem": {"Hpe": {"Faults": [{"Reasons": [
{"ReasonId": 302, "DateTime": "2023-05-12T01:51:50Z"},
{"ReasonId": 303, "DateTime": "2023-05-13T01:51:50Z"}
]}]}}}
}]})json";
absl::flat_hash_map<int, platforms_vbmc::VendorEvent> registry;
auto vendor_event1 = platforms_vbmc::VendorEvent();
vendor_event1.set_severity(platforms_vbmc::OtsEvent::SEVERITY_CRITICAL);
vendor_event1.set_reason_id(302);
registry.emplace(302, vendor_event1);
auto vendor_event2 = platforms_vbmc::VendorEvent();
vendor_event2.set_severity(platforms_vbmc::OtsEvent::SEVERITY_WARNING);
vendor_event2.set_reason_id(303);
registry.emplace(303, vendor_event2);
EventParseConfig parse_config = {
.registry = registry,
.event_parse = GetEventParseProtoWithOemPathReasonId()};
EXPECT_THAT(
Event::ParseRedfishEvent(parse_config, kEventJson),
IsOkAndHolds(Contains(AllOf(
Property(&Event::severity, EventSeverity::kWarning),
Property(&Event::event_id, 1), Property(&Event::reason_id, 303)))));
}
TEST(FindReasonIdOemPathTest, EventWithReasonIdNotInRegistry) {
// If reason ID is not found in registry fall back to MessageSeverity
constexpr absl::string_view kEventJson =
R"json({"Id" : "1","Events": [{"MessageSeverity": "Warning", "EventId":
"1", "OriginOfCondition": {"Oem": {"Hpe": {"Faults": [{"Reasons":
[{"ReasonId": 302, "DateTime": "2023-05-12T01:51:50Z"}]}]}}}
}]})json";
EventParseConfig parse_config = {.event_parse =
GetEventParseProtoWithOemPathReasonId()};
EXPECT_THAT(
Event::ParseRedfishEvent(parse_config, kEventJson),
IsOkAndHolds(Contains(AllOf(
Property(&Event::severity, EventSeverity::kWarning),
Property(&Event::event_id, 1), Property(&Event::reason_id, 302)))));
}
milotic_grpc_proxy::EventParse GetEventParseProtoWithMsgArgsReasonId() {
return ecclesia::ParseTextAsProtoOrDie<milotic_grpc_proxy::EventParse>(R"pb(
reason_id_parse: {
message_args_index: {
message_key: "ServiceEventGeneratedNoIndictment"
message_arg_index: 1
}
}
)pb");
}
TEST(FindReasonIdMessageArgsTest, EventWithInvalidMessageId) {
// If MessageId is invalid and reason id parsing with message arg is set,
// InvalidArgument error is returned
constexpr absl::string_view kEventJson =
R"json({"Id" : "1","Events": [{
"MessageSeverity": "Critical", "EventId": "1",
"Message": "A service event has been generated against npar 0 for reason ID 1349.",
"MessageArgs":["0","1349"],
"MessageId":"ServiceEventGeneratedNoIndictment"
}]})json";
EventParseConfig parse_config = {.event_parse =
GetEventParseProtoWithMsgArgsReasonId()};
EXPECT_THAT(Event::ParseRedfishEvent(parse_config, kEventJson),
StatusIs(absl::StatusCode::kInvalidArgument,
"MessageId not in correct format"));
}
TEST(FindReasonIdMessageArgsTest, MessageArgIndexNotPresent) {
// MessageSeverity will be used, since we're not able to find the reason ID
constexpr absl::string_view kEventJson =
R"json({"Id" : "1","Events": [{
"MessageSeverity": "Critical", "EventId": "1",
"Message": "A service event has been generated against npar 0 for reason ID 1349.",
"MessageArgs":["1349"],
"MessageId":"H3Alert.1.1.ServiceEventGeneratedNoIndictment"
}]})json";
EventParseConfig parse_config = {.event_parse =
GetEventParseProtoWithMsgArgsReasonId()};
EXPECT_THAT(Event::ParseRedfishEvent(parse_config, kEventJson),
IsOkAndHolds(Contains(
AllOf(Property(&Event::severity, EventSeverity::kCritical),
Property(&Event::event_id, 1),
Property(&Event::reason_id, kInvalidReasonId)))));
}
TEST(FindReasonIdMessageArgsTest, MessageArgIndexNotInt) {
// MessageSeverity will be used, since we're not able to find the reason ID
constexpr absl::string_view kEventJson =
R"json({"Id" : "1","Events": [{
"MessageSeverity": "Critical", "EventId": "1",
"Message": "A service event has been generated against npar 0 for reason ID 1349.",
"MessageArgs":["0", "invalid"],
"MessageId":"H3Alert.1.1.ServiceEventGeneratedNoIndictment"
}]})json";
EventParseConfig parse_config = {.event_parse =
GetEventParseProtoWithMsgArgsReasonId()};
EXPECT_THAT(Event::ParseRedfishEvent(parse_config, kEventJson),
IsOkAndHolds(Contains(
AllOf(Property(&Event::severity, EventSeverity::kCritical),
Property(&Event::event_id, 1),
Property(&Event::reason_id, kInvalidReasonId)))));
}
TEST(FindReasonIdMessageArgsTest, EventWithValidReasonID) {
// Registry severity should be used instead of MessageSeverity
constexpr absl::string_view kEventJson =
R"json({"Id" : "1","Events": [{
"MessageSeverity": "Critical", "EventId": "1",
"Message": "A service event has been generated against npar 0 for reason ID 1349.",
"MessageArgs":["0","1349"],
"MessageId":"H3Alert.1.1.ServiceEventGeneratedNoIndictment"
}]})json";
absl::flat_hash_map<int, platforms_vbmc::VendorEvent> registry;
auto vendor_event = platforms_vbmc::VendorEvent();
vendor_event.set_severity(platforms_vbmc::OtsEvent::SEVERITY_WARNING);
vendor_event.set_reason_id(1349);
registry.emplace(1349, vendor_event);
EventParseConfig parse_config = {
.registry = registry,
.event_parse = GetEventParseProtoWithMsgArgsReasonId()};
EXPECT_THAT(
Event::ParseRedfishEvent(parse_config, kEventJson),
IsOkAndHolds(Contains(AllOf(
Property(&Event::severity, EventSeverity::kWarning),
Property(&Event::event_id, 1), Property(&Event::reason_id, 1349)))));
}
TEST(FindReasonIdMessageArgsTest, EventWithMissingMessageArgs) {
// Registry severity should be used instead of MessageSeverity
constexpr absl::string_view kEventJson =
R"json({"Id" : "1","Events": [{
"MessageSeverity": "Critical", "EventId": "1",
"Message": "A service event has been generated against npar 0 for reason ID 1349.",
"MessageId":"H3Alert.1.1.ServiceEventGeneratedNoIndictment"
}]})json";
EventParseConfig parse_config = {.event_parse =
GetEventParseProtoWithMsgArgsReasonId()};
EXPECT_THAT(Event::ParseRedfishEvent(parse_config, kEventJson),
IsOkAndHolds(Contains(
AllOf(Property(&Event::severity, EventSeverity::kCritical),
Property(&Event::event_id, 1),
Property(&Event::reason_id, kInvalidReasonId)))));
}
TEST(IgnoreEventsWOReasonIdTest, UseOkSeverity) {
// If ignore w/o reasonId is set, use Ok severity if we cannot find reasonId
constexpr absl::string_view kEventJson =
R"json({"Id" : "1","Events": [{
"MessageSeverity": "Critical", "EventId": "1",
"MessageId":"H3Alert.1.1.ServiceEventGeneratedNoIndictment"
}]})json";
milotic_grpc_proxy::EventParse proto_config;
proto_config.set_ignore_event_sev_wo_reason_id(true);
EventParseConfig parse_config = {.event_parse = proto_config};
EXPECT_THAT(Event::ParseRedfishEvent(parse_config, kEventJson),
IsOkAndHolds(
Contains(AllOf(Property(&Event::severity, EventSeverity::kOk),
Property(&Event::event_id, 1)))));
}
TEST(IgnoreEventsWOReasonIdTest, ReasonIdPresentRegistryEmpty) {
// If we find reasonId but registry is empty/doesn't contain the reasonId we
// use MessageSeverity
constexpr absl::string_view kEventJson =
R"json({"Id" : "1","Events": [{
"MessageSeverity": "Critical", "EventId": "1",
"Message": "A service event has been generated against npar 0 for reason ID 1349.",
"MessageArgs":["0","1349"],
"MessageId":"H3Alert.1.1.ServiceEventGeneratedNoIndictment"
}]})json";
milotic_grpc_proxy::EventParse proto_config =
GetEventParseProtoWithMsgArgsReasonId();
proto_config.set_ignore_event_sev_wo_reason_id(true);
EventParseConfig parse_config = {.event_parse = proto_config};
EXPECT_THAT(
Event::ParseRedfishEvent(parse_config, kEventJson),
IsOkAndHolds(Contains(AllOf(
Property(&Event::severity, EventSeverity::kCritical),
Property(&Event::event_id, 1), Property(&Event::reason_id, 1349)))));
}
TEST(FindMessageKeyTest, EventWithInvalidMessageId) {
// If MessageId is invalid and ignore_message_keys is set,
// InvalidArgument error is returned
constexpr absl::string_view kEventJson =
R"json({"Id" : "1","Events": [{"MessageSeverity": "Warning", "EventId": "1",
"MessageId": "LastEventIdTooOld"
}]})json";
RepeatedPtrField<std::string> ignore_list;
ignore_list.Add("LastEventIdTooOld");
milotic_grpc_proxy::EventParse proto_config;
*proto_config.mutable_ignore_event_sev_message_keys() = ignore_list;
EventParseConfig parse_config = {.event_parse = proto_config};
EXPECT_THAT(Event::ParseRedfishEvent(parse_config, kEventJson),
StatusIs(absl::StatusCode::kInvalidArgument,
"MessageId not in correct format"));
}
TEST(FindMessageKeyTest, EventWithMessageKeyInIgnoreList) {
// OK severity should be used instead of MessageSeverity
constexpr absl::string_view kEventJson =
R"json({"Id" : "1","Events": [{"MessageSeverity": "Warning", "EventId": "1",
"MessageId": "H3Alert.1.1.LastEventIdTooOld"
}]})json";
RepeatedPtrField<std::string> ignore_list;
ignore_list.Add("LastEventIdTooOld");
milotic_grpc_proxy::EventParse proto_config;
*proto_config.mutable_ignore_event_sev_message_keys() = ignore_list;
EventParseConfig parse_config = {.event_parse = proto_config};
EXPECT_THAT(Event::ParseRedfishEvent(parse_config, kEventJson),
IsOkAndHolds(
Contains(AllOf(Property(&Event::severity, EventSeverity::kOk),
Property(&Event::event_id, 1)))));
}
TEST(FindMessagePrefixTest, EventWithInvalidMessageId) {
// If MessageId is invalid and ignore_message_prefix is set,
// InvalidArgument error is returned
constexpr absl::string_view kEventJson =
R"json({"Id" : "1","Events": [{"MessageSeverity": "Warning", "EventId": "1",
"MessageId": "ResourceStatusChangedWarning"
}]})json";
RepeatedPtrField<std::string> ignore_list;
ignore_list.Add("ResourceEvent");
milotic_grpc_proxy::EventParse proto_config;
*proto_config.mutable_ignore_event_sev_message_prefix() = ignore_list;
EventParseConfig parse_config = {.event_parse = proto_config};
EXPECT_THAT(Event::ParseRedfishEvent(parse_config, kEventJson),
StatusIs(absl::StatusCode::kInvalidArgument,
"MessageId not in correct format"));
}
TEST(FindMessagePrefixTest, EventWithMessagePrefixInIgnoreList) {
// OK severity should be used instead of MessageSeverity
constexpr absl::string_view kEventJson =
R"json({"Id" : "1","Events": [{"MessageSeverity": "Warning", "EventId": "1",
"MessageId": "ResourceEvent.1.3.ResourceStatusChangedWarning"
}]})json";
RepeatedPtrField<std::string> ignore_list;
ignore_list.Add("ResourceEvent");
milotic_grpc_proxy::EventParse proto_config;
*proto_config.mutable_ignore_event_sev_message_prefix() = ignore_list;
EventParseConfig parse_config = {.event_parse = proto_config};
EXPECT_THAT(Event::ParseRedfishEvent(parse_config, kEventJson),
IsOkAndHolds(
Contains(AllOf(Property(&Event::severity, EventSeverity::kOk),
Property(&Event::event_id, 1)))));
}
TEST(ParseReplayEventTest, EmptyResponse) {
constexpr absl::string_view kEventJson;
EventParseConfig parse_config;
EXPECT_THAT(Event::ParseReplayEvents(parse_config, kEventJson),
IsOkAndHolds(SizeIs(0)));
}
TEST(ParseReplayEventTest, InvalidJson) {
constexpr absl::string_view kEventJson = R"json(invalid-json)json";
EventParseConfig parse_config;
EXPECT_THAT(
Event::ParseReplayEvents(parse_config, kEventJson),
StatusIs(absl::StatusCode::kInvalidArgument, "Failed to parse json"));
}
TEST(ParseReplayEventTest, NotArray) {
constexpr absl::string_view kEventJson =
R"json({"MessageSeverity": "Critical", "EventId": "1"})json";
EventParseConfig parse_config;
EXPECT_THAT(Event::ParseReplayEvents(parse_config, kEventJson),
StatusIs(absl::StatusCode::kInvalidArgument, "Invalid json"));
}
TEST(ParseReplayEventTest, MultipleEvents) {
constexpr absl::string_view kEventJson =
R"json([{"MessageSeverity": "Critical", "EventId": "1"},
{"MessageSeverity": "Critical", "EventId": "2"}])json";
EventParseConfig parse_config;
EXPECT_THAT(Event::ParseReplayEvents(parse_config, kEventJson),
IsOkAndHolds(SizeIs(2)));
}
TEST(ParseReplayEventTest, OneInvalidEvent) {
constexpr absl::string_view kEventJson =
R"json([{"MessageSeverity": "Critical", "EventId": "1"},
{"MessageSeverity": "Critical", "EventId": "a"}])json";
EventParseConfig parse_config;
EXPECT_THAT(
Event::ParseReplayEvents(parse_config, kEventJson),
StatusIs(absl::StatusCode::kInvalidArgument, "EventId is not a number"));
}
TEST(EventSeverityTest, ToString) {
EXPECT_EQ(EventSeverityToString(EventSeverity::kOk), "OK");
EXPECT_EQ(EventSeverityToString(EventSeverity::kLog), "Log");
EXPECT_EQ(EventSeverityToString(EventSeverity::kWarning), "Warning");
EXPECT_EQ(EventSeverityToString(EventSeverity::kEmergent), "Emergent");
EXPECT_EQ(EventSeverityToString(EventSeverity::kCritical), "Critical");
EXPECT_EQ(EventSeverityToString(static_cast<EventSeverity>(255)), "");
}
TEST(EventSeverityTest, FromString) {
EXPECT_THAT(StringToEventSeverity("OK"), IsOkAndHolds(EventSeverity::kOk));
EXPECT_THAT(StringToEventSeverity("Warning"),
IsOkAndHolds(EventSeverity::kWarning));
EXPECT_THAT(StringToEventSeverity("Critical"),
IsOkAndHolds(EventSeverity::kCritical));
}
TEST(EventSeverityTest, FromStringInvalid) {
EXPECT_THAT(StringToEventSeverity("Invalid"),
StatusIs(absl::StatusCode::kInvalidArgument));
}
TEST(EventToProtoTest, ToProto_Redfish) {
Event event(R"({"Id": "1"})", 1, EventSeverity::kCritical, 100);
EXPECT_THAT(
event.ToProto(), EqualsProto(R"pb(
event { severity: SEVERITY_CRITICAL event_json: "{\"Id\": \"1\"}" }
)pb"));
}
TEST(EventAccessorsTest, CperData) {
Event::CperEventData cper_data;
cper_data.origin = "TestOrigin";
Event event(R"({"Id": "1"})", 1, EventSeverity::kOk, kInvalidReasonId,
std::move(cper_data));
EXPECT_TRUE(event.is_cper_event());
ASSERT_TRUE(event.cper_event_data().has_value());
EXPECT_EQ(event.cper_event_data()->origin, "TestOrigin");
}
TEST(EventAccessorsTest, NonCperData) {
Event redfish_event(R"({"Id": "2"})", 2, EventSeverity::kOk);
EXPECT_FALSE(redfish_event.is_cper_event());
EXPECT_FALSE(redfish_event.cper_event_data().has_value());
}
TEST(EventCoverageTest, ParseReplayEvents_NonObjectElement) {
// Parsed event is integer, not object.
constexpr absl::string_view kEventJson = R"json([1, "string"])json";
EventParseConfig parse_config;
EXPECT_THAT(Event::ParseReplayEvents(parse_config, kEventJson),
// Depending on CreateEvent implementation, it might fail to find
// EventId and return InvalidArgument "EventId not found"
StatusIs(absl::StatusCode::kInvalidArgument));
}
TEST(EventCoverageTest, ParseReplayEvents_MissingEventId) {
constexpr absl::string_view kEventJson = R"json([{"OnlyKey": "Value"}])json";
EventParseConfig parse_config;
EXPECT_THAT(
Event::ParseReplayEvents(parse_config, kEventJson),
StatusIs(absl::StatusCode::kInvalidArgument, "EventId not found"));
}
TEST(EventCoverageTest, FindEventMessageId_NoMessageId) {
// Trigger FindEventMessageId by having an ignore list
constexpr absl::string_view kEventJson =
R"json({"Id": "1", "Events": [{"EventId": "1", "MessageSeverity": "Critical"}]})json";
EventParseConfig parse_config = {
.event_parse =
ecclesia::ParseTextAsProtoOrDie<milotic_grpc_proxy::EventParse>(R"pb(
ignore_event_sev_message_keys: "SomeKey"
)pb")};
// Should return NotFound for MessageId, propagated as error because we tried
// to ignore keys
EXPECT_THAT(Event::ParseRedfishEvent(parse_config, kEventJson),
StatusIs(absl::StatusCode::kNotFound,
"event json does not contain MessageId"));
}
TEST(EventCoverageTest, FindEventMessageId_MessageIdNotString) {
constexpr absl::string_view kEventJson =
R"json({"Id": "1", "Events": [{"EventId": "1", "MessageSeverity": "Critical", "MessageId": 123}]})json";
EventParseConfig parse_config = {
.event_parse =
ecclesia::ParseTextAsProtoOrDie<milotic_grpc_proxy::EventParse>(R"pb(
ignore_event_sev_message_keys: "SomeKey"
)pb")};
EXPECT_THAT(
Event::ParseRedfishEvent(parse_config, kEventJson),
StatusIs(absl::StatusCode::kInvalidArgument, "MessageId is not string"));
}
TEST(EventCoverageTest, FindEventMessageId_MessageIdInvalidFormat) {
// Only 3 parts
constexpr absl::string_view kEventJson =
R"json({"Id": "1", "Events": [{"EventId": "1", "MessageSeverity": "Critical", "MessageId": "A.B.C"}]})json";
EventParseConfig parse_config = {
.event_parse =
ecclesia::ParseTextAsProtoOrDie<milotic_grpc_proxy::EventParse>(R"pb(
ignore_event_sev_message_keys: "SomeKey"
)pb")};
EXPECT_THAT(Event::ParseRedfishEvent(parse_config, kEventJson),
StatusIs(absl::StatusCode::kInvalidArgument,
"MessageId not in correct format"));
}
TEST(EventCoverageTest, FindReasonId_OemPath_FaultsNotObject) {
// Faults exists but is not array (already tested), test elements
constexpr absl::string_view kEventJson =
R"json({"Id" : "1","Events": [{"MessageSeverity": "Warning", "EventId": "1",
"OriginOfCondition": {"Oem": {"Hpe": {"Faults": [1, "string"]}}}
}]})json";
EventParseConfig parse_config = {.event_parse =
GetEventParseProtoWithOemPathReasonId()};
// Should continue and not find reason ID -> Warning
EXPECT_THAT(Event::ParseRedfishEvent(parse_config, kEventJson),
IsOkAndHolds(Contains(
Property(&Event::severity, EventSeverity::kWarning))));
}
TEST(EventCoverageTest, FindReasonSeverity_AllEnums) {
absl::flat_hash_map<int, platforms_vbmc::VendorEvent> registry;
auto add_event = [&](int id, platforms_vbmc::OtsEvent::Severity sev) {
platforms_vbmc::VendorEvent e;
e.set_severity(sev);
e.set_reason_id(id);
registry.emplace(id, e);
};
add_event(1, platforms_vbmc::OtsEvent::SEVERITY_OK);
add_event(2, platforms_vbmc::OtsEvent::SEVERITY_LOG);
add_event(3, platforms_vbmc::OtsEvent::SEVERITY_WARNING);
add_event(4, platforms_vbmc::OtsEvent::SEVERITY_EMERGENT);
add_event(5, platforms_vbmc::OtsEvent::SEVERITY_CRITICAL);
// Invalid/Unknown
add_event(6, platforms_vbmc::OtsEvent::SEVERITY_UNSPECIFIED);
auto make_json = [](int id) {
return absl::StrFormat(
R"json({"Id": "1", "Events": [{"MessageSeverity": "Critical", "EventId": "1",
"OriginOfCondition": {"Oem": {"Hpe": {"Faults": [{"Reasons": [{"ReasonId": %d, "DateTime": "2023-01-01T00:00:00Z"}]}]}}}
}]})json",
id);
};
EventParseConfig parse_config = {
.registry = registry,
.event_parse = GetEventParseProtoWithOemPathReasonId()};
// 1 -> OK
EXPECT_THAT(
Event::ParseRedfishEvent(parse_config, make_json(1)),
IsOkAndHolds(Contains(Property(&Event::severity, EventSeverity::kOk))));
// 2 -> Log
EXPECT_THAT(
Event::ParseRedfishEvent(parse_config, make_json(2)),
IsOkAndHolds(Contains(Property(&Event::severity, EventSeverity::kLog))));
// 3 -> Warning
EXPECT_THAT(Event::ParseRedfishEvent(parse_config, make_json(3)),
IsOkAndHolds(Contains(
Property(&Event::severity, EventSeverity::kWarning))));
// 4 -> Emergent
EXPECT_THAT(Event::ParseRedfishEvent(parse_config, make_json(4)),
IsOkAndHolds(Contains(
Property(&Event::severity, EventSeverity::kEmergent))));
// 5 -> Critical
EXPECT_THAT(Event::ParseRedfishEvent(parse_config, make_json(5)),
IsOkAndHolds(Contains(
Property(&Event::severity, EventSeverity::kCritical))));
// 6 -> Invalid severity in registry -> fallback to MessageSeverity (Critical)
EXPECT_THAT(Event::ParseRedfishEvent(parse_config, make_json(6)),
IsOkAndHolds(Contains(
Property(&Event::severity, EventSeverity::kCritical))));
}
TEST(EventCoverageTest, FindReasonIdMessageArgs_MismatchKey) {
constexpr absl::string_view kEventJson =
R"json({"Id" : "1", "Events": [{
"MessageSeverity": "Critical", "EventId": "1",
"MessageId": "Reg.1.0.CorrectKey",
"MessageArgs": ["123"]
}]})json";
auto proto_config =
ecclesia::ParseTextAsProtoOrDie<milotic_grpc_proxy::EventParse>(R"pb(
reason_id_parse: {
message_args_index: { message_key: "WrongKey" message_arg_index: 0 }
}
)pb");
EventParseConfig parse_config = {.event_parse = proto_config};
// Mismatch key -> Not Found -> fallback to critical
EXPECT_THAT(Event::ParseRedfishEvent(parse_config, kEventJson),
IsOkAndHolds(Contains(
Property(&Event::severity, EventSeverity::kCritical))));
}
TEST(EventCoverageTest, FindReasonIdMessageArgs_ArgsNotArray) {
constexpr absl::string_view kEventJson =
R"json({"Id" : "1", "Events": [{
"MessageSeverity": "Critical", "EventId": "1",
"MessageId": "Reg.1.0.CorrectKey",
"MessageArgs": {}
}]})json";
auto proto_config =
ecclesia::ParseTextAsProtoOrDie<milotic_grpc_proxy::EventParse>(R"pb(
reason_id_parse: {
message_args_index: { message_key: "CorrectKey" message_arg_index: 0 }
}
)pb");
EventParseConfig parse_config = {.event_parse = proto_config};
// MessageArgs not array -> Not Found -> fallback
EXPECT_THAT(Event::ParseRedfishEvent(parse_config, kEventJson),
IsOkAndHolds(Contains(
Property(&Event::severity, EventSeverity::kCritical))));
}
} // namespace
} // namespace milotic