Monitoring System 0.1.0
System resource monitoring with pluggable collectors and alerting
Loading...
Searching...
No Matches
test_alert_manager.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
22#include <gtest/gtest.h>
25
26#include <atomic>
27#include <chrono>
28#include <memory>
29#include <mutex>
30#include <string>
31#include <thread>
32#include <vector>
33
34using namespace kcenon::monitoring;
35using namespace std::chrono_literals;
36
37// =============================================================================
38// alert_manager_config Tests
39// =============================================================================
40
41TEST(AlertManagerConfigTest, DefaultConfigIsValid) {
43 EXPECT_TRUE(config.validate());
44}
45
46TEST(AlertManagerConfigTest, ZeroEvaluationIntervalInvalid) {
48 config.default_evaluation_interval = 0ms;
49 EXPECT_FALSE(config.validate());
50}
51
52TEST(AlertManagerConfigTest, ZeroRepeatIntervalInvalid) {
54 config.default_repeat_interval = 0ms;
55 EXPECT_FALSE(config.validate());
56}
57
58TEST(AlertManagerConfigTest, ZeroMaxAlertsInvalid) {
60 config.max_alerts_per_rule = 0;
61 EXPECT_FALSE(config.validate());
62}
63
64TEST(AlertManagerConfigTest, ZeroMaxSilencesInvalid) {
66 config.max_silences = 0;
67 EXPECT_FALSE(config.validate());
68}
69
70// =============================================================================
71// alert_manager_metrics Tests
72// =============================================================================
73
74TEST(AlertManagerMetricsTest, DefaultZero) {
76 EXPECT_EQ(metrics.rules_evaluated.load(), 0u);
77 EXPECT_EQ(metrics.alerts_created.load(), 0u);
78 EXPECT_EQ(metrics.alerts_resolved.load(), 0u);
79 EXPECT_EQ(metrics.alerts_suppressed.load(), 0u);
80 EXPECT_EQ(metrics.notifications_sent.load(), 0u);
81 EXPECT_EQ(metrics.notifications_failed.load(), 0u);
82}
83
84TEST(AlertManagerMetricsTest, CopyConstructor) {
85 alert_manager_metrics original;
86 original.rules_evaluated = 10;
87 original.alerts_created = 5;
88
89 alert_manager_metrics copy(original);
90 EXPECT_EQ(copy.rules_evaluated.load(), 10u);
91 EXPECT_EQ(copy.alerts_created.load(), 5u);
92}
93
94// =============================================================================
95// Lifecycle Tests
96// =============================================================================
97
98class AlertManagerLifecycleTest : public ::testing::Test {
99protected:
101
102 void SetUp() override {
104 }
105};
106
107TEST_F(AlertManagerLifecycleTest, DefaultConstruction) {
108 alert_manager manager;
109 EXPECT_FALSE(manager.is_running());
110}
111
112TEST_F(AlertManagerLifecycleTest, ConstructWithConfig) {
113 alert_manager manager(config_);
114 EXPECT_FALSE(manager.is_running());
115 EXPECT_EQ(manager.config().default_evaluation_interval, 100ms);
116}
117
119 alert_manager manager(config_);
120 auto start_result = manager.start();
121 EXPECT_TRUE(start_result.is_ok());
122 EXPECT_TRUE(manager.is_running());
123
124 auto stop_result = manager.stop();
125 EXPECT_TRUE(stop_result.is_ok());
126 EXPECT_FALSE(manager.is_running());
127}
128
130 alert_manager manager(config_);
131 EXPECT_TRUE(manager.start().is_ok());
132 EXPECT_FALSE(manager.start().is_ok());
133 manager.stop();
134}
135
136TEST_F(AlertManagerLifecycleTest, StopWithoutStartIsOk) {
137 alert_manager manager(config_);
138 auto result = manager.stop();
139 EXPECT_TRUE(result.is_ok());
140}
141
142TEST_F(AlertManagerLifecycleTest, DestructorStopsManager) {
143 {
144 alert_manager manager(config_);
145 manager.start();
146 EXPECT_TRUE(manager.is_running());
147 }
148 // Destructor should cleanly stop without crash
149 SUCCEED();
150}
151
152// =============================================================================
153// Rule Management Tests
154// =============================================================================
155
156class AlertManagerRuleTest : public ::testing::Test {
157protected:
159
160 std::shared_ptr<alert_rule> create_rule(const std::string& name,
161 const std::string& metric = "cpu_usage") {
162 auto rule = std::make_shared<alert_rule>(name);
163 rule->set_metric_name(metric)
164 .set_severity(alert_severity::critical)
165 .set_trigger(threshold_trigger::above(80.0))
166 .set_summary("Test rule: " + name);
167 return rule;
168 }
169};
170
172 auto rule = create_rule("test_rule");
173 auto result = manager_.add_rule(rule);
174 EXPECT_TRUE(result.is_ok());
175}
176
177TEST_F(AlertManagerRuleTest, AddNullRuleFails) {
178 auto result = manager_.add_rule(nullptr);
179 EXPECT_FALSE(result.is_ok());
180}
181
182TEST_F(AlertManagerRuleTest, GetExistingRule) {
183 auto rule = create_rule("get_test");
184 manager_.add_rule(rule);
185
186 auto retrieved = manager_.get_rule("get_test");
187 ASSERT_NE(retrieved, nullptr);
188 EXPECT_EQ(retrieved->name(), "get_test");
189}
190
191TEST_F(AlertManagerRuleTest, GetNonexistentRuleReturnsNull) {
192 auto retrieved = manager_.get_rule("missing");
193 EXPECT_EQ(retrieved, nullptr);
194}
195
196TEST_F(AlertManagerRuleTest, RemoveExistingRule) {
197 manager_.add_rule(create_rule("to_remove"));
198 auto result = manager_.remove_rule("to_remove");
199 EXPECT_TRUE(result.is_ok());
200 EXPECT_EQ(manager_.get_rule("to_remove"), nullptr);
201}
202
203TEST_F(AlertManagerRuleTest, RemoveNonexistentRuleFails) {
204 auto result = manager_.remove_rule("missing");
205 EXPECT_FALSE(result.is_ok());
206}
207
209 manager_.add_rule(create_rule("rule1"));
210 manager_.add_rule(create_rule("rule2"));
211 manager_.add_rule(create_rule("rule3"));
212
213 auto rules = manager_.get_rules();
214 EXPECT_EQ(rules.size(), 3u);
215}
216
218 auto rules = manager_.get_rules();
219 EXPECT_TRUE(rules.empty());
220}
221
222// =============================================================================
223// alert_rule Builder API Tests
224// =============================================================================
225
226TEST(AlertRuleTest, FluentBuilder) {
227 alert_rule rule("cpu_high");
228 rule.set_metric_name("cpu_usage")
229 .set_severity(alert_severity::critical)
230 .set_summary("CPU usage too high")
231 .set_description("CPU usage exceeded threshold")
232 .set_runbook_url("https://runbooks.example.com/cpu")
233 .add_label("team", "infra")
234 .add_label("env", "prod")
235 .set_group("system_health")
237 .set_for_duration(5min)
238 .set_repeat_interval(10min)
239 .set_enabled(true)
241
242 EXPECT_EQ(rule.name(), "cpu_high");
243 EXPECT_EQ(rule.metric_name(), "cpu_usage");
244 EXPECT_EQ(rule.severity(), alert_severity::critical);
245 EXPECT_EQ(rule.annotations().summary, "CPU usage too high");
246 EXPECT_EQ(rule.annotations().description, "CPU usage exceeded threshold");
247 EXPECT_EQ(*rule.annotations().runbook_url, "https://runbooks.example.com/cpu");
248 EXPECT_EQ(rule.labels().get("team"), "infra");
249 EXPECT_EQ(rule.labels().get("env"), "prod");
250 EXPECT_EQ(rule.group(), "system_health");
251 EXPECT_TRUE(rule.is_enabled());
252 EXPECT_NE(rule.trigger(), nullptr);
253}
254
255TEST(AlertRuleTest, ValidateSuccess) {
256 alert_rule rule("test");
258 auto result = rule.validate();
259 EXPECT_TRUE(result.is_ok());
260}
261
262TEST(AlertRuleTest, ValidateEmptyNameFails) {
263 alert_rule rule("");
265 auto result = rule.validate();
266 EXPECT_FALSE(result.is_ok());
267}
268
269TEST(AlertRuleTest, ValidateNoTriggerFails) {
270 alert_rule rule("test");
271 auto result = rule.validate();
272 EXPECT_FALSE(result.is_ok());
273}
274
275TEST(AlertRuleTest, ValidateInvalidConfigFails) {
276 alert_rule rule("test");
279 auto result = rule.validate();
280 EXPECT_FALSE(result.is_ok());
281}
282
283TEST(AlertRuleTest, CreateAlertFromRule) {
284 alert_rule rule("cpu_high");
285 rule.set_metric_name("cpu_usage")
286 .set_severity(alert_severity::critical)
287 .set_summary("CPU high")
288 .add_label("service", "api")
289 .set_group("infra")
291
292 auto a = rule.create_alert(95.0);
293 EXPECT_EQ(a.name, "cpu_high");
294 EXPECT_EQ(a.severity, alert_severity::critical);
295 EXPECT_EQ(a.value, 95.0);
296 EXPECT_EQ(a.rule_name, "cpu_high");
297 EXPECT_EQ(a.group_key, "infra");
298 EXPECT_EQ(a.labels.get("service"), "api");
299}
300
301TEST(AlertRuleTest, CreateAlertWithoutGroupUsesName) {
302 alert_rule rule("test_rule");
304 auto a = rule.create_alert(90.0);
305 EXPECT_EQ(a.group_key, "test_rule");
306}
307
308TEST(AlertRuleTest, DisabledRule) {
309 alert_rule rule("test");
310 rule.set_enabled(false);
311 EXPECT_FALSE(rule.is_enabled());
312}
313
314TEST(AlertRuleTest, DefaultSeverityIsWarning) {
315 alert_rule rule("test");
316 EXPECT_EQ(rule.severity(), alert_severity::warning);
317}
318
319// =============================================================================
320// alert_rule_config Tests
321// =============================================================================
322
323TEST(AlertRuleConfigTest, DefaultConfigIsValid) {
324 alert_rule_config config;
325 EXPECT_TRUE(config.validate());
326}
327
328TEST(AlertRuleConfigTest, ZeroEvalIntervalInvalid) {
329 alert_rule_config config;
330 config.evaluation_interval = 0ms;
331 EXPECT_FALSE(config.validate());
332}
333
334TEST(AlertRuleConfigTest, ZeroRepeatIntervalInvalid) {
335 alert_rule_config config;
336 config.repeat_interval = 0ms;
337 EXPECT_FALSE(config.validate());
338}
339
340// =============================================================================
341// Rule Group Tests
342// =============================================================================
343
344TEST(AlertRuleGroupTest, Construction) {
345 alert_rule_group group("infra");
346 EXPECT_EQ(group.name(), "infra");
347 EXPECT_TRUE(group.empty());
348 EXPECT_EQ(group.size(), 0u);
349}
350
351TEST(AlertRuleGroupTest, AddRule) {
352 alert_rule_group group("infra");
353 auto rule = std::make_shared<alert_rule>("test");
354 group.add_rule(rule);
355 EXPECT_EQ(group.size(), 1u);
356 EXPECT_FALSE(group.empty());
357 // Rule should have its group set
358 EXPECT_EQ(rule->group(), "infra");
359}
360
361TEST(AlertRuleGroupTest, AddNullRuleIgnored) {
362 alert_rule_group group("test");
363 group.add_rule(nullptr);
364 EXPECT_TRUE(group.empty());
365}
366
367TEST(AlertRuleGroupTest, CommonInterval) {
368 alert_rule_group group("infra");
369 auto rule1 = std::make_shared<alert_rule>("r1");
370 auto rule2 = std::make_shared<alert_rule>("r2");
371 group.add_rule(rule1);
372 group.add_rule(rule2);
373 group.set_common_interval(30s);
374
375 EXPECT_TRUE(group.common_interval().has_value());
376 EXPECT_EQ(*group.common_interval(), 30s);
377 EXPECT_EQ(rule1->config().evaluation_interval, 30s);
378 EXPECT_EQ(rule2->config().evaluation_interval, 30s);
379}
380
381TEST(AlertRuleGroupTest, CommonIntervalNotSetByDefault) {
382 alert_rule_group group("test");
383 EXPECT_FALSE(group.common_interval().has_value());
384}
385
386TEST(AlertRuleGroupTest, AddRuleGroupToManager) {
387 alert_manager manager;
388 auto group = std::make_shared<alert_rule_group>("infra");
389 auto rule = std::make_shared<alert_rule>("test");
390 rule->set_trigger(threshold_trigger::above(80.0))
391 .set_metric_name("cpu");
392 group->add_rule(rule);
393
394 auto result = manager.add_rule_group(group);
395 EXPECT_TRUE(result.is_ok());
396}
397
398// =============================================================================
399// Alert Processing Tests
400// =============================================================================
401
402class AlertManagerProcessingTest : public ::testing::Test {
403protected:
405
406 void SetUp() override {
407 auto rule = std::make_shared<alert_rule>("cpu_high");
408 rule->set_metric_name("cpu_usage")
409 .set_severity(alert_severity::critical)
410 .set_trigger(threshold_trigger::above(80.0))
411 .set_for_duration(0ms); // Immediate transition (no pending wait)
412 manager_.add_rule(rule);
413 }
414};
415
416TEST_F(AlertManagerProcessingTest, ProcessMetricBelowThreshold) {
417 auto result = manager_.process_metric("cpu_usage", 50.0);
418 EXPECT_TRUE(result.is_ok());
419
420 auto alerts = manager_.get_active_alerts();
421 EXPECT_TRUE(alerts.empty());
422}
423
424TEST_F(AlertManagerProcessingTest, ProcessMetricAboveThreshold) {
425 auto result = manager_.process_metric("cpu_usage", 95.0);
426 EXPECT_TRUE(result.is_ok());
427
428 auto alerts = manager_.get_active_alerts();
429 // Should have at least one active alert
430 EXPECT_GE(alerts.size(), 0u); // Implementation may require manager to be running
431}
432
433TEST_F(AlertManagerProcessingTest, ProcessUnknownMetric) {
434 // Processing a metric with no matching rule should still succeed
435 auto result = manager_.process_metric("unknown_metric", 42.0);
436 EXPECT_TRUE(result.is_ok());
437}
438
439TEST_F(AlertManagerProcessingTest, ProcessBatchMetrics) {
440 std::unordered_map<std::string, double> metrics{
441 {"cpu_usage", 95.0},
442 {"memory_usage", 85.0},
443 {"disk_usage", 50.0}};
444
445 auto result = manager_.process_metrics(metrics);
446 EXPECT_TRUE(result.is_ok());
447}
448
449TEST_F(AlertManagerProcessingTest, MetricsTrackRulesEvaluated) {
450 manager_.process_metric("cpu_usage", 50.0);
451 auto metrics = manager_.get_metrics();
452 EXPECT_GE(metrics.rules_evaluated.load(), 1u);
453}
454
455// =============================================================================
456// Alert Resolution Tests
457// =============================================================================
458
459class AlertManagerResolutionTest : public ::testing::Test {
460protected:
462};
463
464TEST_F(AlertManagerResolutionTest, ResolveNonexistentAlert) {
465 auto result = manager_.resolve_alert("nonexistent_fingerprint");
466 // Should fail gracefully for nonexistent alert
467 EXPECT_FALSE(result.is_ok());
468}
469
470TEST_F(AlertManagerResolutionTest, GetAlertByFingerprint) {
471 // With no alerts, should return empty optional
472 auto alert_opt = manager_.get_alert("nonexistent");
473 EXPECT_FALSE(alert_opt.has_value());
474}
475
476// =============================================================================
477// Silence Management Tests
478// =============================================================================
479
480class AlertManagerSilenceTest : public ::testing::Test {
481protected:
483};
484
486 alert_silence silence;
487 silence.matchers.set("service", "api");
488 silence.comment = "Maintenance window";
489
490 auto result = manager_.create_silence(silence);
491 EXPECT_TRUE(result.is_ok());
492}
493
494TEST_F(AlertManagerSilenceTest, CreateSilenceReturnsId) {
495 alert_silence silence;
496 silence.id = 42;
497 auto result = manager_.create_silence(silence);
498 ASSERT_TRUE(result.is_ok());
499 EXPECT_EQ(result.value(), 42u);
500}
501
503 alert_silence silence;
504 auto create_result = manager_.create_silence(silence);
505 ASSERT_TRUE(create_result.is_ok());
506
507 auto delete_result = manager_.delete_silence(create_result.value());
508 EXPECT_TRUE(delete_result.is_ok());
509}
510
511TEST_F(AlertManagerSilenceTest, DeleteNonexistentSilence) {
512 auto result = manager_.delete_silence(99999);
513 EXPECT_FALSE(result.is_ok());
514}
515
517 alert_silence s1;
518 s1.matchers.set("env", "prod");
519 manager_.create_silence(s1);
520
521 alert_silence s2;
522 s2.matchers.set("env", "staging");
523 manager_.create_silence(s2);
524
525 auto silences = manager_.get_silences();
526 EXPECT_EQ(silences.size(), 2u);
527}
528
529TEST_F(AlertManagerSilenceTest, GetSilencesEmpty) {
530 auto silences = manager_.get_silences();
531 EXPECT_TRUE(silences.empty());
532}
533
534TEST_F(AlertManagerSilenceTest, IsSilencedMatchingAlert) {
535 alert_silence silence;
536 silence.matchers.set("service", "api");
537 manager_.create_silence(silence);
538
539 alert a;
540 a.labels.set("service", "api");
541 EXPECT_TRUE(manager_.is_silenced(a));
542}
543
544TEST_F(AlertManagerSilenceTest, IsNotSilencedNonMatchingAlert) {
545 alert_silence silence;
546 silence.matchers.set("service", "api");
547 manager_.create_silence(silence);
548
549 alert a;
550 a.labels.set("service", "web");
551 EXPECT_FALSE(manager_.is_silenced(a));
552}
553
554TEST_F(AlertManagerSilenceTest, IsNotSilencedNoSilences) {
555 alert a;
556 a.labels.set("service", "api");
557 EXPECT_FALSE(manager_.is_silenced(a));
558}
559
560// =============================================================================
561// Notifier Management Tests
562// =============================================================================
563
564class AlertManagerNotifierTest : public ::testing::Test {
565protected:
567};
568
570 auto notifier = std::make_shared<log_notifier>("test_log");
571 auto result = manager_.add_notifier(notifier);
572 EXPECT_TRUE(result.is_ok());
573}
574
575TEST_F(AlertManagerNotifierTest, AddNullNotifierFails) {
576 auto result = manager_.add_notifier(nullptr);
577 EXPECT_FALSE(result.is_ok());
578}
579
581 auto notifier = std::make_shared<log_notifier>("removable");
582 manager_.add_notifier(notifier);
583 auto result = manager_.remove_notifier("removable");
584 EXPECT_TRUE(result.is_ok());
585}
586
587TEST_F(AlertManagerNotifierTest, RemoveNonexistentNotifier) {
588 auto result = manager_.remove_notifier("missing");
589 EXPECT_FALSE(result.is_ok());
590}
591
593 manager_.add_notifier(std::make_shared<log_notifier>("n1"));
594 manager_.add_notifier(std::make_shared<log_notifier>("n2"));
595
596 auto notifiers = manager_.get_notifiers();
597 EXPECT_EQ(notifiers.size(), 2u);
598}
599
600// =============================================================================
601// callback_notifier Tests
602// =============================================================================
603
604TEST(CallbackNotifierTest, NotifyInvokesCallback) {
605 std::atomic<int> count{0};
606 auto notifier = std::make_shared<callback_notifier>(
607 "test_cb",
608 [&](const alert& /*a*/) { count++; });
609
610 alert test_alert;
611 auto result = notifier->notify(test_alert);
612 EXPECT_TRUE(result.is_ok());
613 EXPECT_EQ(count.load(), 1);
614}
615
616TEST(CallbackNotifierTest, NotifyGroupInvokesGroupCallback) {
617 std::atomic<int> group_count{0};
618 auto notifier = std::make_shared<callback_notifier>(
619 "test_cb",
620 [](const alert&) {},
621 [&](const alert_group& /*g*/) { group_count++; });
622
623 alert_group group("test");
624 auto result = notifier->notify_group(group);
625 EXPECT_TRUE(result.is_ok());
626 EXPECT_EQ(group_count.load(), 1);
627}
628
629TEST(CallbackNotifierTest, NotifyGroupFallsBackToIndividual) {
630 std::atomic<int> individual_count{0};
631 auto notifier = std::make_shared<callback_notifier>(
632 "test_cb",
633 [&](const alert& /*a*/) { individual_count++; },
634 nullptr); // No group callback
635
636 alert_group group("test");
637 group.add_alert(alert{});
638 group.add_alert(alert{});
639
640 auto result = notifier->notify_group(group);
641 EXPECT_TRUE(result.is_ok());
642 EXPECT_EQ(individual_count.load(), 2);
643}
644
645TEST(CallbackNotifierTest, NameIsCorrect) {
646 auto notifier = std::make_shared<callback_notifier>(
647 "my_notifier", [](const alert&) {});
648 EXPECT_EQ(notifier->name(), "my_notifier");
649}
650
651TEST(CallbackNotifierTest, IsReadyWithCallback) {
652 auto notifier = std::make_shared<callback_notifier>(
653 "test", [](const alert&) {});
654 EXPECT_TRUE(notifier->is_ready());
655}
656
657TEST(CallbackNotifierTest, NotReadyWithoutCallback) {
658 auto notifier = std::make_shared<callback_notifier>(
659 "test", nullptr);
660 EXPECT_FALSE(notifier->is_ready());
661}
662
663TEST(CallbackNotifierTest, NotifyWithNullCallbackFails) {
664 auto notifier = std::make_shared<callback_notifier>(
665 "test", nullptr);
666 alert a;
667 auto result = notifier->notify(a);
668 EXPECT_FALSE(result.is_ok());
669}
670
671// =============================================================================
672// log_notifier Tests
673// =============================================================================
674
675TEST(LogNotifierTest, DefaultName) {
676 log_notifier notifier;
677 EXPECT_EQ(notifier.name(), "log_notifier");
678}
679
680TEST(LogNotifierTest, CustomName) {
681 log_notifier notifier("custom_logger");
682 EXPECT_EQ(notifier.name(), "custom_logger");
683}
684
685TEST(LogNotifierTest, IsAlwaysReady) {
686 log_notifier notifier;
687 EXPECT_TRUE(notifier.is_ready());
688}
689
690// =============================================================================
691// Metric Provider Tests
692// =============================================================================
693
694TEST(AlertManagerMetricProviderTest, SetMetricProvider) {
695 alert_manager manager;
696 bool called = false;
697
698 manager.set_metric_provider([&](const std::string& name)
699 -> std::optional<double> {
700 called = true;
701 if (name == "cpu") return 95.0;
702 return std::nullopt;
703 });
704
705 // The provider is used internally by the evaluation loop
706 // Just verify it doesn't crash to set
707 SUCCEED();
708}
709
710// =============================================================================
711// Manager Config Access Test
712// =============================================================================
713
714TEST(AlertManagerConfigAccessTest, DefaultConfig) {
715 alert_manager manager;
716 auto& config = manager.config();
717 EXPECT_TRUE(config.validate());
718 EXPECT_EQ(config.default_evaluation_interval, 15000ms);
719}
720
721TEST(AlertManagerConfigAccessTest, CustomConfig) {
723 config.default_evaluation_interval = 5s;
724 config.max_alerts_per_rule = 50;
725
726 alert_manager manager(config);
727 EXPECT_EQ(manager.config().default_evaluation_interval, 5s);
728 EXPECT_EQ(manager.config().max_alerts_per_rule, 50u);
729}
730
731// =============================================================================
732// Metrics Tracking Tests
733// =============================================================================
734
735TEST(AlertManagerMetricsTrackingTest, InitialMetricsAreZero) {
736 alert_manager manager;
737 auto metrics = manager.get_metrics();
738 EXPECT_EQ(metrics.rules_evaluated.load(), 0u);
739 EXPECT_EQ(metrics.alerts_created.load(), 0u);
740 EXPECT_EQ(metrics.alerts_resolved.load(), 0u);
741}
742
743TEST(AlertManagerMetricsTrackingTest, MetricsIncrementOnProcessing) {
744 alert_manager manager;
745
746 auto rule = std::make_shared<alert_rule>("test_rule");
747 rule->set_metric_name("test_metric")
748 .set_trigger(threshold_trigger::above(80.0));
749 manager.add_rule(rule);
750
751 manager.process_metric("test_metric", 50.0);
752
753 auto metrics = manager.get_metrics();
754 EXPECT_GE(metrics.rules_evaluated.load(), 1u);
755}
756
757// =============================================================================
758// Event Bus Integration Test
759// =============================================================================
760
761TEST(AlertManagerEventBusTest, SetEventBusDoesNotCrash) {
762 alert_manager manager;
763 // Passing nullptr should be handled gracefully
764 manager.set_event_bus(nullptr);
765 SUCCEED();
766}
767
768// =============================================================================
769// Non-copyable, Non-movable Test
770// =============================================================================
771
772TEST(AlertManagerNonCopyableTest, VerifyTraits) {
773 EXPECT_FALSE(std::is_copy_constructible_v<alert_manager>);
774 EXPECT_FALSE(std::is_copy_assignable_v<alert_manager>);
775 EXPECT_FALSE(std::is_move_constructible_v<alert_manager>);
776 EXPECT_FALSE(std::is_move_assignable_v<alert_manager>);
777}
Central coordinator for alert lifecycle management.
Alert trigger implementations for various condition types.
std::shared_ptr< alert_rule > create_rule(const std::string &name, const std::string &metric="cpu_usage")
Central coordinator for the alert pipeline.
void set_event_bus(std::shared_ptr< interface_event_bus > event_bus)
Set event bus for publishing alert events.
bool is_running() const
Check if manager is running.
common::VoidResult stop()
Stop the alert manager.
common::VoidResult add_rule(std::shared_ptr< alert_rule > rule)
Add an alert rule.
const alert_manager_config & config() const
Get configuration.
common::VoidResult process_metric(const std::string &metric_name, double value)
Process a metric value.
common::VoidResult add_rule_group(std::shared_ptr< alert_rule_group > group)
Add a rule group.
common::VoidResult start()
Start the alert manager.
alert_manager_metrics get_metrics() const
Get manager metrics.
void set_metric_provider(metric_provider_func provider)
Set the metric provider function.
common::VoidResult resolve_alert(const std::string &fingerprint)
Resolve an alert manually.
A group of related alert rules.
Definition alert_rule.h:356
std::optional< std::chrono::milliseconds > common_interval() const
Get common evaluation interval.
Definition alert_rule.h:417
bool empty() const
Check if group is empty.
Definition alert_rule.h:400
size_t size() const
Get number of rules.
Definition alert_rule.h:394
void set_common_interval(std::chrono::milliseconds interval)
Set common evaluation interval for all rules.
Definition alert_rule.h:406
void add_rule(std::shared_ptr< alert_rule > rule)
Add a rule to the group.
Definition alert_rule.h:375
const std::string & name() const
Get group name.
Definition alert_rule.h:369
Defines conditions and behavior for alert triggering.
Definition alert_rule.h:82
alert_rule & set_evaluation_interval(std::chrono::milliseconds interval)
Set evaluation interval.
Definition alert_rule.h:194
alert_rule & set_trigger(std::shared_ptr< alert_trigger > trigger)
Set the trigger for this rule.
Definition alert_rule.h:240
std::shared_ptr< alert_trigger > trigger() const
Get the trigger.
Definition alert_rule.h:249
const std::string & group() const
Get rule group.
Definition alert_rule.h:102
const std::string & name() const
Get rule name.
Definition alert_rule.h:96
const alert_annotations & annotations() const
Get annotations.
Definition alert_rule.h:151
alert_rule & set_group(std::string group_name)
Set rule group.
Definition alert_rule.h:109
common::VoidResult validate() const
Validate rule configuration.
Definition alert_rule.h:270
alert_rule & set_summary(std::string summary)
Set alert summary.
Definition alert_rule.h:158
alert create_alert(double value) const
Create an alert from this rule.
Definition alert_rule.h:256
alert_rule & set_for_duration(std::chrono::milliseconds duration)
Set for duration (pending time before firing)
Definition alert_rule.h:204
const std::string & metric_name() const
Get metric name to monitor.
Definition alert_rule.h:293
alert_rule & set_description(std::string description)
Set alert description.
Definition alert_rule.h:168
alert_rule & set_enabled(bool enabled)
Enable or disable rule.
Definition alert_rule.h:230
alert_rule & set_severity(alert_severity sev)
Set alert severity.
Definition alert_rule.h:125
bool is_enabled() const
Check if rule is enabled.
Definition alert_rule.h:223
alert_severity severity() const
Get alert severity.
Definition alert_rule.h:118
alert_rule & set_runbook_url(std::string url)
Set runbook URL.
Definition alert_rule.h:178
alert_rule & add_label(const std::string &key, const std::string &value)
Add a label.
Definition alert_rule.h:142
alert_rule & set_repeat_interval(std::chrono::milliseconds interval)
Set notification repeat interval.
Definition alert_rule.h:214
const alert_labels & labels() const
Get labels.
Definition alert_rule.h:134
alert_rule & set_metric_name(std::string name)
Set metric name to monitor.
Definition alert_rule.h:300
Simple notifier that logs alerts.
bool is_ready() const override
Check if the log notifier is ready.
std::string name() const override
Get the name of this log notifier.
static std::shared_ptr< threshold_trigger > above(double threshold)
Create trigger for value > threshold.
std::string description
Detailed description.
std::string summary
Brief description.
std::optional< std::string > runbook_url
Link to runbook.
Group of related alerts for batch notification.
void set(const std::string &key, const std::string &value)
Add or update a label.
std::string get(const std::string &key) const
Get a label value.
Configuration for the alert manager.
std::chrono::milliseconds default_evaluation_interval
Default eval interval.
size_t max_alerts_per_rule
Max alerts per rule.
bool validate() const
Validate configuration.
size_t max_silences
Max active silences.
std::chrono::milliseconds default_repeat_interval
Default repeat interval.
Metrics for alert manager operations.
std::atomic< uint64_t > alerts_suppressed
std::atomic< uint64_t > notifications_sent
std::atomic< uint64_t > notifications_failed
Configuration for an alert rule.
Definition alert_rule.h:36
bool validate() const
Validate configuration.
Definition alert_rule.h:47
std::chrono::milliseconds repeat_interval
Notification repeat interval.
Definition alert_rule.h:39
std::chrono::milliseconds evaluation_interval
How often to evaluate.
Definition alert_rule.h:37
Silence configuration to suppress alerts.
alert_labels matchers
Labels to match.
std::string comment
Reason for silence.
Core alert data structure.
alert_labels labels
Identifying labels.
Result of collector creation.
Basic metric structure for interface compatibility.
TEST(AlertManagerConfigTest, DefaultConfigIsValid)
TEST_F(AlertManagerLifecycleTest, DefaultConstruction)