Public Access
Complete 26.3 parity acceptance and dual-version release workflow
Build and smoke / changes (push) Waiting to run
Build and smoke / changes (push) Waiting to run
This commit is contained in:
1 parent
41daff1e61
commit
4a59fb5d02
26 files changed
+1241
-369
No files matched your search
@@ -0,0 +1,121 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Small dual-target dedicated smoke. Worlds are disposable; stalled checks hand off."""
|
||||
import argparse
|
||||
from server_test_lock import server_test_lock
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
import signal
|
||||
import subprocess
|
||||
import tempfile
|
||||
import time
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
class StalledTest(RuntimeError):
|
||||
pass
|
||||
|
||||
|
||||
def wait_for(process, log, marker, timeout=60):
|
||||
started = time.monotonic()
|
||||
while time.monotonic() - started < timeout:
|
||||
text = log.read_text(errors="replace") if log.exists() else ""
|
||||
if marker in text:
|
||||
return text
|
||||
if process.poll() is not None:
|
||||
raise RuntimeError(f"Server exited before {marker!r}; inspect {log}")
|
||||
time.sleep(0.25)
|
||||
raise StalledTest(f"No result for {marker!r} within {timeout}s; stop and hand off, do not retry")
|
||||
|
||||
|
||||
def stop(process):
|
||||
if process is None or process.poll() is not None:
|
||||
return
|
||||
try:
|
||||
process.stdin.write("stop\n")
|
||||
process.stdin.flush()
|
||||
process.wait(timeout=25)
|
||||
except (BrokenPipeError, subprocess.TimeoutExpired):
|
||||
os.killpg(process.pid, signal.SIGTERM)
|
||||
try:
|
||||
process.wait(timeout=10)
|
||||
except subprocess.TimeoutExpired:
|
||||
os.killpg(process.pid, signal.SIGKILL)
|
||||
process.wait()
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--target", choices=("mc1211", "mc263"), required=True)
|
||||
args = parser.parse_args()
|
||||
logs = ROOT / "build/verification" / args.target
|
||||
logs.mkdir(parents=True, exist_ok=True)
|
||||
work = Path(tempfile.mkdtemp(prefix=f"rivencraft-{args.target}-smoke-"))
|
||||
settings = {"layers": [{"height": 1, "block": "minecraft:bedrock"},
|
||||
{"height": 2, "block": "minecraft:dirt"},
|
||||
{"height": 1, "block": "minecraft:grass_block"}],
|
||||
"biome": "minecraft:plains"}
|
||||
(work / "eula.txt").write_text("eula=true\n")
|
||||
(work / "server.properties").write_text(
|
||||
"server-ip=127.0.0.1\nserver-port=0\nonline-mode=false\nwhite-list=false\n"
|
||||
"view-distance=2\nsimulation-distance=2\ngenerate-structures=false\n"
|
||||
"level-type=minecraft:flat\nlevel-seed=263100\ngenerator-settings=" + json.dumps(settings) + "\n")
|
||||
command = [str(ROOT / "gradlew")]
|
||||
if args.target == "mc263":
|
||||
command += ["-p", str(ROOT / "ports/mc263")]
|
||||
command += ["--no-daemon", "runServer", f"-PserverRunDir={work}", "--console=plain"]
|
||||
process = None
|
||||
try:
|
||||
for phase in ("first", "restart"):
|
||||
log = logs / f"{phase}.log"
|
||||
with log.open("w") as output:
|
||||
process = subprocess.Popen(command, cwd=ROOT, stdin=subprocess.PIPE,
|
||||
stdout=output, stderr=subprocess.STDOUT, text=True, start_new_session=True)
|
||||
wait_for(process, log, "Done (")
|
||||
if args.target == "mc263":
|
||||
if phase == "first":
|
||||
for name, seed in (("smoke_a", 123456789), ("smoke_b", 987654321)):
|
||||
process.stdin.write(f"rivencraft_port age create {name} {seed} flat\n")
|
||||
process.stdin.flush()
|
||||
wait_for(process, log, f"Created rivencraft:age/{name} with seed {seed}")
|
||||
else:
|
||||
text = log.read_text()
|
||||
for name, seed in (("smoke_a", 123456789), ("smoke_b", 987654321)):
|
||||
if f"Loaded 26.3 prototype Age rivencraft:age/{name} with seed {seed}" not in text:
|
||||
raise RuntimeError("Age identity/seed failed full restart")
|
||||
process.stdin.write("rivencraft_port age list\n")
|
||||
process.stdin.flush()
|
||||
process.stdin.write("save-all flush\n")
|
||||
process.stdin.flush()
|
||||
wait_for(process, log, "Saved the game")
|
||||
else:
|
||||
# 1.21.1's Gradle launcher does not forward this pipe. Its
|
||||
# unchanged gameplay uses the recorded/manual regression;
|
||||
# this smoke checks startup and graceful process shutdown.
|
||||
os.killpg(process.pid, signal.SIGINT)
|
||||
if args.target == "mc1211":
|
||||
try:
|
||||
process.wait(timeout=25)
|
||||
except subprocess.TimeoutExpired:
|
||||
stop(process)
|
||||
else:
|
||||
stop(process)
|
||||
if process.returncode not in (0, 130, -signal.SIGINT):
|
||||
raise RuntimeError(f"Server exited with {process.returncode}; inspect {log}")
|
||||
process = None
|
||||
print(f"PASS {args.target} {phase}", flush=True)
|
||||
except StalledTest as error:
|
||||
print(f"HANDOFF: {error}. Manual check: start {args.target}, create two Ages, travel, "
|
||||
"restart and revisit both; confirm names/seeds and return travel.", flush=True)
|
||||
raise SystemExit(2)
|
||||
finally:
|
||||
stop(process)
|
||||
shutil.rmtree(work)
|
||||
print(f"Removed temporary world; logs: {logs}", flush=True)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
with server_test_lock():
|
||||
main()
|
||||
Reference in new issue
Block a user