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"
30*8c232456SShawn 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  */
65462e5926SBob King std::tuple<std::unique_ptr<System>, Chassis*, Device*>
createParentObjects(std::unique_ptr<PresenceDetection> detection)66462e5926SBob King     createParentObjects(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