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
TEST(PowerOffRuleTest,TestRules)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