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