| Alexander Hansen | 40fb549 | 2025-10-28 17:56:12 +0100 | [diff] [blame^] | 1 | // SPDX-License-Identifier: Apache-2.0 | 
 | 2 | // SPDX-FileCopyrightText: Copyright 2019 IBM Corporation | 
 | 3 |  | 
| Matt Spinler | f60ac27 | 2019-12-11 13:47:50 -0600 | [diff] [blame] | 4 | #include "extensions/openpower-pels/data_interface.hpp" | 
 | 5 | #include "extensions/openpower-pels/host_notifier.hpp" | 
 | 6 | #include "mocks.hpp" | 
 | 7 | #include "pel_utils.hpp" | 
 | 8 |  | 
 | 9 | #include <fcntl.h> | 
 | 10 | #include <sys/stat.h> | 
 | 11 | #include <sys/types.h> | 
 | 12 |  | 
 | 13 | #include <chrono> | 
 | 14 |  | 
 | 15 | #include <gtest/gtest.h> | 
 | 16 |  | 
 | 17 | using namespace openpower::pels; | 
 | 18 | using ::testing::_; | 
 | 19 | using ::testing::Invoke; | 
| Matt Spinler | 56e0826 | 2020-01-27 16:14:23 -0600 | [diff] [blame] | 20 | using ::testing::NiceMock; | 
| Matt Spinler | f60ac27 | 2019-12-11 13:47:50 -0600 | [diff] [blame] | 21 | using ::testing::Return; | 
 | 22 | namespace fs = std::filesystem; | 
 | 23 | using namespace std::chrono; | 
 | 24 |  | 
 | 25 | const size_t actionFlags0Offset = 66; | 
 | 26 | const size_t actionFlags1Offset = 67; | 
 | 27 |  | 
 | 28 | class HostNotifierTest : public CleanPELFiles | 
 | 29 | { | 
| Matt Spinler | a943b15 | 2019-12-11 14:44:50 -0600 | [diff] [blame] | 30 |   public: | 
| Matt Spinler | 56e0826 | 2020-01-27 16:14:23 -0600 | [diff] [blame] | 31 |     HostNotifierTest() : repo(repoPath) | 
| Matt Spinler | a943b15 | 2019-12-11 14:44:50 -0600 | [diff] [blame] | 32 |     { | 
 | 33 |         auto r = sd_event_default(&event); | 
 | 34 |         EXPECT_TRUE(r >= 0); | 
| Matt Spinler | 56e0826 | 2020-01-27 16:14:23 -0600 | [diff] [blame] | 35 |  | 
| Matt Spinler | 24a8558 | 2020-01-27 16:40:21 -0600 | [diff] [blame] | 36 |         ON_CALL(dataIface, getHostPELEnablement).WillByDefault(Return(true)); | 
 | 37 |  | 
| Patrick Williams | 075c792 | 2024-08-16 15:19:49 -0400 | [diff] [blame] | 38 |         hostIface = | 
 | 39 |             std::make_unique<NiceMock<MockHostInterface>>(event, dataIface); | 
| Matt Spinler | 56e0826 | 2020-01-27 16:14:23 -0600 | [diff] [blame] | 40 |  | 
 | 41 |         mockHostIface = reinterpret_cast<MockHostInterface*>(hostIface.get()); | 
 | 42 |  | 
| Patrick Williams | d26fa3e | 2021-04-21 15:22:23 -0500 | [diff] [blame] | 43 |         auto send = [this](uint32_t /*id*/, uint32_t /*size*/) { | 
| Matt Spinler | 56e0826 | 2020-01-27 16:14:23 -0600 | [diff] [blame] | 44 |             return this->mockHostIface->send(0); | 
 | 45 |         }; | 
 | 46 |  | 
 | 47 |         // Unless otherwise specified, sendNewLogCmd should always pass. | 
| Matt Spinler | d438c09 | 2025-10-24 10:00:02 -0500 | [diff] [blame] | 48 |         ON_CALL(*mockHostIface, sendNewLogCmd(_, _)).WillByDefault(send); | 
| Matt Spinler | a943b15 | 2019-12-11 14:44:50 -0600 | [diff] [blame] | 49 |     } | 
 | 50 |  | 
 | 51 |     ~HostNotifierTest() | 
 | 52 |     { | 
 | 53 |         sd_event_unref(event); | 
 | 54 |     } | 
 | 55 |  | 
 | 56 |   protected: | 
 | 57 |     sd_event* event; | 
| Matt Spinler | 56e0826 | 2020-01-27 16:14:23 -0600 | [diff] [blame] | 58 |     Repository repo; | 
 | 59 |     NiceMock<MockDataInterface> dataIface; | 
 | 60 |     std::unique_ptr<HostInterface> hostIface; | 
 | 61 |     MockHostInterface* mockHostIface; | 
| Matt Spinler | f60ac27 | 2019-12-11 13:47:50 -0600 | [diff] [blame] | 62 | }; | 
 | 63 |  | 
 | 64 | /** | 
 | 65 |  * @brief Create PEL with the specified action flags | 
 | 66 |  * | 
 | 67 |  * @param[in] actionFlagsMask - Optional action flags to use | 
 | 68 |  * | 
 | 69 |  * @return std::unique_ptr<PEL> | 
 | 70 |  */ | 
 | 71 | std::unique_ptr<PEL> makePEL(uint16_t actionFlagsMask = 0) | 
 | 72 | { | 
 | 73 |     static uint32_t obmcID = 1; | 
 | 74 |     auto data = pelDataFactory(TestPELType::pelSimple); | 
 | 75 |  | 
 | 76 |     data[actionFlags0Offset] |= actionFlagsMask >> 8; | 
 | 77 |     data[actionFlags1Offset] |= actionFlagsMask & 0xFF; | 
 | 78 |  | 
 | 79 |     auto pel = std::make_unique<PEL>(data, obmcID++); | 
 | 80 |     pel->assignID(); | 
 | 81 |     pel->setCommitTime(); | 
 | 82 |     return pel; | 
 | 83 | } | 
 | 84 |  | 
| Matt Spinler | 7d800a4 | 2019-12-12 10:35:01 -0600 | [diff] [blame] | 85 | /** | 
 | 86 |  * @brief Run an iteration of the event loop. | 
 | 87 |  * | 
 | 88 |  * An event loop is used for: | 
 | 89 |  *   1) timer expiration callbacks | 
 | 90 |  *   2) Dispatches | 
 | 91 |  *   3) host interface receive callbacks | 
 | 92 |  * | 
 | 93 |  * @param[in] event - The event object | 
 | 94 |  * @param[in] numEvents - number of times to call Event::run() | 
 | 95 |  * @param[in] timeout - timeout value for run() | 
 | 96 |  */ | 
 | 97 | void runEvents(sdeventplus::Event& event, size_t numEvents, | 
 | 98 |                milliseconds timeout = milliseconds(1)) | 
 | 99 | { | 
 | 100 |     for (size_t i = 0; i < numEvents; i++) | 
 | 101 |     { | 
 | 102 |         event.run(timeout); | 
 | 103 |     } | 
 | 104 | } | 
 | 105 |  | 
