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 "action.hpp" 17 #include "chassis.hpp" 18 #include "configuration.hpp" 19 #include "device.hpp" 20 #include "i2c_interface.hpp" 21 #include "id_map.hpp" 22 #include "log_phase_fault_action.hpp" 23 #include "mock_action.hpp" 24 #include "mock_error_logging.hpp" 25 #include "mock_journal.hpp" 26 #include "mock_sensors.hpp" 27 #include "mock_services.hpp" 28 #include "mocked_i2c_interface.hpp" 29 #include "phase_fault.hpp" 30 #include "phase_fault_detection.hpp" 31 #include "presence_detection.hpp" 32 #include "rail.hpp" 33 #include "rule.hpp" 34 #include "sensor_monitoring.hpp" 35 #include "sensors.hpp" 36 #include "services.hpp" 37 #include "system.hpp" 38 #include "test_sdbus_error.hpp" 39 #include "test_utils.hpp" 40 41 #include <memory> 42 #include <stdexcept> 43 #include <string> 44 #include <utility> 45 #include <vector> 46 47 #include <gmock/gmock.h> 48 #include <gtest/gtest.h> 49 50 using namespace phosphor::power::regulators; 51 using namespace phosphor::power::regulators::test_utils; 52 53 using ::testing::A; 54 using ::testing::Return; 55 using ::testing::Throw; 56 using ::testing::TypedEq; 57 58 static const std::string chassisInvPath{ 59 "/xyz/openbmc_project/inventory/system/chassis"}; 60 61 TEST(SystemTests, Constructor) 62 { 63 // Create Rules 64 std::vector<std::unique_ptr<Rule>> rules{}; 65 rules.emplace_back(createRule("set_voltage_rule")); 66 67 // Create Chassis 68 std::vector<std::unique_ptr<Chassis>> chassis{}; 69 std::vector<std::unique_ptr<Device>> devices{}; 70 devices.emplace_back(createDevice("reg1", {"rail1"})); 71 chassis.emplace_back( 72 std::make_unique<Chassis>(1, chassisInvPath, std::move(devices))); 73 74 // Create System 75 System system{std::move(rules), std::move(chassis)}; 76 EXPECT_EQ(system.getChassis().size(), 1); 77 EXPECT_EQ(system.getChassis()[0]->getNumber(), 1); 78 EXPECT_NO_THROW(system.getIDMap().getRule("set_voltage_rule")); 79 EXPECT_NO_THROW(system.getIDMap().getDevice("reg1")); 80 EXPECT_NO_THROW(system.getIDMap().getRail("rail1")); 81 EXPECT_THROW(system.getIDMap().getRail("rail2"), std::invalid_argument); 82 EXPECT_EQ(system.getRules().size(), 1); 83 EXPECT_EQ(system.getRules()[0]->getID(), "set_voltage_rule"); 84 } 85 86 TEST(SystemTests, ClearCache) 87 { 88 // Create PresenceDetection 89 std::vector<std::unique_ptr<Action>> actions{}; 90 auto presenceDetection = 91 std::make_unique<PresenceDetection>(std::move(actions)); 92 PresenceDetection* presenceDetectionPtr = presenceDetection.get(); 93 94 // Create Device that contains PresenceDetection 95 auto i2cInterface = std::make_unique<i2c::MockedI2CInterface>(); 96 auto device = std::make_unique<Device>( 97 "reg1", true, 98 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1", 99 std::move(i2cInterface), std::move(presenceDetection)); 100 Device* devicePtr = device.get(); 101 102 // Create Chassis that contains Device 103 std::vector<std::unique_ptr<Device>> devices{}; 104 devices.emplace_back(std::move(device)); 105 auto chassis = 106 std::make_unique<Chassis>(1, chassisInvPath, std::move(devices)); 107 Chassis* chassisPtr = chassis.get(); 108 109 // Create System that contains Chassis 110 std::vector<std::unique_ptr<Rule>> rules{}; 111 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 112 chassisVec.emplace_back(std::move(chassis)); 113 System system{std::move(rules), std::move(chassisVec)}; 114 115 // Cache presence value in PresenceDetection 116 MockServices services{}; 117 presenceDetectionPtr->execute(services, system, *chassisPtr, *devicePtr); 118 EXPECT_TRUE(presenceDetectionPtr->getCachedPresence().has_value()); 119 120 // Clear cached data in System 121 system.clearCache(); 122 123 // Verify presence value no longer cached in PresenceDetection 124 EXPECT_FALSE(presenceDetectionPtr->getCachedPresence().has_value()); 125 } 126 127 TEST(SystemTests, ClearErrorHistory) 128 { 129 // Create SensorMonitoring. Will fail with a DBus exception. 130 auto action = std::make_unique<MockAction>(); 131 EXPECT_CALL(*action, execute) 132 .WillRepeatedly(Throw(TestSDBusError{"Unable to set sensor value"})); 133 std::vector<std::unique_ptr<Action>> actions{}; 134 actions.emplace_back(std::move(action)); 135 auto sensorMonitoring = 136 std::make_unique<SensorMonitoring>(std::move(actions)); 137 138 // Create Rail 139 std::unique_ptr<Configuration> configuration{}; 140 auto rail = std::make_unique<Rail>("vddr1", std::move(configuration), 141 std::move(sensorMonitoring)); 142 143 // Create Device that contains Rail 144 auto i2cInterface = std::make_unique<i2c::MockedI2CInterface>(); 145 std::unique_ptr<PresenceDetection> presenceDetection{}; 146 std::unique_ptr<Configuration> deviceConfiguration{}; 147 std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{}; 148 std::vector<std::unique_ptr<Rail>> rails{}; 149 rails.emplace_back(std::move(rail)); 150 auto device = std::make_unique<Device>( 151 "reg1", true, 152 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1", 153 std::move(i2cInterface), std::move(presenceDetection), 154 std::move(deviceConfiguration), std::move(phaseFaultDetection), 155 std::move(rails)); 156 157 // Create Chassis that contains Device 158 std::vector<std::unique_ptr<Device>> devices{}; 159 devices.emplace_back(std::move(device)); 160 auto chassis = 161 std::make_unique<Chassis>(1, chassisInvPath, std::move(devices)); 162 163 // Create System that contains Chassis 164 std::vector<std::unique_ptr<Rule>> rules{}; 165 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 166 chassisVec.emplace_back(std::move(chassis)); 167 System system{std::move(rules), std::move(chassisVec)}; 168 169 // Create mock services 170 MockServices services{}; 171 172 // Expect Sensors service to be called 5+5=10 times 173 MockSensors& sensors = services.getMockSensors(); 174 EXPECT_CALL(sensors, startRail).Times(10); 175 EXPECT_CALL(sensors, setValue).Times(0); 176 EXPECT_CALL(sensors, endRail).Times(10); 177 178 // Expect Journal service to be called 3+3=6 times to log error messages 179 MockJournal& journal = services.getMockJournal(); 180 EXPECT_CALL(journal, logError(A<const std::vector<std::string>&>())) 181 .Times(6); 182 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(6); 183 184 // Expect ErrorLogging service to be called 1+1=2 times to log a DBus error 185 MockErrorLogging& errorLogging = services.getMockErrorLogging(); 186 EXPECT_CALL(errorLogging, logDBusError).Times(2); 187 188 // Monitor sensors 5 times. Should fail every time, write to journal 3 189 // times, and log one error. 190 for (int i = 1; i <= 5; ++i) 191 { 192 system.monitorSensors(services); 193 } 194 195 // Clear error history 196 system.clearErrorHistory(); 197 198 // Monitor sensors 5 times again. Should fail every time, write to journal 199 // 3 times, and log one error. 200 for (int i = 1; i <= 5; ++i) 201 { 202 system.monitorSensors(services); 203 } 204 } 205 206 TEST(SystemTests, CloseDevices) 207 { 208 // Specify an empty rules vector 209 std::vector<std::unique_ptr<Rule>> rules{}; 210 211 // Create mock services. Expect logDebug() to be called. 212 MockServices services{}; 213 MockJournal& journal = services.getMockJournal(); 214 EXPECT_CALL(journal, logDebug("Closing devices in chassis 1")).Times(1); 215 EXPECT_CALL(journal, logDebug("Closing devices in chassis 3")).Times(1); 216 EXPECT_CALL(journal, logInfo(A<const std::string&>())).Times(0); 217 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0); 218 219 // Create Chassis 220 std::vector<std::unique_ptr<Chassis>> chassis{}; 221 chassis.emplace_back(std::make_unique<Chassis>(1, chassisInvPath + '1')); 222 chassis.emplace_back(std::make_unique<Chassis>(3, chassisInvPath + '3')); 223 224 // Create System 225 System system{std::move(rules), std::move(chassis)}; 226 227 // Call closeDevices() 228 system.closeDevices(services); 229 } 230 231 TEST(SystemTests, Configure) 232 { 233 // Create mock services. Expect logInfo() to be called. 234 MockServices services{}; 235 MockJournal& journal = services.getMockJournal(); 236 EXPECT_CALL(journal, logInfo("Configuring chassis 1")).Times(1); 237 EXPECT_CALL(journal, logInfo("Configuring chassis 3")).Times(1); 238 EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0); 239 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0); 240 241 // Specify an empty rules vector 242 std::vector<std::unique_ptr<Rule>> rules{}; 243 244 // Create Chassis 245 std::vector<std::unique_ptr<Chassis>> chassis{}; 246 chassis.emplace_back(std::make_unique<Chassis>(1, chassisInvPath + '1')); 247 chassis.emplace_back(std::make_unique<Chassis>(3, chassisInvPath + '3')); 248 249 // Create System 250 System system{std::move(rules), std::move(chassis)}; 251 252 // Call configure() 253 system.configure(services); 254 } 255 256 TEST(SystemTests, DetectPhaseFaults) 257 { 258 // Create mock services with the following expectations: 259 // - 2 error messages in journal for N phase fault detected in reg0 260 // - 2 error messages in journal for N phase fault detected in reg1 261 // - 1 N phase fault error logged for reg0 262 // - 1 N phase fault error logged for reg1 263 MockServices services{}; 264 MockJournal& journal = services.getMockJournal(); 265 EXPECT_CALL(journal, 266 logError("n phase fault detected in regulator reg0: count=1")) 267 .Times(1); 268 EXPECT_CALL(journal, 269 logError("n phase fault detected in regulator reg0: count=2")) 270 .Times(1); 271 EXPECT_CALL(journal, 272 logError("n phase fault detected in regulator reg1: count=1")) 273 .Times(1); 274 EXPECT_CALL(journal, 275 logError("n phase fault detected in regulator reg1: count=2")) 276 .Times(1); 277 MockErrorLogging& errorLogging = services.getMockErrorLogging(); 278 EXPECT_CALL(errorLogging, logPhaseFault).Times(2); 279 280 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 281 282 // Create Chassis 1 with regulator reg0 283 { 284 // Create PhaseFaultDetection 285 auto action = std::make_unique<LogPhaseFaultAction>(PhaseFaultType::n); 286 std::vector<std::unique_ptr<Action>> actions{}; 287 actions.push_back(std::move(action)); 288 auto phaseFaultDetection = 289 std::make_unique<PhaseFaultDetection>(std::move(actions)); 290 291 // Create Device 292 auto i2cInterface = std::make_unique<i2c::MockedI2CInterface>(); 293 std::unique_ptr<PresenceDetection> presenceDetection{}; 294 std::unique_ptr<Configuration> configuration{}; 295 auto device = std::make_unique<Device>( 296 "reg0", true, 297 "/xyz/openbmc_project/inventory/system/chassis1/motherboard/" 298 "reg0", 299 std::move(i2cInterface), std::move(presenceDetection), 300 std::move(configuration), std::move(phaseFaultDetection)); 301 302 // Create Chassis 303 std::vector<std::unique_ptr<Device>> devices{}; 304 devices.emplace_back(std::move(device)); 305 auto chassis = std::make_unique<Chassis>(1, chassisInvPath + '1', 306 std::move(devices)); 307 chassisVec.emplace_back(std::move(chassis)); 308 } 309 310 // Create Chassis 2 with regulator reg1 311 { 312 // Create PhaseFaultDetection 313 auto action = std::make_unique<LogPhaseFaultAction>(PhaseFaultType::n); 314 std::vector<std::unique_ptr<Action>> actions{}; 315 actions.push_back(std::move(action)); 316 auto phaseFaultDetection = 317 std::make_unique<PhaseFaultDetection>(std::move(actions)); 318 319 // Create Device 320 auto i2cInterface = std::make_unique<i2c::MockedI2CInterface>(); 321 std::unique_ptr<PresenceDetection> presenceDetection{}; 322 std::unique_ptr<Configuration> configuration{}; 323 auto device = std::make_unique<Device>( 324 "reg1", true, 325 "/xyz/openbmc_project/inventory/system/chassis2/motherboard/" 326 "reg1", 327 std::move(i2cInterface), std::move(presenceDetection), 328 std::move(configuration), std::move(phaseFaultDetection)); 329 330 // Create Chassis 331 std::vector<std::unique_ptr<Device>> devices{}; 332 devices.emplace_back(std::move(device)); 333 auto chassis = std::make_unique<Chassis>(2, chassisInvPath + '2', 334 std::move(devices)); 335 chassisVec.emplace_back(std::move(chassis)); 336 } 337 338 // Create System that contains Chassis 339 std::vector<std::unique_ptr<Rule>> rules{}; 340 System system{std::move(rules), std::move(chassisVec)}; 341 342 // Call detectPhaseFaults() 5 times 343 for (int i = 1; i <= 5; ++i) 344 { 345 system.detectPhaseFaults(services); 346 } 347 } 348 349 TEST(SystemTests, GetChassis) 350 { 351 // Specify an empty rules vector 352 std::vector<std::unique_ptr<Rule>> rules{}; 353 354 // Create Chassis 355 std::vector<std::unique_ptr<Chassis>> chassis{}; 356 chassis.emplace_back(std::make_unique<Chassis>(1, chassisInvPath + '1')); 357 chassis.emplace_back(std::make_unique<Chassis>(3, chassisInvPath + '3')); 358 359 // Create System 360 System system{std::move(rules), std::move(chassis)}; 361 EXPECT_EQ(system.getChassis().size(), 2); 362 EXPECT_EQ(system.getChassis()[0]->getNumber(), 1); 363 EXPECT_EQ(system.getChassis()[1]->getNumber(), 3); 364 } 365 366 TEST(SystemTests, GetIDMap) 367 { 368 // Create Rules 369 std::vector<std::unique_ptr<Rule>> rules{}; 370 rules.emplace_back(createRule("set_voltage_rule")); 371 rules.emplace_back(createRule("read_sensors_rule")); 372 373 // Create Chassis 374 std::vector<std::unique_ptr<Chassis>> chassis{}; 375 { 376 // Chassis 1 377 std::vector<std::unique_ptr<Device>> devices{}; 378 devices.emplace_back(createDevice("reg1", {"rail1"})); 379 devices.emplace_back(createDevice("reg2", {"rail2a", "rail2b"})); 380 chassis.emplace_back(std::make_unique<Chassis>(1, chassisInvPath + '1', 381 std::move(devices))); 382 } 383 { 384 // Chassis 2 385 std::vector<std::unique_ptr<Device>> devices{}; 386 devices.emplace_back(createDevice("reg3", {"rail3a", "rail3b"})); 387 devices.emplace_back(createDevice("reg4")); 388 chassis.emplace_back(std::make_unique<Chassis>(2, chassisInvPath + '2', 389 std::move(devices))); 390 } 391 392 // Create System 393 System system{std::move(rules), std::move(chassis)}; 394 const IDMap& idMap = system.getIDMap(); 395 396 // Verify all Rules are in the IDMap 397 EXPECT_NO_THROW(idMap.getRule("set_voltage_rule")); 398 EXPECT_NO_THROW(idMap.getRule("read_sensors_rule")); 399 EXPECT_THROW(idMap.getRule("set_voltage_rule2"), std::invalid_argument); 400 401 // Verify all Devices are in the IDMap 402 EXPECT_NO_THROW(idMap.getDevice("reg1")); 403 EXPECT_NO_THROW(idMap.getDevice("reg2")); 404 EXPECT_NO_THROW(idMap.getDevice("reg3")); 405 EXPECT_NO_THROW(idMap.getDevice("reg4")); 406 EXPECT_THROW(idMap.getDevice("reg5"), std::invalid_argument); 407 408 // Verify all Rails are in the IDMap 409 EXPECT_NO_THROW(idMap.getRail("rail1")); 410 EXPECT_NO_THROW(idMap.getRail("rail2a")); 411 EXPECT_NO_THROW(idMap.getRail("rail2b")); 412 EXPECT_NO_THROW(idMap.getRail("rail3a")); 413 EXPECT_NO_THROW(idMap.getRail("rail3b")); 414 EXPECT_THROW(idMap.getRail("rail4"), std::invalid_argument); 415 } 416 417 TEST(SystemTests, GetRules) 418 { 419 // Create Rules 420 std::vector<std::unique_ptr<Rule>> rules{}; 421 rules.emplace_back(createRule("set_voltage_rule")); 422 rules.emplace_back(createRule("read_sensors_rule")); 423 424 // Create Chassis 425 std::vector<std::unique_ptr<Chassis>> chassis{}; 426 chassis.emplace_back(std::make_unique<Chassis>(1, chassisInvPath)); 427 428 // Create System 429 System system{std::move(rules), std::move(chassis)}; 430 EXPECT_EQ(system.getRules().size(), 2); 431 EXPECT_EQ(system.getRules()[0]->getID(), "set_voltage_rule"); 432 EXPECT_EQ(system.getRules()[1]->getID(), "read_sensors_rule"); 433 } 434 435 TEST(SystemTests, MonitorSensors) 436 { 437 // Create mock services. Set Sensors service expectations. 438 MockServices services{}; 439 MockSensors& sensors = services.getMockSensors(); 440 EXPECT_CALL(sensors, startRail("c1_vdd0", 441 "/xyz/openbmc_project/inventory/system/" 442 "chassis1/motherboard/vdd0_reg", 443 chassisInvPath + '1')) 444 .Times(1); 445 EXPECT_CALL(sensors, startRail("c2_vdd0", 446 "/xyz/openbmc_project/inventory/system/" 447 "chassis2/motherboard/vdd0_reg", 448 chassisInvPath + '2')) 449 .Times(1); 450 EXPECT_CALL(sensors, setValue).Times(0); 451 EXPECT_CALL(sensors, endRail(false)).Times(2); 452 453 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 454 455 // Create Chassis 1 456 { 457 // Create SensorMonitoring for Rail 458 auto action = std::make_unique<MockAction>(); 459 EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true)); 460 std::vector<std::unique_ptr<Action>> actions{}; 461 actions.emplace_back(std::move(action)); 462 auto sensorMonitoring = 463 std::make_unique<SensorMonitoring>(std::move(actions)); 464 465 // Create Rail 466 std::unique_ptr<Configuration> configuration{}; 467 auto rail = std::make_unique<Rail>("c1_vdd0", std::move(configuration), 468 std::move(sensorMonitoring)); 469 470 // Create Device 471 auto i2cInterface = std::make_unique<i2c::MockedI2CInterface>(); 472 std::unique_ptr<PresenceDetection> presenceDetection{}; 473 std::unique_ptr<Configuration> deviceConfiguration{}; 474 std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{}; 475 std::vector<std::unique_ptr<Rail>> rails{}; 476 rails.emplace_back(std::move(rail)); 477 auto device = std::make_unique<Device>( 478 "c1_vdd0_reg", true, 479 "/xyz/openbmc_project/inventory/system/chassis1/motherboard/" 480 "vdd0_reg", 481 std::move(i2cInterface), std::move(presenceDetection), 482 std::move(deviceConfiguration), std::move(phaseFaultDetection), 483 std::move(rails)); 484 485 // Create Chassis 486 std::vector<std::unique_ptr<Device>> devices{}; 487 devices.emplace_back(std::move(device)); 488 auto chassis = std::make_unique<Chassis>(1, chassisInvPath + '1', 489 std::move(devices)); 490 chassisVec.emplace_back(std::move(chassis)); 491 } 492 493 // Create Chassis 2 494 { 495 // Create SensorMonitoring for Rail 496 auto action = std::make_unique<MockAction>(); 497 EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true)); 498 std::vector<std::unique_ptr<Action>> actions{}; 499 actions.emplace_back(std::move(action)); 500 auto sensorMonitoring = 501 std::make_unique<SensorMonitoring>(std::move(actions)); 502 503 // Create Rail 504 std::unique_ptr<Configuration> configuration{}; 505 auto rail = std::make_unique<Rail>("c2_vdd0", std::move(configuration), 506 std::move(sensorMonitoring)); 507 508 // Create Device 509 auto i2cInterface = std::make_unique<i2c::MockedI2CInterface>(); 510 std::unique_ptr<PresenceDetection> presenceDetection{}; 511 std::unique_ptr<Configuration> deviceConfiguration{}; 512 std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{}; 513 std::vector<std::unique_ptr<Rail>> rails{}; 514 rails.emplace_back(std::move(rail)); 515 auto device = std::make_unique<Device>( 516 "c2_vdd0_reg", true, 517 "/xyz/openbmc_project/inventory/system/chassis2/motherboard/" 518 "vdd0_reg", 519 std::move(i2cInterface), std::move(presenceDetection), 520 std::move(deviceConfiguration), std::move(phaseFaultDetection), 521 std::move(rails)); 522 523 // Create Chassis 524 std::vector<std::unique_ptr<Device>> devices{}; 525 devices.emplace_back(std::move(device)); 526 auto chassis = std::make_unique<Chassis>(2, chassisInvPath + '2', 527 std::move(devices)); 528 chassisVec.emplace_back(std::move(chassis)); 529 } 530 531 // Create System that contains Chassis 532 std::vector<std::unique_ptr<Rule>> rules{}; 533 System system{std::move(rules), std::move(chassisVec)}; 534 535 // Call monitorSensors() 536 system.monitorSensors(services); 537 } 538