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