Monitoring System 0.1.0
System resource monitoring with pluggable collectors and alerting
Loading...
Searching...
No Matches
test_smart_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 SMART collector tests
13class SmartCollectorTest : public ::testing::Test {
14 protected:
15 void SetUp() override {
16 collector_ = std::make_unique<smart_collector>();
17 std::unordered_map<std::string, std::string> config;
18 collector_->initialize(config);
19 }
20
21 std::unique_ptr<smart_collector> collector_;
22};
23
24// Test basic initialization
25TEST_F(SmartCollectorTest, InitializesSuccessfully) {
26 EXPECT_TRUE(collector_->is_healthy());
27 EXPECT_EQ(collector_->name(), "smart_collector");
28}
29
30// Test metric types returned
31TEST_F(SmartCollectorTest, ReturnsCorrectMetricTypes) {
32 auto metric_types = collector_->get_metric_types();
33
34 // Should include all expected SMART metrics
35 EXPECT_FALSE(metric_types.empty());
36
37 // Check for expected metric types
38 auto contains = [&metric_types](const std::string& type) {
39 return std::find(metric_types.begin(), metric_types.end(), type) != metric_types.end();
40 };
41
42 EXPECT_TRUE(contains("smart_health_ok"));
43 EXPECT_TRUE(contains("smart_temperature_celsius"));
44 EXPECT_TRUE(contains("smart_reallocated_sectors"));
45 EXPECT_TRUE(contains("smart_power_on_hours"));
46 EXPECT_TRUE(contains("smart_power_cycle_count"));
47 EXPECT_TRUE(contains("smart_pending_sectors"));
48 EXPECT_TRUE(contains("smart_uncorrectable_errors"));
49}
50
51// Test configuration options
52TEST_F(SmartCollectorTest, ConfigurationOptions) {
53 auto custom_collector = std::make_unique<smart_collector>();
54
55 std::unordered_map<std::string, std::string> config = {
56 {"enabled", "true"}, {"collect_temperature", "true"}, {"collect_error_rates", "true"}};
57
58 EXPECT_TRUE(custom_collector->initialize(config));
59 EXPECT_TRUE(custom_collector->is_healthy());
60}
61
62// Test disable collector
63TEST_F(SmartCollectorTest, CanBeDisabled) {
64 auto custom_collector = std::make_unique<smart_collector>();
65
66 std::unordered_map<std::string, std::string> config = {{"enabled", "false"}};
67
68 custom_collector->initialize(config);
69
70 // When disabled, collect should return empty
71 auto metrics = custom_collector->collect();
72 EXPECT_TRUE(metrics.empty());
73}
74
75// Test statistics
76TEST_F(SmartCollectorTest, TracksStatistics) {
77 auto stats = collector_->get_statistics();
78
79 // Should have expected statistics keys
80 EXPECT_TRUE(stats.find("collection_count") != stats.end());
81 EXPECT_TRUE(stats.find("collection_errors") != stats.end());
82 EXPECT_TRUE(stats.find("disks_found") != stats.end());
83
84 // Initial values should be 0
85 EXPECT_EQ(stats["collection_count"], 0.0);
86 EXPECT_EQ(stats["collection_errors"], 0.0);
87}
88
89// Test collect returns metrics (graceful degradation without smartctl)
90TEST_F(SmartCollectorTest, CollectReturnsMetrics) {
91 auto metrics = collector_->collect();
92
93 // This may return empty metrics if smartctl is not available
94 // This is expected behavior - graceful degradation
95 auto stats = collector_->get_statistics();
96 EXPECT_GE(stats["collection_count"], 0.0);
97}
98
99// Test get_last_metrics
100TEST_F(SmartCollectorTest, GetLastMetrics) {
101 collector_->collect();
102 auto last_metrics = collector_->get_last_metrics();
103
104 // Should return vector (may be empty if smartctl not available)
105 // No assertion - just verify it doesn't crash
106 (void)last_metrics;
107}
108
109// Test is_smart_available
110TEST_F(SmartCollectorTest, SmartAvailabilityCheck) {
111 // Should not crash - returns true/false based on smartctl availability
112 bool available = collector_->is_smart_available();
113 (void)available; // Use the variable to avoid warning
114}
115
116// Test smart_disk_metrics structure
117TEST(SmartDiskMetricsTest, DefaultInitialization) {
118 smart_disk_metrics metrics;
119
120 EXPECT_TRUE(metrics.device_path.empty());
121 EXPECT_TRUE(metrics.model_name.empty());
122 EXPECT_TRUE(metrics.serial_number.empty());
123 EXPECT_FALSE(metrics.smart_supported);
124 EXPECT_FALSE(metrics.smart_enabled);
125 EXPECT_TRUE(metrics.health_ok); // Default to healthy
126 EXPECT_EQ(metrics.temperature_celsius, 0.0);
127 EXPECT_EQ(metrics.reallocated_sectors, 0);
128 EXPECT_EQ(metrics.power_on_hours, 0);
129 EXPECT_EQ(metrics.power_cycle_count, 0);
130 EXPECT_EQ(metrics.pending_sectors, 0);
131 EXPECT_EQ(metrics.uncorrectable_errors, 0);
132}
133
134// Test disk_info structure
135TEST(DiskInfoTest, DefaultInitialization) {
136 disk_info info;
137
138 EXPECT_TRUE(info.device_path.empty());
139 EXPECT_TRUE(info.device_type.empty());
140 EXPECT_FALSE(info.smart_available);
141}
142
143// Test smart_info_collector platform detection
144TEST(SmartInfoCollectorTest, BasicFunctionality) {
145 smart_info_collector collector;
146
147 // Test smartctl availability check (should not crash)
148 bool available = collector.is_smartctl_available();
149
150 // If smartctl is not available, enumerate_disks should still work
151 if (!available) {
152 auto disks = collector.enumerate_disks();
153 EXPECT_TRUE(disks.empty()); // No disks without smartctl
154 } else {
155 // If smartctl is available, we might get some disks
156 auto disks = collector.enumerate_disks();
157 // Just verify it doesn't crash - actual disk count depends on system
158 (void)disks;
159 }
160}
161
162// Test disk enumeration (graceful degradation)
163TEST(SmartInfoCollectorTest, EnumerateDisks) {
164 smart_info_collector collector;
165
166 auto disks = collector.enumerate_disks();
167
168 // Should return a vector (may be empty if smartctl not available)
169 // No assertion on size - just verify it doesn't crash
170 (void)disks;
171}
172
173// Test metric collection for non-existent disk
174TEST(SmartInfoCollectorTest, CollectMetricsNonExistentDisk) {
175 smart_info_collector collector;
176
177 disk_info fake_disk;
178 fake_disk.device_path = "/dev/nonexistent_disk_xyz";
179 fake_disk.device_type = "auto";
180 fake_disk.smart_available = false;
181
182 // Should not crash, just return empty/default metrics
183 auto metrics = collector.collect_smart_metrics(fake_disk);
184
185 EXPECT_EQ(metrics.device_path, "/dev/nonexistent_disk_xyz");
186 // SMART should not be "supported" for a non-existent disk
187 EXPECT_FALSE(metrics.smart_supported);
188}
189
190// Test multiple collections don't cause issues
191TEST_F(SmartCollectorTest, MultipleCollectionsAreStable) {
192 for (int i = 0; i < 5; ++i) {
193 auto metrics = collector_->collect();
194 // Should not crash on repeated calls
195 (void)metrics;
196 }
197
198 auto stats = collector_->get_statistics();
199 EXPECT_GE(stats["collection_count"], 5.0);
200 EXPECT_EQ(stats["collection_errors"], 0.0);
201}
202
203} // namespace
204} // namespace monitoring
205} // namespace kcenon
@ info
Informational, no action required.
S.M.A.R.T. disk health monitoring collector.
TEST(AdapterFunctionalityTest, WorksWithoutLogger)
Test Scenario 1: Adapter with NULL logger.
TEST_F(AdaptiveMonitoringTest, AdaptiveConfigDefaults)
std::unique_ptr< battery_collector > collector_