重构:模块化 RRPP Lite 并更新入口
This commit is contained in:
@@ -16,15 +16,19 @@ sys.path = [str(LITE)] + [p for p in sys.path if Path(p).resolve() != Path(__fil
|
||||
|
||||
sys.stdout.reconfigure(encoding="utf-8")
|
||||
|
||||
import proxy_lite as pp
|
||||
import main as pp
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
|
||||
# 构造窗口时不写用户数据目录(避免污染),构造后再指向真实 nodes.json
|
||||
# 构造窗口时不触发用户数据初始化或远程同步;本测试只验证静态菜单和本地节点状态。
|
||||
pp._user_init_local = lambda: None
|
||||
pp._user_init_remote = lambda *args, **kwargs: None
|
||||
pp._nodes_sync_remote = lambda *args, **kwargs: pp._NODES_SYNC_DONE.set()
|
||||
pp._NODES_SYNC_DONE.set()
|
||||
|
||||
app = QApplication(sys.argv)
|
||||
w = pp.MainWindow()
|
||||
w.timer.stop() # 停掉状态轮询,纯静态检查
|
||||
failures = []
|
||||
|
||||
pp._USER_DIR = LITE / "test" # 真实 nodes.json 所在目录
|
||||
nodes = pp._reload_nodes()
|
||||
@@ -44,6 +48,8 @@ for act in menu.actions():
|
||||
if not act.isEnabled():
|
||||
act.trigger()
|
||||
print(f"\n点击禁用项后节点下标: {before} -> {pp._selected_index()} (应不变)")
|
||||
if pp._selected_index() != before:
|
||||
failures.append("点击不可用节点后发生了切换")
|
||||
|
||||
# ── 上次选中的节点已不可用:启动时自动回退到第一个可达节点 ──────────
|
||||
print("\n启动校验(_verify_selected_node):")
|
||||
@@ -54,19 +60,28 @@ else:
|
||||
import json
|
||||
_bak = (pp._USER_DIR / "settings.json").read_bytes() if (pp._USER_DIR / "settings.json").is_file() else None
|
||||
bad_idx = bad[0]
|
||||
pp._SELECTED_NODE = bad_idx # 模拟上次选了不可用节点
|
||||
# 模拟上次持久化选中了不可用节点:内存下标与 current_node 必须一致,
|
||||
# 否则 _verify_selected_node 会先按真实保存的域名重新匹配,测试并非回退分支。
|
||||
pp._settings_save({**pp._settings_load(), "current_node": nodes[bad_idx].get("domain") or ""})
|
||||
pp._SELECTED_NODE = bad_idx
|
||||
switched = pp._verify_selected_node()
|
||||
expect = pp._first_reachable_index(nodes)
|
||||
ok = switched and pp._selected_index() == expect
|
||||
print(f" 上次选中 {nodes[bad_idx].get('domain')}(下标 {bad_idx}) 不可用 -> "
|
||||
f"回退到下标 {pp._selected_index()} ({nodes[pp._selected_index()].get('domain')}) "
|
||||
f"{'PASS' if ok else 'FAIL'}")
|
||||
if not ok:
|
||||
failures.append("不可用节点未回退到首个可达节点")
|
||||
saved = json.loads((pp._USER_DIR / "settings.json").read_text("utf-8")).get("current_node") if (pp._USER_DIR / "settings.json").is_file() else ""
|
||||
ok2 = saved == str(nodes[expect].get("domain") or "")
|
||||
print(f" 回退结果已写入设置 current_node={saved!r} {'PASS' if ok2 else 'FAIL'}")
|
||||
if not ok2:
|
||||
failures.append("节点回退未写回 current_node")
|
||||
# 再校验一次:已经是可达节点,不应再切换
|
||||
ok3 = pp._verify_selected_node() is False
|
||||
print(f" 再次校验不重复切换 {'PASS' if ok3 else 'FAIL'}")
|
||||
if not ok3:
|
||||
failures.append("已回退节点被重复切换")
|
||||
if _bak is None:
|
||||
(pp._USER_DIR / "settings.json").unlink(missing_ok=True)
|
||||
else:
|
||||
@@ -87,13 +102,19 @@ else:
|
||||
ok = switched and ordered[pp._selected_index()].get("domain") == dom_old
|
||||
print(f" current_node={dom_old} 调序后跟随域名 -> 下标 {pp._selected_index()} "
|
||||
f"{'PASS' if ok else 'FAIL'}")
|
||||
if not ok:
|
||||
failures.append("节点调序后没有按域名重新匹配")
|
||||
# 已是正确域名时再跑一次:不应重复切换
|
||||
ok2 = pp._rematch_saved_domain() is False
|
||||
print(f" 再次重匹配不重复切换 {'PASS' if ok2 else 'FAIL'}")
|
||||
if not ok2:
|
||||
failures.append("节点调序重匹配重复切换")
|
||||
# 域名已不在列表(节点被移除):不切换,保持现状
|
||||
pp._settings_save({**pp._settings_load(), "current_node": "gone.example.com"})
|
||||
ok3 = pp._rematch_saved_domain() is False
|
||||
print(f" 节点被移除时不动 {'PASS' if ok3 else 'FAIL'}")
|
||||
if not ok3:
|
||||
failures.append("已移除节点仍发生切换")
|
||||
pp._NODES = None # 还原缓存,后续用例重读文件
|
||||
# 还原 settings.json,避免测试污染
|
||||
if _bak is None:
|
||||
@@ -101,4 +122,6 @@ else:
|
||||
else:
|
||||
(pp._USER_DIR / "settings.json").write_bytes(_bak)
|
||||
|
||||
if failures:
|
||||
raise SystemExit("FAIL: " + "; ".join(failures))
|
||||
print("OK")
|
||||
|
||||
Reference in New Issue
Block a user