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_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 "system.hpp" 30 #include "test_utils.hpp" 31 32 #include <memory> 33 #include <stdexcept> 34 #include <string> 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 using namespace phosphor::power::regulators::test_utils; 43 44 using ::testing::A; 45 using ::testing::Return; 46 using ::testing::TypedEq; 47 48 TEST(ChassisTests, Constructor) 49 { 50 // Test where works: Only required parameters are specified 51 { 52 Chassis chassis{2}; 53 EXPECT_EQ(chassis.getNumber(), 2); 54 EXPECT_EQ(chassis.getDevices().size(), 0); 55 } 56 57 // Test where works: All parameters are specified 58 { 59 // Create vector of Device objects 60 std::vector<std::unique_ptr<Device>> devices{}; 61 devices.emplace_back(createDevice("vdd_reg1")); 62 devices.emplace_back(createDevice("vdd_reg2")); 63 64 // Create Chassis 65 Chassis chassis{1, std::move(devices)}; 66 EXPECT_EQ(chassis.getNumber(), 1); 67 EXPECT_EQ(chassis.getDevices().size(), 2); 68 } 69 70 // Test where fails: Invalid chassis number < 1 71 try 72 { 73 Chassis chassis{0}; 74 ADD_FAILURE() << "Should not have reached this line."; 75 } 76 catch (const std::invalid_argument& e) 77 { 78 EXPECT_STREQ(e.what(), "Invalid chassis number: 0"); 79 } 80 catch (...) 81 { 82 ADD_FAILURE() << "Should not have caught exception."; 83 } 84 } 85 86 TEST(ChassisTests, AddToIDMap) 87 { 88 // Create vector of Device objects 89 std::vector<std::unique_ptr<Device>> devices{}; 90 devices.emplace_back(createDevice("reg1", {"rail1"})); 91 devices.emplace_back(createDevice("reg2", {"rail2a", "rail2b"})); 92 devices.emplace_back(createDevice("reg3")); 93 94 // Create Chassis 95 Chassis chassis{1, std::move(devices)}; 96 97 // Add Device and Rail objects within the Chassis to an IDMap 98 IDMap idMap{}; 99 chassis.addToIDMap(idMap); 100 101 // Verify all Devices are in the IDMap 102 EXPECT_NO_THROW(idMap.getDevice("reg1")); 103 EXPECT_NO_THROW(idMap.getDevice("reg2")); 104 EXPECT_NO_THROW(idMap.getDevice("reg3")); 105 EXPECT_THROW(idMap.getDevice("reg4"), std::invalid_argument); 106 107 // Verify all Rails are in the IDMap 108 EXPECT_NO_THROW(idMap.getRail("rail1")); 109 EXPECT_NO_THROW(idMap.getRail("rail2a")); 110 EXPECT_NO_THROW(idMap.getRail("rail2b")); 111 EXPECT_THROW(idMap.getRail("rail3"), std::invalid_argument); 112 } 113 114 TEST(ChassisTests, ClearCache) 115 { 116 // Create PresenceDetection 117 std::vector<std::unique_ptr<Action>> actions{}; 118 std::unique_ptr<PresenceDetection> presenceDetection = 119 std::make_unique<PresenceDetection>(std::move(actions)); 120 PresenceDetection* presenceDetectionPtr = presenceDetection.get(); 121 122 // Create Device that contains PresenceDetection 123 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface(); 124 std::unique_ptr<Device> device = std::make_unique<Device>( 125 "reg1", true, 126 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1", 127 std::move(i2cInterface), std::move(presenceDetection)); 128 Device* devicePtr = device.get(); 129 130 // Create Chassis that contains Device 131 std::vector<std::unique_ptr<Device>> devices{}; 132 devices.emplace_back(std::move(device)); 133 std::unique_ptr<Chassis> chassis = 134 std::make_unique<Chassis>(1, std::move(devices)); 135 Chassis* chassisPtr = chassis.get(); 136 137 // Create System that contains Chassis 138 std::vector<std::unique_ptr<Rule>> rules{}; 139 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 140 chassisVec.emplace_back(std::move(chassis)); 141 System system{std::move(rules), std::move(chassisVec)}; 142 143 // Cache presence value in PresenceDetection 144 MockServices services{}; 145 presenceDetectionPtr->execute(services, system, *chassisPtr, *devicePtr); 146 EXPECT_TRUE(presenceDetectionPtr->getCachedPresence().has_value()); 147 148 // Clear cached data in Chassis 149 chassisPtr->clearCache(); 150 151 // Verify presence value no longer cached in PresenceDetection 152 EXPECT_FALSE(presenceDetectionPtr->getCachedPresence().has_value()); 153 } 154 155 TEST(ChassisTests, CloseDevices) 156 { 157 // Test where no devices were specified in constructor 158 { 159 // Create mock services. Expect logDebug() to be called. 160 MockServices services{}; 161 MockJournal& journal = services.getMockJournal(); 162 EXPECT_CALL(journal, logDebug("Closing devices in chassis 2")).Times(1); 163 164 // Create Chassis 165 Chassis chassis{2}; 166 167 // Call closeDevices() 168 chassis.closeDevices(services); 169 } 170 171 // Test where devices were specified in constructor 172 { 173 std::vector<std::unique_ptr<Device>> devices{}; 174 175 // Create mock services. Expect logDebug() to be called. 176 MockServices services{}; 177 MockJournal& journal = services.getMockJournal(); 178 EXPECT_CALL(journal, logDebug("Closing devices in chassis 1")).Times(1); 179 180 // Create Device vdd0_reg 181 { 182 // Create mock I2CInterface: isOpen() and close() should be called 183 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface = 184 std::make_unique<i2c::MockedI2CInterface>(); 185 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true)); 186 EXPECT_CALL(*i2cInterface, close).Times(1); 187 188 // Create Device 189 std::unique_ptr<Device> device = 190 std::make_unique<Device>("vdd0_reg", true, 191 "/xyz/openbmc_project/inventory/" 192 "system/chassis/motherboard/vdd0_reg", 193 std::move(i2cInterface)); 194 devices.emplace_back(std::move(device)); 195 } 196 197 // Create Device vdd1_reg 198 { 199 // Create mock I2CInterface: isOpen() and close() should be called 200 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface = 201 std::make_unique<i2c::MockedI2CInterface>(); 202 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true)); 203 EXPECT_CALL(*i2cInterface, close).Times(1); 204 205 // Create Device 206 std::unique_ptr<Device> device = 207 std::make_unique<Device>("vdd1_reg", true, 208 "/xyz/openbmc_project/inventory/" 209 "system/chassis/motherboard/vdd1_reg", 210 std::move(i2cInterface)); 211 devices.emplace_back(std::move(device)); 212 } 213 214 // Create Chassis 215 Chassis chassis{1, std::move(devices)}; 216 217 // Call closeDevices() 218 chassis.closeDevices(services); 219 } 220 } 221 222 TEST(ChassisTests, Configure) 223 { 224 // Test where no devices were specified in constructor 225 { 226 // Create mock services. Expect logInfo() to be called. 227 MockServices services{}; 228 MockJournal& journal = services.getMockJournal(); 229 EXPECT_CALL(journal, logInfo("Configuring chassis 1")).Times(1); 230 EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0); 231 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0); 232 233 // Create Chassis 234 std::unique_ptr<Chassis> chassis = std::make_unique<Chassis>(1); 235 Chassis* chassisPtr = chassis.get(); 236 237 // Create System that contains Chassis 238 std::vector<std::unique_ptr<Rule>> rules{}; 239 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 240 chassisVec.emplace_back(std::move(chassis)); 241 System system{std::move(rules), std::move(chassisVec)}; 242 243 // Call configure() 244 chassisPtr->configure(services, system); 245 } 246 247 // Test where devices were specified in constructor 248 { 249 std::vector<std::unique_ptr<Device>> devices{}; 250 251 // Create mock services. Expect logInfo() and logDebug() to be called. 252 MockServices services{}; 253 MockJournal& journal = services.getMockJournal(); 254 EXPECT_CALL(journal, logInfo("Configuring chassis 2")).Times(1); 255 EXPECT_CALL(journal, logDebug("Configuring vdd0_reg: volts=1.300000")) 256 .Times(1); 257 EXPECT_CALL(journal, logDebug("Configuring vdd1_reg: volts=1.200000")) 258 .Times(1); 259 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0); 260 261 // Create Device vdd0_reg 262 { 263 // Create Configuration 264 std::vector<std::unique_ptr<Action>> actions{}; 265 std::unique_ptr<Configuration> configuration = 266 std::make_unique<Configuration>(1.3, std::move(actions)); 267 268 // Create Device 269 std::unique_ptr<i2c::I2CInterface> i2cInterface = 270 createI2CInterface(); 271 std::unique_ptr<PresenceDetection> presenceDetection{}; 272 std::unique_ptr<Device> device = std::make_unique<Device>( 273 "vdd0_reg", true, 274 "/xyz/openbmc_project/inventory/system/chassis/motherboard/" 275 "vdd0_reg", 276 std::move(i2cInterface), std::move(presenceDetection), 277 std::move(configuration)); 278 devices.emplace_back(std::move(device)); 279 } 280 281 // Create Device vdd1_reg 282 { 283 // Create Configuration 284 std::vector<std::unique_ptr<Action>> actions{}; 285 std::unique_ptr<Configuration> configuration = 286 std::make_unique<Configuration>(1.2, std::move(actions)); 287 288 // Create Device 289 std::unique_ptr<i2c::I2CInterface> i2cInterface = 290 createI2CInterface(); 291 std::unique_ptr<PresenceDetection> presenceDetection{}; 292 std::unique_ptr<Device> device = std::make_unique<Device>( 293 "vdd1_reg", true, 294 "/xyz/openbmc_project/inventory/system/chassis/motherboard/" 295 "vdd1_reg", 296 std::move(i2cInterface), std::move(presenceDetection), 297 std::move(configuration)); 298 devices.emplace_back(std::move(device)); 299 } 300 301 // Create Chassis 302 std::unique_ptr<Chassis> chassis = 303 std::make_unique<Chassis>(2, std::move(devices)); 304 Chassis* chassisPtr = chassis.get(); 305 306 // Create System that contains Chassis 307 std::vector<std::unique_ptr<Rule>> rules{}; 308 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 309 chassisVec.emplace_back(std::move(chassis)); 310 System system{std::move(rules), std::move(chassisVec)}; 311 312 // Call configure() 313 chassisPtr->configure(services, system); 314 } 315 } 316 317 TEST(ChassisTests, GetDevices) 318 { 319 // Test where no devices were specified in constructor 320 { 321 Chassis chassis{2}; 322 EXPECT_EQ(chassis.getDevices().size(), 0); 323 } 324 325 // Test where devices were specified in constructor 326 { 327 // Create vector of Device objects 328 std::vector<std::unique_ptr<Device>> devices{}; 329 devices.emplace_back(createDevice("vdd_reg1")); 330 devices.emplace_back(createDevice("vdd_reg2")); 331 332 // Create Chassis 333 Chassis chassis{1, std::move(devices)}; 334 EXPECT_EQ(chassis.getDevices().size(), 2); 335 EXPECT_EQ(chassis.getDevices()[0]->getID(), "vdd_reg1"); 336 EXPECT_EQ(chassis.getDevices()[1]->getID(), "vdd_reg2"); 337 } 338 } 339 340 TEST(ChassisTests, GetNumber) 341 { 342 Chassis chassis{3}; 343 EXPECT_EQ(chassis.getNumber(), 3); 344 } 345 346 TEST(ChassisTests, MonitorSensors) 347 { 348 // Test where no devices were specified in constructor 349 { 350 // Create mock services. No logging should occur. 351 MockServices services{}; 352 MockJournal& journal = services.getMockJournal(); 353 EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0); 354 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0); 355 356 // Create Chassis 357 std::vector<std::unique_ptr<Device>> devices{}; 358 std::unique_ptr<Chassis> chassis = 359 std::make_unique<Chassis>(1, std::move(devices)); 360 Chassis* chassisPtr = chassis.get(); 361 362 // Create System that contains Chassis 363 std::vector<std::unique_ptr<Rule>> rules{}; 364 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 365 chassisVec.emplace_back(std::move(chassis)); 366 System system{std::move(rules), std::move(chassisVec)}; 367 368 // Call monitorSensors(). Should do nothing. 369 chassisPtr->monitorSensors(services, system); 370 } 371 372 // Test where devices were specified in constructor 373 { 374 // Create mock services. No logging should occur. 375 MockServices services{}; 376 MockJournal& journal = services.getMockJournal(); 377 EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0); 378 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0); 379 380 std::vector<std::unique_ptr<Device>> devices{}; 381 382 // Create PMBusReadSensorAction 383 pmbus_utils::SensorValueType type{pmbus_utils::SensorValueType::iout}; 384 uint8_t command = 0x8C; 385 pmbus_utils::SensorDataFormat format{ 386 pmbus_utils::SensorDataFormat::linear_11}; 387 std::optional<int8_t> exponent{}; 388 std::unique_ptr<PMBusReadSensorAction> action = 389 std::make_unique<PMBusReadSensorAction>(type, command, format, 390 exponent); 391 392 // Create mock I2CInterface. A two-byte read should occur. 393 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface = 394 std::make_unique<i2c::MockedI2CInterface>(); 395 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true)); 396 EXPECT_CALL(*i2cInterface, read(TypedEq<uint8_t>(0x8C), A<uint16_t&>())) 397 .Times(1); 398 399 // Create SensorMonitoring 400 std::vector<std::unique_ptr<Action>> actions{}; 401 actions.emplace_back(std::move(action)); 402 std::unique_ptr<SensorMonitoring> sensorMonitoring = 403 std::make_unique<SensorMonitoring>(std::move(actions)); 404 405 // Create Rail 406 std::vector<std::unique_ptr<Rail>> rails{}; 407 std::unique_ptr<Configuration> configuration{}; 408 std::unique_ptr<Rail> rail = std::make_unique<Rail>( 409 "vdd0", std::move(configuration), std::move(sensorMonitoring)); 410 rails.emplace_back(std::move(rail)); 411 412 // Create Device 413 std::unique_ptr<PresenceDetection> presenceDetection{}; 414 std::unique_ptr<Configuration> deviceConfiguration{}; 415 std::unique_ptr<Device> device = std::make_unique<Device>( 416 "reg1", true, 417 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1", 418 std::move(i2cInterface), std::move(presenceDetection), 419 std::move(deviceConfiguration), std::move(rails)); 420 421 // Create Chassis 422 devices.emplace_back(std::move(device)); 423 std::unique_ptr<Chassis> chassis = 424 std::make_unique<Chassis>(1, std::move(devices)); 425 Chassis* chassisPtr = chassis.get(); 426 427 // Create System that contains Chassis 428 std::vector<std::unique_ptr<Rule>> rules{}; 429 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 430 chassisVec.emplace_back(std::move(chassis)); 431 System system{std::move(rules), std::move(chassisVec)}; 432 433 // Call monitorSensors() 434 chassisPtr->monitorSensors(services, system); 435 } 436 } 437