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