22#include <gtest/gtest.h>
35using namespace std::chrono_literals;
41TEST(AlertManagerConfigTest, DefaultConfigIsValid) {
46TEST(AlertManagerConfigTest, ZeroEvaluationIntervalInvalid) {
52TEST(AlertManagerConfigTest, ZeroRepeatIntervalInvalid) {
58TEST(AlertManagerConfigTest, ZeroMaxAlertsInvalid) {
64TEST(AlertManagerConfigTest, ZeroMaxSilencesInvalid) {
74TEST(AlertManagerMetricsTest, DefaultZero) {
84TEST(AlertManagerMetricsTest, CopyConstructor) {
120 auto start_result = manager.
start();
121 EXPECT_TRUE(start_result.is_ok());
124 auto stop_result = manager.
stop();
125 EXPECT_TRUE(stop_result.is_ok());
131 EXPECT_TRUE(manager.
start().is_ok());
132 EXPECT_FALSE(manager.
start().is_ok());
138 auto result = manager.
stop();
139 EXPECT_TRUE(result.is_ok());
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)
166 .set_summary(
"Test rule: " + name);
172 auto rule = create_rule(
"test_rule");
173 auto result = manager_.add_rule(rule);
174 EXPECT_TRUE(result.is_ok());
178 auto result = manager_.add_rule(
nullptr);
179 EXPECT_FALSE(result.is_ok());
183 auto rule = create_rule(
"get_test");
184 manager_.add_rule(rule);
186 auto retrieved = manager_.get_rule(
"get_test");
187 ASSERT_NE(retrieved,
nullptr);
188 EXPECT_EQ(retrieved->name(),
"get_test");
192 auto retrieved = manager_.get_rule(
"missing");
193 EXPECT_EQ(retrieved,
nullptr);
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);
204 auto result = manager_.remove_rule(
"missing");
205 EXPECT_FALSE(result.is_ok());
209 manager_.add_rule(create_rule(
"rule1"));
210 manager_.add_rule(create_rule(
"rule2"));
211 manager_.add_rule(create_rule(
"rule3"));
213 auto rules = manager_.get_rules();
214 EXPECT_EQ(rules.size(), 3u);
218 auto rules = manager_.get_rules();
219 EXPECT_TRUE(rules.empty());
226TEST(AlertRuleTest, FluentBuilder) {
242 EXPECT_EQ(rule.
name(),
"cpu_high");
244 EXPECT_EQ(rule.
severity(), alert_severity::critical);
248 EXPECT_EQ(rule.
labels().
get(
"team"),
"infra");
249 EXPECT_EQ(rule.
labels().
get(
"env"),
"prod");
250 EXPECT_EQ(rule.
group(),
"system_health");
252 EXPECT_NE(rule.
trigger(),
nullptr);
255TEST(AlertRuleTest, ValidateSuccess) {
259 EXPECT_TRUE(result.is_ok());
262TEST(AlertRuleTest, ValidateEmptyNameFails) {
266 EXPECT_FALSE(result.is_ok());
269TEST(AlertRuleTest, ValidateNoTriggerFails) {
272 EXPECT_FALSE(result.is_ok());
275TEST(AlertRuleTest, ValidateInvalidConfigFails) {
280 EXPECT_FALSE(result.is_ok());
283TEST(AlertRuleTest, CreateAlertFromRule) {
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");
301TEST(AlertRuleTest, CreateAlertWithoutGroupUsesName) {
305 EXPECT_EQ(a.group_key,
"test_rule");
308TEST(AlertRuleTest, DisabledRule) {
314TEST(AlertRuleTest, DefaultSeverityIsWarning) {
316 EXPECT_EQ(rule.
severity(), alert_severity::warning);
323TEST(AlertRuleConfigTest, DefaultConfigIsValid) {
328TEST(AlertRuleConfigTest, ZeroEvalIntervalInvalid) {
334TEST(AlertRuleConfigTest, ZeroRepeatIntervalInvalid) {
344TEST(AlertRuleGroupTest, Construction) {
346 EXPECT_EQ(group.
name(),
"infra");
347 EXPECT_TRUE(group.
empty());
348 EXPECT_EQ(group.
size(), 0u);
351TEST(AlertRuleGroupTest, AddRule) {
353 auto rule = std::make_shared<alert_rule>(
"test");
355 EXPECT_EQ(group.
size(), 1u);
356 EXPECT_FALSE(group.
empty());
358 EXPECT_EQ(rule->group(),
"infra");
361TEST(AlertRuleGroupTest, AddNullRuleIgnored) {
364 EXPECT_TRUE(group.
empty());
367TEST(AlertRuleGroupTest, CommonInterval) {
369 auto rule1 = std::make_shared<alert_rule>(
"r1");
370 auto rule2 = std::make_shared<alert_rule>(
"r2");
377 EXPECT_EQ(rule1->config().evaluation_interval, 30s);
378 EXPECT_EQ(rule2->config().evaluation_interval, 30s);
381TEST(AlertRuleGroupTest, CommonIntervalNotSetByDefault) {
386TEST(AlertRuleGroupTest, AddRuleGroupToManager) {
388 auto group = std::make_shared<alert_rule_group>(
"infra");
389 auto rule = std::make_shared<alert_rule>(
"test");
391 .set_metric_name(
"cpu");
392 group->add_rule(rule);
395 EXPECT_TRUE(result.is_ok());
407 auto rule = std::make_shared<alert_rule>(
"cpu_high");
408 rule->set_metric_name(
"cpu_usage")
409 .set_severity(alert_severity::critical)
411 .set_for_duration(0ms);
417 auto result = manager_.process_metric(
"cpu_usage", 50.0);
418 EXPECT_TRUE(result.is_ok());
420 auto alerts = manager_.get_active_alerts();
421 EXPECT_TRUE(alerts.empty());
425 auto result = manager_.process_metric(
"cpu_usage", 95.0);
426 EXPECT_TRUE(result.is_ok());
428 auto alerts = manager_.get_active_alerts();
430 EXPECT_GE(alerts.size(), 0u);
435 auto result = manager_.process_metric(
"unknown_metric", 42.0);
436 EXPECT_TRUE(result.is_ok());
440 std::unordered_map<std::string, double> metrics{
442 {
"memory_usage", 85.0},
443 {
"disk_usage", 50.0}};
445 auto result = manager_.process_metrics(metrics);
446 EXPECT_TRUE(result.is_ok());
450 manager_.process_metric(
"cpu_usage", 50.0);
451 auto metrics = manager_.get_metrics();
452 EXPECT_GE(metrics.rules_evaluated.load(), 1u);
465 auto result = manager_.
resolve_alert(
"nonexistent_fingerprint");
467 EXPECT_FALSE(result.is_ok());
472 auto alert_opt = manager_.get_alert(
"nonexistent");
473 EXPECT_FALSE(alert_opt.has_value());
488 silence.
comment =
"Maintenance window";
490 auto result = manager_.create_silence(silence);
491 EXPECT_TRUE(result.is_ok());
497 auto result = manager_.create_silence(silence);
498 ASSERT_TRUE(result.is_ok());
499 EXPECT_EQ(result.value(), 42u);
507 auto delete_result = manager_.delete_silence(
create_result.value());
508 EXPECT_TRUE(delete_result.is_ok());
512 auto result = manager_.delete_silence(99999);
513 EXPECT_FALSE(result.is_ok());
519 manager_.create_silence(s1);
523 manager_.create_silence(s2);
525 auto silences = manager_.get_silences();
526 EXPECT_EQ(silences.size(), 2u);
530 auto silences = manager_.get_silences();
531 EXPECT_TRUE(silences.empty());
537 manager_.create_silence(silence);
541 EXPECT_TRUE(manager_.is_silenced(a));
547 manager_.create_silence(silence);
551 EXPECT_FALSE(manager_.is_silenced(a));
557 EXPECT_FALSE(manager_.is_silenced(a));
570 auto notifier = std::make_shared<log_notifier>(
"test_log");
571 auto result = manager_.add_notifier(notifier);
572 EXPECT_TRUE(result.is_ok());
576 auto result = manager_.add_notifier(
nullptr);
577 EXPECT_FALSE(result.is_ok());
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());
588 auto result = manager_.remove_notifier(
"missing");
589 EXPECT_FALSE(result.is_ok());
593 manager_.add_notifier(std::make_shared<log_notifier>(
"n1"));
594 manager_.add_notifier(std::make_shared<log_notifier>(
"n2"));
596 auto notifiers = manager_.get_notifiers();
597 EXPECT_EQ(notifiers.size(), 2u);
604TEST(CallbackNotifierTest, NotifyInvokesCallback) {
605 std::atomic<int> count{0};
606 auto notifier = std::make_shared<callback_notifier>(
608 [&](
const alert& ) { count++; });
611 auto result = notifier->notify(test_alert);
612 EXPECT_TRUE(result.is_ok());
613 EXPECT_EQ(count.load(), 1);
616TEST(CallbackNotifierTest, NotifyGroupInvokesGroupCallback) {
617 std::atomic<int> group_count{0};
618 auto notifier = std::make_shared<callback_notifier>(
624 auto result = notifier->notify_group(group);
625 EXPECT_TRUE(result.is_ok());
626 EXPECT_EQ(group_count.load(), 1);
629TEST(CallbackNotifierTest, NotifyGroupFallsBackToIndividual) {
630 std::atomic<int> individual_count{0};
631 auto notifier = std::make_shared<callback_notifier>(
633 [&](
const alert& ) { individual_count++; },
637 group.add_alert(
alert{});
638 group.add_alert(
alert{});
640 auto result = notifier->notify_group(group);
641 EXPECT_TRUE(result.is_ok());
642 EXPECT_EQ(individual_count.load(), 2);
645TEST(CallbackNotifierTest, NameIsCorrect) {
646 auto notifier = std::make_shared<callback_notifier>(
647 "my_notifier", [](
const alert&) {});
648 EXPECT_EQ(notifier->name(),
"my_notifier");
651TEST(CallbackNotifierTest, IsReadyWithCallback) {
652 auto notifier = std::make_shared<callback_notifier>(
653 "test", [](
const alert&) {});
654 EXPECT_TRUE(notifier->is_ready());
657TEST(CallbackNotifierTest, NotReadyWithoutCallback) {
658 auto notifier = std::make_shared<callback_notifier>(
660 EXPECT_FALSE(notifier->is_ready());
663TEST(CallbackNotifierTest, NotifyWithNullCallbackFails) {
664 auto notifier = std::make_shared<callback_notifier>(
667 auto result = notifier->notify(a);
668 EXPECT_FALSE(result.is_ok());
675TEST(LogNotifierTest, DefaultName) {
677 EXPECT_EQ(notifier.
name(),
"log_notifier");
680TEST(LogNotifierTest, CustomName) {
682 EXPECT_EQ(notifier.
name(),
"custom_logger");
685TEST(LogNotifierTest, IsAlwaysReady) {
694TEST(AlertManagerMetricProviderTest, SetMetricProvider) {
699 -> std::optional<double> {
701 if (name ==
"cpu")
return 95.0;
714TEST(AlertManagerConfigAccessTest, DefaultConfig) {
716 auto& config = manager.
config();
717 EXPECT_TRUE(config.validate());
718 EXPECT_EQ(config.default_evaluation_interval, 15000ms);
721TEST(AlertManagerConfigAccessTest, CustomConfig) {
735TEST(AlertManagerMetricsTrackingTest, InitialMetricsAreZero) {
738 EXPECT_EQ(metrics.rules_evaluated.load(), 0u);
739 EXPECT_EQ(metrics.alerts_created.load(), 0u);
740 EXPECT_EQ(metrics.alerts_resolved.load(), 0u);
743TEST(AlertManagerMetricsTrackingTest, MetricsIncrementOnProcessing) {
746 auto rule = std::make_shared<alert_rule>(
"test_rule");
747 rule->set_metric_name(
"test_metric")
754 EXPECT_GE(metrics.rules_evaluated.load(), 1u);
761TEST(AlertManagerEventBusTest, SetEventBusDoesNotCrash) {
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>);
Central coordinator for alert lifecycle management.
Alert trigger implementations for various condition types.
alert_manager_config config_
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.
std::optional< std::chrono::milliseconds > common_interval() const
Get common evaluation interval.
bool empty() const
Check if group is empty.
size_t size() const
Get number of rules.
void set_common_interval(std::chrono::milliseconds interval)
Set common evaluation interval for all rules.
void add_rule(std::shared_ptr< alert_rule > rule)
Add a rule to the group.
const std::string & name() const
Get group name.
Defines conditions and behavior for alert triggering.
alert_rule & set_evaluation_interval(std::chrono::milliseconds interval)
Set evaluation interval.
alert_rule & set_trigger(std::shared_ptr< alert_trigger > trigger)
Set the trigger for this rule.
std::shared_ptr< alert_trigger > trigger() const
Get the trigger.
const std::string & group() const
Get rule group.
const std::string & name() const
Get rule name.
const alert_annotations & annotations() const
Get annotations.
alert_rule & set_group(std::string group_name)
Set rule group.
common::VoidResult validate() const
Validate rule configuration.
alert_rule & set_summary(std::string summary)
Set alert summary.
alert create_alert(double value) const
Create an alert from this rule.
alert_rule & set_for_duration(std::chrono::milliseconds duration)
Set for duration (pending time before firing)
const std::string & metric_name() const
Get metric name to monitor.
alert_rule & set_description(std::string description)
Set alert description.
alert_rule & set_enabled(bool enabled)
Enable or disable rule.
alert_rule & set_severity(alert_severity sev)
Set alert severity.
bool is_enabled() const
Check if rule is enabled.
alert_severity severity() const
Get alert severity.
alert_rule & set_runbook_url(std::string url)
Set runbook URL.
alert_rule & add_label(const std::string &key, const std::string &value)
Add a label.
alert_rule & set_repeat_interval(std::chrono::milliseconds interval)
Set notification repeat interval.
const alert_labels & labels() const
Get labels.
alert_rule & set_metric_name(std::string name)
Set metric name to monitor.
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_resolved
std::atomic< uint64_t > alerts_suppressed
std::atomic< uint64_t > notifications_sent
std::atomic< uint64_t > alerts_created
std::atomic< uint64_t > notifications_failed
std::atomic< uint64_t > rules_evaluated
Configuration for an alert rule.
bool validate() const
Validate configuration.
std::chrono::milliseconds repeat_interval
Notification repeat interval.
std::chrono::milliseconds evaluation_interval
How often to evaluate.
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)