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) } }