blob: e89af2c3e03ba51959d039ad73e6f1039d734694 [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 McCarneybfe2c252020-03-10 14:05:19 -050030
Shawn McCarney81a2f902021-03-23 21:41:34 -050031#include <sdbusplus/exception.hpp>
32
Shawn McCarneybfe2c252020-03-10 14:05:19 -050033#include <memory>
Bob King462e5922020-11-19 17:48:30 +080034#include <stdexcept>
35#include <string>
36#include <tuple>
Shawn McCarneybfe2c252020-03-10 14:05:19 -050037#include <utility>
38#include <vector>
39
Bob King462e5922020-11-19 17:48:30 +080040#include <gmock/gmock.h>
Shawn McCarneybfe2c252020-03-10 14:05:19 -050041#include <gtest/gtest.h>
42
43using namespace phosphor::power::regulators;
44
Shawn McCarney81a2f902021-03-23 21:41:34 -050045using ::testing::Ref;
Bob King462e5922020-11-19 17:48:30 +080046using ::testing::Return;
47using ::testing::Throw;
48
49/**
Shawn McCarney81a2f902021-03-23 21:41:34 -050050 * Concrete subclass of sdbusplus::exception_t abstract base class.
51 */
52class TestSDBusError : public sdbusplus::exception_t
53{
54 public:
55 TestSDBusError(const std::string& error) : error{error}
56 {
57 }
58
59 const char* what() const noexcept override
60 {
61 return error.c_str();
62 }
63
64 const char* name() const noexcept override
65 {
66 return "";
67 }
68
69 const char* description() const noexcept override
70 {
71 return "";
72 }
73
74 private:
75 const std::string error{};
76};
77
78/**
Bob King462e5922020-11-19 17:48:30 +080079 * Creates the parent objects that normally contain a PresenceDetection object.
80 *
81 * A PresenceDetection object is normally contained within a hierarchy of
82 * System, Chassis, and Device objects. These objects are required in order to
83 * call the execute() method.
84 *
85 * Creates the System, Chassis, and Device objects. The PresenceDetection
86 * object is moved into the Device object.
87 *
88 * @param detection PresenceDetection object to move into object hierarchy
89 * @return Pointers to the System, Chassis, and Device objects. The Chassis and
90 * Device objects are contained within the System object and will be
91 * automatically destructed.
92 */
93std::tuple<std::unique_ptr<System>, Chassis*, Device*>
94 createParentObjects(std::unique_ptr<PresenceDetection> detection)
95{
96 // Create mock I2CInterface
97 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
98 std::make_unique<i2c::MockedI2CInterface>();
99
100 // Create Device that contains PresenceDetection
101 std::unique_ptr<Device> device = std::make_unique<Device>(
102 "vdd_reg", true,
103 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2",
104 std::move(i2cInterface), std::move(detection));
105 Device* devicePtr = device.get();
106
107 // Create Chassis that contains Device
108 std::vector<std::unique_ptr<Device>> devices{};
109 devices.emplace_back(std::move(device));
110 std::unique_ptr<Chassis> chassis =
111 std::make_unique<Chassis>(1, std::move(devices));
112 Chassis* chassisPtr = chassis.get();
113
114 // Create System that contains Chassis
115 std::vector<std::unique_ptr<Rule>> rules{};
116 std::vector<std::unique_ptr<Chassis>> chassisVec{};
117 chassisVec.emplace_back(std::move(chassis));
118 std::unique_ptr<System> system =
119 std::make_unique<System>(std::move(rules), std::move(chassisVec));
120
121 return std::make_tuple(std::move(system), chassisPtr, devicePtr);
122}
123
Shawn McCarneybfe2c252020-03-10 14:05:19 -0500124TEST(PresenceDetectionTests, Constructor)
125{
126 std::vector<std::unique_ptr<Action>> actions{};
Bob King462e5922020-11-19 17:48:30 +0800127 actions.emplace_back(std::make_unique<MockAction>());
Shawn McCarneybfe2c252020-03-10 14:05:19 -0500128
Bob King462e5922020-11-19 17:48:30 +0800129 PresenceDetection detection{std::move(actions)};
130 EXPECT_EQ(detection.getActions().size(), 1);
131 EXPECT_FALSE(detection.getCachedPresence().has_value());
132}
133
134TEST(PresenceDetectionTests, ClearCache)
135{
136 // Create MockAction that will return true once
137 std::unique_ptr<MockAction> action = std::make_unique<MockAction>();
138 EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true));
139
140 // Create PresenceDetection
141 std::vector<std::unique_ptr<Action>> actions{};
142 actions.emplace_back(std::move(action));
143 PresenceDetection* detection = new PresenceDetection(std::move(actions));
144
145 // Create parent System, Chassis, and Device objects
146 auto [system, chassis, device] =
147 createParentObjects(std::unique_ptr<PresenceDetection>{detection});
148
149 // Verify that initially no presence value is cached
150 EXPECT_FALSE(detection->getCachedPresence().has_value());
151
152 // Call execute() which should obtain and cache presence value
153 MockServices services{};
154 EXPECT_TRUE(detection->execute(services, *system, *chassis, *device));
155
156 // Verify true presence value was cached
157 EXPECT_TRUE(detection->getCachedPresence().has_value());
158 EXPECT_TRUE(detection->getCachedPresence().value());
159
160 // Clear cached presence value
161 detection->clearCache();
162
163 // Verify that no presence value is cached
164 EXPECT_FALSE(detection->getCachedPresence().has_value());
Shawn McCarneybfe2c252020-03-10 14:05:19 -0500165}
166
167TEST(PresenceDetectionTests, Execute)
168{
Bob King462e5922020-11-19 17:48:30 +0800169 // Create ComparePresenceAction
170 std::unique_ptr<ComparePresenceAction> action =
171 std::make_unique<ComparePresenceAction>(
172 "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu2",
173 true);
174
175 // Create PresenceDetection
176 std::vector<std::unique_ptr<Action>> actions{};
177 actions.emplace_back(std::move(action));
178 PresenceDetection* detection = new PresenceDetection(std::move(actions));
179
180 // Create parent System, Chassis, and Device objects
181 auto [system, chassis, device] =
182 createParentObjects(std::unique_ptr<PresenceDetection>{detection});
183
184 // Test where works: Present: Value is not cached
185 {
186 EXPECT_FALSE(detection->getCachedPresence().has_value());
187
188 // Create MockServices. MockPresenceService::isPresent() should return
189 // true.
190 MockServices services{};
191 MockPresenceService& presenceService =
192 services.getMockPresenceService();
193 EXPECT_CALL(presenceService,
194 isPresent("/xyz/openbmc_project/inventory/system/chassis/"
195 "motherboard/cpu2"))
196 .Times(1)
197 .WillOnce(Return(true));
198
199 // Execute PresenceDetection
200 EXPECT_TRUE(detection->execute(services, *system, *chassis, *device));
201
202 EXPECT_TRUE(detection->getCachedPresence().has_value());
203 EXPECT_TRUE(detection->getCachedPresence().value());
204 }
205
206 // Test where works: Present: Value is cached
207 {
208 EXPECT_TRUE(detection->getCachedPresence().has_value());
209
210 // Create MockServices. MockPresenceService::isPresent() should not be
211 // called.
212 MockServices services{};
213 MockPresenceService& presenceService =
214 services.getMockPresenceService();
215 EXPECT_CALL(presenceService, isPresent).Times(0);
216
217 // Execute PresenceDetection
218 EXPECT_TRUE(detection->execute(services, *system, *chassis, *device));
219 }
220
221 // Test where works: Not present: Value is not cached
222 {
223 // Clear cached presence value
224 detection->clearCache();
225 EXPECT_FALSE(detection->getCachedPresence().has_value());
226
227 // Create MockServices. MockPresenceService::isPresent() should return
228 // false.
229 MockServices services{};
230 MockPresenceService& presenceService =
231 services.getMockPresenceService();
232 EXPECT_CALL(presenceService,
233 isPresent("/xyz/openbmc_project/inventory/system/chassis/"
234 "motherboard/cpu2"))
235 .Times(1)
236 .WillOnce(Return(false));
237
238 // Execute PresenceDetection
239 EXPECT_FALSE(detection->execute(services, *system, *chassis, *device));
240
241 EXPECT_TRUE(detection->getCachedPresence().has_value());
242 EXPECT_FALSE(detection->getCachedPresence().value());
243 }
244
245 // Test where works: Not present: Value is cached
246 {
247 EXPECT_TRUE(detection->getCachedPresence().has_value());
248
249 // Create MockServices. MockPresenceService::isPresent() should not be
250 // called.
251 MockServices services{};
252 MockPresenceService& presenceService =
253 services.getMockPresenceService();
254 EXPECT_CALL(presenceService, isPresent).Times(0);
255
256 // Execute PresenceDetection
257 EXPECT_FALSE(detection->execute(services, *system, *chassis, *device));
258 }
259
260 // Test where fails
261 {
262 // Clear cached presence value
263 detection->clearCache();
264 EXPECT_FALSE(detection->getCachedPresence().has_value());
265
266 // Create MockServices. MockPresenceService::isPresent() should throw
267 // an exception.
268 MockServices services{};
269 MockPresenceService& presenceService =
270 services.getMockPresenceService();
271 EXPECT_CALL(presenceService,
272 isPresent("/xyz/openbmc_project/inventory/system/chassis/"
273 "motherboard/cpu2"))
274 .Times(1)
Shawn McCarney81a2f902021-03-23 21:41:34 -0500275 .WillOnce(Throw(TestSDBusError{"DBusError: Invalid object path."}));
Bob King462e5922020-11-19 17:48:30 +0800276
277 // Define expected journal messages that should be passed to MockJournal
278 MockJournal& journal = services.getMockJournal();
279 std::vector<std::string> exceptionMessages{
280 "DBusError: Invalid object path.",
281 "ActionError: compare_presence: { fru: "
282 "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu2, "
283 "value: true }"};
284 EXPECT_CALL(journal, logError(exceptionMessages)).Times(1);
285 EXPECT_CALL(journal,
286 logError("Unable to determine presence of vdd_reg"))
287 .Times(1);
288
Shawn McCarney81a2f902021-03-23 21:41:34 -0500289 // Expect logDBusError() to be called
290 MockErrorLogging& errorLogging = services.getMockErrorLogging();
291 EXPECT_CALL(errorLogging,
292 logDBusError(Entry::Level::Warning, Ref(journal)))
293 .Times(1);
294
Bob King462e5922020-11-19 17:48:30 +0800295 // Execute PresenceDetection. Should return true when an error occurs.
296 EXPECT_TRUE(detection->execute(services, *system, *chassis, *device));
297
298 EXPECT_TRUE(detection->getCachedPresence().has_value());
299 EXPECT_TRUE(detection->getCachedPresence().value());
300 }
Shawn McCarneybfe2c252020-03-10 14:05:19 -0500301}
302
303TEST(PresenceDetectionTests, GetActions)
304{
305 std::vector<std::unique_ptr<Action>> actions{};
306
307 MockAction* action1 = new MockAction{};
Bob King462e5922020-11-19 17:48:30 +0800308 actions.emplace_back(std::unique_ptr<MockAction>{action1});
Shawn McCarneybfe2c252020-03-10 14:05:19 -0500309
310 MockAction* action2 = new MockAction{};
Bob King462e5922020-11-19 17:48:30 +0800311 actions.emplace_back(std::unique_ptr<MockAction>{action2});
Shawn McCarneybfe2c252020-03-10 14:05:19 -0500312
Bob King462e5922020-11-19 17:48:30 +0800313 PresenceDetection detection{std::move(actions)};
314 EXPECT_EQ(detection.getActions().size(), 2);
315 EXPECT_EQ(detection.getActions()[0].get(), action1);
316 EXPECT_EQ(detection.getActions()[1].get(), action2);
317}
318
319TEST(PresenceDetectionTests, GetCachedPresence)
320{
321 // Create MockAction that will return false once
322 std::unique_ptr<MockAction> action = std::make_unique<MockAction>();
323 EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(false));
324
325 // Create PresenceDetection
326 std::vector<std::unique_ptr<Action>> actions{};
327 actions.emplace_back(std::move(action));
328 PresenceDetection* detection = new PresenceDetection(std::move(actions));
329
330 // Create parent System, Chassis, and Device objects
331 auto [system, chassis, device] =
332 createParentObjects(std::unique_ptr<PresenceDetection>{detection});
333
334 // Verify that initially no presence value is cached
335 EXPECT_FALSE(detection->getCachedPresence().has_value());
336
337 // Call execute() which should obtain and cache presence value
338 MockServices services{};
339 EXPECT_FALSE(detection->execute(services, *system, *chassis, *device));
340
341 // Verify false presence value was cached
342 EXPECT_TRUE(detection->getCachedPresence().has_value());
343 EXPECT_FALSE(detection->getCachedPresence().value());
344
345 // Clear cached presence value
346 detection->clearCache();
347
348 // Verify that no presence value is cached
349 EXPECT_FALSE(detection->getCachedPresence().has_value());
Shawn McCarneybfe2c252020-03-10 14:05:19 -0500350}