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