blob: 2f2e1f08430f49cbcde082cf1c8b08d25e7748b1 [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()));
134
135 // Not in the repo
136 EXPECT_FALSE(notifier.enqueueRequired(42));
137
138 // Now set this PEL to host acked
139 repo.setPELHostTransState(pel->id(), TransmissionState::acked);
140
141 // Since it's acked, doesn't need to be enqueued or transmitted
142 EXPECT_FALSE(notifier.enqueueRequired(pel->id()));
143}
144
145// Test the 'don't report' PEL flag
146TEST_F(HostNotifierTest, TestPolicyDontReport)
147{
148 Repository repo{repoPath};
149 MockDataInterface dataIface;
150
151 std::unique_ptr<HostInterface> hostIface =
152 std::make_unique<MockHostInterface>(event, dataIface);
153
154 HostNotifier notifier{repo, dataIface, std::move(hostIface)};
155
156 // dontReportToHostFlagBit
157 auto pel = makePEL(0x1000);
158
159 // Double check the action flag is still set
160 std::bitset<16> actionFlags = pel->userHeader().actionFlags();
161 EXPECT_TRUE(actionFlags.test(dontReportToHostFlagBit));
162
163 repo.add(pel);
164
165 // Don't need to send this to the host
166 EXPECT_FALSE(notifier.enqueueRequired(pel->id()));
167}
168
169// Test that hidden PELs need notification when there
170// is no HMC.
171TEST_F(HostNotifierTest, TestPolicyHiddenNoHMC)
172{
173 Repository repo{repoPath};
174 MockDataInterface dataIface;
175
176 std::unique_ptr<HostInterface> hostIface =
177 std::make_unique<MockHostInterface>(event, dataIface);
178
179 HostNotifier notifier{repo, dataIface, std::move(hostIface)};
180
181 // hiddenFlagBit
182 auto pel = makePEL(0x4000);
183
184 // Double check the action flag is still set
185 std::bitset<16> actionFlags = pel->userHeader().actionFlags();
186 EXPECT_TRUE(actionFlags.test(hiddenFlagBit));
187
188 repo.add(pel);
189
190 // Still need to enqueue this
191 EXPECT_TRUE(notifier.enqueueRequired(pel->id()));
192}
193
194// Don't need to enqueue a hidden log already acked by the HMC
195TEST_F(HostNotifierTest, TestPolicyHiddenWithHMCAcked)
196{
197 Repository repo{repoPath};
198 MockDataInterface dataIface;
199
200 std::unique_ptr<HostInterface> hostIface =
201 std::make_unique<MockHostInterface>(event, dataIface);
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 // No HMC yet, so required
215 EXPECT_TRUE(notifier.enqueueRequired(pel->id()));
216
217 repo.setPELHMCTransState(pel->id(), TransmissionState::acked);
218
219 // Not required anymore
220 EXPECT_FALSE(notifier.enqueueRequired(pel->id()));
221}
222
Matt Spinlerf60ac272019-12-11 13:47:50 -0600223// Test that PELs are enqueued on startup
224TEST_F(HostNotifierTest, TestStartup)
225{
226 Repository repo{repoPath};
227 MockDataInterface dataIface;
228
229 // Give the repo 10 PELs to start with
230 for (int i = 0; i < 10; i++)
231 {
232 auto pel = makePEL();
233 repo.add(pel);
234 }
235
Matt Spinlerf60ac272019-12-11 13:47:50 -0600236 std::unique_ptr<HostInterface> hostIface =
237 std::make_unique<MockHostInterface>(event, dataIface);
238
239 HostNotifier notifier{repo, dataIface, std::move(hostIface)};
240
241 ASSERT_EQ(notifier.queueSize(), 10);
242
243 // Now add 10 more after the notifier is watching
244 for (int i = 0; i < 10; i++)
245 {
246 auto pel = makePEL();
247 repo.add(pel);
248 }
249
250 ASSERT_EQ(notifier.queueSize(), 20);
251}