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"
2281a2f90bSShawn 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"
308c232456SShawn McCarney #include "test_sdbus_error.hpp"
31bfe2c25aSShawn McCarney
3281a2f90bSShawn McCarney #include <sdbusplus/exception.hpp>
3381a2f90bSShawn McCarney
34bfe2c25aSShawn McCarney #include <memory>
35462e5926SBob King #include <stdexcept>
36462e5926SBob King #include <string>
37462e5926SBob King #include <tuple>
38bfe2c25aSShawn McCarney #include <utility>
39bfe2c25aSShawn McCarney #include <vector>
40bfe2c25aSShawn McCarney
41462e5926SBob King #include <gmock/gmock.h>
42bfe2c25aSShawn McCarney #include <gtest/gtest.h>
43bfe2c25aSShawn McCarney
44bfe2c25aSShawn McCarney using namespace phosphor::power::regulators;
45bfe2c25aSShawn McCarney
4681a2f90bSShawn McCarney using ::testing::Ref;
47462e5926SBob King using ::testing::Return;
48462e5926SBob King using ::testing::Throw;
49462e5926SBob King
50462e5926SBob King /**
51462e5926SBob King * Creates the parent objects that normally contain a PresenceDetection object.
52462e5926SBob King *
53462e5926SBob King * A PresenceDetection object is normally contained within a hierarchy of
54462e5926SBob King * System, Chassis, and Device objects. These objects are required in order to
55462e5926SBob King * call the execute() method.
56462e5926SBob King *
57462e5926SBob King * Creates the System, Chassis, and Device objects. The PresenceDetection
58462e5926SBob King * object is moved into the Device object.
59462e5926SBob King *
60462e5926SBob King * @param detection PresenceDetection object to move into object hierarchy
61462e5926SBob King * @return Pointers to the System, Chassis, and Device objects. The Chassis and
62462e5926SBob King * Device objects are contained within the System object and will be
63462e5926SBob King * automatically destructed.
64462e5926SBob King */
createParentObjects(std::unique_ptr<PresenceDetection> detection)65*92261f88SPatrick Williams std::tuple<std::unique_ptr<System>, Chassis*, Device*> createParentObjects(
66*92261f88SPatrick Williams std::unique_ptr<PresenceDetection> detection)
67462e5926SBob King {
68462e5926SBob King // Create mock I2CInterface
69462e5926SBob King std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
70462e5926SBob King std::make_unique<i2c::MockedI2CInterface>();
71462e5926SBob King
72462e5926SBob King // Create Device that contains PresenceDetection
73462e5926SBob King std::unique_ptr<Device> device = std::make_unique<Device>(
74462e5926SBob King "vdd_reg", true,
75462e5926SBob King "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2",
76462e5926SBob King std::move(i2cInterface), std::move(detection));
77462e5926SBob King Device* devicePtr = device.get();
78462e5926SBob King
79462e5926SBob King // Create Chassis that contains Device
80462e5926SBob King std::vector<std::unique_ptr<Device>> devices{};
81462e5926SBob King devices.emplace_back(std::move(device));
82cb3f6a63SShawn McCarney std::unique_ptr<Chassis> chassis = std::make_unique<Chassis>(
83cb3f6a63SShawn McCarney 1, "/xyz/openbmc_project/inventory/system/chassis", std::move(devices));
84462e5926SBob King Chassis* chassisPtr = chassis.get();
85462e5926SBob King
86462e5926SBob King // Create System that contains Chassis
87462e5926SBob King std::vector<std::unique_ptr<Rule>> rules{};
88462e5926SBob King std::vector<std::unique_ptr<Chassis>> chassisVec{};
89462e5926SBob King chassisVec.emplace_back(std::move(chassis));
90462e5926SBob King std::unique_ptr<System> system =
91462e5926SBob King std::make_unique<System>(std::move(rules), std::move(chassisVec));
92462e5926SBob King
93462e5926SBob King return std::make_tuple(std::move(system), chassisPtr, devicePtr);
94462e5926SBob King }
95462e5926SBob King
TEST(PresenceDetectionTests,Constructor)96bfe2c25aSShawn McCarney TEST(PresenceDetectionTests, Constructor)
97bfe2c25aSShawn McCarney {
98bfe2c25aSShawn McCarney std::vector<std::unique_ptr<Action>> actions{};
99462e5926SBob King actions.emplace_back(std::make_unique<MockAction>());
100bfe2c25aSShawn McCarney
101462e5926SBob King PresenceDetection detection{std::move(actions)};
102462e5926SBob King EXPECT_EQ(detection.getActions().size(), 1);
103462e5926SBob King EXPECT_FALSE(detection.getCachedPresence().has_value());
104462e5926SBob King }
105462e5926SBob King
TEST(PresenceDetectionTests,ClearCache)106462e5926SBob King TEST(PresenceDetectionTests, ClearCache)
107462e5926SBob King {
108462e5926SBob King // Create MockAction that will return true once
109462e5926SBob King std::unique_ptr<MockAction> action = std::make_unique<MockAction>();
110462e5926SBob King EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true));
111462e5926SBob King
112462e5926SBob King // Create PresenceDetection
113462e5926SBob King std::vector<std::unique_ptr<Action>> actions{};
114462e5926SBob King actions.emplace_back(std::move(action));
115462e5926SBob King PresenceDetection* detection = new PresenceDetection(std::move(actions));
116462e5926SBob King
117462e5926SBob King // Create parent System, Chassis, and Device objects
118462e5926SBob King auto [system, chassis, device] =
119462e5926SBob King createParentObjects(std::unique_ptr<PresenceDetection>{detection});
120462e5926SBob King
121462e5926SBob King // Verify that initially no presence value is cached
122462e5926SBob King EXPECT_FALSE(detection->getCachedPresence().has_value());
123462e5926SBob King
124462e5926SBob King // Call execute() which should obtain and cache presence value
125462e5926SBob King MockServices services{};
126462e5926SBob King EXPECT_TRUE(detection->execute(services, *system, *chassis, *device));
127462e5926SBob King
128462e5926SBob King // Verify true presence value was cached
129462e5926SBob King EXPECT_TRUE(detection->getCachedPresence().has_value());
130462e5926SBob King EXPECT_TRUE(detection->getCachedPresence().value());
131462e5926SBob King
132462e5926SBob King // Clear cached presence value
133462e5926SBob King detection->clearCache();
134462e5926SBob King
135462e5926SBob King // Verify that no presence value is cached
136462e5926SBob King EXPECT_FALSE(detection->getCachedPresence().has_value());
137bfe2c25aSShawn McCarney }
138bfe2c25aSShawn McCarney
TEST(PresenceDetectionTests,Execute)139bfe2c25aSShawn McCarney TEST(PresenceDetectionTests, Execute)
140bfe2c25aSShawn McCarney {
141462e5926SBob King // Create ComparePresenceAction
142462e5926SBob King std::unique_ptr<ComparePresenceAction> action =
143462e5926SBob King std::make_unique<ComparePresenceAction>(
144462e5926SBob King "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu2",
145462e5926SBob King true);
146462e5926SBob King
147462e5926SBob King // Create PresenceDetection
148462e5926SBob King std::vector<std::unique_ptr<Action>> actions{};
149462e5926SBob King actions.emplace_back(std::move(action));
150462e5926SBob King PresenceDetection* detection = new PresenceDetection(std::move(actions));
151462e5926SBob King
152462e5926SBob King // Create parent System, Chassis, and Device objects
153462e5926SBob King auto [system, chassis, device] =
154462e5926SBob King createParentObjects(std::unique_ptr<PresenceDetection>{detection});
155462e5926SBob King
156462e5926SBob King // Test where works: Present: Value is not cached
157462e5926SBob King {
158462e5926SBob King EXPECT_FALSE(detection->getCachedPresence().has_value());
159462e5926SBob King
160462e5926SBob King // Create MockServices. MockPresenceService::isPresent() should return
161462e5926SBob King // true.
162462e5926SBob King MockServices services{};
163462e5926SBob King MockPresenceService& presenceService =
164462e5926SBob King services.getMockPresenceService();
165462e5926SBob King EXPECT_CALL(presenceService,
166462e5926SBob King isPresent("/xyz/openbmc_project/inventory/system/chassis/"
167462e5926SBob King "motherboard/cpu2"))
168462e5926SBob King .Times(1)
169462e5926SBob King .WillOnce(Return(true));
170462e5926SBob King
171462e5926SBob King // Execute PresenceDetection
172462e5926SBob King EXPECT_TRUE(detection->execute(services, *system, *chassis, *device));
173462e5926SBob King
174462e5926SBob King EXPECT_TRUE(detection->getCachedPresence().has_value());
175462e5926SBob King EXPECT_TRUE(detection->getCachedPresence().value());
176462e5926SBob King }
177462e5926SBob King
178462e5926SBob King // Test where works: Present: Value is cached
179462e5926SBob King {
180462e5926SBob King EXPECT_TRUE(detection->getCachedPresence().has_value());
181462e5926SBob King
182462e5926SBob King // Create MockServices. MockPresenceService::isPresent() should not be
183462e5926SBob King // called.
184462e5926SBob King MockServices services{};
185462e5926SBob King MockPresenceService& presenceService =
186462e5926SBob King services.getMockPresenceService();
187462e5926SBob King EXPECT_CALL(presenceService, isPresent).Times(0);
188462e5926SBob King
189462e5926SBob King // Execute PresenceDetection
190462e5926SBob King EXPECT_TRUE(detection->execute(services, *system, *chassis, *device));
191462e5926SBob King }
192462e5926SBob King
193462e5926SBob King // Test where works: Not present: Value is not cached
194462e5926SBob King {
195462e5926SBob King // Clear cached presence value
196462e5926SBob King detection->clearCache();
197462e5926SBob King EXPECT_FALSE(detection->getCachedPresence().has_value());
198462e5926SBob King
199462e5926SBob King // Create MockServices. MockPresenceService::isPresent() should return
200462e5926SBob King // false.
201462e5926SBob King MockServices services{};
202462e5926SBob King MockPresenceService& presenceService =
203462e5926SBob King services.getMockPresenceService();
204462e5926SBob King EXPECT_CALL(presenceService,
205462e5926SBob King isPresent("/xyz/openbmc_project/inventory/system/chassis/"
206462e5926SBob King "motherboard/cpu2"))
207462e5926SBob King .Times(1)
208462e5926SBob King .WillOnce(Return(false));
209462e5926SBob King
210462e5926SBob King // Execute PresenceDetection
211462e5926SBob King EXPECT_FALSE(detection->execute(services, *system, *chassis, *device));
212462e5926SBob King
213462e5926SBob King EXPECT_TRUE(detection->getCachedPresence().has_value());
214462e5926SBob King EXPECT_FALSE(detection->getCachedPresence().value());
215462e5926SBob King }
216462e5926SBob King
217462e5926SBob King // Test where works: Not present: Value is cached
218462e5926SBob King {
219462e5926SBob King EXPECT_TRUE(detection->getCachedPresence().has_value());
220462e5926SBob King
221462e5926SBob King // Create MockServices. MockPresenceService::isPresent() should not be
222462e5926SBob King // called.
223462e5926SBob King MockServices services{};
224462e5926SBob King MockPresenceService& presenceService =
225462e5926SBob King services.getMockPresenceService();
226462e5926SBob King EXPECT_CALL(presenceService, isPresent).Times(0);
227462e5926SBob King
228462e5926SBob King // Execute PresenceDetection
229462e5926SBob King EXPECT_FALSE(detection->execute(services, *system, *chassis, *device));
230462e5926SBob King }
231462e5926SBob King
232462e5926SBob King // Test where fails
233462e5926SBob King {
234462e5926SBob King // Clear cached presence value
235462e5926SBob King detection->clearCache();
236462e5926SBob King EXPECT_FALSE(detection->getCachedPresence().has_value());
237462e5926SBob King
238462e5926SBob King // Create MockServices. MockPresenceService::isPresent() should throw
239462e5926SBob King // an exception.
240462e5926SBob King MockServices services{};
241462e5926SBob King MockPresenceService& presenceService =
242462e5926SBob King services.getMockPresenceService();
243462e5926SBob King EXPECT_CALL(presenceService,
244462e5926SBob King isPresent("/xyz/openbmc_project/inventory/system/chassis/"
245462e5926SBob King "motherboard/cpu2"))
246462e5926SBob King .Times(1)
24781a2f90bSShawn McCarney .WillOnce(Throw(TestSDBusError{"DBusError: Invalid object path."}));
248462e5926SBob King
249462e5926SBob King // Define expected journal messages that should be passed to MockJournal
250462e5926SBob King MockJournal& journal = services.getMockJournal();
251462e5926SBob King std::vector<std::string> exceptionMessages{
252462e5926SBob King "DBusError: Invalid object path.",
253462e5926SBob King "ActionError: compare_presence: { fru: "
254462e5926SBob King "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu2, "
255462e5926SBob King "value: true }"};
256462e5926SBob King EXPECT_CALL(journal, logError(exceptionMessages)).Times(1);
257462e5926SBob King EXPECT_CALL(journal,
258462e5926SBob King logError("Unable to determine presence of vdd_reg"))
259462e5926SBob King .Times(1);
260462e5926SBob King
26181a2f90bSShawn McCarney // Expect logDBusError() to be called
26281a2f90bSShawn McCarney MockErrorLogging& errorLogging = services.getMockErrorLogging();
26381a2f90bSShawn McCarney EXPECT_CALL(errorLogging,
26481a2f90bSShawn McCarney logDBusError(Entry::Level::Warning, Ref(journal)))
26581a2f90bSShawn McCarney .Times(1);
26681a2f90bSShawn McCarney
267462e5926SBob King // Execute PresenceDetection. Should return true when an error occurs.
268462e5926SBob King EXPECT_TRUE(detection->execute(services, *system, *chassis, *device));
269462e5926SBob King
270462e5926SBob King EXPECT_TRUE(detection->getCachedPresence().has_value());
271462e5926SBob King EXPECT_TRUE(detection->getCachedPresence().value());
272462e5926SBob King }
273bfe2c25aSShawn McCarney }
274bfe2c25aSShawn McCarney
TEST(PresenceDetectionTests,GetActions)275bfe2c25aSShawn McCarney TEST(PresenceDetectionTests, GetActions)
276bfe2c25aSShawn McCarney {
277bfe2c25aSShawn McCarney std::vector<std::unique_ptr<Action>> actions{};
278bfe2c25aSShawn McCarney
279bfe2c25aSShawn McCarney MockAction* action1 = new MockAction{};
280462e5926SBob King actions.emplace_back(std::unique_ptr<MockAction>{action1});
281bfe2c25aSShawn McCarney
282bfe2c25aSShawn McCarney MockAction* action2 = new MockAction{};
283462e5926SBob King actions.emplace_back(std::unique_ptr<MockAction>{action2});
284bfe2c25aSShawn McCarney
285462e5926SBob King PresenceDetection detection{std::move(actions)};
286462e5926SBob King EXPECT_EQ(detection.getActions().size(), 2);
287462e5926SBob King EXPECT_EQ(detection.getActions()[0].get(), action1);
288462e5926SBob King EXPECT_EQ(detection.getActions()[1].get(), action2);
289462e5926SBob King }
290462e5926SBob King
TEST(PresenceDetectionTests,GetCachedPresence)291462e5926SBob King TEST(PresenceDetectionTests, GetCachedPresence)
292462e5926SBob King {
293462e5926SBob King // Create MockAction that will return false once
294462e5926SBob King std::unique_ptr<MockAction> action = std::make_unique<MockAction>();
295462e5926SBob King EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(false));
296462e5926SBob King
297462e5926SBob King // Create PresenceDetection
298462e5926SBob King std::vector<std::unique_ptr<Action>> actions{};
299462e5926SBob King actions.emplace_back(std::move(action));
300462e5926SBob King PresenceDetection* detection = new PresenceDetection(std::move(actions));
301462e5926SBob King
302462e5926SBob King // Create parent System, Chassis, and Device objects
303462e5926SBob King auto [system, chassis, device] =
304462e5926SBob King createParentObjects(std::unique_ptr<PresenceDetection>{detection});
305462e5926SBob King
306462e5926SBob King // Verify that initially no presence value is cached
307462e5926SBob King EXPECT_FALSE(detection->getCachedPresence().has_value());
308462e5926SBob King
309462e5926SBob King // Call execute() which should obtain and cache presence value
310462e5926SBob King MockServices services{};
311462e5926SBob King EXPECT_FALSE(detection->execute(services, *system, *chassis, *device));
312462e5926SBob King
313462e5926SBob King // Verify false presence value was cached
314462e5926SBob King EXPECT_TRUE(detection->getCachedPresence().has_value());
315462e5926SBob King EXPECT_FALSE(detection->getCachedPresence().value());
316462e5926SBob King
317462e5926SBob King // Clear cached presence value
318462e5926SBob King detection->clearCache();
319462e5926SBob King
320462e5926SBob King // Verify that no presence value is cached
321462e5926SBob King EXPECT_FALSE(detection->getCachedPresence().has_value());
322bfe2c25aSShawn McCarney }
323