| #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 |