chore: build
This commit is contained in:
@@ -14,11 +14,8 @@ import (
|
||||
type fakeProv struct {
|
||||
mu sync.Mutex
|
||||
specs []demos.ProjectSpec
|
||||
suspended []string
|
||||
resumed []string
|
||||
tornDown []string
|
||||
provErr error
|
||||
resumeErr error
|
||||
provisioned chan struct{}
|
||||
}
|
||||
|
||||
@@ -37,25 +34,13 @@ func (f *fakeProv) TeardownProject(ns string) error {
|
||||
f.tornDown = append(f.tornDown, ns)
|
||||
return nil
|
||||
}
|
||||
func (f *fakeProv) SuspendProject(ns string) error {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
f.suspended = append(f.suspended, ns)
|
||||
return nil
|
||||
}
|
||||
func (f *fakeProv) ResumeProject(ns string) error {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
f.resumed = append(f.resumed, ns)
|
||||
return f.resumeErr
|
||||
}
|
||||
|
||||
var t0 = time.Date(2026, time.September, 20, 12, 0, 0, 0, time.UTC)
|
||||
|
||||
func newTestService(t *testing.T) (*Service, *fakeProv, *time.Time) {
|
||||
t.Helper()
|
||||
prov := newFakeProv()
|
||||
svc := NewService(NewMemStore(), prov, Config{Domain: "vitrine-omnex.club", Grace: 7 * 24 * time.Hour})
|
||||
svc := NewService(NewMemStore(), prov, Config{Domain: "vitrine-omnex.club"})
|
||||
now := t0
|
||||
svc.now = func() time.Time { return now }
|
||||
return svc, prov, &now
|
||||
@@ -109,9 +94,6 @@ func TestCreate_ExpiryIsCalendarMonths(t *testing.T) {
|
||||
if !p.ExpiresAt.Equal(want) {
|
||||
t.Errorf("months=%d : ExpiresAt=%v, attendu %v", months, p.ExpiresAt, want)
|
||||
}
|
||||
if !p.DeleteAt.Equal(want.Add(7 * 24 * time.Hour)) {
|
||||
t.Errorf("months=%d : DeleteAt=%v (grâce de 7 jours attendue)", months, p.DeleteAt)
|
||||
}
|
||||
if p.MonthsPurchased != months {
|
||||
t.Errorf("MonthsPurchased=%d, attendu %d", p.MonthsPurchased, months)
|
||||
}
|
||||
@@ -196,9 +178,6 @@ func TestExtend_AddsMonthsFromCurrentExpiry(t *testing.T) {
|
||||
if got.MonthsPurchased != 15 {
|
||||
t.Errorf("MonthsPurchased=%d, attendu 15", got.MonthsPurchased)
|
||||
}
|
||||
if !got.DeleteAt.Equal(want.Add(7 * 24 * time.Hour)) {
|
||||
t.Errorf("DeleteAt non recalculé : %v", got.DeleteAt)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtend_MonthsBounds(t *testing.T) {
|
||||
@@ -222,89 +201,61 @@ func TestExtend_UnknownProject(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestExpiration_SuspendsAtExpiryThenDeletesAfterGrace(t *testing.T) {
|
||||
func TestExpiration_DeletesAtExpiry(t *testing.T) {
|
||||
svc, prov, now := newTestService(t)
|
||||
p := createReady(t, svc, prov, validInput()) // 3 mois
|
||||
|
||||
// Avant l'échéance : rien ne bouge.
|
||||
*now = p.ExpiresAt.Add(-time.Hour)
|
||||
svc.expireOverdue()
|
||||
if len(prov.suspended) != 0 {
|
||||
t.Fatal("suspension avant l'échéance")
|
||||
if len(prov.tornDown) != 0 {
|
||||
t.Fatal("suppression avant l'échéance")
|
||||
}
|
||||
|
||||
// À l'échéance : suspendu, jamais supprimé.
|
||||
// À l'échéance : supprimé, sans délai de grâce.
|
||||
*now = p.ExpiresAt.Add(time.Minute)
|
||||
svc.expireOverdue()
|
||||
got, _ := svc.Get(p.ID)
|
||||
if got.Status != StatusSuspended || got.SuspendedAt == nil {
|
||||
t.Fatalf("statut %s, attendu suspended", got.Status)
|
||||
}
|
||||
if len(prov.suspended) != 1 || len(prov.tornDown) != 0 {
|
||||
t.Fatalf("suspendus=%v supprimés=%v", prov.suspended, prov.tornDown)
|
||||
}
|
||||
|
||||
// Pendant la grâce : toujours suspendu, données conservées.
|
||||
*now = p.ExpiresAt.Add(6 * 24 * time.Hour)
|
||||
svc.expireOverdue()
|
||||
if len(prov.tornDown) != 0 {
|
||||
t.Fatal("suppression pendant le délai de grâce")
|
||||
}
|
||||
if len(prov.suspended) != 1 {
|
||||
t.Errorf("suspension répétée : %v", prov.suspended)
|
||||
}
|
||||
|
||||
// Grâce dépassée : suppression définitive.
|
||||
*now = p.DeleteAt.Add(time.Minute)
|
||||
svc.expireOverdue()
|
||||
got, _ = svc.Get(p.ID)
|
||||
if got.Status != StatusDeleted || len(prov.tornDown) != 1 || prov.tornDown[0] != p.Namespace {
|
||||
t.Errorf("statut %s, supprimés=%v", got.Status, prov.tornDown)
|
||||
}
|
||||
|
||||
// Déjà supprimé : la boucle ne rappelle pas le cluster.
|
||||
svc.expireOverdue()
|
||||
if len(prov.tornDown) != 1 {
|
||||
t.Errorf("teardown répété : %v", prov.tornDown)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtend_ResumesSuspendedProject(t *testing.T) {
|
||||
func TestExtend_BeforeExpiryKeepsProject(t *testing.T) {
|
||||
svc, prov, now := newTestService(t)
|
||||
p := createReady(t, svc, prov, validInput())
|
||||
|
||||
*now = p.ExpiresAt.Add(2 * 24 * time.Hour)
|
||||
svc.expireOverdue()
|
||||
|
||||
*now = p.ExpiresAt.Add(-time.Hour)
|
||||
got, err := svc.Extend(p.ID, 1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got.Status != StatusReady || got.SuspendedAt != nil {
|
||||
t.Errorf("statut %s suspended_at=%v, attendu ready sans suspension", got.Status, got.SuspendedAt)
|
||||
}
|
||||
if len(prov.resumed) != 1 || prov.resumed[0] != p.Namespace {
|
||||
t.Errorf("relances=%v", prov.resumed)
|
||||
}
|
||||
// Échéance en retard : le nouveau mois part de maintenant, pas de l'ancienne échéance.
|
||||
if want := now.AddDate(0, 1, 0); !got.ExpiresAt.Equal(want) {
|
||||
if want := p.ExpiresAt.AddDate(0, 1, 0); !got.ExpiresAt.Equal(want) {
|
||||
t.Errorf("ExpiresAt=%v, attendu %v", got.ExpiresAt, want)
|
||||
}
|
||||
|
||||
// Renouvelé : la boucle ne doit plus le suspendre.
|
||||
// L'ancienne échéance est passée : le projet renouvelé ne doit pas être supprimé.
|
||||
*now = p.ExpiresAt.Add(time.Minute)
|
||||
svc.expireOverdue()
|
||||
if len(prov.suspended) != 1 {
|
||||
t.Errorf("re-suspension d'un projet renouvelé : %v", prov.suspended)
|
||||
if len(prov.tornDown) != 0 {
|
||||
t.Errorf("suppression d'un projet renouvelé : %v", prov.tornDown)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtend_ResumeFailureKeepsProjectSuspended(t *testing.T) {
|
||||
func TestExtend_DeletedProjectNotExtendable(t *testing.T) {
|
||||
svc, prov, now := newTestService(t)
|
||||
p := createReady(t, svc, prov, validInput())
|
||||
*now = p.ExpiresAt.Add(time.Hour)
|
||||
*now = p.ExpiresAt.Add(time.Minute)
|
||||
svc.expireOverdue()
|
||||
|
||||
prov.resumeErr = errors.New("api k8s indisponible")
|
||||
if _, err := svc.Extend(p.ID, 1); err == nil {
|
||||
t.Fatal("erreur attendue")
|
||||
}
|
||||
got, _ := svc.Get(p.ID)
|
||||
if got.Status != StatusSuspended || !got.ExpiresAt.Equal(p.ExpiresAt) {
|
||||
t.Errorf("l'échec de relance a modifié le projet : %s %v", got.Status, got.ExpiresAt)
|
||||
if _, err := svc.Extend(p.ID, 1); !errors.Is(err, ErrNotExtendable) {
|
||||
t.Errorf("erreur %v, attendu ErrNotExtendable", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -326,19 +277,3 @@ func TestDelete_IsIdempotentAndImmediate(t *testing.T) {
|
||||
t.Errorf("erreur %v, attendu ErrNotFound", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestZeroGraceSuspendsThenDeletesNextTick(t *testing.T) {
|
||||
prov := newFakeProv()
|
||||
svc := NewService(NewMemStore(), prov, Config{})
|
||||
now := t0
|
||||
svc.now = func() time.Time { return now }
|
||||
p := createReady(t, svc, prov, validInput())
|
||||
|
||||
now = p.ExpiresAt.Add(time.Minute)
|
||||
svc.expireOverdue() // suspension
|
||||
svc.expireOverdue() // DeleteAt == ExpiresAt : déjà dépassé
|
||||
got, _ := svc.Get(p.ID)
|
||||
if got.Status != StatusDeleted {
|
||||
t.Errorf("statut %s, attendu deleted (grâce nulle)", got.Status)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user