Files
Bridge-and-Join-s/internal/lkgateway/licensewarn_test.go
T
zuevav 42f5883b4a Лицензия: предупреждения заранее об окончании и о смене версий внешних систем
За 30, 14, 7 и 1 день до окончания договора (офлайн-ключ или застрявшее продление — до конца
ключа) bj шлёт уведомление: что продолжит работать, а что отключится. Каждый порог — один раз,
при продлении договора отсчёт заново; проверка раз в час в licenseLoop.

После каждого опроса версий bj запоминает версии внешних систем (МНП QUIK, ИШ, DEPO, экспортёр
ARQA, «Валидата», Java, PostgreSQL, ОС). Если обновления bj недоступны и версия изменилась —
уведомление, что совместимость с новой версией не гарантируется.

Решение: после окончания лицензии цикл QUIK МНП и личный кабинет продолжают работать.
Состояние — /var/lib/bj/.bj/license-watch.json.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 12:19:47 +03:00

93 lines
4.2 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 lkgateway
import (
"strings"
"testing"
"time"
)
func TestLicenseEnd(t *testing.T) {
now := time.Date(2027, 8, 20, 12, 0, 0, 0, time.UTC)
contract := time.Date(2027, 9, 14, 0, 0, 0, 0, time.UTC)
key := now.Add(55 * 24 * time.Hour)
// Онлайн-ключ продлевается — важна дата договора.
st := LicenseStatus{Valid: true, Online: true, ContractUntil: contract, ExpiresAt: key}
if end, what := licenseEnd(st, now.Add(-time.Hour), now); !end.Equal(contract) || what != "договор" {
t.Fatalf("онлайн с договором: %v %q", end, what)
}
// Онлайн без договора и продление идёт — предупреждать не о чем.
st = LicenseStatus{Valid: true, Online: true, ExpiresAt: key}
if end, _ := licenseEnd(st, now.Add(-time.Hour), now); !end.IsZero() {
t.Fatalf("бессрочная онлайн-лицензия: %v", end)
}
// Продление не проходит 3 суток — считаем до конца ключа.
st = LicenseStatus{Valid: true, Online: true, ExpiresAt: now.Add(10 * 24 * time.Hour), ContractUntil: contract}
if end, what := licenseEnd(st, now.Add(-72*time.Hour), now); !end.Equal(st.ExpiresAt) || !strings.HasPrefix(what, "ключ") {
t.Fatalf("продление не проходит: %v %q", end, what)
}
// Офлайн-ключ — до конца ключа.
st = LicenseStatus{Valid: true, ExpiresAt: key}
if end, what := licenseEnd(st, time.Time{}, now); !end.Equal(key) || what != "ключ" {
t.Fatalf("офлайн: %v %q", end, what)
}
// Уже не действует — без предупреждения заранее.
if end, _ := licenseEnd(LicenseStatus{ContractUntil: contract}, now, now); !end.IsZero() {
t.Fatal("недействующая лицензия")
}
}
func TestExpiryStep(t *testing.T) {
end := "2027-09-14"
cases := []struct {
days int
w licenseWatch
expect int
}{
{45, licenseWatch{}, 0},
{30, licenseWatch{}, 30},
{30, licenseWatch{EndDate: end, WarnedDays: 30}, 0},
{20, licenseWatch{EndDate: end, WarnedDays: 30}, 0},
{14, licenseWatch{EndDate: end, WarnedDays: 30}, 14},
{5, licenseWatch{}, 7}, // первый запуск за 5 дней — одно уведомление, без пачки 30/14/7
{1, licenseWatch{EndDate: end, WarnedDays: 7}, 1},
{0, licenseWatch{EndDate: end, WarnedDays: 1}, 0},
{10, licenseWatch{EndDate: "2026-09-14", WarnedDays: 1}, 14}, // договор продлили — заново
}
for _, c := range cases {
if got := expiryStep(c.days, c.w, end); got != c.expect {
t.Errorf("осталось %d, %+v: порог %d, ожидался %d", c.days, c.w, got, c.expect)
}
}
if ruDays(1) != "1 день" || ruDays(3) != "3 дня" || ruDays(11) != "11 дней" || ruDays(22) != "22 дня" || ruDays(14) != "14 дней" {
t.Errorf("склонение: %s %s %s %s %s", ruDays(1), ruDays(3), ruDays(11), ruDays(22), ruDays(14))
}
}
func TestVersionChanges(t *testing.T) {
w := licenseWatch{Versions: map[string]string{}}
items := []SystemVersion{
{Key: "quik-mnp", Title: "QUIK — Модуль неторговых поручений", Version: "21.4.1"},
{Key: "bj-server", Title: "Ядро bj", Version: "0.1.0"},
{Key: "depo", Title: "Fancy DEPO", Version: ""},
}
if ch := versionChanges(&w, items, false); len(ch) != 0 {
t.Fatalf("первый опрос только запоминает: %v", ch)
}
if w.Versions["quik-mnp"] != "21.4.1" || w.Versions["bj-server"] != "" || w.Versions["depo"] != "" {
t.Fatalf("запомнены: %v", w.Versions)
}
items[0].Version = "21.5.0"
if ch := versionChanges(&w, items, true); len(ch) != 0 {
t.Fatalf("при доступных обновлениях без уведомления: %v", ch)
}
items[0].Version = "21.6.0"
ch := versionChanges(&w, items, false)
if len(ch) != 1 || ch[0] != "QUIK — Модуль неторговых поручений: 21.5.0 → 21.6.0" {
t.Fatalf("изменение при закрытых обновлениях: %v", ch)
}
if ch := versionChanges(&w, items, false); len(ch) != 0 {
t.Fatalf("повторно о той же версии не уведомляем: %v", ch)
}
}