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