blob: 3608539667c79fb126d62599dfd0b04585fb84f9 [file] [log] [blame]
Matt Spinlerf60ac272019-12-11 13:47:50 -06001/**
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
29using namespace openpower::pels;
30using ::testing::_;
31using ::testing::Invoke;
32using ::testing::Return;
33namespace fs = std::filesystem;
34using namespace std::chrono;
35
36const size_t actionFlags0Offset = 66;
37const size_t actionFlags1Offset = 67;
38
39class HostNotifierTest : public CleanPELFiles
40{
Matt Spinlera943b152019-12-11 14:44:50 -060041 public:
42 HostNotifierTest()
43 {
44 auto r = sd_event_default(&event);
45 EXPECT_TRUE(r >= 0);
46 }
47
48 ~HostNotifierTest()
49 {
50 sd_event_unref(event);
51 }
52
53 protected:
54 sd_event* event;
Matt Spinlerf60ac272019-12-11 13:47:50 -060055};
56
57/**
58 * @brief Create PEL with the specified action flags
59 *
60 * @param[in] actionFlagsMask - Optional action flags to use
61 *
62 * @return std::unique_ptr<PEL>
63 */
64std::unique_ptr<PEL> makePEL(uint16_t actionFlagsMask = 0)
65{
66 static uint32_t obmcID = 1;
67 auto data = pelDataFactory(TestPELType::pelSimple);
68
69 data[actionFlags0Offset] |= actionFlagsMask >> 8;
70 data[actionFlags1Offset] |= actionFlagsMask & 0xFF;
71
72 auto pel = std::make_unique<PEL>(data, obmcID++);
73 pel->assignID();
74 pel->setCommitTime();
75 return pel;
76}
77
78// Test that host state change callbacks work
79TEST_F(HostNotifierTest, TestHostStateChange)
80{
81 MockDataInterface dataIface;
82
83 bool hostState = false;
84 bool called = false;
85 DataInterfaceBase::HostStateChangeFunc func = [&hostState,
86 &called](bool state) {
87 hostState = state;
88 called = true;
89 };
90
91 dataIface.subscribeToHostStateChange("test", func);
92
93 // callback called
94 dataIface.changeHostState(true);
95 EXPECT_TRUE(called);
96 EXPECT_TRUE(hostState);
97
98 // No change, not called
99 called = false;
100 dataIface.changeHostState(true);
101 EXPECT_FALSE(called);
102
103 // Called again
104 dataIface.changeHostState(false);
105 EXPECT_FALSE(hostState);
106 EXPECT_TRUE(called);
107
108 // Shouldn't get called after an unsubscribe
109 dataIface.unsubscribeFromHostStateChange("test");
110
111 called = false;
112
113 dataIface.changeHostState(true);
114 EXPECT_FALSE(called);
115}
116
Matt Spinlera943b152019-12-11 14:44:50 -0600117// Test dealing with how acked PELs are put on the
118// notification queue.
119TEST_F(HostNotifierTest, TestPolicyAckedPEL)
120{
121 Repository repo{repoPath};
122 MockDataInterface dataIface;
123
124 std::unique_ptr<HostInterface> hostIface =
125 std::make_unique<MockHostInterface>(event, dataIface);
126
127 HostNotifier notifier{repo, dataIface, std::move(hostIface)};
128
129 auto pel = makePEL();
130 repo.add(pel);
131
132 // This is required
133 EXPECT_TRUE(notifier.enqueueRequired(pel->id()));
Matt Spinlerf77debb2019-12-12 10:04:33 -0600134 EXPECT_TRUE(notifier.notifyRequired(pel->id()));
Matt Spinlera943b152019-12-11 14:44:50 -0600135
136 // Not in the repo
137 EXPECT_FALSE(notifier.enqueueRequired(42));
Matt Spinlerf77debb2019-12-12 10:04:33 -0600138 EXPECT_FALSE(notifier.notifyRequired(42));
Matt Spinlera943b152019-12-11 14:44:50 -0600139
140 // Now set this PEL to host acked
141 repo.setPELHostTransState(pel->id(), TransmissionState::acked);
142
143 // Since it's acked, doesn't need to be enqueued or transmitted
144 EXPECT_FALSE(notifier.enqueueRequired(pel->id()));
Matt Spinlerf77debb2019-12-12 10:04:33 -0600145 EXPECT_FALSE(notifier.notifyRequired(pel->id()));
Matt Spinlera943b152019-12-11 14:44:50 -0600146}
147
148// Test the 'don't report' PEL flag
149TEST_F(HostNotifierTest, TestPolicyDontReport)
150{
151 Repository repo{repoPath};
152 MockDataInterface dataIface;
153
154 std::unique_ptr<HostInterface> hostIface =
155 std::make_unique<MockHostInterface>(event, dataIface);
156
157 HostNotifier notifier{repo, dataIface, std::move(hostIface)};
158
159 // dontReportToHostFlagBit
160 auto pel = makePEL(0x1000);
161
162 // Double check the action flag is still set
163 std::bitset<16> actionFlags = pel->userHeader().actionFlags();
164 EXPECT_TRUE(actionFlags.test(dontReportToHostFlagBit));
165
166 repo.add(pel);
167
168 // Don't need to send this to the host
169 EXPECT_FALSE(notifier.enqueueRequired(pel->id()));
170}
171
172// Test that hidden PELs need notification when there
173// is no HMC.
174TEST_F(HostNotifierTest, TestPolicyHiddenNoHMC)
175{
176 Repository repo{repoPath};
177 MockDataInterface dataIface;
178
179 std::unique_ptr<HostInterface> hostIface =
180 std::make_unique<MockHostInterface>(event, dataIface);
181
182 HostNotifier notifier{repo, dataIface, std::move(hostIface)};
183
184 // hiddenFlagBit
185 auto pel = makePEL(0x4000);
186
187 // Double check the action flag is still set
188 std::bitset<16> actionFlags = pel->userHeader().actionFlags();
189 EXPECT_TRUE(actionFlags.test(hiddenFlagBit));
190
191 repo.add(pel);
192
193 // Still need to enqueue this
194 EXPECT_TRUE(notifier.enqueueRequired(pel->id()));
Matt Spinlerf77debb2019-12-12 10:04:33 -0600195
196 // Still need to send it
197 EXPECT_TRUE(notifier.notifyRequired(pel->id()));
Matt Spinlera943b152019-12-11 14:44:50 -0600198}
199
200// Don't need to enqueue a hidden log already acked by the HMC
201TEST_F(HostNotifierTest, TestPolicyHiddenWithHMCAcked)
202{
203 Repository repo{repoPath};
204 MockDataInterface dataIface;
205
206 std::unique_ptr<HostInterface> hostIface =
207 std::make_unique<MockHostInterface>(event, dataIface);
208
209 HostNotifier notifier{repo, dataIface, std::move(hostIface)};
210
211 // hiddenFlagBit
212 auto pel = makePEL(0x4000);
213
214 // Double check the action flag is still set
215 std::bitset<16> actionFlags = pel->userHeader().actionFlags();
216 EXPECT_TRUE(actionFlags.test(hiddenFlagBit));
217
218 repo.add(pel);
219
220 // No HMC yet, so required
221 EXPECT_TRUE(notifier.enqueueRequired(pel->id()));
222
223 repo.setPELHMCTransState(pel->id(), TransmissionState::acked);
224
225 // Not required anymore
226 EXPECT_FALSE(notifier.enqueueRequired(pel->id()));
227}
228
Matt Spinlerf77debb2019-12-12 10:04:33 -0600229// Test that changing the HMC manage status affects
230// the policy with hidden log notification.
231TEST_F(HostNotifierTest, TestPolicyHiddenWithHMCManaged)
232{
233 Repository repo{repoPath};
234 MockDataInterface dataIface;
235
236 std::unique_ptr<HostInterface> hostIface =
237 std::make_unique<MockHostInterface>(event, dataIface);
238
239 HostNotifier notifier{repo, dataIface, std::move(hostIface)};
240
241 // hiddenFlagBit
242 auto pel = makePEL(0x4000);
243
244 repo.add(pel);
245
246 // The first time, the HMC managed is false
247 EXPECT_TRUE(notifier.notifyRequired(pel->id()));
248
249 dataIface.setHMCManaged(true);
250
251 // This time, HMC managed is true so no need to notify
252 EXPECT_FALSE(notifier.notifyRequired(pel->id()));
253}
254
Matt Spinlerf60ac272019-12-11 13:47:50 -0600255// Test that PELs are enqueued on startup
256TEST_F(HostNotifierTest, TestStartup)
257{
258 Repository repo{repoPath};
259 MockDataInterface dataIface;
260
261 // Give the repo 10 PELs to start with
262 for (int i = 0; i < 10; i++)
263 {
264 auto pel = makePEL();
265 repo.add(pel);
266 }
267
Matt Spinlerf60ac272019-12-11 13:47:50 -0600268 std::unique_ptr<HostInterface> hostIface =
269 std::make_unique<MockHostInterface>(event, dataIface);
270
271 HostNotifier notifier{repo, dataIface, std::move(hostIface)};
272
273 ASSERT_EQ(notifier.queueSize(), 10);
274
275 // Now add 10 more after the notifier is watching
276 for (int i = 0; i < 10; i++)
277 {
278 auto pel = makePEL();
279 repo.add(pel);
280 }
281
282 ASSERT_EQ(notifier.queueSize(), 20);
283}