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_journal.hpp" 23 #include "mock_services.hpp" 24 #include "mocked_i2c_interface.hpp" 25 #include "pmbus_read_sensor_action.hpp" 26 #include "presence_detection.hpp" 27 #include "rail.hpp" 28 #include "rule.hpp" 29 #include "sensor_monitoring.hpp" 30 #include "sensors.hpp" 31 #include "system.hpp" 32 33 #include <memory> 34 #include <optional> 35 #include <utility> 36 #include <vector> 37 38 #include <gmock/gmock.h> 39 #include <gtest/gtest.h> 40 41 using namespace phosphor::power::regulators; 42 43 using ::testing::A; 44 using ::testing::Return; 45 using ::testing::TypedEq; 46 47 static const std::string chassisInvPath{ 48 "/xyz/openbmc_project/inventory/system/chassis"}; 49 50 TEST(RailTests, Constructor) 51 { 52 // Test where only required parameters are specified 53 { 54 Rail rail{"vdd0"}; 55 EXPECT_EQ(rail.getID(), "vdd0"); 56 EXPECT_EQ(rail.getConfiguration(), nullptr); 57 EXPECT_EQ(rail.getSensorMonitoring(), nullptr); 58 } 59 60 // Test where all parameters are specified 61 { 62 // Create Configuration 63 std::optional<double> volts{1.3}; 64 std::vector<std::unique_ptr<Action>> actions{}; 65 actions.push_back(std::make_unique<MockAction>()); 66 actions.push_back(std::make_unique<MockAction>()); 67 std::unique_ptr<Configuration> configuration = 68 std::make_unique<Configuration>(volts, std::move(actions)); 69 70 // Create SensorMonitoring 71 actions.clear(); 72 actions.push_back(std::make_unique<MockAction>()); 73 std::unique_ptr<SensorMonitoring> sensorMonitoring = 74 std::make_unique<SensorMonitoring>(std::move(actions)); 75 76 // Create Rail 77 Rail rail{"vddr1", std::move(configuration), 78 std::move(sensorMonitoring)}; 79 EXPECT_EQ(rail.getID(), "vddr1"); 80 EXPECT_NE(rail.getConfiguration(), nullptr); 81 EXPECT_EQ(rail.getConfiguration()->getVolts().has_value(), true); 82 EXPECT_EQ(rail.getConfiguration()->getVolts().value(), 1.3); 83 EXPECT_EQ(rail.getConfiguration()->getActions().size(), 2); 84 EXPECT_NE(rail.getSensorMonitoring(), nullptr); 85 EXPECT_EQ(rail.getSensorMonitoring()->getActions().size(), 1); 86 } 87 } 88 89 TEST(RailTests, Configure) 90 { 91 // Test where Configuration was not specified in constructor 92 { 93 // Create mock services. No logging should occur. 94 MockServices services{}; 95 MockJournal& journal = services.getMockJournal(); 96 EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0); 97 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0); 98 99 // Create Rail 100 std::unique_ptr<Rail> rail = std::make_unique<Rail>("vdd0"); 101 Rail* railPtr = rail.get(); 102 103 // Create Device that contains Rail 104 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface = 105 std::make_unique<i2c::MockedI2CInterface>(); 106 std::unique_ptr<PresenceDetection> presenceDetection{}; 107 std::unique_ptr<Configuration> deviceConfiguration{}; 108 std::vector<std::unique_ptr<Rail>> rails{}; 109 rails.emplace_back(std::move(rail)); 110 std::unique_ptr<Device> device = std::make_unique<Device>( 111 "reg1", true, 112 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1", 113 std::move(i2cInterface), std::move(presenceDetection), 114 std::move(deviceConfiguration), std::move(rails)); 115 Device* devicePtr = device.get(); 116 117 // Create Chassis that contains Device 118 std::vector<std::unique_ptr<Device>> devices{}; 119 devices.emplace_back(std::move(device)); 120 std::unique_ptr<Chassis> chassis = 121 std::make_unique<Chassis>(1, chassisInvPath, std::move(devices)); 122 Chassis* chassisPtr = chassis.get(); 123 124 // Create System that contains Chassis 125 std::vector<std::unique_ptr<Rule>> rules{}; 126 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 127 chassisVec.emplace_back(std::move(chassis)); 128 System system{std::move(rules), std::move(chassisVec)}; 129 130 // Call configure(). 131 railPtr->configure(services, system, *chassisPtr, *devicePtr); 132 } 133 134 // Test where Configuration was specified in constructor 135 { 136 // Create mock services. Expect logDebug() to be called. 137 MockServices services{}; 138 MockJournal& journal = services.getMockJournal(); 139 EXPECT_CALL(journal, logDebug("Configuring vddr1: volts=1.300000")) 140 .Times(1); 141 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0); 142 143 // Create Configuration 144 std::optional<double> volts{1.3}; 145 std::unique_ptr<MockAction> action = std::make_unique<MockAction>(); 146 EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true)); 147 std::vector<std::unique_ptr<Action>> actions{}; 148 actions.emplace_back(std::move(action)); 149 std::unique_ptr<Configuration> configuration = 150 std::make_unique<Configuration>(volts, std::move(actions)); 151 152 // Create Rail 153 std::unique_ptr<Rail> rail = 154 std::make_unique<Rail>("vddr1", std::move(configuration)); 155 Rail* railPtr = rail.get(); 156 157 // Create Device that contains Rail 158 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface = 159 std::make_unique<i2c::MockedI2CInterface>(); 160 std::unique_ptr<PresenceDetection> presenceDetection{}; 161 std::unique_ptr<Configuration> deviceConfiguration{}; 162 std::vector<std::unique_ptr<Rail>> rails{}; 163 rails.emplace_back(std::move(rail)); 164 std::unique_ptr<Device> device = std::make_unique<Device>( 165 "reg1", true, 166 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1", 167 std::move(i2cInterface), std::move(presenceDetection), 168 std::move(deviceConfiguration), std::move(rails)); 169 Device* devicePtr = device.get(); 170 171 // Create Chassis that contains Device 172 std::vector<std::unique_ptr<Device>> devices{}; 173 devices.emplace_back(std::move(device)); 174 std::unique_ptr<Chassis> chassis = 175 std::make_unique<Chassis>(1, chassisInvPath, std::move(devices)); 176 Chassis* chassisPtr = chassis.get(); 177 178 // Create System that contains Chassis 179 std::vector<std::unique_ptr<Rule>> rules{}; 180 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 181 chassisVec.emplace_back(std::move(chassis)); 182 System system{std::move(rules), std::move(chassisVec)}; 183 184 // Call configure(). 185 railPtr->configure(services, system, *chassisPtr, *devicePtr); 186 } 187 } 188 189 TEST(RailTests, GetConfiguration) 190 { 191 // Test where Configuration was not specified in constructor 192 { 193 Rail rail{"vdd0"}; 194 EXPECT_EQ(rail.getConfiguration(), nullptr); 195 } 196 197 // Test where Configuration was specified in constructor 198 { 199 // Create Configuration 200 std::optional<double> volts{3.2}; 201 std::vector<std::unique_ptr<Action>> actions{}; 202 actions.push_back(std::make_unique<MockAction>()); 203 std::unique_ptr<Configuration> configuration = 204 std::make_unique<Configuration>(volts, std::move(actions)); 205 206 // Create Rail 207 Rail rail{"vddr1", std::move(configuration)}; 208 EXPECT_NE(rail.getConfiguration(), nullptr); 209 EXPECT_EQ(rail.getConfiguration()->getVolts().has_value(), true); 210 EXPECT_EQ(rail.getConfiguration()->getVolts().value(), 3.2); 211 EXPECT_EQ(rail.getConfiguration()->getActions().size(), 1); 212 } 213 } 214 215 TEST(RailTests, GetID) 216 { 217 Rail rail{"vio2"}; 218 EXPECT_EQ(rail.getID(), "vio2"); 219 } 220 221 TEST(RailTests, MonitorSensors) 222 { 223 // Test where SensorMonitoring was not specified in constructor 224 { 225 // Create mock services. No logging should occur. 226 MockServices services{}; 227 MockJournal& journal = services.getMockJournal(); 228 EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0); 229 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0); 230 231 // Create mock I2CInterface. A two-byte read should NOT occur. 232 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface = 233 std::make_unique<i2c::MockedI2CInterface>(); 234 EXPECT_CALL(*i2cInterface, read(A<uint8_t>(), A<uint16_t&>())).Times(0); 235 236 // Create Rail 237 std::unique_ptr<Rail> rail = std::make_unique<Rail>("vdd0"); 238 Rail* railPtr = rail.get(); 239 240 // Create Device that contains Rail 241 std::unique_ptr<PresenceDetection> presenceDetection{}; 242 std::unique_ptr<Configuration> deviceConfiguration{}; 243 std::vector<std::unique_ptr<Rail>> rails{}; 244 rails.emplace_back(std::move(rail)); 245 std::unique_ptr<Device> device = std::make_unique<Device>( 246 "reg1", true, 247 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1", 248 std::move(i2cInterface), std::move(presenceDetection), 249 std::move(deviceConfiguration), std::move(rails)); 250 Device* devicePtr = device.get(); 251 252 // Create Chassis that contains Device 253 std::vector<std::unique_ptr<Device>> devices{}; 254 devices.emplace_back(std::move(device)); 255 std::unique_ptr<Chassis> chassis = 256 std::make_unique<Chassis>(1, chassisInvPath, std::move(devices)); 257 Chassis* chassisPtr = chassis.get(); 258 259 // Create System that contains Chassis 260 std::vector<std::unique_ptr<Rule>> rules{}; 261 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 262 chassisVec.emplace_back(std::move(chassis)); 263 System system{std::move(rules), std::move(chassisVec)}; 264 265 // Call monitorSensors(). 266 railPtr->monitorSensors(services, system, *chassisPtr, *devicePtr); 267 } 268 269 // Test where SensorMonitoring was specified in constructor 270 { 271 // Create mock services. No logging should occur. 272 MockServices services{}; 273 MockJournal& journal = services.getMockJournal(); 274 EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0); 275 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0); 276 277 // Create PMBusReadSensorAction 278 SensorType type{SensorType::iout}; 279 uint8_t command = 0x8C; 280 pmbus_utils::SensorDataFormat format{ 281 pmbus_utils::SensorDataFormat::linear_11}; 282 std::optional<int8_t> exponent{}; 283 std::unique_ptr<PMBusReadSensorAction> action = 284 std::make_unique<PMBusReadSensorAction>(type, command, format, 285 exponent); 286 287 // Create mock I2CInterface. A two-byte read should occur. 288 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface = 289 std::make_unique<i2c::MockedI2CInterface>(); 290 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true)); 291 EXPECT_CALL(*i2cInterface, read(TypedEq<uint8_t>(0x8C), A<uint16_t&>())) 292 .Times(1); 293 294 // Create SensorMonitoring 295 std::vector<std::unique_ptr<Action>> actions{}; 296 actions.emplace_back(std::move(action)); 297 std::unique_ptr<SensorMonitoring> sensorMonitoring = 298 std::make_unique<SensorMonitoring>(std::move(actions)); 299 300 // Create Rail 301 std::unique_ptr<Configuration> configuration{}; 302 std::unique_ptr<Rail> rail = std::make_unique<Rail>( 303 "vddr1", std::move(configuration), std::move(sensorMonitoring)); 304 Rail* railPtr = rail.get(); 305 306 // Create Device that contains Rail 307 std::unique_ptr<PresenceDetection> presenceDetection{}; 308 std::unique_ptr<Configuration> deviceConfiguration{}; 309 std::vector<std::unique_ptr<Rail>> rails{}; 310 rails.emplace_back(std::move(rail)); 311 std::unique_ptr<Device> device = std::make_unique<Device>( 312 "reg1", true, 313 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1", 314 std::move(i2cInterface), std::move(presenceDetection), 315 std::move(deviceConfiguration), std::move(rails)); 316 Device* devicePtr = device.get(); 317 318 // Create Chassis that contains Device 319 std::vector<std::unique_ptr<Device>> devices{}; 320 devices.emplace_back(std::move(device)); 321 std::unique_ptr<Chassis> chassis = 322 std::make_unique<Chassis>(1, chassisInvPath, std::move(devices)); 323 Chassis* chassisPtr = chassis.get(); 324 325 // Create System that contains Chassis 326 std::vector<std::unique_ptr<Rule>> rules{}; 327 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 328 chassisVec.emplace_back(std::move(chassis)); 329 System system{std::move(rules), std::move(chassisVec)}; 330 331 // Call monitorSensors(). 332 railPtr->monitorSensors(services, system, *chassisPtr, *devicePtr); 333 } 334 } 335 336 TEST(RailTests, GetSensorMonitoring) 337 { 338 // Test where SensorMonitoring was not specified in constructor 339 { 340 Rail rail{"vdd0", nullptr, nullptr}; 341 EXPECT_EQ(rail.getSensorMonitoring(), nullptr); 342 } 343 344 // Test where SensorMonitoring was specified in constructor 345 { 346 std::unique_ptr<Configuration> configuration{}; 347 348 // Create SensorMonitoring 349 std::vector<std::unique_ptr<Action>> actions{}; 350 actions.push_back(std::make_unique<MockAction>()); 351 actions.push_back(std::make_unique<MockAction>()); 352 std::unique_ptr<SensorMonitoring> sensorMonitoring = 353 std::make_unique<SensorMonitoring>(std::move(actions)); 354 355 // Create Rail 356 Rail rail{"vddr1", std::move(configuration), 357 std::move(sensorMonitoring)}; 358 EXPECT_NE(rail.getSensorMonitoring(), nullptr); 359 EXPECT_EQ(rail.getSensorMonitoring()->getActions().size(), 2); 360 } 361 } 362