1bfe2c25aSShawn McCarney /** 2bfe2c25aSShawn McCarney * Copyright © 2020 IBM Corporation 3bfe2c25aSShawn McCarney * 4bfe2c25aSShawn McCarney * Licensed under the Apache License, Version 2.0 (the "License"); 5bfe2c25aSShawn McCarney * you may not use this file except in compliance with the License. 6bfe2c25aSShawn McCarney * You may obtain a copy of the License at 7bfe2c25aSShawn McCarney * 8bfe2c25aSShawn McCarney * http://www.apache.org/licenses/LICENSE-2.0 9bfe2c25aSShawn McCarney * 10bfe2c25aSShawn McCarney * Unless required by applicable law or agreed to in writing, software 11bfe2c25aSShawn McCarney * distributed under the License is distributed on an "AS IS" BASIS, 12bfe2c25aSShawn McCarney * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13bfe2c25aSShawn McCarney * See the License for the specific language governing permissions and 14bfe2c25aSShawn McCarney * limitations under the License. 15bfe2c25aSShawn McCarney */ 16bfe2c25aSShawn McCarney #include "action.hpp" 17462e5926SBob King #include "chassis.hpp" 18462e5926SBob King #include "compare_presence_action.hpp" 19462e5926SBob King #include "device.hpp" 20462e5926SBob King #include "i2c_interface.hpp" 21bfe2c25aSShawn McCarney #include "mock_action.hpp" 22*81a2f90bSShawn McCarney #include "mock_error_logging.hpp" 23462e5926SBob King #include "mock_journal.hpp" 24462e5926SBob King #include "mock_presence_service.hpp" 25462e5926SBob King #include "mock_services.hpp" 26462e5926SBob King #include "mocked_i2c_interface.hpp" 27bfe2c25aSShawn McCarney #include "presence_detection.hpp" 28462e5926SBob King #include "rule.hpp" 29462e5926SBob King #include "system.hpp" 30bfe2c25aSShawn McCarney 31*81a2f90bSShawn McCarney #include <sdbusplus/exception.hpp> 32*81a2f90bSShawn McCarney 33bfe2c25aSShawn McCarney #include <memory> 34462e5926SBob King #include <stdexcept> 35462e5926SBob King #include <string> 36462e5926SBob King #include <tuple> 37bfe2c25aSShawn McCarney #include <utility> 38bfe2c25aSShawn McCarney #include <vector> 39bfe2c25aSShawn McCarney 40462e5926SBob King #include <gmock/gmock.h> 41bfe2c25aSShawn McCarney #include <gtest/gtest.h> 42bfe2c25aSShawn McCarney 43bfe2c25aSShawn McCarney using namespace phosphor::power::regulators; 44bfe2c25aSShawn McCarney 45*81a2f90bSShawn McCarney using ::testing::Ref; 46462e5926SBob King using ::testing::Return; 47462e5926SBob King using ::testing::Throw; 48462e5926SBob King 49462e5926SBob King /** 50*81a2f90bSShawn McCarney * Concrete subclass of sdbusplus::exception_t abstract base class. 51*81a2f90bSShawn McCarney */ 52*81a2f90bSShawn McCarney class TestSDBusError : public sdbusplus::exception_t 53*81a2f90bSShawn McCarney { 54*81a2f90bSShawn McCarney public: 55*81a2f90bSShawn McCarney TestSDBusError(const std::string& error) : error{error} 56*81a2f90bSShawn McCarney { 57*81a2f90bSShawn McCarney } 58*81a2f90bSShawn McCarney 59*81a2f90bSShawn McCarney const char* what() const noexcept override 60*81a2f90bSShawn McCarney { 61*81a2f90bSShawn McCarney return error.c_str(); 62*81a2f90bSShawn McCarney } 63*81a2f90bSShawn McCarney 64*81a2f90bSShawn McCarney const char* name() const noexcept override 65*81a2f90bSShawn McCarney { 66*81a2f90bSShawn McCarney return ""; 67*81a2f90bSShawn McCarney } 68*81a2f90bSShawn McCarney 69*81a2f90bSShawn McCarney const char* description() const noexcept override 70*81a2f90bSShawn McCarney { 71*81a2f90bSShawn McCarney return ""; 72*81a2f90bSShawn McCarney } 73*81a2f90bSShawn McCarney 74*81a2f90bSShawn McCarney private: 75*81a2f90bSShawn McCarney const std::string error{}; 76*81a2f90bSShawn McCarney }; 77*81a2f90bSShawn McCarney 78*81a2f90bSShawn McCarney /** 79462e5926SBob King * Creates the parent objects that normally contain a PresenceDetection object. 80462e5926SBob King * 81462e5926SBob King * A PresenceDetection object is normally contained within a hierarchy of 82462e5926SBob King * System, Chassis, and Device objects. These objects are required in order to 83462e5926SBob King * call the execute() method. 84462e5926SBob King * 85462e5926SBob King * Creates the System, Chassis, and Device objects. The PresenceDetection 86462e5926SBob King * object is moved into the Device object. 87462e5926SBob King * 88462e5926SBob King * @param detection PresenceDetection object to move into object hierarchy 89462e5926SBob King * @return Pointers to the System, Chassis, and Device objects. The Chassis and 90462e5926SBob King * Device objects are contained within the System object and will be 91462e5926SBob King * automatically destructed. 92462e5926SBob King */ 93462e5926SBob King std::tuple<std::unique_ptr<System>, Chassis*, Device*> 94462e5926SBob King createParentObjects(std::unique_ptr<PresenceDetection> detection) 95462e5926SBob King { 96462e5926SBob King // Create mock I2CInterface 97462e5926SBob King std::unique_ptr<i2c::MockedI2CInterface> i2cInterface = 98462e5926SBob King std::make_unique<i2c::MockedI2CInterface>(); 99462e5926SBob King 100462e5926SBob King // Create Device that contains PresenceDetection 101462e5926SBob King std::unique_ptr<Device> device = std::make_unique<Device>( 102462e5926SBob King "vdd_reg", true, 103462e5926SBob King "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2", 104462e5926SBob King std::move(i2cInterface), std::move(detection)); 105462e5926SBob King Device* devicePtr = device.get(); 106462e5926SBob King 107462e5926SBob King // Create Chassis that contains Device 108462e5926SBob King std::vector<std::unique_ptr<Device>> devices{}; 109462e5926SBob King devices.emplace_back(std::move(device)); 110462e5926SBob King std::unique_ptr<Chassis> chassis = 111462e5926SBob King std::make_unique<Chassis>(1, std::move(devices)); 112462e5926SBob King Chassis* chassisPtr = chassis.get(); 113462e5926SBob King 114462e5926SBob King // Create System that contains Chassis 115462e5926SBob King std::vector<std::unique_ptr<Rule>> rules{}; 116462e5926SBob King std::vector<std::unique_ptr<Chassis>> chassisVec{}; 117462e5926SBob King chassisVec.emplace_back(std::move(chassis)); 118462e5926SBob King std::unique_ptr<System> system = 119462e5926SBob King std::make_unique<System>(std::move(rules), std::move(chassisVec)); 120462e5926SBob King 121462e5926SBob King return std::make_tuple(std::move(system), chassisPtr, devicePtr); 122462e5926SBob King } 123462e5926SBob King 124bfe2c25aSShawn McCarney TEST(PresenceDetectionTests, Constructor) 125bfe2c25aSShawn McCarney { 126bfe2c25aSShawn McCarney std::vector<std::unique_ptr<Action>> actions{}; 127462e5926SBob King actions.emplace_back(std::make_unique<MockAction>()); 128bfe2c25aSShawn McCarney 129462e5926SBob King PresenceDetection detection{std::move(actions)}; 130462e5926SBob King EXPECT_EQ(detection.getActions().size(), 1); 131462e5926SBob King EXPECT_FALSE(detection.getCachedPresence().has_value()); 132462e5926SBob King } 133462e5926SBob King 134462e5926SBob King TEST(PresenceDetectionTests, ClearCache) 135462e5926SBob King { 136462e5926SBob King // Create MockAction that will return true once 137462e5926SBob King std::unique_ptr<MockAction> action = std::make_unique<MockAction>(); 138462e5926SBob King EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true)); 139462e5926SBob King 140462e5926SBob King // Create PresenceDetection 141462e5926SBob King std::vector<std::unique_ptr<Action>> actions{}; 142462e5926SBob King actions.emplace_back(std::move(action)); 143462e5926SBob King PresenceDetection* detection = new PresenceDetection(std::move(actions)); 144462e5926SBob King 145462e5926SBob King // Create parent System, Chassis, and Device objects 146462e5926SBob King auto [system, chassis, device] = 147462e5926SBob King createParentObjects(std::unique_ptr<PresenceDetection>{detection}); 148462e5926SBob King 149462e5926SBob King // Verify that initially no presence value is cached 150462e5926SBob King EXPECT_FALSE(detection->getCachedPresence().has_value()); 151462e5926SBob King 152462e5926SBob King // Call execute() which should obtain and cache presence value 153462e5926SBob King MockServices services{}; 154462e5926SBob King EXPECT_TRUE(detection->execute(services, *system, *chassis, *device)); 155462e5926SBob King 156462e5926SBob King // Verify true presence value was cached 157462e5926SBob King EXPECT_TRUE(detection->getCachedPresence().has_value()); 158462e5926SBob King EXPECT_TRUE(detection->getCachedPresence().value()); 159462e5926SBob King 160462e5926SBob King // Clear cached presence value 161462e5926SBob King detection->clearCache(); 162462e5926SBob King 163462e5926SBob King // Verify that no presence value is cached 164462e5926SBob King EXPECT_FALSE(detection->getCachedPresence().has_value()); 165bfe2c25aSShawn McCarney } 166bfe2c25aSShawn McCarney 167bfe2c25aSShawn McCarney TEST(PresenceDetectionTests, Execute) 168bfe2c25aSShawn McCarney { 169462e5926SBob King // Create ComparePresenceAction 170462e5926SBob King std::unique_ptr<ComparePresenceAction> action = 171462e5926SBob King std::make_unique<ComparePresenceAction>( 172462e5926SBob King "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu2", 173462e5926SBob King true); 174462e5926SBob King 175462e5926SBob King // Create PresenceDetection 176462e5926SBob King std::vector<std::unique_ptr<Action>> actions{}; 177462e5926SBob King actions.emplace_back(std::move(action)); 178462e5926SBob King PresenceDetection* detection = new PresenceDetection(std::move(actions)); 179462e5926SBob King 180462e5926SBob King // Create parent System, Chassis, and Device objects 181462e5926SBob King auto [system, chassis, device] = 182462e5926SBob King createParentObjects(std::unique_ptr<PresenceDetection>{detection}); 183462e5926SBob King 184462e5926SBob King // Test where works: Present: Value is not cached 185462e5926SBob King { 186462e5926SBob King EXPECT_FALSE(detection->getCachedPresence().has_value()); 187462e5926SBob King 188462e5926SBob King // Create MockServices. MockPresenceService::isPresent() should return 189462e5926SBob King // true. 190462e5926SBob King MockServices services{}; 191462e5926SBob King MockPresenceService& presenceService = 192462e5926SBob King services.getMockPresenceService(); 193462e5926SBob King EXPECT_CALL(presenceService, 194462e5926SBob King isPresent("/xyz/openbmc_project/inventory/system/chassis/" 195462e5926SBob King "motherboard/cpu2")) 196462e5926SBob King .Times(1) 197462e5926SBob King .WillOnce(Return(true)); 198462e5926SBob King 199462e5926SBob King // Execute PresenceDetection 200462e5926SBob King EXPECT_TRUE(detection->execute(services, *system, *chassis, *device)); 201462e5926SBob King 202462e5926SBob King EXPECT_TRUE(detection->getCachedPresence().has_value()); 203462e5926SBob King EXPECT_TRUE(detection->getCachedPresence().value()); 204462e5926SBob King } 205462e5926SBob King 206462e5926SBob King // Test where works: Present: Value is cached 207462e5926SBob King { 208462e5926SBob King EXPECT_TRUE(detection->getCachedPresence().has_value()); 209462e5926SBob King 210462e5926SBob King // Create MockServices. MockPresenceService::isPresent() should not be 211462e5926SBob King // called. 212462e5926SBob King MockServices services{}; 213462e5926SBob King MockPresenceService& presenceService = 214462e5926SBob King services.getMockPresenceService(); 215462e5926SBob King EXPECT_CALL(presenceService, isPresent).Times(0); 216462e5926SBob King 217462e5926SBob King // Execute PresenceDetection 218462e5926SBob King EXPECT_TRUE(detection->execute(services, *system, *chassis, *device)); 219462e5926SBob King } 220462e5926SBob King 221462e5926SBob King // Test where works: Not present: Value is not cached 222462e5926SBob King { 223462e5926SBob King // Clear cached presence value 224462e5926SBob King detection->clearCache(); 225462e5926SBob King EXPECT_FALSE(detection->getCachedPresence().has_value()); 226462e5926SBob King 227462e5926SBob King // Create MockServices. MockPresenceService::isPresent() should return 228462e5926SBob King // false. 229462e5926SBob King MockServices services{}; 230462e5926SBob King MockPresenceService& presenceService = 231462e5926SBob King services.getMockPresenceService(); 232462e5926SBob King EXPECT_CALL(presenceService, 233462e5926SBob King isPresent("/xyz/openbmc_project/inventory/system/chassis/" 234462e5926SBob King "motherboard/cpu2")) 235462e5926SBob King .Times(1) 236462e5926SBob King .WillOnce(Return(false)); 237462e5926SBob King 238462e5926SBob King // Execute PresenceDetection 239462e5926SBob King EXPECT_FALSE(detection->execute(services, *system, *chassis, *device)); 240462e5926SBob King 241462e5926SBob King EXPECT_TRUE(detection->getCachedPresence().has_value()); 242462e5926SBob King EXPECT_FALSE(detection->getCachedPresence().value()); 243462e5926SBob King } 244462e5926SBob King 245462e5926SBob King // Test where works: Not present: Value is cached 246462e5926SBob King { 247462e5926SBob King EXPECT_TRUE(detection->getCachedPresence().has_value()); 248462e5926SBob King 249462e5926SBob King // Create MockServices. MockPresenceService::isPresent() should not be 250462e5926SBob King // called. 251462e5926SBob King MockServices services{}; 252462e5926SBob King MockPresenceService& presenceService = 253462e5926SBob King services.getMockPresenceService(); 254462e5926SBob King EXPECT_CALL(presenceService, isPresent).Times(0); 255462e5926SBob King 256462e5926SBob King // Execute PresenceDetection 257462e5926SBob King EXPECT_FALSE(detection->execute(services, *system, *chassis, *device)); 258462e5926SBob King } 259462e5926SBob King 260462e5926SBob King // Test where fails 261462e5926SBob King { 262462e5926SBob King // Clear cached presence value 263462e5926SBob King detection->clearCache(); 264462e5926SBob King EXPECT_FALSE(detection->getCachedPresence().has_value()); 265462e5926SBob King 266462e5926SBob King // Create MockServices. MockPresenceService::isPresent() should throw 267462e5926SBob King // an exception. 268462e5926SBob King MockServices services{}; 269462e5926SBob King MockPresenceService& presenceService = 270462e5926SBob King services.getMockPresenceService(); 271462e5926SBob King EXPECT_CALL(presenceService, 272462e5926SBob King isPresent("/xyz/openbmc_project/inventory/system/chassis/" 273462e5926SBob King "motherboard/cpu2")) 274462e5926SBob King .Times(1) 275*81a2f90bSShawn McCarney .WillOnce(Throw(TestSDBusError{"DBusError: Invalid object path."})); 276462e5926SBob King 277462e5926SBob King // Define expected journal messages that should be passed to MockJournal 278462e5926SBob King MockJournal& journal = services.getMockJournal(); 279462e5926SBob King std::vector<std::string> exceptionMessages{ 280462e5926SBob King "DBusError: Invalid object path.", 281462e5926SBob King "ActionError: compare_presence: { fru: " 282462e5926SBob King "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu2, " 283462e5926SBob King "value: true }"}; 284462e5926SBob King EXPECT_CALL(journal, logError(exceptionMessages)).Times(1); 285462e5926SBob King EXPECT_CALL(journal, 286462e5926SBob King logError("Unable to determine presence of vdd_reg")) 287462e5926SBob King .Times(1); 288462e5926SBob King 289*81a2f90bSShawn McCarney // Expect logDBusError() to be called 290*81a2f90bSShawn McCarney MockErrorLogging& errorLogging = services.getMockErrorLogging(); 291*81a2f90bSShawn McCarney EXPECT_CALL(errorLogging, 292*81a2f90bSShawn McCarney logDBusError(Entry::Level::Warning, Ref(journal))) 293*81a2f90bSShawn McCarney .Times(1); 294*81a2f90bSShawn McCarney 295462e5926SBob King // Execute PresenceDetection. Should return true when an error occurs. 296462e5926SBob King EXPECT_TRUE(detection->execute(services, *system, *chassis, *device)); 297462e5926SBob King 298462e5926SBob King EXPECT_TRUE(detection->getCachedPresence().has_value()); 299462e5926SBob King EXPECT_TRUE(detection->getCachedPresence().value()); 300462e5926SBob King } 301bfe2c25aSShawn McCarney } 302bfe2c25aSShawn McCarney 303bfe2c25aSShawn McCarney TEST(PresenceDetectionTests, GetActions) 304bfe2c25aSShawn McCarney { 305bfe2c25aSShawn McCarney std::vector<std::unique_ptr<Action>> actions{}; 306bfe2c25aSShawn McCarney 307bfe2c25aSShawn McCarney MockAction* action1 = new MockAction{}; 308462e5926SBob King actions.emplace_back(std::unique_ptr<MockAction>{action1}); 309bfe2c25aSShawn McCarney 310bfe2c25aSShawn McCarney MockAction* action2 = new MockAction{}; 311462e5926SBob King actions.emplace_back(std::unique_ptr<MockAction>{action2}); 312bfe2c25aSShawn McCarney 313462e5926SBob King PresenceDetection detection{std::move(actions)}; 314462e5926SBob King EXPECT_EQ(detection.getActions().size(), 2); 315462e5926SBob King EXPECT_EQ(detection.getActions()[0].get(), action1); 316462e5926SBob King EXPECT_EQ(detection.getActions()[1].get(), action2); 317462e5926SBob King } 318462e5926SBob King 319462e5926SBob King TEST(PresenceDetectionTests, GetCachedPresence) 320462e5926SBob King { 321462e5926SBob King // Create MockAction that will return false once 322462e5926SBob King std::unique_ptr<MockAction> action = std::make_unique<MockAction>(); 323462e5926SBob King EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(false)); 324462e5926SBob King 325462e5926SBob King // Create PresenceDetection 326462e5926SBob King std::vector<std::unique_ptr<Action>> actions{}; 327462e5926SBob King actions.emplace_back(std::move(action)); 328462e5926SBob King PresenceDetection* detection = new PresenceDetection(std::move(actions)); 329462e5926SBob King 330462e5926SBob King // Create parent System, Chassis, and Device objects 331462e5926SBob King auto [system, chassis, device] = 332462e5926SBob King createParentObjects(std::unique_ptr<PresenceDetection>{detection}); 333462e5926SBob King 334462e5926SBob King // Verify that initially no presence value is cached 335462e5926SBob King EXPECT_FALSE(detection->getCachedPresence().has_value()); 336462e5926SBob King 337462e5926SBob King // Call execute() which should obtain and cache presence value 338462e5926SBob King MockServices services{}; 339462e5926SBob King EXPECT_FALSE(detection->execute(services, *system, *chassis, *device)); 340462e5926SBob King 341462e5926SBob King // Verify false presence value was cached 342462e5926SBob King EXPECT_TRUE(detection->getCachedPresence().has_value()); 343462e5926SBob King EXPECT_FALSE(detection->getCachedPresence().value()); 344462e5926SBob King 345462e5926SBob King // Clear cached presence value 346462e5926SBob King detection->clearCache(); 347462e5926SBob King 348462e5926SBob King // Verify that no presence value is cached 349462e5926SBob King EXPECT_FALSE(detection->getCachedPresence().has_value()); 350bfe2c25aSShawn McCarney } 351