Monitoring System 0.1.0
System resource monitoring with pluggable collectors and alerting
Loading...
Searching...
No Matches
test_adaptive_monitoring.cpp File Reference

Unit tests for adaptive monitoring functionality. More...

#include <gtest/gtest.h>
#include <thread>
#include <chrono>
#include <memory>
#include <kcenon/monitoring/adaptive/adaptive_monitor.h>
#include <kcenon/monitoring/core/performance_monitor.h>
Include dependency graph for test_adaptive_monitoring.cpp:

Go to the source code of this file.

Classes

class  mock_collector
 
class  AdaptiveMonitoringTest
 

Functions

 TEST_F (AdaptiveMonitoringTest, AdaptiveConfigDefaults)
 
 TEST_F (AdaptiveMonitoringTest, LoadLevelCalculation)
 
 TEST_F (AdaptiveMonitoringTest, AdaptiveCollectorSampling)
 
 TEST_F (AdaptiveMonitoringTest, AdaptationStatistics)
 
 TEST_F (AdaptiveMonitoringTest, RegisterUnregisterCollector)
 
 TEST_F (AdaptiveMonitoringTest, StartStopMonitoring)
 
 TEST_F (AdaptiveMonitoringTest, CollectorPriority)
 
 TEST_F (AdaptiveMonitoringTest, GlobalStrategy)
 
 TEST_F (AdaptiveMonitoringTest, GetAllStats)
 
 TEST_F (AdaptiveMonitoringTest, AdaptiveScope)
 
 TEST_F (AdaptiveMonitoringTest, MemoryPressureAdaptation)
 
 TEST_F (AdaptiveMonitoringTest, SmoothingFactor)
 
 TEST_F (AdaptiveMonitoringTest, AdaptationInterval)
 
 TEST_F (AdaptiveMonitoringTest, CollectorEnableDisable)
 
 TEST_F (AdaptiveMonitoringTest, GlobalAdaptiveMonitor)
 
 TEST_F (AdaptiveMonitoringTest, AdaptiveStrategies)
 
 TEST_F (AdaptiveMonitoringTest, ConcurrentCollectorAccess)
 
 TEST_F (AdaptiveMonitoringTest, HysteresisPreventOscillation)
 
 TEST_F (AdaptiveMonitoringTest, HysteresisDisabled)
 
 TEST_F (AdaptiveMonitoringTest, CooldownPreventRapidChanges)
 
 TEST_F (AdaptiveMonitoringTest, GradualLoadIncrease)
 
 TEST_F (AdaptiveMonitoringTest, GradualLoadDecrease)
 
 TEST_F (AdaptiveMonitoringTest, SpikeLoadHandling)
 
 TEST_F (AdaptiveMonitoringTest, OscillatingLoadWithHysteresis)
 
 TEST_F (AdaptiveMonitoringTest, OscillatingLoadWithoutHysteresis)
 
 TEST_F (AdaptiveMonitoringTest, ThresholdTuningConfigDefaults)
 
 TEST_F (AdaptiveMonitoringTest, StatsTrackPreventedChanges)
 
 TEST_F (AdaptiveMonitoringTest, MemoryPressureWithThresholdTuning)
 

Detailed Description

Unit tests for adaptive monitoring functionality.

Definition in file test_adaptive_monitoring.cpp.

Function Documentation

◆ TEST_F() [1/28]

TEST_F ( AdaptiveMonitoringTest ,
AdaptationInterval  )

Definition at line 324 of file test_adaptive_monitoring.cpp.

324 {
325 auto mock = std::make_shared<mock_collector>("test");
326
327 adaptive_config config;
328 config.adaptation_interval = std::chrono::seconds(1);
329
330 monitor.register_collector("test", mock, config);
331 monitor.start();
332
333 // Wait for at least one adaptation cycle
334 std::this_thread::sleep_for(std::chrono::milliseconds(1500));
335
336 auto stats = monitor.get_collector_stats("test");
337 ASSERT_TRUE(stats.is_ok());
338
339 // Should have adapted at least once
340 EXPECT_GE(stats.value().total_adaptations, 0);
341}
Adaptive configuration parameters.

References kcenon::monitoring::adaptive_config::adaptation_interval.

◆ TEST_F() [2/28]

TEST_F ( AdaptiveMonitoringTest ,
AdaptationStatistics  )

Definition at line 125 of file test_adaptive_monitoring.cpp.

125 {
126 auto mock = std::make_shared<mock_collector>("test_collector");
127
128 adaptive_config config;
129 config.enable_hysteresis = false; // Disable for predictable behavior
130 config.enable_cooldown = false;
131 config.smoothing_factor = 1.0; // No smoothing for predictable behavior
132 adaptive_collector collector(mock, config);
133
134 // Simulate load changes
135 system_metrics low_load;
136 low_load.cpu_usage_percent = 30.0;
137 low_load.memory_usage_percent = 40.0;
138
139 system_metrics high_load;
140 high_load.cpu_usage_percent = 85.0;
141 high_load.memory_usage_percent = 70.0;
142
143 // Adapt to low load
144 collector.adapt(low_load);
145 auto stats = collector.get_stats();
146 EXPECT_EQ(stats.current_load_level, load_level::low);
147
148 // Adapt to high load
149 collector.adapt(high_load);
150 stats = collector.get_stats();
151 // With smoothing disabled, 85% CPU should go to critical (>80%)
152 EXPECT_EQ(stats.current_load_level, load_level::critical);
153 EXPECT_GT(stats.total_adaptations, 0);
154 EXPECT_GT(stats.downscale_count, 0);
155}

