blob: 3e99f6920d779b37ed4692a901f8cbf427f24f2f [file] [log] [blame]
Alexander Hansen40fb5492025-10-28 17:56:12 +01001// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright 2020 IBM Corporation
3
Matt Spinler05f0c6d2020-08-05 14:21:06 -05004#include "extensions/openpower-pels/service_indicators.hpp"
5#include "mocks.hpp"
6#include "pel_utils.hpp"
7
8#include <gtest/gtest.h>
9
10using namespace openpower::pels;
11using CalloutVector = std::vector<std::unique_ptr<src::Callout>>;
12using ::testing::_;
13using ::testing::Return;
14using ::testing::Throw;
15
16// Test the ignore() function works
17TEST(ServiceIndicatorsTest, IgnoreTest)
18{
19 MockDataInterface dataIface;
20 service_indicators::LightPath lightPath{dataIface};
21
22 // PEL must have serviceable action flag set and be created
23 // by the BMC or Hostboot.
24 std::vector<std::tuple<char, uint16_t, bool>> testParams{
25 {'O', 0xA400, false}, // BMC serviceable, don't ignore
26 {'B', 0xA400, false}, // Hostboot serviceable, don't ignore
27 {'H', 0xA400, true}, // PHYP serviceable, ignore
28 {'O', 0x2400, true}, // BMC not serviceable, ignore
29 {'B', 0x2400, true}, // Hostboot not serviceable, ignore
30 {'H', 0x2400, true}, // PHYP not serviceable, ignore
31 };
32
33 for (const auto& test : testParams)
34 {
35 auto data = pelFactory(1, std::get<char>(test), 0x20,
36 std::get<uint16_t>(test), 500);
37 PEL pel{data};
38
39 EXPECT_EQ(lightPath.ignore(pel), std::get<bool>(test));
40 }
41}
42
43// Test that only high, medium, and medium group A hardware
44// callouts have their location codes extracted.
45TEST(ServiceIndicatorsTest, OneCalloutPriorityTest)
46{
47 MockDataInterface dataIface;
48 service_indicators::LightPath lightPath{dataIface};
49
50 // The priorities to test, with the expected getLocationCodes results.
51 std::vector<std::tuple<CalloutPriority, std::vector<std::string>>>
52 testCallouts{{CalloutPriority::high, {"U27-P1"}},
53 {CalloutPriority::medium, {"U27-P1"}},
54 {CalloutPriority::mediumGroupA, {"U27-P1"}},
55 {CalloutPriority::mediumGroupB, {}},
56 {CalloutPriority::mediumGroupC, {}},
57 {CalloutPriority::low, {}}};
58
59 for (const auto& test : testCallouts)
60 {
61 auto callout = std::make_unique<src::Callout>(
62 std::get<CalloutPriority>(test), "U27-P1", "1234567", "aaaa",
63 "123456789ABC");
64
65 CalloutVector callouts;
66 callouts.push_back(std::move(callout));
67
68 EXPECT_EQ(lightPath.getLocationCodes(callouts),
69 std::get<std::vector<std::string>>(test));
70 }
71}
72
73// Test that only normal hardware callouts and symbolic FRU
74// callouts with trusted location codes have their location
75// codes extracted.
76TEST(ServiceIndicatorsTest, OneCalloutTypeTest)
77{
78 MockDataInterface dataIface;
79 service_indicators::LightPath lightPath{dataIface};
80
81 // Regular hardware callout
82 {
83 CalloutVector callouts;
84 callouts.push_back(
85 std::make_unique<src::Callout>(CalloutPriority::high, "U27-P1",
86 "1234567", "aaaa", "123456789ABC"));
87
88 EXPECT_EQ(lightPath.getLocationCodes(callouts),
89 std::vector<std::string>{"U27-P1"});
90 }
91
92 // Symbolic FRU with trusted loc code callout
93 {
94 CalloutVector callouts;
95 callouts.push_back(std::make_unique<src::Callout>(
96 CalloutPriority::high, "service_docs", "U27-P1", true));
97
98 EXPECT_EQ(lightPath.getLocationCodes(callouts),
99 std::vector<std::string>{"U27-P1"});
100 }
101
102 // Symbolic FRU without trusted loc code callout
103 {
104 CalloutVector callouts;
105 callouts.push_back(std::make_unique<src::Callout>(
106 CalloutPriority::high, "service_docs", "U27-P1", false));
107
108 EXPECT_EQ(lightPath.getLocationCodes(callouts),
109 std::vector<std::string>{});
110 }
111
112 // Procedure callout
113 {
114 CalloutVector callouts;
115 callouts.push_back(
116 std::make_unique<src::Callout>(CalloutPriority::high, "bmc_code"));
117
118 EXPECT_EQ(lightPath.getLocationCodes(callouts),
119 std::vector<std::string>{});
120 }
121}
122
123// Test that only the callouts in the first group have their location
124// codes extracted, where a group is one or more callouts listed
125// together with priorities of high, medium, or medium group A
126// (and medium is only ever contains 1 item).
127TEST(ServiceIndicatorsTest, CalloutGroupingTest)
128{
129 MockDataInterface dataIface;
130 service_indicators::LightPath lightPath{dataIface};
131
132 // high/high/medium/high just grabs the first 2
133 {
134 CalloutVector callouts;
135 callouts.push_back(
136 std::make_unique<src::Callout>(CalloutPriority::high, "U27-P1",
137 "1234567", "aaaa", "123456789ABC"));
138 callouts.push_back(
139 std::make_unique<src::Callout>(CalloutPriority::high, "U27-P2",
140 "1234567", "aaaa", "123456789ABC"));
141 callouts.push_back(
142 std::make_unique<src::Callout>(CalloutPriority::medium, "U27-P3",
143 "1234567", "aaaa", "123456789ABC"));
144 // This high priority callout after a medium isn't actually valid, since
145 // callouts are sorted, but test it anyway.
146 callouts.push_back(
147 std::make_unique<src::Callout>(CalloutPriority::high, "U27-P4",
148 "1234567", "aaaa", "123456789ABC"));
149
150 EXPECT_EQ(lightPath.getLocationCodes(callouts),
151 (std::vector<std::string>{"U27-P1", "U27-P2"}));
152 }
153
154 // medium/medium just grabs the first medium
155 {
156 CalloutVector callouts;
157 callouts.push_back(
158 std::make_unique<src::Callout>(CalloutPriority::medium, "U27-P1",
159 "1234567", "aaaa", "123456789ABC"));
160 callouts.push_back(
161 std::make_unique<src::Callout>(CalloutPriority::medium, "U27-P2",
162 "1234567", "aaaa", "123456789ABC"));
163
164 EXPECT_EQ(lightPath.getLocationCodes(callouts),
165 std::vector<std::string>{"U27-P1"});
166 }
167
168 // mediumA/mediumA/medium just grabs the first 2
169 {
170 CalloutVector callouts;
171 callouts.push_back(std::make_unique<src::Callout>(
172 CalloutPriority::mediumGroupA, "U27-P1", "1234567", "aaaa",
173 "123456789ABC"));
174
175 callouts.push_back(std::make_unique<src::Callout>(
176 CalloutPriority::mediumGroupA, "U27-P2", "1234567", "aaaa",
177 "123456789ABC"));
178
179 callouts.push_back(
180 std::make_unique<src::Callout>(CalloutPriority::medium, "U27-P3",
181 "1234567", "aaaa", "123456789ABC"));
182
183 EXPECT_EQ(lightPath.getLocationCodes(callouts),
184 (std::vector<std::string>{"U27-P1", "U27-P2"}));
185 }
186}
187
188// Test that if any callouts in group are not HW/trusted symbolic
189// FRU callouts then no location codes will be extracted
190TEST(ServiceIndicatorsTest, CalloutMixedTypesTest)
191{
192 MockDataInterface dataIface;
193 service_indicators::LightPath lightPath{dataIface};
194
195 // Mixing FRU with trusted symbolic FRU is OK
196 {
197 CalloutVector callouts;
198 callouts.push_back(
199 std::make_unique<src::Callout>(CalloutPriority::high, "U27-P1",
200 "1234567", "aaaa", "123456789ABC"));
201 callouts.push_back(std::make_unique<src::Callout>(
202 CalloutPriority::high, "service_docs", "U27-P2", true));
203
204 EXPECT_EQ(lightPath.getLocationCodes(callouts),
205 (std::vector<std::string>{"U27-P1", "U27-P2"}));
206 }
207
208 // Normal FRU callout with a non-trusted symbolic FRU callout not OK
209 {
210 CalloutVector callouts;
211 callouts.push_back(
212 std::make_unique<src::Callout>(CalloutPriority::high, "U27-P1",
213 "1234567", "aaaa", "123456789ABC"));
214 callouts.push_back(std::make_unique<src::Callout>(
215 CalloutPriority::high, "service_docs", "U27-P2", false));
216
217 EXPECT_EQ(lightPath.getLocationCodes(callouts),
218 (std::vector<std::string>{}));
219 }
220
221 // Normal FRU callout with a procedure callout not OK
222 {
223 CalloutVector callouts;
224 callouts.push_back(
225 std::make_unique<src::Callout>(CalloutPriority::high, "U27-P1",
226 "1234567", "aaaa", "123456789ABC"));
227 callouts.push_back(
228 std::make_unique<src::Callout>(CalloutPriority::high, "bmc_code"));
229
230 EXPECT_EQ(lightPath.getLocationCodes(callouts),
231 (std::vector<std::string>{}));
232 }
233
234 // Trusted symbolic FRU callout with a non-trusted symbolic
235 // FRU callout not OK
236 {
237 CalloutVector callouts;
238 callouts.push_back(std::make_unique<src::Callout>(
239 CalloutPriority::high, "service_docs", "U27-P2", true));
240
241 callouts.push_back(std::make_unique<src::Callout>(
242 CalloutPriority::high, "service_docs", "U27-P2", false));
243
244 EXPECT_EQ(lightPath.getLocationCodes(callouts),
245 (std::vector<std::string>{}));
246 }
247}
Matt Spinler34a904c2020-08-05 14:53:28 -0500248
249// Test the activate() function
250TEST(ServiceIndicatorsTest, ActivateTest)
251{
252 // pelFactory() will create a PEL with 1 callout with location code
253 // U42. Test the LED for that gets activated.
254 {
255 MockDataInterface dataIface;
256 service_indicators::LightPath lightPath{dataIface};
257
258 EXPECT_CALL(dataIface, getInventoryFromLocCode("U42", 0, true))
Matt Spinlerbad056b2023-01-25 14:16:57 -0600259 .WillOnce(
260 Return(std::vector<std::string>{"/system/chassis/processor"}));
Matt Spinler34a904c2020-08-05 14:53:28 -0500261
Matt Spinler993168d2021-04-07 16:05:03 -0500262 EXPECT_CALL(dataIface,
263 setFunctional("/system/chassis/processor", false))
Matt Spinler34a904c2020-08-05 14:53:28 -0500264 .Times(1);
265
Sumit Kumar76198a22021-07-15 05:59:57 -0500266 EXPECT_CALL(dataIface,
267 setCriticalAssociation("/system/chassis/processor"))
268 .Times(1);
269
Matt Spinler34a904c2020-08-05 14:53:28 -0500270 auto data = pelFactory(1, 'O', 0x20, 0xA400, 500);
271 PEL pel{data};
272
273 lightPath.activate(pel);
274 }
275
Matt Spinlerbad056b2023-01-25 14:16:57 -0600276 // With the same U42 callout, have it be associated with two
277 // inventory paths
278 {
279 MockDataInterface dataIface;
280 service_indicators::LightPath lightPath{dataIface};
281
282 EXPECT_CALL(dataIface, getInventoryFromLocCode("U42", 0, true))
283 .WillOnce(Return(std::vector<std::string>{"/system/chassis/cpu0",
284 "/system/chassis/cpu1"}));
285
286 EXPECT_CALL(dataIface, setFunctional("/system/chassis/cpu0", false))
287 .Times(1);
288 EXPECT_CALL(dataIface, setFunctional("/system/chassis/cpu1", false))
289 .Times(1);
290
291 EXPECT_CALL(dataIface, setCriticalAssociation("/system/chassis/cpu0"))
292 .Times(1);
293 EXPECT_CALL(dataIface, setCriticalAssociation("/system/chassis/cpu1"))
294 .Times(1);
295
296 auto data = pelFactory(1, 'O', 0x20, 0xA400, 500);
297 PEL pel{data};
298
299 lightPath.activate(pel);
300 }
301
Matt Spinler48c44db2020-08-25 12:47:13 -0500302 // A non-info BMC PEL with no callouts will set the platform SAI LED.
303 {
304 MockDataInterface dataIface;
305 service_indicators::LightPath lightPath{dataIface};
306
307 EXPECT_CALL(dataIface,
308 assertLEDGroup("/xyz/openbmc_project/led/groups/"
309 "platform_system_attention_indicator",
310 true))
311 .Times(1);
312
313 auto data = pelDataFactory(TestPELType::pelSimple);
314 PEL pel{data};
315
316 lightPath.activate(pel);
317 }
318
319 // Make getInventoryFromLocCode fail - will set the platform SAI LED
Matt Spinler34a904c2020-08-05 14:53:28 -0500320 {
321 MockDataInterface dataIface;
322 service_indicators::LightPath lightPath{dataIface};
323
324 EXPECT_CALL(dataIface, getInventoryFromLocCode("U42", 0, true))
325 .WillOnce(Throw(std::runtime_error("Fail")));
326
Matt Spinler993168d2021-04-07 16:05:03 -0500327 EXPECT_CALL(dataIface, setFunctional).Times(0);
Matt Spinler34a904c2020-08-05 14:53:28 -0500328
Matt Spinler48c44db2020-08-25 12:47:13 -0500329 EXPECT_CALL(dataIface,
330 assertLEDGroup("/xyz/openbmc_project/led/groups/"
331 "platform_system_attention_indicator",
332 true))
333 .Times(1);
Matt Spinler34a904c2020-08-05 14:53:28 -0500334
335 auto data = pelFactory(1, 'O', 0x20, 0xA400, 500);
336 PEL pel{data};
337
338 lightPath.activate(pel);
339 }
340
Matt Spinler993168d2021-04-07 16:05:03 -0500341 // Make setFunctional fail
Matt Spinler34a904c2020-08-05 14:53:28 -0500342 {
343 MockDataInterface dataIface;
344 service_indicators::LightPath lightPath{dataIface};
345
346 EXPECT_CALL(dataIface, getInventoryFromLocCode("U42", 0, true))
Matt Spinlerbad056b2023-01-25 14:16:57 -0600347 .WillOnce(
348 Return(std::vector<std::string>{"/system/chassis/processor"}));
Matt Spinler34a904c2020-08-05 14:53:28 -0500349
Matt Spinler48c44db2020-08-25 12:47:13 -0500350 EXPECT_CALL(dataIface,
Matt Spinler993168d2021-04-07 16:05:03 -0500351 setFunctional("/system/chassis/processor", false))
Matt Spinler34a904c2020-08-05 14:53:28 -0500352 .WillOnce(Throw(std::runtime_error("Fail")));
353
354 auto data = pelFactory(1, 'O', 0x20, 0xA400, 500);
355 PEL pel{data};
356
357 lightPath.activate(pel);
358 }
Sumit Kumar76198a22021-07-15 05:59:57 -0500359
360 // Test setCriticalAssociation fail
361 {
362 MockDataInterface dataIface;
363 service_indicators::LightPath lightPath{dataIface};
364
365 EXPECT_CALL(dataIface, getInventoryFromLocCode("U42", 0, true))
Matt Spinlerbad056b2023-01-25 14:16:57 -0600366 .WillOnce(
367 Return(std::vector<std::string>{"/system/chassis/processor"}));
Sumit Kumar76198a22021-07-15 05:59:57 -0500368
369 EXPECT_CALL(dataIface,
370 setCriticalAssociation("/system/chassis/processor"))
371 .WillOnce(Throw(std::runtime_error("Fail")));
372
373 auto data = pelFactory(1, 'O', 0x20, 0xA400, 500);
374 PEL pel{data};
375
376 lightPath.activate(pel);
377 }
Matt Spinler34a904c2020-08-05 14:53:28 -0500378}