Files
onion-mc/analysis/client-perf/proposed-configs/tests/test_perf_setup.py
T
logan f949c169a2 feat(perf): add one-step tier setup script for existing players
Default Options only seeds configs when absent, so existing players never
got the tuned settings. build.py --ship now also writes the Deck/Mid/High
tier files to config/onion-perf/<tier>/, and onion-perf-setup.{sh,ps1,bat}
(installed into the instance folder) backs up and replaces the tier's
config files and merges only the tuned video keys into options.txt,
keeping keybinds, audio and vsync/max-FPS choices.

PLAYER-TUNING: point players at the script; bench B4 GC verdict (G1 for
everyone; ZGC/Shenandoah tested worse); 16 GB PCs 5-6 GB heap.
2026-10-18 15:31:20 -04:00

238 lines
10 KiB
Python

"""Tests for onion-perf-setup.sh (and .ps1 when pwsh exists) against temp instance dirs.
Needs `python3 build.py --ship` to have generated config/onion-perf/ in the repo.
Run: python3 -m unittest discover -s analysis/client-perf/proposed-configs/tests
"""
import shutil
import subprocess
import tempfile
import unittest
from pathlib import Path
REPO = Path(__file__).resolve().parents[4]
PERF = REPO / "config" / "onion-perf"
SCRIPTS = ["onion-perf-setup.sh", "onion-perf-setup.ps1", "onion-perf-setup.bat"]
OLD_OPTIONS = (
"version:3955\n"
"maxFps:144\n"
"enableVsync:false\n"
"renderDistance:12\n"
"mipmapLevels:4\n"
"soundCategory_master:0.5\n"
"key_key.attack:key.mouse.left\n"
"key_key.jump:key.keyboard.space\n"
'resourcePacks:["vanilla","file/MyPack.zip"]\n'
)
def runners():
"""(name, argv prefix) for every available POSIX-sh implementation, plus pwsh."""
out = [("sh", ["sh"])]
if shutil.which("dash"):
out.append(("dash", ["dash"]))
if shutil.which("zsh"):
out.append(("zsh-emulate-sh", ["zsh", "--emulate", "sh"]))
return out
PWSH = shutil.which("pwsh")
def tier_options(tier):
kv = {}
for line in (PERF / tier / "options.txt").read_text().splitlines():
k, _, v = line.partition(":")
kv[k] = v
return kv
class Base:
"""Mixin; subclasses set self.cmd(script, args) -> argv."""
def setUp(self):
if not (PERF / "mid").is_dir():
self.skipTest("config/onion-perf not generated (run build.py --ship)")
self.tmp = Path(tempfile.mkdtemp())
self.game = self.tmp / "instance"
(self.game / "config").mkdir(parents=True)
shutil.copytree(PERF, self.game / "config" / "onion-perf")
for s in SCRIPTS:
shutil.copy(REPO / s, self.game / s)
(self.game / "config" / "DistantHorizons.toml").write_text("old dh\n")
(self.game / "config" / "unrelated.toml").write_text("keep me\n")
(self.game / "options.txt").write_text(OLD_OPTIONS)
def tearDown(self):
shutil.rmtree(self.tmp, ignore_errors=True)
def run_setup(self, *args, cwd=None):
return subprocess.run(self.cmd(*args), cwd=cwd or self.tmp, stdin=subprocess.DEVNULL,
capture_output=True, text=True, timeout=60)
def backups(self):
d = self.game / "onion-perf-backup"
return sorted(d.iterdir()) if d.is_dir() else []
def test_tier_copy_backup_and_merge(self):
for tier in ("deck", "mid", "high"):
with self.subTest(tier=tier):
if tier != "deck":
self.tearDown()
self.setUp()
r = self.run_setup(tier, "--yes")
self.assertEqual(r.returncode, 0, r.stdout + r.stderr)
src = PERF / tier
for f in (src / "config").rglob("*"):
if f.is_file():
rel = f.relative_to(src)
self.assertEqual((self.game / rel).read_bytes(), f.read_bytes(), rel)
self.assertEqual((self.game / "config/unrelated.toml").read_text(), "keep me\n")
# backup holds the pre-run files
(b,) = self.backups()
self.assertEqual((b / "config/DistantHorizons.toml").read_text(), "old dh\n")
self.assertEqual((b / "options.txt").read_text(), OLD_OPTIONS)
self.assertFalse((b / "config/unrelated.toml").exists())
# options merged key by key
want = tier_options(tier)
lines = (self.game / "options.txt").read_text().splitlines()
kv = dict(line.partition(":")[::2] for line in lines)
for k in ("version", "maxFps", "enableVsync"):
self.assertEqual(kv[k], dict(x.partition(":")[::2]
for x in OLD_OPTIONS.splitlines())[k], k)
for k, v in want.items():
if k not in ("version", "maxFps", "enableVsync"):
self.assertEqual(kv[k], v, k)
for keep in ("soundCategory_master:0.5", "key_key.attack:key.mouse.left",
"key_key.jump:key.keyboard.space",
'resourcePacks:["vanilla","file/MyPack.zip"]'):
self.assertIn(keep, lines)
self.assertEqual(len(lines), len(set(line.partition(":")[0] for line in lines)))
# existing lines keep their positions; appended keys go at the end
self.assertEqual(lines[0], "version:3955")
self.assertTrue(lines[3].startswith("renderDistance:"))
if want["mipmapLevels"] != "4":
self.assertIn(f"mipmapLevels: 4 -> {want['mipmapLevels']}", r.stdout)
else:
self.assertNotIn("mipmapLevels:", r.stdout)
self.assertIn("(unset) ->", r.stdout)
def test_value_with_colon_replaced_whole(self):
# split on the FIRST ':' only: a tier value containing ':' replaces as a whole
tier_opt = self.game / "config/onion-perf/high/options.txt"
tier_opt.write_text(tier_opt.read_text() + "onionProbe:part1:part2\n")
(self.game / "options.txt").write_text("version:3955\nonionProbe:wrong\n")
r = self.run_setup("high", "--yes")
self.assertEqual(r.returncode, 0, r.stderr)
lines = (self.game / "options.txt").read_text().splitlines()
self.assertIn("onionProbe:part1:part2", lines)
self.assertNotIn("onionProbe:wrong", lines)
self.assertIn("onionProbe: wrong -> part1:part2", r.stdout)
def test_idempotent(self):
self.assertEqual(self.run_setup("deck", "--yes").returncode, 0)
snap = {p: p.read_bytes() for p in self.game.rglob("*") if p.is_file()
and "onion-perf-backup" not in p.parts}
r = self.run_setup("deck", "--yes")
self.assertEqual(r.returncode, 0, r.stderr)
self.assertIn("nothing changed", r.stdout)
self.assertEqual(len(self.backups()), 1)
for p, data in snap.items():
self.assertEqual(p.read_bytes(), data, p)
def test_default_tier_is_mid_when_noninteractive(self):
r = self.run_setup("--yes")
self.assertEqual(r.returncode, 0, r.stderr)
self.assertIn("tier 'mid'", r.stdout)
self.assertEqual((self.game / "config/DistantHorizons.toml").read_bytes(),
(PERF / "mid/config/DistantHorizons.toml").read_bytes())
def test_missing_options(self):
(self.game / "options.txt").unlink()
r = self.run_setup("high", "--yes")
self.assertEqual(r.returncode, 0, r.stderr)
self.assertIn("options.txt not found", r.stdout)
self.assertFalse((self.game / "options.txt").exists())
def test_crlf_options_preserved(self):
(self.game / "options.txt").write_bytes(OLD_OPTIONS.replace("\n", "\r\n").encode())
r = self.run_setup("mid", "--yes")
self.assertEqual(r.returncode, 0, r.stderr)
data = (self.game / "options.txt").read_bytes()
self.assertNotIn(b"\r\r", data)
self.assertEqual(data.count(b"\n"), data.count(b"\r\n"))
self.assertIn(b"key_key.attack:key.mouse.left\r\n", data)
self.assertIn(b"biomeBlendRadius:1\r\n", data)
def test_lf_options_preserved(self):
self.run_setup("mid", "--yes")
self.assertNotIn(b"\r", (self.game / "options.txt").read_bytes())
def test_bad_tier(self):
r = self.run_setup("ultra", "--yes")
self.assertNotEqual(r.returncode, 0)
self.assertEqual((self.game / "config/DistantHorizons.toml").read_text(), "old dh\n")
def test_missing_onion_perf(self):
shutil.rmtree(self.game / "config" / "onion-perf")
r = self.run_setup("mid", "--yes")
self.assertNotEqual(r.returncode, 0)
self.assertIn("Update the modpack", r.stderr)
self.assertEqual(self.backups(), [])
def test_needs_yes_when_noninteractive(self):
r = self.run_setup("mid")
self.assertNotEqual(r.returncode, 0)
self.assertIn("--yes", r.stderr)
self.assertEqual((self.game / "config/DistantHorizons.toml").read_text(), "old dh\n")
def make_sh_case(name, prefix):
class Case(Base, unittest.TestCase):
def cmd(self, *args):
return [*prefix, str(self.game / "onion-perf-setup.sh"), *args]
def test_run_from_game_dir_with_relative_path(self):
r = subprocess.run([*prefix, "onion-perf-setup.sh", "mid", "--yes"], cwd=self.game,
stdin=subprocess.DEVNULL, capture_output=True, text=True)
self.assertEqual(r.returncode, 0, r.stderr)
Case.__name__ = Case.__qualname__ = f"Sh_{name.replace('-', '_')}"
return Case
for _n, _p in runners():
globals()[f"Sh_{_n.replace('-', '_')}"] = make_sh_case(_n, _p)
@unittest.skipUnless(PWSH, "pwsh not installed: onion-perf-setup.ps1 untested here")
class Pwsh(Base, unittest.TestCase):
def cmd(self, *args):
return [PWSH, "-NoProfile", "-ExecutionPolicy", "Bypass", "-File",
str(self.game / "onion-perf-setup.ps1"), *args]
class Packaging(unittest.TestCase):
def test_bat_is_crlf_and_calls_ps1(self):
data = (REPO / "onion-perf-setup.bat").read_bytes()
self.assertEqual(data.count(b"\n"), data.count(b"\r\n"))
self.assertIn(b'-File "%~dp0onion-perf-setup.ps1" %*', data)
def test_scripts_ascii(self):
for s in SCRIPTS:
(REPO / s).read_bytes().decode("ascii")
def test_mid_matches_default_options(self):
do = REPO / "config" / "defaultoptions"
self.assertEqual((PERF / "mid/options.txt").read_bytes(),
(do / "options.txt").read_bytes())
for f in (PERF / "mid/config").rglob("*"):
if f.is_file():
rel = f.relative_to(PERF / "mid")
self.assertEqual(f.read_bytes(), (do / "extra" / rel).read_bytes(), rel)
self.assertFalse((PERF / "mid/config/modernfix-mixins.properties").exists())
if __name__ == "__main__":
unittest.main()