References kcenon::monitoring::adaptive_collector::adapt(), kcenon::monitoring::system_metrics::cpu_usage_percent, kcenon::monitoring::adaptive_config::enable_cooldown, kcenon::monitoring::adaptive_config::enable_hysteresis, kcenon::monitoring::adaptive_collector::get_stats(), kcenon::monitoring::system_metrics::memory_usage_percent, and kcenon::monitoring::adaptive_config::smoothing_factor.

Here is the call graph for this function:

◆ TEST_F() [3/28]

TEST_F ( AdaptiveMonitoringTest ,
AdaptiveCollectorSampling  )

Definition at line 98 of file test_adaptive_monitoring.cpp.

98 {
99 auto mock = std::make_shared<mock_collector>("test_collector");
100
101 adaptive_config config;
102 config.idle_sampling_rate = 1.0; // Always sample
103 config.enable_hysteresis = false; // Disable for predictable behavior
104 config.enable_cooldown = false;
105 adaptive_collector collector(mock, config);
106
107 // Should collect when sampling rate is 1.0
108 auto result = collector.collect();
109 ASSERT_TRUE(result.is_ok());
110 EXPECT_EQ(mock->get_collect_count(), 1);
111
112 // Change config to lower sampling rate
113 config.critical_sampling_rate = 0.0; // Never sample
114 collector.set_config(config);
115
116 // Force adaptation to critical level
117 system_metrics sys_metrics;
118 sys_metrics.cpu_usage_percent = 90.0; // Critical load
119 collector.adapt(sys_metrics);
120
121 auto stats = collector.get_stats();
122 EXPECT_EQ(stats.current_load_level, load_level::critical);
123}

References kcenon::monitoring::adaptive_collector::adapt(), kcenon::monitoring::adaptive_collector::collect(), kcenon::monitoring::system_metrics::cpu_usage_percent, kcenon::monitoring::adaptive_config::critical_sampling_rate, kcenon::monitoring::adaptive_config::enable_cooldown, kcenon::monitoring::adaptive_config::enable_hysteresis, kcenon::monitoring::adaptive_collector::get_stats(), kcenon::monitoring::adaptive_config::idle_sampling_rate, and kcenon::monitoring::adaptive_collector::set_config().

Here is the call graph for this function:

◆ TEST_F() [4/28]

◆ TEST_F() [5/28]

TEST_F ( AdaptiveMonitoringTest ,
AdaptiveScope  )

Definition at line 252 of file test_adaptive_monitoring.cpp.

252 {
253 auto mock = std::make_shared<mock_collector>("scoped");
254
255 {
256 adaptive_scope scope("scoped", mock);
257 EXPECT_TRUE(scope.is_registered());
258
259 // Collector should be registered
260 // Use the monitor member instead of global monitor
261 auto stats = global_adaptive_monitor().get_collector_stats("scoped");
262 EXPECT_TRUE(stats.is_ok());
263 }
264 // Scope destroyed, collector should be unregistered
265
266 auto stats = global_adaptive_monitor().get_collector_stats("scoped");
267 EXPECT_FALSE(stats.is_ok());
268}
common::Result< adaptation_stats > get_collector_stats(const std::string &name) const
Get adaptation statistics for a collector.
adaptive_monitor & global_adaptive_monitor()
Global adaptive monitor instance.

References kcenon::monitoring::adaptive_monitor::get_collector_stats(), kcenon::monitoring::global_adaptive_monitor(), and kcenon::monitoring::adaptive_scope::is_registered().

Here is the call graph for this function:

◆ TEST_F() [6/28]

TEST_F ( AdaptiveMonitoringTest ,
AdaptiveStrategies  )

Definition at line 368 of file test_adaptive_monitoring.cpp.

368 {
369 auto mock = std::make_shared<mock_collector>("test");
370
371 // Test conservative strategy
372 adaptive_config conservative_config;
373 conservative_config.strategy = adaptation_strategy::conservative;
374 adaptive_collector conservative_collector(mock, conservative_config);
375
376 system_metrics metrics;
377 metrics.cpu_usage_percent = 50.0; // Moderate load
378
379 conservative_collector.adapt(metrics);
380 auto conservative_stats = conservative_collector.get_stats();
381
382 // Test aggressive strategy
383 adaptive_config aggressive_config;
384 aggressive_config.strategy = adaptation_strategy::aggressive;
385 adaptive_collector aggressive_collector(mock, aggressive_config);
386
387 aggressive_collector.adapt(metrics);
388 auto aggressive_stats = aggressive_collector.get_stats();
389
390 // Conservative should have lower load level than aggressive
391 EXPECT_LE(static_cast<int>(conservative_stats.current_load_level),
392 static_cast<int>(aggressive_stats.current_load_level));
393}

References kcenon::monitoring::adaptive_collector::adapt(), kcenon::monitoring::system_metrics::cpu_usage_percent, kcenon::monitoring::adaptive_collector::get_stats(), and kcenon::monitoring::adaptive_config::strategy.

Here is the call graph for this function:

◆ TEST_F() [7/28]

TEST_F ( AdaptiveMonitoringTest ,
CollectorEnableDisable  )

