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