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( 272 Return(std::vector<std::string>{"/system/chassis/processor"})); 273 274 EXPECT_CALL(dataIface, 275 setFunctional("/system/chassis/processor", false)) 276 .Times(1); 277 278 EXPECT_CALL(dataIface, 279 setCriticalAssociation("/system/chassis/processor")) 280 .Times(1); 281 282 auto data = pelFactory(1, 'O', 0x20, 0xA400, 500); 283 PEL pel{data}; 284 285 lightPath.activate(pel); 286 } 287 288 // With the same U42 callout, have it be associated with two 289 // inventory paths 290 { 291 MockDataInterface dataIface; 292 service_indicators::LightPath lightPath{dataIface}; 293 294 EXPECT_CALL(dataIface, getInventoryFromLocCode("U42", 0, true)) 295 .WillOnce(Return(std::vector<std::string>{"/system/chassis/cpu0", 296 "/system/chassis/cpu1"})); 297 298 EXPECT_CALL(dataIface, setFunctional("/system/chassis/cpu0", false)) 299 .Times(1); 300 EXPECT_CALL(dataIface, setFunctional("/system/chassis/cpu1", false)) 301 .Times(1); 302 303 EXPECT_CALL(dataIface, setCriticalAssociation("/system/chassis/cpu0")) 304 .Times(1); 305 EXPECT_CALL(dataIface, setCriticalAssociation("/system/chassis/cpu1")) 306 .Times(1); 307 308 auto data = pelFactory(1, 'O', 0x20, 0xA400, 500); 309 PEL pel{data}; 310 311 lightPath.activate(pel); 312 } 313 314 // A non-info BMC PEL with no callouts will set the platform SAI LED. 315 { 316 MockDataInterface dataIface; 317 service_indicators::LightPath lightPath{dataIface}; 318 319 EXPECT_CALL(dataIface, 320 assertLEDGroup("/xyz/openbmc_project/led/groups/" 321 "platform_system_attention_indicator", 322 true)) 323 .Times(1); 324 325 auto data = pelDataFactory(TestPELType::pelSimple); 326 PEL pel{data}; 327 328 lightPath.activate(pel); 329 } 330 331 // Make getInventoryFromLocCode fail - will set the platform SAI LED 332 { 333 MockDataInterface dataIface; 334 service_indicators::LightPath lightPath{dataIface}; 335 336 EXPECT_CALL(dataIface, getInventoryFromLocCode("U42", 0, true)) 337 .WillOnce(Throw(std::runtime_error("Fail"))); 338 339 EXPECT_CALL(dataIface, setFunctional).Times(0); 340 341 EXPECT_CALL(dataIface, 342 assertLEDGroup("/xyz/openbmc_project/led/groups/" 343 "platform_system_attention_indicator", 344 true)) 345 .Times(1); 346 347 auto data = pelFactory(1, 'O', 0x20, 0xA400, 500); 348 PEL pel{data}; 349 350 lightPath.activate(pel); 351 } 352 353 // Make setFunctional fail 354 { 355 MockDataInterface dataIface; 356 service_indicators::LightPath lightPath{dataIface}; 357 358 EXPECT_CALL(dataIface, getInventoryFromLocCode("U42", 0, true)) 359 .WillOnce( 360 Return(std::vector<std::string>{"/system/chassis/processor"})); 361 362 EXPECT_CALL(dataIface, 363 setFunctional("/system/chassis/processor", false)) 364 .WillOnce(Throw(std::runtime_error("Fail"))); 365 366 auto data = pelFactory(1, 'O', 0x20, 0xA400, 500); 367 PEL pel{data}; 368 369 lightPath.activate(pel); 370 } 371 372 // Test setCriticalAssociation fail 373 { 374 MockDataInterface dataIface; 375 service_indicators::LightPath lightPath{dataIface}; 376 377 EXPECT_CALL(dataIface, getInventoryFromLocCode("U42", 0, true)) 378 .WillOnce( 379 Return(std::vector<std::string>{"/system/chassis/processor"})); 380 381 EXPECT_CALL(dataIface, 382 setCriticalAssociation("/system/chassis/processor")) 383 .WillOnce(Throw(std::runtime_error("Fail"))); 384 385 auto data = pelFactory(1, 'O', 0x20, 0xA400, 500); 386 PEL pel{data}; 387 388 lightPath.activate(pel); 389 } 390 } 391