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 std::unique_ptr<PresenceDetection> presenceDetection = 89 std::make_unique<PresenceDetection>(std::move(actions)); 90 PresenceDetection* presenceDetectionPtr = presenceDetection.get(); 91 92 // Create Device that contains PresenceDetection 93 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface(); 94 std::unique_ptr<Device> 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 std::unique_ptr<Chassis> 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 std::unique_ptr<MockAction> 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 std::unique_ptr<SensorMonitoring> sensorMonitoring = 134 std::make_unique<SensorMonitoring>(std::move(actions)); 135 136 // Create Rail 137 std::unique_ptr<Configuration> configuration{}; 138 std::unique_ptr<Rail> rail = std::make_unique<Rail>( 139 "vddr1", std::move(configuration), std::move(sensorMonitoring)); 140 141 // Create Device that contains Rail 142 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface = 143 std::make_unique<i2c::MockedI2CInterface>(); 144 std::unique_ptr<PresenceDetection> presenceDetection{}; 145 std::unique_ptr<Configuration> deviceConfiguration{}; 146 std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{}; 147 std::vector<std::unique_ptr<Rail>> rails{}; 148 rails.emplace_back(std::move(rail)); 149 std::unique_ptr<Device> device = std::make_unique<Device>( 150 "reg1", true, 151 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1", 152 std::move(i2cInterface), std::move(presenceDetection), 153 std::move(deviceConfiguration), std::move(phaseFaultDetection), 154 std::move(rails)); 155 156 // Create Chassis that contains Device 157 std::vector<std::unique_ptr<Device>> devices{}; 158 devices.emplace_back(std::move(device)); 159 std::unique_ptr<Chassis> chassis = 160 std::make_unique<Chassis>(1, chassisInvPath, std::move(devices)); 161 162 // Create System that contains Chassis 163 std::vector<std::unique_ptr<Rule>> rules{}; 164 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 165 chassisVec.emplace_back(std::move(chassis)); 166 System system{std::move(rules), std::move(chassisVec)}; 167 168 // Create mock services 169 MockServices services{}; 170 171 // Expect Sensors service to be called 5+5=10 times 172 MockSensors& sensors = services.getMockSensors(); 173 EXPECT_CALL(sensors, startRail).Times(10); 174 EXPECT_CALL(sensors, setValue).Times(0); 175 EXPECT_CALL(sensors, endRail).Times(10); 176 177 // Expect Journal service to be called 3+3=6 times to log error messages 178 MockJournal& journal = services.getMockJournal(); 179 EXPECT_CALL(journal, logError(A<const std::vector<std::string>&>())) 180 .Times(6); 181 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(6); 182 183 // Expect ErrorLogging service to be called 1+1=2 times to log a DBus error 184 MockErrorLogging& errorLogging = services.getMockErrorLogging(); 185 EXPECT_CALL(errorLogging, logDBusError).Times(2); 186 187 // Monitor sensors 5 times. Should fail every time, write to journal 3 188 // times, and log one error. 189 for (int i = 1; i <= 5; ++i) 190 { 191 system.monitorSensors(services); 192 } 193 194 // Clear error history 195 system.clearErrorHistory(); 196 197 // Monitor sensors 5 times again. Should fail every time, write to journal 198 // 3 times, and log one error. 199 for (int i = 1; i <= 5; ++i) 200 { 201 system.monitorSensors(services); 202 } 203 } 204 205 TEST(SystemTests, CloseDevices) 206 { 207 // Specify an empty rules vector 208 std::vector<std::unique_ptr<Rule>> rules{}; 209 210 // Create mock services. Expect logDebug() to be called. 211 MockServices services{}; 212 MockJournal& journal = services.getMockJournal(); 213 EXPECT_CALL(journal, logDebug("Closing devices in chassis 1")).Times(1); 214 EXPECT_CALL(journal, logDebug("Closing devices in chassis 3")).Times(1); 215 EXPECT_CALL(journal, logInfo(A<const std::string&>())).Times(0); 216 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0); 217 218 // Create Chassis 219 std::vector<std::unique_ptr<Chassis>> chassis{}; 220 chassis.emplace_back(std::make_unique<Chassis>(1, chassisInvPath + '1')); 221 chassis.emplace_back(std::make_unique<Chassis>(3, chassisInvPath + '3')); 222 223 // Create System 224 System system{std::move(rules), std::move(chassis)}; 225 226 // Call closeDevices() 227 system.closeDevices(services); 228 } 229 230 TEST(SystemTests, Configure) 231 { 232 // Create mock services. Expect logInfo() to be called. 233 MockServices services{}; 234 MockJournal& journal = services.getMockJournal(); 235 EXPECT_CALL(journal, logInfo("Configuring chassis 1")).Times(1); 236 EXPECT_CALL(journal, logInfo("Configuring chassis 3")).Times(1); 237 EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0); 238 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0); 239 240 // Specify an empty rules vector 241 std::vector<std::unique_ptr<Rule>> rules{}; 242 243 // Create Chassis 244 std::vector<std::unique_ptr<Chassis>> chassis{}; 245 chassis.emplace_back(std::make_unique<Chassis>(1, chassisInvPath + '1')); 246 chassis.emplace_back(std::make_unique<Chassis>(3, chassisInvPath + '3')); 247 248 // Create System 249 System system{std::move(rules), std::move(chassis)}; 250 251 // Call configure() 252 system.configure(services); 253 } 254 255 TEST(SystemTests, GetChassis) 256 { 257 // Specify an empty rules vector 258 std::vector<std::unique_ptr<Rule>> rules{}; 259 260 // Create Chassis 261 std::vector<std::unique_ptr<Chassis>> chassis{}; 262 chassis.emplace_back(std::make_unique<Chassis>(1, chassisInvPath + '1')); 263 chassis.emplace_back(std::make_unique<Chassis>(3, chassisInvPath + '3')); 264 265 // Create System 266 System system{std::move(rules), std::move(chassis)}; 267 EXPECT_EQ(system.getChassis().size(), 2); 268 EXPECT_EQ(system.getChassis()[0]->getNumber(), 1); 269 EXPECT_EQ(system.getChassis()[1]->getNumber(), 3); 270 } 271 272 TEST(SystemTests, GetIDMap) 273 { 274 // Create Rules 275 std::vector<std::unique_ptr<Rule>> rules{}; 276 rules.emplace_back(createRule("set_voltage_rule")); 277 rules.emplace_back(createRule("read_sensors_rule")); 278 279 // Create Chassis 280 std::vector<std::unique_ptr<Chassis>> chassis{}; 281 { 282 // Chassis 1 283 std::vector<std::unique_ptr<Device>> devices{}; 284 devices.emplace_back(createDevice("reg1", {"rail1"})); 285 devices.emplace_back(createDevice("reg2", {"rail2a", "rail2b"})); 286 chassis.emplace_back(std::make_unique<Chassis>(1, chassisInvPath + '1', 287 std::move(devices))); 288 } 289 { 290 // Chassis 2 291 std::vector<std::unique_ptr<Device>> devices{}; 292 devices.emplace_back(createDevice("reg3", {"rail3a", "rail3b"})); 293 devices.emplace_back(createDevice("reg4")); 294 chassis.emplace_back(std::make_unique<Chassis>(2, chassisInvPath + '2', 295 std::move(devices))); 296 } 297 298 // Create System 299 System system{std::move(rules), std::move(chassis)}; 300 const IDMap& idMap = system.getIDMap(); 301 302 // Verify all Rules are in the IDMap 303 EXPECT_NO_THROW(idMap.getRule("set_voltage_rule")); 304 EXPECT_NO_THROW(idMap.getRule("read_sensors_rule")); 305 EXPECT_THROW(idMap.getRule("set_voltage_rule2"), std::invalid_argument); 306 307 // Verify all Devices are in the IDMap 308 EXPECT_NO_THROW(idMap.getDevice("reg1")); 309 EXPECT_NO_THROW(idMap.getDevice("reg2")); 310 EXPECT_NO_THROW(idMap.getDevice("reg3")); 311 EXPECT_NO_THROW(idMap.getDevice("reg4")); 312 EXPECT_THROW(idMap.getDevice("reg5"), std::invalid_argument); 313 314 // Verify all Rails are in the IDMap 315 EXPECT_NO_THROW(idMap.getRail("rail1")); 316 EXPECT_NO_THROW(idMap.getRail("rail2a")); 317 EXPECT_NO_THROW(idMap.getRail("rail2b")); 318 EXPECT_NO_THROW(idMap.getRail("rail3a")); 319 EXPECT_NO_THROW(idMap.getRail("rail3b")); 320 EXPECT_THROW(idMap.getRail("rail4"), std::invalid_argument); 321 } 322 323 TEST(SystemTests, GetRules) 324 { 325 // Create Rules 326 std::vector<std::unique_ptr<Rule>> rules{}; 327 rules.emplace_back(createRule("set_voltage_rule")); 328 rules.emplace_back(createRule("read_sensors_rule")); 329 330 // Create Chassis 331 std::vector<std::unique_ptr<Chassis>> chassis{}; 332 chassis.emplace_back(std::make_unique<Chassis>(1, chassisInvPath)); 333 334 // Create System 335 System system{std::move(rules), std::move(chassis)}; 336 EXPECT_EQ(system.getRules().size(), 2); 337 EXPECT_EQ(system.getRules()[0]->getID(), "set_voltage_rule"); 338 EXPECT_EQ(system.getRules()[1]->getID(), "read_sensors_rule"); 339 } 340 341 TEST(SystemTests, MonitorSensors) 342 { 343 // Create mock services. Set Sensors service expectations. 344 MockServices services{}; 345 MockSensors& sensors = services.getMockSensors(); 346 EXPECT_CALL(sensors, startRail("c1_vdd0", 347 "/xyz/openbmc_project/inventory/system/" 348 "chassis1/motherboard/vdd0_reg", 349 chassisInvPath + '1')) 350 .Times(1); 351 EXPECT_CALL(sensors, startRail("c2_vdd0", 352 "/xyz/openbmc_project/inventory/system/" 353 "chassis2/motherboard/vdd0_reg", 354 chassisInvPath + '2')) 355 .Times(1); 356 EXPECT_CALL(sensors, setValue).Times(0); 357 EXPECT_CALL(sensors, endRail(false)).Times(2); 358 359 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 360 361 // Create Chassis 1 362 { 363 // Create SensorMonitoring for Rail 364 std::unique_ptr<MockAction> action = std::make_unique<MockAction>(); 365 EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true)); 366 std::vector<std::unique_ptr<Action>> actions{}; 367 actions.emplace_back(std::move(action)); 368 std::unique_ptr<SensorMonitoring> sensorMonitoring = 369 std::make_unique<SensorMonitoring>(std::move(actions)); 370 371 // Create Rail 372 std::unique_ptr<Configuration> configuration{}; 373 std::unique_ptr<Rail> rail = std::make_unique<Rail>( 374 "c1_vdd0", std::move(configuration), std::move(sensorMonitoring)); 375 376 // Create Device 377 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface(); 378 std::unique_ptr<PresenceDetection> presenceDetection{}; 379 std::unique_ptr<Configuration> deviceConfiguration{}; 380 std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{}; 381 std::vector<std::unique_ptr<Rail>> rails{}; 382 rails.emplace_back(std::move(rail)); 383 std::unique_ptr<Device> device = std::make_unique<Device>( 384 "c1_vdd0_reg", true, 385 "/xyz/openbmc_project/inventory/system/chassis1/motherboard/" 386 "vdd0_reg", 387 std::move(i2cInterface), std::move(presenceDetection), 388 std::move(deviceConfiguration), std::move(phaseFaultDetection), 389 std::move(rails)); 390 391 // Create Chassis 392 std::vector<std::unique_ptr<Device>> devices{}; 393 devices.emplace_back(std::move(device)); 394 std::unique_ptr<Chassis> chassis = std::make_unique<Chassis>( 395 1, chassisInvPath + '1', std::move(devices)); 396 chassisVec.emplace_back(std::move(chassis)); 397 } 398 399 // Create Chassis 2 400 { 401 // Create SensorMonitoring for Rail 402 std::unique_ptr<MockAction> action = std::make_unique<MockAction>(); 403 EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true)); 404 std::vector<std::unique_ptr<Action>> actions{}; 405 actions.emplace_back(std::move(action)); 406 std::unique_ptr<SensorMonitoring> sensorMonitoring = 407 std::make_unique<SensorMonitoring>(std::move(actions)); 408 409 // Create Rail 410 std::unique_ptr<Configuration> configuration{}; 411 std::unique_ptr<Rail> rail = std::make_unique<Rail>( 412 "c2_vdd0", std::move(configuration), std::move(sensorMonitoring)); 413 414 // Create Device 415 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface(); 416 std::unique_ptr<PresenceDetection> presenceDetection{}; 417 std::unique_ptr<Configuration> deviceConfiguration{}; 418 std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{}; 419 std::vector<std::unique_ptr<Rail>> rails{}; 420 rails.emplace_back(std::move(rail)); 421 std::unique_ptr<Device> device = std::make_unique<Device>( 422 "c2_vdd0_reg", true, 423 "/xyz/openbmc_project/inventory/system/chassis2/motherboard/" 424 "vdd0_reg", 425 std::move(i2cInterface), std::move(presenceDetection), 426 std::move(deviceConfiguration), std::move(phaseFaultDetection), 427 std::move(rails)); 428 429 // Create Chassis 430 std::vector<std::unique_ptr<Device>> devices{}; 431 devices.emplace_back(std::move(device)); 432 std::unique_ptr<Chassis> chassis = std::make_unique<Chassis>( 433 2, chassisInvPath + '2', std::move(devices)); 434 chassisVec.emplace_back(std::move(chassis)); 435 } 436 437 // Create System that contains Chassis 438 std::vector<std::unique_ptr<Rule>> rules{}; 439 System system{std::move(rules), std::move(chassisVec)}; 440 441 // Call monitorSensors() 442 system.monitorSensors(services); 443 } 444