| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170 |
- """Tests unitaires pour les algorithmes de rétention (fonctions pures, sans Flask)."""
- from datetime import datetime, timedelta
- def days_ago(n):
- return datetime.utcnow() - timedelta(days=n)
- # ---------------------------------------------------------------------------
- # _retention_count
- # ---------------------------------------------------------------------------
- class TestRetentionCount:
- def test_supprime_les_plus_anciens(self):
- from retention import _retention_count
- archives = [
- "a_20260101.tar", "a_20260102.tar", "a_20260103.tar",
- "a_20260104.tar", "a_20260105.tar",
- ]
- assert _retention_count(archives, 3) == ["a_20260101.tar", "a_20260102.tar"]
- def test_moins_que_n_garde_tout(self):
- from retention import _retention_count
- archives = ["a_20260101.tar", "a_20260102.tar"]
- assert _retention_count(archives, 5) == []
- def test_exactement_n_garde_tout(self):
- from retention import _retention_count
- archives = ["a_20260101.tar", "a_20260102.tar", "a_20260103.tar"]
- assert _retention_count(archives, 3) == []
- def test_liste_vide(self):
- from retention import _retention_count
- assert _retention_count([], 5) == []
- def test_keep_1_supprime_tous_sauf_dernier(self):
- from retention import _retention_count
- archives = ["a_20260101.tar", "a_20260102.tar", "a_20260103.tar"]
- assert _retention_count(archives, 1) == ["a_20260101.tar", "a_20260102.tar"]
- # ---------------------------------------------------------------------------
- # _retention_daily
- # ---------------------------------------------------------------------------
- class TestRetentionDaily:
- def test_supprime_archives_trop_anciennes(self):
- from retention import _retention_daily
- archives = [
- f"a_{days_ago(35).strftime('%Y%m%d')}.tar",
- f"a_{days_ago(31).strftime('%Y%m%d')}.tar",
- f"a_{days_ago(10).strftime('%Y%m%d')}.tar",
- f"a_{days_ago(1).strftime('%Y%m%d')}.tar",
- ]
- result = _retention_daily(archives, 30)
- assert archives[0] in result
- assert archives[1] in result
- assert archives[2] not in result
- assert archives[3] not in result
- def test_deduplique_meme_jour(self):
- from retention import _retention_daily
- today = days_ago(0).strftime("%Y%m%d")
- a1 = f"a_{today}.tar"
- a2 = f"a_{today}_2.tar"
- archives = sorted([a1, a2])
- result = _retention_daily(archives, 30)
- assert len(result) == 1
- def test_garde_une_par_jour_dans_fenetre(self):
- from retention import _retention_daily
- archives = [f"a_{days_ago(i).strftime('%Y%m%d')}.tar" for i in range(9, -1, -1)]
- assert _retention_daily(archives, 30) == []
- def test_liste_vide(self):
- from retention import _retention_daily
- assert _retention_daily([], 30) == []
- def test_toutes_hors_fenetre(self):
- from retention import _retention_daily
- archives = [
- f"a_{days_ago(60).strftime('%Y%m%d')}.tar",
- f"a_{days_ago(45).strftime('%Y%m%d')}.tar",
- ]
- result = _retention_daily(archives, 30)
- assert set(result) == set(archives)
- # ---------------------------------------------------------------------------
- # _retention_gfs
- # ---------------------------------------------------------------------------
- class TestRetentionGFS:
- def test_liste_vide(self):
- from retention import _retention_gfs
- assert _retention_gfs([], {"daily": 7, "weekly": 4, "monthly": 12}) == []
- def test_tous_dans_fenetre_daily_gardes(self):
- from retention import _retention_gfs
- archives = [f"a_2026050{i}.tar" for i in range(1, 8)] # 7 archives
- assert _retention_gfs(archives, {"daily": 7, "weekly": 2, "monthly": 2}) == []
- def test_daily_supprime_au_dela_de_n(self):
- from retention import _retention_gfs
- # 15 archives consécutives (mai 01-15), daily=7
- # Le mensuel et hebdo tombent dans la fenêtre daily pour cet exemple
- archives = [f"a_202605{i:02d}.tar" for i in range(1, 16)]
- to_delete = _retention_gfs(archives, {"daily": 7, "weekly": 1, "monthly": 1})
- # Les 7 plus récentes (mai 9-15) sont gardées par daily
- for i in range(9, 16):
- assert f"a_202605{i:02d}.tar" not in to_delete
- def test_monthly_sauve_archive_ancienne(self):
- from retention import _retention_gfs
- # Archives sur 5 mois distincts
- archives = [
- "a_20260115.tar", # janvier (plus vieux)
- "a_20260215.tar", # février
- "a_20260315.tar", # mars
- "a_20260415.tar", # avril
- "a_20260510.tar", # mai
- "a_20260511.tar", # mai (plus récent)
- ]
- # daily=2 garde mai11+mai10, weekly=1 garde semaine de mai11,
- # monthly=3 garde mai→mai11, avr→avr15, mars→mars15
- # Supprimés : jan15, fév15
- to_delete = _retention_gfs(archives, {"daily": 2, "weekly": 1, "monthly": 3})
- assert "a_20260115.tar" in to_delete
- assert "a_20260215.tar" in to_delete
- assert "a_20260315.tar" not in to_delete
- assert "a_20260415.tar" not in to_delete
- assert "a_20260510.tar" not in to_delete
- assert "a_20260511.tar" not in to_delete
- assert len(to_delete) == 2
- def test_weekly_un_seul_representant_par_semaine(self):
- from retention import _retention_gfs
- # Semaine 19 (mai 04-10) + semaine 20 (mai 11) — vérifiées ISO
- # 2026-05-04 est un lundi (début de semaine 19)
- # 2026-05-11 est un lundi (début de semaine 20)
- archives = [
- "a_20260504.tar", "a_20260505.tar", "a_20260506.tar",
- "a_20260507.tar", "a_20260508.tar", "a_20260509.tar",
- "a_20260510.tar", "a_20260511.tar",
- ]
- # daily=3 : mai11, mai10, mai09
- # weekly=2 : sem20→mai11, sem19→mai10 (déjà en daily)
- # monthly=1 : mai→mai11
- # Keepers : {mai09, mai10, mai11}
- # Supprimés : {mai04, mai05, mai06, mai07, mai08}
- to_delete = _retention_gfs(archives, {"daily": 3, "weekly": 2, "monthly": 1})
- assert "a_20260511.tar" not in to_delete
- assert "a_20260510.tar" not in to_delete
- assert "a_20260509.tar" not in to_delete
- assert "a_20260504.tar" in to_delete
- assert "a_20260508.tar" in to_delete
- assert len(to_delete) == 5
- def test_une_archive_peut_couvrir_plusieurs_niveaux(self):
- from retention import _retention_gfs
- # Une seule archive : elle doit être conservée même avec daily=1, weekly=1, monthly=1
- archives = ["a_20260511.tar"]
- assert _retention_gfs(archives, {"daily": 1, "weekly": 1, "monthly": 1}) == []
- def test_defaults_utilises_si_config_vide(self):
- from retention import _retention_gfs
- # Config vide → defaults daily=7, weekly=4, monthly=12
- # Avec 3 archives, tout doit être gardé
- archives = ["a_20260509.tar", "a_20260510.tar", "a_20260511.tar"]
- assert _retention_gfs(archives, {}) == []
|