Monitoring System 0.1.0
System resource monitoring with pluggable collectors and alerting
Loading...
Searching...
No Matches
test_interrupt_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
8#include <thread> // for std::this_thread::sleep_for
9
10namespace kcenon {
11namespace monitoring {
12namespace {
13
14// Test fixture for interrupt_collector tests
15class InterruptCollectorTest : public ::testing::Test {
16 protected:
17 void SetUp() override {
18 collector_ = std::make_unique<interrupt_collector>();
19 std::unordered_map<std::string, std::string> config;
20 collector_->initialize(config);
21 }
22
23 std::unique_ptr<interrupt_collector> collector_;
24};
25
26// Test basic initialization
27TEST_F(InterruptCollectorTest, InitializesSuccessfully) {
28 EXPECT_NE(collector_, nullptr);
29 EXPECT_EQ(collector_->name(), "interrupt_collector");
30}
31
32// Test metric types returned
33TEST_F(InterruptCollectorTest, ReturnsCorrectMetricTypes) {
34 auto types = collector_->get_metric_types();
35 EXPECT_FALSE(types.empty());
36
37 // Check for expected metric types
38 std::vector<std::string> expected = {
39 "interrupts_total",
40 "interrupts_per_sec",
41 "soft_interrupts_total",
42 "soft_interrupts_per_sec"
43 };
44
45 for (const auto& expected_type : expected) {
46 EXPECT_NE(std::find(types.begin(), types.end(), expected_type), types.end())
47 << "Missing metric type: " << expected_type;
48 }
49}
50
51// Test configuration options
52TEST_F(InterruptCollectorTest, ConfigurationOptions) {
53 auto collector = std::make_unique<interrupt_collector>();
54 std::unordered_map<std::string, std::string> config;
55 config["collect_per_cpu"] = "true";
56 config["collect_soft_interrupts"] = "false";
57 EXPECT_TRUE(collector->initialize(config));
58
59 auto stats = collector->get_statistics();
60 EXPECT_DOUBLE_EQ(stats["collect_per_cpu"], 1.0);
61 EXPECT_DOUBLE_EQ(stats["collect_soft_interrupts"], 0.0);
62}
63
64// Test disable collector
65TEST_F(InterruptCollectorTest, CanBeDisabled) {
66 auto collector = std::make_unique<interrupt_collector>();
67 std::unordered_map<std::string, std::string> config;
68 config["enabled"] = "false";
69 collector->initialize(config);
70
71 auto metrics = collector->collect();
72 EXPECT_TRUE(metrics.empty());
73
74 auto stats = collector->get_statistics();
75 EXPECT_DOUBLE_EQ(stats["enabled"], 0.0);
76}
77
78// Test statistics
79TEST_F(InterruptCollectorTest, TracksStatistics) {
80 // Collect some metrics
81 collector_->collect();
82 collector_->collect();
83
84 auto stats = collector_->get_statistics();
85 if (collector_->is_interrupt_monitoring_available()) {
86 // On platforms with interrupt monitoring, collections should succeed
87 EXPECT_GE(stats["collection_count"], 2.0);
88 } else {
89 // On platforms without interrupt monitoring (e.g. Windows),
90 // collections fail gracefully and increment error count instead
91 EXPECT_GE(stats["collection_errors"], 2.0);
92 }
93}
94
95// Test collect returns metrics (graceful degradation when unavailable)
96TEST_F(InterruptCollectorTest, CollectReturnsMetrics) {
97 // Should not throw even if platform-specific metrics fail
98 EXPECT_NO_THROW(collector_->collect());
99}
100
101// Test get_last_metrics
102TEST_F(InterruptCollectorTest, GetLastMetrics) {
103 collector_->collect();
104 auto last = collector_->get_last_metrics();
105
106 if (collector_->is_interrupt_monitoring_available()) {
107 // On platforms with interrupt monitoring, timestamp should be recent
108 auto now = std::chrono::system_clock::now();
109 auto diff = std::chrono::duration_cast<std::chrono::seconds>(now - last.timestamp);
110 EXPECT_LT(diff.count(), 10); // Within 10 seconds
111 } else {
112 // On platforms without interrupt monitoring (e.g. Windows),
113 // last_metrics_ is never updated so metrics_available stays false
114 EXPECT_FALSE(last.metrics_available);
115 }
116}
117
118// Test is_interrupt_monitoring_available
119TEST_F(InterruptCollectorTest, InterruptMonitoringAvailabilityCheck) {
120 // This should return true or false depending on platform
121 // Either result is valid - we just want to ensure it doesn't crash
122 EXPECT_NO_THROW(collector_->is_interrupt_monitoring_available());
123}
124
125// Test interrupt_metrics structure
126TEST(InterruptMetricsTest, DefaultInitialization) {
127 interrupt_metrics metrics;
128 EXPECT_EQ(metrics.interrupts_total, 0);
129 EXPECT_DOUBLE_EQ(metrics.interrupts_per_sec, 0.0);
130 EXPECT_EQ(metrics.soft_interrupts_total, 0);
131 EXPECT_DOUBLE_EQ(metrics.soft_interrupts_per_sec, 0.0);
132 EXPECT_TRUE(metrics.per_cpu.empty());
133 EXPECT_FALSE(metrics.metrics_available);
134 EXPECT_FALSE(metrics.soft_interrupts_available);
135}
136
137// Test cpu_interrupt_info structure
138TEST(CpuInterruptInfoTest, DefaultInitialization) {
139 cpu_interrupt_info info;
140 EXPECT_EQ(info.cpu_id, 0);
141 EXPECT_EQ(info.interrupt_count, 0);
142 EXPECT_DOUBLE_EQ(info.interrupts_per_sec, 0.0);
143}
144
145// Test interrupt_info_collector basic functionality
146TEST(InterruptInfoCollectorTest, BasicFunctionality) {
147 interrupt_info_collector collector;
148
149 // Test availability check
150 EXPECT_NO_THROW(collector.is_interrupt_monitoring_available());
151
152 // Test metrics collection
153 auto metrics = collector.collect_metrics();
154
155 // Timestamp should be set
156 auto now = std::chrono::system_clock::now();
157 auto diff = std::chrono::duration_cast<std::chrono::seconds>(now - metrics.timestamp);
158 EXPECT_LT(diff.count(), 10);
159}
160
161// Test multiple collections are stable
162TEST_F(InterruptCollectorTest, MultipleCollectionsAreStable) {
163 for (int i = 0; i < 10; ++i) {
164 auto metrics = collector_->collect();
165 // Should not crash or throw
166 EXPECT_NO_THROW(collector_->get_statistics());
167 }
168
169 auto stats = collector_->get_statistics();
170 if (collector_->is_interrupt_monitoring_available()) {
171 EXPECT_GE(stats["collection_count"], 10.0);
172 } else {
173 // On platforms without interrupt monitoring (e.g. Windows),
174 // all collections fail gracefully
175 EXPECT_GE(stats["collection_errors"], 10.0);
176 }
177}
178
179// Test that metrics have correct tags when collected
180TEST_F(InterruptCollectorTest, MetricsHaveCorrectTags) {
181 auto metrics = collector_->collect();
182
183 for (const auto& m : metrics) {
184 // All metrics should have the collector tag
185 auto it = m.tags.find("collector");
186 if (it != m.tags.end()) {
187 EXPECT_EQ(it->second, "interrupt_collector");
188 }
189 }
190}
191
192// Test is_available reflects actual state
193TEST_F(InterruptCollectorTest, IsAvailableReflectsState) {
194 // When enabled, availability depends on platform support
195 bool available = false;
196 EXPECT_NO_THROW(available = collector_->is_available());
197 (void)available; // Suppress unused variable warning
198
199 // When disabled, collector should still report availability status
200 auto disabled_collector = std::make_unique<interrupt_collector>();
201 std::unordered_map<std::string, std::string> config;
202 config["enabled"] = "false";
203 disabled_collector->initialize(config);
204 EXPECT_NO_THROW(disabled_collector->is_available());
205}
206
207#if defined(__linux__) || defined(__APPLE__)
208// Platform-specific test: On Unix-like systems, interrupt monitoring should be available
209TEST_F(InterruptCollectorTest, UnixInterruptMonitoringAvailable) {
210 EXPECT_TRUE(collector_->is_interrupt_monitoring_available());
211}
212
213// Platform-specific test: Should have positive interrupt count on Unix
214TEST(InterruptInfoCollectorTest, HasInterruptsOnUnix) {
215 interrupt_info_collector collector;
216
217 if (collector.is_interrupt_monitoring_available()) {
218 auto metrics = collector.collect_metrics();
219 EXPECT_TRUE(metrics.metrics_available);
220 // Interrupt count should be positive on a running system
221 EXPECT_GT(metrics.interrupts_total, 0);
222 }
223}
224
225// Platform-specific test: Rate calculation works after multiple samples
226TEST(InterruptInfoCollectorTest, RateCalculationWorks) {
227 interrupt_info_collector collector;
228
229 if (collector.is_interrupt_monitoring_available()) {
230 // First sample - rate should be 0
231 auto first = collector.collect_metrics();
232 EXPECT_DOUBLE_EQ(first.interrupts_per_sec, 0.0);
233
234 // Brief pause to allow some interrupts
235 std::this_thread::sleep_for(std::chrono::milliseconds(100));
236
237 // Second sample - rate should be calculated (may still be 0 if no change)
238 auto second = collector.collect_metrics();
239 // Rate is computed, no crash expected
240 EXPECT_GE(second.interrupts_per_sec, 0.0);
241 }
242}
243#endif
244
245#if defined(_WIN32)
246// Platform-specific test: On Windows, interrupt monitoring is not yet available
247TEST_F(InterruptCollectorTest, WindowsInterruptMonitoringUnavailable) {
248 EXPECT_FALSE(collector_->is_interrupt_monitoring_available());
249}
250
251// Platform-specific test: Windows metrics should indicate unavailability
252TEST(InterruptInfoCollectorTest, WindowsReturnsUnavailableMetrics) {
253 interrupt_info_collector collector;
254 auto metrics = collector.collect_metrics();
255 EXPECT_FALSE(metrics.metrics_available);
256}
257#endif
258
259} // namespace
260} // namespace monitoring
261} // namespace kcenon
Hardware and software interrupt statistics monitoring collector.
@ info
Informational, no action required.
TEST(AdapterFunctionalityTest, WorksWithoutLogger)
Test Scenario 1: Adapter with NULL logger.
TEST_F(AdaptiveMonitoringTest, AdaptiveConfigDefaults)
std::unique_ptr< battery_collector > collector_