fix(station): ehrliche Abbruchmeldung, apt-update darf scheitern
Fixrunde 2 zu Task 6b. - Die Vorbedingung "display.py liegt in der Ablage" steht jetzt VOR dem ersten sudo install. Vorher stand sie dahinter, und die Meldung "Nichts installiert" war schlicht unwahr: server.py, products.py, das CLI und die Stations-Unit lagen dann schon auf dem Pi. Ausgerechnet an dem Werkbank-Moment, fuer den die Pruefung gedacht ist, log das Skript den Bediener an. Die Ablage raeumt ein EXIT-Trap jetzt auf beiden Wegen aus dem Block ab, nicht nur im Erfolgsfall. - "apt-get update" ist keine Voraussetzung mehr fuer "apt-get install": update meldet schon dann einen Fehler, wenn eine einzige Quelle nicht erreichbar ist, und ein Pi, auf dem das Paket aus dem Cache gekommen waere, bekam so still kein Pillow. - Die Signalhandler beenden jetzt selbst (130/143/129). Ein Handler ohne exit laesst bash weiterlaufen - ein Strg-C konnte in "fertig, Exit 0" muenden. Die Begruendung im Kommentar war falsch und ist korrigiert: zum Aufraeumen haette der EXIT-Trap allein genuegt. - test_host.sh ruft die Shell-Suiten aus einer Liste auf, und der Coverage-Test prueft diese Liste gegen das Dateisystem statt im Skripttext nach Dateinamen zu suchen - ein nachgestellter Kommentar hebelte die alte Regel aus. Er deckt jetzt ganz tools/ ab, nicht nur station/tests. - Neue Szenarien: Wahrheitsgehalt der Abbruchmeldung, apt-update-Fall, und ein Strg-C, das aus den Trap-Zeilen des Skripts selbst geprueft wird.
This commit is contained in:
@@ -41,14 +41,42 @@ def pytest_paths():
|
||||
return paths
|
||||
|
||||
|
||||
def own_test_files():
|
||||
def own_test_files(suffix=".py"):
|
||||
return sorted(
|
||||
p.resolve()
|
||||
for p in TOOLS_DIR.rglob("test_*.py")
|
||||
for p in TOOLS_DIR.rglob("test_*" + suffix)
|
||||
if not any(part in IGNORED_PARTS for part in p.parts)
|
||||
)
|
||||
|
||||
|
||||
def listed_shell_suites():
|
||||
"""Die Eintraege des SHELL_SUITES-Feldes in tools/test_host.sh, aufgeloest.
|
||||
|
||||
Ausdruecklich gegen das FELD geprueft und nicht per Textsuche nach Dateinamen: eine
|
||||
Textsuche ist schon durch einen nachgestellten Kommentar ("echo x # test_deploy.sh"),
|
||||
ein ": \"test_deploy.sh\"" oder einen Heredoc-Inhalt erfuellt - sie belegt nur, dass
|
||||
der Name irgendwo vorkommt, nicht dass die Suite laeuft (Task 6b F2).
|
||||
"""
|
||||
text = TEST_HOST.read_text()
|
||||
block = re.search(r"^SHELL_SUITES=\((.*?)^\)", text, re.M | re.S)
|
||||
assert block, (
|
||||
"in tools/test_host.sh gibt es kein 'SHELL_SUITES=(...)'-Feld mehr - die "
|
||||
"Vollstaendigkeitspruefung der Shell-Suiten haengt daran"
|
||||
)
|
||||
# Und das Feld muss auch wirklich abgearbeitet werden, sonst ist es nur Deko.
|
||||
assert re.search(r'for\s+\w+\s+in\s+"\$\{SHELL_SUITES\[@\]\}"', text), (
|
||||
"tools/test_host.sh arbeitet SHELL_SUITES nicht in einer Schleife ab - die "
|
||||
"aufgefuehrten Suiten wuerden gar nicht laufen"
|
||||
)
|
||||
paths = []
|
||||
for raw in block.group(1).split():
|
||||
arg = raw.strip('"')
|
||||
if not arg or arg.startswith("#"):
|
||||
continue
|
||||
paths.append(Path(arg.replace("$ROOT", str(REPO_ROOT))).resolve())
|
||||
return paths
|
||||
|
||||
|
||||
def test_every_test_file_is_reached_by_test_host():
|
||||
roots = pytest_paths()
|
||||
orphans = []
|
||||
@@ -72,23 +100,28 @@ def test_every_shell_suite_is_called_by_test_host():
|
||||
Haelfte nicht ab, weil die Shell-Suiten nicht ueber pytest laufen, sondern einzeln
|
||||
aufgerufen werden.
|
||||
"""
|
||||
# Nur AUSFUEHRBARE Zeilen zaehlen, keine Kommentare: der Kommentarblock ueber den
|
||||
# Aufrufen nennt test_deploy.sh beim Namen, und eine blosse Textsuche waere damit
|
||||
# auch dann erfuellt, wenn die Aufrufzeile fehlt - der Test waere gruen, ohne etwas
|
||||
# zu pruefen (genau die Falle, die er verhindern soll).
|
||||
lines = [
|
||||
line.strip()
|
||||
for line in TEST_HOST.read_text().splitlines()
|
||||
if line.strip() and not line.strip().startswith("#")
|
||||
listed = listed_shell_suites()
|
||||
# Symmetrisch zur .py-Regel: das GANZE tools/ wird durchsucht, nicht nur
|
||||
# tools/station/tests - eine kuenftige Shell-Suite an einer neuen Stelle faellt sonst
|
||||
# weiterhin durch (Task 6b F2).
|
||||
# tools/test_host.sh heisst selbst "test_*.sh", ist aber der Aufrufer und keine
|
||||
# Suite - es kann sich schlecht selbst auffuehren.
|
||||
missing = [
|
||||
s.relative_to(REPO_ROOT)
|
||||
for s in own_test_files(".sh")
|
||||
if s != TEST_HOST.resolve() and s not in listed
|
||||
]
|
||||
missing = []
|
||||
for suite in sorted((TOOLS_DIR / "station" / "tests").glob("test_*.sh")):
|
||||
# So, wie test_host.sh sie aufruft: "$ROOT/tools/station/tests/<name>"
|
||||
if not any(suite.name in line for line in lines):
|
||||
missing.append(suite.relative_to(REPO_ROOT))
|
||||
assert not missing, (
|
||||
"diese Shell-Suiten ruft tools/test_host.sh nicht auf, sie laufen also nur bei "
|
||||
"Handaufruf: {}".format(", ".join(str(m) for m in missing))
|
||||
"diese Shell-Suiten stehen nicht in SHELL_SUITES von tools/test_host.sh, sie "
|
||||
"laufen also nur bei Handaufruf: {}".format(", ".join(str(m) for m in missing))
|
||||
)
|
||||
# Und andersherum: ein Eintrag, den es nicht mehr gibt, laesst test_host.sh beim
|
||||
# naechsten Lauf hart scheitern - das faellt hier schon vorher auf.
|
||||
verschwunden = [str(p) for p in listed if not p.exists()]
|
||||
assert not verschwunden, (
|
||||
"SHELL_SUITES in tools/test_host.sh nennt Dateien, die es nicht gibt: {}".format(
|
||||
", ".join(verschwunden)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user