xref: /openbmc/phosphor-logging/test/elog_quiesce_test.cpp (revision ce9fe69344d82feb03edd3cd123a8a5d78fef32b)
1 #include "config.h"
2 
3 #include "elog_entry.hpp"
4 #include "log_manager.hpp"
5 
6 #include <filesystem>
7 #include <sdbusplus/bus.hpp>
8 #include <sdbusplus/test/sdbus_mock.hpp>
9 
10 #include <gmock/gmock.h>
11 #include <gtest/gtest.h>
12 
13 namespace phosphor
14 {
15 namespace logging
16 {
17 namespace test
18 {
19 
20 class 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     {
29         // Ensure any errors serializing to filesystem have directory created
30         std::filesystem::create_directory(ERRLOG_PERSIST_PATH);
31     }
32 };
33 
34 // Test that false is returned when no callout is present in the log
35 TEST_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
59 TEST_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 
84 // Test that no blocking errors are created when no callout
85 TEST_F(TestQuiesceOnError, testNoBlockingErrorsCreated)
86 {
87     uint32_t id = 99;
88     uint64_t timestamp{100};
89     std::string message{"test error"};
90     std::string fwLevel{"level42"};
91     std::vector<std::string> testData{"no", "callout"};
92     phosphor::logging::AssociationList associations{};
93 
94     Entry elog{mockedBus,
95                std::string(OBJ_ENTRY) + '/' + std::to_string(id),
96                id,
97                timestamp,
98                Entry::Level::Informational,
99                std::move(message),
100                std::move(testData),
101                std::move(associations),
102                fwLevel,
103                manager};
104 
105     manager.checkQuiesceOnError(elog);
106     EXPECT_EQ(manager.getBlockingErrSize(), 0);
107 }
108 
109 // Test that a blocking error is created on entry with callout
110 TEST_F(TestQuiesceOnError, testBlockingErrorsCreated)
111 {
112     uint32_t id = 100;
113     uint64_t timestamp{100};
114     std::string message{"test error"};
115     std::string fwLevel{"level42"};
116     std::vector<std::string> testData{
117         "CALLOUT_INVENTORY_PATH=/xyz/openbmc_project/inventory/system/chassis/"
118         "motherboard/powersupply0/"};
119     phosphor::logging::AssociationList associations{};
120 
121     // Ensure D-Bus object created for this blocking error
122     // First allow any number of sd_bus_emit_object_added calls
123     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(testing::_, testing::_))
124         .Times(testing::AnyNumber());
125     // Second verify the new block100 object is created once
126     EXPECT_CALL(sdbusMock,
127                 sd_bus_emit_object_added(
128                     testing::_, testing::HasSubstr(
129                                     "/xyz/openbmc_project/logging/block100")))
130         .Times(1);
131 
132     Entry elog{mockedBus,
133                std::string(OBJ_ENTRY) + '/' + std::to_string(id),
134                id,
135                timestamp,
136                Entry::Level::Informational,
137                std::move(message),
138                std::move(testData),
139                std::move(associations),
140                fwLevel,
141                manager};
142 
143     manager.checkQuiesceOnError(elog);
144     // Created error with callout so expect a blocking error now
145     EXPECT_EQ(manager.getBlockingErrSize(), 1);
146 
147     // Now delete the error and make sure the object and entry go away
148     EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(testing::_, testing::_))
149         .Times(testing::AnyNumber());
150     EXPECT_CALL(sdbusMock,
151                 sd_bus_emit_object_removed(
152                     testing::_, testing::HasSubstr(
153                                     "/xyz/openbmc_project/logging/block100")))
154         .Times(1);
155 
156     // Make sure nothing happens within invalid id
157     manager.checkAndRemoveBlockingError(id + 1);
158     EXPECT_EQ(manager.getBlockingErrSize(), 1);
159 
160     manager.checkAndRemoveBlockingError(id);
161     EXPECT_EQ(manager.getBlockingErrSize(), 0);
162 }
163 
164 // Test that a blocking error is created on entry with callout
165 TEST_F(TestQuiesceOnError, testBlockingErrorsResolved)
166 {
167     uint32_t id = 101;
168     uint64_t timestamp{100};
169     std::string message{"test error"};
170     std::string fwLevel{"level42"};
171     std::vector<std::string> testData{
172         "CALLOUT_INVENTORY_PATH=/xyz/openbmc_project/inventory/system/chassis/"
173         "motherboard/powersupply0/"};
174     phosphor::logging::AssociationList associations{};
175 
176     // Ensure D-Bus object created for this blocking error
177     // First allow any number of sd_bus_emit_object_added calls
178     EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(testing::_, testing::_))
179         .Times(testing::AnyNumber());
180     // Second verify the new block100 object is created once
181     EXPECT_CALL(sdbusMock,
182                 sd_bus_emit_object_added(
183                     testing::_, testing::HasSubstr(
184                                     "/xyz/openbmc_project/logging/block101")))
185         .Times(1);
186 
187     Entry elog{mockedBus,
188                std::string(OBJ_ENTRY) + '/' + std::to_string(id),
189                id,
190                timestamp,
191                Entry::Level::Informational,
192                std::move(message),
193                std::move(testData),
194                std::move(associations),
195                fwLevel,
196                manager};
197 
198     manager.checkQuiesceOnError(elog);
199     // Created error with callout so expect a blocking error now
200     EXPECT_EQ(manager.getBlockingErrSize(), 1);
201     // Also should have a callback create looking for entry to be resolved
202     EXPECT_EQ(manager.getEntryCallbackSize(), 1);
203 
204     // Now resolve the error and make sure the object and entry go away
205     EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(testing::_, testing::_))
206         .Times(testing::AnyNumber());
207     EXPECT_CALL(sdbusMock,
208                 sd_bus_emit_object_removed(
209                     testing::_, testing::HasSubstr(
210                                     "/xyz/openbmc_project/logging/block101")))
211         .Times(1);
212 
213     elog.resolved(true);
214     // Note that property signal callbacks do not work in unit test so directly
215     // call the interface to find and resolve blocking entries
216     manager.checkAndRemoveBlockingError(101);
217     EXPECT_EQ(manager.getBlockingErrSize(), 0);
218     EXPECT_EQ(manager.getEntryCallbackSize(), 0);
219 }
220 
221 } // namespace test
222 } // namespace logging
223 } // namespace phosphor
224