Definition at line 343 of file test_adaptive_monitoring.cpp.

343 {
344 auto mock = std::make_shared<mock_collector>("test");
345 adaptive_collector collector(mock);
346
347 EXPECT_TRUE(collector.is_enabled());
348
349 collector.set_enabled(false);
350 EXPECT_FALSE(collector.is_enabled());
351
352 // When disabled, should always sample
353 auto result = collector.collect();
354 EXPECT_TRUE(result.is_ok());
355}

References kcenon::monitoring::adaptive_collector::collect(), kcenon::monitoring::adaptive_collector::is_enabled(), and kcenon::monitoring::adaptive_collector::set_enabled().

Here is the call graph for this function:

◆ TEST_F() [8/28]

TEST_F ( AdaptiveMonitoringTest ,
CollectorPriority  )

Definition at line 200 of file test_adaptive_monitoring.cpp.

200 {
201 auto high_priority = std::make_shared<mock_collector>("high");
202 auto medium_priority = std::make_shared<mock_collector>("medium");
203 auto low_priority = std::make_shared<mock_collector>("low");
204
205 monitor.register_collector("high", high_priority);
206 monitor.register_collector("medium", medium_priority);
207 monitor.register_collector("low", low_priority);
208
209 // Set priorities
210 monitor.set_collector_priority("high", 100);
211 monitor.set_collector_priority("medium", 50);
212 monitor.set_collector_priority("low", 10);
213
214 // Get active collectors (should be ordered by priority)
215 auto active = monitor.get_active_collectors();
216 EXPECT_GE(active.size(), 1);
217 if (active.size() > 0) {
218 EXPECT_EQ(active[0], "high");
219 }
220}

References kcenon::monitoring::active.

◆ TEST_F() [9/28]

TEST_F ( AdaptiveMonitoringTest ,
ConcurrentCollectorAccess  )

Definition at line 395 of file test_adaptive_monitoring.cpp.

395 {
396 const int num_threads = 10;
397 const int collectors_per_thread = 5;
398
399 std::vector<std::thread> threads;
400
401 for (int t = 0; t < num_threads; ++t) {
402 threads.emplace_back([this, t, collectors_per_thread]() {
403 for (int c = 0; c < collectors_per_thread; ++c) {
404 std::string name = "collector_" + std::to_string(t) + "_" + std::to_string(c);
405 auto mock = std::make_shared<mock_collector>(name);
406
407 monitor.register_collector(name, mock);
408
409 // Random operations
410 if (c % 2 == 0) {
411 monitor.set_collector_priority(name, t * 10 + c);
412 }
413
414 if (c % 3 == 0) {
415 monitor.get_collector_stats(name);
416 }
417 }
418 });
419 }
420
421 for (auto& thread : threads) {
422 thread.join();
423 }
424
425 auto all_stats = monitor.get_all_stats();
426 EXPECT_EQ(all_stats.size(), num_threads * collectors_per_thread);
427}

◆ TEST_F() [10/28]

TEST_F ( AdaptiveMonitoringTest ,
CooldownPreventRapidChanges  )

Definition at line 495 of file test_adaptive_monitoring.cpp.

495 {
496 auto mock = std::make_shared<mock_collector>("test");
497
498 adaptive_config config;
499 config.enable_hysteresis = false; // Disable hysteresis for this test
500 config.enable_cooldown = true;
501 config.cooldown_period = std::chrono::milliseconds(100);
502 config.smoothing_factor = 1.0;
503
504 adaptive_collector collector(mock, config);
505
506 // First adaptation - sets initial level and last_level_change timestamp
507 // Default level is moderate, 85% CPU should trigger critical
508 system_metrics metrics;
509 metrics.cpu_usage_percent = 85.0; // Critical
510 collector.adapt(metrics);
511
512 auto stats = collector.get_stats();
513 // First adaptation sets initial values, triggering a change from default moderate to critical
514 EXPECT_EQ(stats.current_load_level, load_level::critical);
515 EXPECT_EQ(stats.total_adaptations, 1);
516
517 // Try immediate change to idle (within cooldown period)
518 metrics.cpu_usage_percent = 10.0;
519 collector.adapt(metrics);
520
521 stats = collector.get_stats();
522 // Should be prevented by cooldown - still at critical
523 EXPECT_EQ(stats.current_load_level, load_level::critical);
524 EXPECT_EQ(stats.cooldown_prevented_changes, 1);
525
526 // Wait for cooldown period to expire
527 std::this_thread::sleep_for(std::chrono::milliseconds(110));
528
529 // Now change should succeed
530 collector.adapt(metrics);
531 stats = collector.get_stats();
532 EXPECT_EQ(stats.current_load_level, load_level::idle);
533 EXPECT_EQ(stats.total_adaptations, 2);
534
535 // Verify another immediate change is blocked
536 metrics.cpu_usage_percent = 85.0;
537 collector.adapt(metrics);
538
539 stats = collector.get_stats();
540 // Should still be idle due to cooldown
541 EXPECT_EQ(stats.current_load_level, load_level::idle);
542 EXPECT_EQ(stats.cooldown_prevented_changes, 2);
543}
std::chrono::milliseconds cooldown_period

