Files
libretro/tests/test_pack_probe.py
T
Abdessamad Derraz e19b82ea47 refactor: keep proof lines, drop the test showcase
Emulator pages show a run only when a profile's evidence names it or it
answers an issue, as one line naming the BIOS the core ran. The Tested
blocks, region outcomes, coverage, campaign and pack tables and the
benchmark figures are gone from the site; the records stay.
2026-10-28 07:29:58 +01:00

328 lines
16 KiB
Python

"""pack_probe.py tests a platform's pack the way a user installs it.
The rules (which cores a platform runs, what is staged, how a run maps back
to the pack, the verdict read from a record, the line written) are checked
on synthetic data. Two classes lay a real BIOS folder out from this
checkout, one per install path: the pack generate_pack.py builds, extracted,
and install.py --dest from that pack and the published manifest. They are
narrowed to one system to stay short, and skip when the collection is not
on disk.
"""
from __future__ import annotations
import contextlib
import io
import json
import shutil
import unittest
import zipfile
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parent.parent
import sys # noqa: E402
sys.path.insert(0, str(REPO_ROOT / "scripts"))
import measurement_records as mr # noqa: E402
import pack_probe as pp # noqa: E402
TMP = REPO_ROOT / "tmp" / "tests" / "pack_probe"
SATURN = {
"type": "libretro",
"cores": ["mednafen_saturn", "beetle-saturn"],
"systems": ["sega-saturn"],
"files": [
{"name": "sega_101.bin", "region": ["japan"]},
{"name": "mpr-17933.bin", "aliases": ["saturn_bios.bin"]},
{"name": "standalone.bin", "mode": "standalone"},
],
}
SCANNER = {
"type": "libretro",
"cores": ["swanstation"],
"systems": ["sony-playstation"],
"found_by": "content",
"files": [{"name": "scph5501.bin", "size": 524288},
{"name": "ps2.bin", "size": [524288, 4194304]}],
}
KRONOS = {
"type": "libretro",
"cores": ["kronos"],
"systems": ["sega-saturn"],
"files": [{"name": "saturn_bios.bin", "path": "kronos/saturn_bios.bin"}],
}
def layout(files: dict[str, int], entries: dict[str, str | None] | None = None) -> pp.Layout:
"""A layout whose sizes are given, nothing on disk."""
return pp.Layout("pack", Path("/nonexistent"), entries or {rel: rel for rel in files}, {},
sizes=dict(files))
class CoreChoice(unittest.TestCase):
def test_system_ids_compare_normalised(self) -> None:
config = {"systems": {"megacd": {}, "psx": {}}}
self.assertEqual(pp.platform_system(config, "sega-mega-cd"), "megacd")
self.assertIsNone(pp.platform_system(config, "sega-saturn"))
def test_standalone_only_is_not_run_as_a_core(self) -> None:
both = {"type": "standalone + libretro", "cores": ["duckstation", "duckstation-sa"]}
self.assertTrue(pp.libretro_build_runs("duckstation", both, {}))
self.assertFalse(pp.libretro_build_runs("duckstation", both, {"standalone_cores": ["duckstation"]}))
self.assertTrue(pp.libretro_build_runs("duckstation", both, {
"standalone_cores": ["duckstation"], "dual_mode_cores": ["duckstation-sa"]}))
self.assertFalse(pp.libretro_build_runs("x", {"type": "standalone"}, {}))
self.assertFalse(pp.libretro_build_runs("x", {"type": "alias"}, {}))
def test_buildbot_name(self) -> None:
buildbot = {"mednafen_psx", "mednafen_psx_hw", "kronos"}
beetle = {"cores": ["beetle_psx", "mednafen_psx", "mednafen_psx_hw"]}
# The target names both builds: both run.
self.assertEqual(pp.so_names("beetle_psx", beetle, buildbot, {"mednafen_psx", "mednafen_psx_hw"}),
["mednafen_psx", "mednafen_psx_hw"])
# A target in the platform's own names: the first buildbot name.
self.assertEqual(pp.so_names("beetle_psx", beetle, buildbot, {"beetle-psx"}), ["mednafen_psx"])
self.assertEqual(pp.so_names("kronos", {"cores": ["kronos"]}, buildbot, None), ["kronos"])
self.assertEqual(pp.so_names("gone", {"cores": ["gone"]}, buildbot, None), [])
def test_choose_cores(self) -> None:
profiles = {"beetle_saturn": SATURN, "kronos": KRONOS, "swanstation": SCANNER,
"ssf": {"type": "standalone", "cores": ["ssf"], "systems": ["sega-saturn"]}}
config = {"_key": "p", "cores": ["beetle-saturn", "kronos", "ssf", "swanstation"],
"systems": {"saturn": {}}}
buildbot = {"mednafen_saturn", "kronos", "swanstation"}
self.assertEqual(pp.choose_cores(config, profiles, "sega-saturn", buildbot, None),
[pp.CoreChoice("beetle_saturn", "mednafen_saturn"), pp.CoreChoice("kronos", "kronos")])
class Staging(unittest.TestCase):
FILES = {"sega_101.bin": 524288, "saturn_bios.bin": 524288, "scph5501.bin": 524288,
"big.bin": 4194304, "other.rom": 1000, "kronos/saturn_bios.bin": 524288,
"kronos/stvbios.zip": 10, "mame/hash/saturn.xml": 5, "standalone.bin": 1}
def test_declared_names_aliases_and_platform_list(self) -> None:
staged = pp.initial_stage(layout(self.FILES), SATURN, ["other.rom", "absent.bin"])
self.assertEqual(staged, {"sega_101.bin", "saturn_bios.bin", "other.rom"})
def test_a_folder_comes_whole(self) -> None:
staged = pp.initial_stage(layout(self.FILES), KRONOS, [])
self.assertEqual(staged, {"kronos/saturn_bios.bin", "kronos/stvbios.zip"})
def test_a_core_that_scans_gets_every_root_file_of_its_sizes(self) -> None:
staged = pp.initial_stage(layout(self.FILES), SCANNER, [])
self.assertEqual(staged, {"sega_101.bin", "saturn_bios.bin", "scph5501.bin", "big.bin"})
def test_grow_to_a_fixed_point(self) -> None:
staged = {"sega_101.bin"}
added = pp.grow_stage(self.FILES, staged, ["other.rom", "absent.bin", "mame/hash", "kronos"])
self.assertEqual(added, {"other.rom", "mame/hash/saturn.xml", "kronos/saturn_bios.bin",
"kronos/stvbios.zip"})
self.assertEqual(pp.grow_stage(self.FILES, staged | added, ["absent.bin"]), set())
class Mapping(unittest.TestCase):
def test_opened_files_map_to_their_entry_and_probes_to_findings(self) -> None:
lay = layout({"sega_101.bin": 1, "BIOS/Saturn_BIOS.bin": 1, "extra.bin": 1},
{"sega_101.bin": "sega_101.bin", "BIOS/Saturn_BIOS.bin": "BIOS/Saturn_BIOS.bin",
"extra.bin": None})
rep = {"files_opened": [{"path": "sega_101.bin", "sha1_after": "a" * 40},
{"path": "extra.bin", "sha1_after": "b" * 40},
{"path": "bkram.bin", "sha1_after": "c" * 40}],
"files_probed_absent": ["saturn_bios.bin", "mpr-17933.bin", "cfg.ini"]}
opened, findings = pp.map_run(lay, {"sega_101.bin", "extra.bin"}, rep, SATURN)
self.assertEqual(opened, [
{"path": "sega_101.bin", "entry": "sega_101.bin", "sha1": "a" * 40, "created": False},
{"path": "extra.bin", "entry": None, "sha1": "b" * 40, "created": False},
{"path": "bkram.bin", "entry": None, "sha1": "c" * 40, "created": True}])
self.assertEqual(findings, [
{"kind": "elsewhere", "path": "saturn_bios.bin", "declared_by": ["mpr-17933.bin"],
"paths": ["BIOS/Saturn_BIOS.bin"]},
{"kind": "missing_declared", "path": "mpr-17933.bin", "declared_by": ["mpr-17933.bin"], "paths": []},
{"kind": "missing_undeclared", "path": "cfg.ini", "declared_by": [], "paths": []},
{"kind": "unlisted", "path": "extra.bin", "declared_by": [], "paths": []}])
def test_a_name_tried_before_an_alias_that_is_read_is_no_finding(self) -> None:
profile = {"files": [{"name": "tmss.md", "aliases": ["bios_MD.bin"]}, {"name": "bios_CD_U.bin"}]}
lay = layout({"bios_MD.bin": 1})
rep = {"files_opened": [{"path": "bios_MD.bin", "sha1_after": "a" * 40}],
"files_probed_absent": ["tmss.md", "bios_CD_U.bin"]}
_, findings = pp.map_run(lay, {"bios_MD.bin"}, rep, profile)
self.assertEqual(findings, [{"kind": "missing_declared", "path": "bios_CD_U.bin",
"declared_by": ["bios_CD_U.bin"], "paths": []}])
def test_manifest_entries(self) -> None:
manifest = {"files": [{"dest": "a.bin"}],
"case_variants": [{"dest": "A.BIN"}, {"dest": "a.bin"}],
"data_directories": [{"ref": "bluemsx", "dest": "", "files": {"Machines/x.ini": {}}},
{"ref": "dolphin", "dest": "dolphin-emu/Sys/", "files": {"y": {}}}]}
self.assertEqual(pp.manifest_entries(manifest), {
"a.bin": "files:a.bin", "A.BIN": "case_variants:A.BIN",
"Machines/x.ini": "data_directories:bluemsx:Machines/x.ini",
"dolphin-emu/Sys/y": "data_directories:dolphin:y"})
class Verdict(unittest.TestCase):
def test_a_record_before_the_oracle_is_unknown(self) -> None:
self.assertEqual(pp.run_verdict(None), ("unknown", None))
self.assertEqual(pp.run_verdict({"variants": [{"repetitions": [{}]}]}), ("unknown", None))
def test_the_first_variant_decides(self) -> None:
evidence = {"rule": "reference_frame", "detail": "frame 120"}
record = {"variants": [{"verdict": "boots", "verdict_evidence": evidence, "repetitions": [{}]}]}
self.assertEqual(pp.run_verdict(record), ("boots", evidence))
self.assertEqual(pp.run_verdict({"variants": [{"verdict": "maybe"}]}), ("unknown", None))
class Line(unittest.TestCase):
def setUp(self) -> None:
self.root = TMP / "line"
shutil.rmtree(self.root, ignore_errors=True)
self.root.mkdir(parents=True)
def line(self) -> dict:
return {
"schema_version": 1, "probed_at": "2026-10-27T12:00:00+00:00", "platform": "retroarch",
"platform_version": "v1.22.2", "target": "linux-x86_64", "install": "pack",
"source": {"pack": {"file": "RetroArch_BIOS_Pack.zip", "sha256": "0" * 64, "size": 1,
"members": 1}, "manifest": None, "repo_commit": "1" * 40},
"system": "sega-saturn", "platform_system": "sega-saturn", "emulator": "beetle_saturn",
"core": {"file": "mednafen_saturn_libretro.so", "sha256": "2" * 64,
"artifact": "https://buildbot.libretro.com/x.zip", "last_modified": None},
"content": {"label": "Game (Japan)", "catalog": "redump", "region": "japan"},
"records": ["2026-10-27-0123456789ab"], "rounds": 1, "staged": 3, "verdict": "unknown",
"verdict_evidence": None,
"files_opened": [{"path": "sega_101.bin", "entry": "sega_101.bin", "sha1": "3" * 40,
"created": False}],
"findings": [{"kind": "missing_declared", "path": "x.bin", "declared_by": ["x.bin"], "paths": []}],
"error": None,
}
def test_the_line_is_sealed_valid_and_read_back(self) -> None:
sealed = pp.append_line(self.line(), self.root)
self.assertEqual(mr.read_campaign(self.root, mr.PACK_PROBES), [sealed])
try:
from jsonschema import Draft202012Validator
except ImportError:
self.skipTest("jsonschema is a tooling dependency")
schema = json.loads((REPO_ROOT / "schemas" / "pack-probe.schema.json").read_text())
self.assertEqual(list(Draft202012Validator(schema).iter_errors(sealed)), [])
def test_the_cli_refuses_an_unknown_platform(self) -> None:
with self.assertRaises(SystemExit), contextlib.redirect_stderr(io.StringIO()):
pp.main(["run", "--platform", "nowhere"])
with contextlib.redirect_stderr(io.StringIO()):
self.assertEqual(pp.main(["plan", "-p", "Lakka"]), 2)
class SitePages(unittest.TestCase):
"""A pack probe runs before a release: its records stay in measurements/
and reach no page."""
def test_the_pack_blocks_are_gone(self) -> None:
import sitemeasurements as sm
for name in ("pack_summary", "packs_section", "pack_tested_section", "by_platform"):
self.assertFalse(hasattr(sm, name), name)
def test_pack_runs_stay_off_the_emulator_page(self) -> None:
import sitemeasurements as sm
subject = pp.subject_for("retroarch", "pack", "sega-saturn", "mednafen_saturn", "Game (Japan)")
self.assertEqual(subject, "pack-retroarch-pack-sega-saturn-mednafen-saturn-game-japan")
index = {"items": [{"emulator": "beetle_saturn", "subject": subject},
{"emulator": "beetle_saturn", "subject": "boot-sega-101-bin"}]}
self.assertEqual([i["subject"] for i in sm.by_emulator(index)["beetle_saturn"]],
["boot-sega-101-bin"])
def test_a_markdown_link_keeps_only_safe_targets(self) -> None:
"""A Markdown link in site text keeps only http(s) and relative targets."""
import sitemarkup
self.assertEqual(sitemarkup.inline_html("[x](javascript:alert(1))"), "[x](javascript:alert(1))")
self.assertEqual(sitemarkup.inline_html('[x](https://a.org/"onmouseover=1)'),
'<a href="https://a.org/&quot;onmouseover=1">x</a>')
self.assertEqual(sitemarkup.inline_html("[x](../a.md)"), '<a href="../a.md">x</a>')
class Lock(unittest.TestCase):
"""The probe lock is held for one core_probe run and released after it."""
def test_held_for_each_run_only(self) -> None:
import fcntl
import subprocess
import unittest.mock
work = TMP / "lock"
shutil.rmtree(work, ignore_errors=True)
lock = work / "probe.lock"
held = []
def try_lock() -> bool:
with lock.open("a") as handle:
try:
fcntl.flock(handle, fcntl.LOCK_EX | fcntl.LOCK_NB)
except BlockingIOError:
return True
fcntl.flock(handle, fcntl.LOCK_UN)
return False
def fake_run(command, **kwargs):
held.append(try_lock())
self.assertEqual(kwargs["env"]["RETROBIOS_PROBE_LOCK_HELD"], "1")
self.assertEqual(kwargs["env"]["RETROBIOS_PROBE_LOCK"], str(lock))
return subprocess.CompletedProcess(command, 2, "", "refused")
lay = layout({"a.bin": 1})
with unittest.mock.patch.object(pp, "PROBE_LOCK", lock), \
unittest.mock.patch.object(pp.subprocess, "run", fake_run):
for _ in range(2):
self.assertEqual(pp.core_probe(["run"], {"a.bin"}, lay, work), (2, None, "refused"))
self.assertEqual(held, [True, True])
self.assertFalse(try_lock())
def collection_on_disk() -> bool:
return (REPO_ROOT / "bios" / "Sony" / "PlayStation" / "scph5501.bin").is_file()
@unittest.skipUnless(collection_on_disk(), "the collection is not on disk")
class RealLayouts(unittest.TestCase):
"""Both install paths, from this checkout, narrowed to PlayStation."""
@classmethod
def setUpClass(cls) -> None:
cls.work = TMP / "real"
shutil.rmtree(cls.work, ignore_errors=True)
cls.pack = pp.build_pack("retroarch", cls.work / "dist", ["--system", "sony-playstation"])
cls.identity = pp.pack_identity(cls.pack)
@classmethod
def tearDownClass(cls) -> None:
shutil.rmtree(cls.work, ignore_errors=True)
def test_pack_path(self) -> None:
lay = pp.pack_layout(self.pack, self.work / "pack", self.identity)
with zipfile.ZipFile(self.pack) as handle:
members = {i.filename for i in handle.infolist() if not i.is_dir()}
self.assertEqual(set(lay.files), members)
self.assertEqual(lay.files["scph5501.bin"], "scph5501.bin")
self.assertEqual(lay.source["pack"]["members"], len(members))
swan = pp.load_emulator_profiles(str(REPO_ROOT / "emulators"))["swanstation"]
self.assertIn("scph5501.bin", pp.initial_stage(lay, swan, []))
def test_installer_path(self) -> None:
lay = pp.installer_layout("retroarch", self.pack, self.identity,
REPO_ROOT / "install" / "retroarch.json", self.work / "installer",
["--system", "sony-playstation"])
self.assertEqual(lay.root, self.work / "installer" / "system")
self.assertEqual(lay.files["scph5501.bin"], "files:scph5501.bin")
self.assertEqual(lay.source["manifest"]["path"], "install/retroarch.json")
self.assertTrue(all(entry for entry in lay.files.values()), lay.files)
if __name__ == "__main__":
unittest.main()