| Matt Spinler | f60ac27 | 2019-12-11 13:47:50 -0600 | [diff] [blame] | 106 | // Test that host state change callbacks work | 
 | 107 | TEST_F(HostNotifierTest, TestHostStateChange) | 
 | 108 | { | 
| Matt Spinler | f60ac27 | 2019-12-11 13:47:50 -0600 | [diff] [blame] | 109 |     bool hostState = false; | 
 | 110 |     bool called = false; | 
| Patrick Williams | 075c792 | 2024-08-16 15:19:49 -0400 | [diff] [blame] | 111 |     DataInterfaceBase::HostStateChangeFunc func = | 
 | 112 |         [&hostState, &called](bool state) { | 
 | 113 |             hostState = state; | 
 | 114 |             called = true; | 
 | 115 |         }; | 
| Matt Spinler | f60ac27 | 2019-12-11 13:47:50 -0600 | [diff] [blame] | 116 |  | 
 | 117 |     dataIface.subscribeToHostStateChange("test", func); | 
 | 118 |  | 
 | 119 |     // callback called | 
 | 120 |     dataIface.changeHostState(true); | 
 | 121 |     EXPECT_TRUE(called); | 
 | 122 |     EXPECT_TRUE(hostState); | 
 | 123 |  | 
 | 124 |     // No change, not called | 
 | 125 |     called = false; | 
 | 126 |     dataIface.changeHostState(true); | 
 | 127 |     EXPECT_FALSE(called); | 
 | 128 |  | 
 | 129 |     // Called again | 
 | 130 |     dataIface.changeHostState(false); | 
 | 131 |     EXPECT_FALSE(hostState); | 
 | 132 |     EXPECT_TRUE(called); | 
 | 133 |  | 
 | 134 |     // Shouldn't get called after an unsubscribe | 
 | 135 |     dataIface.unsubscribeFromHostStateChange("test"); | 
 | 136 |  | 
 | 137 |     called = false; | 
 | 138 |  | 
 | 139 |     dataIface.changeHostState(true); | 
 | 140 |     EXPECT_FALSE(called); | 
 | 141 | } | 
 | 142 |  | 
| Matt Spinler | a943b15 | 2019-12-11 14:44:50 -0600 | [diff] [blame] | 143 | // Test dealing with how acked PELs are put on the | 
 | 144 | // notification queue. | 
 | 145 | TEST_F(HostNotifierTest, TestPolicyAckedPEL) | 
 | 146 | { | 
| Matt Spinler | a943b15 | 2019-12-11 14:44:50 -0600 | [diff] [blame] | 147 |     HostNotifier notifier{repo, dataIface, std::move(hostIface)}; | 
 | 148 |  | 
 | 149 |     auto pel = makePEL(); | 
 | 150 |     repo.add(pel); | 
 | 151 |  | 
 | 152 |     // This is required | 
 | 153 |     EXPECT_TRUE(notifier.enqueueRequired(pel->id())); | 
| Matt Spinler | f77debb | 2019-12-12 10:04:33 -0600 | [diff] [blame] | 154 |     EXPECT_TRUE(notifier.notifyRequired(pel->id())); | 
| Matt Spinler | a943b15 | 2019-12-11 14:44:50 -0600 | [diff] [blame] | 155 |  | 
 | 156 |     // Not in the repo | 
 | 157 |     EXPECT_FALSE(notifier.enqueueRequired(42)); | 
| Matt Spinler | f77debb | 2019-12-12 10:04:33 -0600 | [diff] [blame] | 158 |     EXPECT_FALSE(notifier.notifyRequired(42)); | 
| Matt Spinler | a943b15 | 2019-12-11 14:44:50 -0600 | [diff] [blame] | 159 |  | 
 | 160 |     // Now set this PEL to host acked | 
 | 161 |     repo.setPELHostTransState(pel->id(), TransmissionState::acked); | 
 | 162 |  | 
 | 163 |     // Since it's acked, doesn't need to be enqueued or transmitted | 
 | 164 |     EXPECT_FALSE(notifier.enqueueRequired(pel->id())); | 
| Matt Spinler | f77debb | 2019-12-12 10:04:33 -0600 | [diff] [blame] | 165 |     EXPECT_FALSE(notifier.notifyRequired(pel->id())); | 
| Matt Spinler | a943b15 | 2019-12-11 14:44:50 -0600 | [diff] [blame] | 166 | } | 
 | 167 |  | 
 | 168 | // Test the 'don't report' PEL flag | 
 | 169 | TEST_F(HostNotifierTest, TestPolicyDontReport) | 
 | 170 | { | 
| Matt Spinler | a943b15 | 2019-12-11 14:44:50 -0600 | [diff] [blame] | 171 |     HostNotifier notifier{repo, dataIface, std::move(hostIface)}; | 
 | 172 |  | 
 | 173 |     // dontReportToHostFlagBit | 
 | 174 |     auto pel = makePEL(0x1000); | 
 | 175 |  | 
 | 176 |     // Double check the action flag is still set | 
 | 177 |     std::bitset<16> actionFlags = pel->userHeader().actionFlags(); | 
 | 178 |     EXPECT_TRUE(actionFlags.test(dontReportToHostFlagBit)); | 
 | 179 |  | 
 | 180 |     repo.add(pel); | 
 | 181 |  | 
 | 182 |     // Don't need to send this to the host | 
 | 183 |     EXPECT_FALSE(notifier.enqueueRequired(pel->id())); | 
 | 184 | } | 
 | 185 |  | 
 | 186 | // Test that hidden PELs need notification when there | 
 | 187 | // is no HMC. | 
 | 188 | TEST_F(HostNotifierTest, TestPolicyHiddenNoHMC) | 
 | 189 | { | 
| Matt Spinler | a943b15 | 2019-12-11 14:44:50 -0600 | [diff] [blame] | 190 |     HostNotifier notifier{repo, dataIface, std::move(hostIface)}; | 
 | 191 |  | 
 | 192 |     // hiddenFlagBit | 
 | 193 |     auto pel = makePEL(0x4000); | 
 | 194 |  | 
 | 195 |     // Double check the action flag is still set | 
 | 196 |     std::bitset<16> actionFlags = pel->userHeader().actionFlags(); | 
 | 197 |     EXPECT_TRUE(actionFlags.test(hiddenFlagBit)); | 
 | 198 |  | 
 | 199 |     repo.add(pel); | 
 | 200 |  | 
 | 201 |     // Still need to enqueue this | 
 | 202 |     EXPECT_TRUE(notifier.enqueueRequired(pel->id())); | 
| Matt Spinler | f77debb | 2019-12-12 10:04:33 -0600 | [diff] [blame] | 203 |  | 
 | 204 |     // Still need to send it | 
 | 205 |     EXPECT_TRUE(notifier.notifyRequired(pel->id())); | 
| Matt Spinler | a943b15 | 2019-12-11 14:44:50 -0600 | [diff] [blame] | 206 | } | 
 | 207 |  | 
 | 208 | // Don't need to enqueue a hidden log already acked by the HMC | 
 | 209 | TEST_F(HostNotifierTest, TestPolicyHiddenWithHMCAcked) | 
 | 210 | { | 
| Matt Spinler | a943b15 | 2019-12-11 14:44:50 -0600 | [diff] [blame] | 211 |     HostNotifier notifier{repo, dataIface, std::move(hostIface)}; | 
 | 212 |  | 
 | 213 |     // hiddenFlagBit | 
 | 214 |     auto pel = makePEL(0x4000); | 
 | 215 |  | 
 | 216 |     // Double check the action flag is still set | 
 | 217 |     std::bitset<16> actionFlags = pel->userHeader().actionFlags(); | 
 | 218 |     EXPECT_TRUE(actionFlags.test(hiddenFlagBit)); | 
 | 219 |  | 
 | 220 |     repo.add(pel); | 
 | 221 |  | 
 | 222 |     // No HMC yet, so required | 
 | 223 |     EXPECT_TRUE(notifier.enqueueRequired(pel->id())); | 
 | 224 |  | 
 | 225 |     repo.setPELHMCTransState(pel->id(), TransmissionState::acked); | 
 | 226 |  | 
 | 227 |     // Not required anymore | 
 | 228 |     EXPECT_FALSE(notifier.enqueueRequired(pel->id())); | 
 | 229 | } | 
 | 230 |  | 
