1 /**
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"
17 #include "chassis.hpp"
18 #include "configuration.hpp"
19 #include "device.hpp"
20 #include "i2c_interface.hpp"
21 #include "id_map.hpp"
22 #include "journal.hpp"
23 #include "mock_journal.hpp"
24 #include "mocked_i2c_interface.hpp"
25 #include "presence_detection.hpp"
26 #include "rail.hpp"
27 #include "rule.hpp"
28 #include "system.hpp"
29 #include "test_utils.hpp"
30 
31 #include <memory>
32 #include <stdexcept>
33 #include <string>
34 #include <utility>
35 #include <vector>
36 
37 #include <gtest/gtest.h>
38 
39 using namespace phosphor::power::regulators;
40 using namespace phosphor::power::regulators::test_utils;
41 
42 using ::testing::Return;
43 
44 TEST(ChassisTests, Constructor)
45 {
46     // Test where works: Only required parameters are specified
47     {
48         Chassis chassis{2};
49         EXPECT_EQ(chassis.getNumber(), 2);
50         EXPECT_EQ(chassis.getDevices().size(), 0);
51     }
52 
53     // Test where works: All parameters are specified
54     {
55         // Create vector of Device objects
56         std::vector<std::unique_ptr<Device>> devices{};
57         devices.emplace_back(createDevice("vdd_reg1"));
58         devices.emplace_back(createDevice("vdd_reg2"));
59 
60         // Create Chassis
61         Chassis chassis{1, std::move(devices)};
62         EXPECT_EQ(chassis.getNumber(), 1);
63         EXPECT_EQ(chassis.getDevices().size(), 2);
64     }
65 
66     // Test where fails: Invalid chassis number < 1
67     try
68     {
69         Chassis chassis{0};
70         ADD_FAILURE() << "Should not have reached this line.";
71     }
72     catch (const std::invalid_argument& e)
73     {
74         EXPECT_STREQ(e.what(), "Invalid chassis number: 0");
75     }
76     catch (...)
77     {
78         ADD_FAILURE() << "Should not have caught exception.";
79     }
80 }
81 
82 TEST(ChassisTests, AddToIDMap)
83 {
84     // Create vector of Device objects
85     std::vector<std::unique_ptr<Device>> devices{};
86     devices.emplace_back(createDevice("reg1", {"rail1"}));
87     devices.emplace_back(createDevice("reg2", {"rail2a", "rail2b"}));
88     devices.emplace_back(createDevice("reg3"));
89 
90     // Create Chassis
91     Chassis chassis{1, std::move(devices)};
92 
93     // Add Device and Rail objects within the Chassis to an IDMap
94     IDMap idMap{};
95     chassis.addToIDMap(idMap);
96 
97     // Verify all Devices are in the IDMap
98     EXPECT_NO_THROW(idMap.getDevice("reg1"));
99     EXPECT_NO_THROW(idMap.getDevice("reg2"));
100     EXPECT_NO_THROW(idMap.getDevice("reg3"));
101     EXPECT_THROW(idMap.getDevice("reg4"), std::invalid_argument);
102 
103     // Verify all Rails are in the IDMap
104     EXPECT_NO_THROW(idMap.getRail("rail1"));
105     EXPECT_NO_THROW(idMap.getRail("rail2a"));
106     EXPECT_NO_THROW(idMap.getRail("rail2b"));
107     EXPECT_THROW(idMap.getRail("rail3"), std::invalid_argument);
108 }
109 
110 TEST(ChassisTests, CloseDevices)
111 {
112     // Test where no devices were specified in constructor
113     {
114         // Create Chassis
115         Chassis chassis{2};
116 
117         // Call closeDevices()
118         journal::clear();
119         chassis.closeDevices();
120         EXPECT_EQ(journal::getErrMessages().size(), 0);
121         EXPECT_EQ(journal::getInfoMessages().size(), 0);
122         std::vector<std::string> expectedDebugMessages{
123             "Closing devices in chassis 2"};
124         EXPECT_EQ(journal::getDebugMessages(), expectedDebugMessages);
125     }
126 
127     // Test where devices were specified in constructor
128     {
129         std::vector<std::unique_ptr<Device>> devices{};
130 
131         // Create Device vdd0_reg
132         {
133             // Create mock I2CInterface: isOpen() and close() should be called
134             std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
135                 std::make_unique<i2c::MockedI2CInterface>();
136             EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
137             EXPECT_CALL(*i2cInterface, close).Times(1);
138 
139             // Create Device
140             std::unique_ptr<Device> device = std::make_unique<Device>(
141                 "vdd0_reg", true, "/system/chassis/motherboard/vdd0_reg",
142                 std::move(i2cInterface));
143             devices.emplace_back(std::move(device));
144         }
145 
146         // Create Device vdd1_reg
147         {
148             // Create mock I2CInterface: isOpen() and close() should be called
149             std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
150                 std::make_unique<i2c::MockedI2CInterface>();
151             EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
152             EXPECT_CALL(*i2cInterface, close).Times(1);
153 
154             // Create Device
155             std::unique_ptr<Device> device = std::make_unique<Device>(
156                 "vdd1_reg", true, "/system/chassis/motherboard/vdd1_reg",
157                 std::move(i2cInterface));
158             devices.emplace_back(std::move(device));
159         }
160 
161         // Create Chassis
162         Chassis chassis{1, std::move(devices)};
163 
164         // Call closeDevices()
165         journal::clear();
166         chassis.closeDevices();
167         EXPECT_EQ(journal::getErrMessages().size(), 0);
168         EXPECT_EQ(journal::getInfoMessages().size(), 0);
169         std::vector<std::string> expectedDebugMessages{
170             "Closing devices in chassis 1"};
171         EXPECT_EQ(journal::getDebugMessages(), expectedDebugMessages);
172     }
173 }
174 
175 TEST(ChassisTests, Configure)
176 {
177     // Test where no devices were specified in constructor
178     {
179         // Create Chassis
180         std::unique_ptr<Chassis> chassis = std::make_unique<Chassis>(1);
181         Chassis* chassisPtr = chassis.get();
182 
183         // Create System that contains Chassis
184         std::vector<std::unique_ptr<Rule>> rules{};
185         std::vector<std::unique_ptr<Chassis>> chassisVec{};
186         chassisVec.emplace_back(std::move(chassis));
187         System system{std::move(rules), std::move(chassisVec)};
188 
189         // Call configure()
190         journal::clear();
191         chassisPtr->configure(system);
192         EXPECT_EQ(journal::getDebugMessages().size(), 0);
193         EXPECT_EQ(journal::getErrMessages().size(), 0);
194         std::vector<std::string> expectedInfoMessages{"Configuring chassis 1"};
195         EXPECT_EQ(journal::getInfoMessages(), expectedInfoMessages);
196     }
197 
198     // Test where devices were specified in constructor
199     {
200         std::vector<std::unique_ptr<Device>> devices{};
201 
202         // Create Device vdd0_reg
203         {
204             // Create Configuration
205             std::vector<std::unique_ptr<Action>> actions{};
206             std::unique_ptr<Configuration> configuration =
207                 std::make_unique<Configuration>(1.3, std::move(actions));
208 
209             // Create Device
210             std::unique_ptr<i2c::I2CInterface> i2cInterface =
211                 createI2CInterface();
212             std::unique_ptr<PresenceDetection> presenceDetection{};
213             std::unique_ptr<Device> device = std::make_unique<Device>(
214                 "vdd0_reg", true, "/system/chassis/motherboard/vdd0_reg",
215                 std::move(i2cInterface), std::move(presenceDetection),
216                 std::move(configuration));
217             devices.emplace_back(std::move(device));
218         }
219 
220         // Create Device vdd1_reg
221         {
222             // Create Configuration
223             std::vector<std::unique_ptr<Action>> actions{};
224             std::unique_ptr<Configuration> configuration =
225                 std::make_unique<Configuration>(1.2, std::move(actions));
226 
227             // Create Device
228             std::unique_ptr<i2c::I2CInterface> i2cInterface =
229                 createI2CInterface();
230             std::unique_ptr<PresenceDetection> presenceDetection{};
231             std::unique_ptr<Device> device = std::make_unique<Device>(
232                 "vdd1_reg", true, "/system/chassis/motherboard/vdd1_reg",
233                 std::move(i2cInterface), std::move(presenceDetection),
234                 std::move(configuration));
235             devices.emplace_back(std::move(device));
236         }
237 
238         // Create Chassis
239         std::unique_ptr<Chassis> chassis =
240             std::make_unique<Chassis>(2, std::move(devices));
241         Chassis* chassisPtr = chassis.get();
242 
243         // Create System that contains Chassis
244         std::vector<std::unique_ptr<Rule>> rules{};
245         std::vector<std::unique_ptr<Chassis>> chassisVec{};
246         chassisVec.emplace_back(std::move(chassis));
247         System system{std::move(rules), std::move(chassisVec)};
248 
249         // Call configure()
250         journal::clear();
251         chassisPtr->configure(system);
252         std::vector<std::string> expectedDebugMessages{
253             "Configuring vdd0_reg: volts=1.300000",
254             "Configuring vdd1_reg: volts=1.200000"};
255         EXPECT_EQ(journal::getDebugMessages(), expectedDebugMessages);
256         EXPECT_EQ(journal::getErrMessages().size(), 0);
257         std::vector<std::string> expectedInfoMessages{"Configuring chassis 2"};
258         EXPECT_EQ(journal::getInfoMessages(), expectedInfoMessages);
259     }
260 }
261 
262 TEST(ChassisTests, GetDevices)
263 {
264     // Test where no devices were specified in constructor
265     {
266         Chassis chassis{2};
267         EXPECT_EQ(chassis.getDevices().size(), 0);
268     }
269 
270     // Test where devices were specified in constructor
271     {
272         // Create vector of Device objects
273         std::vector<std::unique_ptr<Device>> devices{};
274         devices.emplace_back(createDevice("vdd_reg1"));
275         devices.emplace_back(createDevice("vdd_reg2"));
276 
277         // Create Chassis
278         Chassis chassis{1, std::move(devices)};
279         EXPECT_EQ(chassis.getDevices().size(), 2);
280         EXPECT_EQ(chassis.getDevices()[0]->getID(), "vdd_reg1");
281         EXPECT_EQ(chassis.getDevices()[1]->getID(), "vdd_reg2");
282     }
283 }
284 
285 TEST(ChassisTests, GetNumber)
286 {
287     Chassis chassis{3};
288     EXPECT_EQ(chassis.getNumber(), 3);
289 }
290