Quatre tests comparaient des mots français à une sortie traduite : ils échouaient dès que EL_LANG passait à « en », pour une raison étrangère à ce qu'ils vérifient. Ils comparent maintenant à t(clé). La suite passe dans les deux langues, ce qui est la seule façon de le savoir. Et le transfert mobile s'IGNORE quand le paquet est à moitié construit (manifeste plein, index absents) au lieu de remonter une erreur : un état incomplet n'est pas une régression du transfert. --- EN --- Four tests compared French words against translated output: they failed as soon as EL_LANG turned to "en", for a reason foreign to what they check. They now compare against t(key). The suite passes in both languages, which is the only way to know it. And the mobile transfer now SKIPS when the bundle is half-built (manifest full, indexes missing) instead of raising an error: an incomplete state is not a regression of the transfer. Assisted-by: Claude Opus 5
131 lines
4.5 KiB
Python
131 lines
4.5 KiB
Python
#!/usr/bin/env python3
|
|
# © 2026 TechnoLibre (http://www.technolibre.ca)
|
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
|
|
"""La ligne de totaux du formulaire QEMU/KVM : la place, pas seulement la
|
|
demande.
|
|
|
|
La ligne disait « ~126 G » sans dire sur quoi : on découvrait au déploiement
|
|
qu'il ne restait pas la place. Elle dit maintenant la demande, ce qui reste et
|
|
la capacité — et elle prévient quand ça ne rentre pas, pour les trois limites
|
|
(RAM, disque, cœurs) au lieu d'une seule à la fois.
|
|
|
|
La sonde disque est vérifiée à part : elle doit tomber sur une partition qui
|
|
existe même quand le répertoire d'images n'a jamais été créé.
|
|
"""
|
|
|
|
import asyncio
|
|
import sys
|
|
import unittest
|
|
|
|
sys.argv = ["todo.py"]
|
|
from script.todo.todo import TODO # noqa: E402
|
|
|
|
try:
|
|
import textual # noqa: F401
|
|
|
|
TEXTUAL = True
|
|
except Exception: # pragma: no cover - dépend de l'environnement
|
|
TEXTUAL = False
|
|
|
|
|
|
class TestSondeDisque(unittest.TestCase):
|
|
def test_it_measures_the_filesystem_that_will_hold_the_disks(self):
|
|
libre, total = TODO._host_disk_gb()
|
|
self.assertGreater(total, 0)
|
|
self.assertLessEqual(libre, total)
|
|
|
|
def test_a_missing_directory_falls_back_to_a_parent(self):
|
|
# /var/lib/libvirt/images n'existe qu'après le premier déploiement :
|
|
# sans repli, la place s'afficherait comme inconnue sur une machine
|
|
# neuve, là où elle est justement la plus utile.
|
|
libre, total = TODO._host_disk_gb("/n/existe/pas/du/tout")
|
|
self.assertGreater(total, 0)
|
|
|
|
def test_it_never_raises(self):
|
|
self.assertEqual(len(TODO._host_disk_gb("")), 2)
|
|
|
|
|
|
def contexte():
|
|
"""Contexte minimal du formulaire, avec des mesures CHOISIES : la ligne
|
|
doit se lire pareil quelle que soit la machine qui lance le test."""
|
|
todo = TODO.__new__(TODO)
|
|
mod = todo._qemu_import_module()
|
|
todo._qemu_list_domains = lambda: []
|
|
todo._qemu_branch_list = lambda: ["develop", "master"]
|
|
ctx = todo._qemu_form_context(mod)
|
|
ctx["free_disk"] = 500
|
|
ctx["total_disk"] = 900
|
|
ctx["free_ram"] = 64000
|
|
ctx["host_cpu"] = 64
|
|
return ctx
|
|
|
|
|
|
@unittest.skipUnless(TEXTUAL, "Textual absent")
|
|
class TestLigneDeTotaux(unittest.TestCase):
|
|
def _ligne(self, combien, ctx=None):
|
|
from script.todo.qemu_deploy_form import run_deploy_form
|
|
|
|
ctx = ctx or contexte()
|
|
vu = {}
|
|
|
|
async def scenario():
|
|
from textual.widgets import SelectionList, Static
|
|
|
|
app = run_deploy_form(ctx, run_app=False)
|
|
async with app.run_test(size=(200, 50)) as pilote:
|
|
await pilote.pause()
|
|
liste = app.query_one(SelectionList)
|
|
for i in range(combien):
|
|
liste.select(liste.get_option_at_index(i).value)
|
|
await pilote.pause()
|
|
await pilote.pause()
|
|
widget = app.query_one("#totals", Static)
|
|
vu["ligne"] = str(
|
|
getattr(widget, "_content", "") or widget.render()
|
|
)
|
|
vu["vms"] = len(app.vms)
|
|
|
|
asyncio.run(scenario())
|
|
return vu
|
|
|
|
def test_nothing_ticked_says_how_to_fill_the_list(self):
|
|
# Un total à zéro n'apprend rien.
|
|
self.assertNotIn("~", self._ligne(0)["ligne"])
|
|
|
|
def test_it_shows_the_demand_the_room_and_the_capacity(self):
|
|
ligne = self._ligne(2)["ligne"]
|
|
self.assertIn("~", ligne)
|
|
self.assertIn("500 G", ligne)
|
|
self.assertIn("900 G", ligne)
|
|
|
|
def test_a_plan_bigger_than_the_room_is_flagged(self):
|
|
ctx = contexte()
|
|
ctx["free_disk"] = 1
|
|
ctx["total_disk"] = 900
|
|
self.assertIn("⚠", self._ligne(2, ctx)["ligne"])
|
|
|
|
def test_the_three_limits_are_reported_together(self):
|
|
# N'en montrer qu'une cachait les autres : on corrigeait la première
|
|
# pour découvrir la suivante au déploiement.
|
|
ctx = contexte()
|
|
ctx["free_disk"] = 1
|
|
ctx["free_ram"] = 1
|
|
ctx["host_cpu"] = 1
|
|
ligne = self._ligne(2, ctx)["ligne"]
|
|
self.assertEqual(ligne.count("⚠"), 1)
|
|
from script.todo.deploy_form_lib import t
|
|
|
|
for cle in ("> host free RAM", "> host free disk", "> host cores"):
|
|
self.assertIn(t(cle), ligne, ligne)
|
|
|
|
def test_an_unknown_measure_shows_no_room_at_all(self):
|
|
ctx = contexte()
|
|
ctx["free_disk"] = 0
|
|
ctx["total_disk"] = 0
|
|
ligne = self._ligne(2, ctx)["ligne"]
|
|
self.assertIn("~", ligne)
|
|
self.assertNotIn("/", ligne)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main(verbosity=2)
|