| Matt Spinler | f77debb | 2019-12-12 10:04:33 -0600 | [diff] [blame] | 231 | // Test that changing the HMC manage status affects | 
 | 232 | // the policy with hidden log notification. | 
 | 233 | TEST_F(HostNotifierTest, TestPolicyHiddenWithHMCManaged) | 
 | 234 | { | 
| Matt Spinler | f77debb | 2019-12-12 10:04:33 -0600 | [diff] [blame] | 235 |     HostNotifier notifier{repo, dataIface, std::move(hostIface)}; | 
 | 236 |  | 
 | 237 |     // hiddenFlagBit | 
 | 238 |     auto pel = makePEL(0x4000); | 
 | 239 |  | 
 | 240 |     repo.add(pel); | 
 | 241 |  | 
 | 242 |     // The first time, the HMC managed is false | 
 | 243 |     EXPECT_TRUE(notifier.notifyRequired(pel->id())); | 
 | 244 |  | 
 | 245 |     dataIface.setHMCManaged(true); | 
 | 246 |  | 
 | 247 |     // This time, HMC managed is true so no need to notify | 
 | 248 |     EXPECT_FALSE(notifier.notifyRequired(pel->id())); | 
 | 249 | } | 
 | 250 |  | 
| Matt Spinler | f60ac27 | 2019-12-11 13:47:50 -0600 | [diff] [blame] | 251 | // Test that PELs are enqueued on startup | 
 | 252 | TEST_F(HostNotifierTest, TestStartup) | 
 | 253 | { | 
| Matt Spinler | f60ac27 | 2019-12-11 13:47:50 -0600 | [diff] [blame] | 254 |     // Give the repo 10 PELs to start with | 
 | 255 |     for (int i = 0; i < 10; i++) | 
 | 256 |     { | 
 | 257 |         auto pel = makePEL(); | 
 | 258 |         repo.add(pel); | 
 | 259 |     } | 
 | 260 |  | 
| Matt Spinler | f60ac27 | 2019-12-11 13:47:50 -0600 | [diff] [blame] | 261 |     HostNotifier notifier{repo, dataIface, std::move(hostIface)}; | 
 | 262 |  | 
 | 263 |     ASSERT_EQ(notifier.queueSize(), 10); | 
 | 264 |  | 
 | 265 |     // Now add 10 more after the notifier is watching | 
 | 266 |     for (int i = 0; i < 10; i++) | 
 | 267 |     { | 
 | 268 |         auto pel = makePEL(); | 
 | 269 |         repo.add(pel); | 
 | 270 |     } | 
 | 271 |  | 
 | 272 |     ASSERT_EQ(notifier.queueSize(), 20); | 
 | 273 | } | 
