[FIX] test long cache : ne pas compter le refus d'un miroir en faute
The verdict counted every upstream line of an already seen package as a file the cache failed to serve. A mirror that publishes the distribution under another path answers 404 to each package; the client moves to the next mirror, which the cache serves from disk. The 404 goes upstream on both VMs without anything missing, and an openSUSE campaign failed on six such lines. An upstream answer of 400 or more is now reported apart and not counted. Checked: a test for the refusal, and one where a delivered 200 still fails. --- FR --- Le verdict comptait toute ligne d'amont d'un paquet déjà vu comme un fichier que le cache n'a pas servi. Un miroir qui publie la distribution sous un autre chemin répond 404 à chaque paquet ; le client passe au miroir suivant, que le cache sert du disque. Le 404 repart à l'amont aux deux VM sans que rien ne manque, et une campagne openSUSE échouait sur six de ces lignes. Une réponse d'amont de 400 ou plus est désormais signalée à part, sans compter. Vérifié : un test du refus, et un où un 200 livré échoue toujours. Assisted-by: Claude Opus 5
This commit is contained in:
parent
433fe753c3
commit
156956a1f0
2 changed files with 57 additions and 4 deletions
|
|
@ -828,7 +828,24 @@ def verdict(premier, second, journal):
|
|||
vues1 = {l["url"] for l in p1}
|
||||
|
||||
# Le critère : ce que les DEUX ont demandé ne doit pas être ressorti.
|
||||
fautes = [l for l in p2 if l["url"] in vues1 and l.get("upstream")]
|
||||
#
|
||||
# Un REFUS de l'amont n'en est pas : un miroir qui range sa distribution
|
||||
# sous un autre chemin répond 404 à chaque paquet, le client passe au
|
||||
# miroir suivant, et le cache sert celui-là du disque. Il n'a rien livré
|
||||
# que le cache aurait dû garder — un 404 figé masquerait le fichier publié
|
||||
# ensuite. Le compter en faute fait échouer une mesure où tout a été servi.
|
||||
refus = [
|
||||
l
|
||||
for l in p2
|
||||
if l.get("upstream")
|
||||
and isinstance(l.get("status"), int)
|
||||
and l["status"] >= 400
|
||||
]
|
||||
fautes = [
|
||||
l
|
||||
for l in p2
|
||||
if l["url"] in vues1 and l.get("upstream") and l not in refus
|
||||
]
|
||||
# Ce que la seconde a découvert seule : légitime sur une publication
|
||||
# continue, montré pour que personne ne prenne un miroir qui bouge pour
|
||||
# une panne de cache.
|
||||
|
|
@ -901,6 +918,12 @@ def verdict(premier, second, journal):
|
|||
)
|
||||
for l in neufs[:5]:
|
||||
dire(f" + {l['url'].rsplit('/', 1)[-1]}", journal)
|
||||
if refus:
|
||||
dire(
|
||||
f" ({len(refus)} refus de l'amont, non comptés : un miroir a"
|
||||
" répondu par une erreur, le fichier est venu d'ailleurs)",
|
||||
journal,
|
||||
)
|
||||
if fautes:
|
||||
dire("", journal)
|
||||
dire(
|
||||
|
|
|
|||
|
|
@ -42,20 +42,25 @@ def charger():
|
|||
QC = charger()
|
||||
|
||||
|
||||
def ligne(url, upstream, octets=1000, issue="stored", classe="immutable"):
|
||||
def ligne(
|
||||
url, upstream, octets=1000, issue="stored", classe="immutable", statut=None
|
||||
):
|
||||
"""Une ligne du journal d'accès du cache.
|
||||
|
||||
La CLASSE est ce que le filtre lit désormais : c'est le cache qui décide
|
||||
si un fichier est figé, et la tenir ici en dur revenait à laisser un index
|
||||
se faire passer pour un paquet.
|
||||
se faire passer pour un paquet. Le STATUT n'est écrit que s'il est donné.
|
||||
"""
|
||||
return {
|
||||
l = {
|
||||
"url": url,
|
||||
"upstream": upstream,
|
||||
"bytes": octets,
|
||||
"outcome": issue,
|
||||
"class": classe,
|
||||
}
|
||||
if statut is not None:
|
||||
l["status"] = statut
|
||||
return l
|
||||
|
||||
|
||||
PAQUET_A = (
|
||||
|
|
@ -155,6 +160,31 @@ class TestVerdict(unittest.TestCase):
|
|||
de mesure, donc pas de succès."""
|
||||
self.assertFalse(QC.verdict([ligne(PAQUET_A, True)], [], None))
|
||||
|
||||
def test_un_miroir_qui_refuse_ne_fait_pas_echouer(self):
|
||||
"""Un miroir rangé sous un autre chemin répond 404 à chaque paquet ; le
|
||||
client prend le fichier ailleurs, et le cache le sert du disque. Le
|
||||
404 repart à l'amont aux deux VM sans que rien n'ait manqué."""
|
||||
mauvais = PAQUET_A.replace("miroir.example", "autre.example/x")
|
||||
premier = [
|
||||
ligne(mauvais, True, octets=153, issue="fetched", statut=404),
|
||||
ligne(PAQUET_A, True, statut=200),
|
||||
]
|
||||
second = [
|
||||
ligne(mauvais, True, octets=153, issue="fetched", statut=404),
|
||||
ligne(PAQUET_A, False, issue="hit", statut=200),
|
||||
]
|
||||
self.assertTrue(
|
||||
QC.verdict(premier, second, None),
|
||||
"le 404 d'un miroir a été compté comme un paquet ressorti",
|
||||
)
|
||||
|
||||
def test_un_paquet_livre_deux_fois_reste_une_faute(self):
|
||||
"""Le refus est écarté, pas la réponse livrée : un 200 déjà vu qui
|
||||
repart à l'amont fait toujours échouer."""
|
||||
premier = [ligne(PAQUET_A, True, statut=200)]
|
||||
second = [ligne(PAQUET_A, True, statut=200)]
|
||||
self.assertFalse(QC.verdict(premier, second, None))
|
||||
|
||||
def test_le_melange(self):
|
||||
premier = [ligne(PAQUET_A, True), ligne(PAQUET_B, True)]
|
||||
second = [
|
||||
|
|
|
|||
Loading…
Reference in a new issue