1 #include "health_metric_collection.hpp"
2
3 #include <sdbusplus/test/sdbus_mock.hpp>
4 #include <xyz/openbmc_project/Metric/Value/server.hpp>
5
6 #include <gtest/gtest.h>
7
8 namespace ConfigIntf = phosphor::health::metric::config;
9 namespace MetricIntf = phosphor::health::metric;
10 namespace CollectionIntf = phosphor::health::metric::collection;
11
12 using PathInterface =
13 sdbusplus::common::xyz::openbmc_project::metric::Value::namespace_path;
14 using ThresholdIntf =
15 sdbusplus::server::xyz::openbmc_project::common::Threshold;
16 using ::testing::Invoke;
17 using ::testing::IsNull;
18 using ::testing::NotNull;
19 using ::testing::StrEq;
20
21 class HealthMetricCollectionTest : public ::testing::Test
22 {
23 public:
24 sdbusplus::SdBusMock sdbusMock;
25 sdbusplus::bus_t bus = sdbusplus::get_mocked_new(&sdbusMock);
26
27 static constexpr auto busName = "xyz.openbmc_project.test.HealthMon";
28 static constexpr auto objPath = "/xyz/openbmc_project/sdbusplus/test";
29 const std::string valueInterface =
30 sdbusplus::common::xyz::openbmc_project::metric::Value::interface;
31 const std::string thresholdInterface =
32 sdbusplus::common::xyz::openbmc_project::common::Threshold::interface;
33 ConfigIntf::HealthMetric::map_t configs;
34
SetUp()35 void SetUp() override
36 {
37 sdbusplus::server::manager_t objManager(bus, objPath);
38 bus.request_name(busName);
39
40 configs = ConfigIntf::getHealthMetricConfigs();
41 EXPECT_THAT(configs.size(), testing::Ge(1));
42 // Update the health metric window size to 1 and path for test purposes
43 for (auto& [key, values] : configs)
44 {
45 for (auto& config : values)
46 {
47 config.windowSize = 1;
48 if (key == MetricIntf::Type::storage)
49 {
50 config.path = "/tmp";
51 }
52 }
53 }
54 }
55
updateThreshold(ThresholdIntf::Bound bound,double value)56 void updateThreshold(ThresholdIntf::Bound bound, double value)
57 {
58 for (auto& [key, values] : configs)
59 {
60 for (auto& config : values)
61 {
62 for (auto& threshold : config.thresholds)
63 {
64 if (get<ThresholdIntf::Bound>(threshold.first) == bound)
65 {
66 threshold.second.value = value;
67 }
68 }
69 }
70 }
71 }
72
createCollection()73 void createCollection()
74 {
75 std::map<MetricIntf::Type,
76 std::unique_ptr<CollectionIntf::HealthMetricCollection>>
77 collections;
78 MetricIntf::paths_t bmcPaths = {};
79 for (const auto& [type, collectionConfig] : configs)
80 {
81 collections[type] =
82 std::make_unique<CollectionIntf::HealthMetricCollection>(
83 bus, type, collectionConfig, bmcPaths);
84 collections[type]->read();
85 }
86 }
87 };
88
TEST_F(HealthMetricCollectionTest,TestCreation)89 TEST_F(HealthMetricCollectionTest, TestCreation)
90 {
91 // Change threshold values to avoid threshold assertion
92 updateThreshold(ThresholdIntf::Bound::Upper, 100);
93 updateThreshold(ThresholdIntf::Bound::Lower, 0);
94
95 EXPECT_CALL(sdbusMock,
96 sd_bus_emit_properties_changed_strv(
97 IsNull(), NotNull(), StrEq(valueInterface), NotNull()))
98 .WillRepeatedly(Invoke(
99 [&]([[maybe_unused]] sd_bus* bus, [[maybe_unused]] const char* path,
100 [[maybe_unused]] const char* interface, const char** names) {
101 // Test no signal generation for metric init properties
102 const std::set<std::string> metricInitProperties = {
103 "MaxValue", "MinValue", "Unit"};
104 EXPECT_THAT(metricInitProperties,
105 testing::Not(testing::Contains(names[0])));
106 // Test signal generated for Value property set
107 const std::set<std::string> metricSetProperties = {"Value"};
108 EXPECT_THAT(metricSetProperties, testing::Contains(names[0]));
109 return 0;
110 }));
111
112 EXPECT_CALL(sdbusMock,
113 sd_bus_emit_properties_changed_strv(
114 IsNull(), NotNull(), StrEq(thresholdInterface), NotNull()))
115 .WillRepeatedly(Invoke(
116 [&]([[maybe_unused]] sd_bus* bus, [[maybe_unused]] const char* path,
117 [[maybe_unused]] const char* interface, const char** names) {
118 // Test signal generated for Value property set
119 EXPECT_STREQ("Value", names[0]);
120 // Test no signal generation for threshold asserted
121 EXPECT_STRNE("Asserted", names[0]);
122 return 0;
123 }));
124
125 createCollection();
126 }
127
TEST_F(HealthMetricCollectionTest,TestThresholdAsserted)128 TEST_F(HealthMetricCollectionTest, TestThresholdAsserted)
129 {
130 // Change threshold values to trigger threshold assertion
131 updateThreshold(ThresholdIntf::Bound::Upper, 0);
132 updateThreshold(ThresholdIntf::Bound::Lower, 100);
133
134 // Test metric value property change
135 EXPECT_CALL(sdbusMock,
136 sd_bus_emit_properties_changed_strv(
137 IsNull(), NotNull(), StrEq(valueInterface), NotNull()))
138 .WillRepeatedly(Invoke(
139 [&]([[maybe_unused]] sd_bus* bus, [[maybe_unused]] const char* path,
140 [[maybe_unused]] const char* interface, const char** names) {
141 EXPECT_THAT("Value", StrEq(names[0]));
142 return 0;
143 }));
144
145 // Test threshold asserted property change
146 EXPECT_CALL(sdbusMock,
147 sd_bus_emit_properties_changed_strv(
148 IsNull(), NotNull(), StrEq(thresholdInterface), NotNull()))
149 .WillRepeatedly(Invoke(
150 [&]([[maybe_unused]] sd_bus* bus, [[maybe_unused]] const char* path,
151 [[maybe_unused]] const char* interface, const char** names) {
152 // Test signal generation for threshold properties set
153 const std::set<std::string> thresholdProperties = {"Value",
154 "Asserted"};
155 EXPECT_THAT(thresholdProperties, testing::Contains(names[0]));
156 return 0;
157 }));
158
159 // Test AssertionChanged signal generation
160 EXPECT_CALL(sdbusMock,
161 sd_bus_message_new_signal(IsNull(), NotNull(), NotNull(),
162 StrEq(thresholdInterface),
163 StrEq("AssertionChanged")))
164 .Times(6);
165
166 createCollection();
167 }
168