blob: e2bc8beda1970334c859923e8b3253f8fe9dc886 [file] [log] [blame]
Patrick Williamsf0af3582024-10-10 16:32:32 -04001#include "config.h"
2
3#include "log_manager.hpp"
4#include "paths.hpp"
5
6#include <phosphor-logging/commit.hpp>
7#include <sdbusplus/async.hpp>
8#include <sdbusplus/server/manager.hpp>
9#include <xyz/openbmc_project/Logging/Entry/client.hpp>
10#include <xyz/openbmc_project/Logging/event.hpp>
11
12#include <thread>
13
14#include <gmock/gmock.h>
15#include <gtest/gtest.h>
16
17namespace phosphor::logging::test
18{
19using LoggingCleared = sdbusplus::event::xyz::openbmc_project::Logging::Cleared;
20using LoggingEntry = sdbusplus::client::xyz::openbmc_project::logging::Entry<>;
21
22// Fixture to spawn the log-manager for dbus-based testing.
23class TestLogManagerDbus : public ::testing::Test
24{
25 protected:
26 // Create the daemon and sdbusplus::async::contexts.
27 void SetUp() override
28 {
29 // The daemon requires directories to be created first.
30 std::filesystem::create_directories(phosphor::logging::paths::error());
31
32 data = std::make_unique<fixture_data>();
33 }
34
35 // Stop the daemon, etc.
36 void TearDown() override
37 {
38 data.reset();
39 }
40
41 /** Run a client task, wait for it to complete, and stop daemon. */
42 template <typename T>
43 void run(T&& t)
44 {
45 data->client_ctx.spawn(std::move(t) | stdexec::then([this]() {
46 data->stop(data->client_ctx);
47 }));
48 data->client_ctx.run();
49 }
50
51 // Data for the fixture.
52 struct fixture_data
53 {
54 fixture_data() :
55 client_ctx(), server_ctx(), objManager(server_ctx, OBJ_LOGGING),
56 iMgr(server_ctx, OBJ_INTERNAL), mgr(server_ctx, OBJ_LOGGING, iMgr)
57 {
58 // Create a thread for the daemon.
59 task = std::thread([this]() {
60 server_ctx.request_name(BUSNAME_LOGGING);
61 server_ctx.run();
62 });
63 }
64
65 ~fixture_data()
66 {
67 // Stop the server and wait for the thread to exit.
68 stop(server_ctx);
69 task.join();
70 }
71
72 // Spawn a task to gracefully shutdown an sdbusplus::async::context
73 static void stop(sdbusplus::async::context& ctx)
74 {
75 ctx.spawn(stdexec::just() |
76 stdexec::then([&ctx]() { ctx.request_stop(); }));
77 }
78
79 sdbusplus::async::context client_ctx;
80 sdbusplus::async::context server_ctx;
81 sdbusplus::server::manager_t objManager;
82 internal::Manager iMgr;
83 Manager mgr;
84 std::thread task;
85 };
86
87 std::unique_ptr<fixture_data> data;
88};
89
90// Ensure we can successfully create and throw an sdbusplus event.
91TEST_F(TestLogManagerDbus, GenerateSimpleEvent)
92{
93 EXPECT_THROW(
94 { throw LoggingCleared("NUMBER_OF_LOGS", 1); }, LoggingCleared);
95 return;
96}
97
98// Call the synchronous version of the commit function and verify that the
99// daemon gives us a path.
100TEST_F(TestLogManagerDbus, CallCommitSync)
101{
102 auto path = lg2::commit(LoggingCleared("NUMBER_OF_LOGS", 3));
103 ASSERT_FALSE(path.str.empty());
104 EXPECT_THAT(path.str,
105 ::testing::StartsWith(
106 std::filesystem::path(LoggingEntry::namespace_path::value) /
107 LoggingEntry::namespace_path::entry));
108}
109
110// Call the asynchronous version of the commit function and verify that the
111// metadata is saved correctly.
112TEST_F(TestLogManagerDbus, CallCommitAsync)
113{
114 sdbusplus::message::object_path path{};
115 std::string log_count{};
Patrick Williams247fed62024-10-31 15:12:02 -0400116 pid_t pid = 0;
117 std::string source_file{};
Patrick Williamsf0af3582024-10-10 16:32:32 -0400118
Patrick Williams247fed62024-10-31 15:12:02 -0400119 auto create_log = [&, this]() -> sdbusplus::async::task<> {
Patrick Williamsf0af3582024-10-10 16:32:32 -0400120 // Log an event.
121 path = co_await lg2::commit(data->client_ctx,
122 LoggingCleared("NUMBER_OF_LOGS", 6));
123
124 // Grab the additional data.
125 auto additionalData = co_await LoggingEntry(data->client_ctx)
126 .service(Entry::default_service)
127 .path(path.str)
128 .additional_data();
129
Patrick Williams247fed62024-10-31 15:12:02 -0400130 // Extract the NUMBER_OF_LOGS, PID, and CODE_FILE.
Patrick Williamsf0af3582024-10-10 16:32:32 -0400131 for (const auto& value : additionalData)
132 {
Patrick Williams247fed62024-10-31 15:12:02 -0400133 auto getValue = [&value]() {
134 return value.substr(value.find_first_of('=') + 1);
135 };
136
Patrick Williamsf0af3582024-10-10 16:32:32 -0400137 if (value.starts_with("NUMBER_OF_LOGS="))
138 {
Patrick Williams247fed62024-10-31 15:12:02 -0400139 log_count = getValue();
140 }
141 if (value.starts_with("_PID="))
142 {
143 pid = std::stoull(getValue());
144 }
145 if (value.starts_with("_CODE_FILE="))
146 {
147 source_file = getValue();
Patrick Williamsf0af3582024-10-10 16:32:32 -0400148 }
149 }
150
151 co_return;
152 };
153
154 run(create_log());
155
156 ASSERT_FALSE(path.str.empty());
157 ASSERT_FALSE(log_count.empty());
158
159 EXPECT_THAT(path.str,
160 ::testing::StartsWith(
161 std::filesystem::path(LoggingEntry::namespace_path::value) /
162 LoggingEntry::namespace_path::entry));
163
164 EXPECT_EQ(log_count, "6");
Patrick Williams247fed62024-10-31 15:12:02 -0400165 EXPECT_EQ(pid, getpid());
166 EXPECT_EQ(source_file, std::source_location::current().file_name());
Patrick Williamsf0af3582024-10-10 16:32:32 -0400167}
168
169} // namespace phosphor::logging::test