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