1 /** 2 * Copyright © 2019 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 "mock_action.hpp" 22 #include "mock_error_logging.hpp" 23 #include "mock_journal.hpp" 24 #include "mock_sensors.hpp" 25 #include "mock_services.hpp" 26 #include "mocked_i2c_interface.hpp" 27 #include "phase_fault_detection.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 "system.hpp" 34 #include "test_sdbus_error.hpp" 35 36 #include <memory> 37 #include <optional> 38 #include <utility> 39 #include <vector> 40 41 #include <gmock/gmock.h> 42 #include <gtest/gtest.h> 43 44 using namespace phosphor::power::regulators; 45 46 using ::testing::A; 47 using ::testing::Return; 48 using ::testing::Throw; 49 using ::testing::TypedEq; 50 51 static const std::string chassisInvPath{ 52 "/xyz/openbmc_project/inventory/system/chassis"}; 53 54 TEST(RailTests, Constructor) 55 { 56 // Test where only required parameters are specified 57 { 58 Rail rail{"vdd0"}; 59 EXPECT_EQ(rail.getID(), "vdd0"); 60 EXPECT_EQ(rail.getConfiguration(), nullptr); 61 EXPECT_EQ(rail.getSensorMonitoring(), nullptr); 62 } 63 64 // Test where all parameters are specified 65 { 66 // Create Configuration 67 std::optional<double> volts{1.3}; 68 std::vector<std::unique_ptr<Action>> actions{}; 69 actions.push_back(std::make_unique<MockAction>()); 70 actions.push_back(std::make_unique<MockAction>()); 71 std::unique_ptr<Configuration> configuration = 72 std::make_unique<Configuration>(volts, std::move(actions)); 73 74 // Create SensorMonitoring 75 actions.clear(); 76 actions.push_back(std::make_unique<MockAction>()); 77 std::unique_ptr<SensorMonitoring> sensorMonitoring = 78 std::make_unique<SensorMonitoring>(std::move(actions)); 79 80 // Create Rail 81 Rail rail{"vddr1", std::move(configuration), 82 std::move(sensorMonitoring)}; 83 EXPECT_EQ(rail.getID(), "vddr1"); 84 EXPECT_NE(rail.getConfiguration(), nullptr); 85 EXPECT_EQ(rail.getConfiguration()->getVolts().has_value(), true); 86 EXPECT_EQ(rail.getConfiguration()->getVolts().value(), 1.3); 87 EXPECT_EQ(rail.getConfiguration()->getActions().size(), 2); 88 EXPECT_NE(rail.getSensorMonitoring(), nullptr); 89 EXPECT_EQ(rail.getSensorMonitoring()->getActions().size(), 1); 90 } 91 } 92 93 TEST(RailTests, ClearErrorHistory) 94 { 95 // Create SensorMonitoring. Will fail with a DBus exception. 96 std::unique_ptr<MockAction> action = std::make_unique<MockAction>(); 97 EXPECT_CALL(*action, execute) 98 .WillRepeatedly(Throw(TestSDBusError{"Unable to set sensor value"})); 99 std::vector<std::unique_ptr<Action>> actions{}; 100 actions.emplace_back(std::move(action)); 101 std::unique_ptr<SensorMonitoring> sensorMonitoring = 102 std::make_unique<SensorMonitoring>(std::move(actions)); 103 104 // Create Rail 105 std::unique_ptr<Configuration> configuration{}; 106 std::unique_ptr<Rail> rail = std::make_unique<Rail>( 107 "vddr1", std::move(configuration), std::move(sensorMonitoring)); 108 Rail* railPtr = rail.get(); 109 110 // Create Device that contains Rail 111 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface = 112 std::make_unique<i2c::MockedI2CInterface>(); 113 std::unique_ptr<PresenceDetection> presenceDetection{}; 114 std::unique_ptr<Configuration> deviceConfiguration{}; 115 std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{}; 116 std::vector<std::unique_ptr<Rail>> rails{}; 117 rails.emplace_back(std::move(rail)); 118 std::unique_ptr<Device> device = std::make_unique<Device>( 119 "reg1", true, 120 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1", 121 std::move(i2cInterface), std::move(presenceDetection), 122 std::move(deviceConfiguration), std::move(phaseFaultDetection), 123 std::move(rails)); 124 Device* devicePtr = device.get(); 125 126 // Create Chassis that contains Device 127 std::vector<std::unique_ptr<Device>> devices{}; 128 devices.emplace_back(std::move(device)); 129 std::unique_ptr<Chassis> chassis = 130 std::make_unique<Chassis>(1, chassisInvPath, std::move(devices)); 131 Chassis* chassisPtr = chassis.get(); 132 133 // Create System that contains Chassis 134 std::vector<std::unique_ptr<Rule>> rules{}; 135 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 136 chassisVec.emplace_back(std::move(chassis)); 137 System system{std::move(rules), std::move(chassisVec)}; 138 139 // Create lambda that sets MockServices expectations. The lambda allows 140 // us to set expectations multiple times without duplicate code. 141 auto setExpectations = [](MockServices& services) { 142 // Expect Sensors service to be called 10 times 143 MockSensors& sensors = services.getMockSensors(); 144 EXPECT_CALL(sensors, startRail).Times(10); 145 EXPECT_CALL(sensors, setValue).Times(0); 146 EXPECT_CALL(sensors, endRail(true)).Times(10); 147 148 // Expect Journal service to be called 6 times to log error messages 149 MockJournal& journal = services.getMockJournal(); 150 EXPECT_CALL(journal, logError(A<const std::vector<std::string>&>())) 151 .Times(6); 152 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(6); 153 154 // Expect ErrorLogging service to be called once to log a DBus error 155 MockErrorLogging& errorLogging = services.getMockErrorLogging(); 156 EXPECT_CALL(errorLogging, logDBusError).Times(1); 157 }; 158 159 // Monitor sensors 10 times. Verify errors logged. 160 { 161 // Create mock services. Set expectations via lambda. 162 MockServices services{}; 163 setExpectations(services); 164 165 for (int i = 1; i <= 10; ++i) 166 { 167 railPtr->monitorSensors(services, system, *chassisPtr, *devicePtr); 168 } 169 } 170 171 // Clear error history 172 railPtr->clearErrorHistory(); 173 174 // Monitor sensors 10 more times. Verify errors logged again. 175 { 176 // Create mock services. Set expectations via lambda. 177 MockServices services{}; 178 setExpectations(services); 179 180 for (int i = 1; i <= 10; ++i) 181 { 182 railPtr->monitorSensors(services, system, *chassisPtr, *devicePtr); 183 } 184 } 185 } 186 187 TEST(RailTests, Configure) 188 { 189 // Test where Configuration was not specified in constructor 190 { 191 // Create mock services. No logging should occur. 192 MockServices services{}; 193 MockJournal& journal = services.getMockJournal(); 194 EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0); 195 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0); 196 197 // Create Rail 198 std::unique_ptr<Rail> rail = std::make_unique<Rail>("vdd0"); 199 Rail* railPtr = rail.get(); 200 201 // Create Device that contains Rail 202 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface = 203 std::make_unique<i2c::MockedI2CInterface>(); 204 std::unique_ptr<PresenceDetection> presenceDetection{}; 205 std::unique_ptr<Configuration> deviceConfiguration{}; 206 std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{}; 207 std::vector<std::unique_ptr<Rail>> rails{}; 208 rails.emplace_back(std::move(rail)); 209 std::unique_ptr<Device> device = std::make_unique<Device>( 210 "reg1", true, 211 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1", 212 std::move(i2cInterface), std::move(presenceDetection), 213 std::move(deviceConfiguration), std::move(phaseFaultDetection), 214 std::move(rails)); 215 Device* devicePtr = device.get(); 216 217 // Create Chassis that contains Device 218 std::vector<std::unique_ptr<Device>> devices{}; 219 devices.emplace_back(std::move(device)); 220 std::unique_ptr<Chassis> chassis = 221 std::make_unique<Chassis>(1, chassisInvPath, std::move(devices)); 222 Chassis* chassisPtr = chassis.get(); 223 224 // Create System that contains Chassis 225 std::vector<std::unique_ptr<Rule>> rules{}; 226 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 227 chassisVec.emplace_back(std::move(chassis)); 228 System system{std::move(rules), std::move(chassisVec)}; 229 230 // Call configure(). 231 railPtr->configure(services, system, *chassisPtr, *devicePtr); 232 } 233 234 // Test where Configuration was specified in constructor 235 { 236 // Create mock services. Expect logDebug() to be called. 237 MockServices services{}; 238 MockJournal& journal = services.getMockJournal(); 239 EXPECT_CALL(journal, logDebug("Configuring vddr1: volts=1.300000")) 240 .Times(1); 241 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0); 242 243 // Create Configuration 244 std::optional<double> volts{1.3}; 245 std::unique_ptr<MockAction> action = std::make_unique<MockAction>(); 246 EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true)); 247 std::vector<std::unique_ptr<Action>> actions{}; 248 actions.emplace_back(std::move(action)); 249 std::unique_ptr<Configuration> configuration = 250 std::make_unique<Configuration>(volts, std::move(actions)); 251 252 // Create Rail 253 std::unique_ptr<Rail> rail = 254 std::make_unique<Rail>("vddr1", std::move(configuration)); 255 Rail* railPtr = rail.get(); 256 257 // Create Device that contains Rail 258 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface = 259 std::make_unique<i2c::MockedI2CInterface>(); 260 std::unique_ptr<PresenceDetection> presenceDetection{}; 261 std::unique_ptr<Configuration> deviceConfiguration{}; 262 std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{}; 263 std::vector<std::unique_ptr<Rail>> rails{}; 264 rails.emplace_back(std::move(rail)); 265 std::unique_ptr<Device> device = std::make_unique<Device>( 266 "reg1", true, 267 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1", 268 std::move(i2cInterface), std::move(presenceDetection), 269 std::move(deviceConfiguration), std::move(phaseFaultDetection), 270 std::move(rails)); 271 Device* devicePtr = device.get(); 272 273 // Create Chassis that contains Device 274 std::vector<std::unique_ptr<Device>> devices{}; 275 devices.emplace_back(std::move(device)); 276 std::unique_ptr<Chassis> chassis = 277 std::make_unique<Chassis>(1, chassisInvPath, std::move(devices)); 278 Chassis* chassisPtr = chassis.get(); 279 280 // Create System that contains Chassis 281 std::vector<std::unique_ptr<Rule>> rules{}; 282 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 283 chassisVec.emplace_back(std::move(chassis)); 284 System system{std::move(rules), std::move(chassisVec)}; 285 286 // Call configure(). 287 railPtr->configure(services, system, *chassisPtr, *devicePtr); 288 } 289 } 290 291 TEST(RailTests, GetConfiguration) 292 { 293 // Test where Configuration was not specified in constructor 294 { 295 Rail rail{"vdd0"}; 296 EXPECT_EQ(rail.getConfiguration(), nullptr); 297 } 298 299 // Test where Configuration was specified in constructor 300 { 301 // Create Configuration 302 std::optional<double> volts{3.2}; 303 std::vector<std::unique_ptr<Action>> actions{}; 304 actions.push_back(std::make_unique<MockAction>()); 305 std::unique_ptr<Configuration> configuration = 306 std::make_unique<Configuration>(volts, std::move(actions)); 307 308 // Create Rail 309 Rail rail{"vddr1", std::move(configuration)}; 310 EXPECT_NE(rail.getConfiguration(), nullptr); 311 EXPECT_EQ(rail.getConfiguration()->getVolts().has_value(), true); 312 EXPECT_EQ(rail.getConfiguration()->getVolts().value(), 3.2); 313 EXPECT_EQ(rail.getConfiguration()->getActions().size(), 1); 314 } 315 } 316 317 TEST(RailTests, GetID) 318 { 319 Rail rail{"vio2"}; 320 EXPECT_EQ(rail.getID(), "vio2"); 321 } 322 323 TEST(RailTests, MonitorSensors) 324 { 325 // Test where SensorMonitoring was not specified in constructor 326 { 327 // Create mock services. No Sensors methods should be called. 328 MockServices services{}; 329 MockSensors& sensors = services.getMockSensors(); 330 EXPECT_CALL(sensors, startRail).Times(0); 331 EXPECT_CALL(sensors, setValue).Times(0); 332 EXPECT_CALL(sensors, endRail).Times(0); 333 334 // Create Rail 335 std::unique_ptr<Rail> rail = std::make_unique<Rail>("vdd0"); 336 Rail* railPtr = rail.get(); 337 338 // Create Device that contains Rail 339 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface = 340 std::make_unique<i2c::MockedI2CInterface>(); 341 std::unique_ptr<PresenceDetection> presenceDetection{}; 342 std::unique_ptr<Configuration> deviceConfiguration{}; 343 std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{}; 344 std::vector<std::unique_ptr<Rail>> rails{}; 345 rails.emplace_back(std::move(rail)); 346 std::unique_ptr<Device> device = std::make_unique<Device>( 347 "reg1", true, 348 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1", 349 std::move(i2cInterface), std::move(presenceDetection), 350 std::move(deviceConfiguration), std::move(phaseFaultDetection), 351 std::move(rails)); 352 Device* devicePtr = device.get(); 353 354 // Create Chassis that contains Device 355 std::vector<std::unique_ptr<Device>> devices{}; 356 devices.emplace_back(std::move(device)); 357 std::unique_ptr<Chassis> chassis = 358 std::make_unique<Chassis>(1, chassisInvPath, std::move(devices)); 359 Chassis* chassisPtr = chassis.get(); 360 361 // Create System that contains Chassis 362 std::vector<std::unique_ptr<Rule>> rules{}; 363 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 364 chassisVec.emplace_back(std::move(chassis)); 365 System system{std::move(rules), std::move(chassisVec)}; 366 367 // Call monitorSensors() 368 railPtr->monitorSensors(services, system, *chassisPtr, *devicePtr); 369 } 370 371 // Test where SensorMonitoring was specified in constructor 372 { 373 // Create mock services. Set Sensors service expectations. 374 MockServices services{}; 375 MockSensors& sensors = services.getMockSensors(); 376 EXPECT_CALL(sensors, 377 startRail("vddr1", 378 "/xyz/openbmc_project/inventory/system/chassis/" 379 "motherboard/reg1", 380 chassisInvPath)) 381 .Times(1); 382 EXPECT_CALL(sensors, setValue).Times(0); 383 EXPECT_CALL(sensors, endRail(false)).Times(1); 384 385 // Create SensorMonitoring 386 std::unique_ptr<MockAction> action = std::make_unique<MockAction>(); 387 EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true)); 388 std::vector<std::unique_ptr<Action>> actions{}; 389 actions.emplace_back(std::move(action)); 390 std::unique_ptr<SensorMonitoring> sensorMonitoring = 391 std::make_unique<SensorMonitoring>(std::move(actions)); 392 393 // Create Rail 394 std::unique_ptr<Configuration> configuration{}; 395 std::unique_ptr<Rail> rail = std::make_unique<Rail>( 396 "vddr1", std::move(configuration), std::move(sensorMonitoring)); 397 Rail* railPtr = rail.get(); 398 399 // Create Device that contains Rail 400 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface = 401 std::make_unique<i2c::MockedI2CInterface>(); 402 std::unique_ptr<PresenceDetection> presenceDetection{}; 403 std::unique_ptr<Configuration> deviceConfiguration{}; 404 std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{}; 405 std::vector<std::unique_ptr<Rail>> rails{}; 406 rails.emplace_back(std::move(rail)); 407 std::unique_ptr<Device> device = std::make_unique<Device>( 408 "reg1", true, 409 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1", 410 std::move(i2cInterface), std::move(presenceDetection), 411 std::move(deviceConfiguration), std::move(phaseFaultDetection), 412 std::move(rails)); 413 Device* devicePtr = device.get(); 414 415 // Create Chassis that contains Device 416 std::vector<std::unique_ptr<Device>> devices{}; 417 devices.emplace_back(std::move(device)); 418 std::unique_ptr<Chassis> chassis = 419 std::make_unique<Chassis>(1, chassisInvPath, std::move(devices)); 420 Chassis* chassisPtr = chassis.get(); 421 422 // Create System that contains Chassis 423 std::vector<std::unique_ptr<Rule>> rules{}; 424 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 425 chassisVec.emplace_back(std::move(chassis)); 426 System system{std::move(rules), std::move(chassisVec)}; 427 428 // Call monitorSensors() 429 railPtr->monitorSensors(services, system, *chassisPtr, *devicePtr); 430 } 431 } 432 433 TEST(RailTests, GetSensorMonitoring) 434 { 435 // Test where SensorMonitoring was not specified in constructor 436 { 437 Rail rail{"vdd0", nullptr, nullptr}; 438 EXPECT_EQ(rail.getSensorMonitoring(), nullptr); 439 } 440 441 // Test where SensorMonitoring was specified in constructor 442 { 443 std::unique_ptr<Configuration> configuration{}; 444 445 // Create SensorMonitoring 446 std::vector<std::unique_ptr<Action>> actions{}; 447 actions.push_back(std::make_unique<MockAction>()); 448 actions.push_back(std::make_unique<MockAction>()); 449 std::unique_ptr<SensorMonitoring> sensorMonitoring = 450 std::make_unique<SensorMonitoring>(std::move(actions)); 451 452 // Create Rail 453 Rail rail{"vddr1", std::move(configuration), 454 std::move(sensorMonitoring)}; 455 EXPECT_NE(rail.getSensorMonitoring(), nullptr); 456 EXPECT_EQ(rail.getSensorMonitoring()->getActions().size(), 2); 457 } 458 } 459