#include "common/events.hpp" #include #include #include #include #include #include #include #include class TestEventServer; class TestEventEntry; using namespace std::literals; namespace EventIntf = phosphor::modbus::events; using EventServerIntf = sdbusplus::aserver::xyz::openbmc_project::logging::Create; using EventEntryIntf = sdbusplus::aserver::xyz::openbmc_project::logging::Entry; namespace SensorThresholdErrorIntf = sdbusplus::error::xyz::openbmc_project::sensor::Threshold; namespace SensorThresholdEventIntf = sdbusplus::event::xyz::openbmc_project::sensor::Threshold; namespace SensorErrorIntf = sdbusplus::error::xyz::openbmc_project::Sensor; namespace SensorEventIntf = sdbusplus::event::xyz::openbmc_project::Sensor; namespace ControllerErrorIntf = sdbusplus::error::xyz::openbmc_project::state::SMC; namespace ControllerEventIntf = sdbusplus::event::xyz::openbmc_project::state::SMC; namespace PowerErrorIntf = sdbusplus::error::xyz::openbmc_project::state::Power; namespace PowerEventIntf = sdbusplus::event::xyz::openbmc_project::state::Power; namespace LeakErrorIntf = sdbusplus::error::xyz::openbmc_project::state::leak::Detector; namespace LeakEventIntf = sdbusplus::event::xyz::openbmc_project::state::leak::Detector; // Test Event Class to mock the EventEntry class TestEventEntry : public EventEntryIntf { public: TestEventEntry(sdbusplus::async::context& ctx, const char* path) : EventEntryIntf(ctx, path) {} auto method_call(get_entry_t) -> sdbusplus::async::task { get_entry_t::return_type fd1 = 0; co_return fd1; } }; // Test Event Server Class to mock the EventServer class TestEventServer : public EventServerIntf { public: TestEventServer(sdbusplus::async::context& ctx, const char* path) : EventServerIntf(ctx, path), ctx(ctx) {} auto method_call(create_t, auto message, auto, auto) -> sdbusplus::async::task { static int cnt = 1; cnt++; // Append the count to the object path to make it unique for each event std::string objectPath = "/xyz/openbmc_project/logging/entry/TestEvent1" + std::to_string(cnt); EXPECT_EQ(message, expectedEvent) << "Event name mismatch"; eventEntries.emplace_back( std::make_unique(ctx, objectPath.c_str())); co_return sdbusplus::message::object_path(objectPath); } auto method_call(create_with_ffdc_files_t, auto, auto, auto, auto) -> sdbusplus::async::task { co_return; } std::string expectedEvent = ""; private: sdbusplus::async::context& ctx; std::vector> eventEntries; }; class EventsTest : public ::testing::Test { public: enum class EventTestType { sensorWarningEvent, sensorCriticalEvent, sensorFailureEvent, controllerFailureEvent, powerFailureEvent, leakWarningEvent, leakCriticalEvent, }; static constexpr auto sensorObjectPath = "/xyz/openbmc_project/sensors/OutletTemperature"; static constexpr auto serviceName = "xyz.openbmc_project.Logging"; static constexpr auto assert = true; static constexpr auto deassert = false; const char* objectPath = "/xyz/openbmc_project/logging"; sdbusplus::async::context ctx; EventIntf::Events events; TestEventServer eventServer; sdbusplus::server::manager_t manager; EventsTest() : events(ctx), eventServer(ctx, objectPath), manager(ctx, objectPath) { ctx.request_name(serviceName); } ~EventsTest() noexcept override {} auto testAssertEvent(EventTestType eventType) -> sdbusplus::async::task { switch (eventType) { case EventTestType::sensorWarningEvent: eventServer.expectedEvent = SensorThresholdErrorIntf::ReadingWarning::errName; co_await events.generateSensorReadingEvent( sdbusplus::message::object_path(sensorObjectPath), EventIntf::EventLevel::warning, 60, EventIntf::SensorValueIntf::Unit::DegreesC, assert); break; case EventTestType::sensorCriticalEvent: eventServer.expectedEvent = SensorThresholdErrorIntf::ReadingCritical::errName; co_await events.generateSensorReadingEvent( sdbusplus::message::object_path(sensorObjectPath), EventIntf::EventLevel::critical, 80, EventIntf::SensorValueIntf::Unit::DegreesC, assert); break; case EventTestType::sensorFailureEvent: eventServer.expectedEvent = SensorErrorIntf::SensorFailure::errName; co_await events.generateSensorFailureEvent( sdbusplus::message::object_path(sensorObjectPath), assert); break; case EventTestType::controllerFailureEvent: eventServer.expectedEvent = ControllerErrorIntf::SMCFailed::errName; co_await events.generateControllerFailureEvent( sdbusplus::message::object_path(sensorObjectPath), "", assert); break; case EventTestType::powerFailureEvent: eventServer.expectedEvent = PowerErrorIntf::PowerRailFault::errName; co_await events.generatePowerFaultEvent( sdbusplus::message::object_path(sensorObjectPath), "", assert); break; case EventTestType::leakWarningEvent: eventServer.expectedEvent = LeakErrorIntf::LeakDetectedWarning::errName; co_await events.generateLeakDetectedEvent( sdbusplus::message::object_path(sensorObjectPath), EventIntf::EventLevel::warning, assert); break; case EventTestType::leakCriticalEvent: eventServer.expectedEvent = LeakErrorIntf::LeakDetectedCritical::errName; co_await events.generateLeakDetectedEvent( sdbusplus::message::object_path(sensorObjectPath), EventIntf::EventLevel::critical, assert); break; } } auto testDeassertEvent(EventTestType eventType) -> sdbusplus::async::task { switch (eventType) { case EventTestType::sensorWarningEvent: eventServer.expectedEvent = SensorThresholdEventIntf::SensorReadingNormalRange::errName; co_await events.generateSensorReadingEvent( sdbusplus::message::object_path(sensorObjectPath), EventIntf::EventLevel::warning, 40, EventIntf::SensorValueIntf::Unit::DegreesC, deassert); break; case EventTestType::sensorCriticalEvent: eventServer.expectedEvent = SensorThresholdEventIntf::SensorReadingNormalRange::errName; co_await events.generateSensorReadingEvent( sdbusplus::message::object_path(sensorObjectPath), EventIntf::EventLevel::critical, 40, EventIntf::SensorValueIntf::Unit::DegreesC, deassert); break; case EventTestType::sensorFailureEvent: eventServer.expectedEvent = SensorEventIntf::SensorRestored::errName; co_await events.generateSensorFailureEvent( sdbusplus::message::object_path(sensorObjectPath), deassert); break; case EventTestType::controllerFailureEvent: eventServer.expectedEvent = ControllerEventIntf::SMCRestored::errName; co_await events.generateControllerFailureEvent( sdbusplus::message::object_path(sensorObjectPath), "", deassert); break; case EventTestType::powerFailureEvent: eventServer.expectedEvent = PowerEventIntf::PowerRailFaultRecovered::errName; co_await events.generatePowerFaultEvent( sdbusplus::message::object_path(sensorObjectPath), "", deassert); break; case EventTestType::leakWarningEvent: eventServer.expectedEvent = LeakEventIntf::LeakDetectedNormal::errName; co_await events.generateLeakDetectedEvent( sdbusplus::message::object_path(sensorObjectPath), EventIntf::EventLevel::warning, deassert); break; case EventTestType::leakCriticalEvent: eventServer.expectedEvent = LeakEventIntf::LeakDetectedNormal::errName; co_await events.generateLeakDetectedEvent( sdbusplus::message::object_path(sensorObjectPath), EventIntf::EventLevel::critical, deassert); break; } } auto testEvents(EventTestType eventType) -> sdbusplus::async::task { co_await testAssertEvent(eventType); co_await sdbusplus::async::sleep_for(ctx, 1s); co_await testDeassertEvent(eventType); ctx.request_stop(); } }; TEST_F(EventsTest, TestEventsSensorWarning) { ctx.spawn(testEvents(EventTestType::sensorWarningEvent)); ctx.run(); } TEST_F(EventsTest, TestEventsSensorCritical) { ctx.spawn(testEvents(EventTestType::sensorCriticalEvent)); ctx.run(); } TEST_F(EventsTest, TestEventsSensorFailure) { ctx.spawn(testEvents(EventTestType::sensorFailureEvent)); ctx.run(); } TEST_F(EventsTest, TestEventsControllerFailure) { ctx.spawn(testEvents(EventTestType::controllerFailureEvent)); ctx.run(); } TEST_F(EventsTest, TestEventsPowerFailure) { ctx.spawn(testEvents(EventTestType::powerFailureEvent)); ctx.run(); } TEST_F(EventsTest, TestEventsLeakWarning) { ctx.spawn(testEvents(EventTestType::leakWarningEvent)); ctx.run(); } TEST_F(EventsTest, TestEventsLeakCritical) { ctx.spawn(testEvents(EventTestType::leakCriticalEvent)); ctx.run(); }