Netpulse_SasS/agent/internal/session/creds_test.go
byrsapty cd8d4c62ed Історія метрик, шаблони будь-яких перевірок, маршрути правил
Метрики збиралися в ts.samples і не показувалися ніде — побачити
зібране можна було лише через psql. Додано GET /devices/{id}/series і
/metrics: джерело (сирі дані, 5m, 1h) обирається за потрібним кроком,
бакетизація в БД, пропуск у даних лишається пропуском, а не лінією
через діру.

Знайдено живим прогоном: зонд працює рівно годину. CredentialTTL —
година, Credentials() свідомо не віддає прострочені (щоб не блокувати
облікові записи на пристроях), а поновлення не просив ніхто:
CredentialRequest є в контракті з Етапу 2, сервер його обробляє, агент
не надсилає. Будь-яка інсталяція припиняла збирати SNMP через годину
після старту й мовчала про це.

Шаблон описує перевірки будь-якого типу, не лише OID. Пачкою в один PDU
збираються тільки snmp.get; решта — елемент на чек, слід у
core.checks.template_item_key. Вбудований шаблон «Доступність (ICMP)».
Імпорт/експорт глобальний і поштучний, свій формат замість Zabbix-YAML.

Спільний розклад бекапів із перевизначенням на хості: прапорець
follows_default, а не порівняння значень — власний розклад може
випадково збігтися зі спільним.

Правило саме каже, куди йде його алерт: канали, тихі години, групи
хостів, повідомлення про відновлення. Канали правила перекривають
маршрути повністю.

Доступи до обладнання отримали свою сторінку: SSH-паролі й
SNMP-community заводяться, змінюються й видаляються з вебу. Секрет
назовні не повертається ніколи.

Дрібниці за скаргами: відступи в картках шаблонів, українська множина,
ручний ввід інтервалу опитування, підтвердження видалення з описом
наслідків замість «Ви впевнені?», помітні кнопки видалення замість
сірого ✕ у кутку.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-24 17:21:50 +03:00

73 lines
2.6 KiB
Go
Raw Permalink 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 session
import (
"context"
"testing"
"time"
npv1 "github.com/netpulse/netpulse/gen/go/netpulse/v1"
"google.golang.org/protobuf/types/known/timestamppb"
)
// Комплект доступів живе годину. Якщо його не поновлювати, зонд через
// цю годину замовкає: Credentials() свідомо не віддає прострочені, і
// кожна перевірка падає з «немає креденшелів».
//
// Перевіряємо саме рішення, а не мережу: підсовуємо пачку, що от-от
// протухне, і чекаємо на запит поновлення.
func TestSessionAsksToRenewExpiringCredentials(t *testing.T) {
s := &Session{}
out := make(chan *npv1.ControlUp, 4)
ctx := context.Background()
// Свіжа пачка — просити нічого.
s.applyCredentials(&npv1.CredentialBundle{
ExpiresAt: timestamppb.New(time.Now().Add(time.Hour)),
})
s.maybeRenewCredentials(ctx, out)
if len(out) != 0 {
t.Fatal("попросили поновлення на свіжій пачці")
}
// Лишилось менше запасу — час просити.
s.applyCredentials(&npv1.CredentialBundle{
ExpiresAt: timestamppb.New(time.Now().Add(credRenewBefore / 2)),
})
s.maybeRenewCredentials(ctx, out)
if len(out) != 1 {
t.Fatalf("очікували один запит, отримали %d", len(out))
}
msg := <-out
req := msg.GetCredentialRequest()
if req == nil {
t.Fatal("надіслано не CredentialRequest")
}
if req.Reason != "expiring" {
t.Fatalf("причина %q", req.Reason)
}
// Повторний тік одразу після запиту не має додати другого.
s.maybeRenewCredentials(ctx, out)
if len(out) != 0 {
t.Fatal("запит продубльовано, антиспам не спрацював")
}
// Уже прострочена пачка — причина інша.
s.applyCredentials(&npv1.CredentialBundle{
ExpiresAt: timestamppb.New(time.Now().Add(-time.Minute)),
})
s.maybeRenewCredentials(ctx, out)
if len(out) != 1 {
t.Fatalf("очікували запит на простроченій пачці, отримали %d", len(out))
}
if r := (<-out).GetCredentialRequest(); r == nil || r.Reason != "expired" {
t.Fatalf("причина %v", r)
}
// Пачка без TTL — поновлювати нічого.
s.applyCredentials(&npv1.CredentialBundle{})
s.maybeRenewCredentials(ctx, out)
if len(out) != 0 {
t.Fatal("попросили поновлення для пачки без терміну")
}
}