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