"""Exercise the real offline installer with unusable external tools and proxies.""" import ctypes import json import os import subprocess import tempfile import time from pathlib import Path ROOT = Path(__file__).resolve().parent.parent ARTIFACTS = ROOT / "test-artifacts" ARTIFACTS.mkdir(exist_ok=True) INSTALLER = ROOT / "dist/YouTubeDL-Helper-Setup.exe" environment = {**os.environ, "PATH": str(Path(os.environ.get("SystemRoot", r"C:\Windows")) / "System32"), "PYTHONHOME": "C:/NONEXISTENT", "PYTHONPATH": "C:/NONEXISTENT", "PYTHONNOUSERSITE": "1", "HTTP_PROXY": "http://127.0.0.1:9", "HTTPS_PROXY": "http://127.0.0.1:9", "ALL_PROXY": "http://127.0.0.1:9"} def run(*args): result = subprocess.run([str(item) for item in args], env=environment, capture_output=True, encoding="utf-8", errors="replace", timeout=180) if result.returncode: raise RuntimeError(json.dumps({"code": result.returncode, "stdout": result.stdout[-500:], "stderr": result.stderr[-2500:]})) return result def picker(manager, folder): import base64 encoded = base64.b64encode(json.dumps(str(folder)).encode()).decode() process = subprocess.Popen([str(manager), "--pick-folder", "--initial-folder", encoded], env=environment, stdout=subprocess.PIPE, stderr=subprocess.PIPE, creationflags=subprocess.CREATE_NO_WINDOW) user32 = ctypes.windll.user32 callback_type = ctypes.WINFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, ctypes.c_void_p) dialogs = [] def callback(window, unused): pid = ctypes.c_ulong(); user32.GetWindowThreadProcessId(window, ctypes.byref(pid)) if pid.value == process.pid: name = ctypes.create_unicode_buffer(256); user32.GetClassNameW(window, name, 256) if name.value == "#32770" and user32.IsWindowVisible(window): dialogs.append(window) return True deadline = time.monotonic() + 15 handler = callback_type(callback) while not dialogs and time.monotonic() < deadline: user32.EnumWindows(handler, 0); time.sleep(0.1) assert dialogs, "The bundled Windows folder picker must open" # Select its preselected existing folder, including Unicode in the path. user32.PostMessageW(ctypes.c_void_p(dialogs[0]), 0x0111, 1, 0) # WM_COMMAND / IDOK output, errors = process.communicate(timeout=15) assert process.returncode == 0, errors.decode("utf-8", errors="replace") assert Path(json.loads(output)) == folder with tempfile.TemporaryDirectory(prefix="offline-bundle-", dir=ARTIFACTS) as temporary: parent = Path(temporary) application = parent / "Helper" legacy = application / ".runtime"; legacy.mkdir(parents=True) (legacy / "completed-jobs.json").write_text("[]") first = run(INSTALLER, "--silent", "--no-register", "--target-root", application) assert (application / "data/completed-jobs.json").read_text() == "[]" marker = json.loads((application / "installation.json").read_text(encoding="utf-8-sig")) release = Path(marker["current"]) python = release / "runtime/python/python.exe" measured = json.loads(run(python, "-I", "-B", "-c", "import json,sys; from host.media import capabilities,tool; print(json.dumps({'python':sys.executable,'path':sys.path,'hardware':capabilities(),'tools':{k:tool(k) for k in ('node','ffmpeg','ffprobe')}}))").stdout) assert measured["hardware"]["ready"] assert measured["hardware"]["bundle"]["mode"] == "autonomous" assert {"h264", "hevc", "av1"} <= set(measured["hardware"]["nvenc"]), measured["hardware"] assert Path(measured["python"]).is_relative_to(release) assert all(Path(path).is_relative_to(release) for path in measured["tools"].values()) assert all(Path(path).is_relative_to(release) for path in measured["path"]) picker(application / "YouTubeDL-Manager.exe", ARTIFACTS) preserved = release / "user-kept.mp4"; preserved.write_bytes(b"user file") history = application / "data/completed-jobs.json"; history.parent.mkdir(exist_ok=True); history.write_text("[]") # Reinstall beside the running copy; an old DLL handle must not prevent repair. handle = (release / "runtime/python/python313.dll").open("rb") try: run(INSTALLER, "--silent", "--no-register", "--target-root", application) finally: handle.close() current = Path(json.loads((application / "installation.json").read_text(encoding="utf-8-sig"))["current"]) assert current != release and current.is_dir() manager = application / "YouTubeDL-Manager.exe" run(manager, "--uninstall", "--silent", "--target-root", application) assert preserved.read_bytes() == b"user file" and history.read_text() == "[]" assert not current.exists() and not python.exists() deadline = time.monotonic() + 15 while manager.exists() and time.monotonic() < deadline: time.sleep(0.1) assert not manager.exists(), "The uninstaller must remove its own installed executable" # Payload damage must be rejected before registering or installing any tools. damaged = parent / "damaged.exe" payload = bytearray(INSTALLER.read_bytes()); offset = payload.index(b"PK\x03\x04"); payload[offset + 100] ^= 1 damaged.write_bytes(payload) invalid = subprocess.run([str(damaged), "--silent", "--no-register", "--target-root", str(parent / "Invalid")], env=environment, capture_output=True, encoding="utf-8", timeout=60) assert invalid.returncode != 0 and "Контрольная сумма" in invalid.stderr, invalid.stderr (ARTIFACTS / "offline-bundle.json").write_text(json.dumps({"offlineInstallation": "passed", "isolatedRuntime": "passed", "folderPicker": "passed", "repairWhileOldFilesOpen": "passed", "uninstallPreservesUserMedia": "passed", "corruptedPayload": "rejected", "versions": measured["hardware"]["dependencies"], "nvenc": measured["hardware"]["nvenc"]}, ensure_ascii=False, indent=2), encoding="utf-8") print("Offline bundle passed: isolated runtime, blocked proxies, Windows picker, NVENC, repair, scoped uninstall and damaged-payload rejection.")