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 "chassis.hpp" 17 #include "device.hpp" 18 #include "id_map.hpp" 19 #include "mock_journal.hpp" 20 #include "mock_services.hpp" 21 #include "mocked_i2c_interface.hpp" 22 #include "pmbus_read_sensor_action.hpp" 23 #include "rail.hpp" 24 #include "rule.hpp" 25 #include "sensors.hpp" 26 #include "services.hpp" 27 #include "system.hpp" 28 #include "test_utils.hpp" 29 30 #include <memory> 31 #include <stdexcept> 32 #include <string> 33 #include <utility> 34 #include <vector> 35 36 #include <gmock/gmock.h> 37 #include <gtest/gtest.h> 38 39 using namespace phosphor::power::regulators; 40 using namespace phosphor::power::regulators::test_utils; 41 42 using ::testing::A; 43 using ::testing::Return; 44 using ::testing::TypedEq; 45 46 static const std::string chassisInvPath{ 47 "/xyz/openbmc_project/inventory/system/chassis"}; 48 49 TEST(SystemTests, Constructor) 50 { 51 // Create Rules 52 std::vector<std::unique_ptr<Rule>> rules{}; 53 rules.emplace_back(createRule("set_voltage_rule")); 54 55 // Create Chassis 56 std::vector<std::unique_ptr<Chassis>> chassis{}; 57 std::vector<std::unique_ptr<Device>> devices{}; 58 devices.emplace_back(createDevice("reg1", {"rail1"})); 59 chassis.emplace_back( 60 std::make_unique<Chassis>(1, chassisInvPath, std::move(devices))); 61 62 // Create System 63 System system{std::move(rules), std::move(chassis)}; 64 EXPECT_EQ(system.getChassis().size(), 1); 65 EXPECT_EQ(system.getChassis()[0]->getNumber(), 1); 66 EXPECT_NO_THROW(system.getIDMap().getRule("set_voltage_rule")); 67 EXPECT_NO_THROW(system.getIDMap().getDevice("reg1")); 68 EXPECT_NO_THROW(system.getIDMap().getRail("rail1")); 69 EXPECT_THROW(system.getIDMap().getRail("rail2"), std::invalid_argument); 70 EXPECT_EQ(system.getRules().size(), 1); 71 EXPECT_EQ(system.getRules()[0]->getID(), "set_voltage_rule"); 72 } 73 74 TEST(SystemTests, ClearCache) 75 { 76 // Create PresenceDetection 77 std::vector<std::unique_ptr<Action>> actions{}; 78 std::unique_ptr<PresenceDetection> presenceDetection = 79 std::make_unique<PresenceDetection>(std::move(actions)); 80 PresenceDetection* presenceDetectionPtr = presenceDetection.get(); 81 82 // Create Device that contains PresenceDetection 83 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface(); 84 std::unique_ptr<Device> device = std::make_unique<Device>( 85 "reg1", true, 86 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1", 87 std::move(i2cInterface), std::move(presenceDetection)); 88 Device* devicePtr = device.get(); 89 90 // Create Chassis that contains Device 91 std::vector<std::unique_ptr<Device>> devices{}; 92 devices.emplace_back(std::move(device)); 93 std::unique_ptr<Chassis> chassis = 94 std::make_unique<Chassis>(1, chassisInvPath, std::move(devices)); 95 Chassis* chassisPtr = chassis.get(); 96 97 // Create System that contains Chassis 98 std::vector<std::unique_ptr<Rule>> rules{}; 99 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 100 chassisVec.emplace_back(std::move(chassis)); 101 System system{std::move(rules), std::move(chassisVec)}; 102 103 // Cache presence value in PresenceDetection 104 MockServices services{}; 105 presenceDetectionPtr->execute(services, system, *chassisPtr, *devicePtr); 106 EXPECT_TRUE(presenceDetectionPtr->getCachedPresence().has_value()); 107 108 // Clear cached data in System 109 system.clearCache(); 110 111 // Verify presence value no longer cached in PresenceDetection 112 EXPECT_FALSE(presenceDetectionPtr->getCachedPresence().has_value()); 113 } 114 115 TEST(SystemTests, CloseDevices) 116 { 117 // Specify an empty rules vector 118 std::vector<std::unique_ptr<Rule>> rules{}; 119 120 // Create mock services. Expect logDebug() to be called. 121 MockServices services{}; 122 MockJournal& journal = services.getMockJournal(); 123 EXPECT_CALL(journal, logDebug("Closing devices in chassis 1")).Times(1); 124 EXPECT_CALL(journal, logDebug("Closing devices in chassis 3")).Times(1); 125 EXPECT_CALL(journal, logInfo(A<const std::string&>())).Times(0); 126 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0); 127 128 // Create Chassis 129 std::vector<std::unique_ptr<Chassis>> chassis{}; 130 chassis.emplace_back(std::make_unique<Chassis>(1, chassisInvPath + '1')); 131 chassis.emplace_back(std::make_unique<Chassis>(3, chassisInvPath + '3')); 132 133 // Create System 134 System system{std::move(rules), std::move(chassis)}; 135 136 // Call closeDevices() 137 system.closeDevices(services); 138 } 139 140 TEST(SystemTests, Configure) 141 { 142 // Create mock services. Expect logInfo() to be called. 143 MockServices services{}; 144 MockJournal& journal = services.getMockJournal(); 145 EXPECT_CALL(journal, logInfo("Configuring chassis 1")).Times(1); 146 EXPECT_CALL(journal, logInfo("Configuring chassis 3")).Times(1); 147 EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0); 148 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0); 149 150 // Specify an empty rules vector 151 std::vector<std::unique_ptr<Rule>> rules{}; 152 153 // Create Chassis 154 std::vector<std::unique_ptr<Chassis>> chassis{}; 155 chassis.emplace_back(std::make_unique<Chassis>(1, chassisInvPath + '1')); 156 chassis.emplace_back(std::make_unique<Chassis>(3, chassisInvPath + '3')); 157 158 // Create System 159 System system{std::move(rules), std::move(chassis)}; 160 161 // Call configure() 162 system.configure(services); 163 } 164 165 TEST(SystemTests, GetChassis) 166 { 167 // Specify an empty rules vector 168 std::vector<std::unique_ptr<Rule>> rules{}; 169 170 // Create Chassis 171 std::vector<std::unique_ptr<Chassis>> chassis{}; 172 chassis.emplace_back(std::make_unique<Chassis>(1, chassisInvPath + '1')); 173 chassis.emplace_back(std::make_unique<Chassis>(3, chassisInvPath + '3')); 174 175 // Create System 176 System system{std::move(rules), std::move(chassis)}; 177 EXPECT_EQ(system.getChassis().size(), 2); 178 EXPECT_EQ(system.getChassis()[0]->getNumber(), 1); 179 EXPECT_EQ(system.getChassis()[1]->getNumber(), 3); 180 } 181 182 TEST(SystemTests, GetIDMap) 183 { 184 // Create Rules 185 std::vector<std::unique_ptr<Rule>> rules{}; 186 rules.emplace_back(createRule("set_voltage_rule")); 187 rules.emplace_back(createRule("read_sensors_rule")); 188 189 // Create Chassis 190 std::vector<std::unique_ptr<Chassis>> chassis{}; 191 { 192 // Chassis 1 193 std::vector<std::unique_ptr<Device>> devices{}; 194 devices.emplace_back(createDevice("reg1", {"rail1"})); 195 devices.emplace_back(createDevice("reg2", {"rail2a", "rail2b"})); 196 chassis.emplace_back(std::make_unique<Chassis>(1, chassisInvPath + '1', 197 std::move(devices))); 198 } 199 { 200 // Chassis 2 201 std::vector<std::unique_ptr<Device>> devices{}; 202 devices.emplace_back(createDevice("reg3", {"rail3a", "rail3b"})); 203 devices.emplace_back(createDevice("reg4")); 204 chassis.emplace_back(std::make_unique<Chassis>(2, chassisInvPath + '2', 205 std::move(devices))); 206 } 207 208 // Create System 209 System system{std::move(rules), std::move(chassis)}; 210 const IDMap& idMap = system.getIDMap(); 211 212 // Verify all Rules are in the IDMap 213 EXPECT_NO_THROW(idMap.getRule("set_voltage_rule")); 214 EXPECT_NO_THROW(idMap.getRule("read_sensors_rule")); 215 EXPECT_THROW(idMap.getRule("set_voltage_rule2"), std::invalid_argument); 216 217 // Verify all Devices are in the IDMap 218 EXPECT_NO_THROW(idMap.getDevice("reg1")); 219 EXPECT_NO_THROW(idMap.getDevice("reg2")); 220 EXPECT_NO_THROW(idMap.getDevice("reg3")); 221 EXPECT_NO_THROW(idMap.getDevice("reg4")); 222 EXPECT_THROW(idMap.getDevice("reg5"), std::invalid_argument); 223 224 // Verify all Rails are in the IDMap 225 EXPECT_NO_THROW(idMap.getRail("rail1")); 226 EXPECT_NO_THROW(idMap.getRail("rail2a")); 227 EXPECT_NO_THROW(idMap.getRail("rail2b")); 228 EXPECT_NO_THROW(idMap.getRail("rail3a")); 229 EXPECT_NO_THROW(idMap.getRail("rail3b")); 230 EXPECT_THROW(idMap.getRail("rail4"), std::invalid_argument); 231 } 232 233 TEST(SystemTests, GetRules) 234 { 235 // Create Rules 236 std::vector<std::unique_ptr<Rule>> rules{}; 237 rules.emplace_back(createRule("set_voltage_rule")); 238 rules.emplace_back(createRule("read_sensors_rule")); 239 240 // Create Chassis 241 std::vector<std::unique_ptr<Chassis>> chassis{}; 242 chassis.emplace_back(std::make_unique<Chassis>(1, chassisInvPath)); 243 244 // Create System 245 System system{std::move(rules), std::move(chassis)}; 246 EXPECT_EQ(system.getRules().size(), 2); 247 EXPECT_EQ(system.getRules()[0]->getID(), "set_voltage_rule"); 248 EXPECT_EQ(system.getRules()[1]->getID(), "read_sensors_rule"); 249 } 250 251 TEST(SystemTests, MonitorSensors) 252 { 253 // Create mock services. No logging should occur. 254 MockServices services{}; 255 MockJournal& journal = services.getMockJournal(); 256 EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0); 257 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0); 258 259 // Create PMBusReadSensorAction 260 SensorType type{SensorType::iout}; 261 uint8_t command = 0x8C; 262 pmbus_utils::SensorDataFormat format{ 263 pmbus_utils::SensorDataFormat::linear_11}; 264 std::optional<int8_t> exponent{}; 265 std::unique_ptr<PMBusReadSensorAction> action = 266 std::make_unique<PMBusReadSensorAction>(type, command, format, 267 exponent); 268 269 // Create mock I2CInterface. A two-byte read should occur. 270 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface = 271 std::make_unique<i2c::MockedI2CInterface>(); 272 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true)); 273 EXPECT_CALL(*i2cInterface, read(TypedEq<uint8_t>(0x8C), A<uint16_t&>())) 274 .Times(1); 275 276 // Create SensorMonitoring 277 std::vector<std::unique_ptr<Action>> actions{}; 278 actions.emplace_back(std::move(action)); 279 std::unique_ptr<SensorMonitoring> sensorMonitoring = 280 std::make_unique<SensorMonitoring>(std::move(actions)); 281 282 // Create Rail 283 std::vector<std::unique_ptr<Rail>> rails{}; 284 std::unique_ptr<Configuration> configuration{}; 285 std::unique_ptr<Rail> rail = std::make_unique<Rail>( 286 "vdd0", std::move(configuration), std::move(sensorMonitoring)); 287 rails.emplace_back(std::move(rail)); 288 289 // Create Device 290 std::unique_ptr<PresenceDetection> presenceDetection{}; 291 std::unique_ptr<Configuration> deviceConfiguration{}; 292 std::unique_ptr<Device> device = std::make_unique<Device>( 293 "reg1", true, 294 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1", 295 std::move(i2cInterface), std::move(presenceDetection), 296 std::move(deviceConfiguration), std::move(rails)); 297 298 // Create Chassis 299 std::vector<std::unique_ptr<Device>> devices{}; 300 devices.emplace_back(std::move(device)); 301 std::unique_ptr<Chassis> chassis = 302 std::make_unique<Chassis>(1, chassisInvPath, std::move(devices)); 303 304 // Create System that contains Chassis 305 std::vector<std::unique_ptr<Rule>> rules{}; 306 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 307 chassisVec.emplace_back(std::move(chassis)); 308 System system{std::move(rules), std::move(chassisVec)}; 309 310 // Call monitorSensors() 311 system.monitorSensors(services); 312 } 313