Ampel / ampel (push) Successful in 1m18s
Zwei Wuensche des Commanders vom 28.08.2026.
## 1. „kannst du noch einbauen das man den arbeitsordner usw. in den
## Einstellungen setzen kann und direkt im setup?"
In den Einstellungen ging es seit 35370fd (freies Pfadfeld plus die Laufwerke
als Ein-Klick-Wahl). Im SETUP wurde bisher nur nach Programmordner und Ablage
gefragt — der Arbeitsordner tauchte erst auf, wenn schon installiert war.
Das ist die falsche Reihenfolge: Der Roh-Rip einer 4K-UHD ist bis zu 100 GB
gross. Wer erst NACH der ersten vollen Platte erfaehrt, wo die liegen, hat es
zu spaet erfahren — genau so lief am 25.07.2026 die VM-Platte voll.
Neu ist auch ein Waechter, der alle drei Arten von halb angeschlossenem Feld
faengt (kein Eingabefeld, keine Vorbelegung, wird beim Installieren nicht
mitgeschickt). Der dritte Fall ist der gemeinste: Man waehlt etwas, es
passiert nichts, und niemand sagt warum.
## 2. „der könnte theoretisch auch automatisch ausgelesen werden, ich glaube
## das web rippy kann das"
Er hatte recht. `makemkv_key.refresh_loop()` laeuft seit jeher taeglich mit
(main.py, Startereignis). GEMESSEN am 28.08.2026: Forum antwortet in 3,3 s,
gueltiger Key mit 62 Zeichen, und in seinen Einstellungen lag bereits einer.
Es war nur nichts davon zu sehen. Kein Knopf, keine Meldung, keine Zeitangabe
— im Feld stand ein Key, und ob der von Hand kam oder von selbst, wusste
niemand. Eine Automatik, die man nicht sehen kann, ist fuer den Benutzer
keine.
Dazu kam eine echte Luecke: Die Schleife startet 60 Sekunden nach dem Server.
Wer gleich nach dem Einrichten eine Blu-ray einlegt, rippt ohne Key — MakeMKV
faellt in den 30-Tage-Testmodus. Das Setup holt ihn jetzt selbst.
Der geholte Key wandert NICHT ueber die Leitung zurueck: Er steht in den
Einstellungen, und ein zweiter Weg zu demselben Wert ist ein zweiter Weg, ihn
zu verlieren.
Rechtlich unveraendert: oeffentliche Beta-LIZENZ der Software, KEIN
Disc-Schluessel. Rippy liefert und verteilt keine Disc-Schluessel.
803 Tests gruen, ruff sauber.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
282 lines
12 KiB
Python
282 lines
12 KiB
Python
"""Der Einrichtungs-Assistent — die Pruefungen, ohne etwas zu installieren.
|
||
|
||
## Warum es diese Tests gibt
|
||
|
||
Commander am 28.08.2026: *„Dann haette ich beim ‚Setup' auch erwartet das nen
|
||
echtes setup passiert — wo will ich das hinspeichern, nen pre requirement
|
||
check usw. Da kommt garnichts Rippy geht einfach auf."*
|
||
|
||
Er hatte recht: Ein Doppelklick installierte stillschweigend und oeffnete das
|
||
Fenster. Der Nutzer wurde nichts gefragt und erfuhr nichts.
|
||
|
||
Alle Pruefungen sind eingespritzt — kein Fenster, keine Installation, kein
|
||
WebView2. Sonst waere „kein Laufwerk" nur auf einem Rechner ohne Laufwerk
|
||
pruefbar, und genau dort sieht es niemand.
|
||
"""
|
||
|
||
import os
|
||
|
||
from rippy import einrichtung as e
|
||
|
||
|
||
def _p(zustand, name="X"):
|
||
return {"name": name, "zustand": zustand, "text": "", "abhilfe": ""}
|
||
|
||
|
||
# ── Was blockiert und was nicht ─────────────────────────────────────────
|
||
def test_ohne_fehler_darf_installiert_werden():
|
||
assert e.darf_installieren([_p(e.OK), _p(e.WARNUNG)]) is True
|
||
|
||
|
||
def test_ein_fehler_blockiert():
|
||
assert e.darf_installieren([_p(e.OK), _p(e.FEHLER)]) is False
|
||
|
||
|
||
def test_eine_warnung_blockiert_NICHT():
|
||
"""Eine Warnung, die den Knopf sperrt, ist eine Bevormundung. Rippy ohne
|
||
optisches Laufwerk ist ein vorgesehener Betriebsfall — eine reine
|
||
Komprimier-Maschine."""
|
||
assert e.darf_installieren([_p(e.WARNUNG), _p(e.WARNUNG)]) is True
|
||
|
||
|
||
# ── Die einzelnen Pruefungen ────────────────────────────────────────────
|
||
def test_windows_10_und_11_gehen():
|
||
assert e.pruefe_windows(22631)["zustand"] == e.OK
|
||
assert e.pruefe_windows(19045)["zustand"] == e.OK
|
||
|
||
|
||
def test_zu_altes_windows_ist_ein_fehler():
|
||
befund = e.pruefe_windows(7601) # Windows 7
|
||
assert befund["zustand"] == e.FEHLER
|
||
assert befund["abhilfe"], "ein Befund ohne Abhilfe laesst den Nutzer ratlos"
|
||
|
||
|
||
def test_fehlendes_webview_ist_nur_eine_warnung():
|
||
"""Ohne WebView2 faellt Rippy auf den Browser zurueck. Das ist weniger
|
||
schoen, aber es LAEUFT — ein Fehler waere hier eine Luege."""
|
||
befund = e.pruefe_webview(version="")
|
||
assert befund["zustand"] == e.WARNUNG
|
||
assert "Browser" in befund["abhilfe"]
|
||
|
||
|
||
def test_vorhandenes_webview_ist_ok():
|
||
assert e.pruefe_webview(version="151.0.4129.107")["zustand"] == e.OK
|
||
|
||
|
||
def test_zu_wenig_platz_ist_ein_fehler():
|
||
befund = e.pruefe_platz("C:\\egal", frei_mb=100)
|
||
assert befund["zustand"] == e.FEHLER
|
||
assert "500" in befund["text"]
|
||
|
||
|
||
def test_genug_platz_ist_ok():
|
||
assert e.pruefe_platz("C:\\egal", frei_mb=5000)["zustand"] == e.OK
|
||
|
||
|
||
def test_fehlendes_schreibrecht_ist_ein_fehler():
|
||
"""`os.access(..., W_OK)` luegt unter Windows — es beantwortet die Frage
|
||
anhand des Nur-Lesen-Flags, nicht anhand der Zugriffsrechte. Deshalb wird
|
||
wirklich geschrieben."""
|
||
befund = e.pruefe_schreibrecht("C:\\Programme\\Rippy",
|
||
probe=(False, "Zugriff verweigert"))
|
||
assert befund["zustand"] == e.FEHLER
|
||
assert "Benutzer" in befund["abhilfe"]
|
||
|
||
|
||
def test_schreibprobe_am_echten_ordner(tmp_path):
|
||
befund = e.pruefe_schreibrecht(str(tmp_path))
|
||
assert befund["zustand"] == e.OK
|
||
# Und die Probe darf nichts hinterlassen.
|
||
assert list(tmp_path.iterdir()) == []
|
||
|
||
|
||
# ── Administrator und Netzlaufwerke ─────────────────────────────────────
|
||
def test_normal_gestartet_ist_der_richtige_zustand():
|
||
"""Rippy braucht KEINE Administratorrechte — Vorgabeordner unter
|
||
%LOCALAPPDATA%, Autostart unter HKCU."""
|
||
befund = e.pruefe_administrator(erhoeht=False)
|
||
assert befund["zustand"] == e.OK
|
||
|
||
|
||
def test_als_administrator_wird_vor_den_fehlenden_netzlaufwerken_gewarnt():
|
||
"""DER Befund des Commanders (28.08.2026): „Wenn man das Tool als Admin
|
||
startet, kann man im explorer kein netzlaufwerk waehlen."
|
||
|
||
Ein erhoehter Prozess bekommt ein anderes Zugriffstoken; eingebundene
|
||
Netzlaufwerke haengen am Token der Sitzung. Windows-Verhalten, kein
|
||
Rippy-Fehler — aber Rippy hat ihn hineinlaufen lassen."""
|
||
befund = e.pruefe_administrator(erhoeht=True, laufwerke=["X:", "Y:", "Z:"])
|
||
assert befund["zustand"] == e.WARNUNG
|
||
assert "X:" in befund["abhilfe"]
|
||
assert "UNC" in befund["abhilfe"] or "Server" in befund["abhilfe"]
|
||
|
||
|
||
def test_fehlendes_laufwerk_wird_beim_namen_genannt():
|
||
"""„Schreibrechte fehlen" war richtig im Wortlaut und unbrauchbar als
|
||
Auskunft: Das Laufwerk war fuer den erhoehten Prozess gar nicht da."""
|
||
# `laufwerk_da=False` eingespritzt: Die Frage "existiert Q:" laesst sich
|
||
# auf dem Linux-Runner der Ampel gar nicht beantworten. Ohne den
|
||
# Einspritzpunkt waere dieser Zweig nur auf einem Windows-Rechner mit
|
||
# genau diesem fehlenden Laufwerk pruefbar -- also nirgends.
|
||
befund = e.pruefe_schreibrecht(
|
||
"Q:" + chr(92) + "Rippy", probe=(False, "Pfad nicht gefunden"),
|
||
erhoeht=True, laufwerk_da=False)
|
||
assert befund["zustand"] == e.FEHLER
|
||
assert "Q:" in befund["text"]
|
||
assert "nicht vorhanden" in befund["text"]
|
||
assert "Administrator" in befund["abhilfe"]
|
||
|
||
|
||
def test_programme_ordner_erklaert_den_teufelskreis():
|
||
"""Program Files verlangt Administrator, Administrator versteckt die
|
||
Netzlaufwerke — und Rippy braucht beides nicht."""
|
||
befund = e.pruefe_schreibrecht(
|
||
"C:" + chr(92) + "Program Files (x86)" + chr(92) + "Rippy",
|
||
probe=(False, "Zugriff verweigert"))
|
||
assert befund["zustand"] == e.FEHLER
|
||
assert "Administratorrechte" in befund["abhilfe"]
|
||
assert "Vorgabeordner" in befund["abhilfe"]
|
||
|
||
|
||
def test_programme_wird_erkannt():
|
||
B = chr(92)
|
||
assert e._unter_programme("C:" + B + "Program Files" + B + "Rippy") is True
|
||
assert e._unter_programme("C:" + B + "Program Files (x86)" + B + "R") is True
|
||
assert e._unter_programme("C:" + B + "Users" + B + "X" + B + "Rippy") is False
|
||
|
||
|
||
def test_belegter_port_ist_nur_eine_warnung():
|
||
"""Sehr oft ist es ein bereits laufendes Rippy — und dann ist eine
|
||
Neuinstallation genau richtig."""
|
||
befund = e.pruefe_port(7788, belegt=True)
|
||
assert befund["zustand"] == e.WARNUNG
|
||
assert "Rippy" in befund["abhilfe"]
|
||
|
||
|
||
def test_freier_port_ist_ok():
|
||
assert e.pruefe_port(7788, belegt=False)["zustand"] == e.OK
|
||
|
||
|
||
def test_kein_laufwerk_ist_nur_eine_warnung():
|
||
"""install.sh sagt seit Langem: ohne Laufwerk „laeuft trotzdem durch, dann
|
||
ist das eine reine KOMPRIMIER-Maschine"."""
|
||
befund = e.pruefe_laufwerk(laufwerke=[])
|
||
assert befund["zustand"] == e.WARNUNG
|
||
assert "komprimieren" in befund["abhilfe"]
|
||
|
||
|
||
def test_gefundenes_laufwerk_wird_genannt():
|
||
befund = e.pruefe_laufwerk(laufwerke=["\\\\.\\G:"])
|
||
assert befund["zustand"] == e.OK
|
||
assert "G:" in befund["text"]
|
||
|
||
|
||
# ── Die Werkzeuge ───────────────────────────────────────────────────────
|
||
def _bestand(makemkv, handbrake):
|
||
return {
|
||
"makemkv": {"titel": "MakeMKV", "da": makemkv, "version": "1.18.4",
|
||
"pflicht": True},
|
||
"handbrake": {"titel": "HandBrakeCLI", "da": handbrake,
|
||
"version": "1.11.2", "pflicht": False},
|
||
}
|
||
|
||
|
||
def test_fehlendes_makemkv_ist_eine_warnung_mit_ausweg():
|
||
befunde = {b["name"]: b for b in e.pruefe_werkzeuge(_bestand(False, True))}
|
||
assert befunde["MakeMKV"]["zustand"] == e.WARNUNG
|
||
assert "makemkv.com" in befunde["MakeMKV"]["abhilfe"]
|
||
|
||
|
||
def test_fehlendes_handbrake_ist_kein_problem():
|
||
"""Es liegt im Paket — das Setup legt es beim Installieren daneben."""
|
||
befunde = {b["name"]: b for b in e.pruefe_werkzeuge(_bestand(True, False))}
|
||
assert befunde["HandBrakeCLI"]["zustand"] == e.OK
|
||
assert "mitgeliefert" in befunde["HandBrakeCLI"]["text"]
|
||
|
||
|
||
def test_vorhandene_werkzeuge_zeigen_ihre_version():
|
||
befunde = {b["name"]: b for b in e.pruefe_werkzeuge(_bestand(True, True))}
|
||
assert befunde["MakeMKV"]["text"] == "1.18.4"
|
||
|
||
|
||
# ── Die Zusammenfassung ─────────────────────────────────────────────────
|
||
def test_zusammenfassung_nennt_die_fehler_beim_namen():
|
||
text = e.zusammenfassung([_p(e.FEHLER, "Speicherplatz"), _p(e.OK, "Port")])
|
||
assert "nicht möglich" in text
|
||
assert "Speicherplatz" in text
|
||
|
||
|
||
def test_zusammenfassung_nennt_die_hinweise():
|
||
text = e.zusammenfassung([_p(e.WARNUNG, "MakeMKV"), _p(e.OK, "Port")])
|
||
assert "MakeMKV" in text
|
||
assert "nicht möglich" not in text
|
||
|
||
|
||
def test_alles_gruen_sagt_es_auch_so():
|
||
assert e.zusammenfassung([_p(e.OK), _p(e.OK)]) == "Alles bereit."
|
||
|
||
|
||
def test_jede_pruefung_hat_dieselbe_form():
|
||
"""Ein fehlendes Feld waere in der Oberflaeche ein `undefined`."""
|
||
for befund in ([e.pruefe_windows(22631), e.pruefe_webview(version=""),
|
||
e.pruefe_administrator(erhoeht=True, laufwerke=["X:"]),
|
||
e.pruefe_administrator(erhoeht=False),
|
||
e.pruefe_laufwerk(laufwerke=[]),
|
||
e.pruefe_platz("C:\\x", frei_mb=9999),
|
||
e.pruefe_port(7788, belegt=False)]
|
||
+ e.pruefe_werkzeuge(_bestand(False, False))):
|
||
assert set(befund) == {"name", "zustand", "text", "abhilfe"}, befund
|
||
assert befund["zustand"] in (e.OK, e.WARNUNG, e.FEHLER)
|
||
if befund["zustand"] != e.OK:
|
||
assert befund["abhilfe"], (
|
||
"%s sagt nicht, was zu tun ist" % befund["name"])
|
||
|
||
|
||
# ── Die Vorgaben ────────────────────────────────────────────────────────
|
||
def test_vorgaben_sind_vollstaendig():
|
||
if os.name != "nt":
|
||
import pytest
|
||
pytest.skip("Registry-Vorgaben gibt es nur unter Windows")
|
||
v = e.vorgaben()
|
||
assert set(v) == {"ziel", "ablage", "arbeit", "port", "autostart",
|
||
"verknuepfungen", "werkzeuge_holen"}
|
||
assert v["port"] == 7788
|
||
assert v["ziel"] and v["ablage"] and v["arbeit"]
|
||
for feld in ("ablage", "arbeit"):
|
||
assert "/app/" not in v[feld], "Container-Pfad in einer Windows-Vorgabe"
|
||
|
||
|
||
def test_netzwerkpfad_als_administrator_wird_erklaert():
|
||
"""Der zweite Teil des Befunds: Auch Netz-ANMELDUNGEN haengen am Token
|
||
der Sitzung. Ein erhoehter Prozess kennt die Zugangsdaten zur Freigabe
|
||
nicht und bekommt 'Zugriff verweigert' -- dieselbe Meldung wie bei einem
|
||
echten Rechteproblem."""
|
||
B = chr(92)
|
||
befund = e.pruefe_schreibrecht(
|
||
B + B + "NAS" + B + "Filme", probe=(False, "Zugriff verweigert"),
|
||
erhoeht=True)
|
||
assert befund["zustand"] == e.FEHLER
|
||
assert "ohne Administrator" in befund["abhilfe"]
|
||
|
||
|
||
def test_netzwerkpfad_ohne_administrator_bekommt_die_normale_meldung():
|
||
B = chr(92)
|
||
befund = e.pruefe_schreibrecht(
|
||
B + B + "NAS" + B + "Filme", probe=(False, "Netzwerkpfad nicht gefunden"),
|
||
erhoeht=False)
|
||
assert befund["zustand"] == e.FEHLER
|
||
assert "Administrator" not in befund["abhilfe"] or "keine" in befund["abhilfe"]
|
||
|
||
|
||
def test_ein_vorhandenes_laufwerk_ist_kein_laufwerks_problem():
|
||
"""Sonst waere JEDER Schreibfehler auf C: ein 'Laufwerk fehlt'."""
|
||
B = chr(92)
|
||
assert e.laufwerk_fehlt("C:" + B + "Programme", vorhanden=True) is False
|
||
assert e.laufwerk_fehlt("Q:" + B + "Rippy", vorhanden=False) is True
|
||
|
||
|
||
def test_unc_und_posix_sind_keine_laufwerksbuchstaben():
|
||
B = chr(92)
|
||
assert e.laufwerk_fehlt(B + B + "NAS" + B + "Filme") is False
|
||
assert e.laufwerk_fehlt("/srv/rippy") is False
|