1f0af358fSPatrick Williams #include "config.h"
2f0af358fSPatrick Williams
3f0af358fSPatrick Williams #include "log_manager.hpp"
4f0af358fSPatrick Williams #include "paths.hpp"
5f0af358fSPatrick Williams
6f0af358fSPatrick Williams #include <phosphor-logging/commit.hpp>
7f0af358fSPatrick Williams #include <sdbusplus/async.hpp>
8f0af358fSPatrick Williams #include <sdbusplus/server/manager.hpp>
9f0af358fSPatrick Williams #include <xyz/openbmc_project/Logging/Entry/client.hpp>
10f0af358fSPatrick Williams #include <xyz/openbmc_project/Logging/event.hpp>
11f0af358fSPatrick Williams
12f0af358fSPatrick Williams #include <thread>
13f0af358fSPatrick Williams
14f0af358fSPatrick Williams #include <gmock/gmock.h>
15f0af358fSPatrick Williams #include <gtest/gtest.h>
16f0af358fSPatrick Williams
17f0af358fSPatrick Williams namespace phosphor::logging::test
18f0af358fSPatrick Williams {
19f0af358fSPatrick Williams using LoggingCleared = sdbusplus::event::xyz::openbmc_project::Logging::Cleared;
20f0af358fSPatrick Williams using LoggingEntry = sdbusplus::client::xyz::openbmc_project::logging::Entry<>;
21f0af358fSPatrick Williams
22f0af358fSPatrick Williams // Fixture to spawn the log-manager for dbus-based testing.
23f0af358fSPatrick Williams class TestLogManagerDbus : public ::testing::Test
24f0af358fSPatrick Williams {
25f0af358fSPatrick Williams protected:
26f0af358fSPatrick Williams // Create the daemon and sdbusplus::async::contexts.
SetUp()27f0af358fSPatrick Williams void SetUp() override
28f0af358fSPatrick Williams {
29f0af358fSPatrick Williams // The daemon requires directories to be created first.
30f0af358fSPatrick Williams std::filesystem::create_directories(phosphor::logging::paths::error());
31f0af358fSPatrick Williams
32f0af358fSPatrick Williams data = std::make_unique<fixture_data>();
33f0af358fSPatrick Williams }
34f0af358fSPatrick Williams
35f0af358fSPatrick Williams // Stop the daemon, etc.
TearDown()36f0af358fSPatrick Williams void TearDown() override
37f0af358fSPatrick Williams {
38f0af358fSPatrick Williams data.reset();
39f0af358fSPatrick Williams }
40f0af358fSPatrick Williams
41f0af358fSPatrick Williams /** Run a client task, wait for it to complete, and stop daemon. */
42f0af358fSPatrick Williams template <typename T>
run(T && t)43f0af358fSPatrick Williams void run(T&& t)
44f0af358fSPatrick Williams {
45f0af358fSPatrick Williams data->client_ctx.spawn(std::move(t) | stdexec::then([this]() {
46f0af358fSPatrick Williams data->stop(data->client_ctx);
47f0af358fSPatrick Williams }));
48f0af358fSPatrick Williams data->client_ctx.run();
49f0af358fSPatrick Williams }
50f0af358fSPatrick Williams
51f0af358fSPatrick Williams // Data for the fixture.
52f0af358fSPatrick Williams struct fixture_data
53f0af358fSPatrick Williams {
fixture_dataphosphor::logging::test::TestLogManagerDbus::fixture_data54f0af358fSPatrick Williams fixture_data() :
55f0af358fSPatrick Williams client_ctx(), server_ctx(), objManager(server_ctx, OBJ_LOGGING),
56f0af358fSPatrick Williams iMgr(server_ctx, OBJ_INTERNAL), mgr(server_ctx, OBJ_LOGGING, iMgr)
57f0af358fSPatrick Williams {
58f0af358fSPatrick Williams // Create a thread for the daemon.
59f0af358fSPatrick Williams task = std::thread([this]() {
60f0af358fSPatrick Williams server_ctx.request_name(BUSNAME_LOGGING);
61f0af358fSPatrick Williams server_ctx.run();
62f0af358fSPatrick Williams });
63f0af358fSPatrick Williams }
64f0af358fSPatrick Williams
~fixture_dataphosphor::logging::test::TestLogManagerDbus::fixture_data65f0af358fSPatrick Williams ~fixture_data()
66f0af358fSPatrick Williams {
67f0af358fSPatrick Williams // Stop the server and wait for the thread to exit.
68f0af358fSPatrick Williams stop(server_ctx);
69f0af358fSPatrick Williams task.join();
70f0af358fSPatrick Williams }
71f0af358fSPatrick Williams
72f0af358fSPatrick Williams // Spawn a task to gracefully shutdown an sdbusplus::async::context
stopphosphor::logging::test::TestLogManagerDbus::fixture_data73f0af358fSPatrick Williams static void stop(sdbusplus::async::context& ctx)
74f0af358fSPatrick Williams {
75f0af358fSPatrick Williams ctx.spawn(stdexec::just() |
76f0af358fSPatrick Williams stdexec::then([&ctx]() { ctx.request_stop(); }));
77f0af358fSPatrick Williams }
78f0af358fSPatrick Williams
79f0af358fSPatrick Williams sdbusplus::async::context client_ctx;
80f0af358fSPatrick Williams sdbusplus::async::context server_ctx;
81f0af358fSPatrick Williams sdbusplus::server::manager_t objManager;
82f0af358fSPatrick Williams internal::Manager iMgr;
83f0af358fSPatrick Williams Manager mgr;
84f0af358fSPatrick Williams std::thread task;
85f0af358fSPatrick Williams };
86f0af358fSPatrick Williams
87f0af358fSPatrick Williams std::unique_ptr<fixture_data> data;
886eb96bf7SPatrick Williams
896eb96bf7SPatrick Williams static constexpr auto journal_unavailable = "UNAVAILABLE";
last_journal_entry()906eb96bf7SPatrick Williams std::string last_journal_entry()
916eb96bf7SPatrick Williams {
926eb96bf7SPatrick Williams if constexpr (LG2_COMMIT_JOURNAL)
936eb96bf7SPatrick Williams {
946eb96bf7SPatrick Williams // When running under Docker, the journal is not available and
956eb96bf7SPatrick Williams // sd-journal calls just silently pass. Return a string to make
966eb96bf7SPatrick Williams // it obvious.
976eb96bf7SPatrick Williams if (!std::filesystem::exists("/run/systemd/journal/socket"))
986eb96bf7SPatrick Williams {
996eb96bf7SPatrick Williams return journal_unavailable;
1006eb96bf7SPatrick Williams }
1016eb96bf7SPatrick Williams
1026eb96bf7SPatrick Williams sd_journal* j = nullptr;
1036eb96bf7SPatrick Williams
1046eb96bf7SPatrick Williams sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY);
1056eb96bf7SPatrick Williams sd_journal_add_match(j, "SYSLOG_IDENTIFIER=test_manager_dbus_tests",
1066eb96bf7SPatrick Williams SIZE_MAX);
1076eb96bf7SPatrick Williams
1086eb96bf7SPatrick Williams SD_JOURNAL_FOREACH_BACKWARDS(j)
1096eb96bf7SPatrick Williams {
1106eb96bf7SPatrick Williams const char* data = nullptr;
1116eb96bf7SPatrick Williams size_t length = 0;
1126eb96bf7SPatrick Williams
1136eb96bf7SPatrick Williams sd_journal_get_data(j, "MESSAGE", (const void**)&data, &length);
1146eb96bf7SPatrick Williams
1156eb96bf7SPatrick Williams std::string entry(data, length);
1166eb96bf7SPatrick Williams if (entry.contains("OPENBMC_MESSAGE_ID="))
1176eb96bf7SPatrick Williams {
1186eb96bf7SPatrick Williams return entry;
1196eb96bf7SPatrick Williams }
1206eb96bf7SPatrick Williams }
1216eb96bf7SPatrick Williams }
1226eb96bf7SPatrick Williams
1236eb96bf7SPatrick Williams return "";
1246eb96bf7SPatrick Williams }
125f0af358fSPatrick Williams };
126f0af358fSPatrick Williams
127f0af358fSPatrick Williams // Ensure we can successfully create and throw an sdbusplus event.
TEST_F(TestLogManagerDbus,GenerateSimpleEvent)128f0af358fSPatrick Williams TEST_F(TestLogManagerDbus, GenerateSimpleEvent)
129f0af358fSPatrick Williams {
130f0af358fSPatrick Williams EXPECT_THROW(
131f0af358fSPatrick Williams { throw LoggingCleared("NUMBER_OF_LOGS", 1); }, LoggingCleared);
132f0af358fSPatrick Williams return;
133f0af358fSPatrick Williams }
134f0af358fSPatrick Williams
135f0af358fSPatrick Williams // Call the synchronous version of the commit function and verify that the
136f0af358fSPatrick Williams // daemon gives us a path.
TEST_F(TestLogManagerDbus,CallCommitSync)137f0af358fSPatrick Williams TEST_F(TestLogManagerDbus, CallCommitSync)
138f0af358fSPatrick Williams {
139f0af358fSPatrick Williams auto path = lg2::commit(LoggingCleared("NUMBER_OF_LOGS", 3));
1406eb96bf7SPatrick Williams
1416eb96bf7SPatrick Williams if constexpr (LG2_COMMIT_DBUS)
1426eb96bf7SPatrick Williams {
143f0af358fSPatrick Williams ASSERT_FALSE(path.str.empty());
1446eb96bf7SPatrick Williams EXPECT_THAT(
1456eb96bf7SPatrick Williams path.str,
146f0af358fSPatrick Williams ::testing::StartsWith(
147f0af358fSPatrick Williams std::filesystem::path(LoggingEntry::namespace_path::value) /
148f0af358fSPatrick Williams LoggingEntry::namespace_path::entry));
149f0af358fSPatrick Williams }
150f0af358fSPatrick Williams
1516eb96bf7SPatrick Williams if constexpr (LG2_COMMIT_JOURNAL)
1526eb96bf7SPatrick Williams {
1536eb96bf7SPatrick Williams auto entry = last_journal_entry();
1546eb96bf7SPatrick Williams if (entry != journal_unavailable)
1556eb96bf7SPatrick Williams {
1566eb96bf7SPatrick Williams EXPECT_THAT(entry, ::testing::HasSubstr(
1576eb96bf7SPatrick Williams "\"xyz.openbmc_project.Logging.Cleared\":"));
1586eb96bf7SPatrick Williams EXPECT_THAT(entry, ::testing::HasSubstr("\"NUMBER_OF_LOGS\":3"));
1596eb96bf7SPatrick Williams }
1606eb96bf7SPatrick Williams }
1616eb96bf7SPatrick Williams }
1626eb96bf7SPatrick Williams
163f0af358fSPatrick Williams // Call the asynchronous version of the commit function and verify that the
164f0af358fSPatrick Williams // metadata is saved correctly.
TEST_F(TestLogManagerDbus,CallCommitAsync)165f0af358fSPatrick Williams TEST_F(TestLogManagerDbus, CallCommitAsync)
166f0af358fSPatrick Williams {
167f0af358fSPatrick Williams sdbusplus::message::object_path path{};
168f0af358fSPatrick Williams std::string log_count{};
169247fed60SPatrick Williams pid_t pid = 0;
170247fed60SPatrick Williams std::string source_file{};
171f0af358fSPatrick Williams
172247fed60SPatrick Williams auto create_log = [&, this]() -> sdbusplus::async::task<> {
173f0af358fSPatrick Williams // Log an event.
174f0af358fSPatrick Williams path = co_await lg2::commit(data->client_ctx,
175f0af358fSPatrick Williams LoggingCleared("NUMBER_OF_LOGS", 6));
176f0af358fSPatrick Williams
1776eb96bf7SPatrick Williams if constexpr (LG2_COMMIT_DBUS)
1786eb96bf7SPatrick Williams {
179f0af358fSPatrick Williams // Grab the additional data.
180f0af358fSPatrick Williams auto additionalData = co_await LoggingEntry(data->client_ctx)
181f0af358fSPatrick Williams .service(Entry::default_service)
182f0af358fSPatrick Williams .path(path.str)
183f0af358fSPatrick Williams .additional_data();
184f0af358fSPatrick Williams
185247fed60SPatrick Williams // Extract the NUMBER_OF_LOGS, PID, and CODE_FILE.
186f0af358fSPatrick Williams for (const auto& value : additionalData)
187f0af358fSPatrick Williams {
188*ea6d9c45SPatrick Williams if (value.first == "NUMBER_OF_LOGS")
189f0af358fSPatrick Williams {
190*ea6d9c45SPatrick Williams log_count = value.second;
191247fed60SPatrick Williams }
192*ea6d9c45SPatrick Williams if (value.first == "_PID")
193247fed60SPatrick Williams {
194*ea6d9c45SPatrick Williams pid = std::stoull(value.second);
195247fed60SPatrick Williams }
196*ea6d9c45SPatrick Williams if (value.first == "_CODE_FILE")
197247fed60SPatrick Williams {
198*ea6d9c45SPatrick Williams source_file = value.second;
199f0af358fSPatrick Williams }
200f0af358fSPatrick Williams }
2016eb96bf7SPatrick Williams }
202f0af358fSPatrick Williams
203f0af358fSPatrick Williams co_return;
204f0af358fSPatrick Williams };
205f0af358fSPatrick Williams
206f0af358fSPatrick Williams run(create_log());
207f0af358fSPatrick Williams
2086eb96bf7SPatrick Williams if constexpr (LG2_COMMIT_DBUS)
2096eb96bf7SPatrick Williams {
210f0af358fSPatrick Williams ASSERT_FALSE(path.str.empty());
211f0af358fSPatrick Williams ASSERT_FALSE(log_count.empty());
212f0af358fSPatrick Williams
2136eb96bf7SPatrick Williams EXPECT_THAT(
2146eb96bf7SPatrick Williams path.str,
215f0af358fSPatrick Williams ::testing::StartsWith(
216f0af358fSPatrick Williams std::filesystem::path(LoggingEntry::namespace_path::value) /
217f0af358fSPatrick Williams LoggingEntry::namespace_path::entry));
218f0af358fSPatrick Williams
219f0af358fSPatrick Williams EXPECT_EQ(log_count, "6");
220247fed60SPatrick Williams EXPECT_EQ(pid, getpid());
221247fed60SPatrick Williams EXPECT_EQ(source_file, std::source_location::current().file_name());
222f0af358fSPatrick Williams }
223f0af358fSPatrick Williams
2246eb96bf7SPatrick Williams if constexpr (LG2_COMMIT_JOURNAL)
2256eb96bf7SPatrick Williams {
2266eb96bf7SPatrick Williams auto entry = last_journal_entry();
2276eb96bf7SPatrick Williams if (entry != journal_unavailable)
2286eb96bf7SPatrick Williams {
2296eb96bf7SPatrick Williams EXPECT_THAT(entry, ::testing::HasSubstr(
2306eb96bf7SPatrick Williams "\"xyz.openbmc_project.Logging.Cleared\":"));
2316eb96bf7SPatrick Williams EXPECT_THAT(entry, ::testing::HasSubstr("\"NUMBER_OF_LOGS\":6"));
2326eb96bf7SPatrick Williams }
2336eb96bf7SPatrick Williams }
2346eb96bf7SPatrick Williams }
2356eb96bf7SPatrick Williams
236f0af358fSPatrick Williams } // namespace phosphor::logging::test
237