xref: /openbmc/phosphor-logging/test/openpower-pels/service_indicators_test.cpp (revision 40fb54935ce7367636a7156039396ee91cc4d5e2)
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