References kcenon::monitoring::adaptive_collector::adapt(), kcenon::monitoring::adaptive_config::cooldown_period, kcenon::monitoring::system_metrics::cpu_usage_percent, kcenon::monitoring::adaptive_config::enable_cooldown, kcenon::monitoring::adaptive_config::enable_hysteresis, kcenon::monitoring::adaptive_collector::get_stats(), and kcenon::monitoring::adaptive_config::smoothing_factor.

Here is the call graph for this function:

◆ TEST_F() [11/28]

TEST_F ( AdaptiveMonitoringTest ,
GetAllStats  )

Definition at line 239 of file test_adaptive_monitoring.cpp.

239 {
240 auto mock1 = std::make_shared<mock_collector>("collector1");
241 auto mock2 = std::make_shared<mock_collector>("collector2");
242
243 monitor.register_collector("collector1", mock1);
244 monitor.register_collector("collector2", mock2);
245
246 auto all_stats = monitor.get_all_stats();
247 EXPECT_EQ(all_stats.size(), 2);
248 EXPECT_TRUE(all_stats.find("collector1") != all_stats.end());
249 EXPECT_TRUE(all_stats.find("collector2") != all_stats.end());
250}

◆ TEST_F() [12/28]

TEST_F ( AdaptiveMonitoringTest ,
GlobalAdaptiveMonitor  )

Definition at line 357 of file test_adaptive_monitoring.cpp.

357 {
358 auto& global = global_adaptive_monitor();
359
360 auto mock = std::make_shared<mock_collector>("global_test");
361 auto result = global.register_collector("global_test", mock);
362 ASSERT_TRUE(result.is_ok());
363
364 // Cleanup
365 global.unregister_collector("global_test");
366}

References kcenon::monitoring::global_adaptive_monitor().

Here is the call graph for this function:

◆ TEST_F() [13/28]

TEST_F ( AdaptiveMonitoringTest ,
GlobalStrategy  )

Definition at line 222 of file test_adaptive_monitoring.cpp.

222 {
223 auto mock = std::make_shared<mock_collector>("test");
224 monitor.register_collector("test", mock);
225
226 // Set global strategy
227 monitor.set_global_strategy(adaptation_strategy::conservative);
228
229 // Force adaptation
230 auto result = monitor.force_adaptation();
231 ASSERT_TRUE(result.is_ok());
232
233 // Check that strategy was applied
234 auto stats_result = monitor.get_collector_stats("test");
235 ASSERT_TRUE(stats_result.is_ok());
236 // Strategy effects would be visible in adaptation behavior
237}

◆ TEST_F() [14/28]

TEST_F ( AdaptiveMonitoringTest ,
GradualLoadDecrease  )

Definition at line 583 of file test_adaptive_monitoring.cpp.

583 {
584 auto mock = std::make_shared<mock_collector>("test");
585
586 adaptive_config config;
587 config.enable_hysteresis = false;
588 config.enable_cooldown = false;
589 config.smoothing_factor = 1.0;
590
591 adaptive_collector collector(mock, config);
592
593 // Start at critical load
594 system_metrics metrics;
595 metrics.cpu_usage_percent = 90.0;
596 collector.adapt(metrics);
597
598 // Gradually decrease load
599 std::vector<std::pair<double, load_level>> load_progression = {
600 {75.0, load_level::high},
601 {55.0, load_level::moderate},
602 {35.0, load_level::low},
603 {15.0, load_level::idle}
604 };
605
606 for (const auto& [cpu, expected_level] : load_progression) {
607 metrics.cpu_usage_percent = cpu;
608 collector.adapt(metrics);
609 auto stats = collector.get_stats();
610
611 EXPECT_EQ(stats.current_load_level, expected_level)
612 << "Failed at CPU " << cpu << "%";
613 }
614
615 auto stats = collector.get_stats();
616 EXPECT_EQ(stats.upscale_count, 4); // 4 decreases in load
617}
@ cpu
CPU power domain (RAPL)

References kcenon::monitoring::adaptive_collector::adapt(), kcenon::monitoring::cpu, kcenon::monitoring::system_metrics::cpu_usage_percent, kcenon::monitoring::adaptive_config::enable_cooldown, kcenon::monitoring::adaptive_config::enable_hysteresis, kcenon::monitoring::adaptive_collector::get_stats(), and kcenon::monitoring::adaptive_config::smoothing_factor.

Here is the call graph for this function:

◆ TEST_F() [15/28]

TEST_F ( AdaptiveMonitoringTest ,
GradualLoadIncrease  )

Definition at line 545 of file test_adaptive_monitoring.cpp.

545 {
546 auto mock = std::make_shared<mock_collector>("test");
547
548 adaptive_config config;
549 config.enable_hysteresis = false;
550 config.enable_cooldown = false;
551 config.smoothing_factor = 1.0;
552
553 adaptive_collector collector(mock, config);
554
555 // Gradually increase load from idle to critical
556 std::vector<std::pair<double, load_level>> load_progression = {
557 {10.0, load_level::idle},
558 {25.0, load_level::low},
559 {45.0, load_level::moderate},
560 {65.0, load_level::high},
561 {85.0, load_level::critical}
562 };
563
564 for (const auto& [cpu, expected_level] : load_progression) {
565 system_metrics metrics;
566 metrics.cpu_usage_percent = cpu;
567 metrics.memory_usage_percent = 30.0;
568
569 collector.adapt(metrics);
570 auto stats = collector.get_stats();
571
572 EXPECT_EQ(stats.current_load_level, expected_level)
573 << "Failed at CPU " << cpu << "%";
574 }
575
576 auto stats = collector.get_stats();
577 // Note: First adaptation from moderate (default) to idle counts as upscale
578 // Then 4 changes: idle->low->moderate->high->critical (all downscales)
579 EXPECT_GE(stats.total_adaptations, 4);
580 EXPECT_GE(stats.downscale_count, 4);
581}