| Matt Spinler | 7d800a4 | 2019-12-12 10:35:01 -0600 | [diff] [blame] | 274 |  | 
 | 275 | // Test the simple path were PELs get sent to the host | 
 | 276 | TEST_F(HostNotifierTest, TestSendCmd) | 
 | 277 | { | 
| Matt Spinler | 7d800a4 | 2019-12-12 10:35:01 -0600 | [diff] [blame] | 278 |     sdeventplus::Event sdEvent{event}; | 
 | 279 |  | 
| Matt Spinler | 7d800a4 | 2019-12-12 10:35:01 -0600 | [diff] [blame] | 280 |     HostNotifier notifier{repo, dataIface, std::move(hostIface)}; | 
 | 281 |  | 
| Matt Spinler | 7d800a4 | 2019-12-12 10:35:01 -0600 | [diff] [blame] | 282 |     // Add a PEL with the host off | 
 | 283 |     auto pel = makePEL(); | 
 | 284 |     repo.add(pel); | 
 | 285 |  | 
 | 286 |     EXPECT_EQ(notifier.queueSize(), 1); | 
 | 287 |  | 
 | 288 |     dataIface.changeHostState(true); | 
 | 289 |  | 
| Matt Spinler | e5f7508 | 2022-01-24 16:09:51 -0600 | [diff] [blame] | 290 |     runEvents(sdEvent, 2); | 
| Matt Spinler | 7d800a4 | 2019-12-12 10:35:01 -0600 | [diff] [blame] | 291 |  | 
 | 292 |     // It was sent up | 
| Matt Spinler | 56e0826 | 2020-01-27 16:14:23 -0600 | [diff] [blame] | 293 |     EXPECT_EQ(mockHostIface->numCmdsProcessed(), 1); | 
| Matt Spinler | 7d800a4 | 2019-12-12 10:35:01 -0600 | [diff] [blame] | 294 |     EXPECT_EQ(notifier.queueSize(), 0); | 
 | 295 |  | 
 | 296 |     // Verify the state was written to the PEL. | 
 | 297 |     Repository::LogID id{Repository::LogID::Pel{pel->id()}}; | 
 | 298 |     auto data = repo.getPELData(id); | 
 | 299 |     PEL pelFromRepo{*data}; | 
 | 300 |     EXPECT_EQ(pelFromRepo.hostTransmissionState(), TransmissionState::sent); | 
 | 301 |  | 
 | 302 |     // Add a few more PELs.  They will get sent. | 
 | 303 |     pel = makePEL(); | 
 | 304 |     repo.add(pel); | 
 | 305 |  | 
 | 306 |     // Dispatch it by hitting the event loop (no commands sent yet) | 
 | 307 |     // Don't need to test this step discretely in the future | 
 | 308 |     runEvents(sdEvent, 1); | 
| Matt Spinler | 56e0826 | 2020-01-27 16:14:23 -0600 | [diff] [blame] | 309 |     EXPECT_EQ(mockHostIface->numCmdsProcessed(), 1); | 
| Matt Spinler | 7d800a4 | 2019-12-12 10:35:01 -0600 | [diff] [blame] | 310 |     EXPECT_EQ(notifier.queueSize(), 0); | 
 | 311 |  | 
 | 312 |     // Send the command | 
 | 313 |     runEvents(sdEvent, 1); | 
 | 314 |  | 
| Matt Spinler | 56e0826 | 2020-01-27 16:14:23 -0600 | [diff] [blame] | 315 |     EXPECT_EQ(mockHostIface->numCmdsProcessed(), 2); | 
| Matt Spinler | 7d800a4 | 2019-12-12 10:35:01 -0600 | [diff] [blame] | 316 |     EXPECT_EQ(notifier.queueSize(), 0); | 
 | 317 |  | 
 | 318 |     pel = makePEL(); | 
 | 319 |     repo.add(pel); | 
 | 320 |  | 
 | 321 |     // dispatch and process the command | 
 | 322 |     runEvents(sdEvent, 2); | 
 | 323 |  | 
| Matt Spinler | 56e0826 | 2020-01-27 16:14:23 -0600 | [diff] [blame] | 324 |     EXPECT_EQ(mockHostIface->numCmdsProcessed(), 3); | 
| Matt Spinler | 7d800a4 | 2019-12-12 10:35:01 -0600 | [diff] [blame] | 325 |     EXPECT_EQ(notifier.queueSize(), 0); | 
 | 326 | } | 
 | 327 |  | 
 | 328 | // Test that if the class is created with the host up, | 
 | 329 | // it will send PELs | 
 | 330 | TEST_F(HostNotifierTest, TestStartAfterHostUp) | 
 | 331 | { | 
| Matt Spinler | 7d800a4 | 2019-12-12 10:35:01 -0600 | [diff] [blame] | 332 |     // Add PELs right away | 
 | 333 |     auto pel = makePEL(); | 
 | 334 |     repo.add(pel); | 
 | 335 |     pel = makePEL(); | 
 | 336 |     repo.add(pel); | 
 | 337 |  | 
 | 338 |     sdeventplus::Event sdEvent{event}; | 
 | 339 |  | 
| Matt Spinler | 7d800a4 | 2019-12-12 10:35:01 -0600 | [diff] [blame] | 340 |     // Create the HostNotifier class with the host already up | 
 | 341 |     dataIface.changeHostState(true); | 
 | 342 |     HostNotifier notifier{repo, dataIface, std::move(hostIface)}; | 
 | 343 |  | 
 | 344 |     // It should start sending PELs right away | 
| Matt Spinler | e5f7508 | 2022-01-24 16:09:51 -0600 | [diff] [blame] | 345 |     runEvents(sdEvent, 3); | 
| Matt Spinler | 7d800a4 | 2019-12-12 10:35:01 -0600 | [diff] [blame] | 346 |  | 
| Matt Spinler | 56e0826 | 2020-01-27 16:14:23 -0600 | [diff] [blame] | 347 |     EXPECT_EQ(mockHostIface->numCmdsProcessed(), 2); | 
| Matt Spinler | 7d800a4 | 2019-12-12 10:35:01 -0600 | [diff] [blame] | 348 |     EXPECT_EQ(notifier.queueSize(), 0); | 
 | 349 | } | 
 | 350 |  | 
 | 351 | // Test that a single failure will cause a retry | 
 | 352 | TEST_F(HostNotifierTest, TestHostRetry) | 
 | 353 | { | 
| Matt Spinler | 7d800a4 | 2019-12-12 10:35:01 -0600 | [diff] [blame] | 354 |     sdeventplus::Event sdEvent{event}; | 
 | 355 |  | 
| Matt Spinler | 7d800a4 | 2019-12-12 10:35:01 -0600 | [diff] [blame] | 356 |     HostNotifier notifier{repo, dataIface, std::move(hostIface)}; | 
 | 357 |  | 
| Patrick Williams | d26fa3e | 2021-04-21 15:22:23 -0500 | [diff] [blame] | 358 |     auto sendFailure = [this](uint32_t /*id*/, uint32_t /*size*/) { | 
| Matt Spinler | 56e0826 | 2020-01-27 16:14:23 -0600 | [diff] [blame] | 359 |         return this->mockHostIface->send(1); | 
| Matt Spinler | 7d800a4 | 2019-12-12 10:35:01 -0600 | [diff] [blame] | 360 |     }; | 
| Patrick Williams | d26fa3e | 2021-04-21 15:22:23 -0500 | [diff] [blame] | 361 |     auto sendSuccess = [this](uint32_t /*id*/, uint32_t /*size*/) { | 
| Matt Spinler | 56e0826 | 2020-01-27 16:14:23 -0600 | [diff] [blame] | 362 |         return this->mockHostIface->send(0); | 
| Matt Spinler | 7d800a4 | 2019-12-12 10:35:01 -0600 | [diff] [blame] | 363 |     }; | 
 | 364 |  | 
| Matt Spinler | 56e0826 | 2020-01-27 16:14:23 -0600 | [diff] [blame] | 365 |     EXPECT_CALL(*mockHostIface, sendNewLogCmd(_, _)) | 
| Matt Spinler | d438c09 | 2025-10-24 10:00:02 -0500 | [diff] [blame] | 366 |         .WillOnce(sendFailure) | 
 | 367 |         .WillOnce(sendSuccess) | 
 | 368 |         .WillOnce(sendSuccess); | 
| Matt Spinler | 7d800a4 | 2019-12-12 10:35:01 -0600 | [diff] [blame] | 369 |  | 
 | 370 |     dataIface.changeHostState(true); | 
 | 371 |  | 
 | 372 |     auto pel = makePEL(); | 
 | 373 |     repo.add(pel); | 
 | 374 |  | 
 | 375 |     // Dispatch and handle the command | 
 | 376 |     runEvents(sdEvent, 2); | 
 | 377 |  | 
 | 378 |     // The command failed, so the queue isn't empty | 
| Matt Spinler | 56e0826 | 2020-01-27 16:14:23 -0600 | [diff] [blame] | 379 |     EXPECT_EQ(mockHostIface->numCmdsProcessed(), 1); | 
| Matt Spinler | 7d800a4 | 2019-12-12 10:35:01 -0600 | [diff] [blame] | 380 |     EXPECT_EQ(notifier.queueSize(), 1); | 
 | 381 |  | 
 | 382 |     // Run the events again to let the timer expire and the | 
 | 383 |     // command to be retried, which will be successful. | 
| Matt Spinler | 56e0826 | 2020-01-27 16:14:23 -0600 | [diff] [blame] | 384 |     runEvents(sdEvent, 2, mockHostIface->getReceiveRetryDelay()); | 
| Matt Spinler | 7d800a4 | 2019-12-12 10:35:01 -0600 | [diff] [blame] | 385 |  | 
| Matt Spinler | 56e0826 | 2020-01-27 16:14:23 -0600 | [diff] [blame] | 386 |     EXPECT_EQ(mockHostIface->numCmdsProcessed(), 2); | 
| Matt Spinler | 7d800a4 | 2019-12-12 10:35:01 -0600 | [diff] [blame] | 387 |     EXPECT_EQ(notifier.queueSize(), 0); | 
 | 388 |  | 
 | 389 |     // This one should pass with no problems | 
 | 390 |     pel = makePEL(); | 
 | 391 |     repo.add(pel); | 
 | 392 |  | 
 | 393 |     // Dispatch and handle the command | 
 | 394 |     runEvents(sdEvent, 2); | 
 | 395 |  | 
| Matt Spinler | 56e0826 | 2020-01-27 16:14:23 -0600 | [diff] [blame] | 396 |     EXPECT_EQ(mockHostIface->numCmdsProcessed(), 3); | 
| Matt Spinler | 7d800a4 | 2019-12-12 10:35:01 -0600 | [diff] [blame] | 397 |     EXPECT_EQ(notifier.queueSize(), 0); | 
 | 398 | } | 
 | 399 |  | 
 | 400 | // Test that all commands fail and notifier will give up | 
 | 401 | TEST_F(HostNotifierTest, TestHardFailure) | 
 | 402 | { | 
| Matt Spinler | 7d800a4 | 2019-12-12 10:35:01 -0600 | [diff] [blame] | 403 |     sdeventplus::Event sdEvent{event}; | 
 | 404 |  | 
| Matt Spinler | 7d800a4 | 2019-12-12 10:35:01 -0600 | [diff] [blame] | 405 |     HostNotifier notifier{repo, dataIface, std::move(hostIface)}; | 
 | 406 |  | 
 | 407 |     // Every call will fail | 
| Patrick Williams | d26fa3e | 2021-04-21 15:22:23 -0500 | [diff] [blame] | 408 |     auto sendFailure = [this](uint32_t /*id*/, uint32_t /*size*/) { | 
| Matt Spinler | 56e0826 | 2020-01-27 16:14:23 -0600 | [diff] [blame] | 409 |         return this->mockHostIface->send(1); | 
| Matt Spinler | 7d800a4 | 2019-12-12 10:35:01 -0600 | [diff] [blame] | 410 |     }; | 
 | 411 |  | 
| Matt Spinler | 56e0826 | 2020-01-27 16:14:23 -0600 | [diff] [blame] | 412 |     EXPECT_CALL(*mockHostIface, sendNewLogCmd(_, _)) | 
| Matt Spinler | d438c09 | 2025-10-24 10:00:02 -0500 | [diff] [blame] | 413 |         .WillRepeatedly(sendFailure); | 
| Matt Spinler | 7d800a4 | 2019-12-12 10:35:01 -0600 | [diff] [blame] | 414 |  | 
 | 415 |     dataIface.changeHostState(true); | 
 | 416 |  | 
 | 417 |     auto pel = makePEL(); | 
 | 418 |     repo.add(pel); | 
 | 419 |  | 
 | 420 |     // Clock more retries than necessary | 
| Matt Spinler | 56e0826 | 2020-01-27 16:14:23 -0600 | [diff] [blame] | 421 |     runEvents(sdEvent, 40, mockHostIface->getReceiveRetryDelay()); | 
| Matt Spinler | 7d800a4 | 2019-12-12 10:35:01 -0600 | [diff] [blame] | 422 |  | 
 | 423 |     // Should have stopped after the 15 Tries | 
| Matt Spinler | 56e0826 | 2020-01-27 16:14:23 -0600 | [diff] [blame] | 424 |     EXPECT_EQ(mockHostIface->numCmdsProcessed(), 15); | 
| Matt Spinler | 7d800a4 | 2019-12-12 10:35:01 -0600 | [diff] [blame] | 425 |     EXPECT_EQ(notifier.queueSize(), 1); | 
 | 426 |  | 
 | 427 |     // Now add another PEL, and it should start trying again | 
 | 428 |     // though it will also eventually give up | 
 | 429 |     pel = makePEL(); | 
 | 430 |     repo.add(pel); | 
 | 431 |  | 
| Matt Spinler | 56e0826 | 2020-01-27 16:14:23 -0600 | [diff] [blame] | 432 |     runEvents(sdEvent, 40, mockHostIface->getReceiveRetryDelay()); | 
| Matt Spinler | 7d800a4 | 2019-12-12 10:35:01 -0600 | [diff] [blame] | 433 |  | 
 | 434 |     // Tried an additional 15 times | 
| Matt Spinler | 56e0826 | 2020-01-27 16:14:23 -0600 | [diff] [blame] | 435 |     EXPECT_EQ(mockHostIface->numCmdsProcessed(), 30); | 
| Matt Spinler | 7d800a4 | 2019-12-12 10:35:01 -0600 | [diff] [blame] | 436 |     EXPECT_EQ(notifier.queueSize(), 2); | 
 | 437 | } | 
 | 438 |  | 
