feat(config): isolate config and database via HAOCODE_CONFIG_FILE override
core/config_paths.py resolves a single override so tests and multiple instances can run against isolated temp config/db without touching user data.
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""tests/_test_env.py —— 自动化测试的统一临时环境(P0-01 新增)
|
||||
|
||||
铁律(VERIFICATION.md §凭据与运行数据隔离):
|
||||
1. 每个测试进程独立临时目录 + 最小临时配置;
|
||||
2. 在 import 任何可能间接加载 MainWindow 的模块之前设置 HAOCODE_CONFIG_FILE;
|
||||
3. 在 import MainWindow 之前把 core.db_manager._DEFAULT_DB 指向临时数据库;
|
||||
4. 写入、迁移、附件和截图产物只落到临时目录。
|
||||
|
||||
用法(放在测试文件顶部、任何 UI import 之前):
|
||||
|
||||
from tests._test_env import isolate
|
||||
isolate("bashpanel", config={"providers": {}, "mode_switch": True})
|
||||
|
||||
说明:
|
||||
· 临时目录按 进程 pid 隔离,测试进程互不干扰;
|
||||
· 默认临时配置为最小可启动结构(空 providers + 测试 provider);
|
||||
· 本模块不 import 任何 PyQt 模块,可在无 GUI 环境中安全调用。
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
_TESTS_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
_ROOT = os.path.dirname(_TESTS_DIR)
|
||||
if _ROOT not in sys.path:
|
||||
sys.path.insert(0, _ROOT)
|
||||
|
||||
|
||||
def default_config() -> dict:
|
||||
"""最小可启动临时配置(不含任何真实凭据)。"""
|
||||
return {
|
||||
"providers": {
|
||||
"testprov": {
|
||||
"api_key": "test-key-not-real",
|
||||
"base_url": "http://127.0.0.1:9/v1",
|
||||
"models": ["test-model"],
|
||||
"model_contexts": {"test-model": 100000},
|
||||
}
|
||||
},
|
||||
"default_provider": "testprov",
|
||||
"default_model": "test-model",
|
||||
}
|
||||
|
||||
|
||||
def isolate(tag: str = "t", config: dict | None = None) -> dict:
|
||||
"""创建临时配置 + 临时数据库并完成重定向。必须在 import MainWindow 之前调用。
|
||||
|
||||
返回 {"base": 临时目录, "config": 临时配置路径, "db": 临时数据库路径}。
|
||||
"""
|
||||
base = os.path.join(tempfile.gettempdir(),
|
||||
f"haocode_test_{tag}_{os.getpid()}")
|
||||
os.makedirs(base, exist_ok=True)
|
||||
|
||||
cfg_path = os.path.join(base, "config.json")
|
||||
with open(cfg_path, "w", encoding="utf-8") as f:
|
||||
json.dump(config if config is not None else default_config(),
|
||||
f, ensure_ascii=False, indent=2)
|
||||
|
||||
db_path = os.path.join(base, "chat_history.db")
|
||||
for p in (db_path, db_path + "-wal", db_path + "-shm"):
|
||||
if os.path.exists(p):
|
||||
os.remove(p)
|
||||
|
||||
os.environ["HAOCODE_CONFIG_FILE"] = cfg_path
|
||||
|
||||
# P1-03:QtWebEngine 独立 profile 重定向到临时目录(源码运行才在 data/webengine/)
|
||||
os.environ.setdefault("HAOCODE_WEBENGINE_PROFILE_DIR", os.path.join(base, "webengine_profile"))
|
||||
|
||||
import core.db_manager as _dbm
|
||||
_dbm._DEFAULT_DB = db_path
|
||||
|
||||
return {"base": base, "config": cfg_path, "db": db_path}
|
||||
Reference in New Issue
Block a user