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