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, 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 285 // Make getInventoryFromLocCode fail 286 { 287 MockDataInterface dataIface; 288 service_indicators::LightPath lightPath{dataIface}; 289 290 EXPECT_CALL(dataIface, getInventoryFromLocCode("U42", 0, true)) 291 .WillOnce(Throw(std::runtime_error("Fail"))); 292 293 EXPECT_CALL(dataIface, getFaultLEDGroup(_)).Times(0); 294 295 EXPECT_CALL(dataIface, assertLEDGroup(_, true)).Times(0); 296 297 auto data = pelFactory(1, 'O', 0x20, 0xA400, 500); 298 PEL pel{data}; 299 300 lightPath.activate(pel); 301 } 302 303 // Make getFaultLEDGroup fail 304 { 305 MockDataInterface dataIface; 306 service_indicators::LightPath lightPath{dataIface}; 307 308 EXPECT_CALL(dataIface, getInventoryFromLocCode("U42", 0, true)) 309 .WillOnce(Return("/system/chassis/processor")); 310 311 EXPECT_CALL(dataIface, getFaultLEDGroup("/system/chassis/processor")) 312 .WillOnce(Throw(std::runtime_error("Fail"))); 313 314 EXPECT_CALL(dataIface, assertLEDGroup(_, true)).Times(0); 315 316 auto data = pelFactory(1, 'O', 0x20, 0xA400, 500); 317 PEL pel{data}; 318 319 lightPath.activate(pel); 320 } 321 322 // Make assertLEDGroup fail 323 { 324 MockDataInterface dataIface; 325 service_indicators::LightPath lightPath{dataIface}; 326 327 EXPECT_CALL(dataIface, getInventoryFromLocCode("U42", 0, true)) 328 .WillOnce(Return("/system/chassis/processor")); 329 330 EXPECT_CALL(dataIface, getFaultLEDGroup("/system/chassis/processor")) 331 .WillOnce(Return("/led/groups/cpu0")); 332 333 EXPECT_CALL(dataIface, assertLEDGroup("/led/groups/cpu0", true)) 334 .WillOnce(Throw(std::runtime_error("Fail"))); 335 336 auto data = pelFactory(1, 'O', 0x20, 0xA400, 500); 337 PEL pel{data}; 338 339 lightPath.activate(pel); 340 } 341 } 342