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 =
51             std::make_unique<NiceMock<MockHostInterface>>(event, 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