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