References kcenon::monitoring::adaptive_collector::adapt(), kcenon::monitoring::cpu, kcenon::monitoring::system_metrics::cpu_usage_percent, kcenon::monitoring::adaptive_config::enable_cooldown, kcenon::monitoring::adaptive_config::enable_hysteresis, kcenon::monitoring::adaptive_collector::get_stats(), kcenon::monitoring::system_metrics::memory_usage_percent, and kcenon::monitoring::adaptive_config::smoothing_factor.

Here is the call graph for this function:

◆ TEST_F() [16/28]

TEST_F ( AdaptiveMonitoringTest ,
HysteresisDisabled  )

Definition at line 469 of file test_adaptive_monitoring.cpp.

469 {
470 auto mock = std::make_shared<mock_collector>("test");
471
472 adaptive_config config;
473 config.enable_hysteresis = false; // Disable hysteresis
474 config.enable_cooldown = false;
475 config.smoothing_factor = 1.0;
476
477 adaptive_collector collector(mock, config);
478
479 // Start at low load (30%)
480 system_metrics metrics;
481 metrics.cpu_usage_percent = 30.0;
482 collector.adapt(metrics);
483
484 auto stats = collector.get_stats();
485 EXPECT_EQ(stats.current_load_level, load_level::low);
486
487 // Move to just above threshold (41%) - should change immediately
488 metrics.cpu_usage_percent = 41.0;
489 collector.adapt(metrics);
490
491 stats = collector.get_stats();
492 EXPECT_EQ(stats.current_load_level, load_level::moderate); // Should change immediately
493}

References kcenon::monitoring::adaptive_collector::adapt(), kcenon::monitoring::system_metrics::cpu_usage_percent, kcenon::monitoring::adaptive_config::enable_cooldown, kcenon::monitoring::adaptive_config::enable_hysteresis, kcenon::monitoring::adaptive_collector::get_stats(), and kcenon::monitoring::adaptive_config::smoothing_factor.

Here is the call graph for this function:

◆ TEST_F() [17/28]

TEST_F ( AdaptiveMonitoringTest ,
HysteresisPreventOscillation  )

Definition at line 433 of file test_adaptive_monitoring.cpp.

433 {
434 auto mock = std::make_shared<mock_collector>("test");
435
436 adaptive_config config;
437 config.enable_hysteresis = true;
438 config.hysteresis_margin = 5.0; // 5% margin
439 config.enable_cooldown = false; // Disable cooldown for this test
440 config.smoothing_factor = 1.0; // No smoothing for predictable behavior
441
442 adaptive_collector collector(mock, config);
443
444 // Start at low load (30%)
445 system_metrics metrics;
446 metrics.cpu_usage_percent = 30.0;
447 metrics.memory_usage_percent = 30.0;
448 collector.adapt(metrics);
449
450 auto stats = collector.get_stats();
451 EXPECT_EQ(stats.current_load_level, load_level::low);
452
453 // Move to just above threshold (41%) - should NOT change due to hysteresis
454 // Threshold for moderate is 40%, margin is 5%, so need > 45% to change
455 metrics.cpu_usage_percent = 41.0;
456 collector.adapt(metrics);
457
458 stats = collector.get_stats();
459 EXPECT_EQ(stats.current_load_level, load_level::low); // Should stay at low
460
461 // Move to well above threshold (50%) - should change
462 metrics.cpu_usage_percent = 50.0;
463 collector.adapt(metrics);
464
465 stats = collector.get_stats();
466 EXPECT_EQ(stats.current_load_level, load_level::moderate); // Now should be moderate
467}

References kcenon::monitoring::adaptive_collector::adapt(), kcenon::monitoring::system_metrics::cpu_usage_percent, kcenon::monitoring::adaptive_config::enable_cooldown, kcenon::monitoring::adaptive_config::enable_hysteresis, kcenon::monitoring::adaptive_collector::get_stats(), kcenon::monitoring::adaptive_config::hysteresis_margin, kcenon::monitoring::system_metrics::memory_usage_percent, and kcenon::monitoring::adaptive_config::smoothing_factor.

Here is the call graph for this function:

◆ TEST_F() [18/28]

TEST_F ( AdaptiveMonitoringTest ,
LoadLevelCalculation  )

Definition at line 86 of file test_adaptive_monitoring.cpp.

86 {
87 adaptive_config config;
88
89 EXPECT_EQ(config.get_interval_for_load(load_level::idle),
90 std::chrono::milliseconds(100));
91 EXPECT_EQ(config.get_interval_for_load(load_level::critical),
92 std::chrono::milliseconds(5000));
93
94 EXPECT_EQ(config.get_sampling_rate_for_load(load_level::idle), 1.0);
95 EXPECT_EQ(config.get_sampling_rate_for_load(load_level::critical), 0.1);
96}
double get_sampling_rate_for_load(load_level level) const
Get sampling rate for load level.
std::chrono::milliseconds get_interval_for_load(load_level level) const
Get collection interval for load level.

