"""语义分析器骨架测试(T-G0):enabled 门控 / DDL / 独立挂载 / 配置构建。""" import pytest pytest.importorskip("fastapi") from fastapi import FastAPI from fastapi.testclient import TestClient import gateway.api as ga from gateway.sense.config import build_sense_config from gateway.sense.store import SenseStore def test_sense_disabled_by_default_404(): """D-G7:默认 enabled=False -> 全局 app 不注册任何 /sense 路由。""" client = TestClient(ga.app) assert client.get("/sense/health").status_code == 404 assert client.get("/sense/admin/agreement").status_code == 404 def test_ddl_creates_tables_and_indexes(tmp_path): """两表 + 两索引幂等创建。""" store = SenseStore.init_db(tmp_path / "sense.sqlite3") tables = set(store.table_names()) assert {"tier_observations", "sense_artifacts"} <= tables idx = set(store.index_names()) assert {"idx_obs_ts", "idx_obs_policy"} <= idx SenseStore.init_db(tmp_path / "sense.sqlite3") # 幂等 def test_build_sense_config_defaults(): """缺省值 + mode 非法回落 collect(D-G7)。""" cfg = build_sense_config({}) assert cfg.enabled is False assert cfg.mode == "collect" assert cfg.embedder.dim == 1024 assert cfg.min_labels == 500 assert cfg.tier_pool_hint("proxy", "t1") == "local-small" assert cfg.tier_pool_hint("proxy", "t3") == "premium" assert cfg.tier_pool_hint("client", "t2") == "budget" # 无配置兜底 bad = build_sense_config({"sense": {"mode": "turbo", "enabled": True}}) assert bad.mode == "collect" def test_enabled_router_health(tmp_path): """enabled=True 独立挂载:/sense/health 透出灰度状态。""" cfg = build_sense_config({"sense": {"enabled": True, "mode": "collect", "db_path": str(tmp_path / "s.sqlite3")}}) app = FastAPI() app.include_router( __import__("gateway.sense", fromlist=["x"]).build_sense_router(cfg)) client = TestClient(app) r = client.get("/sense/health") assert r.status_code == 200 data = r.json() assert data["enabled"] is True and data["mode"] == "collect" def test_observation_roundtrip(tmp_path): """观察写入/标签回填/计数/留存清理(store 基础链路)。""" store = SenseStore.init_db(tmp_path / "s.sqlite3") store.insert_observation({ "request_id": "r1", "consumer": "pipeline", "decided_tier": "T2", "executed_tier": "T2", "probs": '{"t1":0.2,"t2":0.6,"t3":0.2}', "policy_version": "v0-rule", "features": '{"turns":1}'}) store.insert_observation({ "request_id": "r2", "consumer": "proxy", "decided_tier": "T1", "executed_tier": "T1", "probs": "{}", "policy_version": "v0-rule", "features": "{}", "outcome": "ok"}) assert store.count_labeled() == 0 store.set_true_tier("r1", "T2") assert store.count_labeled() == 1 rows = store.labeled_rows() assert rows[0]["request_id"] == "r1" and rows[0]["true_tier"] == "T2" assert store.update_outcome("r2", "escalated", executed_tier="T2") is True # 180d 清理 import time assert store.purge_older_than(time.time() + 10) >= 2 assert store.count_labeled() == 0