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