| Matt Spinler | 527ff34 | 2023-06-29 12:52:34 -0500 | [diff] [blame] | 439 | // Test that if the command cannot be started it will give | 
 | 440 | // up but still try again later | 
 | 441 | TEST_F(HostNotifierTest, TestCannotStartCmd) | 
 | 442 | { | 
 | 443 |     sdeventplus::Event sdEvent{event}; | 
 | 444 |  | 
 | 445 |     HostNotifier notifier{repo, dataIface, std::move(hostIface)}; | 
 | 446 |  | 
 | 447 |     // Make it behave like startCommand() fails. | 
 | 448 |     auto sendFailure = [this](uint32_t /*id*/, uint32_t /*size*/) { | 
 | 449 |         this->mockHostIface->cancelCmd(); | 
 | 450 |         return CmdStatus::failure; | 
 | 451 |     }; | 
 | 452 |  | 
 | 453 |     auto sendSuccess = [this](uint32_t /*id*/, uint32_t /*size*/) { | 
 | 454 |         return this->mockHostIface->send(0); | 
 | 455 |     }; | 
 | 456 |  | 
 | 457 |     // Fails 16 times (1 fail + 15  retries) and | 
 | 458 |     // then start working. | 
 | 459 |     EXPECT_CALL(*mockHostIface, sendNewLogCmd(_, _)) | 
| Matt Spinler | d438c09 | 2025-10-24 10:00:02 -0500 | [diff] [blame] | 460 |         .WillOnce(sendFailure) | 
 | 461 |         .WillOnce(sendFailure) | 
 | 462 |         .WillOnce(sendFailure) | 
 | 463 |         .WillOnce(sendFailure) | 
 | 464 |         .WillOnce(sendFailure) | 
 | 465 |         .WillOnce(sendFailure) | 
 | 466 |         .WillOnce(sendFailure) | 
 | 467 |         .WillOnce(sendFailure) | 
 | 468 |         .WillOnce(sendFailure) | 
 | 469 |         .WillOnce(sendFailure) | 
 | 470 |         .WillOnce(sendFailure) | 
 | 471 |         .WillOnce(sendFailure) | 
 | 472 |         .WillOnce(sendFailure) | 
 | 473 |         .WillOnce(sendFailure) | 
 | 474 |         .WillOnce(sendFailure) | 
 | 475 |         .WillOnce(sendFailure) | 
 | 476 |         .WillRepeatedly(sendSuccess); | 
| Matt Spinler | 527ff34 | 2023-06-29 12:52:34 -0500 | [diff] [blame] | 477 |  | 
 | 478 |     dataIface.changeHostState(true); | 
 | 479 |  | 
 | 480 |     auto pel = makePEL(); | 
 | 481 |     repo.add(pel); | 
 | 482 |  | 
 | 483 |     // Clock more retries than necessary | 
 | 484 |     runEvents(sdEvent, 40, mockHostIface->getReceiveRetryDelay()); | 
 | 485 |  | 
 | 486 |     // Didn't get far enough for a cmd to be processed | 
 | 487 |     EXPECT_EQ(mockHostIface->numCmdsProcessed(), 0); | 
 | 488 |     EXPECT_EQ(notifier.queueSize(), 1); | 
 | 489 |  | 
 | 490 |     // At this point, commands will work again. | 
 | 491 |  | 
 | 492 |     pel = makePEL(); | 
 | 493 |     repo.add(pel); | 
 | 494 |  | 
 | 495 |     // Run the events to send the PELs | 
 | 496 |     runEvents(sdEvent, 5, mockHostIface->getReceiveRetryDelay()); | 
 | 497 |  | 
 | 498 |     // All PELs sent | 
 | 499 |     EXPECT_EQ(mockHostIface->numCmdsProcessed(), 2); | 
 | 500 |     EXPECT_EQ(notifier.queueSize(), 0); | 
 | 501 | } | 
 | 502 |  | 
