Files
libretro/tests/test_site_bootstrap.py
T
Abdessamad Derraz 9e6af0aa6b feat: serve the one-line installer from the site
The site serves install.sh at /retrobios/i and install.ps1 at
/retrobios/i.ps1. generate_site.py writes both copies with the
installer address set to install.py at the commit the site is built
from (GITHUB_SHA in CI, HEAD locally), so the pinned SHA-256 and the
downloaded installer always come from one commit, including while a
deploy is still running.

Every command a user copies names the short address. The raw form
stays on the installer page as the fallback. Deploy Site now runs on
changes to install.sh and install.ps1. The install box weight keeps
the address length its ratio was fitted on, so no console page moves.
2026-10-28 05:47:38 +01:00

233 lines
11 KiB
Python

"""The one-line commands the site serves.
`curl -fsSL https://abdess.github.io/retrobios/i | sh` and the PowerShell
`i.ps1` replaced a raw.githubusercontent.com address of 70 characters. The
site deploys some eleven minutes after a push: a copy that pinned one
commit's installer and downloaded another's would refuse every install for
that long, so each copy reads install.py from the commit it was built from.
"""
from __future__ import annotations
import hashlib
import json
import os
import re
import subprocess
import sys
import tempfile
import unittest
from pathlib import Path
from unittest import mock
REPO_ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(REPO_ROOT))
sys.path.insert(0, str(REPO_ROOT / "scripts"))
import install # noqa: E402
import sitebootstrap # noqa: E402
from siteguides import INSTALL_BASE, INSTALL_PS1, INSTALL_SH, install_command # noqa: E402
WEBSITE = REPO_ROOT / "website"
DOCS = WEBSITE / "src" / "content" / "docs"
OLD_SH = "raw.githubusercontent.com/Abdess/retrobios/main/install.sh"
OLD_PS1 = "raw.githubusercontent.com/Abdess/retrobios/main/install.ps1"
def _head() -> str:
return subprocess.run(["git", "rev-parse", "HEAD"], cwd=REPO_ROOT, check=True,
capture_output=True, text=True).stdout.strip()
def _pin(text: str) -> str:
match = re.search(r'(?:DEFAULT_INSTALL_SHA256="|\$defaultInstallSha256 = ")([0-9a-f]{64})"',
text)
assert match, "no installer pin"
return match.group(1)
class ServedCopies(unittest.TestCase):
def setUp(self):
self.commit = _head()
def test_each_copy_is_its_bootstrap_but_for_the_installer_address(self):
for name, (source, _line) in sitebootstrap.SOURCES.items():
with self.subTest(name=name):
original = (REPO_ROOT / source).read_text(encoding="utf-8").splitlines()
served = sitebootstrap.served_text(name, REPO_ROOT, self.commit).splitlines()
self.assertEqual(len(original), len(served))
changed = [(a, b) for a, b in zip(original, served) if a != b]
self.assertEqual(len(changed), 1, changed)
before, after = changed[0]
self.assertIn("https://raw.githubusercontent.com/Abdess/retrobios/main/install.py",
before)
self.assertEqual(after, before.replace(
"https://raw.githubusercontent.com/Abdess/retrobios/main/install.py",
sitebootstrap.installer_url(self.commit)))
def test_the_address_names_the_commit_whose_installer_the_pin_holds(self):
installer = hashlib.sha256((REPO_ROOT / "install.py").read_bytes()).hexdigest()
url = f"https://raw.githubusercontent.com/Abdess/retrobios/{self.commit}/install.py"
for name in sitebootstrap.SOURCES:
with self.subTest(name=name):
text = sitebootstrap.served_text(name, REPO_ROOT, self.commit)
self.assertIn(f'"{url}"', text)
self.assertEqual(_pin(text), installer)
def test_ci_builds_from_the_pushed_commit(self):
pushed = "a" * 40
with mock.patch.dict(os.environ, {"GITHUB_SHA": pushed}):
self.assertEqual(sitebootstrap.build_commit(REPO_ROOT), pushed)
with mock.patch.dict(os.environ, {"GITHUB_SHA": "main"}), \
self.assertRaises(ValueError):
sitebootstrap.build_commit(REPO_ROOT)
with mock.patch.dict(os.environ, {"GITHUB_SHA": ""}):
self.assertEqual(sitebootstrap.build_commit(REPO_ROOT), self.commit)
def test_the_copies_land_at_the_root_of_the_public_folder(self):
with tempfile.TemporaryDirectory(dir=REPO_ROOT / "tmp" if (REPO_ROOT / "tmp").is_dir()
else None) as scratch:
public = Path(scratch) / "public"
written = sitebootstrap.write_bootstraps(public, REPO_ROOT, self.commit)
self.assertEqual(sorted(p.name for p in written), ["i", "i.ps1"])
for path in written:
self.assertEqual(path.read_text(encoding="utf-8"),
sitebootstrap.served_text(path.name, REPO_ROOT, self.commit))
def test_a_bootstrap_without_its_address_line_stops_the_build(self):
with tempfile.TemporaryDirectory(dir=REPO_ROOT / "tmp" if (REPO_ROOT / "tmp").is_dir()
else None) as scratch:
root = Path(scratch)
(root / "install.sh").write_text("#!/bin/sh\n", encoding="utf-8")
with self.assertRaises(ValueError):
sitebootstrap.served_text("i", root, self.commit)
class DocumentedCommands(unittest.TestCase):
def test_the_addresses_are_the_served_paths(self):
config = (WEBSITE / "astro.config.mjs").read_text(encoding="utf-8")
site = re.search(r"const SITE = '([^']+)'", config).group(1)
base = re.search(r"const BASE = '([^']+)'", config).group(1)
self.assertEqual(f"{INSTALL_BASE}/", site + base)
self.assertEqual(INSTALL_SH, f"{site}{base}{sitebootstrap.SH_NAME}")
self.assertEqual(INSTALL_PS1, f"{site}{base}{sitebootstrap.PS1_NAME}")
self.assertEqual(install.BOOTSTRAP_URL, INSTALL_SH)
self.assertEqual(f"{install.BOOTSTRAP_URL}.ps1", INSTALL_PS1)
def test_the_installer_hints_give_the_short_command(self):
with mock.patch.dict(os.environ, {"RETROBIOS_BOOTSTRAP": "sh"}):
self.assertEqual(install.Invocation().launcher(), f"curl -fsSL {INSTALL_SH} | sh -s --")
with mock.patch.dict(os.environ, {"RETROBIOS_BOOTSTRAP": "ps1"}):
self.assertEqual(install.Invocation().launcher(),
f"&([scriptblock]::Create((irm {INSTALL_PS1})))")
def test_every_page_a_user_copies_from_gives_the_short_command(self):
sources = {
"wiki/installer.md": [install_command("sh"), install_command("powershell")],
"wiki/first-install.md": [install_command("sh"), install_command("powershell")],
"wiki/faq.md": [f"curl -fsSL {INSTALL_SH} | sh -s -- --dry-run"],
"wiki/troubleshooting.md": [install_command("sh", "--check")],
"wiki/tools.md": [install_command("sh"), install_command("powershell")],
"website/src/components/FilePicker.astro": [f"'curl -fsSL {INSTALL_SH} | sh -s --'"],
"scripts/download.sh": [f"curl -fsSL {INSTALL_SH} | sh -s -- --platform <name>"],
"scripts/download.py": [f"curl -fsSL {INSTALL_SH} | sh -s -- --platform <name>"],
}
for rel, commands in sources.items():
text = (REPO_ROOT / rel).read_text(encoding="utf-8")
for command in commands:
with self.subTest(file=rel, command=command):
self.assertIn(command, text)
def test_the_raw_form_is_written_once_as_the_fallback(self):
"""The long address stays on the installer page only, for the day
the site is down."""
surfaces = [*sorted((REPO_ROOT / "wiki").glob("*.md")), REPO_ROOT / "README.md",
REPO_ROOT / "CONTRIBUTING.md", REPO_ROOT / "install.py",
*sorted((REPO_ROOT / "scripts").rglob("*.py")),
REPO_ROOT / "scripts" / "download.sh",
*sorted((WEBSITE / "src" / "components").glob("*.astro"))]
found = {
str(path.relative_to(REPO_ROOT)): text.count(OLD_SH) + text.count(OLD_PS1)
for path in surfaces
for text in [path.read_text(encoding="utf-8")]
if OLD_SH in text or OLD_PS1 in text
}
self.assertEqual(found, {"wiki/installer.md": 2})
def test_typed_by_hand_without_the_scheme(self):
page = (REPO_ROOT / "wiki" / "installer.md").read_text(encoding="utf-8")
bare = INSTALL_BASE.removeprefix("https://")
self.assertIn(f"curl -fL {bare}/{sitebootstrap.SH_NAME} | sh", page)
self.assertIn(f"irm {bare}/{sitebootstrap.PS1_NAME} | iex", page)
class NothingElseAtTheseAddresses(unittest.TestCase):
"""A page or a folder named i would take the address, or turn it into a
redirect to i/ that `curl | sh` reads as HTML."""
NAMES = tuple(sitebootstrap.SOURCES)
def test_no_source_page_takes_the_names(self):
for folder in (REPO_ROOT / "wiki", WEBSITE / "src" / "pages"):
taken = sorted(str(path.relative_to(REPO_ROOT)) for path in folder.glob("i*")
if path.name == "i" or path.name.split(".", 1)[0] == "i")
with self.subTest(folder=str(folder.relative_to(REPO_ROOT))):
self.assertEqual(taken, [])
@unittest.skipUnless(DOCS.is_dir(), "site not generated")
def test_no_generated_page_or_redirect_takes_the_names(self):
for name in self.NAMES:
stem = name.split(".", 1)[0]
with self.subTest(name=name):
self.assertFalse((DOCS / stem).exists())
self.assertEqual(sorted(DOCS.glob(f"{stem}.md*")), [])
redirects = WEBSITE / "src" / "generated" / "redirects.json"
if redirects.is_file():
sources = {key.strip("/").removeprefix("retrobios/")
for key in json.loads(redirects.read_text(encoding="utf-8"))}
self.assertEqual(sources & set(self.NAMES), set())
@unittest.skipUnless((WEBSITE / "dist" / "index.html").is_file(), "site not built")
def test_the_built_site_serves_files_at_the_addresses(self):
for name in self.NAMES:
path = WEBSITE / "dist" / name
with self.subTest(name=name):
self.assertTrue(path.is_file())
text = path.read_text(encoding="utf-8")
self.assertRegex(text, r"raw\.githubusercontent\.com/Abdess/retrobios/[0-9a-f]{40}/"
r"install\.py")
class GeneratedSurfaces(unittest.TestCase):
def test_a_shorter_address_moves_no_section(self):
"""The install boxes weigh in the split of a manufacturer's page,
fitted on the 66-character raw address: weighed at their new length,
Nintendo DS fell back onto the Nintendo summary and lost its page."""
import generate_site
tail = " | sh -s -- --check"
self.assertEqual(generate_site._install_box_weight([f"curl -fsSL {INSTALL_SH}{tail}"]),
len("curl -fsSL ") + 66 + len(tail) + 1)
line = f"&([scriptblock]::Create((irm {INSTALL_PS1}))) --check"
self.assertEqual(generate_site._install_box_weight([line]),
len(line) - len(INSTALL_PS1) + 67 + 1)
def test_the_readme_shows_the_short_form(self):
readme = (REPO_ROOT / "README.md").read_text(encoding="utf-8")
quick = readme.split("## Quick install", 1)[1].split("\n## ", 1)[0]
self.assertIn(f"\n{install_command('sh')}\n", quick)
self.assertIn(f"\n{install_command('powershell')}\n", quick)
self.assertNotIn("raw.githubusercontent.com", quick)
@unittest.skipUnless(DOCS.is_dir(), "site not generated")
def test_the_site_shows_the_short_form(self):
pages = {path: path.read_text(encoding="utf-8") for path in DOCS.rglob("*.md*")}
self.assertTrue(any(INSTALL_SH in text for text in pages.values()))
long_form = sorted(str(path.relative_to(DOCS)) for path, text in pages.items()
if OLD_SH in text or OLD_PS1 in text)
self.assertEqual(long_form, ["wiki/installer.md"])
if __name__ == "__main__":
unittest.main()