5#include <gtest/gtest.h>
14class ProcessMetricsCollectorTest :
public ::testing::Test {
16 void SetUp()
override {
17 collector_ = std::make_unique<process_metrics_collector>();
18 std::unordered_map<std::string, std::string> config;
25TEST_F(ProcessMetricsCollectorTest, InitializesSuccessfully) {
27 EXPECT_EQ(
collector_->name(),
"process_metrics_collector");
30TEST_F(ProcessMetricsCollectorTest, ReturnsCorrectMetricTypes) {
32 EXPECT_FALSE(types.empty());
34 std::vector<std::string> expected = {
35 "process.fd.open_count",
36 "process.fd.usage_percent",
37 "process.fs.inodes_total",
38 "process.fs.inodes_used",
39 "process.context_switches.total",
40 "process.context_switches.voluntary"
43 for (
const auto& expected_type : expected) {
44 EXPECT_NE(std::find(types.begin(), types.end(), expected_type), types.end())
45 <<
"Missing metric type: " << expected_type;
49TEST_F(ProcessMetricsCollectorTest, ConfigurationOptions) {
50 auto collector = std::make_unique<process_metrics_collector>();
51 std::unordered_map<std::string, std::string> config;
52 config[
"fd_warning_threshold"] =
"70.0";
53 config[
"fd_critical_threshold"] =
"90.0";
54 config[
"collect_inodes"] =
"false";
55 EXPECT_TRUE(collector->initialize(config));
57 auto stats = collector->get_statistics();
58 EXPECT_DOUBLE_EQ(stats[
"fd_warning_threshold"], 70.0);
59 EXPECT_DOUBLE_EQ(stats[
"fd_critical_threshold"], 90.0);
60 EXPECT_DOUBLE_EQ(stats[
"collect_inodes"], 0.0);
63TEST_F(ProcessMetricsCollectorTest, CanBeDisabled) {
64 auto collector = std::make_unique<process_metrics_collector>();
65 std::unordered_map<std::string, std::string> config;
66 config[
"enabled"] =
"false";
67 collector->initialize(config);
69 auto metrics = collector->collect();
70 EXPECT_TRUE(metrics.empty());
72 auto stats = collector->get_statistics();
73 EXPECT_DOUBLE_EQ(stats[
"enabled"], 0.0);
76TEST_F(ProcessMetricsCollectorTest, TracksStatistics) {
81 EXPECT_GE(stats[
"collection_count"], 2.0);
82 EXPECT_GE(stats[
"collection_errors"], 0.0);
85TEST_F(ProcessMetricsCollectorTest, CollectReturnsMetrics) {
89TEST_F(ProcessMetricsCollectorTest, GetLastMetrics) {
93 auto now = std::chrono::system_clock::now();
94 auto diff = std::chrono::duration_cast<std::chrono::seconds>(now - last.timestamp);
95 EXPECT_LT(diff.count(), 10);
98TEST_F(ProcessMetricsCollectorTest, MonitoringAvailabilityChecks) {
99 EXPECT_NO_THROW(
collector_->is_fd_monitoring_available());
100 EXPECT_NO_THROW(
collector_->is_inode_monitoring_available());
101 EXPECT_NO_THROW(
collector_->is_context_switch_monitoring_available());
104TEST_F(ProcessMetricsCollectorTest, SelectiveCollectionFdOnly) {
105 auto collector = std::make_unique<process_metrics_collector>();
106 std::unordered_map<std::string, std::string> config;
107 config[
"collect_fd"] =
"true";
108 config[
"collect_inodes"] =
"false";
109 config[
"collect_context_switches"] =
"false";
110 collector->initialize(config);
112 auto types = collector->get_metric_types();
113 bool has_fd_metric =
false;
114 bool has_inode_metric =
false;
115 bool has_cs_metric =
false;
117 for (
const auto& t : types) {
118 if (t.find(
"process.fd.") != std::string::npos) has_fd_metric =
true;
119 if (t.find(
"process.fs.") != std::string::npos) has_inode_metric =
true;
120 if (t.find(
"process.context_switches.") != std::string::npos) has_cs_metric =
true;
123 EXPECT_TRUE(has_fd_metric);
124 EXPECT_FALSE(has_inode_metric);
125 EXPECT_FALSE(has_cs_metric);
128TEST_F(ProcessMetricsCollectorTest, SelectiveCollectionInodesOnly) {
129 auto collector = std::make_unique<process_metrics_collector>();
130 std::unordered_map<std::string, std::string> config;
131 config[
"collect_fd"] =
"false";
132 config[
"collect_inodes"] =
"true";
133 config[
"collect_context_switches"] =
"false";
134 collector->initialize(config);
136 auto types = collector->get_metric_types();
137 bool has_fd_metric =
false;
138 bool has_inode_metric =
false;
139 bool has_cs_metric =
false;
141 for (
const auto& t : types) {
142 if (t.find(
"process.fd.") != std::string::npos) has_fd_metric =
true;
143 if (t.find(
"process.fs.") != std::string::npos) has_inode_metric =
true;
144 if (t.find(
"process.context_switches.") != std::string::npos) has_cs_metric =
true;
147 EXPECT_FALSE(has_fd_metric);
148 EXPECT_TRUE(has_inode_metric);
149 EXPECT_FALSE(has_cs_metric);
152TEST_F(ProcessMetricsCollectorTest, MultipleCollectionsAreStable) {
153 for (
int i = 0; i < 10; ++i) {
155 EXPECT_NO_THROW(
collector_->get_statistics());
159 EXPECT_GE(stats[
"collection_count"], 10.0);
162TEST_F(ProcessMetricsCollectorTest, MetricsHaveCorrectTags) {
165 for (
const auto& m : metrics) {
166 auto it = m.tags.find(
"collector");
167 if (it != m.tags.end()) {
168 EXPECT_EQ(it->second,
"process_metrics_collector");
173TEST_F(ProcessMetricsCollectorTest, IsHealthyReflectsState) {
176 auto disabled_collector = std::make_unique<process_metrics_collector>();
177 std::unordered_map<std::string, std::string> config;
178 config[
"enabled"] =
"false";
179 disabled_collector->initialize(config);
180 EXPECT_TRUE(disabled_collector->is_healthy());
183TEST_F(ProcessMetricsCollectorTest, ConfigConstructor) {
184 process_metrics_config config;
185 config.collect_fd =
true;
186 config.collect_inodes =
false;
187 config.collect_context_switches =
false;
188 config.fd_warning_threshold = 75.0;
190 auto collector = std::make_unique<process_metrics_collector>(config);
191 std::unordered_map<std::string, std::string> init_config;
192 collector->initialize(init_config);
194 auto stats = collector->get_statistics();
195 EXPECT_DOUBLE_EQ(stats[
"collect_fd"], 1.0);
196 EXPECT_DOUBLE_EQ(stats[
"collect_inodes"], 0.0);
197 EXPECT_DOUBLE_EQ(stats[
"collect_context_switches"], 0.0);
198 EXPECT_DOUBLE_EQ(stats[
"fd_warning_threshold"], 75.0);
201TEST(ProcessMetricsStructTest, DefaultInitialization) {
202 process_metrics metrics;
203 EXPECT_EQ(metrics.fd.fd_used_process, 0);
204 EXPECT_EQ(metrics.inodes.total_inodes, 0);
205 EXPECT_EQ(metrics.context_switches.system_context_switches_total, 0);
208TEST(FdInfoCollectorTest, BasicFunctionality) {
209 fd_info_collector collector;
211 EXPECT_NO_THROW(collector.is_fd_monitoring_available());
213 auto metrics = collector.collect_metrics();
215 auto now = std::chrono::system_clock::now();
216 auto diff = std::chrono::duration_cast<std::chrono::seconds>(now - metrics.timestamp);
217 EXPECT_LT(diff.count(), 10);
220TEST(FdInfoCollectorTest, ProcessFDCountChangesWithOpenFiles) {
221 fd_info_collector collector;
223 auto initial = collector.collect_metrics();
225 std::vector<std::unique_ptr<std::fstream>> files;
226 for (
int i = 0; i < 5; ++i) {
227 auto file = std::make_unique<std::fstream>();
228 file->open(
"/dev/null", std::ios::in);
229 if (file->is_open()) {
230 files.push_back(std::move(file));
234 auto after_open = collector.collect_metrics();
238 if (initial.fd_used_process > 0 && after_open.fd_used_process > 0) {
239 EXPECT_GE(after_open.fd_used_process, initial.fd_used_process);
243TEST(InodeInfoCollectorTest, BasicFunctionality) {
244 inode_info_collector collector;
246 EXPECT_NO_THROW(collector.is_inode_monitoring_available());
248 auto metrics = collector.collect_metrics();
250 auto now = std::chrono::system_clock::now();
251 auto diff = std::chrono::duration_cast<std::chrono::seconds>(now - metrics.timestamp);
252 EXPECT_LT(diff.count(), 10);
255TEST(ContextSwitchInfoCollectorTest, BasicFunctionality) {
256 context_switch_info_collector collector;
258 EXPECT_NO_THROW(collector.is_context_switch_monitoring_available());
260 auto metrics = collector.collect_metrics();
262 auto now = std::chrono::system_clock::now();
263 auto diff = std::chrono::duration_cast<std::chrono::seconds>(now - metrics.timestamp);
264 EXPECT_LT(diff.count(), 10);
267#if defined(__linux__) || defined(__APPLE__)
268TEST_F(ProcessMetricsCollectorTest, UnixFdMonitoringAvailable) {
269 EXPECT_TRUE(
collector_->is_fd_monitoring_available());
272TEST_F(ProcessMetricsCollectorTest, UnixInodeMonitoringAvailable) {
273 EXPECT_TRUE(
collector_->is_inode_monitoring_available());
276TEST_F(ProcessMetricsCollectorTest, UnixContextSwitchMonitoringAvailable) {
277 EXPECT_TRUE(
collector_->is_context_switch_monitoring_available());
280TEST(InodeInfoCollectorTest, HasFilesystemsOnUnix) {
281 inode_info_collector collector;
283 if (collector.is_inode_monitoring_available()) {
284 auto metrics = collector.collect_metrics();
285 EXPECT_TRUE(metrics.metrics_available);
286 EXPECT_FALSE(metrics.filesystems.empty());
290TEST(ContextSwitchInfoCollectorTest, ProcessSwitchesNonNegative) {
291 context_switch_info_collector collector;
293 if (collector.is_context_switch_monitoring_available()) {
294 auto metrics = collector.collect_metrics();
295 EXPECT_GE(metrics.process_info.voluntary_switches, 0);
296 EXPECT_GE(metrics.process_info.nonvoluntary_switches, 0);
297 EXPECT_GE(metrics.process_info.total_switches, 0);
303TEST_F(ProcessMetricsCollectorTest, WindowsInodeMonitoringUnavailable) {
304 EXPECT_FALSE(
collector_->is_inode_monitoring_available());
307TEST_F(ProcessMetricsCollectorTest, WindowsContextSwitchMonitoringUnavailable) {
308 EXPECT_FALSE(
collector_->is_context_switch_monitoring_available());
Unified process-level metrics collector.
TEST(AdapterFunctionalityTest, WorksWithoutLogger)
Test Scenario 1: Adapter with NULL logger.
TEST_F(AdaptiveMonitoringTest, AdaptiveConfigDefaults)
std::unique_ptr< battery_collector > collector_