blob: 467507312ecc36af042a0e48a207c449c7f3ef7c [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 no blocking errors are created when no callout
85TEST_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
110TEST_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);
Andrew Geisslerced6e2a2020-04-07 16:15:29 -0500146
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);
Andrew Geissler6a0ef6f2020-04-06 15:06:31 -0500162}
163
Andrew Geissler7f6d4bc2020-04-16 14:47:34 -0500164// Test that a blocking error is created on entry with callout
165TEST_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
Andrew Geisslere4960ee2020-03-30 14:31:52 -0500221} // namespace test
222} // namespace logging
223} // namespace phosphor