blob: a8651683f3f03e8472d8ccc386db8219f224f31c [file] [log] [blame]
Andrew Geisslere4960ee2020-03-30 14:31:52 -05001#include "config.h"
2
3#include "elog_entry.hpp"
4#include "log_manager.hpp"
5
6#include <sdbusplus/bus.hpp>
7#include <sdbusplus/test/sdbus_mock.hpp>
8
Patrick Williams2544b412022-10-04 08:41:06 -05009#include <filesystem>
10
Andrew Geisslere4960ee2020-03-30 14:31:52 -050011#include <gmock/gmock.h>
12#include <gtest/gtest.h>
13
14namespace phosphor
15{
16namespace logging
17{
18namespace test
19{
20
21class TestQuiesceOnError : public testing::Test
22{
23 public:
24 sdbusplus::SdBusMock sdbusMock;
Patrick Williams45e83522022-07-22 19:26:52 -050025 sdbusplus::bus_t mockedBus = sdbusplus::get_mocked_new(&sdbusMock);
Andrew Geisslere4960ee2020-03-30 14:31:52 -050026 phosphor::logging::internal::Manager manager;
27
28 TestQuiesceOnError() : manager(mockedBus, OBJ_INTERNAL)
29 {
Andrew Geisslerce9fe692020-06-16 14:23:10 -050030 // Ensure any errors serializing to filesystem have directory created
31 std::filesystem::create_directory(ERRLOG_PERSIST_PATH);
Andrew Geisslere4960ee2020-03-30 14:31:52 -050032 }
33};
34
35// Test that false is returned when no callout is present in the log
36TEST_F(TestQuiesceOnError, testNoCallout)
37{
38 uint32_t id = 99;
39 uint64_t timestamp{100};
40 std::string message{"test error"};
41 std::string fwLevel{"level42"};
Matt Spinlerfb978da2022-01-21 08:42:24 -060042 std::string path{"/tmp/99"};
Andrew Geisslere4960ee2020-03-30 14:31:52 -050043 std::vector<std::string> testData{"no", "callout"};
44 phosphor::logging::AssociationList associations{};
45
46 Entry elog{mockedBus,
47 std::string(OBJ_ENTRY) + '/' + std::to_string(id),
48 id,
49 timestamp,
50 Entry::Level::Informational,
51 std::move(message),
52 std::move(testData),
53 std::move(associations),
54 fwLevel,
Matt Spinlerfb978da2022-01-21 08:42:24 -060055 path,
Andrew Geisslere4960ee2020-03-30 14:31:52 -050056 manager};
57
58 EXPECT_EQ(manager.isCalloutPresent(elog), false);
59}
60
61// Test that trues is returned when a callout is present in the log
62TEST_F(TestQuiesceOnError, testCallout)
63{
64 uint32_t id = 99;
65 uint64_t timestamp{100};
66 std::string message{"test error"};
67 std::string fwLevel{"level42"};
Matt Spinlerfb978da2022-01-21 08:42:24 -060068 std::string path{"/tmp/99"};
Andrew Geisslere4960ee2020-03-30 14:31:52 -050069 std::vector<std::string> testData{
70 "CALLOUT_INVENTORY_PATH=/xyz/openbmc_project/inventory/system/chassis/"
71 "motherboard/powersupply0/"};
72 phosphor::logging::AssociationList associations{};
73
74 Entry elog{mockedBus,
75 std::string(OBJ_ENTRY) + '/' + std::to_string(id),
76 id,
77 timestamp,
78 Entry::Level::Informational,
79 std::move(message),
80 std::move(testData),
81 std::move(associations),
82 fwLevel,
Matt Spinlerfb978da2022-01-21 08:42:24 -060083 path,
Andrew Geisslere4960ee2020-03-30 14:31:52 -050084 manager};
85
86 EXPECT_EQ(manager.isCalloutPresent(elog), true);
87}
88
Andrew Geissler6a0ef6f2020-04-06 15:06:31 -050089// Test that a blocking error is created on entry with callout
90TEST_F(TestQuiesceOnError, testBlockingErrorsCreated)
91{
92 uint32_t id = 100;
93 uint64_t timestamp{100};
94 std::string message{"test error"};
95 std::string fwLevel{"level42"};
Matt Spinlerfb978da2022-01-21 08:42:24 -060096 std::string path{"/tmp/99"};
Andrew Geissler6a0ef6f2020-04-06 15:06:31 -050097 std::vector<std::string> testData{
98 "CALLOUT_INVENTORY_PATH=/xyz/openbmc_project/inventory/system/chassis/"
99 "motherboard/powersupply0/"};
100 phosphor::logging::AssociationList associations{};
101
102 // Ensure D-Bus object created for this blocking error
103 // First allow any number of sd_bus_emit_object_added calls
104 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(testing::_, testing::_))
105 .Times(testing::AnyNumber());
106 // Second verify the new block100 object is created once
107 EXPECT_CALL(sdbusMock,
108 sd_bus_emit_object_added(
109 testing::_, testing::HasSubstr(
110 "/xyz/openbmc_project/logging/block100")))
111 .Times(1);
112
113 Entry elog{mockedBus,
114 std::string(OBJ_ENTRY) + '/' + std::to_string(id),
115 id,
116 timestamp,
117 Entry::Level::Informational,
118 std::move(message),
119 std::move(testData),
120 std::move(associations),
121 fwLevel,
Matt Spinlerfb978da2022-01-21 08:42:24 -0600122 path,
Andrew Geissler6a0ef6f2020-04-06 15:06:31 -0500123 manager};
124
Andrew Geissler32874542020-07-09 09:17:03 -0500125 manager.quiesceOnError(id);
Andrew Geissler6a0ef6f2020-04-06 15:06:31 -0500126 // Created error with callout so expect a blocking error now
127 EXPECT_EQ(manager.getBlockingErrSize(), 1);
Andrew Geisslerced6e2a2020-04-07 16:15:29 -0500128
129 // Now delete the error and make sure the object and entry go away
130 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(testing::_, testing::_))
131 .Times(testing::AnyNumber());
132 EXPECT_CALL(sdbusMock,
133 sd_bus_emit_object_removed(
134 testing::_, testing::HasSubstr(
135 "/xyz/openbmc_project/logging/block100")))
136 .Times(1);
137
138 // Make sure nothing happens within invalid id
139 manager.checkAndRemoveBlockingError(id + 1);
140 EXPECT_EQ(manager.getBlockingErrSize(), 1);
141
142 manager.checkAndRemoveBlockingError(id);
143 EXPECT_EQ(manager.getBlockingErrSize(), 0);
Andrew Geissler6a0ef6f2020-04-06 15:06:31 -0500144}
145
Andrew Geissler7f6d4bc2020-04-16 14:47:34 -0500146// Test that a blocking error is created on entry with callout
147TEST_F(TestQuiesceOnError, testBlockingErrorsResolved)
148{
149 uint32_t id = 101;
150 uint64_t timestamp{100};
151 std::string message{"test error"};
152 std::string fwLevel{"level42"};
Matt Spinlerfb978da2022-01-21 08:42:24 -0600153 std::string path{"/tmp/99"};
Andrew Geissler7f6d4bc2020-04-16 14:47:34 -0500154 std::vector<std::string> testData{
155 "CALLOUT_INVENTORY_PATH=/xyz/openbmc_project/inventory/system/chassis/"
156 "motherboard/powersupply0/"};
157 phosphor::logging::AssociationList associations{};
158
159 // Ensure D-Bus object created for this blocking error
160 // First allow any number of sd_bus_emit_object_added calls
161 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(testing::_, testing::_))
162 .Times(testing::AnyNumber());
163 // Second verify the new block100 object is created once
164 EXPECT_CALL(sdbusMock,
165 sd_bus_emit_object_added(
166 testing::_, testing::HasSubstr(
167 "/xyz/openbmc_project/logging/block101")))
168 .Times(1);
169
170 Entry elog{mockedBus,
171 std::string(OBJ_ENTRY) + '/' + std::to_string(id),
172 id,
173 timestamp,
174 Entry::Level::Informational,
175 std::move(message),
176 std::move(testData),
177 std::move(associations),
178 fwLevel,
Matt Spinlerfb978da2022-01-21 08:42:24 -0600179 path,
Andrew Geissler7f6d4bc2020-04-16 14:47:34 -0500180 manager};
181
Andrew Geissler32874542020-07-09 09:17:03 -0500182 manager.quiesceOnError(id);
Andrew Geissler7f6d4bc2020-04-16 14:47:34 -0500183 // Created error with callout so expect a blocking error now
184 EXPECT_EQ(manager.getBlockingErrSize(), 1);
185 // Also should have a callback create looking for entry to be resolved
186 EXPECT_EQ(manager.getEntryCallbackSize(), 1);
187
188 // Now resolve the error and make sure the object and entry go away
189 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(testing::_, testing::_))
190 .Times(testing::AnyNumber());
191 EXPECT_CALL(sdbusMock,
192 sd_bus_emit_object_removed(
193 testing::_, testing::HasSubstr(
194 "/xyz/openbmc_project/logging/block101")))
195 .Times(1);
196
197 elog.resolved(true);
198 // Note that property signal callbacks do not work in unit test so directly
199 // call the interface to find and resolve blocking entries
200 manager.checkAndRemoveBlockingError(101);
201 EXPECT_EQ(manager.getBlockingErrSize(), 0);
202 EXPECT_EQ(manager.getEntryCallbackSize(), 0);
203}
204
Andrew Geissler72a1cca2020-09-10 16:49:09 -0500205// Test that a blocking error is only created once for an individual bmc id
206TEST_F(TestQuiesceOnError, testBlockingErrorTwice)
207{
208 uint32_t id = 100;
209 uint64_t timestamp{100};
210 std::string message{"test error"};
211 std::string fwLevel{"level42"};
Matt Spinlerfb978da2022-01-21 08:42:24 -0600212 std::string path{"/tmp/99"};
Andrew Geissler72a1cca2020-09-10 16:49:09 -0500213 std::vector<std::string> testData{
214 "CALLOUT_INVENTORY_PATH=/xyz/openbmc_project/inventory/system/chassis/"
215 "motherboard/powersupply0/"};
216 phosphor::logging::AssociationList associations{};
217
218 // Ensure D-Bus object created for this blocking error
219 // First allow any number of sd_bus_emit_object_added calls
220 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(testing::_, testing::_))
221 .Times(testing::AnyNumber());
222 // Second verify the new block100 object is created once
223 EXPECT_CALL(sdbusMock,
224 sd_bus_emit_object_added(
225 testing::_, testing::HasSubstr(
226 "/xyz/openbmc_project/logging/block100")))
227 .Times(1);
228
229 Entry elog{mockedBus,
230 std::string(OBJ_ENTRY) + '/' + std::to_string(id),
231 id,
232 timestamp,
233 Entry::Level::Informational,
234 std::move(message),
235 std::move(testData),
236 std::move(associations),
237 fwLevel,
Matt Spinlerfb978da2022-01-21 08:42:24 -0600238 path,
Andrew Geissler72a1cca2020-09-10 16:49:09 -0500239 manager};
240
241 manager.quiesceOnError(id);
242 // Created error with callout so expect a blocking error now
243 EXPECT_EQ(manager.getBlockingErrSize(), 1);
244
245 // Now pass in same ID and make sure it's ignored
246 manager.quiesceOnError(id);
247
248 // Now delete the error and make sure the object and entry go away
249 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(testing::_, testing::_))
250 .Times(testing::AnyNumber());
251 EXPECT_CALL(sdbusMock,
252 sd_bus_emit_object_removed(
253 testing::_, testing::HasSubstr(
254 "/xyz/openbmc_project/logging/block100")))
255 .Times(1);
256
257 manager.checkAndRemoveBlockingError(id);
258 EXPECT_EQ(manager.getBlockingErrSize(), 0);
259}
260
Andrew Geisslere4960ee2020-03-30 14:31:52 -0500261} // namespace test
262} // namespace logging
263} // namespace phosphor