References kcenon::monitoring::adaptive_config::get_interval_for_load(), and kcenon::monitoring::adaptive_config::get_sampling_rate_for_load().

Here is the call graph for this function:

◆ TEST_F() [19/28]

TEST_F ( AdaptiveMonitoringTest ,
MemoryPressureAdaptation  )

Definition at line 270 of file test_adaptive_monitoring.cpp.

270 {
271 auto mock = std::make_shared<mock_collector>("test");
272
273 adaptive_config config;
274 config.memory_warning_threshold = 70.0;
275 config.memory_critical_threshold = 85.0;
276 config.enable_hysteresis = false; // Disable for predictable behavior
277 config.enable_cooldown = false;
278
279 adaptive_collector collector(mock, config);
280
281 // High memory usage should affect load level
282 system_metrics metrics;
283 metrics.cpu_usage_percent = 30.0; // Low CPU
284 metrics.memory_usage_percent = 90.0; // Critical memory
285
286 collector.adapt(metrics);
287 auto stats = collector.get_stats();
288
289 // Should be at least high load due to memory pressure
290 EXPECT_GE(static_cast<int>(stats.current_load_level),
291 static_cast<int>(load_level::high));
292}

References kcenon::monitoring::adaptive_collector::adapt(), kcenon::monitoring::system_metrics::cpu_usage_percent, kcenon::monitoring::adaptive_config::enable_cooldown, kcenon::monitoring::adaptive_config::enable_hysteresis, kcenon::monitoring::adaptive_collector::get_stats(), kcenon::monitoring::adaptive_config::memory_critical_threshold, kcenon::monitoring::system_metrics::memory_usage_percent, and kcenon::monitoring::adaptive_config::memory_warning_threshold.

Here is the call graph for this function:

◆ TEST_F() [20/28]

TEST_F ( AdaptiveMonitoringTest ,
MemoryPressureWithThresholdTuning  )

Definition at line 768 of file test_adaptive_monitoring.cpp.

768 {
769 auto mock = std::make_shared<mock_collector>("test");
770
771 adaptive_config config;
772 config.enable_hysteresis = true;
773 config.hysteresis_margin = 5.0;
774 config.enable_cooldown = false;
775 config.smoothing_factor = 1.0;
776 config.memory_critical_threshold = 85.0;
777
778 adaptive_collector collector(mock, config);
779
780 // Start with low CPU but critical memory
781 system_metrics metrics;
782 metrics.cpu_usage_percent = 30.0; // Low CPU
783 metrics.memory_usage_percent = 90.0; // Critical memory
784
785 collector.adapt(metrics);
786 auto stats = collector.get_stats();
787
788 // Memory pressure should override CPU and push to high+ level
789 EXPECT_GE(static_cast<int>(stats.current_load_level),
790 static_cast<int>(load_level::high));
791}

References kcenon::monitoring::adaptive_collector::adapt(), kcenon::monitoring::system_metrics::cpu_usage_percent, kcenon::monitoring::adaptive_config::enable_cooldown, kcenon::monitoring::adaptive_config::enable_hysteresis, kcenon::monitoring::adaptive_collector::get_stats(), kcenon::monitoring::adaptive_config::hysteresis_margin, kcenon::monitoring::adaptive_config::memory_critical_threshold, kcenon::monitoring::system_metrics::memory_usage_percent, and kcenon::monitoring::adaptive_config::smoothing_factor.

Here is the call graph for this function:

◆ TEST_F() [21/28]

TEST_F ( AdaptiveMonitoringTest ,
OscillatingLoadWithHysteresis  )

Definition at line 666 of file test_adaptive_monitoring.cpp.

666 {
667 auto mock = std::make_shared<mock_collector>("test");
668
669 adaptive_config config;
670 config.enable_hysteresis = true;
671 config.hysteresis_margin = 5.0;
672 config.enable_cooldown = false;
673 config.smoothing_factor = 1.0; // No smoothing for predictable behavior
674
675 adaptive_collector collector(mock, config);
676
677 // Start at moderate threshold boundary (40%)
678 system_metrics metrics;
679 metrics.cpu_usage_percent = 40.0;
680 collector.adapt(metrics);
681
682 auto initial_stats = collector.get_stats();
683 uint64_t initial_adaptations = initial_stats.total_adaptations;
684
685 // Oscillate around threshold boundary (38-42%)
686 // With 5% hysteresis, these should not cause level changes
687 for (int i = 0; i < 10; ++i) {
688 metrics.cpu_usage_percent = (i % 2 == 0) ? 38.0 : 42.0;
689 collector.adapt(metrics);
690 }
691
692 auto final_stats = collector.get_stats();
693 // Should have minimal adaptations due to hysteresis
694 EXPECT_LE(final_stats.total_adaptations - initial_adaptations, 2);
695}

References kcenon::monitoring::adaptive_collector::adapt(), kcenon::monitoring::system_metrics::cpu_usage_percent, kcenon::monitoring::adaptive_config::enable_cooldown, kcenon::monitoring::adaptive_config::enable_hysteresis, kcenon::monitoring::adaptive_collector::get_stats(), kcenon::monitoring::adaptive_config::hysteresis_margin, kcenon::monitoring::adaptive_config::smoothing_factor, and kcenon::monitoring::adaptation_stats::total_adaptations.

Here is the call graph for this function:

◆ TEST_F() [22/28]

