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_environment.hpp"
17 #include "device.hpp"
18 #include "i2c_interface.hpp"
19 #include "id_map.hpp"
20 #include "mock_services.hpp"
21 #include "mocked_i2c_interface.hpp"
22 #include "phase_fault.hpp"
23 #include "rule.hpp"
24 
25 #include <cstddef> // for size_t
26 #include <exception>
27 #include <memory>
28 #include <stdexcept>
29 #include <utility>
30 #include <vector>
31 
32 #include <gtest/gtest.h>
33 
34 using namespace phosphor::power::regulators;
35 
36 TEST(ActionEnvironmentTests, Constructor)
37 {
38     // Create IDMap
39     IDMap idMap{};
40 
41     // Create mock services.
42     MockServices services{};
43 
44     // Create Device and add to IDMap
45     std::unique_ptr<i2c::I2CInterface> i2cInterface =
46         i2c::create(1, 0x70, i2c::I2CInterface::InitialState::CLOSED);
47     Device reg1{
48         "regulator1", true,
49         "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
50         std::move(i2cInterface)};
51     idMap.addDevice(reg1);
52 
53     // Verify object state after constructor
54     try
55     {
56         ActionEnvironment env{idMap, "regulator1", services};
57         EXPECT_EQ(env.getAdditionalErrorData().size(), 0);
58         EXPECT_EQ(env.getDevice().getID(), "regulator1");
59         EXPECT_EQ(env.getDeviceID(), "regulator1");
60         EXPECT_EQ(env.getPhaseFaults().size(), 0);
61         EXPECT_EQ(env.getRuleDepth(), 0);
62         EXPECT_EQ(env.getVolts().has_value(), false);
63     }
64     catch (const std::exception& error)
65     {
66         ADD_FAILURE() << "Should not have caught exception.";
67     }
68 }
69 
70 TEST(ActionEnvironmentTests, AddAdditionalErrorData)
71 {
72     IDMap idMap{};
73     MockServices services{};
74     ActionEnvironment env{idMap, "", services};
75     EXPECT_EQ(env.getAdditionalErrorData().size(), 0);
76 
77     env.addAdditionalErrorData("foo", "foo_value");
78     env.addAdditionalErrorData("bar", "bar_value");
79     EXPECT_EQ(env.getAdditionalErrorData().size(), 2);
80     EXPECT_EQ(env.getAdditionalErrorData().at("foo"), "foo_value");
81     EXPECT_EQ(env.getAdditionalErrorData().at("bar"), "bar_value");
82 }
83 
84 TEST(ActionEnvironmentTests, AddPhaseFault)
85 {
86     IDMap idMap{};
87     MockServices services{};
88     ActionEnvironment env{idMap, "", services};
89     EXPECT_EQ(env.getPhaseFaults().size(), 0);
90 
91     // Add N phase fault
92     env.addPhaseFault(PhaseFaultType::n);
93     EXPECT_EQ(env.getPhaseFaults().size(), 1);
94     EXPECT_EQ(env.getPhaseFaults().count(PhaseFaultType::n), 1);
95     EXPECT_EQ(env.getPhaseFaults().count(PhaseFaultType::n_plus_1), 0);
96 
97     // Add N+1 phase fault
98     env.addPhaseFault(PhaseFaultType::n_plus_1);
99     EXPECT_EQ(env.getPhaseFaults().size(), 2);
100     EXPECT_EQ(env.getPhaseFaults().count(PhaseFaultType::n), 1);
101     EXPECT_EQ(env.getPhaseFaults().count(PhaseFaultType::n_plus_1), 1);
102 
103     // Add N+1 phase fault again; should be ignored since stored in a std::set
104     env.addPhaseFault(PhaseFaultType::n_plus_1);
105     EXPECT_EQ(env.getPhaseFaults().size(), 2);
106 }
107 
108 TEST(ActionEnvironmentTests, DecrementRuleDepth)
109 {
110     IDMap idMap{};
111     MockServices services{};
112     ActionEnvironment env{idMap, "", services};
113     EXPECT_EQ(env.getRuleDepth(), 0);
114     env.incrementRuleDepth("set_voltage_rule");
115     env.incrementRuleDepth("set_voltage_rule");
116     EXPECT_EQ(env.getRuleDepth(), 2);
117     env.decrementRuleDepth();
118     EXPECT_EQ(env.getRuleDepth(), 1);
119     env.decrementRuleDepth();
120     EXPECT_EQ(env.getRuleDepth(), 0);
121     env.decrementRuleDepth();
122     EXPECT_EQ(env.getRuleDepth(), 0);
123 }
124 
125 TEST(ActionEnvironmentTests, GetAdditionalErrorData)
126 {
127     IDMap idMap{};
128     MockServices services{};
129     ActionEnvironment env{idMap, "", services};
130     EXPECT_EQ(env.getAdditionalErrorData().size(), 0);
131 
132     env.addAdditionalErrorData("foo", "foo_value");
133     EXPECT_EQ(env.getAdditionalErrorData().size(), 1);
134     EXPECT_EQ(env.getAdditionalErrorData().at("foo"), "foo_value");
135 
136     env.addAdditionalErrorData("bar", "bar_value");
137     EXPECT_EQ(env.getAdditionalErrorData().size(), 2);
138     EXPECT_EQ(env.getAdditionalErrorData().at("bar"), "bar_value");
139 }
140 
141 TEST(ActionEnvironmentTests, GetDevice)
142 {
143     // Create IDMap
144     IDMap idMap{};
145 
146     // Create mock services.
147     MockServices services{};
148 
149     // Create Device and add to IDMap
150     std::unique_ptr<i2c::I2CInterface> i2cInterface =
151         i2c::create(1, 0x70, i2c::I2CInterface::InitialState::CLOSED);
152     Device reg1{
153         "regulator1", true,
154         "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
155         std::move(i2cInterface)};
156     idMap.addDevice(reg1);
157 
158     ActionEnvironment env{idMap, "regulator1", services};
159 
160     // Test where current device ID is in the IDMap
161     try
162     {
163         Device& device = env.getDevice();
164         EXPECT_EQ(device.getID(), "regulator1");
165         EXPECT_EQ(&device, &reg1);
166     }
167     catch (const std::exception& error)
168     {
169         ADD_FAILURE() << "Should not have caught exception.";
170     }
171 
172     // Test where current device ID is not in the IDMap
173     env.setDeviceID("regulator2");
174     try
175     {
176         env.getDevice();
177         ADD_FAILURE() << "Should not have reached this line.";
178     }
179     catch (const std::invalid_argument& ia_error)
180     {
181         EXPECT_STREQ(ia_error.what(),
182                      "Unable to find device with ID \"regulator2\"");
183     }
184     catch (const std::exception& error)
185     {
186         ADD_FAILURE() << "Should not have caught exception.";
187     }
188 }
189 
190 TEST(ActionEnvironmentTests, GetDeviceID)
191 {
192     IDMap idMap{};
193     MockServices services{};
194     ActionEnvironment env{idMap, "", services};
195     EXPECT_EQ(env.getDeviceID(), "");
196     env.setDeviceID("regulator1");
197     EXPECT_EQ(env.getDeviceID(), "regulator1");
198 }
199 
200 TEST(ActionEnvironmentTests, GetPhaseFaults)
201 {
202     IDMap idMap{};
203     MockServices services{};
204     ActionEnvironment env{idMap, "", services};
205     EXPECT_EQ(env.getPhaseFaults().size(), 0);
206 
207     env.addPhaseFault(PhaseFaultType::n);
208     env.addPhaseFault(PhaseFaultType::n_plus_1);
209     EXPECT_EQ(env.getPhaseFaults().size(), 2);
210     EXPECT_EQ(env.getPhaseFaults().count(PhaseFaultType::n), 1);
211     EXPECT_EQ(env.getPhaseFaults().count(PhaseFaultType::n_plus_1), 1);
212 }
213 
214 TEST(ActionEnvironmentTests, GetRule)
215 {
216     // Create IDMap
217     IDMap idMap{};
218 
219     // Create mock services.
220     MockServices services{};
221 
222     Rule setVoltageRule{"set_voltage_rule",
223                         std::vector<std::unique_ptr<Action>>{}};
224     idMap.addRule(setVoltageRule);
225 
226     ActionEnvironment env{idMap, "", services};
227 
228     // Test where rule ID is in the IDMap
229     try
230     {
231         Rule& rule = env.getRule("set_voltage_rule");
232         EXPECT_EQ(rule.getID(), "set_voltage_rule");
233         EXPECT_EQ(&rule, &setVoltageRule);
234     }
235     catch (const std::exception& error)
236     {
237         ADD_FAILURE() << "Should not have caught exception.";
238     }
239 
240     // Test where rule ID is not in the IDMap
241     try
242     {
243         env.getRule("set_voltage_rule2");
244         ADD_FAILURE() << "Should not have reached this line.";
245     }
246     catch (const std::invalid_argument& ia_error)
247     {
248         EXPECT_STREQ(ia_error.what(),
249                      "Unable to find rule with ID \"set_voltage_rule2\"");
250     }
251     catch (const std::exception& error)
252     {
253         ADD_FAILURE() << "Should not have caught exception.";
254     }
255 }
256 
257 TEST(ActionEnvironmentTests, GetRuleDepth)
258 {
259     IDMap idMap{};
260     MockServices services{};
261     ActionEnvironment env{idMap, "", services};
262     EXPECT_EQ(env.getRuleDepth(), 0);
263     env.incrementRuleDepth("set_voltage_rule");
264     EXPECT_EQ(env.getRuleDepth(), 1);
265     env.incrementRuleDepth("set_voltage_rule");
266     EXPECT_EQ(env.getRuleDepth(), 2);
267     env.decrementRuleDepth();
268     EXPECT_EQ(env.getRuleDepth(), 1);
269     env.decrementRuleDepth();
270     EXPECT_EQ(env.getRuleDepth(), 0);
271 }
272 
273 TEST(ActionEnvironmentTests, GetServices)
274 {
275     IDMap idMap{};
276     MockServices services{};
277     ActionEnvironment env{idMap, "", services};
278     EXPECT_EQ(&(env.getServices()), &services);
279 }
280 
281 TEST(ActionEnvironmentTests, GetVolts)
282 {
283     IDMap idMap{};
284     MockServices services{};
285     ActionEnvironment env{idMap, "", services};
286     EXPECT_EQ(env.getVolts().has_value(), false);
287     env.setVolts(1.31);
288     EXPECT_EQ(env.getVolts().has_value(), true);
289     EXPECT_EQ(env.getVolts().value(), 1.31);
290 }
291 
292 TEST(ActionEnvironmentTests, IncrementRuleDepth)
293 {
294     IDMap idMap{};
295     MockServices services{};
296     ActionEnvironment env{idMap, "", services};
297     EXPECT_EQ(env.getRuleDepth(), 0);
298 
299     // Test where rule depth has not exceeded maximum
300     try
301     {
302         for (size_t i = 1; i <= env.maxRuleDepth; ++i)
303         {
304             env.incrementRuleDepth("set_voltage_rule");
305             EXPECT_EQ(env.getRuleDepth(), i);
306         }
307     }
308     catch (const std::exception& error)
309     {
310         ADD_FAILURE() << "Should not have caught exception.";
311     }
312 
313     // Test where rule depth has exceeded maximum
314     try
315     {
316         env.incrementRuleDepth("set_voltage_rule");
317     }
318     catch (const std::runtime_error& r_error)
319     {
320         EXPECT_STREQ(r_error.what(),
321                      "Maximum rule depth exceeded by rule set_voltage_rule.");
322     }
323     catch (const std::exception& error)
324     {
325         ADD_FAILURE() << "Should not have caught exception.";
326     }
327 }
328 
329 TEST(ActionEnvironmentTests, SetDeviceID)
330 {
331     IDMap idMap{};
332     MockServices services{};
333     ActionEnvironment env{idMap, "regulator1", services};
334     EXPECT_EQ(env.getDeviceID(), "regulator1");
335     env.setDeviceID("regulator2");
336     EXPECT_EQ(env.getDeviceID(), "regulator2");
337 }
338 
339 TEST(ActionEnvironmentTests, SetVolts)
340 {
341     try
342     {
343         IDMap idMap{};
344         MockServices services{};
345         ActionEnvironment env{idMap, "", services};
346         EXPECT_EQ(env.getVolts().has_value(), false);
347         env.setVolts(2.35);
348         EXPECT_EQ(env.getVolts().has_value(), true);
349         EXPECT_EQ(env.getVolts().value(), 2.35);
350     }
351     catch (const std::exception& error)
352     {
353         ADD_FAILURE() << "Should not have caught exception.";
354     }
355 }
356