Monitoring System 0.1.0
System resource monitoring with pluggable collectors and alerting
Loading...
Searching...
No Matches
test_power_collector.cpp
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2021-2025, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
5#include <gtest/gtest.h>
7
8namespace kcenon {
9namespace monitoring {
10namespace {
11
12// Test fixture for power collector tests
13class PowerCollectorTest : public ::testing::Test {
14 protected:
15 void SetUp() override {
16 collector_ = std::make_unique<power_collector>();
17 std::unordered_map<std::string, std::string> config;
18 collector_->initialize(config);
19 }
20
21 std::unique_ptr<power_collector> collector_;
22};
23
24// Test basic initialization
25TEST_F(PowerCollectorTest, InitializesSuccessfully) {
26 EXPECT_EQ(collector_->name(), "power");
27}
28
29// Test metric types returned
30TEST_F(PowerCollectorTest, ReturnsCorrectMetricTypes) {
31 auto metric_types = collector_->get_metric_types();
32
33 // Should include all expected power metrics
34 EXPECT_FALSE(metric_types.empty());
35
36 // Check for expected metric types
37 auto contains = [&metric_types](const std::string& type) {
38 return std::find(metric_types.begin(), metric_types.end(), type) != metric_types.end();
39 };
40
41 EXPECT_TRUE(contains("power_consumption_watts"));
42 EXPECT_TRUE(contains("energy_consumed_joules"));
43 EXPECT_TRUE(contains("power_limit_watts"));
44 EXPECT_TRUE(contains("battery_percent"));
45 EXPECT_TRUE(contains("battery_is_charging"));
46}
47
48// Test configuration options
49TEST_F(PowerCollectorTest, ConfigurationOptions) {
50 auto custom_collector = std::make_unique<power_collector>();
51
52 std::unordered_map<std::string, std::string> config = {
53 {"enabled", "true"}, {"collect_battery", "true"}, {"collect_rapl", "true"}};
54
55 EXPECT_TRUE(custom_collector->initialize(config));
56}
57
58// Test disable collector
59TEST_F(PowerCollectorTest, CanBeDisabled) {
60 auto custom_collector = std::make_unique<power_collector>();
61
62 std::unordered_map<std::string, std::string> config = {{"enabled", "false"}};
63
64 custom_collector->initialize(config);
65
66 // When disabled, collect should return empty
67 auto metrics = custom_collector->collect();
68 EXPECT_TRUE(metrics.empty());
69}
70
71// Test statistics
72TEST_F(PowerCollectorTest, TracksStatistics) {
73 auto stats = collector_->get_statistics();
74
75 // Should have expected statistics keys
76 EXPECT_TRUE(stats.find("collection_count") != stats.end());
77 EXPECT_TRUE(stats.find("collection_errors") != stats.end());
78 EXPECT_TRUE(stats.find("sources_found") != stats.end());
79
80 // Initial values should be 0
81 EXPECT_EQ(stats["collection_count"], 0.0);
82 EXPECT_EQ(stats["collection_errors"], 0.0);
83}
84
85// Test collect returns metrics (graceful degradation when sources unavailable)
86TEST_F(PowerCollectorTest, CollectReturnsMetrics) {
87 auto metrics = collector_->collect();
88
89 // This may return empty metrics if power sources are not available
90 // This is expected behavior - graceful degradation
91 auto stats = collector_->get_statistics();
92 EXPECT_GE(stats["collection_count"], 1.0);
93}
94
95// Test get_last_readings
96TEST_F(PowerCollectorTest, GetLastReadings) {
97 collector_->collect();
98 auto last_readings = collector_->get_last_readings();
99
100 // Should return vector (may be empty if power not available)
101 // No assertion - just verify it doesn't crash
102 (void)last_readings;
103}
104
105// Test is_power_available
106TEST_F(PowerCollectorTest, PowerAvailabilityCheck) {
107 // Should not crash - returns true/false based on power source availability
108 bool available = collector_->is_power_available();
109 (void)available; // Use the variable to avoid warning
110}
111
112// Test power_reading structure
113TEST(PowerReadingTest, DefaultInitialization) {
114 power_reading reading;
115
116 EXPECT_TRUE(reading.source.id.empty());
117 EXPECT_TRUE(reading.source.name.empty());
118 EXPECT_EQ(reading.source.type, power_source_type::unknown);
119 EXPECT_EQ(reading.power_watts, 0.0);
120 EXPECT_EQ(reading.energy_joules, 0.0);
121 EXPECT_EQ(reading.power_limit_watts, 0.0);
122 EXPECT_EQ(reading.voltage_volts, 0.0);
123 EXPECT_EQ(reading.battery_percent, 0.0);
124 EXPECT_FALSE(reading.power_available);
125 EXPECT_FALSE(reading.battery_available);
126 EXPECT_FALSE(reading.is_charging);
127 EXPECT_FALSE(reading.is_discharging);
128}
129
130// Test power_source_info structure
131TEST(PowerSourceInfoTest, DefaultInitialization) {
132 power_source_info info;
133
134 EXPECT_TRUE(info.id.empty());
135 EXPECT_TRUE(info.name.empty());
136 EXPECT_TRUE(info.path.empty());
137 EXPECT_EQ(info.type, power_source_type::unknown);
138}
139
140// Test power_source_type_to_string conversion
141TEST(PowerSourceTypeTest, TypeToStringConversion) {
153}
154
155// Test power_info_collector basic functionality
156TEST(PowerInfoCollectorTest, BasicFunctionality) {
157 power_info_collector collector;
158
159 // Test power availability check (should not crash)
160 bool available = collector.is_power_available();
161
162 // If power is not available, enumerate_sources should still work
163 if (!available) {
164 auto sources = collector.enumerate_sources();
165 // Empty sources without power is acceptable
166 (void)sources;
167 } else {
168 // If power is available, we might get some sources
169 auto sources = collector.enumerate_sources();
170 // Just verify it doesn't crash - actual source count depends on system
171 (void)sources;
172 }
173}
174
175// Test source enumeration (graceful degradation)
176TEST(PowerInfoCollectorTest, EnumerateSources) {
177 power_info_collector collector;
178
179 auto sources = collector.enumerate_sources();
180
181 // Should return a vector (may be empty if power not available)
182 // No assertion on size - just verify it doesn't crash
183 (void)sources;
184}
185
186// Test multiple collections don't cause issues
187TEST_F(PowerCollectorTest, MultipleCollectionsAreStable) {
188 for (int i = 0; i < 5; ++i) {
189 auto metrics = collector_->collect();
190 // Should not crash on repeated calls
191 (void)metrics;
192 }
193
194 auto stats = collector_->get_statistics();
195 EXPECT_GE(stats["collection_count"], 5.0);
196 EXPECT_EQ(stats["collection_errors"], 0.0);
197}
198
199// Test that metrics have correct tags when collected
200TEST_F(PowerCollectorTest, MetricsHaveCorrectTags) {
201 auto metrics = collector_->collect();
202
203 for (const auto& m : metrics) {
204 // If we have any metrics, check they have the expected tags
205 if (!m.name.empty()) {
206 EXPECT_TRUE(m.tags.find("source_id") != m.tags.end());
207 EXPECT_TRUE(m.tags.find("source_name") != m.tags.end());
208 EXPECT_TRUE(m.tags.find("source_type") != m.tags.end());
209 }
210 }
211}
212
213// Test read_all_power
214TEST(PowerInfoCollectorTest, ReadAllPower) {
215 power_info_collector collector;
216
217 auto readings = collector.read_all_power();
218
219 // Should return a vector (may be empty if power not available)
220 // No assertion on size - just verify it doesn't crash
221 for (const auto& reading : readings) {
222 // If we got readings, they should have valid source info
223 EXPECT_FALSE(reading.source.id.empty());
224 }
225}
226
227// Test battery-specific configuration
228TEST_F(PowerCollectorTest, BatteryConfigurationDisabled) {
229 auto custom_collector = std::make_unique<power_collector>();
230
231 std::unordered_map<std::string, std::string> config = {
232 {"enabled", "true"}, {"collect_battery", "false"}};
233
234 EXPECT_TRUE(custom_collector->initialize(config));
235
236 // Collection should still work but may filter battery sources
237 auto metrics = custom_collector->collect();
238 (void)metrics; // Just verify it runs
239}
240
241// Test RAPL-specific configuration
242TEST_F(PowerCollectorTest, RaplConfigurationDisabled) {
243 auto custom_collector = std::make_unique<power_collector>();
244
245 std::unordered_map<std::string, std::string> config = {
246 {"enabled", "true"}, {"collect_rapl", "false"}};
247
248 EXPECT_TRUE(custom_collector->initialize(config));
249
250 // Collection should still work but may filter RAPL sources
251 auto metrics = custom_collector->collect();
252 (void)metrics; // Just verify it runs
253}
254
255} // namespace
256} // namespace monitoring
257} // namespace kcenon
std::string power_source_type_to_string(power_source_type type)
Convert power_source_type to string representation.
@ info
Informational, no action required.
@ platform
Platform/system power domain.
@ other
Other power source type.
@ unknown
Unknown power source type.
@ memory
Memory/DRAM power domain (RAPL)
@ cpu
CPU power domain (RAPL)
@ ac
AC adapter / mains power.
@ package
Processor package power domain (RAPL)
Power consumption monitoring collector.
TEST(AdapterFunctionalityTest, WorksWithoutLogger)
Test Scenario 1: Adapter with NULL logger.
TEST_F(AdaptiveMonitoringTest, AdaptiveConfigDefaults)
std::unique_ptr< battery_collector > collector_