From 55e865ecb8a7abfe62836c783334016a96c96e3d Mon Sep 17 00:00:00 2001 From: rcourtman <8825017+rcourtman@users.noreply.github.com> Date: Wed, 7 Oct 2026 17:30:18 +0100 Subject: [PATCH] Move the config save regressions to the end of their file main added TestUpdateConfigKeepsLowTriggerClearBelowTrigger (#2678) at the spot these tests were inserted, with its own import block, so the PR no longer merged. The tests now sit at the end of the file and the concurrency test waits on a channel instead of sync.WaitGroup, leaving the import line as main has it. --- internal/alerts/config_validation_test.go | 103 +++++++++++----------- 1 file changed, 51 insertions(+), 52 deletions(-) diff --git a/internal/alerts/config_validation_test.go b/internal/alerts/config_validation_test.go index d83f7016dd..8780dbd719 100644 --- a/internal/alerts/config_validation_test.go +++ b/internal/alerts/config_validation_test.go @@ -1,9 +1,6 @@ package alerts -import ( - "sync" - "testing" -) +import "testing" func TestUpdateConfigNormalizesBackupIndicatorHours(t *testing.T) { t.Run("non-positive values default", func(t *testing.T) { @@ -86,6 +83,49 @@ func TestUpdateConfigNormalizesFlappingSettings(t *testing.T) { } } +func TestUpdateConfigNormalizesExactEscalationRoutingAndRepeatPolicy(t *testing.T) { + m := newTestManager(t) + cfg := m.GetConfig() + cfg.Schedule.Escalation = EscalationConfig{ + Enabled: true, + RepeatCritical: true, + RepeatEvery: 1, + Levels: []EscalationLevel{ + { + After: -1, + Notify: "WEBHOOKS", + DestinationIDs: []string{" webhook:pager ", "email", "webhook:pager", "https://secret.example"}, + }, + {After: 181, Notify: "email"}, + }, + } + + m.UpdateConfig(cfg) + + got := m.GetConfig().Schedule.Escalation + if got.RepeatEvery != DefaultEscalationRepeatMinutes { + t.Fatalf("repeat interval = %d, want %d", got.RepeatEvery, DefaultEscalationRepeatMinutes) + } + if got.Levels[0].Notify != "webhook" { + t.Fatalf("legacy target = %q, want webhook", got.Levels[0].Notify) + } + if got.Levels[0].After != MinEscalationDelayMinutes { + t.Fatalf("minimum escalation delay = %d, want %d", got.Levels[0].After, MinEscalationDelayMinutes) + } + if got.Levels[1].After != MaxEscalationDelayMinutes { + t.Fatalf("maximum escalation delay = %d, want %d", got.Levels[1].After, MaxEscalationDelayMinutes) + } + wantIDs := []string{"webhook:pager", "email"} + if len(got.Levels[0].DestinationIDs) != len(wantIDs) { + t.Fatalf("destination IDs = %v, want %v", got.Levels[0].DestinationIDs, wantIDs) + } + for index, want := range wantIDs { + if got.Levels[0].DestinationIDs[index] != want { + t.Fatalf("destination IDs = %v, want %v", got.Levels[0].DestinationIDs, wantIDs) + } + } +} + // The thresholds page sends no flapping, alert TTL or custom-rule keys. A save // through ApplyConfigUpdate must leave those settings as stored, also after // the merged config is normalized in place. @@ -140,17 +180,19 @@ func TestApplyConfigUpdateKeepsConcurrentPartialUpdates(t *testing.T) { base.MaxAlertAgeDays = 0 m.UpdateConfig(base) - var wg sync.WaitGroup - for _, body := range []string{`{"flappingEnabled": true}`, `{"maxAlertAgeDays": 9}`} { - wg.Add(1) + bodies := []string{`{"flappingEnabled": true}`, `{"maxAlertAgeDays": 9}`} + done := make(chan struct{}, len(bodies)) + for _, body := range bodies { go func(body string) { - defer wg.Done() + defer func() { done <- struct{}{} }() if _, err := m.ApplyConfigUpdate([]byte(body)); err != nil { t.Errorf("ApplyConfigUpdate(%s): %v", body, err) } }(body) } - wg.Wait() + for range bodies { + <-done + } got := m.GetConfig() if !got.FlappingEnabled || got.MaxAlertAgeDays != 9 { @@ -159,46 +201,3 @@ func TestApplyConfigUpdateKeepsConcurrentPartialUpdates(t *testing.T) { } } } - -func TestUpdateConfigNormalizesExactEscalationRoutingAndRepeatPolicy(t *testing.T) { - m := newTestManager(t) - cfg := m.GetConfig() - cfg.Schedule.Escalation = EscalationConfig{ - Enabled: true, - RepeatCritical: true, - RepeatEvery: 1, - Levels: []EscalationLevel{ - { - After: -1, - Notify: "WEBHOOKS", - DestinationIDs: []string{" webhook:pager ", "email", "webhook:pager", "https://secret.example"}, - }, - {After: 181, Notify: "email"}, - }, - } - - m.UpdateConfig(cfg) - - got := m.GetConfig().Schedule.Escalation - if got.RepeatEvery != DefaultEscalationRepeatMinutes { - t.Fatalf("repeat interval = %d, want %d", got.RepeatEvery, DefaultEscalationRepeatMinutes) - } - if got.Levels[0].Notify != "webhook" { - t.Fatalf("legacy target = %q, want webhook", got.Levels[0].Notify) - } - if got.Levels[0].After != MinEscalationDelayMinutes { - t.Fatalf("minimum escalation delay = %d, want %d", got.Levels[0].After, MinEscalationDelayMinutes) - } - if got.Levels[1].After != MaxEscalationDelayMinutes { - t.Fatalf("maximum escalation delay = %d, want %d", got.Levels[1].After, MaxEscalationDelayMinutes) - } - wantIDs := []string{"webhook:pager", "email"} - if len(got.Levels[0].DestinationIDs) != len(wantIDs) { - t.Fatalf("destination IDs = %v, want %v", got.Levels[0].DestinationIDs, wantIDs) - } - for index, want := range wantIDs { - if got.Levels[0].DestinationIDs[index] != want { - t.Fatalf("destination IDs = %v, want %v", got.Levels[0].DestinationIDs, wantIDs) - } - } -}