blob: ac78974caea8e2af1a7991b0ba54b79615ed6b84 [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;
24 sdbusplus::bus::bus mockedBus = sdbusplus::get_mocked_new(&sdbusMock);
25 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"};
41 std::vector<std::string> testData{"no", "callout"};
42 phosphor::logging::AssociationList associations{};
43
44 Entry elog{mockedBus,
45 std::string(OBJ_ENTRY) + '/' + std::to_string(id),
46 id,
47 timestamp,
48 Entry::Level::Informational,
49 std::move(message),
50 std::move(testData),
51 std::move(associations),
52 fwLevel,
53 manager};
54
55 EXPECT_EQ(manager.isCalloutPresent(elog), false);
56}
57
58// Test that trues is returned when a callout is present in the log
59TEST_F(TestQuiesceOnError, testCallout)
60{
61 uint32_t id = 99;
62 uint64_t timestamp{100};
63 std::string message{"test error"};
64 std::string fwLevel{"level42"};
65 std::vector<std::string> testData{
66 "CALLOUT_INVENTORY_PATH=/xyz/openbmc_project/inventory/system/chassis/"
67 "motherboard/powersupply0/"};
68 phosphor::logging::AssociationList associations{};
69
70 Entry elog{mockedBus,
71 std::string(OBJ_ENTRY) + '/' + std::to_string(id),
72 id,
73 timestamp,
74 Entry::Level::Informational,
75 std::move(message),
76 std::move(testData),
77 std::move(associations),
78 fwLevel,
79 manager};
80
81 EXPECT_EQ(manager.isCalloutPresent(elog), true);
82}
83
Andrew Geissler6a0ef6f2020-04-06 15:06:31 -050084// Test that a blocking error is created on entry with callout
85TEST_F(TestQuiesceOnError, testBlockingErrorsCreated)
86{
87 uint32_t id = 100;
88 uint64_t timestamp{100};
89 std::string message{"test error"};
90 std::string fwLevel{"level42"};
91 std::vector<std::string> testData{
92 "CALLOUT_INVENTORY_PATH=/xyz/openbmc_project/inventory/system/chassis/"
93 "motherboard/powersupply0/"};
94 phosphor::logging::AssociationList associations{};
95
96 // Ensure D-Bus object created for this blocking error
97 // First allow any number of sd_bus_emit_object_added calls
98 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(testing::_, testing::_))
99 .Times(testing::AnyNumber());
100 // Second verify the new block100 object is created once
101 EXPECT_CALL(sdbusMock,
102 sd_bus_emit_object_added(
103 testing::_, testing::HasSubstr(
104 "/xyz/openbmc_project/logging/block100")))
105 .Times(1);
106
107 Entry elog{mockedBus,
108 std::string(OBJ_ENTRY) + '/' + std::to_string(id),
109 id,
110 timestamp,
111 Entry::Level::Informational,
112 std::move(message),
113 std::move(testData),
114 std::move(associations),
115 fwLevel,
116 manager};
117
Andrew Geissler32874542020-07-09 09:17:03 -0500118 manager.quiesceOnError(id);
Andrew Geissler6a0ef6f2020-04-06 15:06:31 -0500119 // Created error with callout so expect a blocking error now
120 EXPECT_EQ(manager.getBlockingErrSize(), 1);
Andrew Geisslerced6e2a2020-04-07 16:15:29 -0500121
122 // Now delete the error and make sure the object and entry go away
123 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(testing::_, testing::_))
124 .Times(testing::AnyNumber());
125 EXPECT_CALL(sdbusMock,
126 sd_bus_emit_object_removed(
127 testing::_, testing::HasSubstr(
128 "/xyz/openbmc_project/logging/block100")))
129 .Times(1);
130
131 // Make sure nothing happens within invalid id
132 manager.checkAndRemoveBlockingError(id + 1);
133 EXPECT_EQ(manager.getBlockingErrSize(), 1);
134
135 manager.checkAndRemoveBlockingError(id);
136 EXPECT_EQ(manager.getBlockingErrSize(), 0);
Andrew Geissler6a0ef6f2020-04-06 15:06:31 -0500137}
138
Andrew Geissler7f6d4bc2020-04-16 14:47:34 -0500139// Test that a blocking error is created on entry with callout
140TEST_F(TestQuiesceOnError, testBlockingErrorsResolved)
141{
142 uint32_t id = 101;
143 uint64_t timestamp{100};
144 std::string message{"test error"};
145 std::string fwLevel{"level42"};
146 std::vector<std::string> testData{
147 "CALLOUT_INVENTORY_PATH=/xyz/openbmc_project/inventory/system/chassis/"
148 "motherboard/powersupply0/"};
149 phosphor::logging::AssociationList associations{};
150
151 // Ensure D-Bus object created for this blocking error
152 // First allow any number of sd_bus_emit_object_added calls
153 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(testing::_, testing::_))
154 .Times(testing::AnyNumber());
155 // Second verify the new block100 object is created once
156 EXPECT_CALL(sdbusMock,
157 sd_bus_emit_object_added(
158 testing::_, testing::HasSubstr(
159 "/xyz/openbmc_project/logging/block101")))
160 .Times(1);
161
162 Entry elog{mockedBus,
163 std::string(OBJ_ENTRY) + '/' + std::to_string(id),
164 id,
165 timestamp,
166 Entry::Level::Informational,
167 std::move(message),
168 std::move(testData),
169 std::move(associations),
170 fwLevel,
171 manager};
172
Andrew Geissler32874542020-07-09 09:17:03 -0500173 manager.quiesceOnError(id);
Andrew Geissler7f6d4bc2020-04-16 14:47:34 -0500174 // Created error with callout so expect a blocking error now
175 EXPECT_EQ(manager.getBlockingErrSize(), 1);
176 // Also should have a callback create looking for entry to be resolved
177 EXPECT_EQ(manager.getEntryCallbackSize(), 1);
178
179 // Now resolve the error and make sure the object and entry go away
180 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(testing::_, testing::_))
181 .Times(testing::AnyNumber());
182 EXPECT_CALL(sdbusMock,
183 sd_bus_emit_object_removed(
184 testing::_, testing::HasSubstr(
185 "/xyz/openbmc_project/logging/block101")))
186 .Times(1);
187
188 elog.resolved(true);
189 // Note that property signal callbacks do not work in unit test so directly
190 // call the interface to find and resolve blocking entries
191 manager.checkAndRemoveBlockingError(101);
192 EXPECT_EQ(manager.getBlockingErrSize(), 0);
193 EXPECT_EQ(manager.getEntryCallbackSize(), 0);
194}
195
Andrew Geissler72a1cca2020-09-10 16:49:09 -0500196// Test that a blocking error is only created once for an individual bmc id
197TEST_F(TestQuiesceOnError, testBlockingErrorTwice)
198{
199 uint32_t id = 100;
200 uint64_t timestamp{100};
201 std::string message{"test error"};
202 std::string fwLevel{"level42"};
203 std::vector<std::string> testData{
204 "CALLOUT_INVENTORY_PATH=/xyz/openbmc_project/inventory/system/chassis/"
205 "motherboard/powersupply0/"};
206 phosphor::logging::AssociationList associations{};
207
208 // Ensure D-Bus object created for this blocking error
209 // First allow any number of sd_bus_emit_object_added calls
210 EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(testing::_, testing::_))
211 .Times(testing::AnyNumber());
212 // Second verify the new block100 object is created once
213 EXPECT_CALL(sdbusMock,
214 sd_bus_emit_object_added(
215 testing::_, testing::HasSubstr(
216 "/xyz/openbmc_project/logging/block100")))
217 .Times(1);
218
219 Entry elog{mockedBus,
220 std::string(OBJ_ENTRY) + '/' + std::to_string(id),
221 id,
222 timestamp,
223 Entry::Level::Informational,
224 std::move(message),
225 std::move(testData),
226 std::move(associations),
227 fwLevel,
228 manager};
229
230 manager.quiesceOnError(id);
231 // Created error with callout so expect a blocking error now
232 EXPECT_EQ(manager.getBlockingErrSize(), 1);
233
234 // Now pass in same ID and make sure it's ignored
235 manager.quiesceOnError(id);
236
237 // Now delete the error and make sure the object and entry go away
238 EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(testing::_, testing::_))
239 .Times(testing::AnyNumber());
240 EXPECT_CALL(sdbusMock,
241 sd_bus_emit_object_removed(
242 testing::_, testing::HasSubstr(
243 "/xyz/openbmc_project/logging/block100")))
244 .Times(1);
245
246 manager.checkAndRemoveBlockingError(id);
247 EXPECT_EQ(manager.getBlockingErrSize(), 0);
248}
249
Andrew Geisslere4960ee2020-03-30 14:31:52 -0500250} // namespace test
251} // namespace logging
252} // namespace phosphor