1e4960ee7SAndrew Geissler #include "config.h"
2e4960ee7SAndrew Geissler
3e4960ee7SAndrew Geissler #include "elog_entry.hpp"
4e4960ee7SAndrew Geissler #include "log_manager.hpp"
5fa2d962bSPatrick Williams #include "paths.hpp"
6e4960ee7SAndrew Geissler
7e4960ee7SAndrew Geissler #include <sdbusplus/bus.hpp>
8e4960ee7SAndrew Geissler #include <sdbusplus/test/sdbus_mock.hpp>
9e4960ee7SAndrew Geissler
102544b419SPatrick Williams #include <filesystem>
112544b419SPatrick Williams
12e4960ee7SAndrew Geissler #include <gmock/gmock.h>
13e4960ee7SAndrew Geissler #include <gtest/gtest.h>
14e4960ee7SAndrew Geissler
15e4960ee7SAndrew Geissler namespace phosphor
16e4960ee7SAndrew Geissler {
17e4960ee7SAndrew Geissler namespace logging
18e4960ee7SAndrew Geissler {
19e4960ee7SAndrew Geissler namespace test
20e4960ee7SAndrew Geissler {
21e4960ee7SAndrew Geissler
22e4960ee7SAndrew Geissler class TestQuiesceOnError : public testing::Test
23e4960ee7SAndrew Geissler {
24e4960ee7SAndrew Geissler public:
25e4960ee7SAndrew Geissler sdbusplus::SdBusMock sdbusMock;
2645e83521SPatrick Williams sdbusplus::bus_t mockedBus = sdbusplus::get_mocked_new(&sdbusMock);
27e4960ee7SAndrew Geissler phosphor::logging::internal::Manager manager;
28e4960ee7SAndrew Geissler
TestQuiesceOnError()29e4960ee7SAndrew Geissler TestQuiesceOnError() : manager(mockedBus, OBJ_INTERNAL)
30e4960ee7SAndrew Geissler {
31ce9fe693SAndrew Geissler // Ensure any errors serializing to filesystem have directory created
32fa2d962bSPatrick Williams std::filesystem::create_directories(paths::error());
33e4960ee7SAndrew Geissler }
34e4960ee7SAndrew Geissler };
35e4960ee7SAndrew Geissler
36e4960ee7SAndrew Geissler // Test that false is returned when no callout is present in the log
TEST_F(TestQuiesceOnError,testNoCallout)37e4960ee7SAndrew Geissler TEST_F(TestQuiesceOnError, testNoCallout)
38e4960ee7SAndrew Geissler {
39e4960ee7SAndrew Geissler uint32_t id = 99;
40e4960ee7SAndrew Geissler uint64_t timestamp{100};
41e4960ee7SAndrew Geissler std::string message{"test error"};
42e4960ee7SAndrew Geissler std::string fwLevel{"level42"};
43fb978da4SMatt Spinler std::string path{"/tmp/99"};
44*ea21d995SPatrick Williams std::map<std::string, std::string> testData{{"no", "no"},
45*ea21d995SPatrick Williams {"callout", "callout"}};
46e4960ee7SAndrew Geissler phosphor::logging::AssociationList associations{};
47e4960ee7SAndrew Geissler
48e4960ee7SAndrew Geissler Entry elog{mockedBus,
49e4960ee7SAndrew Geissler std::string(OBJ_ENTRY) + '/' + std::to_string(id),
50e4960ee7SAndrew Geissler id,
51e4960ee7SAndrew Geissler timestamp,
52e4960ee7SAndrew Geissler Entry::Level::Informational,
53e4960ee7SAndrew Geissler std::move(message),
54e4960ee7SAndrew Geissler std::move(testData),
55e4960ee7SAndrew Geissler std::move(associations),
56e4960ee7SAndrew Geissler fwLevel,
57fb978da4SMatt Spinler path,
58e4960ee7SAndrew Geissler manager};
59e4960ee7SAndrew Geissler
60e4960ee7SAndrew Geissler EXPECT_EQ(manager.isCalloutPresent(elog), false);
61e4960ee7SAndrew Geissler }
62e4960ee7SAndrew Geissler
63e4960ee7SAndrew Geissler // Test that trues is returned when a callout is present in the log
TEST_F(TestQuiesceOnError,testCallout)64e4960ee7SAndrew Geissler TEST_F(TestQuiesceOnError, testCallout)
65e4960ee7SAndrew Geissler {
66e4960ee7SAndrew Geissler uint32_t id = 99;
67e4960ee7SAndrew Geissler uint64_t timestamp{100};
68e4960ee7SAndrew Geissler std::string message{"test error"};
69e4960ee7SAndrew Geissler std::string fwLevel{"level42"};
70fb978da4SMatt Spinler std::string path{"/tmp/99"};
71*ea21d995SPatrick Williams std::map<std::string, std::string> testData{
72*ea21d995SPatrick Williams {"CALLOUT_INVENTORY_PATH",
73*ea21d995SPatrick Williams "/xyz/openbmc_project/inventory/system/chassis/motherboard/powersupply0/"}};
74e4960ee7SAndrew Geissler phosphor::logging::AssociationList associations{};
75e4960ee7SAndrew Geissler
76e4960ee7SAndrew Geissler Entry elog{mockedBus,
77e4960ee7SAndrew Geissler std::string(OBJ_ENTRY) + '/' + std::to_string(id),
78e4960ee7SAndrew Geissler id,
79e4960ee7SAndrew Geissler timestamp,
80e4960ee7SAndrew Geissler Entry::Level::Informational,
81e4960ee7SAndrew Geissler std::move(message),
82e4960ee7SAndrew Geissler std::move(testData),
83e4960ee7SAndrew Geissler std::move(associations),
84e4960ee7SAndrew Geissler fwLevel,
85fb978da4SMatt Spinler path,
86e4960ee7SAndrew Geissler manager};
87e4960ee7SAndrew Geissler
88e4960ee7SAndrew Geissler EXPECT_EQ(manager.isCalloutPresent(elog), true);
89e4960ee7SAndrew Geissler }
90e4960ee7SAndrew Geissler
916a0ef6f5SAndrew Geissler // Test that a blocking error is created on entry with callout
TEST_F(TestQuiesceOnError,testBlockingErrorsCreated)926a0ef6f5SAndrew Geissler TEST_F(TestQuiesceOnError, testBlockingErrorsCreated)
936a0ef6f5SAndrew Geissler {
946a0ef6f5SAndrew Geissler uint32_t id = 100;
956a0ef6f5SAndrew Geissler uint64_t timestamp{100};
966a0ef6f5SAndrew Geissler std::string message{"test error"};
976a0ef6f5SAndrew Geissler std::string fwLevel{"level42"};
98fb978da4SMatt Spinler std::string path{"/tmp/99"};
99*ea21d995SPatrick Williams std::map<std::string, std::string> testData{
100*ea21d995SPatrick Williams {"CALLOUT_INVENTORY_PATH",
101*ea21d995SPatrick Williams "/xyz/openbmc_project/inventory/system/chassis/motherboard/powersupply0/"}};
1026a0ef6f5SAndrew Geissler phosphor::logging::AssociationList associations{};
1036a0ef6f5SAndrew Geissler
1046a0ef6f5SAndrew Geissler // Ensure D-Bus object created for this blocking error
1056a0ef6f5SAndrew Geissler // First allow any number of sd_bus_emit_object_added calls
1066a0ef6f5SAndrew Geissler EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(testing::_, testing::_))
1076a0ef6f5SAndrew Geissler .Times(testing::AnyNumber());
1086a0ef6f5SAndrew Geissler // Second verify the new block100 object is created once
1096a0ef6f5SAndrew Geissler EXPECT_CALL(sdbusMock,
1106a0ef6f5SAndrew Geissler sd_bus_emit_object_added(
1116a0ef6f5SAndrew Geissler testing::_, testing::HasSubstr(
1126a0ef6f5SAndrew Geissler "/xyz/openbmc_project/logging/block100")))
1136a0ef6f5SAndrew Geissler .Times(1);
1146a0ef6f5SAndrew Geissler
1156a0ef6f5SAndrew Geissler Entry elog{mockedBus,
1166a0ef6f5SAndrew Geissler std::string(OBJ_ENTRY) + '/' + std::to_string(id),
1176a0ef6f5SAndrew Geissler id,
1186a0ef6f5SAndrew Geissler timestamp,
1196a0ef6f5SAndrew Geissler Entry::Level::Informational,
1206a0ef6f5SAndrew Geissler std::move(message),
1216a0ef6f5SAndrew Geissler std::move(testData),
1226a0ef6f5SAndrew Geissler std::move(associations),
1236a0ef6f5SAndrew Geissler fwLevel,
124fb978da4SMatt Spinler path,
1256a0ef6f5SAndrew Geissler manager};
1266a0ef6f5SAndrew Geissler
12732874543SAndrew Geissler manager.quiesceOnError(id);
1286a0ef6f5SAndrew Geissler // Created error with callout so expect a blocking error now
1296a0ef6f5SAndrew Geissler EXPECT_EQ(manager.getBlockingErrSize(), 1);
130ced6e2a0SAndrew Geissler
131ced6e2a0SAndrew Geissler // Now delete the error and make sure the object and entry go away
132ced6e2a0SAndrew Geissler EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(testing::_, testing::_))
133ced6e2a0SAndrew Geissler .Times(testing::AnyNumber());
134ced6e2a0SAndrew Geissler EXPECT_CALL(sdbusMock,
135ced6e2a0SAndrew Geissler sd_bus_emit_object_removed(
136ced6e2a0SAndrew Geissler testing::_, testing::HasSubstr(
137ced6e2a0SAndrew Geissler "/xyz/openbmc_project/logging/block100")))
138ced6e2a0SAndrew Geissler .Times(1);
139ced6e2a0SAndrew Geissler
140ced6e2a0SAndrew Geissler // Make sure nothing happens within invalid id
141ced6e2a0SAndrew Geissler manager.checkAndRemoveBlockingError(id + 1);
142ced6e2a0SAndrew Geissler EXPECT_EQ(manager.getBlockingErrSize(), 1);
143ced6e2a0SAndrew Geissler
144ced6e2a0SAndrew Geissler manager.checkAndRemoveBlockingError(id);
145ced6e2a0SAndrew Geissler EXPECT_EQ(manager.getBlockingErrSize(), 0);
1466a0ef6f5SAndrew Geissler }
1476a0ef6f5SAndrew Geissler
1487f6d4bcfSAndrew Geissler // Test that a blocking error is created on entry with callout
TEST_F(TestQuiesceOnError,testBlockingErrorsResolved)1497f6d4bcfSAndrew Geissler TEST_F(TestQuiesceOnError, testBlockingErrorsResolved)
1507f6d4bcfSAndrew Geissler {
1517f6d4bcfSAndrew Geissler uint32_t id = 101;
1527f6d4bcfSAndrew Geissler uint64_t timestamp{100};
1537f6d4bcfSAndrew Geissler std::string message{"test error"};
1547f6d4bcfSAndrew Geissler std::string fwLevel{"level42"};
155fb978da4SMatt Spinler std::string path{"/tmp/99"};
156*ea21d995SPatrick Williams std::map<std::string, std::string> testData{
157*ea21d995SPatrick Williams {"CALLOUT_INVENTORY_PATH",
158*ea21d995SPatrick Williams "/xyz/openbmc_project/inventory/system/chassis/motherboard/powersupply0/"}};
1597f6d4bcfSAndrew Geissler phosphor::logging::AssociationList associations{};
1607f6d4bcfSAndrew Geissler
1617f6d4bcfSAndrew Geissler // Ensure D-Bus object created for this blocking error
1627f6d4bcfSAndrew Geissler // First allow any number of sd_bus_emit_object_added calls
1637f6d4bcfSAndrew Geissler EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(testing::_, testing::_))
1647f6d4bcfSAndrew Geissler .Times(testing::AnyNumber());
1657f6d4bcfSAndrew Geissler // Second verify the new block100 object is created once
1667f6d4bcfSAndrew Geissler EXPECT_CALL(sdbusMock,
1677f6d4bcfSAndrew Geissler sd_bus_emit_object_added(
1687f6d4bcfSAndrew Geissler testing::_, testing::HasSubstr(
1697f6d4bcfSAndrew Geissler "/xyz/openbmc_project/logging/block101")))
1707f6d4bcfSAndrew Geissler .Times(1);
1717f6d4bcfSAndrew Geissler
1727f6d4bcfSAndrew Geissler Entry elog{mockedBus,
1737f6d4bcfSAndrew Geissler std::string(OBJ_ENTRY) + '/' + std::to_string(id),
1747f6d4bcfSAndrew Geissler id,
1757f6d4bcfSAndrew Geissler timestamp,
1767f6d4bcfSAndrew Geissler Entry::Level::Informational,
1777f6d4bcfSAndrew Geissler std::move(message),
1787f6d4bcfSAndrew Geissler std::move(testData),
1797f6d4bcfSAndrew Geissler std::move(associations),
1807f6d4bcfSAndrew Geissler fwLevel,
181fb978da4SMatt Spinler path,
1827f6d4bcfSAndrew Geissler manager};
1837f6d4bcfSAndrew Geissler
18432874543SAndrew Geissler manager.quiesceOnError(id);
1857f6d4bcfSAndrew Geissler // Created error with callout so expect a blocking error now
1867f6d4bcfSAndrew Geissler EXPECT_EQ(manager.getBlockingErrSize(), 1);
1877f6d4bcfSAndrew Geissler // Also should have a callback create looking for entry to be resolved
1887f6d4bcfSAndrew Geissler EXPECT_EQ(manager.getEntryCallbackSize(), 1);
1897f6d4bcfSAndrew Geissler
1907f6d4bcfSAndrew Geissler // Now resolve the error and make sure the object and entry go away
1917f6d4bcfSAndrew Geissler EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(testing::_, testing::_))
1927f6d4bcfSAndrew Geissler .Times(testing::AnyNumber());
1937f6d4bcfSAndrew Geissler EXPECT_CALL(sdbusMock,
1947f6d4bcfSAndrew Geissler sd_bus_emit_object_removed(
1957f6d4bcfSAndrew Geissler testing::_, testing::HasSubstr(
1967f6d4bcfSAndrew Geissler "/xyz/openbmc_project/logging/block101")))
1977f6d4bcfSAndrew Geissler .Times(1);
1987f6d4bcfSAndrew Geissler
1997f6d4bcfSAndrew Geissler elog.resolved(true);
2007f6d4bcfSAndrew Geissler // Note that property signal callbacks do not work in unit test so directly
2017f6d4bcfSAndrew Geissler // call the interface to find and resolve blocking entries
2027f6d4bcfSAndrew Geissler manager.checkAndRemoveBlockingError(101);
2037f6d4bcfSAndrew Geissler EXPECT_EQ(manager.getBlockingErrSize(), 0);
2047f6d4bcfSAndrew Geissler EXPECT_EQ(manager.getEntryCallbackSize(), 0);
2057f6d4bcfSAndrew Geissler }
2067f6d4bcfSAndrew Geissler
20772a1cca2SAndrew Geissler // Test that a blocking error is only created once for an individual bmc id
TEST_F(TestQuiesceOnError,testBlockingErrorTwice)20872a1cca2SAndrew Geissler TEST_F(TestQuiesceOnError, testBlockingErrorTwice)
20972a1cca2SAndrew Geissler {
21072a1cca2SAndrew Geissler uint32_t id = 100;
21172a1cca2SAndrew Geissler uint64_t timestamp{100};
21272a1cca2SAndrew Geissler std::string message{"test error"};
21372a1cca2SAndrew Geissler std::string fwLevel{"level42"};
214fb978da4SMatt Spinler std::string path{"/tmp/99"};
215*ea21d995SPatrick Williams std::map<std::string, std::string> testData{
216*ea21d995SPatrick Williams {"CALLOUT_INVENTORY_PATH",
217*ea21d995SPatrick Williams "/xyz/openbmc_project/inventory/system/chassis/motherboard/powersupply0/"}};
21872a1cca2SAndrew Geissler phosphor::logging::AssociationList associations{};
21972a1cca2SAndrew Geissler
22072a1cca2SAndrew Geissler // Ensure D-Bus object created for this blocking error
22172a1cca2SAndrew Geissler // First allow any number of sd_bus_emit_object_added calls
22272a1cca2SAndrew Geissler EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(testing::_, testing::_))
22372a1cca2SAndrew Geissler .Times(testing::AnyNumber());
22472a1cca2SAndrew Geissler // Second verify the new block100 object is created once
22572a1cca2SAndrew Geissler EXPECT_CALL(sdbusMock,
22672a1cca2SAndrew Geissler sd_bus_emit_object_added(
22772a1cca2SAndrew Geissler testing::_, testing::HasSubstr(
22872a1cca2SAndrew Geissler "/xyz/openbmc_project/logging/block100")))
22972a1cca2SAndrew Geissler .Times(1);
23072a1cca2SAndrew Geissler
23172a1cca2SAndrew Geissler Entry elog{mockedBus,
23272a1cca2SAndrew Geissler std::string(OBJ_ENTRY) + '/' + std::to_string(id),
23372a1cca2SAndrew Geissler id,
23472a1cca2SAndrew Geissler timestamp,
23572a1cca2SAndrew Geissler Entry::Level::Informational,
23672a1cca2SAndrew Geissler std::move(message),
23772a1cca2SAndrew Geissler std::move(testData),
23872a1cca2SAndrew Geissler std::move(associations),
23972a1cca2SAndrew Geissler fwLevel,
240fb978da4SMatt Spinler path,
24172a1cca2SAndrew Geissler manager};
24272a1cca2SAndrew Geissler
24372a1cca2SAndrew Geissler manager.quiesceOnError(id);
24472a1cca2SAndrew Geissler // Created error with callout so expect a blocking error now
24572a1cca2SAndrew Geissler EXPECT_EQ(manager.getBlockingErrSize(), 1);
24672a1cca2SAndrew Geissler
24772a1cca2SAndrew Geissler // Now pass in same ID and make sure it's ignored
24872a1cca2SAndrew Geissler manager.quiesceOnError(id);
24972a1cca2SAndrew Geissler
25072a1cca2SAndrew Geissler // Now delete the error and make sure the object and entry go away
25172a1cca2SAndrew Geissler EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(testing::_, testing::_))
25272a1cca2SAndrew Geissler .Times(testing::AnyNumber());
25372a1cca2SAndrew Geissler EXPECT_CALL(sdbusMock,
25472a1cca2SAndrew Geissler sd_bus_emit_object_removed(
25572a1cca2SAndrew Geissler testing::_, testing::HasSubstr(
25672a1cca2SAndrew Geissler "/xyz/openbmc_project/logging/block100")))
25772a1cca2SAndrew Geissler .Times(1);
25872a1cca2SAndrew Geissler
25972a1cca2SAndrew Geissler manager.checkAndRemoveBlockingError(id);
26072a1cca2SAndrew Geissler EXPECT_EQ(manager.getBlockingErrSize(), 0);
26172a1cca2SAndrew Geissler }
26272a1cca2SAndrew Geissler
263e4960ee7SAndrew Geissler } // namespace test
264e4960ee7SAndrew Geissler } // namespace logging
265e4960ee7SAndrew Geissler } // namespace phosphor
266