1 #include "../json_parser.hpp" 2 #include "../power_off_rule.hpp" 3 #include "mock_power_interface.hpp" 4 5 #include <gtest/gtest.h> 6 7 using namespace phosphor::fan::monitor; 8 using json = nlohmann::json; 9 10 TEST(PowerOffRuleTest, TestRules) 11 { 12 PowerOffAction::PrePowerOffFunc func; 13 sd_event* event; 14 sd_event_default(&event); 15 sdeventplus::Event sdEvent{event}; 16 17 const auto faultConfig = R"( 18 { 19 "fault_handling": 20 { 21 "power_off_config": [ 22 { 23 "type": "hard", 24 "cause": "missing_fan_frus", 25 "count": 2, 26 "delay": 0, 27 "state": "at_pgood" 28 }, 29 { 30 "type": "soft", 31 "cause": "nonfunc_fan_rotors", 32 "count": 3, 33 "delay": 0, 34 "state": "runtime" 35 }, 36 { 37 "type": "soft", 38 "cause": "nonfunc_fan_rotors", 39 "count": 4, 40 "delay": 1, 41 "state": "runtime" 42 }, 43 { 44 "type": "hard", 45 "cause": "missing_fan_frus", 46 "count": 4, 47 "delay": 1, 48 "state": "runtime" 49 } 50 ] 51 } 52 })"_json; 53 54 std::shared_ptr<PowerInterfaceBase> powerIface = 55 std::make_shared<MockPowerInterface>(); 56 57 MockPowerInterface& mockIface = 58 static_cast<MockPowerInterface&>(*powerIface); 59 60 EXPECT_CALL(mockIface, hardPowerOff).Times(1); 61 EXPECT_CALL(mockIface, softPowerOff).Times(1); 62 63 auto rules = getPowerOffRules(faultConfig, powerIface, func); 64 ASSERT_EQ(rules.size(), 4); 65 66 FanHealth health{{"fan0", {false, {true, true}}}, 67 {"fan1", {false, {true, true}}}}; 68 69 { 70 // Check rule 0 71 72 // wrong state, won't be active 73 rules[0]->check(PowerRuleState::runtime, health); 74 EXPECT_FALSE(rules[0]->active()); 75 76 rules[0]->check(PowerRuleState::atPgood, health); 77 EXPECT_TRUE(rules[0]->active()); 78 79 // Run the event loop, since the timeout is 0 it should 80 // run the power off and satisfy the EXPECT_CALL above 81 sdEvent.run(std::chrono::milliseconds(1)); 82 83 // It doesn't really make much sense to cancel a rule after it 84 // powered off, but it should at least say it isn't active. 85 rules[0]->cancel(); 86 EXPECT_FALSE(rules[0]->active()); 87 } 88 89 { 90 // Check the second rule. 91 rules[1]->check(PowerRuleState::runtime, health); 92 EXPECT_FALSE(rules[1]->active()); 93 94 // > 2 nonfunc rotors 95 health["fan0"] = {true, {true, false}}; 96 health["fan1"] = {true, {false, false}}; 97 98 rules[1]->check(PowerRuleState::runtime, health); 99 EXPECT_TRUE(rules[1]->active()); 100 101 // Run the event loop, since the timeout is 0 it should 102 // run the power off and satisfy the EXPECT_CALL above 103 sdEvent.run(std::chrono::milliseconds(1)); 104 } 105 106 { 107 // Check the third rule. It has a timeout so long we can 108 // cancel it before it runs. 109 health["fan0"] = {true, {false, false}}; 110 health["fan1"] = {true, {false, false}}; 111 112 rules[2]->check(PowerRuleState::runtime, health); 113 EXPECT_TRUE(rules[2]->active()); 114 115 sdEvent.run(std::chrono::milliseconds(1)); 116 117 rules[2]->cancel(); 118 EXPECT_FALSE(rules[2]->active()); 119 120 // This will go past the timeout, it should have been canceled so the 121 // soft power off won't have run and the EXPECT_CALL above 122 // should be happy. 123 sdEvent.run(std::chrono::seconds(1)); 124 } 125 126 { 127 // Check the 4th rule. Resolve it before it completes 128 health["fan0"] = {false, {true, true}}; 129 health["fan1"] = {false, {true, true}}; 130 health["fan2"] = {false, {true, true}}; 131 health["fan3"] = {false, {true, true}}; 132 133 rules[3]->check(PowerRuleState::runtime, health); 134 EXPECT_TRUE(rules[3]->active()); 135 136 // Won't complete yet 137 sdEvent.run(std::chrono::milliseconds(1)); 138 139 // Make them present 140 health["fan0"] = {true, {true, true}}; 141 health["fan1"] = {true, {true, true}}; 142 health["fan2"] = {true, {true, true}}; 143 health["fan3"] = {true, {true, true}}; 144 145 // It should be inactive now 146 rules[3]->check(PowerRuleState::runtime, health); 147 EXPECT_FALSE(rules[3]->active()); 148 } 149 } 150