Netpulse_SasS/server/internal/store/alerts_rule_update_test.go
byrsapty cedf1d261d
All checks were successful
CI / hygiene (push) Successful in 9s
CI / web (push) Successful in 1m18s
CI / server (push) Successful in 1m50s
CI / agent (push) Successful in 1m2s
Ескалації: журнал більше не бреше, ack не воскрешає драбину
Три вади, знайдені рецензією, яких щасливий шлях показати не міг:

* outcome='sent' писався до доставки; помилка читання каналів клала в
  кеш порожню мапу й з'їдала всі сходинки кабінету за тік — усі зі
  слідом «надіслано». Канали тепер читаються до просування стану,
  журнал пишеться після доставки, з правдою.
* UPDATE не мав stopped_at IS NULL — підтвердження алерту посеред
  партії не рятувало людину від дзвінка.
* час брався раз на партію.

Плюс суміжне: UpdateRule не гасив алертів вимкненого правила, сервер
домислював enabled на оновленні, channel_ids сходинок не звірялись із
каналами кабінету (зокрема чужого).

І scripts/dbtest.sh — тести проти бази перестали мовчки пропускатись.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-28 17:20:18 +03:00

92 lines
5.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package store
import "testing"
// Рішення про прапорець «увімкнено» при правці правила.
//
// ЧОГО ЦЕЙ ФАЙЛ БОЇТЬСЯ. Обидві вади, які він закриває, тихі: система
// після них не падає й нічого не пише в журнал. Видно їх тільки з
// телефона о третій ночі — або, що гірше, не видно взагалі.
//
// 1. Правило вимкнули через PUT (форма надсилає правило цілком) — і
// його алерти лишились у firing НАЗАВЖДИ: вимкнене правило випадає
// з ActiveRules, тобто ResolveMissing за ним більше не біжить і
// погасити їх немає кому. Драбина ескалації при цьому працює далі —
// з повторами вона будить людей тижнями за проблемою, за якою вже
// ніхто не стежить.
// 2. Форма не надсилала `enabled` взагалі, а сервер читав відсутність
// поля як `true`. Тобто відкрити вимкнене правило, поправити в ньому
// будь-що й зберегти — означало мовчки його ввімкнути.
//
// Перевіряється чистою функцією, а не базою, з тієї ж причини, що й
// planRestore поруч: на живій базі кожен із чотирьох випадків — це
// окремий стенд із правилом, алертом і драбиною, а ціна помилки в
// будь-якому з них платиться не тут і не одразу.
func TestPlanRuleEnabledResolvesOnDisable(t *testing.T) {
// Головний випадок: увімкнене правило вимикають правкою. Алерти
// треба гасити тут же — іншої нагоди в них не буде.
off := false
enabled, resolve := planRuleEnabled(true, &off)
if enabled {
t.Fatal("правило мало лишитись вимкненим")
}
if !resolve {
t.Fatal("алерти не гасяться: після вимкнення їх нікому закрити, " +
"і драбина ескалації будитиме людей за ними далі")
}
}
func TestPlanRuleEnabledKeepsAlertsWhenStillDisabled(t *testing.T) {
// Правку вимкненого правила зберігають повторно. Гасити нема чого:
// його алерти закрив той перехід, який його вимкнув, а зайвий
// прохід — це ще один запис у event_outbox на кожне збереження.
off := false
enabled, resolve := planRuleEnabled(false, &off)
if enabled {
t.Fatal("правило мало лишитись вимкненим")
}
if resolve {
t.Fatal("гасити нічого: правило вже було вимкнене до правки")
}
}
func TestPlanRuleEnabledKeepsAlertsWhenEnabling(t *testing.T) {
// Увімкнення — не привід чіпати алерти: рішення про них ухвалить
// найближчий тік движка, і саме він знає, чи проблема ще триває.
on := true
enabled, resolve := planRuleEnabled(false, &on)
if !enabled {
t.Fatal("правило мало ввімкнутись")
}
if resolve {
t.Fatal("увімкнення гасить алерти — цього не мало статись")
}
}
func TestPlanRuleEnabledLeavesDisabledRuleAlone(t *testing.T) {
// ВАДА Б. Поля `enabled` у тілі немає — саме так виглядав кожен
// PUT із форми правил. Вимкнене правило мусить лишитись вимкненим:
// «поля не було» означає «не чіпайте», а не «вмикайте».
enabled, resolve := planRuleEnabled(false, nil)
if enabled {
t.Fatal("правка без поля `enabled` увімкнула вимкнене правило — " +
"людина дізнається про це зі сповіщення, а не з форми")
}
if resolve {
t.Fatal("гасити нічого: стан не змінився")
}
}
func TestPlanRuleEnabledLeavesEnabledRuleAlone(t *testing.T) {
// Другий бік тієї ж пари, і без нього перший нічого не доводить:
// функція, яка завжди повертає false, пройшла б попередній тест.
enabled, resolve := planRuleEnabled(true, nil)
if !enabled {
t.Fatal("правка без поля `enabled` вимкнула увімкнене правило — " +
"це мовчазна зупинка моніторингу")
}
if resolve {
t.Fatal("гасити нічого: стан не змінився")
}
}