1 // SPDX-License-Identifier: Apache-2.0
2 // SPDX-FileCopyrightText: Copyright 2020 IBM Corporation
3
4 #include "extensions/openpower-pels/service_indicators.hpp"
5 #include "mocks.hpp"
6 #include "pel_utils.hpp"
7
8 #include <gtest/gtest.h>
9
10 using namespace openpower::pels;
11 using CalloutVector = std::vector<std::unique_ptr<src::Callout>>;
12 using ::testing::_;
13 using ::testing::Return;
14 using ::testing::Throw;
15
16 // Test the ignore() function works
TEST(ServiceIndicatorsTest,IgnoreTest)17 TEST(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.
TEST(ServiceIndicatorsTest,OneCalloutPriorityTest)45 TEST(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.
TEST(ServiceIndicatorsTest,OneCalloutTypeTest)76 TEST(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).
TEST(ServiceIndicatorsTest,CalloutGroupingTest)127 TEST(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
TEST(ServiceIndicatorsTest,CalloutMixedTypesTest)190 TEST(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 }
248
249 // Test the activate() function
TEST(ServiceIndicatorsTest,ActivateTest)250 TEST(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))
259 .WillOnce(
260 Return(std::vector<std::string>{"/system/chassis/processor"}));
261
262 EXPECT_CALL(dataIface,
263 setFunctional("/system/chassis/processor", false))
264 .Times(1);
265
266 EXPECT_CALL(dataIface,
267 setCriticalAssociation("/system/chassis/processor"))
268 .Times(1);
269
270 auto data = pelFactory(1, 'O', 0x20, 0xA400, 500);
271 PEL pel{data};
272
273 lightPath.activate(pel);
274 }
275
276 // 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
302 // 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
320 {
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
327 EXPECT_CALL(dataIface, setFunctional).Times(0);
328
329 EXPECT_CALL(dataIface,
330 assertLEDGroup("/xyz/openbmc_project/led/groups/"
331 "platform_system_attention_indicator",
332 true))
333 .Times(1);
334
335 auto data = pelFactory(1, 'O', 0x20, 0xA400, 500);
336 PEL pel{data};
337
338 lightPath.activate(pel);
339 }
340
341 // Make setFunctional fail
342 {
343 MockDataInterface dataIface;
344 service_indicators::LightPath lightPath{dataIface};
345
346 EXPECT_CALL(dataIface, getInventoryFromLocCode("U42", 0, true))
347 .WillOnce(
348 Return(std::vector<std::string>{"/system/chassis/processor"}));
349
350 EXPECT_CALL(dataIface,
351 setFunctional("/system/chassis/processor", false))
352 .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 }
359
360 // Test setCriticalAssociation fail
361 {
362 MockDataInterface dataIface;
363 service_indicators::LightPath lightPath{dataIface};
364
365 EXPECT_CALL(dataIface, getInventoryFromLocCode("U42", 0, true))
366 .WillOnce(
367 Return(std::vector<std::string>{"/system/chassis/processor"}));
368
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 }
378 }
379