Monitoring System 0.1.0
System resource monitoring with pluggable collectors and alerting
Loading...
Searching...
No Matches
test_network_metrics_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 network_metrics_collector tests
13class NetworkMetricsCollectorTest : public ::testing::Test {
14 protected:
15 void SetUp() override {
16 collector_ = std::make_unique<network_metrics_collector>();
17 std::unordered_map<std::string, std::string> config;
18 collector_->initialize(config);
19 }
20
21 std::unique_ptr<network_metrics_collector> collector_;
22};
23
24// Test basic initialization
25TEST_F(NetworkMetricsCollectorTest, InitializesSuccessfully) {
26 EXPECT_NE(collector_, nullptr);
27 EXPECT_EQ(collector_->name(), "network_metrics_collector");
28}
29
30// Test metric types returned
31TEST_F(NetworkMetricsCollectorTest, ReturnsCorrectMetricTypes) {
32 auto types = collector_->get_metric_types();
33 EXPECT_FALSE(types.empty());
34
35 // Check for expected socket buffer metric types
36 std::vector<std::string> expected_socket_types = {
37 "network_socket_recv_buffer_bytes",
38 "network_socket_send_buffer_bytes",
39 "network_socket_memory_bytes",
40 "network_socket_count_total"
41 };
42
43 for (const auto& expected : expected_socket_types) {
44 bool found = std::find(types.begin(), types.end(), expected) != types.end();
45 EXPECT_TRUE(found) << "Expected metric type not found: " << expected;
46 }
47
48 // Check for expected TCP state metric types
49 std::vector<std::string> expected_tcp_types = {
50 "network_tcp_connections_established",
51 "network_tcp_connections_time_wait",
52 "network_tcp_connections_close_wait",
53 "network_tcp_connections_total"
54 };
55
56 for (const auto& expected : expected_tcp_types) {
57 bool found = std::find(types.begin(), types.end(), expected) != types.end();
58 EXPECT_TRUE(found) << "Expected metric type not found: " << expected;
59 }
60}
61
62// Test configuration options
63TEST_F(NetworkMetricsCollectorTest, ConfigurationOptions) {
64 auto collector = std::make_unique<network_metrics_collector>();
65
66 std::unordered_map<std::string, std::string> config = {
67 {"enabled", "true"},
68 {"collect_socket_buffers", "true"},
69 {"collect_tcp_states", "true"},
70 {"time_wait_warning_threshold", "5000"},
71 {"close_wait_warning_threshold", "50"},
72 {"queue_full_threshold_bytes", "32768"},
73 {"memory_warning_threshold_bytes", "52428800"}
74 };
75
76 EXPECT_TRUE(collector->initialize(config));
77}
78
79// Test disable collector
80TEST_F(NetworkMetricsCollectorTest, CanBeDisabled) {
81 auto collector = std::make_unique<network_metrics_collector>();
82
83 std::unordered_map<std::string, std::string> config = {
84 {"enabled", "false"}
85 };
86
87 collector->initialize(config);
88
89 auto metrics = collector->collect();
90 // Disabled collector should return empty metrics
91 EXPECT_TRUE(metrics.empty());
92}
93
94// Test disable socket buffers collection
95TEST_F(NetworkMetricsCollectorTest, CanDisableSocketBuffers) {
96 auto collector = std::make_unique<network_metrics_collector>();
97
98 std::unordered_map<std::string, std::string> config = {
99 {"collect_socket_buffers", "false"},
100 {"collect_tcp_states", "true"}
101 };
102
103 collector->initialize(config);
104
105 auto types = collector->get_metric_types();
106 // Should not contain socket buffer types
107 bool found = std::find(types.begin(), types.end(),
108 "network_socket_recv_buffer_bytes") != types.end();
109 EXPECT_FALSE(found);
110}
111
112// Test disable TCP states collection
113TEST_F(NetworkMetricsCollectorTest, CanDisableTcpStates) {
114 auto collector = std::make_unique<network_metrics_collector>();
115
116 std::unordered_map<std::string, std::string> config = {
117 {"collect_socket_buffers", "true"},
118 {"collect_tcp_states", "false"}
119 };
120
121 collector->initialize(config);
122
123 auto types = collector->get_metric_types();
124 // Should not contain TCP state types
125 bool found = std::find(types.begin(), types.end(),
126 "network_tcp_connections_established") != types.end();
127 EXPECT_FALSE(found);
128}
129
130// Test statistics
131TEST_F(NetworkMetricsCollectorTest, TracksStatistics) {
132 auto stats = collector_->get_statistics();
133 EXPECT_TRUE(stats.find("collection_count") != stats.end());
134 EXPECT_TRUE(stats.find("collection_errors") != stats.end());
135 EXPECT_TRUE(stats.find("enabled") != stats.end());
136 EXPECT_TRUE(stats.find("socket_buffer_available") != stats.end());
137 EXPECT_TRUE(stats.find("tcp_state_available") != stats.end());
138}
139
140// Test collect returns metrics (graceful degradation when unavailable)
141TEST_F(NetworkMetricsCollectorTest, CollectReturnsMetrics) {
142 auto metrics = collector_->collect();
143 // May be empty if not available on this platform
144 // Just verify it doesn't crash
145}
146
147// Test get_last_metrics
148TEST_F(NetworkMetricsCollectorTest, GetLastMetrics) {
149 collector_->collect(); // Trigger a collection
150 auto last = collector_->get_last_metrics();
151 // Verify timestamp is set
152 auto now = std::chrono::system_clock::now();
153 auto diff = std::chrono::duration_cast<std::chrono::seconds>(now - last.timestamp);
154 EXPECT_LT(diff.count(), 10); // Should be recent
155}
156
157// Test monitoring availability checks
158TEST_F(NetworkMetricsCollectorTest, MonitoringAvailabilityCheck) {
159 bool socket_available = collector_->is_socket_buffer_monitoring_available();
160 bool tcp_available = collector_->is_tcp_state_monitoring_available();
161 // Just check it returns booleans without crashing
162 (void)socket_available;
163 (void)tcp_available;
164}
165
166// Test network_metrics structure
167TEST(NetworkMetricsTest, DefaultInitialization) {
168 network_metrics metrics;
169 EXPECT_EQ(metrics.recv_buffer_bytes, 0);
170 EXPECT_EQ(metrics.send_buffer_bytes, 0);
171 EXPECT_EQ(metrics.socket_memory_bytes, 0);
172 EXPECT_EQ(metrics.socket_count, 0);
173 EXPECT_EQ(metrics.tcp_socket_count, 0);
174 EXPECT_EQ(metrics.udp_socket_count, 0);
175 EXPECT_FALSE(metrics.socket_buffer_available);
176 EXPECT_EQ(metrics.total_connections, 0);
177 EXPECT_FALSE(metrics.tcp_state_available);
178}
179
180// Test tcp_state_counts structure
181TEST(TcpStateCountsTest, DefaultInitialization) {
182 tcp_state_counts counts;
183 EXPECT_EQ(counts.established, 0);
184 EXPECT_EQ(counts.syn_sent, 0);
185 EXPECT_EQ(counts.syn_recv, 0);
186 EXPECT_EQ(counts.fin_wait1, 0);
187 EXPECT_EQ(counts.fin_wait2, 0);
188 EXPECT_EQ(counts.time_wait, 0);
189 EXPECT_EQ(counts.close, 0);
190 EXPECT_EQ(counts.close_wait, 0);
191 EXPECT_EQ(counts.last_ack, 0);
192 EXPECT_EQ(counts.listen, 0);
193 EXPECT_EQ(counts.closing, 0);
194 EXPECT_EQ(counts.unknown, 0);
195}
196
197// Test tcp_state_counts increment
198TEST(TcpStateCountsTest, IncrementWorks) {
199 tcp_state_counts counts;
200 counts.increment(tcp_state::ESTABLISHED);
201 counts.increment(tcp_state::ESTABLISHED);
202 counts.increment(tcp_state::TIME_WAIT);
203
204 EXPECT_EQ(counts.established, 2);
205 EXPECT_EQ(counts.time_wait, 1);
206 EXPECT_EQ(counts.total(), 3);
207}
208
209// Test tcp_state_counts get_count
210TEST(TcpStateCountsTest, GetCountWorks) {
211 tcp_state_counts counts;
212 counts.established = 10;
213 counts.close_wait = 5;
214
215 EXPECT_EQ(counts.get_count(tcp_state::ESTABLISHED), 10);
216 EXPECT_EQ(counts.get_count(tcp_state::CLOSE_WAIT), 5);
217 EXPECT_EQ(counts.get_count(tcp_state::TIME_WAIT), 0);
218}
219
220// Test tcp_state_to_string
221TEST(TcpStateTest, ToStringWorks) {
222 EXPECT_EQ(tcp_state_to_string(tcp_state::ESTABLISHED), "ESTABLISHED");
223 EXPECT_EQ(tcp_state_to_string(tcp_state::SYN_SENT), "SYN_SENT");
224 EXPECT_EQ(tcp_state_to_string(tcp_state::TIME_WAIT), "TIME_WAIT");
225 EXPECT_EQ(tcp_state_to_string(tcp_state::CLOSE_WAIT), "CLOSE_WAIT");
226 EXPECT_EQ(tcp_state_to_string(tcp_state::LISTEN), "LISTEN");
227 EXPECT_EQ(tcp_state_to_string(tcp_state::UNKNOWN), "UNKNOWN");
228}
229
230// Test network_info_collector basic functionality
231TEST(NetworkInfoCollectorTest, BasicFunctionality) {
232 network_info_collector collector;
233
234 // Check availability
235 bool socket_available = collector.is_socket_buffer_monitoring_available();
236 bool tcp_available = collector.is_tcp_state_monitoring_available();
237
238 // Collect metrics with default config
239 network_metrics_config config;
240 auto metrics = collector.collect_metrics(config);
241
242 // If available, should have valid data
243 if (socket_available) {
244 EXPECT_TRUE(metrics.socket_buffer_available);
245 }
246 if (tcp_available) {
247 EXPECT_TRUE(metrics.tcp_state_available);
248 }
249}
250
251// Test multiple collections are stable
252TEST_F(NetworkMetricsCollectorTest, MultipleCollectionsAreStable) {
253 for (int i = 0; i < 3; ++i) {
254 auto metrics = collector_->collect();
255 // Should not crash
256 }
257
258 auto stats = collector_->get_statistics();
259 // Collection count should have increased
260}
261
262// Test that metrics have correct tags when collected
263TEST_F(NetworkMetricsCollectorTest, MetricsHaveCorrectTags) {
264 auto metrics = collector_->collect();
265 for (const auto& m : metrics) {
266 // All metrics should have collector tag
267 auto it = m.tags.find("collector");
268 if (it != m.tags.end()) {
269 EXPECT_EQ(it->second, "network_metrics_collector");
270 }
271 }
272}
273
274// Test is_available reflects actual state
275TEST_F(NetworkMetricsCollectorTest, IsAvailableReflectsState) {
276 bool available = collector_->is_available();
277 // Should be available initially (no errors yet)
278 EXPECT_TRUE(available);
279}
280
281// Test network_metrics_config default values
282TEST(NetworkMetricsConfigTest, DefaultValues) {
283 network_metrics_config config;
284 EXPECT_TRUE(config.collect_socket_buffers);
285 EXPECT_TRUE(config.collect_tcp_states);
286 EXPECT_EQ(config.time_wait_warning_threshold, 10000);
287 EXPECT_EQ(config.close_wait_warning_threshold, 100);
288 EXPECT_EQ(config.queue_full_threshold_bytes, 65536);
289 EXPECT_EQ(config.memory_warning_threshold_bytes, 104857600);
290}
291
292#if defined(__linux__) || defined(__APPLE__)
293// Platform-specific test: On Unix-like systems, monitoring should be available
294TEST_F(NetworkMetricsCollectorTest, UnixNetworkMonitoringAvailable) {
295 bool socket_available = collector_->is_socket_buffer_monitoring_available();
296 bool tcp_available = collector_->is_tcp_state_monitoring_available();
297 // At least one should be available on Unix
298 EXPECT_TRUE(socket_available || tcp_available);
299}
300
301// Platform-specific test: Should have at least some network data
302TEST(NetworkInfoCollectorTest, HasNetworkDataOnUnix) {
303 network_info_collector collector;
304
305 if (!collector.is_socket_buffer_monitoring_available() &&
306 !collector.is_tcp_state_monitoring_available()) {
307 GTEST_SKIP() << "Network monitoring not available";
308 }
309
310 network_metrics_config config;
311 auto metrics = collector.collect_metrics(config);
312
313 // Should have at least some data
314 EXPECT_TRUE(metrics.socket_buffer_available || metrics.tcp_state_available);
315}
316
317// Platform-specific test: TCP connections should have some data
318TEST(NetworkInfoCollectorTest, HasTcpConnectionsOnUnix) {
319 network_info_collector collector;
320
321 if (!collector.is_tcp_state_monitoring_available()) {
322 GTEST_SKIP() << "TCP state monitoring not available";
323 }
324
325 network_metrics_config config;
326 config.collect_socket_buffers = false;
327 config.collect_tcp_states = true;
328 auto metrics = collector.collect_metrics(config);
329
330 EXPECT_TRUE(metrics.tcp_state_available);
331 // Should have at least one listening socket or established connection
332 EXPECT_GT(metrics.total_connections, 0);
333}
334#endif
335
336#if defined(_WIN32)
337// Platform-specific test: On Windows, socket buffer monitoring is not available
338// but TCP state monitoring works via GetExtendedTcpTable()
339TEST_F(NetworkMetricsCollectorTest, WindowsNetworkMonitoringUnavailable) {
340 EXPECT_FALSE(collector_->is_socket_buffer_monitoring_available());
341 EXPECT_TRUE(collector_->is_tcp_state_monitoring_available());
342}
343
344// Platform-specific test: Windows metrics reflect actual API availability
345TEST(NetworkInfoCollectorTest, WindowsReturnsUnavailableMetrics) {
346 network_info_collector collector;
347 network_metrics_config config;
348 auto metrics = collector.collect_metrics(config);
349 // Socket buffers are not available on Windows
350 EXPECT_FALSE(metrics.socket_buffer_available);
351 // TCP states are available via GetExtendedTcpTable()
352 EXPECT_TRUE(metrics.tcp_state_available);
353}
354#endif
355
356} // namespace
357} // namespace monitoring
358} // namespace kcenon
std::string tcp_state_to_string(tcp_state state)
Convert tcp_state to string representation.
@ SYN_SENT
SYN sent, waiting for SYN-ACK.
@ TIME_WAIT
Waiting for enough time to pass (2MSL)
@ UNKNOWN
Unknown or invalid state.
@ ESTABLISHED
Connection established.
@ CLOSE_WAIT
Remote side has closed, waiting for local close.
@ LISTEN
Listening for incoming connections.
Unified network metrics collector for socket buffers and TCP states.
TEST(AdapterFunctionalityTest, WorksWithoutLogger)
Test Scenario 1: Adapter with NULL logger.
TEST_F(AdaptiveMonitoringTest, AdaptiveConfigDefaults)
std::unique_ptr< battery_collector > collector_