| Matt Spinler | 7d800a4 | 2019-12-12 10:35:01 -0600 | [diff] [blame] | 503 | // Cancel an in progress command | 
 | 504 | TEST_F(HostNotifierTest, TestCancelCmd) | 
 | 505 | { | 
| Matt Spinler | 7d800a4 | 2019-12-12 10:35:01 -0600 | [diff] [blame] | 506 |     sdeventplus::Event sdEvent{event}; | 
| Matt Spinler | 7d800a4 | 2019-12-12 10:35:01 -0600 | [diff] [blame] | 507 |     HostNotifier notifier{repo, dataIface, std::move(hostIface)}; | 
 | 508 |  | 
| Matt Spinler | 7d800a4 | 2019-12-12 10:35:01 -0600 | [diff] [blame] | 509 |     dataIface.changeHostState(true); | 
 | 510 |  | 
 | 511 |     // Add and send one PEL, but don't enter the event loop | 
 | 512 |     // so the receive function can't run. | 
 | 513 |     auto pel = makePEL(); | 
 | 514 |     repo.add(pel); | 
 | 515 |  | 
 | 516 |     // Not dispatched yet | 
 | 517 |     EXPECT_EQ(notifier.queueSize(), 1); | 
 | 518 |  | 
 | 519 |     // Dispatch it | 
| Matt Spinler | e5f7508 | 2022-01-24 16:09:51 -0600 | [diff] [blame] | 520 |     runEvents(sdEvent, 2); | 
| Matt Spinler | 7d800a4 | 2019-12-12 10:35:01 -0600 | [diff] [blame] | 521 |  | 
 | 522 |     // It was sent and off the queue | 
 | 523 |     EXPECT_EQ(notifier.queueSize(), 0); | 
 | 524 |  | 
 | 525 |     // This will cancel the receive | 
 | 526 |     dataIface.changeHostState(false); | 
 | 527 |  | 
 | 528 |     // Back on the queue | 
 | 529 |     EXPECT_EQ(notifier.queueSize(), 1); | 
 | 530 |  | 
 | 531 |     // Turn the host back on and make sure | 
 | 532 |     // commands will work again | 
 | 533 |     dataIface.changeHostState(true); | 
 | 534 |  | 
 | 535 |     runEvents(sdEvent, 1); | 
 | 536 |  | 
| Matt Spinler | 56e0826 | 2020-01-27 16:14:23 -0600 | [diff] [blame] | 537 |     EXPECT_EQ(mockHostIface->numCmdsProcessed(), 1); | 
| Matt Spinler | 7d800a4 | 2019-12-12 10:35:01 -0600 | [diff] [blame] | 538 |     EXPECT_EQ(notifier.queueSize(), 0); | 
 | 539 | } | 
| Matt Spinler | cc3b64a | 2019-12-12 11:27:10 -0600 | [diff] [blame] | 540 |  | 
 | 541 | // Test that acking a PEL persist across power cycles | 
 | 542 | TEST_F(HostNotifierTest, TestPowerCycleAndAcks) | 
 | 543 | { | 
| Matt Spinler | cc3b64a | 2019-12-12 11:27:10 -0600 | [diff] [blame] | 544 |     sdeventplus::Event sdEvent{event}; | 
 | 545 |  | 
| Matt Spinler | cc3b64a | 2019-12-12 11:27:10 -0600 | [diff] [blame] | 546 |     HostNotifier notifier{repo, dataIface, std::move(hostIface)}; | 
 | 547 |  | 
| Matt Spinler | cc3b64a | 2019-12-12 11:27:10 -0600 | [diff] [blame] | 548 |     // Add 2 PELs with host off | 
 | 549 |     auto pel = makePEL(); | 
 | 550 |     repo.add(pel); | 
 | 551 |     auto id1 = pel->id(); | 
 | 552 |  | 
 | 553 |     pel = makePEL(); | 
 | 554 |     repo.add(pel); | 
 | 555 |     auto id2 = pel->id(); | 
 | 556 |  | 
 | 557 |     dataIface.changeHostState(true); | 
 | 558 |  | 
| Matt Spinler | e5f7508 | 2022-01-24 16:09:51 -0600 | [diff] [blame] | 559 |     runEvents(sdEvent, 3); | 
| Matt Spinler | cc3b64a | 2019-12-12 11:27:10 -0600 | [diff] [blame] | 560 |  | 
 | 561 |     // The were both sent. | 
| Matt Spinler | 56e0826 | 2020-01-27 16:14:23 -0600 | [diff] [blame] | 562 |     EXPECT_EQ(mockHostIface->numCmdsProcessed(), 2); | 
| Matt Spinler | cc3b64a | 2019-12-12 11:27:10 -0600 | [diff] [blame] | 563 |     EXPECT_EQ(notifier.queueSize(), 0); | 
 | 564 |  | 
 | 565 |     dataIface.changeHostState(false); | 
 | 566 |  | 
 | 567 |     // Those PELs weren't acked, so they will get sent again | 
 | 568 |     EXPECT_EQ(notifier.queueSize(), 2); | 
 | 569 |  | 
 | 570 |     // Power back on and send them again | 
 | 571 |     dataIface.changeHostState(true); | 
| Matt Spinler | e5f7508 | 2022-01-24 16:09:51 -0600 | [diff] [blame] | 572 |     runEvents(sdEvent, 3); | 
| Matt Spinler | cc3b64a | 2019-12-12 11:27:10 -0600 | [diff] [blame] | 573 |  | 
| Matt Spinler | 56e0826 | 2020-01-27 16:14:23 -0600 | [diff] [blame] | 574 |     EXPECT_EQ(mockHostIface->numCmdsProcessed(), 4); | 
| Matt Spinler | cc3b64a | 2019-12-12 11:27:10 -0600 | [diff] [blame] | 575 |     EXPECT_EQ(notifier.queueSize(), 0); | 
 | 576 |  | 
 | 577 |     // Ack them and verify the state in the PEL. | 
 | 578 |     notifier.ackPEL(id1); | 
 | 579 |     notifier.ackPEL(id2); | 
 | 580 |  | 
 | 581 |     Repository::LogID id{Repository::LogID::Pel{id1}}; | 
 | 582 |     auto data = repo.getPELData(id); | 
 | 583 |     PEL pelFromRepo1{*data}; | 
 | 584 |     EXPECT_EQ(pelFromRepo1.hostTransmissionState(), TransmissionState::acked); | 
 | 585 |  | 
 | 586 |     id.pelID.id = id2; | 
 | 587 |     data = repo.getPELData(id); | 
 | 588 |     PEL pelFromRepo2{*data}; | 
 | 589 |     EXPECT_EQ(pelFromRepo2.hostTransmissionState(), TransmissionState::acked); | 
 | 590 |  | 
 | 591 |     // Power back off, and they should't get re-added | 
 | 592 |     dataIface.changeHostState(false); | 
 | 593 |  | 
 | 594 |     EXPECT_EQ(notifier.queueSize(), 0); | 
 | 595 | } | 
