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