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 "action_environment.hpp"
18 #include "device.hpp"
19 #include "id_map.hpp"
20 #include "mock_action.hpp"
21 #include "mock_services.hpp"
22 #include "rule.hpp"
23 #include "run_rule_action.hpp"
24 
25 #include <exception>
26 #include <memory>
27 #include <stdexcept>
28 #include <utility>
29 #include <vector>
30 
31 #include <gmock/gmock.h>
32 #include <gtest/gtest.h>
33 
34 using namespace phosphor::power::regulators;
35 
36 using ::testing::Return;
37 using ::testing::Throw;
38 
39 TEST(RunRuleActionTests, Constructor)
40 {
41     RunRuleAction action{"set_voltage_rule"};
42     EXPECT_EQ(action.getRuleID(), "set_voltage_rule");
43 }
44 
45 TEST(RunRuleActionTests, Execute)
46 {
47     // Test where rule ID is not in the IDMap/ActionEnvironment
48     try
49     {
50         IDMap idMap{};
51         MockServices services{};
52         ActionEnvironment env{idMap, "", services};
53         RunRuleAction runRuleAction{"set_voltage_rule"};
54         runRuleAction.execute(env);
55         ADD_FAILURE() << "Should not have reached this line.";
56     }
57     catch (const std::invalid_argument& ia_error)
58     {
59         EXPECT_STREQ(ia_error.what(),
60                      "Unable to find rule with ID \"set_voltage_rule\"");
61     }
62     catch (const std::exception& error)
63     {
64         ADD_FAILURE() << "Should not have caught exception.";
65     }
66 
67     // Test where a rule action throws an exception
68     try
69     {
70         // Create rule with action that throws an exception
71         std::vector<std::unique_ptr<Action>> actions{};
72         std::unique_ptr<MockAction> action = std::make_unique<MockAction>();
73         EXPECT_CALL(*action, execute)
74             .Times(1)
75             .WillOnce(Throw(std::logic_error{"Communication error"}));
76         actions.push_back(std::move(action));
77         Rule rule("exception_rule", std::move(actions));
78 
79         // Create ActionEnvironment
80         IDMap idMap{};
81         idMap.addRule(rule);
82         MockServices services{};
83         ActionEnvironment env{idMap, "", services};
84 
85         // Create RunRuleAction
86         RunRuleAction runRuleAction{"exception_rule"};
87         runRuleAction.execute(env);
88         ADD_FAILURE() << "Should not have reached this line.";
89     }
90     catch (const std::exception& error)
91     {
92         EXPECT_STREQ(error.what(), "Communication error");
93     }
94 
95     // Test where rule calls itself and results in infinite recursion
96     try
97     {
98         // Create rule that calls itself
99         std::vector<std::unique_ptr<Action>> actions{};
100         actions.push_back(std::make_unique<RunRuleAction>("infinite_rule"));
101         Rule rule("infinite_rule", std::move(actions));
102 
103         // Create ActionEnvironment
104         IDMap idMap{};
105         idMap.addRule(rule);
106         MockServices services{};
107         ActionEnvironment env{idMap, "", services};
108 
109         // Create RunRuleAction
110         RunRuleAction runRuleAction{"infinite_rule"};
111         runRuleAction.execute(env);
112         ADD_FAILURE() << "Should not have reached this line.";
113     }
114     catch (const std::runtime_error& r_error)
115     {
116         EXPECT_STREQ(r_error.what(),
117                      "Maximum rule depth exceeded by rule infinite_rule.");
118     }
119     catch (const std::exception& error)
120     {
121         ADD_FAILURE() << "Should not have caught exception.";
122     }
123 
124     // Test where last action returns false
125     try
126     {
127         // Create rule with two actions.  Last action returns false.
128         std::vector<std::unique_ptr<Action>> actions{};
129         std::unique_ptr<MockAction> action;
130 
131         action = std::make_unique<MockAction>();
132         EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true));
133         actions.push_back(std::move(action));
134 
135         action = std::make_unique<MockAction>();
136         EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(false));
137         actions.push_back(std::move(action));
138 
139         Rule rule("set_voltage_rule", std::move(actions));
140 
141         // Create ActionEnvironment
142         IDMap idMap{};
143         idMap.addRule(rule);
144         MockServices services{};
145         ActionEnvironment env{idMap, "", services};
146 
147         // Create RunRuleAction
148         RunRuleAction runRuleAction{"set_voltage_rule"};
149         EXPECT_EQ(runRuleAction.execute(env), false);
150         EXPECT_EQ(env.getRuleDepth(), 0);
151     }
152     catch (const std::exception& error)
153     {
154         ADD_FAILURE() << "Should not have caught exception.";
155     }
156 
157     // Test where last action returns true
158     try
159     {
160         // Create rule with two actions.  Last action returns true.
161         std::vector<std::unique_ptr<Action>> actions{};
162         std::unique_ptr<MockAction> action;
163 
164         action = std::make_unique<MockAction>();
165         EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(false));
166         actions.push_back(std::move(action));
167 
168         action = std::make_unique<MockAction>();
169         EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true));
170         actions.push_back(std::move(action));
171 
172         Rule rule("set_voltage_rule", std::move(actions));
173 
174         // Create ActionEnvironment
175         IDMap idMap{};
176         idMap.addRule(rule);
177         MockServices services{};
178         ActionEnvironment env{idMap, "", services};
179 
180         // Create RunRuleAction
181         RunRuleAction runRuleAction{"set_voltage_rule"};
182         EXPECT_EQ(runRuleAction.execute(env), true);
183         EXPECT_EQ(env.getRuleDepth(), 0);
184     }
185     catch (const std::exception& error)
186     {
187         ADD_FAILURE() << "Should not have caught exception.";
188     }
189 }
190 
191 TEST(RunRuleActionTests, GetRuleID)
192 {
193     RunRuleAction action{"read_sensors_rule"};
194     EXPECT_EQ(action.getRuleID(), "read_sensors_rule");
195 }
196 
197 TEST(RunRuleActionTests, ToString)
198 {
199     RunRuleAction action{"set_voltage_rule"};
200     EXPECT_EQ(action.toString(), "run_rule: set_voltage_rule");
201 }
202