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 "compare_presence_action.hpp" 19 #include "device.hpp" 20 #include "i2c_interface.hpp" 21 #include "mock_action.hpp" 22 #include "mock_journal.hpp" 23 #include "mock_presence_service.hpp" 24 #include "mock_services.hpp" 25 #include "mocked_i2c_interface.hpp" 26 #include "presence_detection.hpp" 27 #include "rule.hpp" 28 #include "system.hpp" 29 30 #include <memory> 31 #include <stdexcept> 32 #include <string> 33 #include <tuple> 34 #include <utility> 35 #include <vector> 36 37 #include <gmock/gmock.h> 38 #include <gtest/gtest.h> 39 40 using namespace phosphor::power::regulators; 41 42 using ::testing::Return; 43 using ::testing::Throw; 44 45 /** 46 * Creates the parent objects that normally contain a PresenceDetection object. 47 * 48 * A PresenceDetection object is normally contained within a hierarchy of 49 * System, Chassis, and Device objects. These objects are required in order to 50 * call the execute() method. 51 * 52 * Creates the System, Chassis, and Device objects. The PresenceDetection 53 * object is moved into the Device object. 54 * 55 * @param detection PresenceDetection object to move into object hierarchy 56 * @return Pointers to the System, Chassis, and Device objects. The Chassis and 57 * Device objects are contained within the System object and will be 58 * automatically destructed. 59 */ 60 std::tuple<std::unique_ptr<System>, Chassis*, Device*> 61 createParentObjects(std::unique_ptr<PresenceDetection> detection) 62 { 63 // Create mock I2CInterface 64 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface = 65 std::make_unique<i2c::MockedI2CInterface>(); 66 67 // Create Device that contains PresenceDetection 68 std::unique_ptr<Device> device = std::make_unique<Device>( 69 "vdd_reg", true, 70 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2", 71 std::move(i2cInterface), std::move(detection)); 72 Device* devicePtr = device.get(); 73 74 // Create Chassis that contains Device 75 std::vector<std::unique_ptr<Device>> devices{}; 76 devices.emplace_back(std::move(device)); 77 std::unique_ptr<Chassis> chassis = 78 std::make_unique<Chassis>(1, std::move(devices)); 79 Chassis* chassisPtr = chassis.get(); 80 81 // Create System that contains Chassis 82 std::vector<std::unique_ptr<Rule>> rules{}; 83 std::vector<std::unique_ptr<Chassis>> chassisVec{}; 84 chassisVec.emplace_back(std::move(chassis)); 85 std::unique_ptr<System> system = 86 std::make_unique<System>(std::move(rules), std::move(chassisVec)); 87 88 return std::make_tuple(std::move(system), chassisPtr, devicePtr); 89 } 90 91 TEST(PresenceDetectionTests, Constructor) 92 { 93 std::vector<std::unique_ptr<Action>> actions{}; 94 actions.emplace_back(std::make_unique<MockAction>()); 95 96 PresenceDetection detection{std::move(actions)}; 97 EXPECT_EQ(detection.getActions().size(), 1); 98 EXPECT_FALSE(detection.getCachedPresence().has_value()); 99 } 100 101 TEST(PresenceDetectionTests, ClearCache) 102 { 103 // Create MockAction that will return true once 104 std::unique_ptr<MockAction> action = std::make_unique<MockAction>(); 105 EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true)); 106 107 // Create PresenceDetection 108 std::vector<std::unique_ptr<Action>> actions{}; 109 actions.emplace_back(std::move(action)); 110 PresenceDetection* detection = new PresenceDetection(std::move(actions)); 111 112 // Create parent System, Chassis, and Device objects 113 auto [system, chassis, device] = 114 createParentObjects(std::unique_ptr<PresenceDetection>{detection}); 115 116 // Verify that initially no presence value is cached 117 EXPECT_FALSE(detection->getCachedPresence().has_value()); 118 119 // Call execute() which should obtain and cache presence value 120 MockServices services{}; 121 EXPECT_TRUE(detection->execute(services, *system, *chassis, *device)); 122 123 // Verify true presence value was cached 124 EXPECT_TRUE(detection->getCachedPresence().has_value()); 125 EXPECT_TRUE(detection->getCachedPresence().value()); 126 127 // Clear cached presence value 128 detection->clearCache(); 129 130 // Verify that no presence value is cached 131 EXPECT_FALSE(detection->getCachedPresence().has_value()); 132 } 133 134 TEST(PresenceDetectionTests, Execute) 135 { 136 // Create ComparePresenceAction 137 std::unique_ptr<ComparePresenceAction> action = 138 std::make_unique<ComparePresenceAction>( 139 "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu2", 140 true); 141 142 // Create PresenceDetection 143 std::vector<std::unique_ptr<Action>> actions{}; 144 actions.emplace_back(std::move(action)); 145 PresenceDetection* detection = new PresenceDetection(std::move(actions)); 146 147 // Create parent System, Chassis, and Device objects 148 auto [system, chassis, device] = 149 createParentObjects(std::unique_ptr<PresenceDetection>{detection}); 150 151 // Test where works: Present: Value is not cached 152 { 153 EXPECT_FALSE(detection->getCachedPresence().has_value()); 154 155 // Create MockServices. MockPresenceService::isPresent() should return 156 // true. 157 MockServices services{}; 158 MockPresenceService& presenceService = 159 services.getMockPresenceService(); 160 EXPECT_CALL(presenceService, 161 isPresent("/xyz/openbmc_project/inventory/system/chassis/" 162 "motherboard/cpu2")) 163 .Times(1) 164 .WillOnce(Return(true)); 165 166 // Execute PresenceDetection 167 EXPECT_TRUE(detection->execute(services, *system, *chassis, *device)); 168 169 EXPECT_TRUE(detection->getCachedPresence().has_value()); 170 EXPECT_TRUE(detection->getCachedPresence().value()); 171 } 172 173 // Test where works: Present: Value is cached 174 { 175 EXPECT_TRUE(detection->getCachedPresence().has_value()); 176 177 // Create MockServices. MockPresenceService::isPresent() should not be 178 // called. 179 MockServices services{}; 180 MockPresenceService& presenceService = 181 services.getMockPresenceService(); 182 EXPECT_CALL(presenceService, isPresent).Times(0); 183 184 // Execute PresenceDetection 185 EXPECT_TRUE(detection->execute(services, *system, *chassis, *device)); 186 } 187 188 // Test where works: Not present: Value is not cached 189 { 190 // Clear cached presence value 191 detection->clearCache(); 192 EXPECT_FALSE(detection->getCachedPresence().has_value()); 193 194 // Create MockServices. MockPresenceService::isPresent() should return 195 // false. 196 MockServices services{}; 197 MockPresenceService& presenceService = 198 services.getMockPresenceService(); 199 EXPECT_CALL(presenceService, 200 isPresent("/xyz/openbmc_project/inventory/system/chassis/" 201 "motherboard/cpu2")) 202 .Times(1) 203 .WillOnce(Return(false)); 204 205 // Execute PresenceDetection 206 EXPECT_FALSE(detection->execute(services, *system, *chassis, *device)); 207 208 EXPECT_TRUE(detection->getCachedPresence().has_value()); 209 EXPECT_FALSE(detection->getCachedPresence().value()); 210 } 211 212 // Test where works: Not present: Value is cached 213 { 214 EXPECT_TRUE(detection->getCachedPresence().has_value()); 215 216 // Create MockServices. MockPresenceService::isPresent() should not be 217 // called. 218 MockServices services{}; 219 MockPresenceService& presenceService = 220 services.getMockPresenceService(); 221 EXPECT_CALL(presenceService, isPresent).Times(0); 222 223 // Execute PresenceDetection 224 EXPECT_FALSE(detection->execute(services, *system, *chassis, *device)); 225 } 226 227 // Test where fails 228 { 229 // Clear cached presence value 230 detection->clearCache(); 231 EXPECT_FALSE(detection->getCachedPresence().has_value()); 232 233 // Create MockServices. MockPresenceService::isPresent() should throw 234 // an exception. 235 MockServices services{}; 236 MockPresenceService& presenceService = 237 services.getMockPresenceService(); 238 EXPECT_CALL(presenceService, 239 isPresent("/xyz/openbmc_project/inventory/system/chassis/" 240 "motherboard/cpu2")) 241 .Times(1) 242 .WillOnce( 243 Throw(std::runtime_error{"DBusError: Invalid object path."})); 244 245 // Define expected journal messages that should be passed to MockJournal 246 MockJournal& journal = services.getMockJournal(); 247 std::vector<std::string> exceptionMessages{ 248 "DBusError: Invalid object path.", 249 "ActionError: compare_presence: { fru: " 250 "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu2, " 251 "value: true }"}; 252 EXPECT_CALL(journal, logError(exceptionMessages)).Times(1); 253 EXPECT_CALL(journal, 254 logError("Unable to determine presence of vdd_reg")) 255 .Times(1); 256 257 // Execute PresenceDetection. Should return true when an error occurs. 258 EXPECT_TRUE(detection->execute(services, *system, *chassis, *device)); 259 260 EXPECT_TRUE(detection->getCachedPresence().has_value()); 261 EXPECT_TRUE(detection->getCachedPresence().value()); 262 } 263 } 264 265 TEST(PresenceDetectionTests, GetActions) 266 { 267 std::vector<std::unique_ptr<Action>> actions{}; 268 269 MockAction* action1 = new MockAction{}; 270 actions.emplace_back(std::unique_ptr<MockAction>{action1}); 271 272 MockAction* action2 = new MockAction{}; 273 actions.emplace_back(std::unique_ptr<MockAction>{action2}); 274 275 PresenceDetection detection{std::move(actions)}; 276 EXPECT_EQ(detection.getActions().size(), 2); 277 EXPECT_EQ(detection.getActions()[0].get(), action1); 278 EXPECT_EQ(detection.getActions()[1].get(), action2); 279 } 280 281 TEST(PresenceDetectionTests, GetCachedPresence) 282 { 283 // Create MockAction that will return false once 284 std::unique_ptr<MockAction> action = std::make_unique<MockAction>(); 285 EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(false)); 286 287 // Create PresenceDetection 288 std::vector<std::unique_ptr<Action>> actions{}; 289 actions.emplace_back(std::move(action)); 290 PresenceDetection* detection = new PresenceDetection(std::move(actions)); 291 292 // Create parent System, Chassis, and Device objects 293 auto [system, chassis, device] = 294 createParentObjects(std::unique_ptr<PresenceDetection>{detection}); 295 296 // Verify that initially no presence value is cached 297 EXPECT_FALSE(detection->getCachedPresence().has_value()); 298 299 // Call execute() which should obtain and cache presence value 300 MockServices services{}; 301 EXPECT_FALSE(detection->execute(services, *system, *chassis, *device)); 302 303 // Verify false presence value was cached 304 EXPECT_TRUE(detection->getCachedPresence().has_value()); 305 EXPECT_FALSE(detection->getCachedPresence().value()); 306 307 // Clear cached presence value 308 detection->clearCache(); 309 310 // Verify that no presence value is cached 311 EXPECT_FALSE(detection->getCachedPresence().has_value()); 312 } 313