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