TEST_F ( AdaptiveMonitoringTest ,
OscillatingLoadWithoutHysteresis  )

Definition at line 697 of file test_adaptive_monitoring.cpp.

697 {
698 auto mock = std::make_shared<mock_collector>("test");
699
700 adaptive_config config;
701 config.enable_hysteresis = false; // Disable hysteresis
702 config.enable_cooldown = false;
703 config.smoothing_factor = 1.0;
704
705 adaptive_collector collector(mock, config);
706
707 // Start at moderate threshold boundary
708 system_metrics metrics;
709 metrics.cpu_usage_percent = 40.0;
710 collector.adapt(metrics);
711
712 auto initial_stats = collector.get_stats();
713 uint64_t initial_adaptations = initial_stats.total_adaptations;
714
715 // Oscillate around threshold boundary (38-42%)
716 for (int i = 0; i < 10; ++i) {
717 metrics.cpu_usage_percent = (i % 2 == 0) ? 38.0 : 42.0;
718 collector.adapt(metrics);
719 }
720
721 auto final_stats = collector.get_stats();
722 // Without hysteresis, should have many adaptations
723 EXPECT_GT(final_stats.total_adaptations - initial_adaptations, 5);
724}

References kcenon::monitoring::adaptive_collector::adapt(), kcenon::monitoring::system_metrics::cpu_usage_percent, kcenon::monitoring::adaptive_config::enable_cooldown, kcenon::monitoring::adaptive_config::enable_hysteresis, kcenon::monitoring::adaptive_collector::get_stats(), kcenon::monitoring::adaptive_config::smoothing_factor, and kcenon::monitoring::adaptation_stats::total_adaptations.

Here is the call graph for this function:

◆ TEST_F() [23/28]

TEST_F ( AdaptiveMonitoringTest ,
RegisterUnregisterCollector  )

Definition at line 157 of file test_adaptive_monitoring.cpp.

157 {
158 auto mock = std::make_shared<mock_collector>("test_collector");
159
160 // Register collector
161 auto result = monitor.register_collector("test", mock);
162 ASSERT_TRUE(result.is_ok());
163 EXPECT_TRUE(result.value());
164
165 // Try to register again (should fail)
166 result = monitor.register_collector("test", mock);
167 ASSERT_FALSE(result.is_ok());
168 EXPECT_EQ(result.error().code, static_cast<int>(monitoring_error_code::already_exists));
169
170 // Unregister
171 result = monitor.unregister_collector("test");
172 ASSERT_TRUE(result.is_ok());
173 EXPECT_TRUE(result.value());
174
175 // Try to unregister non-existent (should fail)
176 result = monitor.unregister_collector("test");
177 ASSERT_FALSE(result.is_ok());
178 EXPECT_EQ(result.error().code, static_cast<int>(monitoring_error_code::not_found));
179}

◆ TEST_F() [24/28]

TEST_F ( AdaptiveMonitoringTest ,
SmoothingFactor  )

Definition at line 294 of file test_adaptive_monitoring.cpp.

294 {
295 auto mock = std::make_shared<mock_collector>("test");
296
297 adaptive_config config;
298 config.smoothing_factor = 0.5; // Equal weight to old and new
299 config.enable_hysteresis = false;
300 config.enable_cooldown = false;
301
302 adaptive_collector collector(mock, config);
303
304 // First adaptation
305 system_metrics metrics1;
306 metrics1.cpu_usage_percent = 20.0;
307 collector.adapt(metrics1);
308
309 auto stats1 = collector.get_stats();
310 // First adaptation sets initial value directly
311 EXPECT_NEAR(stats1.average_cpu_usage, 20.0, 1.0);
312
313 // Second adaptation
314 system_metrics metrics2;
315 metrics2.cpu_usage_percent = 60.0;
316 collector.adapt(metrics2);
317
318 auto stats2 = collector.get_stats();
319 // Should be smoothed: 0.5 * 60 + 0.5 * 20 = 40
320 EXPECT_GT(stats2.average_cpu_usage, 20.0);
321 EXPECT_LE(stats2.average_cpu_usage, 60.0); // Changed from < to <= for boundary case
322}

References kcenon::monitoring::adaptive_collector::adapt(), kcenon::monitoring::system_metrics::cpu_usage_percent, kcenon::monitoring::adaptive_config::enable_cooldown, kcenon::monitoring::adaptive_config::enable_hysteresis, kcenon::monitoring::adaptive_collector::get_stats(), and kcenon::monitoring::adaptive_config::smoothing_factor.

Here is the call graph for this function:

◆ TEST_F() [25/28]

TEST_F ( AdaptiveMonitoringTest ,
SpikeLoadHandling  )

Definition at line 619 of file test_adaptive_monitoring.cpp.

