erplibre/script/todo/longtest_menu.py
Mathieu Benoit 8e5f5b9097 [UPD] LongTest : trois étages par défaut, la mesure le dit
Le défaut promettait dix étages qu'aucune machine ne tient. Une descente
complète par ligne, sur 28 cœurs :

    étage 1 :   0 s d'amorçage,    200 s d'installation, 280 s en tout
    étage 2 :  37 s,               344 s,                495 s
    étage 3 :  93 s,               777 s,              1 064 s
    étage 4 : 15 608 s,         26 306 s,      n'a pas abouti

Trois étages coûtent une demi-heure. Le quatrième a coûté 4 h 20 d'amorçage et
7 h 18 d'installation sur la même machine : tout y est 15 à 30 fois plus lent,
pas une seule étape. C'est aussi là que les fabricants s'arrêtent — le
quatrième étage est le troisième hyperviseur imbriqué, AMD en documente deux.

La profondeur reste le seul paramètre, et le README dit désormais ce qu'on
achète en la montant.

--- EN ---

The default promised ten levels no machine can hold. One full descent per row,
on 28 cores:

    level 1:      0 s boot,    200 s install,   280 s total
    level 2:     37 s,         344 s,           495 s
    level 3:     93 s,         777 s,         1 064 s
    level 4: 15 608 s,      26 306 s,      did not finish

Three levels cost half an hour. The fourth cost 4 h 20 of boot and 7 h 18 of
install on the same machine: everything there is 15 to 30 times slower, not one
step. It is also where the vendors stop — level 4 is the third nested
hypervisor, and AMD documents two.

Depth remains the only parameter, and the README now says what raising it buys.

Assisted-by: claude-opus-5
(cherry picked from commit 226d6ffa3c664ba9e1a6dfdf48d52027b52eda23)
2026-08-29 01:53:03 -04:00

98 lines
4 KiB
Python

#!/usr/bin/env python3
# © 2026 TechnoLibre (http://www.technolibre.ca)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
"""Les tests LONGS : de vraies machines, des heures.
Ils vivent dans `LongTest/` et non dans `test/`, et ce n'est pas un rangement
de confort : le lanceur unitaire balaie `test/test_*.py` et doit rester
lançable en quelques secondes, partout. Un test qui crée dix VM n'a rien à y
faire — il le ferait échouer sur toute machine sans virtualisation, et
personne ne l'attendrait.
Ce menu ne fait que les lancer, en montrant leur sortie en direct : ces
scripts durent des heures, et une sortie capturée jusqu'à la fin ne dirait
rien pendant tout ce temps.
"""
import os
import click
from script.todo.todo_i18n import t
# Le répertoire des tests longs, à la racine du dépôt.
LONGTEST_DIR = "LongTest"
class LongTestMenuMixin:
def _longtest_script(self, nom):
"""Chemin d'un test long, ou "" s'il n'est pas là."""
chemin = os.path.join(os.getcwd(), LONGTEST_DIR, nom)
return chemin if os.path.exists(chemin) else ""
def _longtest_run(self, nom, args=""):
"""Lance un test long, sortie en DIRECT.
En direct parce qu'il dure des heures : capturer sa sortie pour
l'afficher à la fin, c'est ne rien montrer pendant tout ce temps —
et c'est justement la progression étage par étage qui intéresse.
"""
chemin = self._longtest_script(nom)
if not chemin:
print(f" ✗ {t('Script not found:')} {LONGTEST_DIR}/{nom}")
return
cmd = f"./.venv.erplibre/bin/python {chemin}"
if args:
cmd += f" {args}"
print(f"\n{t('Will execute:')} {cmd}")
self.execute.exec_command_live(cmd, source_erplibre=False)
def prompt_execute_longtest(self):
print(f"⏳ {t('Long tests: real VMs, hours. Not the unit suite.')}")
choices = [
{
"prompt_description": t(
"Nested Proxmox depth: plan only (dry-run)"
)
},
{"prompt_description": t("Nested Proxmox depth: run it")},
{"prompt_description": t("Undo what the descent created")},
]
help_info = self.fill_help_info(choices)
while True:
status = click.prompt(help_info)
print()
if status == "0":
return False
if status == "1":
self._longtest_run(
"deep_proxmox.py",
f"--depth {self._longtest_depth()} --dry-run",
)
elif status == "2":
# La profondeur est DEMANDÉE : c'est le seul réglage du test,
# et il décide de sa durée — dix étages, c'est une nuit.
self._longtest_run(
"deep_proxmox.py", f"--depth {self._longtest_depth()}"
)
elif status == "3":
# Le script demande « OUI » avant de détruire, mais il liste
# d'abord : on lui fait faire cette liste À BLANC pour que le
# choix « 3 » d'une touche ne mène pas directement à un
# « qm destroy --purge ».
self._longtest_run("deep_proxmox.py", "--detruire --dry-run")
if self._is_yes(input(f"\n{t('Destroy all that? (y/N): ')}")):
self._longtest_run("deep_proxmox.py", "--detruire")
else:
print(t("Command not found !"))
def _longtest_depth(self):
"""Profondeur demandée. Trois par défaut, parce que trois marche.
Mesuré sur cette machine : les trois premiers étages prennent 280, 495
et 1 064 secondes — une demi-heure. Le quatrième a demandé 7 h 18
d'installation et 4 h 20 d'amorçage, et les suivants se comptent en
jours. Dix par défaut promettait ce qu'aucune machine ne tient.
"""
brut = input(f"{t('Depth (default 3): ')}").strip()
return int(brut) if brut.isdigit() and int(brut) > 0 else 3