| Matt Spinler | 41293cb | 2019-12-12 13:11:09 -0600 | [diff] [blame] | 596 |  | 
 | 597 | // Test the host full condition | 
 | 598 | TEST_F(HostNotifierTest, TestHostFull) | 
 | 599 | { | 
 | 600 |     // The full interaction with the host is: | 
 | 601 |     // BMC:  new PEL available | 
 | 602 |     // Host: ReadPELFile  (not modeled here) | 
 | 603 |     // Host: Ack(id) (if not full), or HostFull(id) | 
 | 604 |     // BMC: if full and any new PELs come in, don't sent them | 
 | 605 |     // Start a timer and try again | 
 | 606 |     // Host responds with either Ack or full | 
 | 607 |     // and repeat | 
 | 608 |  | 
| Matt Spinler | 41293cb | 2019-12-12 13:11:09 -0600 | [diff] [blame] | 609 |     sdeventplus::Event sdEvent{event}; | 
| Matt Spinler | 41293cb | 2019-12-12 13:11:09 -0600 | [diff] [blame] | 610 |     HostNotifier notifier{repo, dataIface, std::move(hostIface)}; | 
 | 611 |  | 
| Matt Spinler | 41293cb | 2019-12-12 13:11:09 -0600 | [diff] [blame] | 612 |     dataIface.changeHostState(true); | 
 | 613 |  | 
 | 614 |     // Add and dispatch/send one PEL | 
 | 615 |     auto pel = makePEL(); | 
 | 616 |     auto id = pel->id(); | 
 | 617 |     repo.add(pel); | 
 | 618 |     runEvents(sdEvent, 2); | 
 | 619 |  | 
| Matt Spinler | 56e0826 | 2020-01-27 16:14:23 -0600 | [diff] [blame] | 620 |     EXPECT_EQ(mockHostIface->numCmdsProcessed(), 1); | 
| Matt Spinler | 41293cb | 2019-12-12 13:11:09 -0600 | [diff] [blame] | 621 |     EXPECT_EQ(notifier.queueSize(), 0); | 
 | 622 |  | 
 | 623 |     // Host is full | 
 | 624 |     notifier.setHostFull(id); | 
 | 625 |  | 
 | 626 |     // It goes back on the queue | 
 | 627 |     EXPECT_EQ(notifier.queueSize(), 1); | 
 | 628 |  | 
 | 629 |     // The transmission state goes back to new | 
 | 630 |     Repository::LogID i{Repository::LogID::Pel{id}}; | 
 | 631 |     auto data = repo.getPELData(i); | 
 | 632 |     PEL pelFromRepo{*data}; | 
 | 633 |     EXPECT_EQ(pelFromRepo.hostTransmissionState(), TransmissionState::newPEL); | 
 | 634 |  | 
 | 635 |     // Clock it, nothing should be sent still. | 
 | 636 |     runEvents(sdEvent, 1); | 
 | 637 |  | 
| Matt Spinler | 56e0826 | 2020-01-27 16:14:23 -0600 | [diff] [blame] | 638 |     EXPECT_EQ(mockHostIface->numCmdsProcessed(), 1); | 
| Matt Spinler | 41293cb | 2019-12-12 13:11:09 -0600 | [diff] [blame] | 639 |     EXPECT_EQ(notifier.queueSize(), 1); | 
 | 640 |  | 
 | 641 |     // Add another PEL and clock it, still nothing sent | 
 | 642 |     pel = makePEL(); | 
 | 643 |     repo.add(pel); | 
 | 644 |     runEvents(sdEvent, 2); | 
| Matt Spinler | 56e0826 | 2020-01-27 16:14:23 -0600 | [diff] [blame] | 645 |     EXPECT_EQ(mockHostIface->numCmdsProcessed(), 1); | 
| Matt Spinler | 41293cb | 2019-12-12 13:11:09 -0600 | [diff] [blame] | 646 |     EXPECT_EQ(notifier.queueSize(), 2); | 
 | 647 |  | 
 | 648 |     // Let the host full timer expire to trigger a retry. | 
 | 649 |     // Add some extra event passes just to be sure nothing new is sent. | 
| Matt Spinler | 56e0826 | 2020-01-27 16:14:23 -0600 | [diff] [blame] | 650 |     runEvents(sdEvent, 5, mockHostIface->getHostFullRetryDelay()); | 
| Matt Spinler | 41293cb | 2019-12-12 13:11:09 -0600 | [diff] [blame] | 651 |  | 
 | 652 |     // The timer expiration will send just the 1, not both | 
| Matt Spinler | 56e0826 | 2020-01-27 16:14:23 -0600 | [diff] [blame] | 653 |     EXPECT_EQ(mockHostIface->numCmdsProcessed(), 2); | 
| Matt Spinler | 41293cb | 2019-12-12 13:11:09 -0600 | [diff] [blame] | 654 |     EXPECT_EQ(notifier.queueSize(), 1); | 
 | 655 |  | 
 | 656 |     // Host still full | 
 | 657 |     notifier.setHostFull(id); | 
 | 658 |  | 
 | 659 |     // Let the host full timer attempt again | 
| Matt Spinler | 56e0826 | 2020-01-27 16:14:23 -0600 | [diff] [blame] | 660 |     runEvents(sdEvent, 2, mockHostIface->getHostFullRetryDelay()); | 
 | 661 |     EXPECT_EQ(mockHostIface->numCmdsProcessed(), 3); | 
| Matt Spinler | 41293cb | 2019-12-12 13:11:09 -0600 | [diff] [blame] | 662 |  | 
 | 663 |     // Add yet another PEL with the retry timer expired. | 
 | 664 |     // It shouldn't get sent out. | 
 | 665 |     pel = makePEL(); | 
 | 666 |     repo.add(pel); | 
 | 667 |     runEvents(sdEvent, 2); | 
| Matt Spinler | 56e0826 | 2020-01-27 16:14:23 -0600 | [diff] [blame] | 668 |     EXPECT_EQ(mockHostIface->numCmdsProcessed(), 3); | 
| Matt Spinler | 41293cb | 2019-12-12 13:11:09 -0600 | [diff] [blame] | 669 |  | 
 | 670 |     // The last 2 PELs still on the queue | 
 | 671 |     EXPECT_EQ(notifier.queueSize(), 2); | 
 | 672 |  | 
 | 673 |     // Host no longer full, it finally acks the first PEL | 
 | 674 |     notifier.ackPEL(id); | 
 | 675 |  | 
 | 676 |     // Now the remaining 2 PELs will be dispatched | 
 | 677 |     runEvents(sdEvent, 3); | 
 | 678 |  | 
| Matt Spinler | 56e0826 | 2020-01-27 16:14:23 -0600 | [diff] [blame] | 679 |     EXPECT_EQ(mockHostIface->numCmdsProcessed(), 5); | 
| Matt Spinler | 41293cb | 2019-12-12 13:11:09 -0600 | [diff] [blame] | 680 |     EXPECT_EQ(notifier.queueSize(), 0); | 
 | 681 | } | 
