Files
ITWorx-Pulse-Public/internal/alert/operations_integration_test.go
ITWorx Pulse release export bd774932d5
Public source validation / validate (push) Failing after 3m8s
Publish ITWorx Pulse source
2026-09-03 02:09:19 +02:00

72 lines
3.0 KiB
Go

package alert
import (
"context"
"os"
"testing"
"time"
"github.com/itworx/pulse/internal/database"
)
func TestPostgreSQLAlertOperationsAreRevisionSafeAndRestartable(t *testing.T) {
dsn := os.Getenv("PULSE_TEST_DATABASE_URL")
if dsn == "" {
t.Skip("PULSE_TEST_DATABASE_URL is not set")
}
ctx, cancel := context.WithTimeout(context.Background(), 45*time.Second)
defer cancel()
pool, err := database.NewPool(ctx, database.Config{URL: dsn, MaxConns: 8, MinConns: 1})
if err != nil {
t.Fatal(err)
}
defer pool.Close()
if err := database.Migrate(ctx, pool); err != nil {
t.Fatal(err)
}
document, registry := validDocument(t)
document.Enabled = true
rules := Repository{Pool: pool, Registry: registry}
created, version, err := rules.Create(ctx, "operations-integration", document, "operations test")
if err != nil {
t.Fatal(err)
}
store := StateRepository{Pool: pool}
base := time.Date(2026, time.January, 4, 12, 0, 0, 0, time.UTC)
policy := Policy{PendingSeconds: 0, ResolveSeconds: 0, UnknownBehavior: UnknownRetain}
firing, _, _, err := store.ApplyObservation(ctx, StateInput{RuleID: created.ID, RuleVersionID: version.ID, Fingerprint: "operations:test", Policy: policy, Observation: observation(base, "evaluation-1", true)})
if err != nil {
t.Fatal(err)
}
if firing.State != StateFiring {
t.Fatalf("state = %s", firing.State)
}
ack, occurrence, duplicate, err := store.AcknowledgeRevision(ctx, firing.ID, "operator", "ack-operation-1", base.Add(time.Second), firing.Revision)
if err != nil || duplicate || ack.State != StateAcknowledged || occurrence.EventType != "acknowledge" {
t.Fatalf("ack result=%#v occurrence=%#v duplicate=%v err=%v", ack, occurrence, duplicate, err)
}
retry, _, duplicate, err := store.AcknowledgeRevision(ctx, firing.ID, "operator", "ack-operation-1", base.Add(time.Second), firing.Revision)
if err != nil || !duplicate || retry.Revision != ack.Revision {
t.Fatalf("ack retry=%#v duplicate=%v err=%v", retry, duplicate, err)
}
restarted := StateRepository{Pool: pool}
persisted, err := restarted.GetInstance(ctx, firing.ID)
if err != nil {
t.Fatal(err)
}
if persisted.State != StateAcknowledged || persisted.AcknowledgedBy != "operator" {
t.Fatalf("ack did not survive restart: %#v", persisted)
}
unack, occurrence, duplicate, err := restarted.Unacknowledge(ctx, firing.ID, "operator", "unack-operation-1", base.Add(2*time.Second), ack.Revision)
if err != nil || duplicate || unack.State != StateFiring || unack.AcknowledgedBy != "" || occurrence.EventType != "unacknowledge" {
t.Fatalf("unack result=%#v occurrence=%#v duplicate=%v err=%v", unack, occurrence, duplicate, err)
}
resolved, _, _, err := restarted.ApplyObservation(ctx, StateInput{RuleID: created.ID, RuleVersionID: version.ID, Fingerprint: "operations:test", Policy: policy, Observation: observation(base.Add(3*time.Second), "evaluation-2", false)})
if err != nil {
t.Fatal(err)
}
if resolved.State != StateResolved {
t.Fatalf("resolved state was lost after unacknowledge: %#v", resolved)
}
}