Files
RustNotMC/tests/test_nightly.py
T
SashegDev 874b6f20c2 Клиент: начальный импорт кодовой базы
Основа — Horizon (MIT). История апстрима не переносится: этот репозиторий ведёт свою.
2026-10-29 22:04:28 +03:00

183 lines
9.4 KiB
Python

import datetime as dt
import unittest
from pathlib import Path
from tools.ci import nightly
from tools.ci import nightly_set as ns
NOW = "2026-10-28T12:00:00+00:00"
PATTERNS = ns.guarded_patterns((Path(__file__).resolve().parents[1] / ".github/CODEOWNERS").read_text())
def pr(n, head="h", state="open", files=("crates/horizon-world/src/lib.rs",), base="main"):
return ns.PullRequest(n, state, f"{head}{n}", f"Fix {n}", f"dev{n}", base, list(files))
def lookup(*prs):
known = {p.number: p for p in prs}
return lambda n: known.get(n)
def run(state, text, login="kacpherek", *prs):
return ns.apply(state, ns.parse(text), login, NOW, lookup(*prs), PATTERNS)
T = dt.datetime(2026, 10, 28, 12, 0, tzinfo=dt.timezone.utc)
def ref(name, sha, hours):
return nightly.Ref(name, sha, T + dt.timedelta(hours=hours))
class NightlyTests(unittest.TestCase):
def test_the_newest_union_newer_than_main_is_built(self):
main = ref("main", "m", 0)
unions = [ref("union/a", "a", 1), ref("union/b", "b", 3), ref("union/c", "c", -2)]
self.assertEqual(nightly.choose(main, unions, contains=lambda a, b: False).name, "union/b")
def test_main_when_no_union_is_newer(self):
main = ref("main", "m", 5)
unions = [ref("union/a", "a", 1), ref("union/b", "b", 3)]
self.assertEqual(nightly.choose(main, unions, contains=lambda a, b: False).name, "main")
self.assertEqual(nightly.choose(main, [], contains=lambda a, b: False).name, "main")
def test_a_union_main_already_holds_is_skipped(self):
main = ref("main", "m", 0)
unions = [ref("union/landed", "l", 2), ref("union/open", "o", 1)]
landed = lambda a, b: a == "l" # noqa: E731
self.assertEqual(nightly.choose(main, unions, contains=landed).name, "union/open")
def test_only_old_dated_nightlies_are_pruned(self):
tags = [{"tagName": "nightly", "isPrerelease": True},
{"tagName": "nightly-2026-10-20", "isPrerelease": True},
{"tagName": "nightly-2026-10-21", "isPrerelease": True},
{"tagName": "nightly-2026-10-19", "isPrerelease": False},
{"tagName": "v0.2.80", "isPrerelease": False},
{"tagName": "nightly-2026-10-15-extra", "isPrerelease": True}]
self.assertEqual(nightly.stale(tags, dt.date(2026, 10, 28), 7), ["nightly-2026-10-20"])
def test_notes_list_what_is_not_on_main(self):
text = nightly.notes("2026-10-28", ref("union/a", "0c0206714abc", 1),
[{"number": 2476, "title": "Fix pistons", "headRefOid": "x"}])
self.assertIn("Nightly 2026-10-28 · 0c02067", text)
self.assertIn("- Fix pistons (#2476)", text)
self.assertIn("Everything in it is on main.", nightly.notes("2026-10-28", ref("main", "m" * 40, 0), []))
def test_notes_name_the_commit_and_its_permanent_source_tag(self):
sha = "0c0206714abc" + "0" * 28
text = nightly.notes("2026-10-28", ref("union/a", sha, 1), [])
self.assertIn(f"Source: commit {sha}, kept for good as the tag `nightly-source/2026-10-28-0c02067`", text)
main = nightly.Ref("main", "m" * 40, None)
self.assertIn("`nightly-source/2026-10-28-bbbbbbb`",
nightly.set_notes("2026-10-28", nightly.Ref("b", "b" * 40, None), main, [], []))
def test_the_source_tag_outlives_every_prune(self):
tag = nightly.source_tag("2026-10-20", "a" * 40)
self.assertEqual(nightly.stale([{"tagName": tag, "isPrerelease": True}], dt.date(2026, 11, 28), 7), [])
self.assertIsNone(nightly.DATED.match(tag))
class ScheduledTests(unittest.TestCase):
def test_the_scheduled_nightly_takes_new_heads_and_drops_closed_ones(self):
state = run({}, "/nightly 1 2 3 4", "kacpherek", pr(1), pr(2), pr(3), pr(4)).state
get = lookup(pr(1, head="new"), pr(2, state="merged"), pr(3, state="closed"),
pr(4, files=[".github/workflows/x.yml"]))
kept, left_out = nightly.refresh(state["prs"], get, PATTERNS)
self.assertEqual([(e["number"], e["head"]) for e in kept], [(1, "new1")])
self.assertEqual(len(left_out), 3)
self.assertIn("merged", left_out[0])
def test_notes_list_each_pull_request_and_who_picked_it(self):
prs = run({}, "/nightly 1 2", "kacpherek", pr(1), pr(2)).state["prs"]
main = nightly.Ref("main", "m" * 40, None)
text = nightly.set_notes("2026-10-28", nightly.Ref("nightly/build-2026-10-28-1", "b" * 40, None), main, prs,
["#3 Fix 3: closed, left out"])
self.assertIn("can include pull requests not reviewed yet, picked by trusted reviewers", text)
self.assertIn("- Fix 1 (#1) by dev1, at h1, picked by kacpherek", text)
self.assertIn("### Left out (1)", text)
if __name__ == "__main__":
unittest.main()
WORKFLOWS = Path(__file__).resolve().parents[1] / ".github" / "workflows"
class UntrustedBuildTests(unittest.TestCase):
"""A nightly can hold unreviewed pull requests: nothing its build leaves may reach a release (game-build.yml)."""
def setUp(self):
self.game = (WORKFLOWS / "game-build.yml").read_text()
def test_only_the_release_is_trusted(self):
self.assertIn("trusted: true", (WORKFLOWS / "release.yml").read_text())
nightly_build = (WORKFLOWS / "nightly-build.yml").read_text()
self.assertIn("trusted: false", nightly_build)
self.assertNotIn("trusted: true", nightly_build)
self.assertIn("default: false", self.game.split("trusted:", 1)[1].split("developer_id:", 1)[0])
def test_an_untrusted_build_neither_shares_nor_saves_the_release_cache(self):
self.assertIn("shared-key: ${{ inputs.trusted && 'release' || 'nightly' }}-${{ matrix.name }}", self.game)
self.assertIn("save-if: ${{ inputs.trusted }}", self.game)
self.assertEqual(self.game.count("Swatinem/rust-cache"), 1)
def test_an_untrusted_build_never_runs_on_the_release_runner(self):
runs_on = [line for line in self.game.splitlines() if "runs-on:" in line]
self.assertEqual(len(runs_on), 2)
pr_runner = "fromJSON('[\"self-hosted\", \"macOS\", \"horizon-game\"]')"
for line in runs_on:
self.assertIn(f"inputs.trusted && vars.MAC_RUNNER || {pr_runner}", line)
def test_a_trusted_build_never_reads_the_shared_sccache(self):
calls = self.game.count("bash tools/ci/runner-env.sh")
self.assertEqual(self.game.count("HORIZON_NO_SCCACHE: ${{ inputs.trusted && '1' || '' }}"), calls)
env = (Path(__file__).resolve().parents[1] / "tools/ci/runner-env.sh").read_text()
self.assertEqual(env.count('-z "${HORIZON_NO_SCCACHE:-}"'), 2)
class PruneBuildsTests(unittest.TestCase):
TODAY = dt.date(2026, 11, 10)
def test_only_old_unpublished_builds_go(self):
branches = {
"nightly/build-2026-10-27-1": "a", # old: goes
"nightly/build-2026-10-27-2": "pub", # old, but a published nightly-<date> points to it: stays
"nightly/build-2026-11-02-1": "c", # old enough by one day: goes
"nightly/build-2026-11-03-1": "d", # exactly 7 days: stays
"nightly/build-2026-11-09-3": "e", # recent: stays
}
self.assertEqual(nightly.stale_builds(branches, {"pub"}, self.TODAY, 7),
["nightly/build-2026-10-27-1", "nightly/build-2026-11-02-1"])
def test_the_newest_build_always_stays(self):
branches = {"nightly/build-2026-10-01-1": "a", "nightly/build-2026-10-01-2": "b"}
self.assertEqual(nightly.stale_builds(branches, set(), self.TODAY, 7), ["nightly/build-2026-10-01-1"])
self.assertEqual(nightly.stale_builds({"nightly/build-2026-10-01-1": "a"}, set(), self.TODAY, 7), [])
# the newest by number, not by text: -10 is newer than -9
branches = {"nightly/build-2026-10-01-9": "a", "nightly/build-2026-10-01-10": "b"}
self.assertEqual(nightly.stale_builds(branches, set(), self.TODAY, 7), ["nightly/build-2026-10-01-9"])
def test_nothing_else_is_touched(self):
branches = {"nightly-state": "s", "nightly/build-x": "x", "main": "m", "nightly/build-2026-10-01-1-fix": "f",
"feature/nightly/build-2026-10-01-1": "g", "nightly/build-2026-10-02-1": "n"}
self.assertEqual(nightly.stale_builds(branches, set(), self.TODAY, 7), [])
def test_the_source_is_archived_from_git_signed_attached_and_tagged(self):
build = (WORKFLOWS / "nightly-build.yml").read_text()
pick = build.split("\n build:", 1)[0]
self.assertIn('git archive --format=tar.gz --prefix="horizon-${SHA:0:7}/" -o horizon-source.tar.gz "$SHA"',
pick)
sign = build.split("\n sign:", 1)[1].split("\n publish:", 1)[0]
self.assertIn("dist/horizon-source.tar.gz", sign.split("sign_release.sh nightly", 1)[1])
publish = build.split("\n publish:", 1)[1].split("\n answer:", 1)[0]
self.assertIn('"dist/horizon-source.tar.gz#Source of this Nightly', publish)
self.assertIn('nightly.py keep-source "$SHA" "$DATE"', publish)
def test_the_workflow_prunes_on_schedule_only(self):
build = (WORKFLOWS / "nightly-build.yml").read_text()
step = build.split("Old nightly/build-* branches deleted", 1)[1].split("- uses:", 1)[0]
self.assertIn("if: github.event_name == 'schedule'", step)
self.assertIn("prune-builds --days 7", step)
self.assertIn("GITHUB_STEP_SUMMARY", step)