lg2: commit: add methods for new sdbusplus events
Add implementations and test cases for the `lg2::commit` functions.
Signed-off-by: Patrick Williams <patrick@stwcx.xyz>
Change-Id: I25a87fd65738e4debbe98f3473709f77d51777e9
diff --git a/lib/lg2_commit.cpp b/lib/lg2_commit.cpp
index 2c20311..60dd30e 100644
--- a/lib/lg2_commit.cpp
+++ b/lib/lg2_commit.cpp
@@ -1,21 +1,90 @@
+#include <sys/syslog.h>
+
+#include <nlohmann/json.hpp>
#include <phosphor-logging/lg2/commit.hpp>
#include <sdbusplus/async.hpp>
#include <sdbusplus/exception.hpp>
+#include <xyz/openbmc_project/Logging/Create/client.hpp>
+#include <xyz/openbmc_project/Logging/Entry/client.hpp>
namespace lg2::details
{
-auto commit([[maybe_unused]] sdbusplus::exception::generated_event_base&& t)
- -> sdbusplus::message::object_path
+using Create = sdbusplus::client::xyz::openbmc_project::logging::Create<>;
+using Entry = sdbusplus::client::xyz::openbmc_project::logging::Entry<>;
+
+/* Convert syslog severity to Entry::Level */
+static auto severity_from_syslog(int s) -> Entry::Level
{
- return {};
+ switch (s)
+ {
+ case LOG_DEBUG:
+ return Entry::Level::Debug;
+
+ case LOG_INFO:
+ return Entry::Level::Informational;
+
+ case LOG_NOTICE:
+ return Entry::Level::Notice;
+
+ case LOG_WARNING:
+ return Entry::Level::Warning;
+
+ case LOG_ERR:
+ return Entry::Level::Error;
+
+ case LOG_CRIT:
+ return Entry::Level::Critical;
+
+ case LOG_ALERT:
+ return Entry::Level::Alert;
+
+ case LOG_EMERG:
+ return Entry::Level::Emergency;
+ }
+ return Entry::Level::Emergency;
}
-auto commit([[maybe_unused]] sdbusplus::async::context& ctx,
- [[maybe_unused]] sdbusplus::exception::generated_event_base&& t)
+using AdditionalData_t = std::map<std::string, std::string>;
+
+/* Create AdditionalData from the sdbusplus event json. */
+static auto data_from_json(sdbusplus::exception::generated_event_base& t)
+ -> AdditionalData_t
+{
+ AdditionalData_t result{};
+
+ auto j = t.to_json()[t.name()];
+ for (const auto& item : j.items())
+ {
+ result.emplace(item.key(), item.value().dump());
+ }
+
+ return result;
+}
+
+auto commit(sdbusplus::exception::generated_event_base&& t)
+ -> sdbusplus::message::object_path
+{
+ auto b = sdbusplus::bus::new_default();
+ auto m = b.new_method_call(Create::default_service, Create::instance_path,
+ Create::interface, "Create");
+
+ m.append(t.name(), severity_from_syslog(t.severity()), data_from_json(t));
+
+ auto reply = b.call(m);
+
+ return reply.unpack<sdbusplus::message::object_path>();
+}
+
+auto commit(sdbusplus::async::context& ctx,
+ sdbusplus::exception::generated_event_base&& t)
-> sdbusplus::async::task<sdbusplus::message::object_path>
{
- co_return {};
+ co_return co_await Create(ctx)
+ .service(Create::default_service)
+ .path(Create::instance_path)
+ .create(t.name(), severity_from_syslog(t.severity()),
+ data_from_json(t));
}
} // namespace lg2::details
diff --git a/test/basic_event_commit.cpp b/test/basic_event_commit.cpp
deleted file mode 100644
index fc454d9..0000000
--- a/test/basic_event_commit.cpp
+++ /dev/null
@@ -1,23 +0,0 @@
-#include <phosphor-logging/commit.hpp>
-#include <xyz/openbmc_project/Logging/event.hpp>
-
-#include <gtest/gtest.h>
-
-namespace phosphor::logging::test
-{
-
-using LoggingCleared = sdbusplus::event::xyz::openbmc_project::Logging::Cleared;
-
-TEST(TestBasicEventCommit, GenerateSimpleEvent)
-{
- EXPECT_THROW(
- { throw LoggingCleared("NUMBER_OF_LOGS", 1); }, LoggingCleared);
- return;
-}
-
-TEST(TestBasicEventCommit, CallCommit)
-{
- lg2::commit(LoggingCleared("NUMBER_OF_LOGS", 3));
-}
-
-} // namespace phosphor::logging::test
diff --git a/test/log_manager_dbus_tests.cpp b/test/log_manager_dbus_tests.cpp
new file mode 100644
index 0000000..ac33ded
--- /dev/null
+++ b/test/log_manager_dbus_tests.cpp
@@ -0,0 +1,153 @@
+#include "config.h"
+
+#include "log_manager.hpp"
+#include "paths.hpp"
+
+#include <phosphor-logging/commit.hpp>
+#include <sdbusplus/async.hpp>
+#include <sdbusplus/server/manager.hpp>
+#include <xyz/openbmc_project/Logging/Entry/client.hpp>
+#include <xyz/openbmc_project/Logging/event.hpp>
+
+#include <thread>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace phosphor::logging::test
+{
+using LoggingCleared = sdbusplus::event::xyz::openbmc_project::Logging::Cleared;
+using LoggingEntry = sdbusplus::client::xyz::openbmc_project::logging::Entry<>;
+
+// Fixture to spawn the log-manager for dbus-based testing.
+class TestLogManagerDbus : public ::testing::Test
+{
+ protected:
+ // Create the daemon and sdbusplus::async::contexts.
+ void SetUp() override
+ {
+ // The daemon requires directories to be created first.
+ std::filesystem::create_directories(phosphor::logging::paths::error());
+
+ data = std::make_unique<fixture_data>();
+ }
+
+ // Stop the daemon, etc.
+ void TearDown() override
+ {
+ data.reset();
+ }
+
+ /** Run a client task, wait for it to complete, and stop daemon. */
+ template <typename T>
+ void run(T&& t)
+ {
+ data->client_ctx.spawn(std::move(t) | stdexec::then([this]() {
+ data->stop(data->client_ctx);
+ }));
+ data->client_ctx.run();
+ }
+
+ // Data for the fixture.
+ struct fixture_data
+ {
+ fixture_data() :
+ client_ctx(), server_ctx(), objManager(server_ctx, OBJ_LOGGING),
+ iMgr(server_ctx, OBJ_INTERNAL), mgr(server_ctx, OBJ_LOGGING, iMgr)
+ {
+ // Create a thread for the daemon.
+ task = std::thread([this]() {
+ server_ctx.request_name(BUSNAME_LOGGING);
+ server_ctx.run();
+ });
+ }
+
+ ~fixture_data()
+ {
+ // Stop the server and wait for the thread to exit.
+ stop(server_ctx);
+ task.join();
+ }
+
+ // Spawn a task to gracefully shutdown an sdbusplus::async::context
+ static void stop(sdbusplus::async::context& ctx)
+ {
+ ctx.spawn(stdexec::just() |
+ stdexec::then([&ctx]() { ctx.request_stop(); }));
+ }
+
+ sdbusplus::async::context client_ctx;
+ sdbusplus::async::context server_ctx;
+ sdbusplus::server::manager_t objManager;
+ internal::Manager iMgr;
+ Manager mgr;
+ std::thread task;
+ };
+
+ std::unique_ptr<fixture_data> data;
+};
+
+// Ensure we can successfully create and throw an sdbusplus event.
+TEST_F(TestLogManagerDbus, GenerateSimpleEvent)
+{
+ EXPECT_THROW(
+ { throw LoggingCleared("NUMBER_OF_LOGS", 1); }, LoggingCleared);
+ return;
+}
+
+// Call the synchronous version of the commit function and verify that the
+// daemon gives us a path.
+TEST_F(TestLogManagerDbus, CallCommitSync)
+{
+ auto path = lg2::commit(LoggingCleared("NUMBER_OF_LOGS", 3));
+ ASSERT_FALSE(path.str.empty());
+ EXPECT_THAT(path.str,
+ ::testing::StartsWith(
+ std::filesystem::path(LoggingEntry::namespace_path::value) /
+ LoggingEntry::namespace_path::entry));
+}
+
+// Call the asynchronous version of the commit function and verify that the
+// metadata is saved correctly.
+TEST_F(TestLogManagerDbus, CallCommitAsync)
+{
+ sdbusplus::message::object_path path{};
+ std::string log_count{};
+
+ auto create_log = [this, &path, &log_count]() -> sdbusplus::async::task<> {
+ // Log an event.
+ path = co_await lg2::commit(data->client_ctx,
+ LoggingCleared("NUMBER_OF_LOGS", 6));
+
+ // Grab the additional data.
+ auto additionalData = co_await LoggingEntry(data->client_ctx)
+ .service(Entry::default_service)
+ .path(path.str)
+ .additional_data();
+
+ // Extract the NUMBER_OF_LOGS.
+ for (const auto& value : additionalData)
+ {
+ if (value.starts_with("NUMBER_OF_LOGS="))
+ {
+ log_count = value.substr(value.find_first_of('=') + 1);
+ }
+ }
+
+ co_return;
+ };
+
+ run(create_log());
+
+ ASSERT_FALSE(path.str.empty());
+ ASSERT_FALSE(log_count.empty());
+
+ EXPECT_THAT(path.str,
+ ::testing::StartsWith(
+ std::filesystem::path(LoggingEntry::namespace_path::value) /
+ LoggingEntry::namespace_path::entry));
+
+ EXPECT_EQ(log_count, "6");
+}
+
+} // namespace phosphor::logging::test
diff --git a/test/meson.build b/test/meson.build
index bdf3cdb..822a4f8 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -24,8 +24,8 @@
endif
tests = [
- 'basic_event_commit',
'extensions_test',
+ 'log_manager_dbus_tests',
'remote_logging_test_address',
'remote_logging_test_config',
'remote_logging_test_port',