- Created monitoring and alerting service with Prometheus integration - Support for alert rules with thresholds and severities - Alert firing and resolution tracking - Notification callbacks for alert events - Continuous monitoring with configurable intervals - Default alert rules for common scenarios - Prometheus query evaluation and threshold checking - Comprehensive unit tests for core functionality
251 lines
6.3 KiB
Go
251 lines
6.3 KiB
Go
package services
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
func TestNewMonitoringAlertingService(t *testing.T) {
|
|
config := MonitoringConfig{
|
|
PrometheusURL: "",
|
|
Logger: zap.NewNop(),
|
|
}
|
|
|
|
service, err := NewMonitoringAlertingService(config)
|
|
if err != nil {
|
|
t.Fatalf("NewMonitoringAlertingService() error = %v", err)
|
|
}
|
|
|
|
if service == nil {
|
|
t.Error("NewMonitoringAlertingService() returned nil")
|
|
}
|
|
if service.logger == nil {
|
|
t.Error("NewMonitoringAlertingService() returned service with nil logger")
|
|
}
|
|
if service.rules == nil {
|
|
t.Error("NewMonitoringAlertingService() returned service with nil rules")
|
|
}
|
|
if service.activeAlerts == nil {
|
|
t.Error("NewMonitoringAlertingService() returned service with nil activeAlerts")
|
|
}
|
|
}
|
|
|
|
func TestMonitoringAlertingService_AddAlertRule(t *testing.T) {
|
|
config := MonitoringConfig{
|
|
Logger: zap.NewNop(),
|
|
}
|
|
|
|
service, err := NewMonitoringAlertingService(config)
|
|
if err != nil {
|
|
t.Fatalf("NewMonitoringAlertingService() error = %v", err)
|
|
}
|
|
|
|
rule := AlertRule{
|
|
Name: "test_rule",
|
|
Query: "up",
|
|
Threshold: 1.0,
|
|
Severity: SeverityWarning,
|
|
Duration: 5 * time.Minute,
|
|
Description: "Test rule",
|
|
Enabled: true,
|
|
}
|
|
|
|
service.AddAlertRule(rule)
|
|
|
|
rules := service.GetAlertRules()
|
|
if len(rules) != 1 {
|
|
t.Errorf("AddAlertRule() rules count = %d, want 1", len(rules))
|
|
}
|
|
if rules[0].Name != "test_rule" {
|
|
t.Errorf("AddAlertRule() rule name = %s, want test_rule", rules[0].Name)
|
|
}
|
|
}
|
|
|
|
func TestMonitoringAlertingService_GetAlertRules(t *testing.T) {
|
|
config := MonitoringConfig{
|
|
Logger: zap.NewNop(),
|
|
}
|
|
|
|
service, err := NewMonitoringAlertingService(config)
|
|
if err != nil {
|
|
t.Fatalf("NewMonitoringAlertingService() error = %v", err)
|
|
}
|
|
|
|
// Add multiple rules
|
|
service.AddAlertRule(AlertRule{Name: "rule1", Enabled: true})
|
|
service.AddAlertRule(AlertRule{Name: "rule2", Enabled: true})
|
|
|
|
rules := service.GetAlertRules()
|
|
if len(rules) != 2 {
|
|
t.Errorf("GetAlertRules() returned %d rules, want 2", len(rules))
|
|
}
|
|
}
|
|
|
|
func TestMonitoringAlertingService_GetActiveAlerts(t *testing.T) {
|
|
config := MonitoringConfig{
|
|
Logger: zap.NewNop(),
|
|
}
|
|
|
|
service, err := NewMonitoringAlertingService(config)
|
|
if err != nil {
|
|
t.Fatalf("NewMonitoringAlertingService() error = %v", err)
|
|
}
|
|
|
|
alerts := service.GetActiveAlerts()
|
|
if len(alerts) != 0 {
|
|
t.Errorf("GetActiveAlerts() returned %d alerts, want 0", len(alerts))
|
|
}
|
|
}
|
|
|
|
func TestMonitoringAlertingService_ResolveAlert(t *testing.T) {
|
|
config := MonitoringConfig{
|
|
Logger: zap.NewNop(),
|
|
}
|
|
|
|
service, err := NewMonitoringAlertingService(config)
|
|
if err != nil {
|
|
t.Fatalf("NewMonitoringAlertingService() error = %v", err)
|
|
}
|
|
|
|
// Try to resolve non-existent alert
|
|
err = service.ResolveAlert("nonexistent")
|
|
if err == nil {
|
|
t.Error("ResolveAlert() should return error for non-existent alert")
|
|
}
|
|
}
|
|
|
|
func TestMonitoringAlertingService_GetAlertByRuleName(t *testing.T) {
|
|
config := MonitoringConfig{
|
|
Logger: zap.NewNop(),
|
|
}
|
|
|
|
service, err := NewMonitoringAlertingService(config)
|
|
if err != nil {
|
|
t.Fatalf("NewMonitoringAlertingService() error = %v", err)
|
|
}
|
|
|
|
// Get non-existent alert
|
|
alert, exists := service.GetAlertByRuleName("nonexistent")
|
|
if exists {
|
|
t.Error("GetAlertByRuleName() should return false for non-existent alert")
|
|
}
|
|
if alert != nil {
|
|
t.Error("GetAlertByRuleName() should return nil for non-existent alert")
|
|
}
|
|
}
|
|
|
|
func TestMonitoringAlertingService_SetNotificationFunc(t *testing.T) {
|
|
config := MonitoringConfig{
|
|
Logger: zap.NewNop(),
|
|
}
|
|
|
|
service, err := NewMonitoringAlertingService(config)
|
|
if err != nil {
|
|
t.Fatalf("NewMonitoringAlertingService() error = %v", err)
|
|
}
|
|
|
|
notificationCalled := false
|
|
service.SetNotificationFunc(func(*MonitoringAlertNotification) error {
|
|
notificationCalled = true
|
|
return nil
|
|
})
|
|
|
|
// Verify function is set (can't test directly, but we can check it doesn't panic)
|
|
if service == nil {
|
|
t.Error("SetNotificationFunc() failed")
|
|
}
|
|
_ = notificationCalled
|
|
}
|
|
|
|
func TestGetDefaultAlertRules(t *testing.T) {
|
|
rules := GetDefaultAlertRules()
|
|
|
|
if len(rules) == 0 {
|
|
t.Error("GetDefaultAlertRules() returned empty rules")
|
|
}
|
|
|
|
// Check that default rules have required fields
|
|
for _, rule := range rules {
|
|
if rule.Name == "" {
|
|
t.Error("GetDefaultAlertRules() rule missing name")
|
|
}
|
|
if rule.Query == "" {
|
|
t.Error("GetDefaultAlertRules() rule missing query")
|
|
}
|
|
if rule.Severity == "" {
|
|
t.Error("GetDefaultAlertRules() rule missing severity")
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestAlertSeverity_Constants(t *testing.T) {
|
|
if SeverityCritical == "" {
|
|
t.Error("SeverityCritical constant is empty")
|
|
}
|
|
if SeverityWarning == "" {
|
|
t.Error("SeverityWarning constant is empty")
|
|
}
|
|
if SeverityInfo == "" {
|
|
t.Error("SeverityInfo constant is empty")
|
|
}
|
|
}
|
|
|
|
func TestAlertStatus_Constants(t *testing.T) {
|
|
if AlertStatusFiring == "" {
|
|
t.Error("AlertStatusFiring constant is empty")
|
|
}
|
|
if AlertStatusResolved == "" {
|
|
t.Error("AlertStatusResolved constant is empty")
|
|
}
|
|
if AlertStatusPending == "" {
|
|
t.Error("AlertStatusPending constant is empty")
|
|
}
|
|
}
|
|
|
|
// Note: Full integration tests would require:
|
|
// 1. A running Prometheus instance
|
|
// 2. Actual metrics being exported
|
|
// 3. Verification of alert firing and resolution
|
|
// 4. Testing of notification functions
|
|
//
|
|
// Example integration test structure:
|
|
// func TestMonitoringAlertingService_CheckAlerts_Integration(t *testing.T) {
|
|
// // Skip if Prometheus not available
|
|
// prometheusURL := os.Getenv("PROMETHEUS_URL")
|
|
// if prometheusURL == "" {
|
|
// t.Skip("Prometheus not configured")
|
|
// }
|
|
//
|
|
// config := MonitoringConfig{
|
|
// PrometheusURL: prometheusURL,
|
|
// Logger: zap.NewNop(),
|
|
// }
|
|
//
|
|
// service, err := NewMonitoringAlertingService(config)
|
|
// if err != nil {
|
|
// t.Fatalf("NewMonitoringAlertingService() error = %v", err)
|
|
// }
|
|
//
|
|
// // Add a test rule
|
|
// rule := AlertRule{
|
|
// Name: "test_rule",
|
|
// Query: "up",
|
|
// Threshold: 1.0,
|
|
// Severity: SeverityWarning,
|
|
// Enabled: true,
|
|
// }
|
|
// service.AddAlertRule(rule)
|
|
//
|
|
// ctx := context.Background()
|
|
// err = service.CheckAlerts(ctx)
|
|
// if err != nil {
|
|
// t.Fatalf("CheckAlerts() error = %v", err)
|
|
// }
|
|
//
|
|
// // Verify alerts were checked
|
|
// alerts := service.GetActiveAlerts()
|
|
// // Assert based on actual Prometheus metrics
|
|
// }
|
|
|