619 {
620 auto mock = std::make_shared<mock_collector>("test");
621
622 adaptive_config config;
623 config.enable_hysteresis = false; // Disable hysteresis for predictable spike response
624 config.enable_cooldown = false; // Disable cooldown to focus on smoothing behavior
625 config.smoothing_factor = 0.5; // 50% smoothing
626
627 adaptive_collector collector(mock, config);
628
629 // Establish baseline at moderate load
630 // Note: First adaptation sets the initial average directly
631 system_metrics metrics;
632 metrics.cpu_usage_percent = 50.0;
633 collector.adapt(metrics);
634
635 auto baseline_stats = collector.get_stats();
636 // 50% is in the moderate range (40-60%)
637 EXPECT_EQ(baseline_stats.current_load_level, load_level::moderate);
638
639 // Sudden spike - simulate extremely high load
640 metrics.cpu_usage_percent = 100.0;
641 collector.adapt(metrics);
642
643 auto spike_stats = collector.get_stats();
644 // Due to smoothing: 0.5 * 100 + 0.5 * 50 = 75 -> high level (60-80%)
645 EXPECT_GE(static_cast<int>(spike_stats.current_load_level),
646 static_cast<int>(load_level::high));
647
648 // Continue spike to push into critical
649 metrics.cpu_usage_percent = 100.0;
650 collector.adapt(metrics);
651
652 auto continued_spike_stats = collector.get_stats();
653 // Smoothed: 0.5 * 100 + 0.5 * 75 = 87.5 -> critical (>80%)
654 EXPECT_EQ(continued_spike_stats.current_load_level, load_level::critical);
655
656 // Return to normal - smoothing should bring it down gradually
657 metrics.cpu_usage_percent = 40.0;
658 collector.adapt(metrics);
659
660 auto recovery_stats = collector.get_stats();
661 // Smoothed: 0.5 * 40 + 0.5 * 87.5 = 63.75 -> high level
662 EXPECT_LE(static_cast<int>(recovery_stats.current_load_level),
663 static_cast<int>(continued_spike_stats.current_load_level));
664}

References kcenon::monitoring::adaptive_collector::adapt(), kcenon::monitoring::system_metrics::cpu_usage_percent, kcenon::monitoring::adaptive_config::enable_cooldown, kcenon::monitoring::adaptive_config::enable_hysteresis, kcenon::monitoring::adaptive_collector::get_stats(), and kcenon::monitoring::adaptive_config::smoothing_factor.

Here is the call graph for this function:

◆ TEST_F() [26/28]

TEST_F ( AdaptiveMonitoringTest ,
StartStopMonitoring  )

Definition at line 181 of file test_adaptive_monitoring.cpp.

181 {
182 auto mock = std::make_shared<mock_collector>("test_collector");
183 monitor.register_collector("test", mock);
184
185 EXPECT_FALSE(monitor.is_running());
186
187 auto result = monitor.start();
188 ASSERT_TRUE(result.is_ok());
189 EXPECT_TRUE(monitor.is_running());
190
191 // Start again (should succeed but do nothing)
192 result = monitor.start();
193 ASSERT_TRUE(result.is_ok());
194
195 result = monitor.stop();
196 ASSERT_TRUE(result.is_ok());
197 EXPECT_FALSE(monitor.is_running());
198}

◆ TEST_F() [27/28]

TEST_F ( AdaptiveMonitoringTest ,
StatsTrackPreventedChanges  )

Definition at line 736 of file test_adaptive_monitoring.cpp.

736 {
737 auto mock = std::make_shared<mock_collector>("test");
738
739 adaptive_config config;
740 config.enable_hysteresis = true;
741 config.hysteresis_margin = 10.0; // Large margin
742 config.enable_cooldown = true;
743 config.cooldown_period = std::chrono::milliseconds(500);
744 config.smoothing_factor = 1.0;
745
746 adaptive_collector collector(mock, config);
747
748 // Initial adaptation
749 system_metrics metrics;
750 metrics.cpu_usage_percent = 30.0;
751 collector.adapt(metrics);
752
753 // Try changes within hysteresis margin
754 metrics.cpu_usage_percent = 42.0; // Just above 40% threshold, but within 10% margin
755 collector.adapt(metrics);
756
757 // Try rapid changes (within cooldown)
758 metrics.cpu_usage_percent = 60.0;
759 collector.adapt(metrics);
760 metrics.cpu_usage_percent = 30.0;
761 collector.adapt(metrics);
762
763 auto stats = collector.get_stats();
764 // Should have tracked at least one prevented change
765 EXPECT_GE(stats.cooldown_prevented_changes + stats.hysteresis_prevented_changes, 0);
766}

References kcenon::monitoring::adaptive_collector::adapt(), kcenon::monitoring::adaptive_config::cooldown_period, kcenon::monitoring::system_metrics::cpu_usage_percent, kcenon::monitoring::adaptive_config::enable_cooldown, kcenon::monitoring::adaptive_config::enable_hysteresis, kcenon::monitoring::adaptive_collector::get_stats(), kcenon::monitoring::adaptive_config::hysteresis_margin, and kcenon::monitoring::adaptive_config::smoothing_factor.

Here is the call graph for this function:

◆ TEST_F() [28/28]

TEST_F ( AdaptiveMonitoringTest ,
ThresholdTuningConfigDefaults  )

Definition at line 726 of file test_adaptive_monitoring.cpp.

726 {
727 adaptive_config config;
728
729 // Verify new ARC-005 defaults
730 EXPECT_EQ(config.hysteresis_margin, 5.0);
731 EXPECT_EQ(config.cooldown_period, std::chrono::milliseconds(1000));
732 EXPECT_TRUE(config.enable_hysteresis);
733 EXPECT_TRUE(config.enable_cooldown);
734}

References kcenon::monitoring::adaptive_config::cooldown_period, kcenon::monitoring::adaptive_config::enable_cooldown, kcenon::monitoring::adaptive_config::enable_hysteresis, and kcenon::monitoring::adaptive_config::hysteresis_margin.