zapret-kvn/tests/test_core_release_freeze.py
loop-uh 96d43de5ac
Some checks failed
Windows project source guards / test (push) Failing after 1m18s
release: freeze cores for Windows 0.8.16 and Android 0.4.11; Android Hysteria догоняет сам
Подготовка пары релизов больше не останавливается, когда встроенная Hysteria
Android отстаёт от выбранной для Windows: android_hysteria_parity вызывает
android/scripts/update_hysteria_core.py, который перегенерирует серию патчей и
пишет её только после собственных проверок. Отставание, пережившее
перегенерацию, по-прежнему останавливает заморозку.

Заморозка для Windows 0.8.16 и Android v0.4.11: sing-box-extended
v1.14.1-extended-2.7.2, Hysteria app/v2.13.0, amneziawg-go v3.1.20260828.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 00:36:26 +03:00

118 lines
6.9 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import copy
import json
from pathlib import Path
import shutil
import tempfile
import unittest
from scripts.check_core_release_freeze import digest, verify
from scripts.prepare_core_release import android_hysteria_parity, android_pin_changes
ROOT = Path(__file__).resolve().parents[1]
ANDROID = ROOT.parent / "android"
class CoreReleaseFreezeTests(unittest.TestCase):
def test_receipt_rejects_other_release_and_changed_inputs(self):
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
(root / "scripts").mkdir()
path = root / "scripts/core-lock.windows-x64.json"
core = {"version": "v1.14.1-extended-2.7.2", "commit": "5" * 40}
path.write_text(json.dumps({"amnezia": {"version": "v3.1.1"}, "singbox_build": {**core, "zip_sha256": "0" * 64}}))
freeze = {"schema": 1, "releases": {"windows": "0.5.8"},
"amnezia": {"version": "v3.1.1"}, "singbox": core,
"inputs": {"windows": {"scripts/core-lock.windows-x64.json": digest(path)}}}
(root / "core-release-freeze.json").write_text(json.dumps(freeze))
self.assertEqual(verify(root, "windows", "0.5.8"), freeze)
with self.assertRaisesRegex(ValueError, "different release"):
verify(root, "windows", "0.5.9")
path.write_text(path.read_text() + "\n")
with self.assertRaisesRegex(ValueError, "input changed"):
verify(root, "windows", "0.5.8")
def test_receipt_rejects_android_core_other_than_frozen(self):
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
properties = root / "core.properties"
properties.write_text(
"CORE_TAG=v1.14.0-extended-2.7.1\nCORE_COMMIT=" + "4" * 40 + "\n"
"ANDROID_WIREGUARD_GO=m@v3.1.1\nANDROID_AMNEZIAWG_GO=m@v3.1.1\nGO_VERSION=1.26.4\n"
)
freeze = {"schema": 1, "releases": {"android": "v0.5.0"},
"amnezia": {"module": "m", "version": "v3.1.1", "toolchain": {"version": "go1.26.4"}},
"singbox": {"version": "v1.14.1-extended-2.7.2", "commit": "5" * 40},
"inputs": {"android": {"core.properties": digest(properties)}}}
(root / "core-release-freeze.json").write_text(json.dumps(freeze))
with self.assertRaisesRegex(ValueError, "Android sing-box differs"):
verify(root, "android", "v0.5.0")
def test_receipt_pins_hysteria_on_both_platforms(self):
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
(root / "scripts").mkdir()
core = {"version": "v1.14.1-extended-2.7.2", "commit": "5" * 40}
lock = root / "scripts/core-lock.windows-x64.json"
amnezia = {"version": "v3.1.1", "module": "m", "toolchain": {"version": "go1.26.8"}}
lock.write_text(json.dumps({
"amnezia": amnezia, "singbox_build": core,
"sources": [{"id": "hysteria", "version": "app/v2.12.2"}],
}))
freeze = {"schema": 1, "releases": {"windows": "0.5.8", "android": "v0.5.0"},
"amnezia": amnezia,
"singbox": core, "hysteria": {"version": "app/v2.12.3"},
"inputs": {"windows": {}, "android": {}}}
(root / "core-release-freeze.json").write_text(json.dumps(freeze))
with self.assertRaisesRegex(ValueError, "Windows Hysteria differs"):
verify(root, "windows", "0.5.8")
(root / "core.properties").write_text(
f"CORE_TAG={core['version']}\nCORE_COMMIT={core['commit']}\n"
"ANDROID_WIREGUARD_GO=m@v3.1.1\nANDROID_AMNEZIAWG_GO=m@v3.1.1\nGO_VERSION=1.26.8\n"
"HYSTERIA_CORE_TAG=app/v2.12.2\n"
)
with self.assertRaisesRegex(ValueError, "Android Hysteria differs"):
verify(root, "android", "v0.5.0")
newer = {"sources": [{"id": "hysteria", "version": "app/v2.12.3"}]}
# Отставание больше не останавливает подготовку: Android сам
# перегенерирует серию патчей. Без его скрипта — понятный отказ.
with self.assertRaisesRegex(ValueError, "updater is missing"):
android_hysteria_parity(root, newer)
# Перегенерация, которая не подняла версию, заморозку не пропускает.
with self.assertRaisesRegex(ValueError, "lags Windows app/v2.12.3 after regeneration"):
android_hysteria_parity(root, newer, regenerate=lambda _android, _version: None)
def regenerate(android: Path, version: str) -> None:
path = android / "core.properties"
path.write_text(path.read_text().replace("HYSTERIA_CORE_TAG=app/v2.12.2", f"HYSTERIA_CORE_TAG={version}"))
self.assertEqual(android_hysteria_parity(root, newer, regenerate=regenerate), "app/v2.12.3")
self.assertIn("HYSTERIA_CORE_TAG=app/v2.12.3", (root / "core.properties").read_text())
(root / "core.properties").write_text(
(root / "core.properties").read_text().replace("app/v2.12.3", "app/v2.12.2")
)
self.assertEqual(
android_hysteria_parity(root, {"sources": [{"id": "hysteria", "version": "app/v2.12.2"}]}),
"app/v2.12.2",
)
@unittest.skipUnless(ANDROID.is_dir(), "paired Android checkout not available")
def test_android_retarget_preserves_upstream_patch_context(self):
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
shutil.copyfile(ANDROID / "core.properties", root / "core.properties")
shutil.copytree(ANDROID / "core-patches", root / "core-patches")
pin = json.loads((ROOT / "scripts/core-lock.windows-x64.json").read_text())["amnezia"]
unchanged = android_pin_changes(root, pin)
for path, text in unchanged.items():
self.assertEqual(path.read_text(), text)
pin = copy.deepcopy(pin)
pin.update(version="v3.1.20990101", module_sum="h1:futurezip", module_go_mod_sum="h1:futuremod")
changes = android_pin_changes(root, pin)
patch_path = root / "core-patches/0005-official-amnezia-wg-unified.patch"
before, after = patch_path.read_text().splitlines(), changes[patch_path].splitlines()
self.assertEqual(len(before), len(after))
for old, new in zip(before, after):
if not old.startswith("+"):
self.assertEqual(old, new)
self.assertIn("v3.1.20990101 h1:futurezip", changes[patch_path])
self.assertIn("v3.1.20990101/go.mod h1:futuremod", changes[patch_path])