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