"""offscreen 模式切换功能测试:DB 持久化 + 首条消息锁定 + worker 分派 运行: QT_QPA_PLATFORM=offscreen python tests/smoke_mode.py """ import os import sys sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) os.environ.setdefault("QT_QPA_PLATFORM", "offscreen") os.environ.setdefault("HAOCODE_RENDER", "software") os.environ["QTWEBENGINE_CHROMIUM_FLAGS"] = "--disable-gpu" # 绕过 AMD 核显 context lost os.environ.setdefault("PYTHONIOENCODING", "utf-8") # 铁律:测试不得污染真实 data/chat_history.db → DBManager 默认路径重定向到临时文件 import tempfile as _tf # noqa: E402 import core.db_manager as _dbm # noqa: E402 _dbm._DEFAULT_DB = os.path.join(_tf.gettempdir(), f"haocode_test_smoke_mode_{os.getpid()}.db") from PyQt6.QtWidgets import QApplication # noqa: E402 from ui.views.main_window import MainWindow # noqa: E402 (QtWebEngine 须先于 QApplication import 完成) app = QApplication(sys.argv) ok = True def check(name, cond): global ok print((" PASS " if cond else " FAIL ") + name) if not cond: ok = False window = MainWindow() # 本套件验证「默认锁定」语义:显式置 mode_switch=false,不受本机 data/config.json 影响 # (仅内存,不会写回配置文件) window.config_data["mode_switch"] = False window._refresh_mode_button() # 1) 新建会话 → 未锁定 window.on_new_chat_clicked() sid = window.current_session_id check("新会话未锁定 (mode=None)", window._get_current_mode() is None) check("按钮显示待选 Chat", "Chat" in window.btn_mode.text() and "🔒" not in window.btn_mode.text()) # 2) 浮动弹窗开/关 + 选择 window.show_mode_popup() check("弹窗打开", window.mode_popup.isVisible()) window._select_mode("worker") check("选 worker 后按钮更新", "Worker" in window.btn_mode.text()) check("选择后弹窗自动关闭", not window.mode_popup.isVisible()) # 3) 首条发送 → 锁定 window._lock_session_mode() check("发送后锁定 worker", window.db.get_session_mode(sid) == "worker") check("按钮显示锁定", "🔒" in window.btn_mode.text()) # 4) 锁定后不可改 window._select_mode("chat") check("锁定后选择无效", window.db.get_session_mode(sid) == "worker") # 5) worker 分派 w1 = window._create_stream_worker([], "worker") w2 = window._create_stream_worker([], "chat") from core.llm_engine import AgentWorker, ChatWorker # noqa: E402 check("worker 模式 → AgentWorker", isinstance(w1, AgentWorker)) check("chat 模式 → ChatWorker", isinstance(w2, ChatWorker)) check("ChatWorker 有基础信号", all(hasattr(w2, s) for s in ("chunk_received", "reasoning_received", "error_occurred"))) check("ChatWorker 无工具信号(chat 模式不暴露)", not hasattr(w2, "tool_execution_started")) # 6) 切回新会话 → 解锁 window.on_new_chat_clicked() check("新会话恢复可选", window._get_current_mode() is None and "🔒" not in window.btn_mode.text()) # 7) 旧会话(无 mode 列值)→ 默认 chat 路径 window.load_messages_to_web(sid) check("切回已锁定会话显示锁定", window._get_current_mode() == "worker" and "🔒" in window.btn_mode.text()) # 8) mode_switch=true → 中途切换放行(旧锁定会话解锁 + 选择立即落库) window.config_data["mode_switch"] = True window._refresh_mode_button() check("开关开启后旧会话解锁显示", "🔒" not in window.btn_mode.text()) window._select_mode("chat") check("开关开启后中途切换生效", window.db.get_session_mode(sid) == "chat") window.config_data["mode_switch"] = False try: window.close() except Exception: pass app.quit() print("\n===== " + ("ALL PASS" if ok else "HAS FAILURES") + " =====") sys.exit(0 if ok else 1)