Files

124 lines
4.2 KiB
Python

"""config 模块行为测试 (真实 JSON 文件读写, 非 mock)
运行: cd /home/lou/文档/7z-encrypt && .venv/bin/python -m unittest discover -s tests -v
"""
import json
import os
import sys
import tempfile
import unittest
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from config import AppConfig, ConfigError
VALID = {
"server": {"url": "http://127.0.0.1:8000", "timeout": 30, "max_retries": 3},
"crypto": {"key_id": "default_key", "keyring_path": "config/keyring.json"},
"splitter": {"chunk_size_mb": 10},
"state": {"db_path": "config/tasks.db", "cleanup_days": 7},
}
def write_cfg(td: str, data: dict) -> str:
path = os.path.join(td, "config.json")
with open(path, "w", encoding="utf-8") as f:
json.dump(data, f)
return path
class TestLoad(unittest.TestCase):
def setUp(self):
self._td = tempfile.TemporaryDirectory(prefix='hermes-test-')
self.addCleanup(self._td.cleanup)
def test_valid_config(self):
cfg = AppConfig(write_cfg(self._td.name, VALID))
self.assertEqual(cfg.server_url, "http://127.0.0.1:8000")
self.assertEqual(cfg.key_id, "default_key")
self.assertEqual(cfg.chunk_size, 10 * 1024 * 1024)
self.assertEqual(cfg.cleanup_days, 7)
def test_defaults_filled(self):
cfg = AppConfig(write_cfg(self._td.name, {"server": {"url": "http://x:1"}}))
self.assertEqual(cfg.timeout, 30) # 默认值兜底
self.assertEqual(cfg.max_retries, 3)
self.assertEqual(cfg.retry_delay, 1.0)
self.assertEqual(cfg.data["splitter"]["chunk_size_mb"], 10)
self.assertEqual(cfg.key_id, "default_key")
def test_user_overrides_default(self):
data = dict(VALID)
data["server"] = {"url": "http://x:1", "timeout": 5}
cfg = AppConfig(write_cfg(self._td.name, data))
self.assertEqual(cfg.timeout, 5) # 用户覆盖
self.assertEqual(cfg.max_retries, 3) # 未覆盖的保持默认
def test_missing_file(self):
with self.assertRaises(ConfigError):
AppConfig(os.path.join(self._td.name, "nope.json"))
def test_invalid_json(self):
path = os.path.join(self._td.name, "config.json")
with open(path, "w", encoding="utf-8") as f:
f.write("{not json")
with self.assertRaises(json.JSONDecodeError):
AppConfig(path)
class TestValidate(unittest.TestCase):
def setUp(self):
self._td = tempfile.TemporaryDirectory(prefix='hermes-test-')
self.addCleanup(self._td.cleanup)
def _cfg(self, **mut):
data = json.loads(json.dumps(VALID))
for k, v in mut.items():
data[k] = v
return AppConfig(write_cfg(self._td.name, data))
def test_missing_server_url(self):
with self.assertRaises(ConfigError):
self._cfg(server={})
def test_bad_url_scheme(self):
with self.assertRaises(ConfigError):
self._cfg(server={"url": "ftp://x"})
def test_bad_chunk_size(self):
with self.assertRaises(ConfigError):
self._cfg(splitter={"chunk_size_mb": 0})
def test_bad_max_retries(self):
with self.assertRaises(ConfigError):
self._cfg(server={"url": "http://x:1", "max_retries": 0})
def test_bad_timeout(self):
with self.assertRaises(ConfigError):
self._cfg(server={"url": "http://x:1", "timeout": -1})
class TestFactory(unittest.TestCase):
"""分发: 构造各模块实例 (真实构造, 非 mock)"""
def setUp(self):
self._td = tempfile.TemporaryDirectory(prefix='hermes-test-')
self.addCleanup(self._td.cleanup)
def test_build_instances(self):
cfg = AppConfig(write_cfg(self._td.name, VALID))
from crypto import CryptoEngine
from transfer import TransferClient
from state import TaskStore
self.assertIsInstance(cfg.build_crypto(), CryptoEngine)
t = cfg.build_transfer()
self.assertIsInstance(t, TransferClient)
self.assertEqual(t.base_url, VALID["server"]["url"])
self.assertEqual(t.max_retries, 3)
self.assertIsInstance(cfg.build_store(), TaskStore)
if __name__ == '__main__':
unittest.main()