xref: /openbmc/phosphor-logging/test/log_manager_dbus_tests.cpp (revision ea6d9c4586d4b9435955124daf5f3afcf4a056c1)
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