blob: 0c386fbaf0ab966d1b3c50e33f983ecf6a1d36b3 [file] [log] [blame]
Shawn McCarneya2461b32019-10-24 18:53:01 -05001/**
2 * Copyright © 2019 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 */
Shawn McCarney0b1a0e72020-03-11 18:01:44 -050016#include "action.hpp"
Shawn McCarneyeb7bec42020-04-14 09:38:15 -050017#include "chassis.hpp"
Shawn McCarney0b1a0e72020-03-11 18:01:44 -050018#include "configuration.hpp"
Shawn McCarneya2461b32019-10-24 18:53:01 -050019#include "device.hpp"
Shawn McCarneyafb7fc32019-12-11 19:42:03 -060020#include "i2c_interface.hpp"
Shawn McCarneydb0b8332020-04-06 14:13:04 -050021#include "id_map.hpp"
Shawn McCarney0b1a0e72020-03-11 18:01:44 -050022#include "mock_action.hpp"
Shawn McCarney81a2f902021-03-23 21:41:34 -050023#include "mock_error_logging.hpp"
Shawn McCarneyeb7bec42020-04-14 09:38:15 -050024#include "mock_journal.hpp"
Bob King23243f82020-07-29 10:38:57 +080025#include "mock_services.hpp"
Shawn McCarneyb4d18a42020-06-02 10:27:05 -050026#include "mocked_i2c_interface.hpp"
Bob King8e1cd0b2020-07-08 13:30:27 +080027#include "pmbus_read_sensor_action.hpp"
Shawn McCarney0b1a0e72020-03-11 18:01:44 -050028#include "presence_detection.hpp"
29#include "rail.hpp"
Shawn McCarneyeb7bec42020-04-14 09:38:15 -050030#include "rule.hpp"
Shawn McCarney2f9e14f2021-04-29 02:45:18 -050031#include "sensors.hpp"
Shawn McCarneyeb7bec42020-04-14 09:38:15 -050032#include "system.hpp"
Shawn McCarney8a3afd72020-03-12 14:28:44 -050033#include "test_utils.hpp"
Shawn McCarneyafb7fc32019-12-11 19:42:03 -060034
35#include <memory>
Shawn McCarney0b1a0e72020-03-11 18:01:44 -050036#include <optional>
Shawn McCarney525e20c2020-04-14 11:05:39 -050037#include <string>
Shawn McCarneyafb7fc32019-12-11 19:42:03 -060038#include <utility>
Shawn McCarney0b1a0e72020-03-11 18:01:44 -050039#include <vector>
Shawn McCarneya2461b32019-10-24 18:53:01 -050040
Shawn McCarneyeb7bec42020-04-14 09:38:15 -050041#include <gmock/gmock.h>
Shawn McCarneya2461b32019-10-24 18:53:01 -050042#include <gtest/gtest.h>
43
44using namespace phosphor::power::regulators;
Shawn McCarney8a3afd72020-03-12 14:28:44 -050045using namespace phosphor::power::regulators::test_utils;
Shawn McCarneyafb7fc32019-12-11 19:42:03 -060046
Bob King8e1cd0b2020-07-08 13:30:27 +080047using ::testing::A;
Shawn McCarney81a2f902021-03-23 21:41:34 -050048using ::testing::Ref;
Shawn McCarneyeb7bec42020-04-14 09:38:15 -050049using ::testing::Return;
Shawn McCarneyb4d18a42020-06-02 10:27:05 -050050using ::testing::Throw;
Bob King8e1cd0b2020-07-08 13:30:27 +080051using ::testing::TypedEq;
Shawn McCarneyeb7bec42020-04-14 09:38:15 -050052
Shawn McCarneycb3f6a62021-04-30 10:54:30 -050053static const std::string chassisInvPath{
54 "/xyz/openbmc_project/inventory/system/chassis"};
55
Shawn McCarneya2461b32019-10-24 18:53:01 -050056TEST(DeviceTests, Constructor)
57{
Shawn McCarney0b1a0e72020-03-11 18:01:44 -050058 // Test where only required parameters are specified
59 {
60 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
61 i2c::I2CInterface* i2cInterfacePtr = i2cInterface.get();
Bob Kinga76898f2020-10-13 15:08:33 +080062 Device device{
63 "vdd_reg", true,
64 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2",
65 std::move(i2cInterface)};
Shawn McCarney0b1a0e72020-03-11 18:01:44 -050066 EXPECT_EQ(device.getID(), "vdd_reg");
67 EXPECT_EQ(device.isRegulator(), true);
Bob Kinga76898f2020-10-13 15:08:33 +080068 EXPECT_EQ(
69 device.getFRU(),
70 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2");
Shawn McCarney0b1a0e72020-03-11 18:01:44 -050071 EXPECT_EQ(&(device.getI2CInterface()), i2cInterfacePtr);
72 EXPECT_EQ(device.getPresenceDetection(), nullptr);
73 EXPECT_EQ(device.getConfiguration(), nullptr);
74 EXPECT_EQ(device.getRails().size(), 0);
75 }
76
77 // Test where all parameters are specified
78 {
79 // Create I2CInterface
80 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
81 i2c::I2CInterface* i2cInterfacePtr = i2cInterface.get();
82
83 // Create PresenceDetection
84 std::vector<std::unique_ptr<Action>> actions{};
85 actions.push_back(std::make_unique<MockAction>());
86 std::unique_ptr<PresenceDetection> presenceDetection =
87 std::make_unique<PresenceDetection>(std::move(actions));
88
89 // Create Configuration
90 std::optional<double> volts{};
91 actions.clear();
92 actions.push_back(std::make_unique<MockAction>());
93 actions.push_back(std::make_unique<MockAction>());
94 std::unique_ptr<Configuration> configuration =
95 std::make_unique<Configuration>(volts, std::move(actions));
96
97 // Create vector of Rail objects
98 std::vector<std::unique_ptr<Rail>> rails{};
99 rails.push_back(std::make_unique<Rail>("vdd0"));
100 rails.push_back(std::make_unique<Rail>("vdd1"));
101
102 // Create Device
Bob Kinga76898f2020-10-13 15:08:33 +0800103 Device device{
104 "vdd_reg",
105 false,
106 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
107 std::move(i2cInterface),
108 std::move(presenceDetection),
109 std::move(configuration),
110 std::move(rails)};
Shawn McCarney0b1a0e72020-03-11 18:01:44 -0500111 EXPECT_EQ(device.getID(), "vdd_reg");
112 EXPECT_EQ(device.isRegulator(), false);
Bob Kinga76898f2020-10-13 15:08:33 +0800113 EXPECT_EQ(
114 device.getFRU(),
115 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1");
Shawn McCarney0b1a0e72020-03-11 18:01:44 -0500116 EXPECT_EQ(&(device.getI2CInterface()), i2cInterfacePtr);
117 EXPECT_NE(device.getPresenceDetection(), nullptr);
118 EXPECT_EQ(device.getPresenceDetection()->getActions().size(), 1);
119 EXPECT_NE(device.getConfiguration(), nullptr);
120 EXPECT_EQ(device.getConfiguration()->getVolts().has_value(), false);
121 EXPECT_EQ(device.getConfiguration()->getActions().size(), 2);
122 EXPECT_EQ(device.getRails().size(), 2);
123 }
Shawn McCarneya2461b32019-10-24 18:53:01 -0500124}
125
Shawn McCarneydb0b8332020-04-06 14:13:04 -0500126TEST(DeviceTests, AddToIDMap)
127{
128 std::unique_ptr<PresenceDetection> presenceDetection{};
129 std::unique_ptr<Configuration> configuration{};
130
131 // Create vector of Rail objects
132 std::vector<std::unique_ptr<Rail>> rails{};
133 rails.push_back(std::make_unique<Rail>("vdd0"));
134 rails.push_back(std::make_unique<Rail>("vdd1"));
135
136 // Create Device
Bob Kinga76898f2020-10-13 15:08:33 +0800137 Device device{
138 "vdd_reg",
139 false,
140 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2",
141 std::move(createI2CInterface()),
142 std::move(presenceDetection),
143 std::move(configuration),
144 std::move(rails)};
Shawn McCarneydb0b8332020-04-06 14:13:04 -0500145
146 // Add Device and Rail objects to an IDMap
147 IDMap idMap{};
148 device.addToIDMap(idMap);
149
150 // Verify Device is in the IDMap
151 EXPECT_NO_THROW(idMap.getDevice("vdd_reg"));
152 EXPECT_THROW(idMap.getDevice("vio_reg"), std::invalid_argument);
153
154 // Verify all Rails are in the IDMap
155 EXPECT_NO_THROW(idMap.getRail("vdd0"));
156 EXPECT_NO_THROW(idMap.getRail("vdd1"));
157 EXPECT_THROW(idMap.getRail("vdd2"), std::invalid_argument);
158}
159
Shawn McCarney9bd94d32021-01-25 19:40:42 -0600160TEST(DeviceTests, ClearCache)
161{
162 // Test where Device does not contain a PresenceDetection object
163 try
164 {
165 Device device{
166 "vdd_reg", false,
167 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2",
168 std::move(createI2CInterface())};
169 device.clearCache();
170 }
171 catch (...)
172 {
173 ADD_FAILURE() << "Should not have caught exception.";
174 }
175
176 // Test where Device contains a PresenceDetection object
177 {
178 // Create PresenceDetection
179 std::vector<std::unique_ptr<Action>> actions{};
180 std::unique_ptr<PresenceDetection> presenceDetection =
181 std::make_unique<PresenceDetection>(std::move(actions));
182 PresenceDetection* presenceDetectionPtr = presenceDetection.get();
183
184 // Create Device
185 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
186 std::unique_ptr<Device> device = std::make_unique<Device>(
187 "reg1", true,
188 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
189 std::move(i2cInterface), std::move(presenceDetection));
190 Device* devicePtr = device.get();
191
192 // Create Chassis that contains Device
193 std::vector<std::unique_ptr<Device>> devices{};
194 devices.emplace_back(std::move(device));
195 std::unique_ptr<Chassis> chassis =
Shawn McCarneycb3f6a62021-04-30 10:54:30 -0500196 std::make_unique<Chassis>(1, chassisInvPath, std::move(devices));
Shawn McCarney9bd94d32021-01-25 19:40:42 -0600197 Chassis* chassisPtr = chassis.get();
198
199 // Create System that contains Chassis
200 std::vector<std::unique_ptr<Rule>> rules{};
201 std::vector<std::unique_ptr<Chassis>> chassisVec{};
202 chassisVec.emplace_back(std::move(chassis));
203 System system{std::move(rules), std::move(chassisVec)};
204
205 // Cache presence value in PresenceDetection
206 MockServices services{};
207 presenceDetectionPtr->execute(services, system, *chassisPtr,
208 *devicePtr);
209 EXPECT_TRUE(presenceDetectionPtr->getCachedPresence().has_value());
210
211 // Clear cached data in Device
212 devicePtr->clearCache();
213
214 // Verify presence value no longer cached in PresenceDetection
215 EXPECT_FALSE(presenceDetectionPtr->getCachedPresence().has_value());
216 }
217}
218
Shawn McCarneyb4d18a42020-06-02 10:27:05 -0500219TEST(DeviceTests, Close)
220{
221 // Test where works: I2C interface is not open
222 {
223 // Create mock I2CInterface
224 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
225 std::make_unique<i2c::MockedI2CInterface>();
226 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(false));
227 EXPECT_CALL(*i2cInterface, close).Times(0);
228
Bob Kingd692d6d2020-09-14 13:42:57 +0800229 // Create mock services. No logError should occur.
230 MockServices services{};
231 MockJournal& journal = services.getMockJournal();
232 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
233 EXPECT_CALL(journal, logError(A<const std::vector<std::string>&>()))
234 .Times(0);
235
Shawn McCarneyb4d18a42020-06-02 10:27:05 -0500236 // Create Device
Bob Kinga76898f2020-10-13 15:08:33 +0800237 Device device{
238 "vdd_reg", true,
239 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2",
240 std::move(i2cInterface)};
Shawn McCarneyb4d18a42020-06-02 10:27:05 -0500241
242 // Close Device
Bob Kingd692d6d2020-09-14 13:42:57 +0800243 device.close(services);
Shawn McCarneyb4d18a42020-06-02 10:27:05 -0500244 }
245
246 // Test where works: I2C interface is open
247 {
248 // Create mock I2CInterface
249 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
250 std::make_unique<i2c::MockedI2CInterface>();
251 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
252 EXPECT_CALL(*i2cInterface, close).Times(1);
253
Bob Kingd692d6d2020-09-14 13:42:57 +0800254 // Create mock services. No logError should occur.
255 MockServices services{};
256 MockJournal& journal = services.getMockJournal();
257 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
258 EXPECT_CALL(journal, logError(A<const std::vector<std::string>&>()))
259 .Times(0);
260
Shawn McCarneyb4d18a42020-06-02 10:27:05 -0500261 // Create Device
Bob Kinga76898f2020-10-13 15:08:33 +0800262 Device device{
263 "vdd_reg", true,
264 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2",
265 std::move(i2cInterface)};
Shawn McCarneyb4d18a42020-06-02 10:27:05 -0500266
267 // Close Device
Bob Kingd692d6d2020-09-14 13:42:57 +0800268 device.close(services);
Shawn McCarneyb4d18a42020-06-02 10:27:05 -0500269 }
270
271 // Test where fails: closing I2C interface fails
272 {
273 // Create mock I2CInterface
274 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
275 std::make_unique<i2c::MockedI2CInterface>();
276 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
277 EXPECT_CALL(*i2cInterface, close)
278 .Times(1)
279 .WillOnce(Throw(
280 i2c::I2CException{"Failed to close", "/dev/i2c-1", 0x70}));
281
Shawn McCarney81a2f902021-03-23 21:41:34 -0500282 // Create mock services. Expect logError() and logI2CError() to be
283 // called.
Bob Kingd692d6d2020-09-14 13:42:57 +0800284 MockServices services{};
Shawn McCarney81a2f902021-03-23 21:41:34 -0500285 MockErrorLogging& errorLogging = services.getMockErrorLogging();
Bob Kingd692d6d2020-09-14 13:42:57 +0800286 MockJournal& journal = services.getMockJournal();
287 std::vector<std::string> expectedErrMessagesException{
288 "I2CException: Failed to close: bus /dev/i2c-1, addr 0x70"};
289 EXPECT_CALL(journal, logError("Unable to close device vdd_reg"))
290 .Times(1);
291 EXPECT_CALL(journal, logError(expectedErrMessagesException)).Times(1);
Shawn McCarney81a2f902021-03-23 21:41:34 -0500292 EXPECT_CALL(errorLogging,
293 logI2CError(Entry::Level::Notice, Ref(journal),
294 "/dev/i2c-1", 0x70, 0))
295 .Times(1);
Bob Kingd692d6d2020-09-14 13:42:57 +0800296
Shawn McCarneyb4d18a42020-06-02 10:27:05 -0500297 // Create Device
Bob Kinga76898f2020-10-13 15:08:33 +0800298 Device device{
299 "vdd_reg", true,
300 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2",
301 std::move(i2cInterface)};
Shawn McCarneyb4d18a42020-06-02 10:27:05 -0500302
303 // Close Device
Bob Kingd692d6d2020-09-14 13:42:57 +0800304 device.close(services);
Shawn McCarneyb4d18a42020-06-02 10:27:05 -0500305 }
306}
307
Shawn McCarneyeb7bec42020-04-14 09:38:15 -0500308TEST(DeviceTests, Configure)
309{
Shawn McCarney48033bf2021-01-27 17:56:49 -0600310 // Test where device is not present
311 {
312 // Create mock services. No logging should occur.
313 MockServices services{};
314 MockJournal& journal = services.getMockJournal();
315 EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0);
316 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
317
318 // Create PresenceDetection. Indicates device is not present.
319 std::unique_ptr<MockAction> presAction = std::make_unique<MockAction>();
320 EXPECT_CALL(*presAction, execute).Times(1).WillOnce(Return(false));
321 std::vector<std::unique_ptr<Action>> presActions{};
322 presActions.emplace_back(std::move(presAction));
323 std::unique_ptr<PresenceDetection> presenceDetection =
324 std::make_unique<PresenceDetection>(std::move(presActions));
325
326 // Create Configuration. Action inside it should not be executed.
327 std::optional<double> volts{};
328 std::unique_ptr<MockAction> confAction = std::make_unique<MockAction>();
329 EXPECT_CALL(*confAction, execute).Times(0);
330 std::vector<std::unique_ptr<Action>> confActions{};
331 confActions.emplace_back(std::move(confAction));
332 std::unique_ptr<Configuration> configuration =
333 std::make_unique<Configuration>(volts, std::move(confActions));
334
335 // Create Device
336 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
337 std::unique_ptr<Device> device = std::make_unique<Device>(
338 "reg1", true,
339 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
340 std::move(i2cInterface), std::move(presenceDetection),
341 std::move(configuration));
342 Device* devicePtr = device.get();
343
344 // Create Chassis that contains Device
345 std::vector<std::unique_ptr<Device>> devices{};
346 devices.emplace_back(std::move(device));
347 std::unique_ptr<Chassis> chassis =
Shawn McCarneycb3f6a62021-04-30 10:54:30 -0500348 std::make_unique<Chassis>(1, chassisInvPath, std::move(devices));
Shawn McCarney48033bf2021-01-27 17:56:49 -0600349 Chassis* chassisPtr = chassis.get();
350
351 // Create System that contains Chassis
352 std::vector<std::unique_ptr<Rule>> rules{};
353 std::vector<std::unique_ptr<Chassis>> chassisVec{};
354 chassisVec.emplace_back(std::move(chassis));
355 System system{std::move(rules), std::move(chassisVec)};
356
357 // Call configure(). Should do nothing.
358 devicePtr->configure(services, system, *chassisPtr);
359 }
360
Shawn McCarneyeb7bec42020-04-14 09:38:15 -0500361 // Test where Configuration and Rails were not specified in constructor
362 {
Bob King5cfe5102020-07-30 16:26:18 +0800363 // Create mock services. No logging should occur.
Bob King23243f82020-07-29 10:38:57 +0800364 MockServices services{};
Bob King5cfe5102020-07-30 16:26:18 +0800365 MockJournal& journal = services.getMockJournal();
366 EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0);
367 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
Bob King23243f82020-07-29 10:38:57 +0800368
Shawn McCarneyeb7bec42020-04-14 09:38:15 -0500369 // Create Device
370 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
371 std::unique_ptr<Device> device = std::make_unique<Device>(
Bob Kinga76898f2020-10-13 15:08:33 +0800372 "reg1", true,
373 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
Shawn McCarneyeb7bec42020-04-14 09:38:15 -0500374 std::move(i2cInterface));
375 Device* devicePtr = device.get();
376
377 // Create Chassis that contains Device
378 std::vector<std::unique_ptr<Device>> devices{};
379 devices.emplace_back(std::move(device));
380 std::unique_ptr<Chassis> chassis =
Shawn McCarneycb3f6a62021-04-30 10:54:30 -0500381 std::make_unique<Chassis>(1, chassisInvPath, std::move(devices));
Shawn McCarneyeb7bec42020-04-14 09:38:15 -0500382 Chassis* chassisPtr = chassis.get();
383
384 // Create System that contains Chassis
385 std::vector<std::unique_ptr<Rule>> rules{};
386 std::vector<std::unique_ptr<Chassis>> chassisVec{};
387 chassisVec.emplace_back(std::move(chassis));
388 System system{std::move(rules), std::move(chassisVec)};
389
Bob King5cfe5102020-07-30 16:26:18 +0800390 // Call configure().
Bob King23243f82020-07-29 10:38:57 +0800391 devicePtr->configure(services, system, *chassisPtr);
Shawn McCarneyeb7bec42020-04-14 09:38:15 -0500392 }
393
394 // Test where Configuration and Rails were specified in constructor
395 {
396 std::vector<std::unique_ptr<Rail>> rails{};
397
Bob King5cfe5102020-07-30 16:26:18 +0800398 // Create mock services. Expect logDebug() to be called.
399 // For the Device and both Rails, should execute the Configuration
400 // and log a debug message.
401 MockServices services{};
402 MockJournal& journal = services.getMockJournal();
403 EXPECT_CALL(journal, logDebug("Configuring reg1")).Times(1);
404 EXPECT_CALL(journal, logDebug("Configuring vdd0: volts=1.300000"))
405 .Times(1);
406 EXPECT_CALL(journal, logDebug("Configuring vio0: volts=3.200000"))
407 .Times(1);
408 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
409
Shawn McCarneyeb7bec42020-04-14 09:38:15 -0500410 // Create Rail vdd0
411 {
412 // Create Configuration for Rail
413 std::optional<double> volts{1.3};
414 std::unique_ptr<MockAction> action = std::make_unique<MockAction>();
415 EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true));
416 std::vector<std::unique_ptr<Action>> actions{};
417 actions.emplace_back(std::move(action));
418 std::unique_ptr<Configuration> configuration =
419 std::make_unique<Configuration>(volts, std::move(actions));
420
421 // Create Rail
422 std::unique_ptr<Rail> rail =
423 std::make_unique<Rail>("vdd0", std::move(configuration));
424 rails.emplace_back(std::move(rail));
425 }
426
427 // Create Rail vio0
428 {
429 // Create Configuration for Rail
430 std::optional<double> volts{3.2};
431 std::unique_ptr<MockAction> action = std::make_unique<MockAction>();
432 EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true));
433 std::vector<std::unique_ptr<Action>> actions{};
434 actions.emplace_back(std::move(action));
435 std::unique_ptr<Configuration> configuration =
436 std::make_unique<Configuration>(volts, std::move(actions));
437
438 // Create Rail
439 std::unique_ptr<Rail> rail =
440 std::make_unique<Rail>("vio0", std::move(configuration));
441 rails.emplace_back(std::move(rail));
442 }
443
444 // Create Configuration for Device
445 std::optional<double> volts{};
446 std::unique_ptr<MockAction> action = std::make_unique<MockAction>();
447 EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true));
448 std::vector<std::unique_ptr<Action>> actions{};
449 actions.emplace_back(std::move(action));
450 std::unique_ptr<Configuration> configuration =
451 std::make_unique<Configuration>(volts, std::move(actions));
452
453 // Create Device
454 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
455 std::unique_ptr<PresenceDetection> presenceDetection{};
456 std::unique_ptr<Device> device = std::make_unique<Device>(
Bob Kinga76898f2020-10-13 15:08:33 +0800457 "reg1", true,
458 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
Shawn McCarneyeb7bec42020-04-14 09:38:15 -0500459 std::move(i2cInterface), std::move(presenceDetection),
460 std::move(configuration), std::move(rails));
461 Device* devicePtr = device.get();
462
463 // Create Chassis that contains Device
464 std::vector<std::unique_ptr<Device>> devices{};
465 devices.emplace_back(std::move(device));
466 std::unique_ptr<Chassis> chassis =
Shawn McCarneycb3f6a62021-04-30 10:54:30 -0500467 std::make_unique<Chassis>(1, chassisInvPath, std::move(devices));
Shawn McCarneyeb7bec42020-04-14 09:38:15 -0500468 Chassis* chassisPtr = chassis.get();
469
470 // Create System that contains Chassis
471 std::vector<std::unique_ptr<Rule>> rules{};
472 std::vector<std::unique_ptr<Chassis>> chassisVec{};
473 chassisVec.emplace_back(std::move(chassis));
474 System system{std::move(rules), std::move(chassisVec)};
475
Bob King5cfe5102020-07-30 16:26:18 +0800476 // Call configure().
Bob King23243f82020-07-29 10:38:57 +0800477 devicePtr->configure(services, system, *chassisPtr);
Shawn McCarneyeb7bec42020-04-14 09:38:15 -0500478 }
479}
480
Shawn McCarney0b1a0e72020-03-11 18:01:44 -0500481TEST(DeviceTests, GetConfiguration)
Shawn McCarneya2461b32019-10-24 18:53:01 -0500482{
Shawn McCarney0b1a0e72020-03-11 18:01:44 -0500483 // Test where Configuration was not specified in constructor
484 {
Bob Kinga76898f2020-10-13 15:08:33 +0800485 Device device{
486 "vdd_reg", true,
487 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2",
488 std::move(createI2CInterface())};
Shawn McCarney0b1a0e72020-03-11 18:01:44 -0500489 EXPECT_EQ(device.getConfiguration(), nullptr);
490 }
Shawn McCarneyafb7fc32019-12-11 19:42:03 -0600491
Shawn McCarney0b1a0e72020-03-11 18:01:44 -0500492 // Test where Configuration was specified in constructor
493 {
494 std::unique_ptr<PresenceDetection> presenceDetection{};
495
496 // Create Configuration
497 std::optional<double> volts{3.2};
498 std::vector<std::unique_ptr<Action>> actions{};
499 actions.push_back(std::make_unique<MockAction>());
500 actions.push_back(std::make_unique<MockAction>());
501 std::unique_ptr<Configuration> configuration =
502 std::make_unique<Configuration>(volts, std::move(actions));
503
504 // Create Device
Bob Kinga76898f2020-10-13 15:08:33 +0800505 Device device{
506 "vdd_reg",
507 true,
508 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2",
509 std::move(createI2CInterface()),
510 std::move(presenceDetection),
511 std::move(configuration)};
Shawn McCarney0b1a0e72020-03-11 18:01:44 -0500512 EXPECT_NE(device.getConfiguration(), nullptr);
513 EXPECT_EQ(device.getConfiguration()->getVolts().has_value(), true);
514 EXPECT_EQ(device.getConfiguration()->getVolts().value(), 3.2);
515 EXPECT_EQ(device.getConfiguration()->getActions().size(), 2);
516 }
Shawn McCarneyafb7fc32019-12-11 19:42:03 -0600517}
518
519TEST(DeviceTests, GetFRU)
520{
Bob Kinga76898f2020-10-13 15:08:33 +0800521 Device device{
522 "vdd_reg", true,
523 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2",
524 std::move(createI2CInterface())};
525 EXPECT_EQ(device.getFRU(),
526 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2");
Shawn McCarneyafb7fc32019-12-11 19:42:03 -0600527}
528
529TEST(DeviceTests, GetI2CInterface)
530{
531 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
532 i2c::I2CInterface* i2cInterfacePtr = i2cInterface.get();
Bob Kinga76898f2020-10-13 15:08:33 +0800533 Device device{
534 "vdd_reg", true,
535 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2",
536 std::move(i2cInterface)};
Shawn McCarneyafb7fc32019-12-11 19:42:03 -0600537 EXPECT_EQ(&(device.getI2CInterface()), i2cInterfacePtr);
Shawn McCarneya2461b32019-10-24 18:53:01 -0500538}
Shawn McCarney0b1a0e72020-03-11 18:01:44 -0500539
540TEST(DeviceTests, GetID)
541{
Bob Kinga76898f2020-10-13 15:08:33 +0800542 Device device{
543 "vdd_reg", false,
544 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2",
545 std::move(createI2CInterface())};
Shawn McCarney0b1a0e72020-03-11 18:01:44 -0500546 EXPECT_EQ(device.getID(), "vdd_reg");
547}
548
549TEST(DeviceTests, GetPresenceDetection)
550{
551 // Test where PresenceDetection was not specified in constructor
552 {
Bob Kinga76898f2020-10-13 15:08:33 +0800553 Device device{
554 "vdd_reg", true,
555 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2",
556 std::move(createI2CInterface())};
Shawn McCarney0b1a0e72020-03-11 18:01:44 -0500557 EXPECT_EQ(device.getPresenceDetection(), nullptr);
558 }
559
560 // Test where PresenceDetection was specified in constructor
561 {
562 // Create PresenceDetection
563 std::vector<std::unique_ptr<Action>> actions{};
564 actions.push_back(std::make_unique<MockAction>());
565 std::unique_ptr<PresenceDetection> presenceDetection =
566 std::make_unique<PresenceDetection>(std::move(actions));
567
568 // Create Device
Bob Kinga76898f2020-10-13 15:08:33 +0800569 Device device{
570 "vdd_reg", false,
571 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2",
572 std::move(createI2CInterface()), std::move(presenceDetection)};
Shawn McCarney0b1a0e72020-03-11 18:01:44 -0500573 EXPECT_NE(device.getPresenceDetection(), nullptr);
574 EXPECT_EQ(device.getPresenceDetection()->getActions().size(), 1);
575 }
576}
577
578TEST(DeviceTests, GetRails)
579{
580 // Test where no rails were specified in constructor
581 {
Bob Kinga76898f2020-10-13 15:08:33 +0800582 Device device{
583 "vdd_reg", true,
584 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2",
585 std::move(createI2CInterface())};
Shawn McCarney0b1a0e72020-03-11 18:01:44 -0500586 EXPECT_EQ(device.getRails().size(), 0);
587 }
588
589 // Test where rails were specified in constructor
590 {
591 std::unique_ptr<PresenceDetection> presenceDetection{};
592 std::unique_ptr<Configuration> configuration{};
593
594 // Create vector of Rail objects
595 std::vector<std::unique_ptr<Rail>> rails{};
596 rails.push_back(std::make_unique<Rail>("vdd0"));
597 rails.push_back(std::make_unique<Rail>("vdd1"));
598
599 // Create Device
Bob Kinga76898f2020-10-13 15:08:33 +0800600 Device device{
601 "vdd_reg",
602 false,
603 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2",
604 std::move(createI2CInterface()),
605 std::move(presenceDetection),
606 std::move(configuration),
607 std::move(rails)};
Shawn McCarney0b1a0e72020-03-11 18:01:44 -0500608 EXPECT_EQ(device.getRails().size(), 2);
609 EXPECT_EQ(device.getRails()[0]->getID(), "vdd0");
610 EXPECT_EQ(device.getRails()[1]->getID(), "vdd1");
611 }
612}
613
Shawn McCarney48033bf2021-01-27 17:56:49 -0600614TEST(DeviceTests, IsPresent)
615{
616 // Test where PresenceDetection not specified in constructor
617 {
618 // Create Device
619 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
620 std::unique_ptr<Device> device = std::make_unique<Device>(
621 "reg1", true,
622 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
623 std::move(i2cInterface));
624 Device* devicePtr = device.get();
625
626 // Create Chassis that contains Device
627 std::vector<std::unique_ptr<Device>> devices{};
628 devices.emplace_back(std::move(device));
629 std::unique_ptr<Chassis> chassis =
Shawn McCarneycb3f6a62021-04-30 10:54:30 -0500630 std::make_unique<Chassis>(1, chassisInvPath, std::move(devices));
Shawn McCarney48033bf2021-01-27 17:56:49 -0600631 Chassis* chassisPtr = chassis.get();
632
633 // Create System that contains Chassis
634 std::vector<std::unique_ptr<Rule>> rules{};
635 std::vector<std::unique_ptr<Chassis>> chassisVec{};
636 chassisVec.emplace_back(std::move(chassis));
637 System system{std::move(rules), std::move(chassisVec)};
638
639 // Create MockServices
640 MockServices services{};
641
642 // Since no PresenceDetection defined, isPresent() should return true
643 EXPECT_TRUE(devicePtr->isPresent(services, system, *chassisPtr));
644 }
645
646 // Test where PresenceDetection was specified in constructor: Is present
647 {
648 // Create PresenceDetection. Indicates device is present.
649 std::unique_ptr<MockAction> action = std::make_unique<MockAction>();
650 EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true));
651 std::vector<std::unique_ptr<Action>> actions{};
652 actions.emplace_back(std::move(action));
653 std::unique_ptr<PresenceDetection> presenceDetection =
654 std::make_unique<PresenceDetection>(std::move(actions));
655
656 // Create Device
657 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
658 std::unique_ptr<Device> device = std::make_unique<Device>(
659 "reg1", true,
660 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
661 std::move(i2cInterface), std::move(presenceDetection));
662 Device* devicePtr = device.get();
663
664 // Create Chassis that contains Device
665 std::vector<std::unique_ptr<Device>> devices{};
666 devices.emplace_back(std::move(device));
667 std::unique_ptr<Chassis> chassis =
Shawn McCarneycb3f6a62021-04-30 10:54:30 -0500668 std::make_unique<Chassis>(1, chassisInvPath, std::move(devices));
Shawn McCarney48033bf2021-01-27 17:56:49 -0600669 Chassis* chassisPtr = chassis.get();
670
671 // Create System that contains Chassis
672 std::vector<std::unique_ptr<Rule>> rules{};
673 std::vector<std::unique_ptr<Chassis>> chassisVec{};
674 chassisVec.emplace_back(std::move(chassis));
675 System system{std::move(rules), std::move(chassisVec)};
676
677 // Create MockServices
678 MockServices services{};
679
680 // PresenceDetection::execute() and isPresent() should return true
681 EXPECT_TRUE(devicePtr->isPresent(services, system, *chassisPtr));
682 }
683
684 // Test where PresenceDetection was specified in constructor: Is not present
685 {
686 // Create PresenceDetection. Indicates device is not present.
687 std::unique_ptr<MockAction> action = std::make_unique<MockAction>();
688 EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(false));
689 std::vector<std::unique_ptr<Action>> actions{};
690 actions.emplace_back(std::move(action));
691 std::unique_ptr<PresenceDetection> presenceDetection =
692 std::make_unique<PresenceDetection>(std::move(actions));
693
694 // Create Device
695 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
696 std::unique_ptr<Device> device = std::make_unique<Device>(
697 "reg1", true,
698 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
699 std::move(i2cInterface), std::move(presenceDetection));
700 Device* devicePtr = device.get();
701
702 // Create Chassis that contains Device
703 std::vector<std::unique_ptr<Device>> devices{};
704 devices.emplace_back(std::move(device));
705 std::unique_ptr<Chassis> chassis =
Shawn McCarneycb3f6a62021-04-30 10:54:30 -0500706 std::make_unique<Chassis>(1, chassisInvPath, std::move(devices));
Shawn McCarney48033bf2021-01-27 17:56:49 -0600707 Chassis* chassisPtr = chassis.get();
708
709 // Create System that contains Chassis
710 std::vector<std::unique_ptr<Rule>> rules{};
711 std::vector<std::unique_ptr<Chassis>> chassisVec{};
712 chassisVec.emplace_back(std::move(chassis));
713 System system{std::move(rules), std::move(chassisVec)};
714
715 // Create MockServices
716 MockServices services{};
717
718 // PresenceDetection::execute() and isPresent() should return false
719 EXPECT_FALSE(devicePtr->isPresent(services, system, *chassisPtr));
720 }
721}
722
Shawn McCarney0b1a0e72020-03-11 18:01:44 -0500723TEST(DeviceTests, IsRegulator)
724{
Bob Kinga76898f2020-10-13 15:08:33 +0800725 Device device{
726 "vdd_reg", false,
727 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2",
728 std::move(createI2CInterface())};
Shawn McCarney0b1a0e72020-03-11 18:01:44 -0500729 EXPECT_EQ(device.isRegulator(), false);
730}
Bob King8e1cd0b2020-07-08 13:30:27 +0800731
732TEST(DeviceTests, MonitorSensors)
733{
Shawn McCarney48033bf2021-01-27 17:56:49 -0600734 // Test where device is not present
735 // TODO: Add this test when sensoring monitoring is fully implemented
736
Bob King8e1cd0b2020-07-08 13:30:27 +0800737 // Test where Rails were not specified in constructor
738 {
Bob King8a552922020-08-05 17:02:31 +0800739 // Create mock services. No logging should occur.
740 MockServices services{};
741 MockJournal& journal = services.getMockJournal();
742 EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0);
743 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
744
Bob King8e1cd0b2020-07-08 13:30:27 +0800745 // Create mock I2CInterface. A two-byte read should NOT occur.
746 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
747 std::make_unique<i2c::MockedI2CInterface>();
748 EXPECT_CALL(*i2cInterface, read(A<uint8_t>(), A<uint16_t&>())).Times(0);
749
750 // Create Device
751 std::unique_ptr<Device> device = std::make_unique<Device>(
Bob Kinga76898f2020-10-13 15:08:33 +0800752 "reg1", true,
753 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
Bob King8e1cd0b2020-07-08 13:30:27 +0800754 std::move(i2cInterface));
755 Device* devicePtr = device.get();
756
757 // Create Chassis that contains Device
758 std::vector<std::unique_ptr<Device>> devices{};
759 devices.emplace_back(std::move(device));
760 std::unique_ptr<Chassis> chassis =
Shawn McCarneycb3f6a62021-04-30 10:54:30 -0500761 std::make_unique<Chassis>(1, chassisInvPath, std::move(devices));
Bob King8e1cd0b2020-07-08 13:30:27 +0800762 Chassis* chassisPtr = chassis.get();
763
764 // Create System that contains Chassis
765 std::vector<std::unique_ptr<Rule>> rules{};
766 std::vector<std::unique_ptr<Chassis>> chassisVec{};
767 chassisVec.emplace_back(std::move(chassis));
768 System system{std::move(rules), std::move(chassisVec)};
769
Bob King8a552922020-08-05 17:02:31 +0800770 // Call monitorSensors().
771 devicePtr->monitorSensors(services, system, *chassisPtr);
Bob King8e1cd0b2020-07-08 13:30:27 +0800772 }
773
774 // Test where Rails were specified in constructor
775 {
Bob King8a552922020-08-05 17:02:31 +0800776 // Create mock services. No logging should occur.
777 MockServices services{};
778 MockJournal& journal = services.getMockJournal();
779 EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0);
780 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
781
Bob King8e1cd0b2020-07-08 13:30:27 +0800782 std::vector<std::unique_ptr<Rail>> rails{};
783
784 // Create PMBusReadSensorAction
Shawn McCarney2f9e14f2021-04-29 02:45:18 -0500785 SensorType type{SensorType::iout};
Bob King8e1cd0b2020-07-08 13:30:27 +0800786 uint8_t command = 0x8C;
787 pmbus_utils::SensorDataFormat format{
788 pmbus_utils::SensorDataFormat::linear_11};
789 std::optional<int8_t> exponent{};
790 std::unique_ptr<PMBusReadSensorAction> action =
791 std::make_unique<PMBusReadSensorAction>(type, command, format,
792 exponent);
793
794 // Create mock I2CInterface. A two-byte read should occur.
795 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
796 std::make_unique<i2c::MockedI2CInterface>();
797 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
798 EXPECT_CALL(*i2cInterface, read(TypedEq<uint8_t>(0x8C), A<uint16_t&>()))
799 .Times(1);
800
801 // Create SensorMonitoring
802 std::vector<std::unique_ptr<Action>> actions{};
803 actions.emplace_back(std::move(action));
804 std::unique_ptr<SensorMonitoring> sensorMonitoring =
805 std::make_unique<SensorMonitoring>(std::move(actions));
806
807 // Create Rail
808 std::unique_ptr<Configuration> configuration{};
809 std::unique_ptr<Rail> rail = std::make_unique<Rail>(
810 "vdd0", std::move(configuration), std::move(sensorMonitoring));
811 rails.emplace_back(std::move(rail));
812
813 // Create Device
814 std::unique_ptr<PresenceDetection> presenceDetection{};
815 std::unique_ptr<Configuration> deviceConfiguration{};
816 std::unique_ptr<Device> device = std::make_unique<Device>(
Bob Kinga76898f2020-10-13 15:08:33 +0800817 "reg1", true,
818 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
Bob King8e1cd0b2020-07-08 13:30:27 +0800819 std::move(i2cInterface), std::move(presenceDetection),
820 std::move(deviceConfiguration), std::move(rails));
821 Device* devicePtr = device.get();
822
823 // Create Chassis that contains Device
824 std::vector<std::unique_ptr<Device>> devices{};
825 devices.emplace_back(std::move(device));
826 std::unique_ptr<Chassis> chassis =
Shawn McCarneycb3f6a62021-04-30 10:54:30 -0500827 std::make_unique<Chassis>(1, chassisInvPath, std::move(devices));
Bob King8e1cd0b2020-07-08 13:30:27 +0800828 Chassis* chassisPtr = chassis.get();
829
830 // Create System that contains Chassis
831 std::vector<std::unique_ptr<Rule>> rules{};
832 std::vector<std::unique_ptr<Chassis>> chassisVec{};
833 chassisVec.emplace_back(std::move(chassis));
834 System system{std::move(rules), std::move(chassisVec)};
835
836 // Call monitorSensors().
Bob King8a552922020-08-05 17:02:31 +0800837 devicePtr->monitorSensors(services, system, *chassisPtr);
Bob King8e1cd0b2020-07-08 13:30:27 +0800838 }
839}