1 /**
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  */
16 #include "action.hpp"
17 #include "chassis.hpp"
18 #include "configuration.hpp"
19 #include "device.hpp"
20 #include "i2c_interface.hpp"
21 #include "id_map.hpp"
22 #include "mock_action.hpp"
23 #include "mock_journal.hpp"
24 #include "mock_services.hpp"
25 #include "mocked_i2c_interface.hpp"
26 #include "pmbus_read_sensor_action.hpp"
27 #include "presence_detection.hpp"
28 #include "rail.hpp"
29 #include "rule.hpp"
30 #include "system.hpp"
31 #include "test_utils.hpp"
32 
33 #include <memory>
34 #include <optional>
35 #include <string>
36 #include <utility>
37 #include <vector>
38 
39 #include <gmock/gmock.h>
40 #include <gtest/gtest.h>
41 
42 using namespace phosphor::power::regulators;
43 using namespace phosphor::power::regulators::test_utils;
44 
45 using ::testing::A;
46 using ::testing::Return;
47 using ::testing::Throw;
48 using ::testing::TypedEq;
49 
50 TEST(DeviceTests, Constructor)
51 {
52     // Test where only required parameters are specified
53     {
54         std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
55         i2c::I2CInterface* i2cInterfacePtr = i2cInterface.get();
56         Device device{"vdd_reg", true, "/system/chassis/motherboard/reg2",
57                       std::move(i2cInterface)};
58         EXPECT_EQ(device.getID(), "vdd_reg");
59         EXPECT_EQ(device.isRegulator(), true);
60         EXPECT_EQ(device.getFRU(), "/system/chassis/motherboard/reg2");
61         EXPECT_EQ(&(device.getI2CInterface()), i2cInterfacePtr);
62         EXPECT_EQ(device.getPresenceDetection(), nullptr);
63         EXPECT_EQ(device.getConfiguration(), nullptr);
64         EXPECT_EQ(device.getRails().size(), 0);
65     }
66 
67     // Test where all parameters are specified
68     {
69         // Create I2CInterface
70         std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
71         i2c::I2CInterface* i2cInterfacePtr = i2cInterface.get();
72 
73         // Create PresenceDetection
74         std::vector<std::unique_ptr<Action>> actions{};
75         actions.push_back(std::make_unique<MockAction>());
76         std::unique_ptr<PresenceDetection> presenceDetection =
77             std::make_unique<PresenceDetection>(std::move(actions));
78 
79         // Create Configuration
80         std::optional<double> volts{};
81         actions.clear();
82         actions.push_back(std::make_unique<MockAction>());
83         actions.push_back(std::make_unique<MockAction>());
84         std::unique_ptr<Configuration> configuration =
85             std::make_unique<Configuration>(volts, std::move(actions));
86 
87         // Create vector of Rail objects
88         std::vector<std::unique_ptr<Rail>> rails{};
89         rails.push_back(std::make_unique<Rail>("vdd0"));
90         rails.push_back(std::make_unique<Rail>("vdd1"));
91 
92         // Create Device
93         Device device{"vdd_reg",
94                       false,
95                       "/system/chassis/motherboard/reg1",
96                       std::move(i2cInterface),
97                       std::move(presenceDetection),
98                       std::move(configuration),
99                       std::move(rails)};
100         EXPECT_EQ(device.getID(), "vdd_reg");
101         EXPECT_EQ(device.isRegulator(), false);
102         EXPECT_EQ(device.getFRU(), "/system/chassis/motherboard/reg1");
103         EXPECT_EQ(&(device.getI2CInterface()), i2cInterfacePtr);
104         EXPECT_NE(device.getPresenceDetection(), nullptr);
105         EXPECT_EQ(device.getPresenceDetection()->getActions().size(), 1);
106         EXPECT_NE(device.getConfiguration(), nullptr);
107         EXPECT_EQ(device.getConfiguration()->getVolts().has_value(), false);
108         EXPECT_EQ(device.getConfiguration()->getActions().size(), 2);
109         EXPECT_EQ(device.getRails().size(), 2);
110     }
111 }
112 
113 TEST(DeviceTests, AddToIDMap)
114 {
115     std::unique_ptr<PresenceDetection> presenceDetection{};
116     std::unique_ptr<Configuration> configuration{};
117 
118     // Create vector of Rail objects
119     std::vector<std::unique_ptr<Rail>> rails{};
120     rails.push_back(std::make_unique<Rail>("vdd0"));
121     rails.push_back(std::make_unique<Rail>("vdd1"));
122 
123     // Create Device
124     Device device{"vdd_reg",
125                   false,
126                   "/system/chassis/motherboard/reg2",
127                   std::move(createI2CInterface()),
128                   std::move(presenceDetection),
129                   std::move(configuration),
130                   std::move(rails)};
131 
132     // Add Device and Rail objects to an IDMap
133     IDMap idMap{};
134     device.addToIDMap(idMap);
135 
136     // Verify Device is in the IDMap
137     EXPECT_NO_THROW(idMap.getDevice("vdd_reg"));
138     EXPECT_THROW(idMap.getDevice("vio_reg"), std::invalid_argument);
139 
140     // Verify all Rails are in the IDMap
141     EXPECT_NO_THROW(idMap.getRail("vdd0"));
142     EXPECT_NO_THROW(idMap.getRail("vdd1"));
143     EXPECT_THROW(idMap.getRail("vdd2"), std::invalid_argument);
144 }
145 
146 TEST(DeviceTests, Close)
147 {
148     // Test where works: I2C interface is not open
149     {
150         // Create mock I2CInterface
151         std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
152             std::make_unique<i2c::MockedI2CInterface>();
153         EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(false));
154         EXPECT_CALL(*i2cInterface, close).Times(0);
155 
156         // Create mock services.  No logError should occur.
157         MockServices services{};
158         MockJournal& journal = services.getMockJournal();
159         EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
160         EXPECT_CALL(journal, logError(A<const std::vector<std::string>&>()))
161             .Times(0);
162 
163         // Create Device
164         Device device{"vdd_reg", true, "/system/chassis/motherboard/reg2",
165                       std::move(i2cInterface)};
166 
167         // Close Device
168         device.close(services);
169     }
170 
171     // Test where works: I2C interface is open
172     {
173         // Create mock I2CInterface
174         std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
175             std::make_unique<i2c::MockedI2CInterface>();
176         EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
177         EXPECT_CALL(*i2cInterface, close).Times(1);
178 
179         // Create mock services.  No logError should occur.
180         MockServices services{};
181         MockJournal& journal = services.getMockJournal();
182         EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
183         EXPECT_CALL(journal, logError(A<const std::vector<std::string>&>()))
184             .Times(0);
185 
186         // Create Device
187         Device device{"vdd_reg", true, "/system/chassis/motherboard/reg2",
188                       std::move(i2cInterface)};
189 
190         // Close Device
191         device.close(services);
192     }
193 
194     // Test where fails: closing I2C interface fails
195     {
196         // Create mock I2CInterface
197         std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
198             std::make_unique<i2c::MockedI2CInterface>();
199         EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
200         EXPECT_CALL(*i2cInterface, close)
201             .Times(1)
202             .WillOnce(Throw(
203                 i2c::I2CException{"Failed to close", "/dev/i2c-1", 0x70}));
204 
205         // Create mock services.  Expect logError() to be called.
206         MockServices services{};
207         MockJournal& journal = services.getMockJournal();
208         std::vector<std::string> expectedErrMessagesException{
209             "I2CException: Failed to close: bus /dev/i2c-1, addr 0x70"};
210         EXPECT_CALL(journal, logError("Unable to close device vdd_reg"))
211             .Times(1);
212         EXPECT_CALL(journal, logError(expectedErrMessagesException)).Times(1);
213 
214         // Create Device
215         Device device{"vdd_reg", true, "/system/chassis/motherboard/reg2",
216                       std::move(i2cInterface)};
217 
218         // Close Device
219         device.close(services);
220     }
221 }
222 
223 TEST(DeviceTests, Configure)
224 {
225     // Test where Configuration and Rails were not specified in constructor
226     {
227         // Create mock services.  No logging should occur.
228         MockServices services{};
229         MockJournal& journal = services.getMockJournal();
230         EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0);
231         EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
232 
233         // Create Device
234         std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
235         std::unique_ptr<Device> device = std::make_unique<Device>(
236             "reg1", true, "/system/chassis/motherboard/reg1",
237             std::move(i2cInterface));
238         Device* devicePtr = device.get();
239 
240         // Create Chassis that contains Device
241         std::vector<std::unique_ptr<Device>> devices{};
242         devices.emplace_back(std::move(device));
243         std::unique_ptr<Chassis> chassis =
244             std::make_unique<Chassis>(1, std::move(devices));
245         Chassis* chassisPtr = chassis.get();
246 
247         // Create System that contains Chassis
248         std::vector<std::unique_ptr<Rule>> rules{};
249         std::vector<std::unique_ptr<Chassis>> chassisVec{};
250         chassisVec.emplace_back(std::move(chassis));
251         System system{std::move(rules), std::move(chassisVec)};
252 
253         // Call configure().
254         devicePtr->configure(services, system, *chassisPtr);
255     }
256 
257     // Test where Configuration and Rails were specified in constructor
258     {
259         std::vector<std::unique_ptr<Rail>> rails{};
260 
261         // Create mock services.  Expect logDebug() to be called.
262         // For the Device and both Rails, should execute the Configuration
263         // and log a debug message.
264         MockServices services{};
265         MockJournal& journal = services.getMockJournal();
266         EXPECT_CALL(journal, logDebug("Configuring reg1")).Times(1);
267         EXPECT_CALL(journal, logDebug("Configuring vdd0: volts=1.300000"))
268             .Times(1);
269         EXPECT_CALL(journal, logDebug("Configuring vio0: volts=3.200000"))
270             .Times(1);
271         EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
272 
273         // Create Rail vdd0
274         {
275             // Create Configuration for Rail
276             std::optional<double> volts{1.3};
277             std::unique_ptr<MockAction> action = std::make_unique<MockAction>();
278             EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true));
279             std::vector<std::unique_ptr<Action>> actions{};
280             actions.emplace_back(std::move(action));
281             std::unique_ptr<Configuration> configuration =
282                 std::make_unique<Configuration>(volts, std::move(actions));
283 
284             // Create Rail
285             std::unique_ptr<Rail> rail =
286                 std::make_unique<Rail>("vdd0", std::move(configuration));
287             rails.emplace_back(std::move(rail));
288         }
289 
290         // Create Rail vio0
291         {
292             // Create Configuration for Rail
293             std::optional<double> volts{3.2};
294             std::unique_ptr<MockAction> action = std::make_unique<MockAction>();
295             EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true));
296             std::vector<std::unique_ptr<Action>> actions{};
297             actions.emplace_back(std::move(action));
298             std::unique_ptr<Configuration> configuration =
299                 std::make_unique<Configuration>(volts, std::move(actions));
300 
301             // Create Rail
302             std::unique_ptr<Rail> rail =
303                 std::make_unique<Rail>("vio0", std::move(configuration));
304             rails.emplace_back(std::move(rail));
305         }
306 
307         // Create Configuration for Device
308         std::optional<double> volts{};
309         std::unique_ptr<MockAction> action = std::make_unique<MockAction>();
310         EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true));
311         std::vector<std::unique_ptr<Action>> actions{};
312         actions.emplace_back(std::move(action));
313         std::unique_ptr<Configuration> configuration =
314             std::make_unique<Configuration>(volts, std::move(actions));
315 
316         // Create Device
317         std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
318         std::unique_ptr<PresenceDetection> presenceDetection{};
319         std::unique_ptr<Device> device = std::make_unique<Device>(
320             "reg1", true, "/system/chassis/motherboard/reg1",
321             std::move(i2cInterface), std::move(presenceDetection),
322             std::move(configuration), std::move(rails));
323         Device* devicePtr = device.get();
324 
325         // Create Chassis that contains Device
326         std::vector<std::unique_ptr<Device>> devices{};
327         devices.emplace_back(std::move(device));
328         std::unique_ptr<Chassis> chassis =
329             std::make_unique<Chassis>(1, std::move(devices));
330         Chassis* chassisPtr = chassis.get();
331 
332         // Create System that contains Chassis
333         std::vector<std::unique_ptr<Rule>> rules{};
334         std::vector<std::unique_ptr<Chassis>> chassisVec{};
335         chassisVec.emplace_back(std::move(chassis));
336         System system{std::move(rules), std::move(chassisVec)};
337 
338         // Call configure().
339         devicePtr->configure(services, system, *chassisPtr);
340     }
341 }
342 
343 TEST(DeviceTests, GetConfiguration)
344 {
345     // Test where Configuration was not specified in constructor
346     {
347         Device device{"vdd_reg", true, "/system/chassis/motherboard/reg2",
348                       std::move(createI2CInterface())};
349         EXPECT_EQ(device.getConfiguration(), nullptr);
350     }
351 
352     // Test where Configuration was specified in constructor
353     {
354         std::unique_ptr<PresenceDetection> presenceDetection{};
355 
356         // Create Configuration
357         std::optional<double> volts{3.2};
358         std::vector<std::unique_ptr<Action>> actions{};
359         actions.push_back(std::make_unique<MockAction>());
360         actions.push_back(std::make_unique<MockAction>());
361         std::unique_ptr<Configuration> configuration =
362             std::make_unique<Configuration>(volts, std::move(actions));
363 
364         // Create Device
365         Device device{"vdd_reg",
366                       true,
367                       "/system/chassis/motherboard/reg2",
368                       std::move(createI2CInterface()),
369                       std::move(presenceDetection),
370                       std::move(configuration)};
371         EXPECT_NE(device.getConfiguration(), nullptr);
372         EXPECT_EQ(device.getConfiguration()->getVolts().has_value(), true);
373         EXPECT_EQ(device.getConfiguration()->getVolts().value(), 3.2);
374         EXPECT_EQ(device.getConfiguration()->getActions().size(), 2);
375     }
376 }
377 
378 TEST(DeviceTests, GetFRU)
379 {
380     Device device{"vdd_reg", true, "/system/chassis/motherboard/reg2",
381                   std::move(createI2CInterface())};
382     EXPECT_EQ(device.getFRU(), "/system/chassis/motherboard/reg2");
383 }
384 
385 TEST(DeviceTests, GetI2CInterface)
386 {
387     std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
388     i2c::I2CInterface* i2cInterfacePtr = i2cInterface.get();
389     Device device{"vdd_reg", true, "/system/chassis/motherboard/reg2",
390                   std::move(i2cInterface)};
391     EXPECT_EQ(&(device.getI2CInterface()), i2cInterfacePtr);
392 }
393 
394 TEST(DeviceTests, GetID)
395 {
396     Device device{"vdd_reg", false, "/system/chassis/motherboard/reg2",
397                   std::move(createI2CInterface())};
398     EXPECT_EQ(device.getID(), "vdd_reg");
399 }
400 
401 TEST(DeviceTests, GetPresenceDetection)
402 {
403     // Test where PresenceDetection was not specified in constructor
404     {
405         Device device{"vdd_reg", true, "/system/chassis/motherboard/reg2",
406                       std::move(createI2CInterface())};
407         EXPECT_EQ(device.getPresenceDetection(), nullptr);
408     }
409 
410     // Test where PresenceDetection was specified in constructor
411     {
412         // Create PresenceDetection
413         std::vector<std::unique_ptr<Action>> actions{};
414         actions.push_back(std::make_unique<MockAction>());
415         std::unique_ptr<PresenceDetection> presenceDetection =
416             std::make_unique<PresenceDetection>(std::move(actions));
417 
418         // Create Device
419         Device device{"vdd_reg", false, "/system/chassis/motherboard/reg2",
420                       std::move(createI2CInterface()),
421                       std::move(presenceDetection)};
422         EXPECT_NE(device.getPresenceDetection(), nullptr);
423         EXPECT_EQ(device.getPresenceDetection()->getActions().size(), 1);
424     }
425 }
426 
427 TEST(DeviceTests, GetRails)
428 {
429     // Test where no rails were specified in constructor
430     {
431         Device device{"vdd_reg", true, "/system/chassis/motherboard/reg2",
432                       std::move(createI2CInterface())};
433         EXPECT_EQ(device.getRails().size(), 0);
434     }
435 
436     // Test where rails were specified in constructor
437     {
438         std::unique_ptr<PresenceDetection> presenceDetection{};
439         std::unique_ptr<Configuration> configuration{};
440 
441         // Create vector of Rail objects
442         std::vector<std::unique_ptr<Rail>> rails{};
443         rails.push_back(std::make_unique<Rail>("vdd0"));
444         rails.push_back(std::make_unique<Rail>("vdd1"));
445 
446         // Create Device
447         Device device{"vdd_reg",
448                       false,
449                       "/system/chassis/motherboard/reg2",
450                       std::move(createI2CInterface()),
451                       std::move(presenceDetection),
452                       std::move(configuration),
453                       std::move(rails)};
454         EXPECT_EQ(device.getRails().size(), 2);
455         EXPECT_EQ(device.getRails()[0]->getID(), "vdd0");
456         EXPECT_EQ(device.getRails()[1]->getID(), "vdd1");
457     }
458 }
459 
460 TEST(DeviceTests, IsRegulator)
461 {
462     Device device{"vdd_reg", false, "/system/chassis/motherboard/reg2",
463                   std::move(createI2CInterface())};
464     EXPECT_EQ(device.isRegulator(), false);
465 }
466 
467 TEST(DeviceTests, MonitorSensors)
468 {
469     // Test where Rails were not specified in constructor
470     {
471         // Create mock services.  No logging should occur.
472         MockServices services{};
473         MockJournal& journal = services.getMockJournal();
474         EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0);
475         EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
476 
477         // Create mock I2CInterface.  A two-byte read should NOT occur.
478         std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
479             std::make_unique<i2c::MockedI2CInterface>();
480         EXPECT_CALL(*i2cInterface, read(A<uint8_t>(), A<uint16_t&>())).Times(0);
481 
482         // Create Device
483         std::unique_ptr<Device> device = std::make_unique<Device>(
484             "reg1", true, "/system/chassis/motherboard/reg1",
485             std::move(i2cInterface));
486         Device* devicePtr = device.get();
487 
488         // Create Chassis that contains Device
489         std::vector<std::unique_ptr<Device>> devices{};
490         devices.emplace_back(std::move(device));
491         std::unique_ptr<Chassis> chassis =
492             std::make_unique<Chassis>(1, std::move(devices));
493         Chassis* chassisPtr = chassis.get();
494 
495         // Create System that contains Chassis
496         std::vector<std::unique_ptr<Rule>> rules{};
497         std::vector<std::unique_ptr<Chassis>> chassisVec{};
498         chassisVec.emplace_back(std::move(chassis));
499         System system{std::move(rules), std::move(chassisVec)};
500 
501         // Call monitorSensors().
502         devicePtr->monitorSensors(services, system, *chassisPtr);
503     }
504 
505     // Test where Rails were specified in constructor
506     {
507         // Create mock services.  No logging should occur.
508         MockServices services{};
509         MockJournal& journal = services.getMockJournal();
510         EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0);
511         EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
512 
513         std::vector<std::unique_ptr<Rail>> rails{};
514 
515         // Create PMBusReadSensorAction
516         pmbus_utils::SensorValueType type{pmbus_utils::SensorValueType::iout};
517         uint8_t command = 0x8C;
518         pmbus_utils::SensorDataFormat format{
519             pmbus_utils::SensorDataFormat::linear_11};
520         std::optional<int8_t> exponent{};
521         std::unique_ptr<PMBusReadSensorAction> action =
522             std::make_unique<PMBusReadSensorAction>(type, command, format,
523                                                     exponent);
524 
525         // Create mock I2CInterface.  A two-byte read should occur.
526         std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
527             std::make_unique<i2c::MockedI2CInterface>();
528         EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
529         EXPECT_CALL(*i2cInterface, read(TypedEq<uint8_t>(0x8C), A<uint16_t&>()))
530             .Times(1);
531 
532         // Create SensorMonitoring
533         std::vector<std::unique_ptr<Action>> actions{};
534         actions.emplace_back(std::move(action));
535         std::unique_ptr<SensorMonitoring> sensorMonitoring =
536             std::make_unique<SensorMonitoring>(std::move(actions));
537 
538         // Create Rail
539         std::unique_ptr<Configuration> configuration{};
540         std::unique_ptr<Rail> rail = std::make_unique<Rail>(
541             "vdd0", std::move(configuration), std::move(sensorMonitoring));
542         rails.emplace_back(std::move(rail));
543 
544         // Create Device
545         std::unique_ptr<PresenceDetection> presenceDetection{};
546         std::unique_ptr<Configuration> deviceConfiguration{};
547         std::unique_ptr<Device> device = std::make_unique<Device>(
548             "reg1", true, "/system/chassis/motherboard/reg1",
549             std::move(i2cInterface), std::move(presenceDetection),
550             std::move(deviceConfiguration), std::move(rails));
551         Device* devicePtr = device.get();
552 
553         // Create Chassis that contains Device
554         std::vector<std::unique_ptr<Device>> devices{};
555         devices.emplace_back(std::move(device));
556         std::unique_ptr<Chassis> chassis =
557             std::make_unique<Chassis>(1, std::move(devices));
558         Chassis* chassisPtr = chassis.get();
559 
560         // Create System that contains Chassis
561         std::vector<std::unique_ptr<Rule>> rules{};
562         std::vector<std::unique_ptr<Chassis>> chassisVec{};
563         chassisVec.emplace_back(std::move(chassis));
564         System system{std::move(rules), std::move(chassisVec)};
565 
566         // Call monitorSensors().
567         devicePtr->monitorSensors(services, system, *chassisPtr);
568     }
569 }
570