xref: /openbmc/phosphor-logging/test/elog_quiesce_test.cpp (revision ea21d995389412b4cea411f647176641b5cf0a9a)
1 #include "config.h"
2 
3 #include "elog_entry.hpp"
4 #include "log_manager.hpp"
5 #include "paths.hpp"
6 
7 #include <sdbusplus/bus.hpp>
8 #include <sdbusplus/test/sdbus_mock.hpp>
9 
10 #include <filesystem>
11 
12 #include <gmock/gmock.h>
13 #include <gtest/gtest.h>
14 
15 namespace phosphor
16 {
17 namespace logging
18 {
19 namespace test
20 {
21 
22 class TestQuiesceOnError : public testing::Test
23 {
24   public:
25     sdbusplus::SdBusMock sdbusMock;
26     sdbusplus::bus_t mockedBus = sdbusplus::get_mocked_new(&sdbusMock);
27     phosphor::logging::internal::Manager manager;
28 
TestQuiesceOnError()29     TestQuiesceOnError() : manager(mockedBus, OBJ_INTERNAL)
30     {
31         // Ensure any errors serializing to filesystem have directory created
32         std::filesystem::create_directories(paths::error());
33     }
34 };
35 
36 // Test that false is returned when no callout is present in the log
TEST_F(TestQuiesceOnError,testNoCallout)37 TEST_F(TestQuiesceOnError, testNoCallout)
38 {
39     uint32_t id = 99;
40     uint64_t timestamp{100};
41     std::string message{"test error"};
42     std::string fwLevel{"level42"};
43     std::string path{"/tmp/99"};
44     std::map<std::string, std::string> testData{{"no", "no"},
45                                                 {"callout", "callout"}};
46     phosphor::logging::AssociationList associations{};
47 
48     Entry elog{mockedBus,
49                std::string(OBJ_ENTRY) + '/' + std::to_string(id),
50                id,
51                timestamp,
52                Entry::Level::Informational,
53                std::move(message),
54                std::move(testData),
55                std::move(associations),
56                fwLevel,
57                path,
58                manager};
59 
60     EXPECT_EQ(manager.isCalloutPresent(elog), false);
61 }
62 
63 // Test that trues is returned when a callout is present in the log
TEST_F(TestQuiesceOnError,testCallout)64 TEST_F(TestQuiesceOnError, testCallout)
65 {
66     uint32_t id = 99;
67     uint64_t timestamp{100};
68     std::string message{"test error"};
69     std::string fwLevel{"level42"};
70     std::string path{"/tmp/99"};
71     std::map<std::string, std::string> testData{
72         {"CALLOUT_INVENTORY_PATH",
73          "/xyz/openbmc_project/inventory/system/chassis/motherboard/powersupply0/"}};
74     phosphor::logging::AssociationList associations{};
75 
76     Entry elog{mockedBus,
77                std::string(OBJ_ENTRY) + '/' + std::to_string(id),
78                id,
79                timestamp,
80                Entry::Level::Informational,
81                std::move(message),
82                std::move(testData),
83                std::move(associations),
84                fwLevel,
85                path,
86                manager};
87 
88     EXPECT_EQ(manager.isCalloutPresent(elog), true);
89 }
90 
91 // Test that a blocking error is created on entry with callout
TEST_F(TestQuiesceOnError,testBlockingErrorsCreated)92 TEST_F(TestQuiesceOnError, testBlockingErrorsCreated)
93 {
94     uint32_t id = 100;
95     uint64_t timestamp{100};
96     std::string message{"test error"};
97     std::string fwLevel{"level42"};
98     std::string path{"/tmp/99"};
99     std::map<std::string, std::string> testData{
100         {"CALLOUT_INVENTORY_PATH",
101          "/xyz/openbmc_project/inventory/system/chassis/motherboard/powersupply0/"}};
102     phosphor::logging::AssociationList associations{};
103 
104     // Ensure D-Bus object created for this blocking error
105     // First allow any number of sd_bus_emit_object_added calls
106     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(testing::_, testing::_))
107         .Times(testing::AnyNumber());
108     // Second verify the new block100 object is created once
109     EXPECT_CALL(sdbusMock,
110                 sd_bus_emit_object_added(
111                     testing::_, testing::HasSubstr(
112                                     "/xyz/openbmc_project/logging/block100")))
113         .Times(1);
114 
115     Entry elog{mockedBus,
116                std::string(OBJ_ENTRY) + '/' + std::to_string(id),
117                id,
118                timestamp,
119                Entry::Level::Informational,
120                std::move(message),
121                std::move(testData),
122                std::move(associations),
123                fwLevel,
124                path,
125                manager};
126 
127     manager.quiesceOnError(id);
128     // Created error with callout so expect a blocking error now
129     EXPECT_EQ(manager.getBlockingErrSize(), 1);
130 
131     // Now delete the error and make sure the object and entry go away
132     EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(testing::_, testing::_))
133         .Times(testing::AnyNumber());
134     EXPECT_CALL(sdbusMock,
135                 sd_bus_emit_object_removed(
136                     testing::_, testing::HasSubstr(
137                                     "/xyz/openbmc_project/logging/block100")))
138         .Times(1);
139 
140     // Make sure nothing happens within invalid id
141     manager.checkAndRemoveBlockingError(id + 1);
142     EXPECT_EQ(manager.getBlockingErrSize(), 1);
143 
144     manager.checkAndRemoveBlockingError(id);
145     EXPECT_EQ(manager.getBlockingErrSize(), 0);
146 }
147 
148 // Test that a blocking error is created on entry with callout
TEST_F(TestQuiesceOnError,testBlockingErrorsResolved)149 TEST_F(TestQuiesceOnError, testBlockingErrorsResolved)
150 {
151     uint32_t id = 101;
152     uint64_t timestamp{100};
153     std::string message{"test error"};
154     std::string fwLevel{"level42"};
155     std::string path{"/tmp/99"};
156     std::map<std::string, std::string> testData{
157         {"CALLOUT_INVENTORY_PATH",
158          "/xyz/openbmc_project/inventory/system/chassis/motherboard/powersupply0/"}};
159     phosphor::logging::AssociationList associations{};
160 
161     // Ensure D-Bus object created for this blocking error
162     // First allow any number of sd_bus_emit_object_added calls
163     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(testing::_, testing::_))
164         .Times(testing::AnyNumber());
165     // Second verify the new block100 object is created once
166     EXPECT_CALL(sdbusMock,
167                 sd_bus_emit_object_added(
168                     testing::_, testing::HasSubstr(
169                                     "/xyz/openbmc_project/logging/block101")))
170         .Times(1);
171 
172     Entry elog{mockedBus,
173                std::string(OBJ_ENTRY) + '/' + std::to_string(id),
174                id,
175                timestamp,
176                Entry::Level::Informational,
177                std::move(message),
178                std::move(testData),
179                std::move(associations),
180                fwLevel,
181                path,
182                manager};
183 
184     manager.quiesceOnError(id);
185     // Created error with callout so expect a blocking error now
186     EXPECT_EQ(manager.getBlockingErrSize(), 1);
187     // Also should have a callback create looking for entry to be resolved
188     EXPECT_EQ(manager.getEntryCallbackSize(), 1);
189 
190     // Now resolve the error and make sure the object and entry go away
191     EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(testing::_, testing::_))
192         .Times(testing::AnyNumber());
193     EXPECT_CALL(sdbusMock,
194                 sd_bus_emit_object_removed(
195                     testing::_, testing::HasSubstr(
196                                     "/xyz/openbmc_project/logging/block101")))
197         .Times(1);
198 
199     elog.resolved(true);
200     // Note that property signal callbacks do not work in unit test so directly
201     // call the interface to find and resolve blocking entries
202     manager.checkAndRemoveBlockingError(101);
203     EXPECT_EQ(manager.getBlockingErrSize(), 0);
204     EXPECT_EQ(manager.getEntryCallbackSize(), 0);
205 }
206 
207 // Test that a blocking error is only created once for an individual bmc id
TEST_F(TestQuiesceOnError,testBlockingErrorTwice)208 TEST_F(TestQuiesceOnError, testBlockingErrorTwice)
209 {
210     uint32_t id = 100;
211     uint64_t timestamp{100};
212     std::string message{"test error"};
213     std::string fwLevel{"level42"};
214     std::string path{"/tmp/99"};
215     std::map<std::string, std::string> testData{
216         {"CALLOUT_INVENTORY_PATH",
217          "/xyz/openbmc_project/inventory/system/chassis/motherboard/powersupply0/"}};
218     phosphor::logging::AssociationList associations{};
219 
220     // Ensure D-Bus object created for this blocking error
221     // First allow any number of sd_bus_emit_object_added calls
222     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(testing::_, testing::_))
223         .Times(testing::AnyNumber());
224     // Second verify the new block100 object is created once
225     EXPECT_CALL(sdbusMock,
226                 sd_bus_emit_object_added(
227                     testing::_, testing::HasSubstr(
228                                     "/xyz/openbmc_project/logging/block100")))
229         .Times(1);
230 
231     Entry elog{mockedBus,
232                std::string(OBJ_ENTRY) + '/' + std::to_string(id),
233                id,
234                timestamp,
235                Entry::Level::Informational,
236                std::move(message),
237                std::move(testData),
238                std::move(associations),
239                fwLevel,
240                path,
241                manager};
242 
243     manager.quiesceOnError(id);
244     // Created error with callout so expect a blocking error now
245     EXPECT_EQ(manager.getBlockingErrSize(), 1);
246 
247     // Now pass in same ID and make sure it's ignored
248     manager.quiesceOnError(id);
249 
250     // Now delete the error and make sure the object and entry go away
251     EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(testing::_, testing::_))
252         .Times(testing::AnyNumber());
253     EXPECT_CALL(sdbusMock,
254                 sd_bus_emit_object_removed(
255                     testing::_, testing::HasSubstr(
256                                     "/xyz/openbmc_project/logging/block100")))
257         .Times(1);
258 
259     manager.checkAndRemoveBlockingError(id);
260     EXPECT_EQ(manager.getBlockingErrSize(), 0);
261 }
262 
263 } // namespace test
264 } // namespace logging
265 } // namespace phosphor
266