1f60ac27eSMatt Spinler /**
2f60ac27eSMatt Spinler * Copyright © 2019 IBM Corporation
3f60ac27eSMatt Spinler *
4f60ac27eSMatt Spinler * Licensed under the Apache License, Version 2.0 (the "License");
5f60ac27eSMatt Spinler * you may not use this file except in compliance with the License.
6f60ac27eSMatt Spinler * You may obtain a copy of the License at
7f60ac27eSMatt Spinler *
8f60ac27eSMatt Spinler * http://www.apache.org/licenses/LICENSE-2.0
9f60ac27eSMatt Spinler *
10f60ac27eSMatt Spinler * Unless required by applicable law or agreed to in writing, software
11f60ac27eSMatt Spinler * distributed under the License is distributed on an "AS IS" BASIS,
12f60ac27eSMatt Spinler * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f60ac27eSMatt Spinler * See the License for the specific language governing permissions and
14f60ac27eSMatt Spinler * limitations under the License.
15f60ac27eSMatt Spinler */
16f60ac27eSMatt Spinler #include "extensions/openpower-pels/data_interface.hpp"
17f60ac27eSMatt Spinler #include "extensions/openpower-pels/host_notifier.hpp"
18f60ac27eSMatt Spinler #include "mocks.hpp"
19f60ac27eSMatt Spinler #include "pel_utils.hpp"
20f60ac27eSMatt Spinler
21f60ac27eSMatt Spinler #include <fcntl.h>
22f60ac27eSMatt Spinler #include <sys/stat.h>
23f60ac27eSMatt Spinler #include <sys/types.h>
24f60ac27eSMatt Spinler
25f60ac27eSMatt Spinler #include <chrono>
26f60ac27eSMatt Spinler
27f60ac27eSMatt Spinler #include <gtest/gtest.h>
28f60ac27eSMatt Spinler
29f60ac27eSMatt Spinler using namespace openpower::pels;
30f60ac27eSMatt Spinler using ::testing::_;
31f60ac27eSMatt Spinler using ::testing::Invoke;
3256e08263SMatt Spinler using ::testing::NiceMock;
33f60ac27eSMatt Spinler using ::testing::Return;
34f60ac27eSMatt Spinler namespace fs = std::filesystem;
35f60ac27eSMatt Spinler using namespace std::chrono;
36f60ac27eSMatt Spinler
37f60ac27eSMatt Spinler const size_t actionFlags0Offset = 66;
38f60ac27eSMatt Spinler const size_t actionFlags1Offset = 67;
39f60ac27eSMatt Spinler
40f60ac27eSMatt Spinler class HostNotifierTest : public CleanPELFiles
41f60ac27eSMatt Spinler {
42a943b15bSMatt Spinler public:
HostNotifierTest()4356e08263SMatt Spinler HostNotifierTest() : repo(repoPath)
44a943b15bSMatt Spinler {
45a943b15bSMatt Spinler auto r = sd_event_default(&event);
46a943b15bSMatt Spinler EXPECT_TRUE(r >= 0);
4756e08263SMatt Spinler
4824a8558bSMatt Spinler ON_CALL(dataIface, getHostPELEnablement).WillByDefault(Return(true));
4924a8558bSMatt Spinler
50*075c7923SPatrick Williams hostIface =
51*075c7923SPatrick Williams std::make_unique<NiceMock<MockHostInterface>>(event, dataIface);
5256e08263SMatt Spinler
5356e08263SMatt Spinler mockHostIface = reinterpret_cast<MockHostInterface*>(hostIface.get());
5456e08263SMatt Spinler
55d26fa3e7SPatrick Williams auto send = [this](uint32_t /*id*/, uint32_t /*size*/) {
5656e08263SMatt Spinler return this->mockHostIface->send(0);
5756e08263SMatt Spinler };
5856e08263SMatt Spinler
5956e08263SMatt Spinler // Unless otherwise specified, sendNewLogCmd should always pass.
6056e08263SMatt Spinler ON_CALL(*mockHostIface, sendNewLogCmd(_, _))
6156e08263SMatt Spinler .WillByDefault(Invoke(send));
62a943b15bSMatt Spinler }
63a943b15bSMatt Spinler
~HostNotifierTest()64a943b15bSMatt Spinler ~HostNotifierTest()
65a943b15bSMatt Spinler {
66a943b15bSMatt Spinler sd_event_unref(event);
67a943b15bSMatt Spinler }
68a943b15bSMatt Spinler
69a943b15bSMatt Spinler protected:
70a943b15bSMatt Spinler sd_event* event;
7156e08263SMatt Spinler Repository repo;
7256e08263SMatt Spinler NiceMock<MockDataInterface> dataIface;
7356e08263SMatt Spinler std::unique_ptr<HostInterface> hostIface;
7456e08263SMatt Spinler MockHostInterface* mockHostIface;
75f60ac27eSMatt Spinler };
76f60ac27eSMatt Spinler
77f60ac27eSMatt Spinler /**
78f60ac27eSMatt Spinler * @brief Create PEL with the specified action flags
79f60ac27eSMatt Spinler *
80f60ac27eSMatt Spinler * @param[in] actionFlagsMask - Optional action flags to use
81f60ac27eSMatt Spinler *
82f60ac27eSMatt Spinler * @return std::unique_ptr<PEL>
83f60ac27eSMatt Spinler */
makePEL(uint16_t actionFlagsMask=0)84f60ac27eSMatt Spinler std::unique_ptr<PEL> makePEL(uint16_t actionFlagsMask = 0)
85f60ac27eSMatt Spinler {
86f60ac27eSMatt Spinler static uint32_t obmcID = 1;
87f60ac27eSMatt Spinler auto data = pelDataFactory(TestPELType::pelSimple);
88f60ac27eSMatt Spinler
89f60ac27eSMatt Spinler data[actionFlags0Offset] |= actionFlagsMask >> 8;
90f60ac27eSMatt Spinler data[actionFlags1Offset] |= actionFlagsMask & 0xFF;
91f60ac27eSMatt Spinler
92f60ac27eSMatt Spinler auto pel = std::make_unique<PEL>(data, obmcID++);
93f60ac27eSMatt Spinler pel->assignID();
94f60ac27eSMatt Spinler pel->setCommitTime();
95f60ac27eSMatt Spinler return pel;
96f60ac27eSMatt Spinler }
97f60ac27eSMatt Spinler
987d800a4eSMatt Spinler /**
997d800a4eSMatt Spinler * @brief Run an iteration of the event loop.
1007d800a4eSMatt Spinler *
1017d800a4eSMatt Spinler * An event loop is used for:
1027d800a4eSMatt Spinler * 1) timer expiration callbacks
1037d800a4eSMatt Spinler * 2) Dispatches
1047d800a4eSMatt Spinler * 3) host interface receive callbacks
1057d800a4eSMatt Spinler *
1067d800a4eSMatt Spinler * @param[in] event - The event object
1077d800a4eSMatt Spinler * @param[in] numEvents - number of times to call Event::run()
1087d800a4eSMatt Spinler * @param[in] timeout - timeout value for run()
1097d800a4eSMatt Spinler */
runEvents(sdeventplus::Event & event,size_t numEvents,milliseconds timeout=milliseconds (1))1107d800a4eSMatt Spinler void runEvents(sdeventplus::Event& event, size_t numEvents,
1117d800a4eSMatt Spinler milliseconds timeout = milliseconds(1))
1127d800a4eSMatt Spinler {
1137d800a4eSMatt Spinler for (size_t i = 0; i < numEvents; i++)
1147d800a4eSMatt Spinler {
1157d800a4eSMatt Spinler event.run(timeout);
1167d800a4eSMatt Spinler }
1177d800a4eSMatt Spinler }
1187d800a4eSMatt Spinler
119f60ac27eSMatt Spinler // Test that host state change callbacks work
TEST_F(HostNotifierTest,TestHostStateChange)120f60ac27eSMatt Spinler TEST_F(HostNotifierTest, TestHostStateChange)
121f60ac27eSMatt Spinler {
122f60ac27eSMatt Spinler bool hostState = false;
123f60ac27eSMatt Spinler bool called = false;
124*075c7923SPatrick Williams DataInterfaceBase::HostStateChangeFunc func =
125*075c7923SPatrick Williams [&hostState, &called](bool state) {
126f60ac27eSMatt Spinler hostState = state;
127f60ac27eSMatt Spinler called = true;
128f60ac27eSMatt Spinler };
129f60ac27eSMatt Spinler
130f60ac27eSMatt Spinler dataIface.subscribeToHostStateChange("test", func);
131f60ac27eSMatt Spinler
132f60ac27eSMatt Spinler // callback called
133f60ac27eSMatt Spinler dataIface.changeHostState(true);
134f60ac27eSMatt Spinler EXPECT_TRUE(called);
135f60ac27eSMatt Spinler EXPECT_TRUE(hostState);
136f60ac27eSMatt Spinler
137f60ac27eSMatt Spinler // No change, not called
138f60ac27eSMatt Spinler called = false;
139f60ac27eSMatt Spinler dataIface.changeHostState(true);
140f60ac27eSMatt Spinler EXPECT_FALSE(called);
141f60ac27eSMatt Spinler
142f60ac27eSMatt Spinler // Called again
143f60ac27eSMatt Spinler dataIface.changeHostState(false);
144f60ac27eSMatt Spinler EXPECT_FALSE(hostState);
145f60ac27eSMatt Spinler EXPECT_TRUE(called);
146f60ac27eSMatt Spinler
147f60ac27eSMatt Spinler // Shouldn't get called after an unsubscribe
148f60ac27eSMatt Spinler dataIface.unsubscribeFromHostStateChange("test");
149f60ac27eSMatt Spinler
150f60ac27eSMatt Spinler called = false;
151f60ac27eSMatt Spinler
152f60ac27eSMatt Spinler dataIface.changeHostState(true);
153f60ac27eSMatt Spinler EXPECT_FALSE(called);
154f60ac27eSMatt Spinler }
155f60ac27eSMatt Spinler
156a943b15bSMatt Spinler // Test dealing with how acked PELs are put on the
157a943b15bSMatt Spinler // notification queue.
TEST_F(HostNotifierTest,TestPolicyAckedPEL)158a943b15bSMatt Spinler TEST_F(HostNotifierTest, TestPolicyAckedPEL)
159a943b15bSMatt Spinler {
160a943b15bSMatt Spinler HostNotifier notifier{repo, dataIface, std::move(hostIface)};
161a943b15bSMatt Spinler
162a943b15bSMatt Spinler auto pel = makePEL();
163a943b15bSMatt Spinler repo.add(pel);
164a943b15bSMatt Spinler
165a943b15bSMatt Spinler // This is required
166a943b15bSMatt Spinler EXPECT_TRUE(notifier.enqueueRequired(pel->id()));
167f77debb9SMatt Spinler EXPECT_TRUE(notifier.notifyRequired(pel->id()));
168a943b15bSMatt Spinler
169a943b15bSMatt Spinler // Not in the repo
170a943b15bSMatt Spinler EXPECT_FALSE(notifier.enqueueRequired(42));
171f77debb9SMatt Spinler EXPECT_FALSE(notifier.notifyRequired(42));
172a943b15bSMatt Spinler
173a943b15bSMatt Spinler // Now set this PEL to host acked
174a943b15bSMatt Spinler repo.setPELHostTransState(pel->id(), TransmissionState::acked);
175a943b15bSMatt Spinler
176a943b15bSMatt Spinler // Since it's acked, doesn't need to be enqueued or transmitted
177a943b15bSMatt Spinler EXPECT_FALSE(notifier.enqueueRequired(pel->id()));
178f77debb9SMatt Spinler EXPECT_FALSE(notifier.notifyRequired(pel->id()));
179a943b15bSMatt Spinler }
180a943b15bSMatt Spinler
181a943b15bSMatt Spinler // Test the 'don't report' PEL flag
TEST_F(HostNotifierTest,TestPolicyDontReport)182a943b15bSMatt Spinler TEST_F(HostNotifierTest, TestPolicyDontReport)
183a943b15bSMatt Spinler {
184a943b15bSMatt Spinler HostNotifier notifier{repo, dataIface, std::move(hostIface)};
185a943b15bSMatt Spinler
186a943b15bSMatt Spinler // dontReportToHostFlagBit
187a943b15bSMatt Spinler auto pel = makePEL(0x1000);
188a943b15bSMatt Spinler
189a943b15bSMatt Spinler // Double check the action flag is still set
190a943b15bSMatt Spinler std::bitset<16> actionFlags = pel->userHeader().actionFlags();
191a943b15bSMatt Spinler EXPECT_TRUE(actionFlags.test(dontReportToHostFlagBit));
192a943b15bSMatt Spinler
193a943b15bSMatt Spinler repo.add(pel);
194a943b15bSMatt Spinler
195a943b15bSMatt Spinler // Don't need to send this to the host
196a943b15bSMatt Spinler EXPECT_FALSE(notifier.enqueueRequired(pel->id()));
197a943b15bSMatt Spinler }
198a943b15bSMatt Spinler
199a943b15bSMatt Spinler // Test that hidden PELs need notification when there
200a943b15bSMatt Spinler // is no HMC.
TEST_F(HostNotifierTest,TestPolicyHiddenNoHMC)201a943b15bSMatt Spinler TEST_F(HostNotifierTest, TestPolicyHiddenNoHMC)
202a943b15bSMatt Spinler {
203a943b15bSMatt Spinler HostNotifier notifier{repo, dataIface, std::move(hostIface)};
204a943b15bSMatt Spinler
205a943b15bSMatt Spinler // hiddenFlagBit
206a943b15bSMatt Spinler auto pel = makePEL(0x4000);
207a943b15bSMatt Spinler
208a943b15bSMatt Spinler // Double check the action flag is still set
209a943b15bSMatt Spinler std::bitset<16> actionFlags = pel->userHeader().actionFlags();
210a943b15bSMatt Spinler EXPECT_TRUE(actionFlags.test(hiddenFlagBit));
211a943b15bSMatt Spinler
212a943b15bSMatt Spinler repo.add(pel);
213a943b15bSMatt Spinler
214a943b15bSMatt Spinler // Still need to enqueue this
215a943b15bSMatt Spinler EXPECT_TRUE(notifier.enqueueRequired(pel->id()));
216f77debb9SMatt Spinler
217f77debb9SMatt Spinler // Still need to send it
218f77debb9SMatt Spinler EXPECT_TRUE(notifier.notifyRequired(pel->id()));
219a943b15bSMatt Spinler }
220a943b15bSMatt Spinler
221a943b15bSMatt Spinler // Don't need to enqueue a hidden log already acked by the HMC
TEST_F(HostNotifierTest,TestPolicyHiddenWithHMCAcked)222a943b15bSMatt Spinler TEST_F(HostNotifierTest, TestPolicyHiddenWithHMCAcked)
223a943b15bSMatt Spinler {
224a943b15bSMatt Spinler HostNotifier notifier{repo, dataIface, std::move(hostIface)};
225a943b15bSMatt Spinler
226a943b15bSMatt Spinler // hiddenFlagBit
227a943b15bSMatt Spinler auto pel = makePEL(0x4000);
228a943b15bSMatt Spinler
229a943b15bSMatt Spinler // Double check the action flag is still set
230a943b15bSMatt Spinler std::bitset<16> actionFlags = pel->userHeader().actionFlags();
231a943b15bSMatt Spinler EXPECT_TRUE(actionFlags.test(hiddenFlagBit));
232a943b15bSMatt Spinler
233a943b15bSMatt Spinler repo.add(pel);
234a943b15bSMatt Spinler
235a943b15bSMatt Spinler // No HMC yet, so required
236a943b15bSMatt Spinler EXPECT_TRUE(notifier.enqueueRequired(pel->id()));
237a943b15bSMatt Spinler
238a943b15bSMatt Spinler repo.setPELHMCTransState(pel->id(), TransmissionState::acked);
239a943b15bSMatt Spinler
240a943b15bSMatt Spinler // Not required anymore
241a943b15bSMatt Spinler EXPECT_FALSE(notifier.enqueueRequired(pel->id()));
242a943b15bSMatt Spinler }
243a943b15bSMatt Spinler
244f77debb9SMatt Spinler // Test that changing the HMC manage status affects
245f77debb9SMatt Spinler // the policy with hidden log notification.
TEST_F(HostNotifierTest,TestPolicyHiddenWithHMCManaged)246f77debb9SMatt Spinler TEST_F(HostNotifierTest, TestPolicyHiddenWithHMCManaged)
247f77debb9SMatt Spinler {
248f77debb9SMatt Spinler HostNotifier notifier{repo, dataIface, std::move(hostIface)};
249f77debb9SMatt Spinler
250f77debb9SMatt Spinler // hiddenFlagBit
251f77debb9SMatt Spinler auto pel = makePEL(0x4000);
252f77debb9SMatt Spinler
253f77debb9SMatt Spinler repo.add(pel);
254f77debb9SMatt Spinler
255f77debb9SMatt Spinler // The first time, the HMC managed is false
256f77debb9SMatt Spinler EXPECT_TRUE(notifier.notifyRequired(pel->id()));
257f77debb9SMatt Spinler
258f77debb9SMatt Spinler dataIface.setHMCManaged(true);
259f77debb9SMatt Spinler
260f77debb9SMatt Spinler // This time, HMC managed is true so no need to notify
261f77debb9SMatt Spinler EXPECT_FALSE(notifier.notifyRequired(pel->id()));
262f77debb9SMatt Spinler }
263f77debb9SMatt Spinler
264f60ac27eSMatt Spinler // Test that PELs are enqueued on startup
TEST_F(HostNotifierTest,TestStartup)265f60ac27eSMatt Spinler TEST_F(HostNotifierTest, TestStartup)
266f60ac27eSMatt Spinler {
267f60ac27eSMatt Spinler // Give the repo 10 PELs to start with
268f60ac27eSMatt Spinler for (int i = 0; i < 10; i++)
269f60ac27eSMatt Spinler {
270f60ac27eSMatt Spinler auto pel = makePEL();
271f60ac27eSMatt Spinler repo.add(pel);
272f60ac27eSMatt Spinler }
273f60ac27eSMatt Spinler
274f60ac27eSMatt Spinler HostNotifier notifier{repo, dataIface, std::move(hostIface)};
275f60ac27eSMatt Spinler
276f60ac27eSMatt Spinler ASSERT_EQ(notifier.queueSize(), 10);
277f60ac27eSMatt Spinler
278f60ac27eSMatt Spinler // Now add 10 more after the notifier is watching
279f60ac27eSMatt Spinler for (int i = 0; i < 10; i++)
280f60ac27eSMatt Spinler {
281f60ac27eSMatt Spinler auto pel = makePEL();
282f60ac27eSMatt Spinler repo.add(pel);
283f60ac27eSMatt Spinler }
284f60ac27eSMatt Spinler
285f60ac27eSMatt Spinler ASSERT_EQ(notifier.queueSize(), 20);
286f60ac27eSMatt Spinler }
2877d800a4eSMatt Spinler
2887d800a4eSMatt Spinler // Test the simple path were PELs get sent to the host
TEST_F(HostNotifierTest,TestSendCmd)2897d800a4eSMatt Spinler TEST_F(HostNotifierTest, TestSendCmd)
2907d800a4eSMatt Spinler {
2917d800a4eSMatt Spinler sdeventplus::Event sdEvent{event};
2927d800a4eSMatt Spinler
2937d800a4eSMatt Spinler HostNotifier notifier{repo, dataIface, std::move(hostIface)};
2947d800a4eSMatt Spinler
2957d800a4eSMatt Spinler // Add a PEL with the host off
2967d800a4eSMatt Spinler auto pel = makePEL();
2977d800a4eSMatt Spinler repo.add(pel);
2987d800a4eSMatt Spinler
2997d800a4eSMatt Spinler EXPECT_EQ(notifier.queueSize(), 1);
3007d800a4eSMatt Spinler
3017d800a4eSMatt Spinler dataIface.changeHostState(true);
3027d800a4eSMatt Spinler
303e5f7508bSMatt Spinler runEvents(sdEvent, 2);
3047d800a4eSMatt Spinler
3057d800a4eSMatt Spinler // It was sent up
30656e08263SMatt Spinler EXPECT_EQ(mockHostIface->numCmdsProcessed(), 1);
3077d800a4eSMatt Spinler EXPECT_EQ(notifier.queueSize(), 0);
3087d800a4eSMatt Spinler
3097d800a4eSMatt Spinler // Verify the state was written to the PEL.
3107d800a4eSMatt Spinler Repository::LogID id{Repository::LogID::Pel{pel->id()}};
3117d800a4eSMatt Spinler auto data = repo.getPELData(id);
3127d800a4eSMatt Spinler PEL pelFromRepo{*data};
3137d800a4eSMatt Spinler EXPECT_EQ(pelFromRepo.hostTransmissionState(), TransmissionState::sent);
3147d800a4eSMatt Spinler
3157d800a4eSMatt Spinler // Add a few more PELs. They will get sent.
3167d800a4eSMatt Spinler pel = makePEL();
3177d800a4eSMatt Spinler repo.add(pel);
3187d800a4eSMatt Spinler
3197d800a4eSMatt Spinler // Dispatch it by hitting the event loop (no commands sent yet)
3207d800a4eSMatt Spinler // Don't need to test this step discretely in the future
3217d800a4eSMatt Spinler runEvents(sdEvent, 1);
32256e08263SMatt Spinler EXPECT_EQ(mockHostIface->numCmdsProcessed(), 1);
3237d800a4eSMatt Spinler EXPECT_EQ(notifier.queueSize(), 0);
3247d800a4eSMatt Spinler
3257d800a4eSMatt Spinler // Send the command
3267d800a4eSMatt Spinler runEvents(sdEvent, 1);
3277d800a4eSMatt Spinler
32856e08263SMatt Spinler EXPECT_EQ(mockHostIface->numCmdsProcessed(), 2);
3297d800a4eSMatt Spinler EXPECT_EQ(notifier.queueSize(), 0);
3307d800a4eSMatt Spinler
3317d800a4eSMatt Spinler pel = makePEL();
3327d800a4eSMatt Spinler repo.add(pel);
3337d800a4eSMatt Spinler
3347d800a4eSMatt Spinler // dispatch and process the command
3357d800a4eSMatt Spinler runEvents(sdEvent, 2);
3367d800a4eSMatt Spinler
33756e08263SMatt Spinler EXPECT_EQ(mockHostIface->numCmdsProcessed(), 3);
3387d800a4eSMatt Spinler EXPECT_EQ(notifier.queueSize(), 0);
3397d800a4eSMatt Spinler }
3407d800a4eSMatt Spinler
3417d800a4eSMatt Spinler // Test that if the class is created with the host up,
3427d800a4eSMatt Spinler // it will send PELs
TEST_F(HostNotifierTest,TestStartAfterHostUp)3437d800a4eSMatt Spinler TEST_F(HostNotifierTest, TestStartAfterHostUp)
3447d800a4eSMatt Spinler {
3457d800a4eSMatt Spinler // Add PELs right away
3467d800a4eSMatt Spinler auto pel = makePEL();
3477d800a4eSMatt Spinler repo.add(pel);
3487d800a4eSMatt Spinler pel = makePEL();
3497d800a4eSMatt Spinler repo.add(pel);
3507d800a4eSMatt Spinler
3517d800a4eSMatt Spinler sdeventplus::Event sdEvent{event};
3527d800a4eSMatt Spinler
3537d800a4eSMatt Spinler // Create the HostNotifier class with the host already up
3547d800a4eSMatt Spinler dataIface.changeHostState(true);
3557d800a4eSMatt Spinler HostNotifier notifier{repo, dataIface, std::move(hostIface)};
3567d800a4eSMatt Spinler
3577d800a4eSMatt Spinler // It should start sending PELs right away
358e5f7508bSMatt Spinler runEvents(sdEvent, 3);
3597d800a4eSMatt Spinler
36056e08263SMatt Spinler EXPECT_EQ(mockHostIface->numCmdsProcessed(), 2);
3617d800a4eSMatt Spinler EXPECT_EQ(notifier.queueSize(), 0);
3627d800a4eSMatt Spinler }
3637d800a4eSMatt Spinler
3647d800a4eSMatt Spinler // Test that a single failure will cause a retry
TEST_F(HostNotifierTest,TestHostRetry)3657d800a4eSMatt Spinler TEST_F(HostNotifierTest, TestHostRetry)
3667d800a4eSMatt Spinler {
3677d800a4eSMatt Spinler sdeventplus::Event sdEvent{event};
3687d800a4eSMatt Spinler
3697d800a4eSMatt Spinler HostNotifier notifier{repo, dataIface, std::move(hostIface)};
3707d800a4eSMatt Spinler
371d26fa3e7SPatrick Williams auto sendFailure = [this](uint32_t /*id*/, uint32_t /*size*/) {
37256e08263SMatt Spinler return this->mockHostIface->send(1);
3737d800a4eSMatt Spinler };
374d26fa3e7SPatrick Williams auto sendSuccess = [this](uint32_t /*id*/, uint32_t /*size*/) {
37556e08263SMatt Spinler return this->mockHostIface->send(0);
3767d800a4eSMatt Spinler };
3777d800a4eSMatt Spinler
37856e08263SMatt Spinler EXPECT_CALL(*mockHostIface, sendNewLogCmd(_, _))
3797d800a4eSMatt Spinler .WillOnce(Invoke(sendFailure))
3807d800a4eSMatt Spinler .WillOnce(Invoke(sendSuccess))
3817d800a4eSMatt Spinler .WillOnce(Invoke(sendSuccess));
3827d800a4eSMatt Spinler
3837d800a4eSMatt Spinler dataIface.changeHostState(true);
3847d800a4eSMatt Spinler
3857d800a4eSMatt Spinler auto pel = makePEL();
3867d800a4eSMatt Spinler repo.add(pel);
3877d800a4eSMatt Spinler
3887d800a4eSMatt Spinler // Dispatch and handle the command
3897d800a4eSMatt Spinler runEvents(sdEvent, 2);
3907d800a4eSMatt Spinler
3917d800a4eSMatt Spinler // The command failed, so the queue isn't empty
39256e08263SMatt Spinler EXPECT_EQ(mockHostIface->numCmdsProcessed(), 1);
3937d800a4eSMatt Spinler EXPECT_EQ(notifier.queueSize(), 1);
3947d800a4eSMatt Spinler
3957d800a4eSMatt Spinler // Run the events again to let the timer expire and the
3967d800a4eSMatt Spinler // command to be retried, which will be successful.
39756e08263SMatt Spinler runEvents(sdEvent, 2, mockHostIface->getReceiveRetryDelay());
3987d800a4eSMatt Spinler
39956e08263SMatt Spinler EXPECT_EQ(mockHostIface->numCmdsProcessed(), 2);
4007d800a4eSMatt Spinler EXPECT_EQ(notifier.queueSize(), 0);
4017d800a4eSMatt Spinler
4027d800a4eSMatt Spinler // This one should pass with no problems
4037d800a4eSMatt Spinler pel = makePEL();
4047d800a4eSMatt Spinler repo.add(pel);
4057d800a4eSMatt Spinler
4067d800a4eSMatt Spinler // Dispatch and handle the command
4077d800a4eSMatt Spinler runEvents(sdEvent, 2);
4087d800a4eSMatt Spinler
40956e08263SMatt Spinler EXPECT_EQ(mockHostIface->numCmdsProcessed(), 3);
4107d800a4eSMatt Spinler EXPECT_EQ(notifier.queueSize(), 0);
4117d800a4eSMatt Spinler }
4127d800a4eSMatt Spinler
4137d800a4eSMatt Spinler // Test that all commands fail and notifier will give up
TEST_F(HostNotifierTest,TestHardFailure)4147d800a4eSMatt Spinler TEST_F(HostNotifierTest, TestHardFailure)
4157d800a4eSMatt Spinler {
4167d800a4eSMatt Spinler sdeventplus::Event sdEvent{event};
4177d800a4eSMatt Spinler
4187d800a4eSMatt Spinler HostNotifier notifier{repo, dataIface, std::move(hostIface)};
4197d800a4eSMatt Spinler
4207d800a4eSMatt Spinler // Every call will fail
421d26fa3e7SPatrick Williams auto sendFailure = [this](uint32_t /*id*/, uint32_t /*size*/) {
42256e08263SMatt Spinler return this->mockHostIface->send(1);
4237d800a4eSMatt Spinler };
4247d800a4eSMatt Spinler
42556e08263SMatt Spinler EXPECT_CALL(*mockHostIface, sendNewLogCmd(_, _))
4267d800a4eSMatt Spinler .WillRepeatedly(Invoke(sendFailure));
4277d800a4eSMatt Spinler
4287d800a4eSMatt Spinler dataIface.changeHostState(true);
4297d800a4eSMatt Spinler
4307d800a4eSMatt Spinler auto pel = makePEL();
4317d800a4eSMatt Spinler repo.add(pel);
4327d800a4eSMatt Spinler
4337d800a4eSMatt Spinler // Clock more retries than necessary
43456e08263SMatt Spinler runEvents(sdEvent, 40, mockHostIface->getReceiveRetryDelay());
4357d800a4eSMatt Spinler
4367d800a4eSMatt Spinler // Should have stopped after the 15 Tries
43756e08263SMatt Spinler EXPECT_EQ(mockHostIface->numCmdsProcessed(), 15);
4387d800a4eSMatt Spinler EXPECT_EQ(notifier.queueSize(), 1);
4397d800a4eSMatt Spinler
4407d800a4eSMatt Spinler // Now add another PEL, and it should start trying again
4417d800a4eSMatt Spinler // though it will also eventually give up
4427d800a4eSMatt Spinler pel = makePEL();
4437d800a4eSMatt Spinler repo.add(pel);
4447d800a4eSMatt Spinler
44556e08263SMatt Spinler runEvents(sdEvent, 40, mockHostIface->getReceiveRetryDelay());
4467d800a4eSMatt Spinler
4477d800a4eSMatt Spinler // Tried an additional 15 times
44856e08263SMatt Spinler EXPECT_EQ(mockHostIface->numCmdsProcessed(), 30);
4497d800a4eSMatt Spinler EXPECT_EQ(notifier.queueSize(), 2);
4507d800a4eSMatt Spinler }
4517d800a4eSMatt Spinler
452527ff346SMatt Spinler // Test that if the command cannot be started it will give
453527ff346SMatt Spinler // up but still try again later
TEST_F(HostNotifierTest,TestCannotStartCmd)454527ff346SMatt Spinler TEST_F(HostNotifierTest, TestCannotStartCmd)
455527ff346SMatt Spinler {
456527ff346SMatt Spinler sdeventplus::Event sdEvent{event};
457527ff346SMatt Spinler
458527ff346SMatt Spinler HostNotifier notifier{repo, dataIface, std::move(hostIface)};
459527ff346SMatt Spinler
460527ff346SMatt Spinler // Make it behave like startCommand() fails.
461527ff346SMatt Spinler auto sendFailure = [this](uint32_t /*id*/, uint32_t /*size*/) {
462527ff346SMatt Spinler this->mockHostIface->cancelCmd();
463527ff346SMatt Spinler return CmdStatus::failure;
464527ff346SMatt Spinler };
465527ff346SMatt Spinler
466527ff346SMatt Spinler auto sendSuccess = [this](uint32_t /*id*/, uint32_t /*size*/) {
467527ff346SMatt Spinler return this->mockHostIface->send(0);
468527ff346SMatt Spinler };
469527ff346SMatt Spinler
470527ff346SMatt Spinler // Fails 16 times (1 fail + 15 retries) and
471527ff346SMatt Spinler // then start working.
472527ff346SMatt Spinler EXPECT_CALL(*mockHostIface, sendNewLogCmd(_, _))
473527ff346SMatt Spinler .WillOnce(Invoke(sendFailure))
474527ff346SMatt Spinler .WillOnce(Invoke(sendFailure))
475527ff346SMatt Spinler .WillOnce(Invoke(sendFailure))
476527ff346SMatt Spinler .WillOnce(Invoke(sendFailure))
477527ff346SMatt Spinler .WillOnce(Invoke(sendFailure))
478527ff346SMatt Spinler .WillOnce(Invoke(sendFailure))
479527ff346SMatt Spinler .WillOnce(Invoke(sendFailure))
480527ff346SMatt Spinler .WillOnce(Invoke(sendFailure))
481527ff346SMatt Spinler .WillOnce(Invoke(sendFailure))
482527ff346SMatt Spinler .WillOnce(Invoke(sendFailure))
483527ff346SMatt Spinler .WillOnce(Invoke(sendFailure))
484527ff346SMatt Spinler .WillOnce(Invoke(sendFailure))
485527ff346SMatt Spinler .WillOnce(Invoke(sendFailure))
486527ff346SMatt Spinler .WillOnce(Invoke(sendFailure))
487527ff346SMatt Spinler .WillOnce(Invoke(sendFailure))
488527ff346SMatt Spinler .WillOnce(Invoke(sendFailure))
489527ff346SMatt Spinler .WillRepeatedly(Invoke(sendSuccess));
490527ff346SMatt Spinler
491527ff346SMatt Spinler dataIface.changeHostState(true);
492527ff346SMatt Spinler
493527ff346SMatt Spinler auto pel = makePEL();
494527ff346SMatt Spinler repo.add(pel);
495527ff346SMatt Spinler
496527ff346SMatt Spinler // Clock more retries than necessary
497527ff346SMatt Spinler runEvents(sdEvent, 40, mockHostIface->getReceiveRetryDelay());
498527ff346SMatt Spinler
499527ff346SMatt Spinler // Didn't get far enough for a cmd to be processed
500527ff346SMatt Spinler EXPECT_EQ(mockHostIface->numCmdsProcessed(), 0);
501527ff346SMatt Spinler EXPECT_EQ(notifier.queueSize(), 1);
502527ff346SMatt Spinler
503527ff346SMatt Spinler // At this point, commands will work again.
504527ff346SMatt Spinler
505527ff346SMatt Spinler pel = makePEL();
506527ff346SMatt Spinler repo.add(pel);
507527ff346SMatt Spinler
508527ff346SMatt Spinler // Run the events to send the PELs
509527ff346SMatt Spinler runEvents(sdEvent, 5, mockHostIface->getReceiveRetryDelay());
510527ff346SMatt Spinler
511527ff346SMatt Spinler // All PELs sent
512527ff346SMatt Spinler EXPECT_EQ(mockHostIface->numCmdsProcessed(), 2);
513527ff346SMatt Spinler EXPECT_EQ(notifier.queueSize(), 0);
514527ff346SMatt Spinler }
515527ff346SMatt Spinler
5167d800a4eSMatt Spinler // Cancel an in progress command
TEST_F(HostNotifierTest,TestCancelCmd)5177d800a4eSMatt Spinler TEST_F(HostNotifierTest, TestCancelCmd)
5187d800a4eSMatt Spinler {
5197d800a4eSMatt Spinler sdeventplus::Event sdEvent{event};
5207d800a4eSMatt Spinler HostNotifier notifier{repo, dataIface, std::move(hostIface)};
5217d800a4eSMatt Spinler
5227d800a4eSMatt Spinler dataIface.changeHostState(true);
5237d800a4eSMatt Spinler
5247d800a4eSMatt Spinler // Add and send one PEL, but don't enter the event loop
5257d800a4eSMatt Spinler // so the receive function can't run.
5267d800a4eSMatt Spinler auto pel = makePEL();
5277d800a4eSMatt Spinler repo.add(pel);
5287d800a4eSMatt Spinler
5297d800a4eSMatt Spinler // Not dispatched yet
5307d800a4eSMatt Spinler EXPECT_EQ(notifier.queueSize(), 1);
5317d800a4eSMatt Spinler
5327d800a4eSMatt Spinler // Dispatch it
533e5f7508bSMatt Spinler runEvents(sdEvent, 2);
5347d800a4eSMatt Spinler
5357d800a4eSMatt Spinler // It was sent and off the queue
5367d800a4eSMatt Spinler EXPECT_EQ(notifier.queueSize(), 0);
5377d800a4eSMatt Spinler
5387d800a4eSMatt Spinler // This will cancel the receive
5397d800a4eSMatt Spinler dataIface.changeHostState(false);
5407d800a4eSMatt Spinler
5417d800a4eSMatt Spinler // Back on the queue
5427d800a4eSMatt Spinler EXPECT_EQ(notifier.queueSize(), 1);
5437d800a4eSMatt Spinler
5447d800a4eSMatt Spinler // Turn the host back on and make sure
5457d800a4eSMatt Spinler // commands will work again
5467d800a4eSMatt Spinler dataIface.changeHostState(true);
5477d800a4eSMatt Spinler
5487d800a4eSMatt Spinler runEvents(sdEvent, 1);
5497d800a4eSMatt Spinler
55056e08263SMatt Spinler EXPECT_EQ(mockHostIface->numCmdsProcessed(), 1);
5517d800a4eSMatt Spinler EXPECT_EQ(notifier.queueSize(), 0);
5527d800a4eSMatt Spinler }
553cc3b64aeSMatt Spinler
554cc3b64aeSMatt Spinler // Test that acking a PEL persist across power cycles
TEST_F(HostNotifierTest,TestPowerCycleAndAcks)555cc3b64aeSMatt Spinler TEST_F(HostNotifierTest, TestPowerCycleAndAcks)
556cc3b64aeSMatt Spinler {
557cc3b64aeSMatt Spinler sdeventplus::Event sdEvent{event};
558cc3b64aeSMatt Spinler
559cc3b64aeSMatt Spinler HostNotifier notifier{repo, dataIface, std::move(hostIface)};
560cc3b64aeSMatt Spinler
561cc3b64aeSMatt Spinler // Add 2 PELs with host off
562cc3b64aeSMatt Spinler auto pel = makePEL();
563cc3b64aeSMatt Spinler repo.add(pel);
564cc3b64aeSMatt Spinler auto id1 = pel->id();
565cc3b64aeSMatt Spinler
566cc3b64aeSMatt Spinler pel = makePEL();
567cc3b64aeSMatt Spinler repo.add(pel);
568cc3b64aeSMatt Spinler auto id2 = pel->id();
569cc3b64aeSMatt Spinler
570cc3b64aeSMatt Spinler dataIface.changeHostState(true);
571cc3b64aeSMatt Spinler
572e5f7508bSMatt Spinler runEvents(sdEvent, 3);
573cc3b64aeSMatt Spinler
574cc3b64aeSMatt Spinler // The were both sent.
57556e08263SMatt Spinler EXPECT_EQ(mockHostIface->numCmdsProcessed(), 2);
576cc3b64aeSMatt Spinler EXPECT_EQ(notifier.queueSize(), 0);
577cc3b64aeSMatt Spinler
578cc3b64aeSMatt Spinler dataIface.changeHostState(false);
579cc3b64aeSMatt Spinler
580cc3b64aeSMatt Spinler // Those PELs weren't acked, so they will get sent again
581cc3b64aeSMatt Spinler EXPECT_EQ(notifier.queueSize(), 2);
582cc3b64aeSMatt Spinler
583cc3b64aeSMatt Spinler // Power back on and send them again
584cc3b64aeSMatt Spinler dataIface.changeHostState(true);
585e5f7508bSMatt Spinler runEvents(sdEvent, 3);
586cc3b64aeSMatt Spinler
58756e08263SMatt Spinler EXPECT_EQ(mockHostIface->numCmdsProcessed(), 4);
588cc3b64aeSMatt Spinler EXPECT_EQ(notifier.queueSize(), 0);
589cc3b64aeSMatt Spinler
590cc3b64aeSMatt Spinler // Ack them and verify the state in the PEL.
591cc3b64aeSMatt Spinler notifier.ackPEL(id1);
592cc3b64aeSMatt Spinler notifier.ackPEL(id2);
593cc3b64aeSMatt Spinler
594cc3b64aeSMatt Spinler Repository::LogID id{Repository::LogID::Pel{id1}};
595cc3b64aeSMatt Spinler auto data = repo.getPELData(id);
596cc3b64aeSMatt Spinler PEL pelFromRepo1{*data};
597cc3b64aeSMatt Spinler EXPECT_EQ(pelFromRepo1.hostTransmissionState(), TransmissionState::acked);
598cc3b64aeSMatt Spinler
599cc3b64aeSMatt Spinler id.pelID.id = id2;
600cc3b64aeSMatt Spinler data = repo.getPELData(id);
601cc3b64aeSMatt Spinler PEL pelFromRepo2{*data};
602cc3b64aeSMatt Spinler EXPECT_EQ(pelFromRepo2.hostTransmissionState(), TransmissionState::acked);
603cc3b64aeSMatt Spinler
604cc3b64aeSMatt Spinler // Power back off, and they should't get re-added
605cc3b64aeSMatt Spinler dataIface.changeHostState(false);
606cc3b64aeSMatt Spinler
607cc3b64aeSMatt Spinler EXPECT_EQ(notifier.queueSize(), 0);
608cc3b64aeSMatt Spinler }
60941293cb8SMatt Spinler
61041293cb8SMatt Spinler // Test the host full condition
TEST_F(HostNotifierTest,TestHostFull)61141293cb8SMatt Spinler TEST_F(HostNotifierTest, TestHostFull)
61241293cb8SMatt Spinler {
61341293cb8SMatt Spinler // The full interaction with the host is:
61441293cb8SMatt Spinler // BMC: new PEL available
61541293cb8SMatt Spinler // Host: ReadPELFile (not modeled here)
61641293cb8SMatt Spinler // Host: Ack(id) (if not full), or HostFull(id)
61741293cb8SMatt Spinler // BMC: if full and any new PELs come in, don't sent them
61841293cb8SMatt Spinler // Start a timer and try again
61941293cb8SMatt Spinler // Host responds with either Ack or full
62041293cb8SMatt Spinler // and repeat
62141293cb8SMatt Spinler
62241293cb8SMatt Spinler sdeventplus::Event sdEvent{event};
62341293cb8SMatt Spinler HostNotifier notifier{repo, dataIface, std::move(hostIface)};
62441293cb8SMatt Spinler
62541293cb8SMatt Spinler dataIface.changeHostState(true);
62641293cb8SMatt Spinler
62741293cb8SMatt Spinler // Add and dispatch/send one PEL
62841293cb8SMatt Spinler auto pel = makePEL();
62941293cb8SMatt Spinler auto id = pel->id();
63041293cb8SMatt Spinler repo.add(pel);
63141293cb8SMatt Spinler runEvents(sdEvent, 2);
63241293cb8SMatt Spinler
63356e08263SMatt Spinler EXPECT_EQ(mockHostIface->numCmdsProcessed(), 1);
63441293cb8SMatt Spinler EXPECT_EQ(notifier.queueSize(), 0);
63541293cb8SMatt Spinler
63641293cb8SMatt Spinler // Host is full
63741293cb8SMatt Spinler notifier.setHostFull(id);
63841293cb8SMatt Spinler
63941293cb8SMatt Spinler // It goes back on the queue
64041293cb8SMatt Spinler EXPECT_EQ(notifier.queueSize(), 1);
64141293cb8SMatt Spinler
64241293cb8SMatt Spinler // The transmission state goes back to new
64341293cb8SMatt Spinler Repository::LogID i{Repository::LogID::Pel{id}};
64441293cb8SMatt Spinler auto data = repo.getPELData(i);
64541293cb8SMatt Spinler PEL pelFromRepo{*data};
64641293cb8SMatt Spinler EXPECT_EQ(pelFromRepo.hostTransmissionState(), TransmissionState::newPEL);
64741293cb8SMatt Spinler
64841293cb8SMatt Spinler // Clock it, nothing should be sent still.
64941293cb8SMatt Spinler runEvents(sdEvent, 1);
65041293cb8SMatt Spinler
65156e08263SMatt Spinler EXPECT_EQ(mockHostIface->numCmdsProcessed(), 1);
65241293cb8SMatt Spinler EXPECT_EQ(notifier.queueSize(), 1);
65341293cb8SMatt Spinler
65441293cb8SMatt Spinler // Add another PEL and clock it, still nothing sent
65541293cb8SMatt Spinler pel = makePEL();
65641293cb8SMatt Spinler repo.add(pel);
65741293cb8SMatt Spinler runEvents(sdEvent, 2);
65856e08263SMatt Spinler EXPECT_EQ(mockHostIface->numCmdsProcessed(), 1);
65941293cb8SMatt Spinler EXPECT_EQ(notifier.queueSize(), 2);
66041293cb8SMatt Spinler
66141293cb8SMatt Spinler // Let the host full timer expire to trigger a retry.
66241293cb8SMatt Spinler // Add some extra event passes just to be sure nothing new is sent.
66356e08263SMatt Spinler runEvents(sdEvent, 5, mockHostIface->getHostFullRetryDelay());
66441293cb8SMatt Spinler
66541293cb8SMatt Spinler // The timer expiration will send just the 1, not both
66656e08263SMatt Spinler EXPECT_EQ(mockHostIface->numCmdsProcessed(), 2);
66741293cb8SMatt Spinler EXPECT_EQ(notifier.queueSize(), 1);
66841293cb8SMatt Spinler
66941293cb8SMatt Spinler // Host still full
67041293cb8SMatt Spinler notifier.setHostFull(id);
67141293cb8SMatt Spinler
67241293cb8SMatt Spinler // Let the host full timer attempt again
67356e08263SMatt Spinler runEvents(sdEvent, 2, mockHostIface->getHostFullRetryDelay());
67456e08263SMatt Spinler EXPECT_EQ(mockHostIface->numCmdsProcessed(), 3);
67541293cb8SMatt Spinler
67641293cb8SMatt Spinler // Add yet another PEL with the retry timer expired.
67741293cb8SMatt Spinler // It shouldn't get sent out.
67841293cb8SMatt Spinler pel = makePEL();
67941293cb8SMatt Spinler repo.add(pel);
68041293cb8SMatt Spinler runEvents(sdEvent, 2);
68156e08263SMatt Spinler EXPECT_EQ(mockHostIface->numCmdsProcessed(), 3);
68241293cb8SMatt Spinler
68341293cb8SMatt Spinler // The last 2 PELs still on the queue
68441293cb8SMatt Spinler EXPECT_EQ(notifier.queueSize(), 2);
68541293cb8SMatt Spinler
68641293cb8SMatt Spinler // Host no longer full, it finally acks the first PEL
68741293cb8SMatt Spinler notifier.ackPEL(id);
68841293cb8SMatt Spinler
68941293cb8SMatt Spinler // Now the remaining 2 PELs will be dispatched
69041293cb8SMatt Spinler runEvents(sdEvent, 3);
69141293cb8SMatt Spinler
69256e08263SMatt Spinler EXPECT_EQ(mockHostIface->numCmdsProcessed(), 5);
69341293cb8SMatt Spinler EXPECT_EQ(notifier.queueSize(), 0);
69441293cb8SMatt Spinler }
695a19b6234SMatt Spinler
696a19b6234SMatt Spinler // Test when the host says it was send a malformed PEL
TEST_F(HostNotifierTest,TestBadPEL)697a19b6234SMatt Spinler TEST_F(HostNotifierTest, TestBadPEL)
698a19b6234SMatt Spinler {
699a19b6234SMatt Spinler sdeventplus::Event sdEvent{event};
700a19b6234SMatt Spinler
701a19b6234SMatt Spinler {
70256e08263SMatt Spinler Repository repo1{repoPath};
70356e08263SMatt Spinler HostNotifier notifier{repo1, dataIface, std::move(hostIface)};
704a19b6234SMatt Spinler
705a19b6234SMatt Spinler dataIface.changeHostState(true);
706a19b6234SMatt Spinler
707a19b6234SMatt Spinler // Add a PEL and dispatch and send it
708a19b6234SMatt Spinler auto pel = makePEL();
709a19b6234SMatt Spinler auto id = pel->id();
71056e08263SMatt Spinler repo1.add(pel);
711a19b6234SMatt Spinler
712a19b6234SMatt Spinler runEvents(sdEvent, 2);
71356e08263SMatt Spinler EXPECT_EQ(mockHostIface->numCmdsProcessed(), 1);
714a19b6234SMatt Spinler EXPECT_EQ(notifier.queueSize(), 0);
715a19b6234SMatt Spinler
716a19b6234SMatt Spinler // The host rejected it.
717a19b6234SMatt Spinler notifier.setBadPEL(id);
718a19b6234SMatt Spinler
719a19b6234SMatt Spinler // Doesn't go back on the queue
720a19b6234SMatt Spinler EXPECT_EQ(notifier.queueSize(), 0);
721a19b6234SMatt Spinler
722a19b6234SMatt Spinler // Check the state was saved in the PEL itself
723a19b6234SMatt Spinler Repository::LogID i{Repository::LogID::Pel{id}};
72456e08263SMatt Spinler auto data = repo1.getPELData(i);
725a19b6234SMatt Spinler PEL pelFromRepo{*data};
726a19b6234SMatt Spinler EXPECT_EQ(pelFromRepo.hostTransmissionState(),
727a19b6234SMatt Spinler TransmissionState::badPEL);
728a19b6234SMatt Spinler
729a19b6234SMatt Spinler dataIface.changeHostState(false);
730a19b6234SMatt Spinler
731a19b6234SMatt Spinler // Ensure it doesn't go back on the queue on a power cycle
732a19b6234SMatt Spinler EXPECT_EQ(notifier.queueSize(), 0);
733a19b6234SMatt Spinler }
734a19b6234SMatt Spinler
735a19b6234SMatt Spinler // Now restore the repo, and make sure it doesn't come back
736a19b6234SMatt Spinler {
73756e08263SMatt Spinler Repository repo1{repoPath};
738a19b6234SMatt Spinler
73956e08263SMatt Spinler std::unique_ptr<HostInterface> hostIface1 =
740a19b6234SMatt Spinler std::make_unique<MockHostInterface>(event, dataIface);
741a19b6234SMatt Spinler
74256e08263SMatt Spinler HostNotifier notifier{repo1, dataIface, std::move(hostIface1)};
743a19b6234SMatt Spinler
744a19b6234SMatt Spinler EXPECT_EQ(notifier.queueSize(), 0);
745a19b6234SMatt Spinler }
746a19b6234SMatt Spinler }
74724a8558bSMatt Spinler
74824a8558bSMatt Spinler // Test that sending PELs can be disabled
TEST_F(HostNotifierTest,TestDisable)74924a8558bSMatt Spinler TEST_F(HostNotifierTest, TestDisable)
75024a8558bSMatt Spinler {
75124a8558bSMatt Spinler // Turn off sending the PELs except for once in the middle
75224a8558bSMatt Spinler EXPECT_CALL(dataIface, getHostPELEnablement())
75324a8558bSMatt Spinler .WillOnce(Return(false))
75424a8558bSMatt Spinler .WillOnce(Return(false))
75524a8558bSMatt Spinler .WillOnce(Return(true))
75624a8558bSMatt Spinler .WillOnce(Return(false))
75724a8558bSMatt Spinler .WillOnce(Return(false))
75824a8558bSMatt Spinler .WillOnce(Return(false));
75924a8558bSMatt Spinler
76024a8558bSMatt Spinler {
76124a8558bSMatt Spinler HostNotifier notifier{repo, dataIface, std::move(hostIface)};
76224a8558bSMatt Spinler
76324a8558bSMatt Spinler // Add a PEL with the host off
76424a8558bSMatt Spinler auto pel = makePEL();
76524a8558bSMatt Spinler repo.add(pel);
76624a8558bSMatt Spinler
76724a8558bSMatt Spinler // Not added to the send queue
76824a8558bSMatt Spinler EXPECT_EQ(notifier.queueSize(), 0);
76924a8558bSMatt Spinler
77024a8558bSMatt Spinler dataIface.changeHostState(true);
77124a8558bSMatt Spinler
77224a8558bSMatt Spinler // Try again with the host on
77324a8558bSMatt Spinler pel = makePEL();
77424a8558bSMatt Spinler repo.add(pel);
77524a8558bSMatt Spinler
77624a8558bSMatt Spinler EXPECT_EQ(notifier.queueSize(), 0);
77724a8558bSMatt Spinler
77824a8558bSMatt Spinler // Now getHostPELEnablement() will return true for the new PEL
77924a8558bSMatt Spinler pel = makePEL();
78024a8558bSMatt Spinler repo.add(pel);
78124a8558bSMatt Spinler
78224a8558bSMatt Spinler EXPECT_EQ(notifier.queueSize(), 1);
78324a8558bSMatt Spinler }
78424a8558bSMatt Spinler
78524a8558bSMatt Spinler // getHostPELEnablement is back to returning false.
78624a8558bSMatt Spinler // Create a new second instance and make sure the 3 existing PELs
78724a8558bSMatt Spinler // aren't put on the queue on startup
78824a8558bSMatt Spinler {
78924a8558bSMatt Spinler Repository repo1{repoPath};
79024a8558bSMatt Spinler std::unique_ptr<HostInterface> hostIface1 =
79124a8558bSMatt Spinler std::make_unique<MockHostInterface>(event, dataIface);
79224a8558bSMatt Spinler
79324a8558bSMatt Spinler HostNotifier notifier{repo1, dataIface, std::move(hostIface1)};
79424a8558bSMatt Spinler
79524a8558bSMatt Spinler EXPECT_EQ(notifier.queueSize(), 0);
79624a8558bSMatt Spinler }
79724a8558bSMatt Spinler }
798