[FIX] test long cache : ne compter vue qu'une URL vraiment livrée
Un même paquet vit sous deux chemins selon le miroir, et la clé du magasin porte le chemin : la première VM peut recevoir « 504 » sur l'un — amont jugé muet — puis être servie du disque par l'autre. Rien n'entre alors au magasin sous le premier chemin, et le téléchargement honnête de la seconde y était compté en faute, faisant échouer une mesure où le cache avait tout servi. Une URL n'est « déjà vue » que si la première VM en a obtenu les octets ; un statut absent vaut livré, les journaux d'avant ne l'écrivant pas toujours. Vérifié : trois tests, deux mutations attrapées. --- EN --- One package lives under two paths depending on the mirror, and the store key carries the path: the first VM can get « 504 » on one — upstream judged mute — then be served from disk by the other. Nothing enters the store under the first path, and the second VM's honest download was counted a fault there, failing a measurement where the cache had served everything. A URL is « already seen » only if the first VM obtained its bytes; a missing status counts as delivered, older logs not always writing it. Checked: three tests, two mutations caught. Assisted-by: Claude Opus 5
This commit is contained in:
parent
96ae77485c
commit
416032fe7b
2 changed files with 56 additions and 8 deletions
|
|
@ -826,11 +826,28 @@ def paquets_seulement(lignes):
|
||||||
return [l for l in lignes if l.get("class") == "immutable"]
|
return [l for l in lignes if l.get("class") == "immutable"]
|
||||||
|
|
||||||
|
|
||||||
|
def livre(ligne):
|
||||||
|
"""La réponse a-t-elle livré le fichier ?
|
||||||
|
|
||||||
|
Un statut absent vaut oui : les journaux d'avant ne l'écrivaient pas
|
||||||
|
toujours, et le prendre pour un échec ferait disparaître des mesures
|
||||||
|
entières. Tout ce qui n'est pas une livraison — refus d'un miroir, « 504 »
|
||||||
|
d'un amont jugé muet — ne compte ni comme faute ni comme fichier déjà vu.
|
||||||
|
"""
|
||||||
|
statut = ligne.get("status")
|
||||||
|
return not isinstance(statut, int) or 200 <= statut < 400
|
||||||
|
|
||||||
|
|
||||||
def verdict(premier, second, journal):
|
def verdict(premier, second, journal):
|
||||||
"""Le critère, puis la manchette. Rend True si le cache a servi."""
|
"""Le critère, puis la manchette. Rend True si le cache a servi."""
|
||||||
p1 = paquets_seulement(premier)
|
p1 = paquets_seulement(premier)
|
||||||
p2 = paquets_seulement(second)
|
p2 = paquets_seulement(second)
|
||||||
vues1 = {l["url"] for l in p1}
|
# « Déjà vue » suppose que la PREMIÈRE VM en a obtenu les octets. Un même
|
||||||
|
# paquet vit sous deux chemins selon le miroir, et la clé porte le chemin :
|
||||||
|
# la première peut recevoir « 504 » sur l'un — amont jugé muet — puis être
|
||||||
|
# servie du disque par l'autre. Le téléchargement honnête de la seconde sur
|
||||||
|
# le premier chemin n'est pas une faute : rien n'était rangé sous cette clé.
|
||||||
|
vues1 = {l["url"] for l in p1 if livre(l)}
|
||||||
|
|
||||||
# Le critère : ce que les DEUX ont demandé ne doit pas être ressorti.
|
# Le critère : ce que les DEUX ont demandé ne doit pas être ressorti.
|
||||||
#
|
#
|
||||||
|
|
@ -839,13 +856,7 @@ def verdict(premier, second, journal):
|
||||||
# miroir suivant, et le cache sert celui-là du disque. Il n'a rien livré
|
# 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é
|
# 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.
|
# ensuite. Le compter en faute fait échouer une mesure où tout a été servi.
|
||||||
refus = [
|
refus = [l for l in p2 if l.get("upstream") and not livre(l)]
|
||||||
l
|
|
||||||
for l in p2
|
|
||||||
if l.get("upstream")
|
|
||||||
and isinstance(l.get("status"), int)
|
|
||||||
and l["status"] >= 400
|
|
||||||
]
|
|
||||||
fautes = [
|
fautes = [
|
||||||
l
|
l
|
||||||
for l in p2
|
for l in p2
|
||||||
|
|
|
||||||
|
|
@ -620,5 +620,42 @@ class TestLeGainSeCalculeParCondition(unittest.TestCase):
|
||||||
self.assertNotIn("gain", texte)
|
self.assertNotIn("gain", texte)
|
||||||
|
|
||||||
|
|
||||||
|
class UneUrlQueLaPremiereNaJamaisObtenue(unittest.TestCase):
|
||||||
|
"""Deux miroirs rangent le même paquet sous deux chemins, et la clé porte
|
||||||
|
le chemin. La première VM reçoit « 504 » sur l'un — amont jugé muet — puis
|
||||||
|
est servie du disque par l'autre ; rien n'entre au magasin sous le premier
|
||||||
|
chemin. Le téléchargement de la seconde n'y est donc pas une faute.
|
||||||
|
"""
|
||||||
|
|
||||||
|
AUTRE = PAQUET_A.replace("miroir.example", "autre-miroir.example")
|
||||||
|
|
||||||
|
def test_un_504_chez_la_premiere_ne_rend_pas_la_seconde_fautive(self):
|
||||||
|
premier = [
|
||||||
|
ligne(
|
||||||
|
self.AUTRE, True, issue="offline-miss", octets=0, statut=504
|
||||||
|
),
|
||||||
|
ligne(PAQUET_A, False, issue="hit", statut=200),
|
||||||
|
]
|
||||||
|
second = [ligne(self.AUTRE, True, issue="stored", statut=200)]
|
||||||
|
self.assertTrue(
|
||||||
|
QC.verdict(premier, second, None),
|
||||||
|
"un 504 de la première VM fait accuser le cache d'un fichier"
|
||||||
|
" qu'il n'a jamais eu à garder",
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_un_fichier_livre_deux_fois_reste_une_faute(self):
|
||||||
|
premier = [ligne(PAQUET_A, True, statut=200)]
|
||||||
|
second = [ligne(PAQUET_A, True, statut=200)]
|
||||||
|
self.assertFalse(QC.verdict(premier, second, None))
|
||||||
|
|
||||||
|
def test_un_statut_absent_vaut_livre(self):
|
||||||
|
"""Les journaux d'avant ne l'écrivaient pas toujours : le prendre pour
|
||||||
|
un échec effacerait des mesures entières."""
|
||||||
|
self.assertTrue(QC.livre({"url": PAQUET_A}))
|
||||||
|
self.assertTrue(QC.livre({"url": PAQUET_A, "status": 206}))
|
||||||
|
self.assertFalse(QC.livre({"url": PAQUET_A, "status": 504}))
|
||||||
|
self.assertFalse(QC.livre({"url": PAQUET_A, "status": 404}))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue