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 mock services 140 MockServices services{}; 141 142 // Expect Sensors service to be called 5+5=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).Times(10); 147 148 // Expect Journal service to be called 3+3=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 1+1=2 times to log a DBus error 155 MockErrorLogging& errorLogging = services.getMockErrorLogging(); 156 EXPECT_CALL(errorLogging, logDBusError).Times(2); 157 158 // Monitor sensors 5 times. Should fail every time, write to journal 3 159 // times, and log one error. 160 for (int i = 1; i <= 5; ++i) 161 { 162 railPtr->monitorSensors(services, system, *chassisPtr, *devicePtr); 163 } 164 165 // Clear error history 166 railPtr->clearErrorHistory(); 167 168 // Monitor sensors 5 times again. Should fail every time, write to journal 169 // 3 times, and log one error. 170 for (int i = 1; i <= 5; ++i) 171 { 172 railPtr->monitorSensors(services, system, *chassisPtr, *devicePtr); 173 } 174 } 175 176 TEST(RailTests, Configure) 177 { 178 // Test where Configuration was not specified in constructor 179 { 180 // Create mock services. No logging should occur. 181 MockServices services{}; 182 MockJournal& journal = services.getMockJournal(); 183 EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0); 184 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0); 185 186 // Create Rail 187 std::unique_ptr<Rail> rail = std::make_unique<Rail>("vdd0"); 188 Rail* railPtr = rail.get(); 189 190 // Create Device that contains Rail 191 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface = 192 std::make_unique<i2c::MockedI2CInterface>(); 193 std::unique_ptr<PresenceDetection> presenceDetection{}; 194 std::unique_ptr<Configuration> deviceConfiguration{}; 195 std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{}; 196 std::vector<std::unique_ptr<Rail>> rails{}; 197 rails.emplace_back(std::move(rail)); 198 std::unique_ptr<Device> device = std::make_unique<Device>( 199 "reg1", true, 200 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1", 201 std::move(i2cInterface), std::move(presenceDetection), 202 std::move(deviceConfiguration), std::move(phaseFaultDetection), 203 std::move(rails)); 204 Device* devicePtr = device.get(); 205 206 // Create Chassis that contains Device 207 std::vector<std::unique_ptr<Device>> devices{}; 208 devices.emplace_back(std::move(device)); 209 std::unique_ptr<Chassis> chassis = 210 std::make_unique<Chassis>(1, chassisInvPath, std::move(devices)); 211 Chassis* chassisPtr = chassis.get(); 212 213 // Create System that contains Chassis 214 std::vector<std::unique_ptr<Rule>> rules{}; 215 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 216 chassisVec.emplace_back(std::move(chassis)); 217 System system{std::move(rules), std::move(chassisVec)}; 218 219 // Call configure(). 220 railPtr->configure(services, system, *chassisPtr, *devicePtr); 221 } 222 223 // Test where Configuration was specified in constructor 224 { 225 // Create mock services. Expect logDebug() to be called. 226 MockServices services{}; 227 MockJournal& journal = services.getMockJournal(); 228 EXPECT_CALL(journal, logDebug("Configuring vddr1: volts=1.300000")) 229 .Times(1); 230 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0); 231 232 // Create Configuration 233 std::optional<double> volts{1.3}; 234 std::unique_ptr<MockAction> action = std::make_unique<MockAction>(); 235 EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true)); 236 std::vector<std::unique_ptr<Action>> actions{}; 237 actions.emplace_back(std::move(action)); 238 std::unique_ptr<Configuration> configuration = 239 std::make_unique<Configuration>(volts, std::move(actions)); 240 241 // Create Rail 242 std::unique_ptr<Rail> rail = 243 std::make_unique<Rail>("vddr1", std::move(configuration)); 244 Rail* railPtr = rail.get(); 245 246 // Create Device that contains Rail 247 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface = 248 std::make_unique<i2c::MockedI2CInterface>(); 249 std::unique_ptr<PresenceDetection> presenceDetection{}; 250 std::unique_ptr<Configuration> deviceConfiguration{}; 251 std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{}; 252 std::vector<std::unique_ptr<Rail>> rails{}; 253 rails.emplace_back(std::move(rail)); 254 std::unique_ptr<Device> device = std::make_unique<Device>( 255 "reg1", true, 256 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1", 257 std::move(i2cInterface), std::move(presenceDetection), 258 std::move(deviceConfiguration), std::move(phaseFaultDetection), 259 std::move(rails)); 260 Device* devicePtr = device.get(); 261 262 // Create Chassis that contains Device 263 std::vector<std::unique_ptr<Device>> devices{}; 264 devices.emplace_back(std::move(device)); 265 std::unique_ptr<Chassis> chassis = 266 std::make_unique<Chassis>(1, chassisInvPath, std::move(devices)); 267 Chassis* chassisPtr = chassis.get(); 268 269 // Create System that contains Chassis 270 std::vector<std::unique_ptr<Rule>> rules{}; 271 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 272 chassisVec.emplace_back(std::move(chassis)); 273 System system{std::move(rules), std::move(chassisVec)}; 274 275 // Call configure(). 276 railPtr->configure(services, system, *chassisPtr, *devicePtr); 277 } 278 } 279 280 TEST(RailTests, GetConfiguration) 281 { 282 // Test where Configuration was not specified in constructor 283 { 284 Rail rail{"vdd0"}; 285 EXPECT_EQ(rail.getConfiguration(), nullptr); 286 } 287 288 // Test where Configuration was specified in constructor 289 { 290 // Create Configuration 291 std::optional<double> volts{3.2}; 292 std::vector<std::unique_ptr<Action>> actions{}; 293 actions.push_back(std::make_unique<MockAction>()); 294 std::unique_ptr<Configuration> configuration = 295 std::make_unique<Configuration>(volts, std::move(actions)); 296 297 // Create Rail 298 Rail rail{"vddr1", std::move(configuration)}; 299 EXPECT_NE(rail.getConfiguration(), nullptr); 300 EXPECT_EQ(rail.getConfiguration()->getVolts().has_value(), true); 301 EXPECT_EQ(rail.getConfiguration()->getVolts().value(), 3.2); 302 EXPECT_EQ(rail.getConfiguration()->getActions().size(), 1); 303 } 304 } 305 306 TEST(RailTests, GetID) 307 { 308 Rail rail{"vio2"}; 309 EXPECT_EQ(rail.getID(), "vio2"); 310 } 311 312 TEST(RailTests, MonitorSensors) 313 { 314 // Test where SensorMonitoring was not specified in constructor 315 { 316 // Create mock services. No Sensors methods should be called. 317 MockServices services{}; 318 MockSensors& sensors = services.getMockSensors(); 319 EXPECT_CALL(sensors, startRail).Times(0); 320 EXPECT_CALL(sensors, setValue).Times(0); 321 EXPECT_CALL(sensors, endRail).Times(0); 322 323 // Create Rail 324 std::unique_ptr<Rail> rail = std::make_unique<Rail>("vdd0"); 325 Rail* railPtr = rail.get(); 326 327 // Create Device that contains Rail 328 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface = 329 std::make_unique<i2c::MockedI2CInterface>(); 330 std::unique_ptr<PresenceDetection> presenceDetection{}; 331 std::unique_ptr<Configuration> deviceConfiguration{}; 332 std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{}; 333 std::vector<std::unique_ptr<Rail>> rails{}; 334 rails.emplace_back(std::move(rail)); 335 std::unique_ptr<Device> device = std::make_unique<Device>( 336 "reg1", true, 337 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1", 338 std::move(i2cInterface), std::move(presenceDetection), 339 std::move(deviceConfiguration), std::move(phaseFaultDetection), 340 std::move(rails)); 341 Device* devicePtr = device.get(); 342 343 // Create Chassis that contains Device 344 std::vector<std::unique_ptr<Device>> devices{}; 345 devices.emplace_back(std::move(device)); 346 std::unique_ptr<Chassis> chassis = 347 std::make_unique<Chassis>(1, chassisInvPath, std::move(devices)); 348 Chassis* chassisPtr = chassis.get(); 349 350 // Create System that contains Chassis 351 std::vector<std::unique_ptr<Rule>> rules{}; 352 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 353 chassisVec.emplace_back(std::move(chassis)); 354 System system{std::move(rules), std::move(chassisVec)}; 355 356 // Call monitorSensors() 357 railPtr->monitorSensors(services, system, *chassisPtr, *devicePtr); 358 } 359 360 // Test where SensorMonitoring was specified in constructor 361 { 362 // Create mock services. Set Sensors service expectations. 363 MockServices services{}; 364 MockSensors& sensors = services.getMockSensors(); 365 EXPECT_CALL(sensors, 366 startRail("vddr1", 367 "/xyz/openbmc_project/inventory/system/chassis/" 368 "motherboard/reg1", 369 chassisInvPath)) 370 .Times(1); 371 EXPECT_CALL(sensors, setValue).Times(0); 372 EXPECT_CALL(sensors, endRail(false)).Times(1); 373 374 // Create SensorMonitoring 375 std::unique_ptr<MockAction> action = std::make_unique<MockAction>(); 376 EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true)); 377 std::vector<std::unique_ptr<Action>> actions{}; 378 actions.emplace_back(std::move(action)); 379 std::unique_ptr<SensorMonitoring> sensorMonitoring = 380 std::make_unique<SensorMonitoring>(std::move(actions)); 381 382 // Create Rail 383 std::unique_ptr<Configuration> configuration{}; 384 std::unique_ptr<Rail> rail = std::make_unique<Rail>( 385 "vddr1", std::move(configuration), std::move(sensorMonitoring)); 386 Rail* railPtr = rail.get(); 387 388 // Create Device that contains Rail 389 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface = 390 std::make_unique<i2c::MockedI2CInterface>(); 391 std::unique_ptr<PresenceDetection> presenceDetection{}; 392 std::unique_ptr<Configuration> deviceConfiguration{}; 393 std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{}; 394 std::vector<std::unique_ptr<Rail>> rails{}; 395 rails.emplace_back(std::move(rail)); 396 std::unique_ptr<Device> device = std::make_unique<Device>( 397 "reg1", true, 398 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1", 399 std::move(i2cInterface), std::move(presenceDetection), 400 std::move(deviceConfiguration), std::move(phaseFaultDetection), 401 std::move(rails)); 402 Device* devicePtr = device.get(); 403 404 // Create Chassis that contains Device 405 std::vector<std::unique_ptr<Device>> devices{}; 406 devices.emplace_back(std::move(device)); 407 std::unique_ptr<Chassis> chassis = 408 std::make_unique<Chassis>(1, chassisInvPath, std::move(devices)); 409 Chassis* chassisPtr = chassis.get(); 410 411 // Create System that contains Chassis 412 std::vector<std::unique_ptr<Rule>> rules{}; 413 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 414 chassisVec.emplace_back(std::move(chassis)); 415 System system{std::move(rules), std::move(chassisVec)}; 416 417 // Call monitorSensors() 418 railPtr->monitorSensors(services, system, *chassisPtr, *devicePtr); 419 } 420 } 421 422 TEST(RailTests, GetSensorMonitoring) 423 { 424 // Test where SensorMonitoring was not specified in constructor 425 { 426 Rail rail{"vdd0", nullptr, nullptr}; 427 EXPECT_EQ(rail.getSensorMonitoring(), nullptr); 428 } 429 430 // Test where SensorMonitoring was specified in constructor 431 { 432 std::unique_ptr<Configuration> configuration{}; 433 434 // Create SensorMonitoring 435 std::vector<std::unique_ptr<Action>> actions{}; 436 actions.push_back(std::make_unique<MockAction>()); 437 actions.push_back(std::make_unique<MockAction>()); 438 std::unique_ptr<SensorMonitoring> sensorMonitoring = 439 std::make_unique<SensorMonitoring>(std::move(actions)); 440 441 // Create Rail 442 Rail rail{"vddr1", std::move(configuration), 443 std::move(sensorMonitoring)}; 444 EXPECT_NE(rail.getSensorMonitoring(), nullptr); 445 EXPECT_EQ(rail.getSensorMonitoring()->getActions().size(), 2); 446 } 447 } 448