A tests-only update (the "Discuss and improve release tests" work). No game, server, protocol or file format change: 1.18.25 plays with 1.18.22 to 1.18.24 (protocol 44). Three lines in src/ exist only for the tests and cost nothing at run time (see "src/: test-only hooks"). Numbers are from a 4-core cloud box.
Map grading removed; the map safety checks kept
- Owner: "The maps test will soon be irrelevant with the addition of real human designed maps, so get rid of it."
- Removed: tests/mapreport.cpp (the decor / layout / movement / creativity / mode fit / balance scores, the >= 7 bar,
the attack/defend -1..+1 s timing band, originality,
# exempt),quark_tests mapreport, docs/MAP_REPORT.md, docs/MAP_METRICS.md, and the report's shot sheets (docs/map_shots/, tools/map_shots.sh). The suite no longer writes .cams files into the source tree. - Kept, every check that fails a broken map: spawns, routes, nav from every spawn to every objective, ladders,
stairs, cart sweep, symmetry, the map format tests. "Built for one mode" (a
forline) moved into testAllMaps. Human-made maps keep their report-only grace (misses print as HUMAN-MADE). - The out-of-bounds check stays: it lived in the report's bar, and moved to tests/mapbounds.cpp with the movement
envelope and tech graph trimmed to what it needs (same sampling, same numbers on every map; 1.18.7's dash rules,
dashReady, carried over). It runs as themapboundsandmapbounds2groups (every other map each) and asquark_tests bounds;OOB_TRACE=<map>lists what's out. - The map editor keeps the measurement: tools/map_editor/native carries its own copy (measure_impl.h, from 07ef254), now the only one; its comments and README say so. The old metric definitions are in git at 07ef254.
- Docs: RELEASE_CHECKLIST, HANDOVER, ASSETS, MAP_STRUCTURES, JUDGMENT_CALLS.
Faster tests: full local run ~279 s -> ~107 s
What each check asserts is unchanged; only waiting that isn't part of a check went, and real-time checks re-run only when the machine itself stalled.
- Bots-only tests on a manual clock (ffaVsExperts, the every-mode loop, testBotAim, testBotFalls, testGrappleBots):
a test clock that moves only when the test steps it to the server's next tick. Every tick runs, none is waited for,
and a seeded match is the same every run (the old wall-clock runs skipped ticks on a loaded box, the cause of the
flaky
hooks >= 1). bots 64 -> 9 s, botaim 62 -> 1.3 s, botfalls 46 -> 1.3 s. 1v1 and duel in the every-mode loop have a joining player since 1.18.21 (F7), so those two stay on the real clock. - brains: the native-vs-interpreted lockstep steps every tick (Server::stepTick, as the mode lockstep does) instead of playing 396 s of game time in real time: 101 -> ~5 s, the same 1.19 million thinks compared.
- Tick-rate tests on 1-1.5 s windows (were 3 s), the window holding the connect dropped unjudged, and a re-run only when this machine stalled a tick past the threshold itself: group tickrate 96 -> ~63 s, and 3 passes in 10 -> 10 in 10. testing's timingTest (1.18.22) wraps them as well.
- Netcode re-runs only on real machine stalls: pump() can measure how long the machine left its loop unrun (wall time minus the thread's CPU time: the game's own slowness never counts). The uptime clock, interpolation delay and input backlog checks run again (3 tries, the last counts) only after such a stall, never with a looser threshold: 8 passes in 10 -> 30 in 30. testClockWrap (the same view-tick lag through the 2^32 ms wrap) moved from "server" into "netcode" beside them, with the same re-run: under the busy parallel phase it read 14-35 ms in 2 of 3 full runs.
- Waits a check doesn't need: countdowns, freeze and round ends skipped where a test doesn't check them (tourney 25 -> 1 s, duel 24 -> 3 s), weapons tests start once both players have spawned, the vote / rejoin / ranked tests poll for what they wait on, the hello retry is 0.5 s in tests.
- Groups: governor, resetmaps and userdata run with the others; only tickrate, netcode and weaponpredict run after them, one at a time. rules, maps and mapbounds, and the mode lockstep (~41 s of CPU) are split in two so no group bounds the run; groups are listed longest first. 3 group processes per core (the groups mostly wait on real-time play: with one per core the cores sat ~70% idle). Groups that only compute run at nice 10 so the real-time groups beside them get the cores (without it, 2 of 3 full runs failed a real-time check after 1.18.22).
- Rules halves: tests whose ports overlap stay in one half (the halves run at once on one port block): hudclock takes 29280-29291, which hide, shorthanded and rps reach too. 1.18.23's mode calls test (one bomb match, ~2 s) joins the second half.
- weaponpredict (the client's weapon prediction over a 40 ms network) runs alone after the others, inside timingTest: in the rules group it missed its 0.8 s window in 1 full run of 3, and in 10 of 20 runs beside 8 busy loops on 1.18.17's own build (about 1 in 30 even idle).
quark_tests NAMEruns the whole group (asgroup NAMEdoes). The 38 subset shortcuts are gone (some shared a group's name and ran less of it). Kept: playtest, serverbench, snapbench, ffaexperts, racefloors, bounds, exportassets, rules NAME (one rules test), signing, launcher, bot, groups, group, serial, and the brain / mode / weapon tools and benches (exportbrain ... modebench, exportweapons ..., exprbench, navbench). An unknown name is an error listing them. 1.18.24's nav and navstuck shortcuts went too: both tests run in the botaim group.- Group times print in real seconds (they were game seconds, 4x).
Sanitizer fixes (CI's final-test job)
- quark_tests replaces operator new / delete; the nothrow forms now go through it too. Under ASan they were ASan's own, so std::stable_sort's buffer was freed by the wrong allocator: 16 of 17 sanitizer reports.
- Server tests are
noinline: inlined into serverTests() their Servers (~1.2 MB each) shared one ~17 MB frame under ASan, past Linux's 8 MB stack. - tests/lsan.supp: the per-thread rules tables are kept on purpose (a thread_local with a destructor crashed at thread exit under MinGW).
- release.yml (sanitizer step only):
ulimit -s 65536(ASan gives every local its own slot: votes ~7.5 MB) andLSAN_OPTIONSwith the suppressions file.
src/: test-only hooks (no run-time cost)
Server::rateStalls_(default true): the loss / bandwidth rate tests leave stalls out of the verdict. One member read where the verdict is made, once per rate window.RankService::helloRetryScale(1.0): a static read only when a ranked hello failed.MasterAnnouncer::queuedPosts(): an accessor the game never calls.- The manual clock (net.cpp): timeNow() keeps its one compare against 1.0 on the game's path; a manual clock uses the
existing scaled path with a zero rate, no new branch.
Server::nextTickForTest()is an inline accessor.
Tools
- Tests editor: the brain / mode tools and bounds count as tools,
mapreportis gone; a list's parallel flag comes from the scheduler call; rewriting the group lists keeps a group's comment lines with it; its tests follow the new tests.cpp (test_serve.py 23/23, run.mjs 47/47). - release_check.sh's list of groups run alone: tickrate, netcode, weaponpredict.