- notifications priority ordering: money-critical reasons (webhooks, sweeps, refunds, gift-card, manual-refund failures) above routine - admin notifications page exposes the flood-cap suppressed count - adminnotify.go contract doc: removed stale 2FA reissue-fail site, current insert-site list Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai> Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
143 lines
5.2 KiB
Go
143 lines
5.2 KiB
Go
//go:build test
|
|
|
|
package adminnotify
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"testing"
|
|
|
|
"crussell/db"
|
|
"crussell/testutils/testdb"
|
|
)
|
|
|
|
func TestMain(m *testing.M) {
|
|
pool := testdb.CreateTestDatabase("crussell_test_adminnotify")
|
|
db.Conn = db.NewPoolProxy(pool)
|
|
code := m.Run()
|
|
testdb.DestroyTestDatabase(pool, "crussell_test_adminnotify")
|
|
os.Exit(code)
|
|
}
|
|
|
|
// TestMaxUnacknowledgedCriticalLogs_Value pins the exported flood-cap constant
|
|
// that every capped insert site folds into its SQL (changing it re-scopes every
|
|
// site at once, so the value is part of the shared contract).
|
|
func TestMaxUnacknowledgedCriticalLogs_Value(t *testing.T) {
|
|
if MaxUnacknowledgedCriticalLogs != 100 {
|
|
t.Errorf("expected MaxUnacknowledgedCriticalLogs to be 100, got %d", MaxUnacknowledgedCriticalLogs)
|
|
}
|
|
}
|
|
|
|
// TestCriticalLogsCapExceeded verifies the exported pre-check that logs a
|
|
// suppression: below the cap it reports false, at the cap true, and
|
|
// acknowledging rows re-arms it.
|
|
func TestCriticalLogsCapExceeded(t *testing.T) {
|
|
ctx := context.Background()
|
|
t.Cleanup(func() {
|
|
_, _ = db.Conn.Exec(ctx, "DELETE FROM admin_notifications WHERE reason = 'critical_payment_log'")
|
|
_, _ = db.Conn.Exec(ctx, "DELETE FROM admin_notification_suppressions WHERE reason = 'critical_payment_log'")
|
|
})
|
|
|
|
if CriticalLogsCapExceeded(ctx, db.Conn, "critical_payment_log") {
|
|
t.Fatal("expected the empty queue to be below the cap")
|
|
}
|
|
|
|
for i := 0; i < MaxUnacknowledgedCriticalLogs-1; i++ {
|
|
if _, err := db.Conn.Exec(ctx, `
|
|
INSERT INTO admin_notifications (reason, created_at)
|
|
VALUES ('critical_payment_log', NOW())
|
|
`); err != nil {
|
|
t.Fatalf("failed to insert row %d: %v", i, err)
|
|
}
|
|
}
|
|
if CriticalLogsCapExceeded(ctx, db.Conn, "critical_payment_log") {
|
|
t.Fatalf("expected %d unacknowledged rows to stay below the cap", MaxUnacknowledgedCriticalLogs-1)
|
|
}
|
|
|
|
if _, err := db.Conn.Exec(ctx, `
|
|
INSERT INTO admin_notifications (reason, created_at)
|
|
VALUES ('critical_payment_log', NOW())
|
|
`); err != nil {
|
|
t.Fatalf("failed to insert the cap row: %v", err)
|
|
}
|
|
if !CriticalLogsCapExceeded(ctx, db.Conn, "critical_payment_log") {
|
|
t.Fatalf("expected %d unacknowledged rows to be at the cap", MaxUnacknowledgedCriticalLogs)
|
|
}
|
|
|
|
if _, err := db.Conn.Exec(ctx, "UPDATE admin_notifications SET acknowledged_at = NOW() WHERE reason = 'critical_payment_log'"); err != nil {
|
|
t.Fatalf("failed to acknowledge the queue: %v", err)
|
|
}
|
|
if CriticalLogsCapExceeded(ctx, db.Conn, "critical_payment_log") {
|
|
t.Fatal("expected acknowledging the queue to re-arm inserts")
|
|
}
|
|
}
|
|
|
|
// TestCriticalLogsCapExceeded_RecordsSuppression pins FIX 3a: hitting the
|
|
// flood cap records the suppression in admin_notification_suppressions (the
|
|
// operator-facing "suppressed this cycle" counter) with a running count, and
|
|
// ActiveSuppressions reports it only while the underlying queue is still at the
|
|
// cap — acknowledging the queue down resets the visible count.
|
|
func TestCriticalLogsCapExceeded_RecordsSuppression(t *testing.T) {
|
|
ctx := context.Background()
|
|
t.Cleanup(func() {
|
|
_, _ = db.Conn.Exec(ctx, "DELETE FROM admin_notifications WHERE reason = 'critical_payment_log'")
|
|
_, _ = db.Conn.Exec(ctx, "DELETE FROM admin_notification_suppressions WHERE reason = 'critical_payment_log'")
|
|
})
|
|
|
|
// Below the cap no suppression is recorded.
|
|
for i := 0; i < MaxUnacknowledgedCriticalLogs-1; i++ {
|
|
if _, err := db.Conn.Exec(ctx, `
|
|
INSERT INTO admin_notifications (reason, created_at)
|
|
VALUES ('critical_payment_log', NOW())
|
|
`); err != nil {
|
|
t.Fatalf("failed to insert row %d: %v", i, err)
|
|
}
|
|
}
|
|
if supps, err := ActiveSuppressions(ctx, db.Conn); err != nil {
|
|
t.Fatalf("ActiveSuppressions failed below the cap: %v", err)
|
|
} else if len(supps) != 0 {
|
|
t.Fatalf("expected no suppression below the cap, got %d", len(supps))
|
|
}
|
|
|
|
// Fill to the cap, then hit it twice: each suppressed alert is recorded.
|
|
if _, err := db.Conn.Exec(ctx, `
|
|
INSERT INTO admin_notifications (reason, created_at)
|
|
VALUES ('critical_payment_log', NOW())
|
|
`); err != nil {
|
|
t.Fatalf("failed to insert the cap row: %v", err)
|
|
}
|
|
if !CriticalLogsCapExceeded(ctx, db.Conn, "critical_payment_log") {
|
|
t.Fatal("expected the queue to be at the cap")
|
|
}
|
|
if !CriticalLogsCapExceeded(ctx, db.Conn, "critical_payment_log") {
|
|
t.Fatal("expected the queue to stay at the cap")
|
|
}
|
|
|
|
supps, err := ActiveSuppressions(ctx, db.Conn)
|
|
if err != nil {
|
|
t.Fatalf("ActiveSuppressions failed: %v", err)
|
|
}
|
|
if len(supps) != 1 {
|
|
t.Fatalf("expected exactly 1 suppression record, got %d", len(supps))
|
|
}
|
|
if supps[0].Reason != "critical_payment_log" {
|
|
t.Errorf("expected reason critical_payment_log, got %s", supps[0].Reason)
|
|
}
|
|
if supps[0].SuppressedCount != 2 {
|
|
t.Errorf("expected suppressed_count 2, got %d", supps[0].SuppressedCount)
|
|
}
|
|
|
|
// Acknowledging the queue below the cap makes the suppression inactive, so
|
|
// the "this cycle" count resets.
|
|
if _, err := db.Conn.Exec(ctx, "UPDATE admin_notifications SET acknowledged_at = NOW() WHERE reason = 'critical_payment_log'"); err != nil {
|
|
t.Fatalf("failed to acknowledge the queue: %v", err)
|
|
}
|
|
supps, err = ActiveSuppressions(ctx, db.Conn)
|
|
if err != nil {
|
|
t.Fatalf("ActiveSuppressions failed after acknowledge: %v", err)
|
|
}
|
|
if len(supps) != 0 {
|
|
t.Errorf("expected the suppression to reset once the queue is below the cap, got %d", len(supps))
|
|
}
|
|
}
|