zapret-kvn/tests/test_singbox_core_updater.py
loop-uh 0b559eb7e6
Some checks failed
Windows project source guards / test (push) Has been cancelled
Update the sing-box core and let the button apply a subscription
The subscription button read the source and applied nothing, so fresh servers
existed only in its report while the table kept the previous count. That read as
lost servers rather than as work not yet done. The button now applies what it
downloads; checking without applying stayed in the context menu, where it says
so.

The sing-box Extended core only ever arrived with a build of the application, so
a fix in the core had to wait for the next Zapret KVN release. The updates page
offers it the same way it offers Xray: show the installed version, look up the
newest release, and replace the executable only on an explicit action. Its tag
carries two versions — the core and the extension set — and both are compared,
otherwise an update within the same core version would go unnoticed. A release
that cannot be read is never treated as newer, and an archive without the
executable leaves the previous core in place.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 20:35:51 +03:00

74 lines
3.2 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.

from __future__ import annotations
from pathlib import Path
import tempfile
import unittest
import zipfile
from xray_fluent.engines.singbox.core_updater import (
ASSET_PATTERN,
_install,
is_newer,
parse_version,
resolve_release,
)
class SingboxCoreVersionTests(unittest.TestCase):
"""Тег несёт две версии сразу: ядра и набора расширений. Сравнивать нужно
обе, иначе обновление внутри одной версии ядра осталось бы незамеченным."""
def test_both_parts_of_the_tag_are_compared(self) -> None:
self.assertEqual((1, 13, 18, 2, 6, 5), parse_version("v1.13.18-extended-2.6.5"))
self.assertTrue(is_newer("v1.13.18-extended-2.6.5", "v1.13.14-extended-2.5.2"))
# Ядро то же, расширения новее.
self.assertTrue(is_newer("v1.13.18-extended-2.6.6", "v1.13.18-extended-2.6.5"))
self.assertFalse(is_newer("v1.13.18-extended-2.6.5", "v1.13.18-extended-2.6.5"))
self.assertFalse(is_newer("v1.13.14-extended-2.5.2", "v1.13.18-extended-2.6.5"))
def test_unreadable_release_never_counts_as_newer(self) -> None:
self.assertIsNone(parse_version("nightly"))
self.assertFalse(is_newer("nightly", "v1.13.18-extended-2.6.5"))
# Неизвестная установленная версия не мешает предложить обновление.
self.assertTrue(is_newer("v1.13.18-extended-2.6.5", ""))
def test_only_the_windows_purego_archive_is_accepted(self) -> None:
self.assertTrue(ASSET_PATTERN.match("sing-box-1.13.18-extended-2.6.5-windows-amd64-purego.zip"))
self.assertFalse(ASSET_PATTERN.match("sing-box-1.13.18-extended-2.6.5-linux-amd64.tar.gz"))
self.assertFalse(ASSET_PATTERN.match("sing-box-1.13.18-extended-2.6.5-windows-arm64-purego.zip"))
class SingboxCoreInstallTests(unittest.TestCase):
def test_install_replaces_the_executable(self) -> None:
with tempfile.TemporaryDirectory() as temp:
root = Path(temp)
target = root / "core" / "sing-box.exe"
target.parent.mkdir(parents=True)
target.write_bytes(b"old")
archive = root / "core.zip"
with zipfile.ZipFile(archive, "w") as bundle:
bundle.writestr("sing-box-1.13.18/sing-box.exe", b"new")
_install(archive, target)
self.assertEqual(b"new", target.read_bytes())
self.assertFalse((target.parent / "sing-box.exe.new").exists())
def test_archive_without_the_executable_is_refused(self) -> None:
with tempfile.TemporaryDirectory() as temp:
root = Path(temp)
target = root / "sing-box.exe"
target.write_bytes(b"old")
archive = root / "core.zip"
with zipfile.ZipFile(archive, "w") as bundle:
bundle.writestr("readme.txt", b"nothing here")
with self.assertRaises(RuntimeError):
_install(archive, target)
# Прежнее ядро обязано остаться на месте.
self.assertEqual(b"old", target.read_bytes())
if __name__ == "__main__":
unittest.main()