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; 32 using ::testing::NiceMock; 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 { 42 public: 43 HostNotifierTest() : repo(repoPath) 44 { 45 auto r = sd_event_default(&event); 46 EXPECT_TRUE(r >= 0); 47 48 ON_CALL(dataIface, getHostPELEnablement).WillByDefault(Return(true)); 49 50 hostIface = std::make_unique<NiceMock<MockHostInterface>>(event, 51 dataIface); 52 53 mockHostIface = reinterpret_cast<MockHostInterface*>(hostIface.get()); 54 55 auto send = [this](uint32_t /*id*/, uint32_t /*size*/) { 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)); 62 } 63 64 ~HostNotifierTest() 65 { 66 sd_event_unref(event); 67 } 68 69 protected: 70 sd_event* event; 71 Repository repo; 72 NiceMock<MockDataInterface> dataIface; 73 std::unique_ptr<HostInterface> hostIface; 74 MockHostInterface* mockHostIface; 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 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 119 // Test that host state change callbacks work 120 TEST_F(HostNotifierTest, TestHostStateChange) 121 { 122 bool hostState = false; 123 bool called = false; 124 DataInterfaceBase::HostStateChangeFunc func = [&hostState, 125 &called](bool state) { 126 hostState = state; 127 called = true; 128 }; 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 156 // Test dealing with how acked PELs are put on the 157 // notification queue. 158 TEST_F(HostNotifierTest, TestPolicyAckedPEL) 159 { 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())); 167 EXPECT_TRUE(notifier.notifyRequired(pel->id())); 168 169 // Not in the repo 170 EXPECT_FALSE(notifier.enqueueRequired(42)); 171 EXPECT_FALSE(notifier.notifyRequired(42)); 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())); 178 EXPECT_FALSE(notifier.notifyRequired(pel->id())); 179 } 180 181 // Test the 'don't report' PEL flag 182 TEST_F(HostNotifierTest, TestPolicyDontReport) 183 { 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 { 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())); 216 217 // Still need to send it 218 EXPECT_TRUE(notifier.notifyRequired(pel->id())); 219 } 220 221 // Don't need to enqueue a hidden log already acked by the HMC 222 TEST_F(HostNotifierTest, TestPolicyHiddenWithHMCAcked) 223 { 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 244 // Test that changing the HMC manage status affects 245 // the policy with hidden log notification. 246 TEST_F(HostNotifierTest, TestPolicyHiddenWithHMCManaged) 247 { 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 264 // Test that PELs are enqueued on startup 265 TEST_F(HostNotifierTest, TestStartup) 266 { 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 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 } 287 288 // Test the simple path were PELs get sent to the host 289 TEST_F(HostNotifierTest, TestSendCmd) 290 { 291 sdeventplus::Event sdEvent{event}; 292 293 HostNotifier notifier{repo, dataIface, std::move(hostIface)}; 294 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 303 runEvents(sdEvent, 2); 304 305 // It was sent up 306 EXPECT_EQ(mockHostIface->numCmdsProcessed(), 1); 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); 322 EXPECT_EQ(mockHostIface->numCmdsProcessed(), 1); 323 EXPECT_EQ(notifier.queueSize(), 0); 324 325 // Send the command 326 runEvents(sdEvent, 1); 327 328 EXPECT_EQ(mockHostIface->numCmdsProcessed(), 2); 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 337 EXPECT_EQ(mockHostIface->numCmdsProcessed(), 3); 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 { 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 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 358 runEvents(sdEvent, 3); 359 360 EXPECT_EQ(mockHostIface->numCmdsProcessed(), 2); 361 EXPECT_EQ(notifier.queueSize(), 0); 362 } 363 364 // Test that a single failure will cause a retry 365 TEST_F(HostNotifierTest, TestHostRetry) 366 { 367 sdeventplus::Event sdEvent{event}; 368 369 HostNotifier notifier{repo, dataIface, std::move(hostIface)}; 370 371 auto sendFailure = [this](uint32_t /*id*/, uint32_t /*size*/) { 372 return this->mockHostIface->send(1); 373 }; 374 auto sendSuccess = [this](uint32_t /*id*/, uint32_t /*size*/) { 375 return this->mockHostIface->send(0); 376 }; 377 378 EXPECT_CALL(*mockHostIface, sendNewLogCmd(_, _)) 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 392 EXPECT_EQ(mockHostIface->numCmdsProcessed(), 1); 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. 397 runEvents(sdEvent, 2, mockHostIface->getReceiveRetryDelay()); 398 399 EXPECT_EQ(mockHostIface->numCmdsProcessed(), 2); 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 409 EXPECT_EQ(mockHostIface->numCmdsProcessed(), 3); 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 { 416 sdeventplus::Event sdEvent{event}; 417 418 HostNotifier notifier{repo, dataIface, std::move(hostIface)}; 419 420 // Every call will fail 421 auto sendFailure = [this](uint32_t /*id*/, uint32_t /*size*/) { 422 return this->mockHostIface->send(1); 423 }; 424 425 EXPECT_CALL(*mockHostIface, sendNewLogCmd(_, _)) 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 434 runEvents(sdEvent, 40, mockHostIface->getReceiveRetryDelay()); 435 436 // Should have stopped after the 15 Tries 437 EXPECT_EQ(mockHostIface->numCmdsProcessed(), 15); 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 445 runEvents(sdEvent, 40, mockHostIface->getReceiveRetryDelay()); 446 447 // Tried an additional 15 times 448 EXPECT_EQ(mockHostIface->numCmdsProcessed(), 30); 449 EXPECT_EQ(notifier.queueSize(), 2); 450 } 451 452 // Cancel an in progress command 453 TEST_F(HostNotifierTest, TestCancelCmd) 454 { 455 sdeventplus::Event sdEvent{event}; 456 HostNotifier notifier{repo, dataIface, std::move(hostIface)}; 457 458 dataIface.changeHostState(true); 459 460 // Add and send one PEL, but don't enter the event loop 461 // so the receive function can't run. 462 auto pel = makePEL(); 463 repo.add(pel); 464 465 // Not dispatched yet 466 EXPECT_EQ(notifier.queueSize(), 1); 467 468 // Dispatch it 469 runEvents(sdEvent, 2); 470 471 // It was sent and off the queue 472 EXPECT_EQ(notifier.queueSize(), 0); 473 474 // This will cancel the receive 475 dataIface.changeHostState(false); 476 477 // Back on the queue 478 EXPECT_EQ(notifier.queueSize(), 1); 479 480 // Turn the host back on and make sure 481 // commands will work again 482 dataIface.changeHostState(true); 483 484 runEvents(sdEvent, 1); 485 486 EXPECT_EQ(mockHostIface->numCmdsProcessed(), 1); 487 EXPECT_EQ(notifier.queueSize(), 0); 488 } 489 490 // Test that acking a PEL persist across power cycles 491 TEST_F(HostNotifierTest, TestPowerCycleAndAcks) 492 { 493 sdeventplus::Event sdEvent{event}; 494 495 HostNotifier notifier{repo, dataIface, std::move(hostIface)}; 496 497 // Add 2 PELs with host off 498 auto pel = makePEL(); 499 repo.add(pel); 500 auto id1 = pel->id(); 501 502 pel = makePEL(); 503 repo.add(pel); 504 auto id2 = pel->id(); 505 506 dataIface.changeHostState(true); 507 508 runEvents(sdEvent, 3); 509 510 // The were both sent. 511 EXPECT_EQ(mockHostIface->numCmdsProcessed(), 2); 512 EXPECT_EQ(notifier.queueSize(), 0); 513 514 dataIface.changeHostState(false); 515 516 // Those PELs weren't acked, so they will get sent again 517 EXPECT_EQ(notifier.queueSize(), 2); 518 519 // Power back on and send them again 520 dataIface.changeHostState(true); 521 runEvents(sdEvent, 3); 522 523 EXPECT_EQ(mockHostIface->numCmdsProcessed(), 4); 524 EXPECT_EQ(notifier.queueSize(), 0); 525 526 // Ack them and verify the state in the PEL. 527 notifier.ackPEL(id1); 528 notifier.ackPEL(id2); 529 530 Repository::LogID id{Repository::LogID::Pel{id1}}; 531 auto data = repo.getPELData(id); 532 PEL pelFromRepo1{*data}; 533 EXPECT_EQ(pelFromRepo1.hostTransmissionState(), TransmissionState::acked); 534 535 id.pelID.id = id2; 536 data = repo.getPELData(id); 537 PEL pelFromRepo2{*data}; 538 EXPECT_EQ(pelFromRepo2.hostTransmissionState(), TransmissionState::acked); 539 540 // Power back off, and they should't get re-added 541 dataIface.changeHostState(false); 542 543 EXPECT_EQ(notifier.queueSize(), 0); 544 } 545 546 // Test the host full condition 547 TEST_F(HostNotifierTest, TestHostFull) 548 { 549 // The full interaction with the host is: 550 // BMC: new PEL available 551 // Host: ReadPELFile (not modeled here) 552 // Host: Ack(id) (if not full), or HostFull(id) 553 // BMC: if full and any new PELs come in, don't sent them 554 // Start a timer and try again 555 // Host responds with either Ack or full 556 // and repeat 557 558 sdeventplus::Event sdEvent{event}; 559 HostNotifier notifier{repo, dataIface, std::move(hostIface)}; 560 561 dataIface.changeHostState(true); 562 563 // Add and dispatch/send one PEL 564 auto pel = makePEL(); 565 auto id = pel->id(); 566 repo.add(pel); 567 runEvents(sdEvent, 2); 568 569 EXPECT_EQ(mockHostIface->numCmdsProcessed(), 1); 570 EXPECT_EQ(notifier.queueSize(), 0); 571 572 // Host is full 573 notifier.setHostFull(id); 574 575 // It goes back on the queue 576 EXPECT_EQ(notifier.queueSize(), 1); 577 578 // The transmission state goes back to new 579 Repository::LogID i{Repository::LogID::Pel{id}}; 580 auto data = repo.getPELData(i); 581 PEL pelFromRepo{*data}; 582 EXPECT_EQ(pelFromRepo.hostTransmissionState(), TransmissionState::newPEL); 583 584 // Clock it, nothing should be sent still. 585 runEvents(sdEvent, 1); 586 587 EXPECT_EQ(mockHostIface->numCmdsProcessed(), 1); 588 EXPECT_EQ(notifier.queueSize(), 1); 589 590 // Add another PEL and clock it, still nothing sent 591 pel = makePEL(); 592 repo.add(pel); 593 runEvents(sdEvent, 2); 594 EXPECT_EQ(mockHostIface->numCmdsProcessed(), 1); 595 EXPECT_EQ(notifier.queueSize(), 2); 596 597 // Let the host full timer expire to trigger a retry. 598 // Add some extra event passes just to be sure nothing new is sent. 599 runEvents(sdEvent, 5, mockHostIface->getHostFullRetryDelay()); 600 601 // The timer expiration will send just the 1, not both 602 EXPECT_EQ(mockHostIface->numCmdsProcessed(), 2); 603 EXPECT_EQ(notifier.queueSize(), 1); 604 605 // Host still full 606 notifier.setHostFull(id); 607 608 // Let the host full timer attempt again 609 runEvents(sdEvent, 2, mockHostIface->getHostFullRetryDelay()); 610 EXPECT_EQ(mockHostIface->numCmdsProcessed(), 3); 611 612 // Add yet another PEL with the retry timer expired. 613 // It shouldn't get sent out. 614 pel = makePEL(); 615 repo.add(pel); 616 runEvents(sdEvent, 2); 617 EXPECT_EQ(mockHostIface->numCmdsProcessed(), 3); 618 619 // The last 2 PELs still on the queue 620 EXPECT_EQ(notifier.queueSize(), 2); 621 622 // Host no longer full, it finally acks the first PEL 623 notifier.ackPEL(id); 624 625 // Now the remaining 2 PELs will be dispatched 626 runEvents(sdEvent, 3); 627 628 EXPECT_EQ(mockHostIface->numCmdsProcessed(), 5); 629 EXPECT_EQ(notifier.queueSize(), 0); 630 } 631 632 // Test when the host says it was send a malformed PEL 633 TEST_F(HostNotifierTest, TestBadPEL) 634 { 635 sdeventplus::Event sdEvent{event}; 636 637 { 638 Repository repo1{repoPath}; 639 HostNotifier notifier{repo1, dataIface, std::move(hostIface)}; 640 641 dataIface.changeHostState(true); 642 643 // Add a PEL and dispatch and send it 644 auto pel = makePEL(); 645 auto id = pel->id(); 646 repo1.add(pel); 647 648 runEvents(sdEvent, 2); 649 EXPECT_EQ(mockHostIface->numCmdsProcessed(), 1); 650 EXPECT_EQ(notifier.queueSize(), 0); 651 652 // The host rejected it. 653 notifier.setBadPEL(id); 654 655 // Doesn't go back on the queue 656 EXPECT_EQ(notifier.queueSize(), 0); 657 658 // Check the state was saved in the PEL itself 659 Repository::LogID i{Repository::LogID::Pel{id}}; 660 auto data = repo1.getPELData(i); 661 PEL pelFromRepo{*data}; 662 EXPECT_EQ(pelFromRepo.hostTransmissionState(), 663 TransmissionState::badPEL); 664 665 dataIface.changeHostState(false); 666 667 // Ensure it doesn't go back on the queue on a power cycle 668 EXPECT_EQ(notifier.queueSize(), 0); 669 } 670 671 // Now restore the repo, and make sure it doesn't come back 672 { 673 Repository repo1{repoPath}; 674 675 std::unique_ptr<HostInterface> hostIface1 = 676 std::make_unique<MockHostInterface>(event, dataIface); 677 678 HostNotifier notifier{repo1, dataIface, std::move(hostIface1)}; 679 680 EXPECT_EQ(notifier.queueSize(), 0); 681 } 682 } 683 684 // Test that sending PELs can be disabled 685 TEST_F(HostNotifierTest, TestDisable) 686 { 687 // Turn off sending the PELs except for once in the middle 688 EXPECT_CALL(dataIface, getHostPELEnablement()) 689 .WillOnce(Return(false)) 690 .WillOnce(Return(false)) 691 .WillOnce(Return(true)) 692 .WillOnce(Return(false)) 693 .WillOnce(Return(false)) 694 .WillOnce(Return(false)); 695 696 { 697 HostNotifier notifier{repo, dataIface, std::move(hostIface)}; 698 699 // Add a PEL with the host off 700 auto pel = makePEL(); 701 repo.add(pel); 702 703 // Not added to the send queue 704 EXPECT_EQ(notifier.queueSize(), 0); 705 706 dataIface.changeHostState(true); 707 708 // Try again with the host on 709 pel = makePEL(); 710 repo.add(pel); 711 712 EXPECT_EQ(notifier.queueSize(), 0); 713 714 // Now getHostPELEnablement() will return true for the new PEL 715 pel = makePEL(); 716 repo.add(pel); 717 718 EXPECT_EQ(notifier.queueSize(), 1); 719 } 720 721 // getHostPELEnablement is back to returning false. 722 // Create a new second instance and make sure the 3 existing PELs 723 // aren't put on the queue on startup 724 { 725 Repository repo1{repoPath}; 726 std::unique_ptr<HostInterface> hostIface1 = 727 std::make_unique<MockHostInterface>(event, dataIface); 728 729 HostNotifier notifier{repo1, dataIface, std::move(hostIface1)}; 730 731 EXPECT_EQ(notifier.queueSize(), 0); 732 } 733 } 734