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 "i2c_write_byte_action.hpp" 22 #include "mock_action.hpp" 23 #include "mock_journal.hpp" 24 #include "mock_services.hpp" 25 #include "mocked_i2c_interface.hpp" 26 #include "pmbus_utils.hpp" 27 #include "pmbus_write_vout_command_action.hpp" 28 #include "presence_detection.hpp" 29 #include "rail.hpp" 30 #include "rule.hpp" 31 #include "system.hpp" 32 33 #include <cstdint> 34 #include <memory> 35 #include <optional> 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::pmbus_utils; 44 45 using ::testing::A; 46 using ::testing::Return; 47 using ::testing::Throw; 48 using ::testing::TypedEq; 49 50 TEST(ConfigurationTests, Constructor) 51 { 52 // Test where volts value specified 53 { 54 std::optional<double> volts{1.3}; 55 56 std::vector<std::unique_ptr<Action>> actions{}; 57 actions.push_back(std::make_unique<MockAction>()); 58 actions.push_back(std::make_unique<MockAction>()); 59 60 Configuration configuration(volts, std::move(actions)); 61 EXPECT_EQ(configuration.getVolts().has_value(), true); 62 EXPECT_EQ(configuration.getVolts().value(), 1.3); 63 EXPECT_EQ(configuration.getActions().size(), 2); 64 } 65 66 // Test where volts value not specified 67 { 68 std::optional<double> volts{}; 69 70 std::vector<std::unique_ptr<Action>> actions{}; 71 actions.push_back(std::make_unique<MockAction>()); 72 73 Configuration configuration(volts, std::move(actions)); 74 EXPECT_EQ(configuration.getVolts().has_value(), false); 75 EXPECT_EQ(configuration.getActions().size(), 1); 76 } 77 } 78 79 // Test for execute(Services&, System&, Chassis&, Device&) 80 TEST(ConfigurationTests, ExecuteForDevice) 81 { 82 // Test where works: Volts value not specified 83 { 84 // Create mock services. Expect logDebug() to be called. 85 MockServices services{}; 86 MockJournal& journal = services.getMockJournal(); 87 EXPECT_CALL(journal, logDebug("Configuring vdd_reg")).Times(1); 88 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0); 89 90 // Create I2CWriteByteAction with register 0x7C and value 0x0A 91 std::unique_ptr<I2CWriteByteAction> action = 92 std::make_unique<I2CWriteByteAction>(0x7C, 0x0A); 93 94 // Create mock I2CInterface. Expect action to write 0x0A to 0x7C. 95 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface = 96 std::make_unique<i2c::MockedI2CInterface>(); 97 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true)); 98 EXPECT_CALL(*i2cInterface, 99 write(TypedEq<uint8_t>(0x7C), TypedEq<uint8_t>(0x0A))) 100 .Times(1); 101 102 // Create Configuration with no volts value specified 103 std::optional<double> volts{}; 104 std::vector<std::unique_ptr<Action>> actions{}; 105 actions.emplace_back(std::move(action)); 106 std::unique_ptr<Configuration> configuration = 107 std::make_unique<Configuration>(volts, std::move(actions)); 108 Configuration* configurationPtr = configuration.get(); 109 110 // Create Device that contains Configuration 111 std::unique_ptr<PresenceDetection> presenceDetection{}; 112 std::unique_ptr<Device> device = std::make_unique<Device>( 113 "vdd_reg", true, "/system/chassis/motherboard/reg2", 114 std::move(i2cInterface), std::move(presenceDetection), 115 std::move(configuration)); 116 Device* devicePtr = device.get(); 117 118 // Create Chassis that contains Device 119 std::vector<std::unique_ptr<Device>> devices{}; 120 devices.emplace_back(std::move(device)); 121 std::unique_ptr<Chassis> chassis = 122 std::make_unique<Chassis>(1, std::move(devices)); 123 Chassis* chassisPtr = chassis.get(); 124 125 // Create System that contains Chassis 126 std::vector<std::unique_ptr<Rule>> rules{}; 127 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 128 chassisVec.emplace_back(std::move(chassis)); 129 System system{std::move(rules), std::move(chassisVec)}; 130 131 // Execute Configuration 132 configurationPtr->execute(services, system, *chassisPtr, *devicePtr); 133 } 134 135 // Test where works: Volts value specified 136 { 137 // Create mock services. Expect logDebug() to be called. 138 MockServices services{}; 139 MockJournal& journal = services.getMockJournal(); 140 EXPECT_CALL(journal, logDebug("Configuring vdd_reg: volts=1.300000")) 141 .Times(1); 142 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0); 143 144 // Create PMBusWriteVoutCommandAction. Do not specify a volts value 145 // because it will get a value of 1.3V from the 146 // ActionEnvironment/Configuration. Specify a -8 exponent. 147 // Linear format volts value = (1.3 / 2^(-8)) = 332.8 = 333 = 0x014D. 148 std::optional<double> volts{}; 149 std::unique_ptr<PMBusWriteVoutCommandAction> action = 150 std::make_unique<PMBusWriteVoutCommandAction>( 151 volts, pmbus_utils::VoutDataFormat::linear, -8, false); 152 153 // Create mock I2CInterface. Expect action to write 0x014D to 154 // VOUT_COMMAND (command/register 0x21). 155 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface = 156 std::make_unique<i2c::MockedI2CInterface>(); 157 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true)); 158 EXPECT_CALL(*i2cInterface, 159 write(TypedEq<uint8_t>(0x21), TypedEq<uint16_t>(0x014D))) 160 .Times(1); 161 162 // Create Configuration with volts value 1.3V 163 std::vector<std::unique_ptr<Action>> actions{}; 164 actions.emplace_back(std::move(action)); 165 std::unique_ptr<Configuration> configuration = 166 std::make_unique<Configuration>(1.3, std::move(actions)); 167 Configuration* configurationPtr = configuration.get(); 168 169 // Create Device that contains Configuration 170 std::unique_ptr<PresenceDetection> presenceDetection{}; 171 std::unique_ptr<Device> device = std::make_unique<Device>( 172 "vdd_reg", true, "/system/chassis/motherboard/reg2", 173 std::move(i2cInterface), std::move(presenceDetection), 174 std::move(configuration)); 175 Device* devicePtr = device.get(); 176 177 // Create Chassis that contains Device 178 std::vector<std::unique_ptr<Device>> devices{}; 179 devices.emplace_back(std::move(device)); 180 std::unique_ptr<Chassis> chassis = 181 std::make_unique<Chassis>(1, std::move(devices)); 182 Chassis* chassisPtr = chassis.get(); 183 184 // Create System that contains Chassis 185 std::vector<std::unique_ptr<Rule>> rules{}; 186 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 187 chassisVec.emplace_back(std::move(chassis)); 188 System system{std::move(rules), std::move(chassisVec)}; 189 190 // Execute Configuration 191 configurationPtr->execute(services, system, *chassisPtr, *devicePtr); 192 } 193 194 // Test where fails 195 { 196 // Create mock services. Expect logDebug() and logError() to be called. 197 MockServices services{}; 198 MockJournal& journal = services.getMockJournal(); 199 std::vector<std::string> expectedErrMessagesException{ 200 "I2CException: Failed to write byte: bus /dev/i2c-1, addr 0x70", 201 "ActionError: i2c_write_byte: { register: 0x7C, value: 0xA, mask: " 202 "0xFF }"}; 203 EXPECT_CALL(journal, logDebug("Configuring vdd_reg")).Times(1); 204 EXPECT_CALL(journal, logError(expectedErrMessagesException)).Times(1); 205 EXPECT_CALL(journal, logError("Unable to configure vdd_reg")).Times(1); 206 207 // Create I2CWriteByteAction with register 0x7C and value 0x0A 208 std::unique_ptr<I2CWriteByteAction> action = 209 std::make_unique<I2CWriteByteAction>(0x7C, 0x0A); 210 211 // Create mock I2CInterface. write() throws an I2CException. 212 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface = 213 std::make_unique<i2c::MockedI2CInterface>(); 214 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true)); 215 EXPECT_CALL(*i2cInterface, 216 write(TypedEq<uint8_t>(0x7C), TypedEq<uint8_t>(0x0A))) 217 .Times(1) 218 .WillOnce(Throw( 219 i2c::I2CException{"Failed to write byte", "/dev/i2c-1", 0x70})); 220 221 // Create Configuration with no volts value specified 222 std::optional<double> volts{}; 223 std::vector<std::unique_ptr<Action>> actions{}; 224 actions.emplace_back(std::move(action)); 225 std::unique_ptr<Configuration> configuration = 226 std::make_unique<Configuration>(volts, std::move(actions)); 227 Configuration* configurationPtr = configuration.get(); 228 229 // Create Device that contains Configuration 230 std::unique_ptr<PresenceDetection> presenceDetection{}; 231 std::unique_ptr<Device> device = std::make_unique<Device>( 232 "vdd_reg", true, "/system/chassis/motherboard/reg2", 233 std::move(i2cInterface), std::move(presenceDetection), 234 std::move(configuration)); 235 Device* devicePtr = device.get(); 236 237 // Create Chassis that contains Device 238 std::vector<std::unique_ptr<Device>> devices{}; 239 devices.emplace_back(std::move(device)); 240 std::unique_ptr<Chassis> chassis = 241 std::make_unique<Chassis>(1, std::move(devices)); 242 Chassis* chassisPtr = chassis.get(); 243 244 // Create System that contains Chassis 245 std::vector<std::unique_ptr<Rule>> rules{}; 246 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 247 chassisVec.emplace_back(std::move(chassis)); 248 System system{std::move(rules), std::move(chassisVec)}; 249 250 // Execute Configuration 251 configurationPtr->execute(services, system, *chassisPtr, *devicePtr); 252 } 253 } 254 255 // Test for execute(Services&, System&, Chassis&, Device&, Rail&) 256 TEST(ConfigurationTests, ExecuteForRail) 257 { 258 // Test where works: Volts value not specified 259 { 260 // Create mock services. Expect logDebug() to be called. 261 MockServices services{}; 262 MockJournal& journal = services.getMockJournal(); 263 EXPECT_CALL(journal, logDebug("Configuring vio2")).Times(1); 264 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0); 265 266 // Create I2CWriteByteAction with register 0x7C and value 0x0A 267 std::unique_ptr<I2CWriteByteAction> action = 268 std::make_unique<I2CWriteByteAction>(0x7C, 0x0A); 269 270 // Create mock I2CInterface. Expect action to write 0x0A to 0x7C. 271 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface = 272 std::make_unique<i2c::MockedI2CInterface>(); 273 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true)); 274 EXPECT_CALL(*i2cInterface, 275 write(TypedEq<uint8_t>(0x7C), TypedEq<uint8_t>(0x0A))) 276 .Times(1); 277 278 // Create Configuration with no volts value specified 279 std::optional<double> volts{}; 280 std::vector<std::unique_ptr<Action>> actions{}; 281 actions.emplace_back(std::move(action)); 282 std::unique_ptr<Configuration> configuration = 283 std::make_unique<Configuration>(volts, std::move(actions)); 284 Configuration* configurationPtr = configuration.get(); 285 286 // Create Rail that contains Configuration 287 std::unique_ptr<Rail> rail = 288 std::make_unique<Rail>("vio2", std::move(configuration)); 289 Rail* railPtr = rail.get(); 290 291 // Create Device that contains Rail 292 std::unique_ptr<PresenceDetection> presenceDetection{}; 293 std::unique_ptr<Configuration> deviceConfiguration{}; 294 std::vector<std::unique_ptr<Rail>> rails{}; 295 rails.emplace_back(std::move(rail)); 296 std::unique_ptr<Device> device = std::make_unique<Device>( 297 "reg1", true, "/system/chassis/motherboard/reg1", 298 std::move(i2cInterface), std::move(presenceDetection), 299 std::move(deviceConfiguration), std::move(rails)); 300 Device* devicePtr = device.get(); 301 302 // Create Chassis that contains Device 303 std::vector<std::unique_ptr<Device>> devices{}; 304 devices.emplace_back(std::move(device)); 305 std::unique_ptr<Chassis> chassis = 306 std::make_unique<Chassis>(1, std::move(devices)); 307 Chassis* chassisPtr = chassis.get(); 308 309 // Create System that contains Chassis 310 std::vector<std::unique_ptr<Rule>> rules{}; 311 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 312 chassisVec.emplace_back(std::move(chassis)); 313 System system{std::move(rules), std::move(chassisVec)}; 314 315 // Execute Configuration 316 configurationPtr->execute(services, system, *chassisPtr, *devicePtr, 317 *railPtr); 318 } 319 320 // Test where works: Volts value specified 321 { 322 // Create mock services. Expect logDebug() to be called. 323 MockServices services{}; 324 MockJournal& journal = services.getMockJournal(); 325 EXPECT_CALL(journal, logDebug("Configuring vio2: volts=1.300000")) 326 .Times(1); 327 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0); 328 329 // Create PMBusWriteVoutCommandAction. Do not specify a volts value 330 // because it will get a value of 1.3V from the 331 // ActionEnvironment/Configuration. Specify a -8 exponent. 332 // Linear format volts value = (1.3 / 2^(-8)) = 332.8 = 333 = 0x014D. 333 std::optional<double> volts{}; 334 std::unique_ptr<PMBusWriteVoutCommandAction> action = 335 std::make_unique<PMBusWriteVoutCommandAction>( 336 volts, pmbus_utils::VoutDataFormat::linear, -8, false); 337 338 // Create mock I2CInterface. Expect action to write 0x014D to 339 // VOUT_COMMAND (command/register 0x21). 340 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface = 341 std::make_unique<i2c::MockedI2CInterface>(); 342 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true)); 343 EXPECT_CALL(*i2cInterface, 344 write(TypedEq<uint8_t>(0x21), TypedEq<uint16_t>(0x014D))) 345 .Times(1); 346 347 // Create Configuration with volts value 1.3V 348 std::vector<std::unique_ptr<Action>> actions{}; 349 actions.emplace_back(std::move(action)); 350 std::unique_ptr<Configuration> configuration = 351 std::make_unique<Configuration>(1.3, std::move(actions)); 352 Configuration* configurationPtr = configuration.get(); 353 354 // Create Rail that contains Configuration 355 std::unique_ptr<Rail> rail = 356 std::make_unique<Rail>("vio2", std::move(configuration)); 357 Rail* railPtr = rail.get(); 358 359 // Create Device that contains Rail 360 std::unique_ptr<PresenceDetection> presenceDetection{}; 361 std::unique_ptr<Configuration> deviceConfiguration{}; 362 std::vector<std::unique_ptr<Rail>> rails{}; 363 rails.emplace_back(std::move(rail)); 364 std::unique_ptr<Device> device = std::make_unique<Device>( 365 "reg1", true, "/system/chassis/motherboard/reg1", 366 std::move(i2cInterface), std::move(presenceDetection), 367 std::move(deviceConfiguration), std::move(rails)); 368 Device* devicePtr = device.get(); 369 370 // Create Chassis that contains Device 371 std::vector<std::unique_ptr<Device>> devices{}; 372 devices.emplace_back(std::move(device)); 373 std::unique_ptr<Chassis> chassis = 374 std::make_unique<Chassis>(1, std::move(devices)); 375 Chassis* chassisPtr = chassis.get(); 376 377 // Create System that contains Chassis 378 std::vector<std::unique_ptr<Rule>> rules{}; 379 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 380 chassisVec.emplace_back(std::move(chassis)); 381 System system{std::move(rules), std::move(chassisVec)}; 382 383 // Execute Configuration 384 configurationPtr->execute(services, system, *chassisPtr, *devicePtr, 385 *railPtr); 386 } 387 388 // Test where fails 389 { 390 // Create mock services. Expect logDebug() and logError() to be called. 391 MockServices services{}; 392 MockJournal& journal = services.getMockJournal(); 393 std::vector<std::string> expectedErrMessagesException{ 394 "I2CException: Failed to write byte: bus /dev/i2c-1, addr 0x70", 395 "ActionError: i2c_write_byte: { register: 0x7C, value: 0xA, mask: " 396 "0xFF }"}; 397 EXPECT_CALL(journal, logDebug("Configuring vio2")).Times(1); 398 EXPECT_CALL(journal, logError(expectedErrMessagesException)).Times(1); 399 EXPECT_CALL(journal, logError("Unable to configure vio2")).Times(1); 400 401 // Create I2CWriteByteAction with register 0x7C and value 0x0A 402 std::unique_ptr<I2CWriteByteAction> action = 403 std::make_unique<I2CWriteByteAction>(0x7C, 0x0A); 404 405 // Create mock I2CInterface. write() throws an I2CException. 406 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface = 407 std::make_unique<i2c::MockedI2CInterface>(); 408 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true)); 409 EXPECT_CALL(*i2cInterface, 410 write(TypedEq<uint8_t>(0x7C), TypedEq<uint8_t>(0x0A))) 411 .Times(1) 412 .WillOnce(Throw( 413 i2c::I2CException{"Failed to write byte", "/dev/i2c-1", 0x70})); 414 415 // Create Configuration with no volts value specified 416 std::optional<double> volts{}; 417 std::vector<std::unique_ptr<Action>> actions{}; 418 actions.emplace_back(std::move(action)); 419 std::unique_ptr<Configuration> configuration = 420 std::make_unique<Configuration>(volts, std::move(actions)); 421 Configuration* configurationPtr = configuration.get(); 422 423 // Create Rail that contains Configuration 424 std::unique_ptr<Rail> rail = 425 std::make_unique<Rail>("vio2", std::move(configuration)); 426 Rail* railPtr = rail.get(); 427 428 // Create Device that contains Rail 429 std::unique_ptr<PresenceDetection> presenceDetection{}; 430 std::unique_ptr<Configuration> deviceConfiguration{}; 431 std::vector<std::unique_ptr<Rail>> rails{}; 432 rails.emplace_back(std::move(rail)); 433 std::unique_ptr<Device> device = std::make_unique<Device>( 434 "reg1", true, "/system/chassis/motherboard/reg1", 435 std::move(i2cInterface), std::move(presenceDetection), 436 std::move(deviceConfiguration), std::move(rails)); 437 Device* devicePtr = device.get(); 438 439 // Create Chassis that contains Device 440 std::vector<std::unique_ptr<Device>> devices{}; 441 devices.emplace_back(std::move(device)); 442 std::unique_ptr<Chassis> chassis = 443 std::make_unique<Chassis>(1, std::move(devices)); 444 Chassis* chassisPtr = chassis.get(); 445 446 // Create System that contains Chassis 447 std::vector<std::unique_ptr<Rule>> rules{}; 448 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 449 chassisVec.emplace_back(std::move(chassis)); 450 System system{std::move(rules), std::move(chassisVec)}; 451 452 // Execute Configuration 453 configurationPtr->execute(services, system, *chassisPtr, *devicePtr, 454 *railPtr); 455 } 456 } 457 458 TEST(ConfigurationTests, GetActions) 459 { 460 std::optional<double> volts{1.3}; 461 462 std::vector<std::unique_ptr<Action>> actions{}; 463 464 MockAction* action1 = new MockAction{}; 465 actions.push_back(std::unique_ptr<MockAction>{action1}); 466 467 MockAction* action2 = new MockAction{}; 468 actions.push_back(std::unique_ptr<MockAction>{action2}); 469 470 Configuration configuration(volts, std::move(actions)); 471 EXPECT_EQ(configuration.getActions().size(), 2); 472 EXPECT_EQ(configuration.getActions()[0].get(), action1); 473 EXPECT_EQ(configuration.getActions()[1].get(), action2); 474 } 475 476 TEST(ConfigurationTests, GetVolts) 477 { 478 // Test where volts value specified 479 { 480 std::optional<double> volts{3.2}; 481 482 std::vector<std::unique_ptr<Action>> actions{}; 483 actions.push_back(std::make_unique<MockAction>()); 484 485 Configuration configuration(volts, std::move(actions)); 486 EXPECT_EQ(configuration.getVolts().has_value(), true); 487 EXPECT_EQ(configuration.getVolts().value(), 3.2); 488 } 489 490 // Test where volts value not specified 491 { 492 std::optional<double> volts{}; 493 494 std::vector<std::unique_ptr<Action>> actions{}; 495 actions.push_back(std::make_unique<MockAction>()); 496 497 Configuration configuration(volts, std::move(actions)); 498 EXPECT_EQ(configuration.getVolts().has_value(), false); 499 } 500 } 501