1 /** 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 22 using namespace openpower::pels; 23 using CalloutVector = std::vector<std::unique_ptr<src::Callout>>; 24 using ::testing::_; 25 using ::testing::Return; 26 using ::testing::Throw; 27 28 // Test the ignore() function works 29 TEST(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. 57 TEST(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. 88 TEST(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). 139 TEST(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 202 TEST(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 } 260 261 // Test the activate() function 262 TEST(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, 274 setFunctional("/system/chassis/processor", false)) 275 .Times(1); 276 277 EXPECT_CALL(dataIface, 278 setCriticalAssociation("/system/chassis/processor")) 279 .Times(1); 280 281 auto data = pelFactory(1, 'O', 0x20, 0xA400, 500); 282 PEL pel{data}; 283 284 lightPath.activate(pel); 285 } 286 287 // A non-info BMC PEL with no callouts will set the platform SAI LED. 288 { 289 MockDataInterface dataIface; 290 service_indicators::LightPath lightPath{dataIface}; 291 292 EXPECT_CALL(dataIface, 293 assertLEDGroup("/xyz/openbmc_project/led/groups/" 294 "platform_system_attention_indicator", 295 true)) 296 .Times(1); 297 298 auto data = pelDataFactory(TestPELType::pelSimple); 299 PEL pel{data}; 300 301 lightPath.activate(pel); 302 } 303 304 // Make getInventoryFromLocCode fail - will set the platform SAI LED 305 { 306 MockDataInterface dataIface; 307 service_indicators::LightPath lightPath{dataIface}; 308 309 EXPECT_CALL(dataIface, getInventoryFromLocCode("U42", 0, true)) 310 .WillOnce(Throw(std::runtime_error("Fail"))); 311 312 EXPECT_CALL(dataIface, setFunctional).Times(0); 313 314 EXPECT_CALL(dataIface, 315 assertLEDGroup("/xyz/openbmc_project/led/groups/" 316 "platform_system_attention_indicator", 317 true)) 318 .Times(1); 319 320 auto data = pelFactory(1, 'O', 0x20, 0xA400, 500); 321 PEL pel{data}; 322 323 lightPath.activate(pel); 324 } 325 326 // Make setFunctional fail 327 { 328 MockDataInterface dataIface; 329 service_indicators::LightPath lightPath{dataIface}; 330 331 EXPECT_CALL(dataIface, getInventoryFromLocCode("U42", 0, true)) 332 .WillOnce(Return("/system/chassis/processor")); 333 334 EXPECT_CALL(dataIface, 335 setFunctional("/system/chassis/processor", false)) 336 .WillOnce(Throw(std::runtime_error("Fail"))); 337 338 auto data = pelFactory(1, 'O', 0x20, 0xA400, 500); 339 PEL pel{data}; 340 341 lightPath.activate(pel); 342 } 343 344 // Test setCriticalAssociation fail 345 { 346 MockDataInterface dataIface; 347 service_indicators::LightPath lightPath{dataIface}; 348 349 EXPECT_CALL(dataIface, getInventoryFromLocCode("U42", 0, true)) 350 .WillOnce(Return("/system/chassis/processor")); 351 352 EXPECT_CALL(dataIface, 353 setCriticalAssociation("/system/chassis/processor")) 354 .WillOnce(Throw(std::runtime_error("Fail"))); 355 356 auto data = pelFactory(1, 'O', 0x20, 0xA400, 500); 357 PEL pel{data}; 358 359 lightPath.activate(pel); 360 } 361 } 362