| Matt Spinler | a19b623 | 2019-12-12 13:30:14 -0600 | [diff] [blame] | 682 |  | 
 | 683 | // Test when the host says it was send a malformed PEL | 
 | 684 | TEST_F(HostNotifierTest, TestBadPEL) | 
 | 685 | { | 
| Matt Spinler | a19b623 | 2019-12-12 13:30:14 -0600 | [diff] [blame] | 686 |     sdeventplus::Event sdEvent{event}; | 
 | 687 |  | 
 | 688 |     { | 
| Matt Spinler | 56e0826 | 2020-01-27 16:14:23 -0600 | [diff] [blame] | 689 |         Repository repo1{repoPath}; | 
 | 690 |         HostNotifier notifier{repo1, dataIface, std::move(hostIface)}; | 
| Matt Spinler | a19b623 | 2019-12-12 13:30:14 -0600 | [diff] [blame] | 691 |  | 
 | 692 |         dataIface.changeHostState(true); | 
 | 693 |  | 
 | 694 |         // Add a PEL and dispatch and send it | 
 | 695 |         auto pel = makePEL(); | 
 | 696 |         auto id = pel->id(); | 
| Matt Spinler | 56e0826 | 2020-01-27 16:14:23 -0600 | [diff] [blame] | 697 |         repo1.add(pel); | 
| Matt Spinler | a19b623 | 2019-12-12 13:30:14 -0600 | [diff] [blame] | 698 |  | 
 | 699 |         runEvents(sdEvent, 2); | 
| Matt Spinler | 56e0826 | 2020-01-27 16:14:23 -0600 | [diff] [blame] | 700 |         EXPECT_EQ(mockHostIface->numCmdsProcessed(), 1); | 
| Matt Spinler | a19b623 | 2019-12-12 13:30:14 -0600 | [diff] [blame] | 701 |         EXPECT_EQ(notifier.queueSize(), 0); | 
 | 702 |  | 
 | 703 |         // The host rejected it. | 
 | 704 |         notifier.setBadPEL(id); | 
 | 705 |  | 
 | 706 |         // Doesn't go back on the queue | 
 | 707 |         EXPECT_EQ(notifier.queueSize(), 0); | 
 | 708 |  | 
 | 709 |         // Check the state was saved in the PEL itself | 
 | 710 |         Repository::LogID i{Repository::LogID::Pel{id}}; | 
| Matt Spinler | 56e0826 | 2020-01-27 16:14:23 -0600 | [diff] [blame] | 711 |         auto data = repo1.getPELData(i); | 
| Matt Spinler | a19b623 | 2019-12-12 13:30:14 -0600 | [diff] [blame] | 712 |         PEL pelFromRepo{*data}; | 
 | 713 |         EXPECT_EQ(pelFromRepo.hostTransmissionState(), | 
 | 714 |                   TransmissionState::badPEL); | 
 | 715 |  | 
 | 716 |         dataIface.changeHostState(false); | 
 | 717 |  | 
 | 718 |         // Ensure it doesn't go back on the queue on a power cycle | 
 | 719 |         EXPECT_EQ(notifier.queueSize(), 0); | 
 | 720 |     } | 
 | 721 |  | 
 | 722 |     // Now restore the repo, and make sure it doesn't come back | 
 | 723 |     { | 
| Matt Spinler | 56e0826 | 2020-01-27 16:14:23 -0600 | [diff] [blame] | 724 |         Repository repo1{repoPath}; | 
| Matt Spinler | a19b623 | 2019-12-12 13:30:14 -0600 | [diff] [blame] | 725 |  | 
| Matt Spinler | 56e0826 | 2020-01-27 16:14:23 -0600 | [diff] [blame] | 726 |         std::unique_ptr<HostInterface> hostIface1 = | 
| Matt Spinler | a19b623 | 2019-12-12 13:30:14 -0600 | [diff] [blame] | 727 |             std::make_unique<MockHostInterface>(event, dataIface); | 
 | 728 |  | 
| Matt Spinler | 56e0826 | 2020-01-27 16:14:23 -0600 | [diff] [blame] | 729 |         HostNotifier notifier{repo1, dataIface, std::move(hostIface1)}; | 
| Matt Spinler | a19b623 | 2019-12-12 13:30:14 -0600 | [diff] [blame] | 730 |  | 
 | 731 |         EXPECT_EQ(notifier.queueSize(), 0); | 
 | 732 |     } | 
 | 733 | } | 
| Matt Spinler | 24a8558 | 2020-01-27 16:40:21 -0600 | [diff] [blame] | 734 |  | 
 | 735 | // Test that sending PELs can be disabled | 
 | 736 | TEST_F(HostNotifierTest, TestDisable) | 
 | 737 | { | 
 | 738 |     // Turn off sending the PELs except for once in the middle | 
 | 739 |     EXPECT_CALL(dataIface, getHostPELEnablement()) | 
 | 740 |         .WillOnce(Return(false)) | 
 | 741 |         .WillOnce(Return(false)) | 
 | 742 |         .WillOnce(Return(true)) | 
 | 743 |         .WillOnce(Return(false)) | 
 | 744 |         .WillOnce(Return(false)) | 
 | 745 |         .WillOnce(Return(false)); | 
 | 746 |  | 
 | 747 |     { | 
 | 748 |         HostNotifier notifier{repo, dataIface, std::move(hostIface)}; | 
 | 749 |  | 
 | 750 |         // Add a PEL with the host off | 
 | 751 |         auto pel = makePEL(); | 
 | 752 |         repo.add(pel); | 
 | 753 |  | 
 | 754 |         // Not added to the send queue | 
 | 755 |         EXPECT_EQ(notifier.queueSize(), 0); | 
 | 756 |  | 
 | 757 |         dataIface.changeHostState(true); | 
 | 758 |  | 
 | 759 |         // Try again with the host on | 
 | 760 |         pel = makePEL(); | 
 | 761 |         repo.add(pel); | 
 | 762 |  | 
 | 763 |         EXPECT_EQ(notifier.queueSize(), 0); | 
 | 764 |  | 
 | 765 |         // Now getHostPELEnablement() will return true for the new PEL | 
 | 766 |         pel = makePEL(); | 
 | 767 |         repo.add(pel); | 
 | 768 |  | 
 | 769 |         EXPECT_EQ(notifier.queueSize(), 1); | 
 | 770 |     } | 
 | 771 |  | 
 | 772 |     // getHostPELEnablement is back to returning false. | 
 | 773 |     // Create a new second instance and make sure the 3 existing PELs | 
 | 774 |     // aren't put on the queue on startup | 
 | 775 |     { | 
 | 776 |         Repository repo1{repoPath}; | 
 | 777 |         std::unique_ptr<HostInterface> hostIface1 = | 
 | 778 |             std::make_unique<MockHostInterface>(event, dataIface); | 
 | 779 |  | 
 | 780 |         HostNotifier notifier{repo1, dataIface, std::move(hostIface1)}; | 
 | 781 |  | 
 | 782 |         EXPECT_EQ(notifier.queueSize(), 0); | 
 | 783 |     } | 
 | 784 | } |