blob: 7416e4fac6d9d035cbe2b7c0405fb5bbe3110c8a [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
Andrew Geisslerce9fe692020-06-16 14:23:10 -05006#include <filesystem>
Andrew Geisslere4960ee2020-03-30 14:31:52 -05007#include <sdbusplus/bus.hpp>
8#include <sdbusplus/test/sdbus_mock.hpp>
9
10#include <gmock/gmock.h>
11#include <gtest/gtest.h>
12
13namespace phosphor
14{
15namespace logging
16{
17namespace test
18{
19
20class TestQuiesceOnError : public testing::Test
21{
22 public:
23 sdbusplus::SdBusMock sdbusMock;
Patrick Williams45e83522022-07-22 19:26:52 -050024 sdbusplus::bus_t mockedBus = sdbusplus::get_mocked_new(&sdbusMock);
Andrew Geisslere4960ee2020-03-30 14:31:52 -050025 phosphor::logging::internal::Manager manager;
26
27 TestQuiesceOnError() : manager(mockedBus, OBJ_INTERNAL)
28 {
Andrew Geisslerce9fe692020-06-16 14:23:10 -050029 // Ensure any errors serializing to filesystem have directory created
30 std::filesystem::create_directory(ERRLOG_PERSIST_PATH);
Andrew Geisslere4960ee2020-03-30 14:31:52 -050031 }
32};
33
34// Test that false is returned when no callout is present in the log
35TEST_F(TestQuiesceOnError, testNoCallout)
36{
37 uint32_t id = 99;
38 uint64_t timestamp{100};
39 std::string message{"test error"};
40 std::string fwLevel{"level42"};
Matt Spinlerfb978da2022-01-21 08:42:24 -060041 std::string path{"/tmp/99"};
Andrew Geisslere4960ee2020-03-30 14:31:52 -050042 std::vector<std::string> testData{"no", "callout"};
43 phosphor::logging::AssociationList associations{};
44
45 Entry elog{mockedBus,
46 std::string(OBJ_ENTRY) + '/' + std::to_string(id),
47 id,
48 timestamp,
49 Entry::Level::Informational,
50 std::move(message),
51 std::move(testData),
52 std::move(associations),
53 fwLevel,
Matt Spinlerfb978da2022-01-21 08:42:24 -060054 path,
Andrew Geisslere4960ee2020-03-30 14:31:52 -050055 manager};
56
57 EXPECT_EQ(manager.isCalloutPresent(elog), false);
58}
59
60// Test that trues is returned when a callout is present in the log
61TEST_F(TestQuiesceOnError, testCallout)
62{
63 uint32_t id = 99;
64 uint64_t timestamp{100};
65 std::string message{"test error"};
66 std::string fwLevel{"level42"};
Matt Spinlerfb978da2022-01-21 08:42:24 -060067 std::string path{"/tmp/99"};
Andrew Geisslere4960ee2020-03-30 14:31:52 -050068 std::vector<std::string> testData{
69 "CALLOUT_INVENTORY_PATH=/xyz/openbmc_project/inventory/system/chassis/"
70 "motherboard/powersupply0/"};
71 phosphor::logging::AssociationList associations{};
72
73 Entry elog{mockedBus,
74 std::string(OBJ_ENTRY) + '/' + std::to_string(id),
75 id,
76 timestamp,
77 Entry::Level::Informational,
78 std::move(message),
79 std::move(testData),
80 std::move(associations),
81 fwLevel,
Matt Spinlerfb978da2022-01-21 08:42:24 -060082 path,
Andrew Geisslere4960ee2020-03-30 14:31:52 -050083 manager};
84
85 EXPECT_EQ(manager.isCalloutPresent(elog), true);
86}
87
Andrew Geissler6a0ef6f2020-04-06 15:06:31 -050088// Test that a blocking error is created on entry with callout
89TEST_F(TestQuiesceOnError, testBlockingErrorsCreated)
90{
91 uint32_t id = 100;
92 uint64_t timestamp{100};
93 std::string message{"test error"};
94 std::string fwLevel{"level42"};
Matt Spinlerfb978da2022-01-21 08:42:24 -060095 std::string path{"/tmp/99"};
Andrew Geissler6a0ef6f2020-04-06 15:06:31 -050096 std::vector<std::string> testData{
97 "CALLOUT_INVENTORY_PATH=/xyz/openbmc_project/inventory/system/chassis/"
98 "motherboard/powersupply0/"};
99 phosphor::logging::AssociationList associations{};
100
101 // Ensure D-Bus object created for this blocking error
102 // First allow any number of sd_bus_emit_object_added calls
103 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(testing::_, testing::_))
104 .Times(testing::AnyNumber());
105 // Second verify the new block100 object is created once
106 EXPECT_CALL(sdbusMock,
107 sd_bus_emit_object_added(
108 testing::_, testing::HasSubstr(
109 "/xyz/openbmc_project/logging/block100")))
110 .Times(1);
111
112 Entry elog{mockedBus,
113 std::string(OBJ_ENTRY) + '/' + std::to_string(id),
114 id,
115 timestamp,
116 Entry::Level::Informational,
117 std::move(message),
118 std::move(testData),
119 std::move(associations),
120 fwLevel,
Matt Spinlerfb978da2022-01-21 08:42:24 -0600121 path,
Andrew Geissler6a0ef6f2020-04-06 15:06:31 -0500122 manager};
123
Andrew Geissler32874542020-07-09 09:17:03 -0500124 manager.quiesceOnError(id);
Andrew Geissler6a0ef6f2020-04-06 15:06:31 -0500125 // Created error with callout so expect a blocking error now
126 EXPECT_EQ(manager.getBlockingErrSize(), 1);
Andrew Geisslerced6e2a2020-04-07 16:15:29 -0500127
128 // Now delete the error and make sure the object and entry go away
129 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(testing::_, testing::_))
130 .Times(testing::AnyNumber());
131 EXPECT_CALL(sdbusMock,
132 sd_bus_emit_object_removed(
133 testing::_, testing::HasSubstr(
134 "/xyz/openbmc_project/logging/block100")))
135 .Times(1);
136
137 // Make sure nothing happens within invalid id
138 manager.checkAndRemoveBlockingError(id + 1);
139 EXPECT_EQ(manager.getBlockingErrSize(), 1);
140
141 manager.checkAndRemoveBlockingError(id);
142 EXPECT_EQ(manager.getBlockingErrSize(), 0);
Andrew Geissler6a0ef6f2020-04-06 15:06:31 -0500143}
144
Andrew Geissler7f6d4bc2020-04-16 14:47:34 -0500145// Test that a blocking error is created on entry with callout
146TEST_F(TestQuiesceOnError, testBlockingErrorsResolved)
147{
148 uint32_t id = 101;
149 uint64_t timestamp{100};
150 std::string message{"test error"};
151 std::string fwLevel{"level42"};
Matt Spinlerfb978da2022-01-21 08:42:24 -0600152 std::string path{"/tmp/99"};
Andrew Geissler7f6d4bc2020-04-16 14:47:34 -0500153 std::vector<std::string> testData{
154 "CALLOUT_INVENTORY_PATH=/xyz/openbmc_project/inventory/system/chassis/"
155 "motherboard/powersupply0/"};
156 phosphor::logging::AssociationList associations{};
157
158 // Ensure D-Bus object created for this blocking error
159 // First allow any number of sd_bus_emit_object_added calls
160 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(testing::_, testing::_))
161 .Times(testing::AnyNumber());
162 // Second verify the new block100 object is created once
163 EXPECT_CALL(sdbusMock,
164 sd_bus_emit_object_added(
165 testing::_, testing::HasSubstr(
166 "/xyz/openbmc_project/logging/block101")))
167 .Times(1);
168
169 Entry elog{mockedBus,
170 std::string(OBJ_ENTRY) + '/' + std::to_string(id),
171 id,
172 timestamp,
173 Entry::Level::Informational,
174 std::move(message),
175 std::move(testData),
176 std::move(associations),
177 fwLevel,
Matt Spinlerfb978da2022-01-21 08:42:24 -0600178 path,
Andrew Geissler7f6d4bc2020-04-16 14:47:34 -0500179 manager};
180
Andrew Geissler32874542020-07-09 09:17:03 -0500181 manager.quiesceOnError(id);
Andrew Geissler7f6d4bc2020-04-16 14:47:34 -0500182 // Created error with callout so expect a blocking error now
183 EXPECT_EQ(manager.getBlockingErrSize(), 1);
184 // Also should have a callback create looking for entry to be resolved
185 EXPECT_EQ(manager.getEntryCallbackSize(), 1);
186
187 // Now resolve the error and make sure the object and entry go away
188 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(testing::_, testing::_))
189 .Times(testing::AnyNumber());
190 EXPECT_CALL(sdbusMock,
191 sd_bus_emit_object_removed(
192 testing::_, testing::HasSubstr(
193 "/xyz/openbmc_project/logging/block101")))
194 .Times(1);
195
196 elog.resolved(true);
197 // Note that property signal callbacks do not work in unit test so directly
198 // call the interface to find and resolve blocking entries
199 manager.checkAndRemoveBlockingError(101);
200 EXPECT_EQ(manager.getBlockingErrSize(), 0);
201 EXPECT_EQ(manager.getEntryCallbackSize(), 0);
202}
203
Andrew Geissler72a1cca2020-09-10 16:49:09 -0500204// Test that a blocking error is only created once for an individual bmc id
205TEST_F(TestQuiesceOnError, testBlockingErrorTwice)
206{
207 uint32_t id = 100;
208 uint64_t timestamp{100};
209 std::string message{"test error"};
210 std::string fwLevel{"level42"};
Matt Spinlerfb978da2022-01-21 08:42:24 -0600211 std::string path{"/tmp/99"};
Andrew Geissler72a1cca2020-09-10 16:49:09 -0500212 std::vector<std::string> testData{
213 "CALLOUT_INVENTORY_PATH=/xyz/openbmc_project/inventory/system/chassis/"
214 "motherboard/powersupply0/"};
215 phosphor::logging::AssociationList associations{};
216
217 // Ensure D-Bus object created for this blocking error
218 // First allow any number of sd_bus_emit_object_added calls
219 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(testing::_, testing::_))
220 .Times(testing::AnyNumber());
221 // Second verify the new block100 object is created once
222 EXPECT_CALL(sdbusMock,
223 sd_bus_emit_object_added(
224 testing::_, testing::HasSubstr(
225 "/xyz/openbmc_project/logging/block100")))
226 .Times(1);
227
228 Entry elog{mockedBus,
229 std::string(OBJ_ENTRY) + '/' + std::to_string(id),
230 id,
231 timestamp,
232 Entry::Level::Informational,
233 std::move(message),
234 std::move(testData),
235 std::move(associations),
236 fwLevel,
Matt Spinlerfb978da2022-01-21 08:42:24 -0600237 path,
Andrew Geissler72a1cca2020-09-10 16:49:09 -0500238 manager};
239
240 manager.quiesceOnError(id);
241 // Created error with callout so expect a blocking error now
242 EXPECT_EQ(manager.getBlockingErrSize(), 1);
243
244 // Now pass in same ID and make sure it's ignored
245 manager.quiesceOnError(id);
246
247 // Now delete the error and make sure the object and entry go away
248 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(testing::_, testing::_))
249 .Times(testing::AnyNumber());
250 EXPECT_CALL(sdbusMock,
251 sd_bus_emit_object_removed(
252 testing::_, testing::HasSubstr(
253 "/xyz/openbmc_project/logging/block100")))
254 .Times(1);
255
256 manager.checkAndRemoveBlockingError(id);
257 EXPECT_EQ(manager.getBlockingErrSize(), 0);
258}
259
Andrew Geisslere4960ee2020-03-30 14:31:52 -0500260} // namespace test
261} // namespace logging
262} // namespace phosphor