#!/usr/bin/env python3 # © 2026 TechnoLibre (http://www.technolibre.ca) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) """Nix et nixos-anywhere posés dans une VM qui n'est pas NixOS. L'option donne à une VM ordinaire — Debian, Arch, Fedora, openSUSE — le gestionnaire de paquets de NixOS à côté du sien, et l'installateur qui s'en sert pour porter NixOS sur une AUTRE machine, jointe par SSH. Ce que ces tests gardent : - l'option n'est pas offerte sur NixOS, où nix EST le système : elle n'y aurait rien à poser ; - elle n'est offerte que là où l'amont bâtit, amd64 et arm64 ; - aucune pose ne peut PENDRE : « || true » couvre l'échec, pas l'attente d'une réponse que personne ne donnera sur un SSH sans terminal ; - nix est appelé par son CHEMIN ABSOLU — le PATH du shell distant a été figé avant que l'installateur ne pose quoi que ce soit ; - les fonctions expérimentales sont redonnées sur la ligne de commande : l'écriture dans /etc/nix/nix.conf demande sudo et peut échouer, l'appel doit réussir quand même ; - le disque annoncé grandit de ce que le store réclame, faute de quoi la VM se remplit pendant l'installation. """ import os import subprocess import sys import tempfile import unittest from pathlib import Path sys.argv = ["todo.py"] from script.todo.todo import TODO # noqa: E402 from script.todo.todo_i18n import TRANSLATIONS # noqa: E402 RACINE = Path(__file__).resolve().parents[1] SPEC = TODO._QEMU_VM_TOOLS["nixanywhere"] class LOption(unittest.TestCase): def test_it_needs_no_desktop(self): """C'est un outil de ligne de commande : une VM serveur le prend.""" self.assertFalse(SPEC["needs_desktop"]) self.assertEqual((), SPEC["desktops"]) def test_it_is_posed_before_the_clone(self): """Comme les autres poses amont : l'outil se garde lui-même et ne fait échouer ni les autres ni l'installation d'ERPLibre.""" self.assertEqual("before", SPEC["phase"]) def test_it_is_not_offered_on_nixos(self): """Sur NixOS, nix est déjà là — l'option n'y a pas de sens.""" self.assertEqual( [], TODO._qemu_tools_for(("nixanywhere",), "amd64", "", "nixos") ) def test_it_is_offered_on_the_imperative_distributions(self): for distro in ("debian", "ubuntu", "arch", "fedora", "opensuse"): with self.subTest(distro=distro): self.assertEqual( ["nixanywhere"], TODO._qemu_tools_for( ("nixanywhere",), "amd64", "", distro ), ) def test_it_is_bounded_to_the_architectures_nix_builds_for(self): """Ailleurs, cocher la case poserait un installateur qui s'arrête.""" self.assertEqual(("amd64", "arm64"), SPEC["arches"]) self.assertEqual( [], TODO._qemu_tools_for(("nixanywhere",), "s390x", "", "debian") ) def test_the_disk_grows_by_what_the_store_asks(self): """Le store porte la fermeture d'un système NixOS complet et le noyau kexec : la VM se remplirait pendant l'installation.""" self.assertEqual(8, SPEC["disk_gb"]) sans = TODO._qemu_tools_disk_gb((), "amd64", "", "debian") avec = TODO._qemu_tools_disk_gb( ("nixanywhere",), "amd64", "", "debian" ) self.assertEqual(sans + 8, avec) class LaCommandeDistante(unittest.TestCase): def setUp(self): self.cmd = TODO.__new__(TODO)._qemu_nixanywhere_remote_cmd() def test_no_pose_can_hang(self): """« || true » couvre l'ÉCHEC, pas l'ATTENTE.""" bornees = [x for x in self.cmd.split("; ") if "timeout " in x] self.assertGreaterEqual(len(bornees), 2) for morceau in bornees: self.assertIn("