blob: ac33ded431d339a966abe85fe9fdb4d903ee0bd0 [file] [log] [blame]
#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