"""hub_backup_lib 单元测试。""" from __future__ import annotations import json import sys import tempfile import unittest import zipfile from pathlib import Path ROOT = Path(__file__).resolve().parents[2] if str(ROOT) not in sys.path: sys.path.insert(0, str(ROOT)) from lib.hub import hub_backup_lib as backup class HubBackupLibTest(unittest.TestCase): def test_normalize_backup_settings(self): cfg = backup.normalize_backup_settings({"auto_hour": 99, "retention_days": 0}) self.assertEqual(cfg["auto_hour"], 23) self.assertEqual(cfg["retention_days"], 1) def test_safe_archive_name(self): self.assertTrue(backup._safe_archive_name("backup_2026-07-02_163045.zip")) self.assertFalse(backup._safe_archive_name("../evil.zip")) def test_run_and_restore_roundtrip(self): with tempfile.TemporaryDirectory() as tmp: root = Path(tmp) / "portal" root.mkdir(parents=True) settings = { "backup": { "auto_enabled": False, "backup_root": str(root), "include_env": False, "include_exchange_images": False, } } hub_settings = backup.HUB_DIR / "hub_settings.json" had = hub_settings.is_file() old = hub_settings.read_text(encoding="utf-8") if had else None try: if not had: hub_settings.write_text('{"version":1,"exchanges":[]}', encoding="utf-8") result = backup.run_backup(trigger="manual", settings=settings) self.assertTrue(result.get("ok"), result) archive = Path(result["path"]) self.assertTrue(archive.is_file()) with zipfile.ZipFile(archive, "r") as zf: names = zf.namelist() self.assertIn("manifest.json", names) manifest = json.loads( zipfile.ZipFile(archive, "r").read("manifest.json").decode("utf-8") ) self.assertEqual(manifest.get("trigger"), "manual") finally: if had and old is not None: hub_settings.write_text(old, encoding="utf-8") elif not had and hub_settings.is_file(): hub_settings.unlink(missing_ok=True) if __name__ == "__main__": unittest.main()